| Drupal | PHP Cross Reference | Content Management Systems |
1 <?php 2 3 /** 4 * @file 5 * Provides API for defining and handling XML-RPC requests. 6 */ 7 8 /** 9 * Invokes XML-RPC methods on this server. 10 * 11 * @param array $callbacks 12 * Array of external XML-RPC method names with the callbacks they map to. 13 */ 14 function xmlrpc_server($callbacks) { 15 $xmlrpc_server = new stdClass(); 16 // Define built-in XML-RPC method names 17 $defaults = array( 18 'system.multicall' => 'xmlrpc_server_multicall', 19 array( 20 'system.methodSignature', 21 'xmlrpc_server_method_signature', 22 array('array', 'string'), 23 'Returns an array describing the return type and required parameters of a method.', 24 ), 25 array( 26 'system.getCapabilities', 27 'xmlrpc_server_get_capabilities', 28 array('struct'), 29 'Returns a struct describing the XML-RPC specifications supported by this server.', 30 ), 31 array( 32 'system.listMethods', 33 'xmlrpc_server_list_methods', 34 array('array'), 35 'Returns an array of available methods on this server.', 36 ), 37 array( 38 'system.methodHelp', 39 'xmlrpc_server_method_help', 40 array('string', 'string'), 41 'Returns a documentation string for the specified method.', 42 ), 43 ); 44 // We build an array of all method names by combining the built-ins 45 // with those defined by modules implementing the _xmlrpc hook. 46 // Built-in methods are overridable. 47 $callbacks = array_merge($defaults, (array) $callbacks); 48 drupal_alter('xmlrpc', $callbacks); 49 foreach ($callbacks as $key => $callback) { 50 // we could check for is_array($callback) 51 if (is_int($key)) { 52 $method = $callback[0]; 53 $xmlrpc_server->callbacks[$method] = $callback[1]; 54 $xmlrpc_server->signatures[$method] = $callback[2]; 55 $xmlrpc_server->help[$method] = $callback[3]; 56 } 57 else { 58 $xmlrpc_server->callbacks[$key] = $callback; 59 $xmlrpc_server->signatures[$key] = ''; 60 $xmlrpc_server->help[$key] = ''; 61 } 62 } 63 64 $data = file_get_contents('php://input'); 65 if (!$data) { 66 print 'XML-RPC server accepts POST requests only.'; 67 drupal_exit(); 68 } 69 $xmlrpc_server->message = xmlrpc_message($data); 70 if (!xmlrpc_message_parse($xmlrpc_server->message)) { 71 xmlrpc_server_error(-32700, t('Parse error. Request not well formed.')); 72 } 73 if ($xmlrpc_server->message->messagetype != 'methodCall') { 74 xmlrpc_server_error(-32600, t('Server error. Invalid XML-RPC. Request must be a methodCall.')); 75 } 76 if (!isset($xmlrpc_server->message->params)) { 77 $xmlrpc_server->message->params = array(); 78 } 79 xmlrpc_server_set($xmlrpc_server); 80 $result = xmlrpc_server_call($xmlrpc_server, $xmlrpc_server->message->methodname, $xmlrpc_server->message->params); 81 82 if (is_object($result) && !empty($result->is_error)) { 83 xmlrpc_server_error($result); 84 } 85 // Encode the result 86 $r = xmlrpc_value($result); 87 // Create the XML 88 $xml = ' 89 <methodResponse> 90 <params> 91 <param> 92 <value>' . xmlrpc_value_get_xml($r) . '</value> 93 </param> 94 </params> 95 </methodResponse> 96 97 '; 98 // Send it 99 xmlrpc_server_output($xml); 100 } 101 102 /** 103 * Throws an XML-RPC error. 104 * 105 * @param $error 106 * An error object or integer error code. 107 * @param $message 108 * (optional) The description of the error. Used only if an integer error 109 * code was passed in. 110 */ 111 function xmlrpc_server_error($error, $message = FALSE) { 112 if ($message && !is_object($error)) { 113 $error = xmlrpc_error($error, $message); 114 } 115 xmlrpc_server_output(xmlrpc_error_get_xml($error)); 116 } 117 118 /** 119 * Sends XML-RPC output to the browser. 120 * 121 * @param string $xml 122 * XML to send to the browser. 123 */ 124 function xmlrpc_server_output($xml) { 125 $xml = '<?xml version="1.0"?>' . "\n" . $xml; 126 drupal_add_http_header('Content-Length', strlen($xml)); 127 drupal_add_http_header('Content-Type', 'text/xml'); 128 echo $xml; 129 drupal_exit(); 130 } 131 132 /** 133 * Stores a copy of an XML-RPC request temporarily. 134 * 135 * @param object $xmlrpc_server 136 * (optional) Request object created by xmlrpc_server(). Omit to leave the 137 * previous server object saved. 138 * 139 * @return 140 * The latest stored request. 141 * 142 * @see xmlrpc_server_get() 143 */ 144 function xmlrpc_server_set($xmlrpc_server = NULL) { 145 static $server; 146 if (!isset($server)) { 147 $server = $xmlrpc_server; 148 } 149 return $server; 150 } 151 152 /** 153 * Retrieves the latest stored XML-RPC request. 154 * 155 * @return object 156 * The stored request. 157 * 158 * @see xmlrpc_server_set() 159 */ 160 function xmlrpc_server_get() { 161 return xmlrpc_server_set(); 162 } 163 164 /** 165 * Dispatches an XML-RPC request and any parameters to the appropriate handler. 166 * 167 * @param object $xmlrpc_server 168 * Object containing information about this XML-RPC server, the methods it 169 * provides, their signatures, etc. 170 * @param string $methodname 171 * The external XML-RPC method name; e.g., 'system.methodHelp'. 172 * @param array $args 173 * Array containing any parameters that are to be sent along with the request. 174 * 175 * @return 176 * The results of the call. 177 */ 178 function xmlrpc_server_call($xmlrpc_server, $methodname, $args) { 179 // Make sure parameters are in an array 180 if ($args && !is_array($args)) { 181 $args = array($args); 182 } 183 // Has this method been mapped to a Drupal function by us or by modules? 184 if (!isset($xmlrpc_server->callbacks[$methodname])) { 185 return xmlrpc_error(-32601, t('Server error. Requested method @methodname not specified.', array("@methodname" => $xmlrpc_server->message->methodname))); 186 } 187 $method = $xmlrpc_server->callbacks[$methodname]; 188 $signature = $xmlrpc_server->signatures[$methodname]; 189 190 // If the method has a signature, validate the request against the signature 191 if (is_array($signature)) { 192 $ok = TRUE; 193 $return_type = array_shift($signature); 194 // Check the number of arguments 195 if (count($args) != count($signature)) { 196 return xmlrpc_error(-32602, t('Server error. Wrong number of method parameters.')); 197 } 198 // Check the argument types 199 foreach ($signature as $key => $type) { 200 $arg = $args[$key]; 201 switch ($type) { 202 case 'int': 203 case 'i4': 204 if (is_array($arg) || !is_int($arg)) { 205 $ok = FALSE; 206 } 207 break; 208 209 case 'base64': 210 case 'string': 211 if (!is_string($arg)) { 212 $ok = FALSE; 213 } 214 break; 215 216 case 'boolean': 217 if ($arg !== FALSE && $arg !== TRUE) { 218 $ok = FALSE; 219 } 220 break; 221 222 case 'float': 223 case 'double': 224 if (!is_float($arg)) { 225 $ok = FALSE; 226 } 227 break; 228 229 case 'date': 230 case 'dateTime.iso8601': 231 if (!$arg->is_date) { 232 $ok = FALSE; 233 } 234 break; 235 } 236 if (!$ok) { 237 return xmlrpc_error(-32602, t('Server error. Invalid method parameters.')); 238 } 239 } 240 } 241 242 if (!function_exists($method)) { 243 return xmlrpc_error(-32601, t('Server error. Requested function @method does not exist.', array("@method" => $method))); 244 } 245 // Call the mapped function 246 return call_user_func_array($method, $args); 247 } 248 249 /** 250 * Dispatches multiple XML-RPC requests. 251 * 252 * @param array $methodcalls 253 * An array of XML-RPC requests to make. Each request is an array with the 254 * following elements: 255 * - methodName: Name of the method to invoke. 256 * - params: Parameters to pass to the method. 257 * 258 * @return 259 * An array of the results of each request. 260 * 261 * @see xmlrpc_server_call() 262 */ 263 function xmlrpc_server_multicall($methodcalls) { 264 // See http://www.xmlrpc.com/discuss/msgReader$1208 265 $return = array(); 266 $xmlrpc_server = xmlrpc_server_get(); 267 foreach ($methodcalls as $call) { 268 $ok = TRUE; 269 if (!isset($call['methodName']) || !isset($call['params'])) { 270 $result = xmlrpc_error(3, t('Invalid syntax for system.multicall.')); 271 $ok = FALSE; 272 } 273 $method = $call['methodName']; 274 $params = $call['params']; 275 if ($method == 'system.multicall') { 276 $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.')); 277 } 278 elseif ($ok) { 279 $result = xmlrpc_server_call($xmlrpc_server, $method, $params); 280 } 281 if (is_object($result) && !empty($result->is_error)) { 282 $return[] = array( 283 'faultCode' => $result->code, 284 'faultString' => $result->message, 285 ); 286 } 287 else { 288 $return[] = array($result); 289 } 290 } 291 return $return; 292 } 293 294 /** 295 * Lists the methods available on this XML-RPC server. 296 * 297 * XML-RPC method system.listMethods maps to this function. 298 * 299 * @return array 300 * Array of the names of methods available on this server. 301 */ 302 function xmlrpc_server_list_methods() { 303 $xmlrpc_server = xmlrpc_server_get(); 304 return array_keys($xmlrpc_server->callbacks); 305 } 306 307 /** 308 * Returns a list of the capabilities of this server. 309 * 310 * XML-RPC method system.getCapabilities maps to this function. 311 * 312 * @return array 313 * Array of server capabilities. 314 * 315 * @see http://groups.yahoo.com/group/xml-rpc/message/2897 316 */ 317 function xmlrpc_server_get_capabilities() { 318 return array( 319 'xmlrpc' => array( 320 'specUrl' => 'http://www.xmlrpc.com/spec', 321 'specVersion' => 1, 322 ), 323 'faults_interop' => array( 324 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', 325 'specVersion' => 20010516, 326 ), 327 'system.multicall' => array( 328 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', 329 'specVersion' => 1, 330 ), 331 'introspection' => array( 332 'specUrl' => 'http://scripts.incutio.com/xmlrpc/introspection.html', 333 'specVersion' => 1, 334 ), 335 ); 336 } 337 338 /** 339 * Returns one method signature for a function. 340 * 341 * This is the function mapped to the XML-RPC method system.methodSignature. 342 * 343 * A method signature is an array of the input and output types of a method. For 344 * instance, the method signature of this function is array('array', 'string'), 345 * because it takes an array and returns a string. 346 * 347 * @param string $methodname 348 * Name of method to return a method signature for. 349 * 350 * @return array 351 * An array of arrays of types, each of the arrays representing one method 352 * signature of the function that $methodname maps to. 353 */ 354 function xmlrpc_server_method_signature($methodname) { 355 $xmlrpc_server = xmlrpc_server_get(); 356 if (!isset($xmlrpc_server->callbacks[$methodname])) { 357 return xmlrpc_error(-32601, t('Server error. Requested method @methodname not specified.', array("@methodname" => $methodname))); 358 } 359 if (!is_array($xmlrpc_server->signatures[$methodname])) { 360 return xmlrpc_error(-32601, t('Server error. Requested method @methodname signature not specified.', array("@methodname" => $methodname))); 361 } 362 // We array of types 363 $return = array(); 364 foreach ($xmlrpc_server->signatures[$methodname] as $type) { 365 $return[] = $type; 366 } 367 return array($return); 368 } 369 370 /** 371 * Returns the help for an XML-RPC method. 372 * 373 * XML-RPC method system.methodHelp maps to this function. 374 * 375 * @param string $method 376 * Name of method for which we return a help string. 377 * 378 * @return string 379 * Help text for $method. 380 */ 381 function xmlrpc_server_method_help($method) { 382 $xmlrpc_server = xmlrpc_server_get(); 383 return $xmlrpc_server->help[$method]; 384 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title