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 //ini_set('error_reporting', 1);
15 * May 2017 - Ciro Scognamiglio <c.scognamiglio@cslash.net>
17 * xmlrpc php module is not compatible anymore with the PLCAPI class,
18 * if the package phpxmlrpc is installed in the same dir it will be used instead
20 * https://github.com/gggeek/phpxmlrpc
22 * If the package is not found the php module XML-RPC is used if available
26 if (file_exists(__DIR__ . '/phpxmlrpc/src/Autoloader.php')) {
27 include_once __DIR__ . '/phpxmlrpc/src/Autoloader.php';
28 PhpXmlRpc\Autoloader::register();
31 require_once 'plc_config.php';
44 function __construct($auth = NULL,
45 $server = PLC_API_HOST,
50 $this->server = $server;
53 $this->cainfo = $cainfo;
54 $this->errors = array();
55 $this->trace = array();
56 $this->calls = array();
57 $this->multicall = false;
60 function rec_join ($arg) {
61 if ( is_array($arg) ) {
63 foreach ( $arg as $i ) {
64 $l = $this->rec_join($i);
66 if ( $l[0] != "<" ) { $ret .= $l . ", "; }
70 settype($arg, "string");
75 function backtrace_php () {
76 $backtrace = debug_backtrace();
78 $len = count($backtrace);
80 foreach( array_reverse($backtrace) as $line ) {
81 $msg .= "File '". $line['file'] . "' line " . $line['line'] . "\n";
82 $msg .= " " . $line['function'] . "( " . $this->rec_join($line['args']) . ")\n";
90 function error_log($error_msg, $backtrace_level = 1) {
91 $backtrace = debug_backtrace();
92 $file = $backtrace[$backtrace_level]['file'];
93 $line = $backtrace[$backtrace_level]['line'];
95 $error_line='PLCAPI error: ' . $error_msg ;
97 $error_line .= ' in file ' . $file;
99 $error_line .= ' on line ' . $line;
100 $this->errors[] = $error_line;
101 # TODO: setup a config variable for more detailed stack traces, for API errors.
103 error_log($error_line);
105 error_log($this->backtrace_php());
110 if (empty($this->trace)) {
113 $last_trace = end($this->trace);
114 return implode("\\n", $last_trace['errors']);
122 function microtime_float() {
123 list($usec, $sec) = explode(" ", microtime());
124 return ((float) $usec + (float) $sec);
127 function call($method, $args = NULL) {
128 if ($this->multicall) {
129 $this->calls[] = array ('methodName' => $method,
133 return $this->internal_call($method, $args, 3);
138 * Use PhpXmlRpc\Value before encoding the request
140 function xmlrpcValue($value) {
141 switch(gettype($value)) {
144 foreach($value as $vk => $vv) {
145 $members[$vk] = $this->xmlrpcValue($vv);
148 if ((array_key_exists(0, $value)) || (empty($value))) {
149 return new PhpXmlRpc\Value($members, 'array');
151 return new PhpXmlRpc\Value($members, 'struct');
156 return new PhpXmlRpc\Value($value, 'double');
159 return new PhpXmlRpc\Value($value, 'boolean');
163 return new PhpXmlRpc\Value(null, 'null');
166 return new PhpXmlRpc\Value($value, 'int');
169 return new PhpXmlRpc\Value($value);
174 function internal_call($method, $args = NULL, $backtrace_level = 2) {
175 if (class_exists('PhpXmlRpc\\PhpXmlRpc')) {
176 return $this->internal_call_phpxmlrpc($method, $args, $backtrace_level);
178 return $this->internal_call_xmlrpc($method, $args, $backtrace_level);
183 * the new internal call, will use PhpXmlRpc
185 function internal_call_phpxmlrpc($method, $args = NULL, $backtrace_level = 2) {
187 // echo '<pre>method and args:<br/>';
188 // var_dump($method);
192 PhpXmlRpc\PhpXmlRpc::$xmlrpc_null_extension = true;
194 if ($this->port == 443) {
200 // Set the URL for the request
201 $url .= $this->server . ':' . $this->port . '/' . $this->path;
203 $client = new PhpXmlRpc\Client($url);
204 $client->setSSLVerifyPeer(false);
207 * 2 -> verify CN (default)
209 $client->setSSLVerifyHost(1);
211 $values = $this->xmlrpcValue($args);
213 $response = $client->send(new PhpXmlRpc\Request($method, $values));
215 // echo '<pre>response:<br/>';
216 // var_dump($response);
218 // echo '<pre>response->value():<br/>';
219 // var_dump($response->value());
222 if (!$response->faultCode()) {
223 $encoder = new PhpXmlRpc\Encoder();
224 $v = $encoder->decode($response->value());
229 "An error occurred [" . $response->faultCode() . "] "
230 . $response->faultString());
236 * The original internal call that uses php XML-RPC
238 function internal_call_xmlrpc($method, $args = NULL, $backtrace_level = 2) {
241 // Verify peer certificate if talking over SSL
242 if ($this->port == 443) {
243 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 2);
244 if (!empty($this->cainfo)) {
245 curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
246 } elseif (defined('PLC_API_CA_SSL_CRT')) {
247 curl_setopt($curl, CURLOPT_CAINFO, PLC_API_CA_SSL_CRT);
254 // Set the URL for the request
255 $url .= $this->server . ':' . $this->port . '/' . $this->path;
256 curl_setopt($curl, CURLOPT_URL, $url);
258 // Marshal the XML-RPC request as a POST variable. <nil/> is an
259 // extension to the XML-RPC spec that is supported in our custom
260 // version of xmlrpc.so via the 'allow_null' output_encoding key.
261 $request = xmlrpc_encode_request($method, $args, array('null_extension'));
262 curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
264 // Construct the HTTP header
265 $header[] = 'Content-type: text/xml';
266 $header[] = 'Content-length: ' . strlen($request);
267 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
269 // Set some miscellaneous options
270 curl_setopt($curl, CURLOPT_TIMEOUT, 180);
272 // Get the output of the request
273 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
274 $t0 = $this->microtime_float();
275 $output = curl_exec($curl);
276 $t1 = $this->microtime_float();
278 if (curl_errno($curl)) {
279 $this->error_log('curl: ' . curl_error($curl), true);
282 $ret = xmlrpc_decode($output);
283 if (is_array($ret) && xmlrpc_is_fault($ret)) {
284 $this->error_log('Fault Code ' . $ret['faultCode'] . ': ' .
285 $ret['faultString'], $backtrace_level, true);
292 $this->trace[] = array('method' => $method,
294 'runtime' => $t1 - $t0,
296 'errors' => $this->errors);
297 $this->errors = array();
303 if (!empty($this->calls)) {
304 $this->error_log ('Warning: multicall already in progress');
307 $this->multicall = true;
310 function xmlrpc_is_fault($arr) {
311 // check if xmlrpc_is_fault exists
312 return is_array($arr)
313 && array_key_exists('faultCode', $arr)
314 && array_key_exists('faultString', $arr);
318 if (!empty ($this->calls)) {
320 $results = $this->internal_call('system.multicall', array ($this->calls));
321 foreach ($results as $result) {
322 if (is_array($result)) {
323 if ($this->xmlrpc_is_fault($result)) {
324 $this->error_log('Fault Code ' . $result['faultCode'] . ': '
325 . $result['faultString'], 1, true);
327 // Thierry - march 30 2007
328 // using $adm->error() is broken with begin/commit style
329 // this is because error() uses last item in trace and checks for ['errors']
330 // when using begin/commit we do run internal_call BUT internal_call checks for
331 // multicall's result globally, not individual results, so ['errors'] comes empty
332 // I considered hacking internal_call
333 // to *NOT* maintain this->trace at all when invoked with multicall
334 // but it is too complex to get all values right
335 // so let's go for the hacky way, and just record individual errors at the right place
336 $this->trace[count($this->trace)-1]['errors'][] = end($this->errors);
348 $this->calls = array();
349 $this->multicall = false;
358 function __call($name, $args) {
359 array_unshift($args, $this->auth);
360 return $this->call($name, $args);
366 $adm = new PLCAPI(array('AuthMethod' => "capability",
367 'Username' => PLC_API_MAINTENANCE_USER,
368 'AuthString' => PLC_API_MAINTENANCE_PASSWORD));