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
16 require_once 'plc_config.php';
29 function PLCAPI($auth = NULL,
30 $server = PLC_API_HOST,
36 $this->server = $server;
39 $this->cainfo = $cainfo;
40 $this->errors = array();
41 $this->trace = array();
42 $this->calls = array();
43 $this->multicall = false;
46 function error_log($error_msg, $backtrace_level = 1)
48 $backtrace = debug_backtrace();
49 $file = $backtrace[$backtrace_level]['file'];
50 $line = $backtrace[$backtrace_level]['line'];
52 $this->errors[] = 'PLCAPI error: ' . $error_msg . ' in ' . $file . ' on line ' . $line;
53 error_log(end($this->errors));
58 if (empty($this->trace)) {
61 $last_trace = end($this->trace);
62 return implode("\\n", $last_trace['errors']);
71 function microtime_float()
73 list($usec, $sec) = explode(" ", microtime());
74 return ((float) $usec + (float) $sec);
77 function generateKey($method, $args)
79 $excluded_API_functions = array("AddSession", "GetSession", "DeleteSession", "AuthCheck", "VerifyPerson");
81 if (array_search($method, $excluded_API_functions))
84 // Key is the md5sum of method + (arguments list - session variables)
87 return md5($method . serialize(arguments));
90 function lookup($method, $args = NULL)
92 $key = $this->generateKey($method, $args);
96 $memcache = new Memcache;
97 $memcache->connect($this->server, 11211) or die ("Could not connect");
99 $result = $memcache->get($key);
101 if ($result == FALSE) {
102 $this->error_log ("MEMCACHE: " . $method . " with " . count($args) . " args lookup failed for " . $key);
106 $this->error_log ("MEMCACHE: " . $method . " with " . count($args) . " args lookup succeded for " . $key);
107 if (gettype($result) == "array")
109 else if ($result == "NULL")
112 return unserialize($result);
117 function call($method, $args = NULL)
119 if ($this->multicall) {
120 $this->calls[] = array ('methodName' => $method,
124 $result = $this->lookup($method, $args);
127 $memcache = new Memcache;
128 $memcache->connect($this->server, 11211) or die ("Could not connect");
130 $result = $this->internal_call ($method, $args, 3);
132 $key = $this->generateKey($method, $args);
135 $memcache->set($key, $result == NULL ? "NULL" : $result, false, 6000);
142 function internal_call($method, $args = NULL, $backtrace_level = 2)
146 // Verify peer certificate if talking over SSL
147 if ($this->port == 443) {
148 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 2);
149 if (!empty($this->cainfo)) {
150 curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
151 } elseif (defined('PLC_API_CA_SSL_CRT')) {
152 curl_setopt($curl, CURLOPT_CAINFO, PLC_API_CA_SSL_CRT);
159 // Set the URL for the request
160 $url .= $this->server . ':' . $this->port . '/' . $this->path;
161 curl_setopt($curl, CURLOPT_URL, $url);
163 // Marshal the XML-RPC request as a POST variable. <nil/> is an
164 // extension to the XML-RPC spec that is supported in our custom
165 // version of xmlrpc.so via the 'allow_null' output_encoding key.
166 $request = xmlrpc_encode_request($method, $args, array('allow_null' => TRUE));
167 curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
169 // Construct the HTTP header
170 $header[] = 'Content-type: text/xml';
171 $header[] = 'Content-length: ' . strlen($request);
172 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
174 // Set some miscellaneous options
175 curl_setopt($curl, CURLOPT_TIMEOUT, 180);
177 // Get the output of the request
178 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
179 $t0 = $this->microtime_float();
180 $output = curl_exec($curl);
181 $t1 = $this->microtime_float();
183 if (curl_errno($curl)) {
184 $this->error_log('curl: ' . curl_error($curl), true);
187 $ret = xmlrpc_decode($output);
188 if (is_array($ret) && xmlrpc_is_fault($ret)) {
189 $this->error_log('Fault Code ' . $ret['faultCode'] . ': ' .
190 $ret['faultString'], $backtrace_level, true);
197 $this->trace[] = array('method' => $method,
199 'runtime' => $t1 - $t0,
201 'errors' => $this->errors);
202 $this->errors = array();
209 if (!empty($this->calls)) {
210 $this->error_log ('Warning: multicall already in progress');
213 $this->multicall = true;
218 if (!empty ($this->calls)) {
220 $results = $this->internal_call ('system.multicall', array ($this->calls));
221 foreach ($results as $result) {
222 if (is_array($result)) {
223 if (xmlrpc_is_fault($result)) {
224 $this->error_log('Fault Code ' . $result['faultCode'] . ': ' .
225 $result['faultString'], 1, true);
227 // Thierry - march 30 2007
228 // using $adm->error() is broken with begin/commit style
229 // this is because error() uses last item in trace and checks for ['errors']
230 // when using begin/commit we do run internal_call BUT internal_call checks for
231 // multicall's result globally, not individual results, so ['errors'] comes empty
232 // I considered hacking internal_call
233 // to *NOT* maintain this->trace at all when invoked with multicall
234 // but it is too complex to get all values right
235 // so let's go for the hacky way, and just record individual errors at the right place
236 $this->trace[count($this->trace)-1]['errors'][] = end($this->errors);
248 $this->calls = array();
249 $this->multicall = false;
258 function __call($name, $args)
260 array_unshift($args, $this->auth);
261 return $this->call($name, $args);
267 $adm = new PLCAPI(array('AuthMethod' => "capability",
268 'Username' => PLC_API_MAINTENANCE_USER,
269 'AuthString' => PLC_API_MAINTENANCE_PASSWORD));