3 // PlanetLab Central Slice API (PLCAPI) PHP interface
5 // DO NOT EDIT. This file was automatically generated at
8 // Mark Huang <mlhuang@cs.princeton.edu>
9 // Copyright (C) 2005-2006 The Trustees of Princeton University
12 require_once 'plc_config.php';
25 function PLCAPI($auth = NULL,
26 $server = PLC_API_HOST,
32 $this->server = $server;
35 $this->cainfo = $cainfo;
36 $this->errors = array();
37 $this->trace = array();
38 $this->calls = array();
39 $this->multicall = false;
42 function rec_join ($arg) {
43 if ( is_array($arg) ) {
45 foreach ( $arg as $i ) {
46 $l = $this->rec_join($i);
48 if ( $l[0] != "<" ) { $ret .= $l . ", "; }
52 settype($arg, "string");
57 function backtrace_php () {
58 $backtrace = debug_backtrace();
60 $len = count($backtrace);
62 foreach( array_reverse($backtrace) as $line ) {
63 $msg .= "File '". $line['file'] . "' line " . $line['line'] . "\n";
64 $msg .= " " . $line['function'] . "( " . $this->rec_join($line['args']) . ")\n";
66 if ( $cnt == $len ) { break; }
71 function error_log($error_msg, $backtrace_level = 1)
73 $backtrace = debug_backtrace();
74 $file = $backtrace[$backtrace_level]['file'];
75 $line = $backtrace[$backtrace_level]['line'];
77 $error_line='PLCAPI error: ' . $error_msg ;
78 if ($file) $error_line .= ' in file ' . $file;
79 if ($line) $error_line .= ' on line ' . $line;
80 $this->errors[] = $error_line;
81 # TODO: setup a config variable for more detailed stack traces, for API errors.
83 error_log($error_line);
85 error_log($this->backtrace_php());
91 if (empty($this->trace)) {
94 $last_trace = end($this->trace);
95 return implode("\\n", $last_trace['errors']);
104 function microtime_float()
106 list($usec, $sec) = explode(" ", microtime());
107 return ((float) $usec + (float) $sec);
110 function call($method, $args = NULL)
112 if ($this->multicall) {
113 $this->calls[] = array ('methodName' => $method,
117 return $this->internal_call ($method, $args, 3);
121 function internal_call($method, $args = NULL, $backtrace_level = 2)
125 // Verify peer certificate if talking over SSL
126 if ($this->port == 443) {
127 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 2);
128 if (!empty($this->cainfo)) {
129 curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
130 } elseif (defined('PLC_API_CA_SSL_CRT')) {
131 curl_setopt($curl, CURLOPT_CAINFO, PLC_API_CA_SSL_CRT);
138 // Set the URL for the request
139 $url .= $this->server . ':' . $this->port . '/' . $this->path;
140 curl_setopt($curl, CURLOPT_URL, $url);
142 // Marshal the XML-RPC request as a POST variable. <nil/> is an
143 // extension to the XML-RPC spec that is supported in our custom
144 // version of xmlrpc.so via the 'allow_null' output_encoding key.
145 $request = xmlrpc_encode_request($method, $args, array('null_extension'));
146 error_log("ENCODED: " . $method . "(" . $args . ")");
147 error_log("OBTAINED: " . $request);
148 curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
150 // Construct the HTTP header
151 $header[] = 'Content-type: text/xml';
152 $header[] = 'Content-length: ' . strlen($request);
153 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
155 // Set some miscellaneous options
156 curl_setopt($curl, CURLOPT_TIMEOUT, 180);
158 // Get the output of the request
159 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
160 $t0 = $this->microtime_float();
161 $output = curl_exec($curl);
162 $t1 = $this->microtime_float();
164 if (curl_errno($curl)) {
165 $this->error_log('curl: ' . curl_error($curl), true);
168 $ret = xmlrpc_decode($output);
169 if (is_array($ret) && xmlrpc_is_fault($ret)) {
170 $this->error_log('Fault Code ' . $ret['faultCode'] . ': ' .
171 $ret['faultString'], $backtrace_level, true);
178 $this->trace[] = array('method' => $method,
180 'runtime' => $t1 - $t0,
182 'errors' => $this->errors);
183 $this->errors = array();
190 if (!empty($this->calls)) {
191 $this->error_log ('Warning: multicall already in progress');
194 $this->multicall = true;
199 if (!empty ($this->calls)) {
201 $results = $this->internal_call ('system.multicall', array ($this->calls));
202 foreach ($results as $result) {
203 if (is_array($result)) {
204 if (xmlrpc_is_fault($result)) {
205 $this->error_log('Fault Code ' . $result['faultCode'] . ': ' .
206 $result['faultString'], 1, true);
208 // Thierry - march 30 2007
209 // using $adm->error() is broken with begin/commit style
210 // this is because error() uses last item in trace and checks for ['errors']
211 // when using begin/commit we do run internal_call BUT internal_call checks for
212 // multicall's result globally, not individual results, so ['errors'] comes empty
213 // I considered hacking internal_call
214 // to *NOT* maintain this->trace at all when invoked with multicall
215 // but it is too complex to get all values right
216 // so let's go for the hacky way, and just record individual errors at the right place
217 $this->trace[count($this->trace)-1]['errors'][] = end($this->errors);
229 $this->calls = array();
230 $this->multicall = false;
239 function __call($name, $args)
241 array_unshift($args, $this->auth);
242 return $this->call($name, $args);
246 // this tentatively allows to tune mainstream xmlrpc php lib
247 // so as to achieve the same behaviour as with our patched lib
248 $GLOBALS['xmlrpc_null_extension'] = true;
249 $GLOBALS['$xmlrpc_null_apache_encoding'] = true;
253 $adm = new PLCAPI(array('AuthMethod' => "capability",
254 'Username' => PLC_API_MAINTENANCE_USER,
255 'AuthString' => PLC_API_MAINTENANCE_PASSWORD));