annotate includes/xmlrpcs.inc @ 15:4347c45bb494 6.7

Drupal 6.7
author Franck Deroche <webmaster@defr.org>
date Tue, 23 Dec 2008 14:32:44 +0100
parents fff6d4c8c043
children
rev   line source
webmaster@1 1 <?php
webmaster@7 2 // $Id: xmlrpcs.inc,v 1.24.2.1 2008/04/28 10:04:52 dries Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * The main entry point for XML-RPC requests.
webmaster@1 6 *
webmaster@1 7 * @param $callbacks
webmaster@1 8 * Array of external XML-RPC method names with the callbacks they map to.
webmaster@1 9 */
webmaster@1 10 function xmlrpc_server($callbacks) {
webmaster@1 11 $xmlrpc_server = new stdClass();
webmaster@1 12 // Define built-in XML-RPC method names
webmaster@1 13 $defaults = array(
webmaster@1 14 'system.multicall' => 'xmlrpc_server_multicall',
webmaster@1 15 array(
webmaster@1 16 'system.methodSignature',
webmaster@1 17 'xmlrpc_server_method_signature',
webmaster@1 18 array('array', 'string'),
webmaster@1 19 'Returns an array describing the return type and required parameters of a method.'
webmaster@1 20 ),
webmaster@1 21 array(
webmaster@1 22 'system.getCapabilities',
webmaster@1 23 'xmlrpc_server_get_capabilities',
webmaster@1 24 array('struct'),
webmaster@1 25 'Returns a struct describing the XML-RPC specifications supported by this server.'
webmaster@1 26 ),
webmaster@1 27 array(
webmaster@1 28 'system.listMethods',
webmaster@1 29 'xmlrpc_server_list_methods',
webmaster@1 30 array('array'),
webmaster@1 31 'Returns an array of available methods on this server.'),
webmaster@1 32 array(
webmaster@1 33 'system.methodHelp',
webmaster@1 34 'xmlrpc_server_method_help',
webmaster@1 35 array('string', 'string'),
webmaster@1 36 'Returns a documentation string for the specified method.')
webmaster@1 37 );
webmaster@1 38 // We build an array of all method names by combining the built-ins
webmaster@1 39 // with those defined by modules implementing the _xmlrpc hook.
webmaster@1 40 // Built-in methods are overridable.
webmaster@1 41 foreach (array_merge($defaults, (array)$callbacks) as $key => $callback) {
webmaster@1 42 // we could check for is_array($callback)
webmaster@1 43 if (is_int($key)) {
webmaster@1 44 $method = $callback[0];
webmaster@1 45 $xmlrpc_server->callbacks[$method] = $callback[1];
webmaster@1 46 $xmlrpc_server->signatures[$method] = $callback[2];
webmaster@1 47 $xmlrpc_server->help[$method] = $callback[3];
webmaster@1 48 }
webmaster@1 49 else {
webmaster@1 50 $xmlrpc_server->callbacks[$key] = $callback;
webmaster@1 51 $xmlrpc_server->signatures[$key] = '';
webmaster@1 52 $xmlrpc_server->help[$key] = '';
webmaster@1 53 }
webmaster@1 54 }
webmaster@1 55
webmaster@1 56 $data = file_get_contents('php://input');
webmaster@1 57 if (!$data) {
webmaster@1 58 die('XML-RPC server accepts POST requests only.');
webmaster@1 59 }
webmaster@1 60 $xmlrpc_server->message = xmlrpc_message($data);
webmaster@1 61 if (!xmlrpc_message_parse($xmlrpc_server->message)) {
webmaster@1 62 xmlrpc_server_error(-32700, t('Parse error. Request not well formed.'));
webmaster@1 63 }
webmaster@1 64 if ($xmlrpc_server->message->messagetype != 'methodCall') {
webmaster@1 65 xmlrpc_server_error(-32600, t('Server error. Invalid XML-RPC. Request must be a methodCall.'));
webmaster@1 66 }
webmaster@1 67 xmlrpc_server_set($xmlrpc_server);
webmaster@1 68 $result = xmlrpc_server_call($xmlrpc_server, $xmlrpc_server->message->methodname, $xmlrpc_server->message->params);
webmaster@1 69
webmaster@1 70 if ($result->is_error) {
webmaster@1 71 xmlrpc_server_error($result);
webmaster@1 72 }
webmaster@1 73 // Encode the result
webmaster@1 74 $r = xmlrpc_value($result);
webmaster@1 75 // Create the XML
webmaster@1 76 $xml = '
webmaster@1 77 <methodResponse>
webmaster@1 78 <params>
webmaster@1 79 <param>
webmaster@1 80 <value>'.
webmaster@1 81 xmlrpc_value_get_xml($r)
webmaster@1 82 .'</value>
webmaster@1 83 </param>
webmaster@1 84 </params>
webmaster@1 85 </methodResponse>
webmaster@1 86
webmaster@1 87 ';
webmaster@1 88 // Send it
webmaster@1 89 xmlrpc_server_output($xml);
webmaster@1 90 }
webmaster@1 91
webmaster@1 92 /**
webmaster@1 93 * Throw an XML-RPC error.
webmaster@1 94 *
webmaster@1 95 * @param $error
webmaster@1 96 * an error object OR integer error code
webmaster@1 97 * @param $message
webmaster@1 98 * description of error, used only if integer error code was passed
webmaster@1 99 */
webmaster@1 100 function xmlrpc_server_error($error, $message = FALSE) {
webmaster@1 101 if ($message && !is_object($error)) {
webmaster@1 102 $error = xmlrpc_error($error, $message);
webmaster@1 103 }
webmaster@1 104 xmlrpc_server_output(xmlrpc_error_get_xml($error));
webmaster@1 105 }
webmaster@1 106
webmaster@1 107 function xmlrpc_server_output($xml) {
webmaster@1 108 $xml = '<?xml version="1.0"?>'."\n". $xml;
webmaster@1 109 header('Connection: close');
webmaster@1 110 header('Content-Length: '. strlen($xml));
webmaster@1 111 header('Content-Type: text/xml');
webmaster@1 112 header('Date: '. date('r'));
webmaster@1 113 echo $xml;
webmaster@1 114 exit;
webmaster@1 115 }
webmaster@1 116
webmaster@1 117 /**
webmaster@1 118 * Store a copy of the request temporarily.
webmaster@1 119 *
webmaster@1 120 * @param $xmlrpc_server
webmaster@1 121 * Request object created by xmlrpc_server().
webmaster@1 122 */
webmaster@1 123 function xmlrpc_server_set($xmlrpc_server = NULL) {
webmaster@1 124 static $server;
webmaster@1 125 if (!isset($server)) {
webmaster@1 126 $server = $xmlrpc_server;
webmaster@1 127 }
webmaster@1 128 return $server;
webmaster@1 129 }
webmaster@1 130
webmaster@1 131 // Retrieve the stored request.
webmaster@1 132 function xmlrpc_server_get() {
webmaster@1 133 return xmlrpc_server_set();
webmaster@1 134 }
webmaster@1 135
webmaster@1 136 /**
webmaster@1 137 * Dispatch the request and any parameters to the appropriate handler.
webmaster@1 138 *
webmaster@1 139 * @param $xmlrpc_server
webmaster@1 140 * @param $methodname
webmaster@1 141 * The external XML-RPC method name, e.g. 'system.methodHelp'
webmaster@1 142 * @param $args
webmaster@1 143 * Array containing any parameters that were sent along with the request.
webmaster@1 144 */
webmaster@1 145 function xmlrpc_server_call($xmlrpc_server, $methodname, $args) {
webmaster@1 146 // Make sure parameters are in an array
webmaster@1 147 if ($args && !is_array($args)) {
webmaster@1 148 $args = array($args);
webmaster@1 149 }
webmaster@1 150 // Has this method been mapped to a Drupal function by us or by modules?
webmaster@1 151 if (!isset($xmlrpc_server->callbacks[$methodname])) {
webmaster@7 152 return xmlrpc_error(-32601, t('Server error. Requested method @methodname not specified.', array("@methodname" => $xmlrpc_server->message->methodname)));
webmaster@1 153 }
webmaster@1 154 $method = $xmlrpc_server->callbacks[$methodname];
webmaster@1 155 $signature = $xmlrpc_server->signatures[$methodname];
webmaster@1 156
webmaster@1 157 // If the method has a signature, validate the request against the signature
webmaster@1 158 if (is_array($signature)) {
webmaster@1 159 $ok = TRUE;
webmaster@1 160 $return_type = array_shift($signature);
webmaster@1 161 // Check the number of arguments
webmaster@1 162 if (count($args) != count($signature)) {
webmaster@1 163 return xmlrpc_error(-32602, t('Server error. Wrong number of method parameters.'));
webmaster@1 164 }
webmaster@1 165 // Check the argument types
webmaster@1 166 foreach ($signature as $key => $type) {
webmaster@1 167 $arg = $args[$key];
webmaster@1 168 switch ($type) {
webmaster@1 169 case 'int':
webmaster@1 170 case 'i4':
webmaster@1 171 if (is_array($arg) || !is_int($arg)) {
webmaster@1 172 $ok = FALSE;
webmaster@1 173 }
webmaster@1 174 break;
webmaster@1 175 case 'base64':
webmaster@1 176 case 'string':
webmaster@1 177 if (!is_string($arg)) {
webmaster@1 178 $ok = FALSE;
webmaster@1 179 }
webmaster@1 180 break;
webmaster@1 181 case 'boolean':
webmaster@1 182 if ($arg !== FALSE && $arg !== TRUE) {
webmaster@1 183 $ok = FALSE;
webmaster@1 184 }
webmaster@1 185 break;
webmaster@1 186 case 'float':
webmaster@1 187 case 'double':
webmaster@1 188 if (!is_float($arg)) {
webmaster@1 189 $ok = FALSE;
webmaster@1 190 }
webmaster@1 191 break;
webmaster@1 192 case 'date':
webmaster@1 193 case 'dateTime.iso8601':
webmaster@1 194 if (!$arg->is_date) {
webmaster@1 195 $ok = FALSE;
webmaster@1 196 }
webmaster@1 197 break;
webmaster@1 198 }
webmaster@1 199 if (!$ok) {
webmaster@1 200 return xmlrpc_error(-32602, t('Server error. Invalid method parameters.'));
webmaster@1 201 }
webmaster@1 202 }
webmaster@1 203 }
webmaster@1 204
webmaster@1 205 if (!function_exists($method)) {
webmaster@7 206 return xmlrpc_error(-32601, t('Server error. Requested function @method does not exist.', array("@method" => $method)));
webmaster@1 207 }
webmaster@1 208 // Call the mapped function
webmaster@1 209 return call_user_func_array($method, $args);
webmaster@1 210 }
webmaster@1 211
webmaster@1 212 function xmlrpc_server_multicall($methodcalls) {
webmaster@1 213 // See http://www.xmlrpc.com/discuss/msgReader$1208
webmaster@1 214 $return = array();
webmaster@1 215 $xmlrpc_server = xmlrpc_server_get();
webmaster@1 216 foreach ($methodcalls as $call) {
webmaster@1 217 $ok = TRUE;
webmaster@1 218 if (!isset($call['methodName']) || !isset($call['params'])) {
webmaster@1 219 $result = xmlrpc_error(3, t('Invalid syntax for system.multicall.'));
webmaster@1 220 $ok = FALSE;
webmaster@1 221 }
webmaster@1 222 $method = $call['methodName'];
webmaster@1 223 $params = $call['params'];
webmaster@1 224 if ($method == 'system.multicall') {
webmaster@1 225 $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.'));
webmaster@1 226 }
webmaster@1 227 elseif ($ok) {
webmaster@1 228 $result = xmlrpc_server_call($xmlrpc_server, $method, $params);
webmaster@1 229 }
webmaster@1 230 if ($result->is_error) {
webmaster@1 231 $return[] = array(
webmaster@1 232 'faultCode' => $result->code,
webmaster@1 233 'faultString' => $result->message
webmaster@1 234 );
webmaster@1 235 }
webmaster@1 236 else {
webmaster@1 237 $return[] = $result;
webmaster@1 238 }
webmaster@1 239 }
webmaster@1 240 return $return;
webmaster@1 241 }
webmaster@1 242
webmaster@1 243
webmaster@1 244 /**
webmaster@1 245 * XML-RPC method system.listMethods maps to this function.
webmaster@1 246 */
webmaster@1 247 function xmlrpc_server_list_methods() {
webmaster@1 248 $xmlrpc_server = xmlrpc_server_get();
webmaster@1 249 return array_keys($xmlrpc_server->callbacks);
webmaster@1 250 }
webmaster@1 251
webmaster@1 252 /**
webmaster@1 253 * XML-RPC method system.getCapabilities maps to this function.
webmaster@1 254 * See http://groups.yahoo.com/group/xml-rpc/message/2897
webmaster@1 255 */
webmaster@1 256 function xmlrpc_server_get_capabilities() {
webmaster@1 257 return array(
webmaster@1 258 'xmlrpc' => array(
webmaster@1 259 'specUrl' => 'http://www.xmlrpc.com/spec',
webmaster@1 260 'specVersion' => 1
webmaster@1 261 ),
webmaster@1 262 'faults_interop' => array(
webmaster@1 263 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
webmaster@1 264 'specVersion' => 20010516
webmaster@1 265 ),
webmaster@1 266 'system.multicall' => array(
webmaster@1 267 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
webmaster@1 268 'specVersion' => 1
webmaster@1 269 ),
webmaster@1 270 'introspection' => array(
webmaster@1 271 'specUrl' => 'http://scripts.incutio.com/xmlrpc/introspection.html',
webmaster@1 272 'specVersion' => 1
webmaster@1 273 )
webmaster@1 274 );
webmaster@1 275 }
webmaster@1 276
webmaster@1 277 /**
webmaster@1 278 * XML-RPC method system.methodSignature maps to this function.
webmaster@1 279 *
webmaster@1 280 * @param $methodname
webmaster@1 281 * Name of method for which we return a method signature.
webmaster@1 282 * @return array
webmaster@1 283 * An array of types representing the method signature of the
webmaster@1 284 * function that the methodname maps to. The methodSignature of
webmaster@1 285 * this function is 'array', 'string' because it takes an array
webmaster@1 286 * and returns a string.
webmaster@1 287 */
webmaster@1 288 function xmlrpc_server_method_signature($methodname) {
webmaster@1 289 $xmlrpc_server = xmlrpc_server_get();
webmaster@1 290 if (!isset($xmlrpc_server->callbacks[$methodname])) {
webmaster@7 291 return xmlrpc_error(-32601, t('Server error. Requested method @methodname not specified.', array("@methodname" => $methodname)));
webmaster@1 292 }
webmaster@1 293 if (!is_array($xmlrpc_server->signatures[$methodname])) {
webmaster@7 294 return xmlrpc_error(-32601, t('Server error. Requested method @methodname signature not specified.', array("@methodname" => $methodname)));
webmaster@1 295 }
webmaster@1 296 // We array of types
webmaster@1 297 $return = array();
webmaster@1 298 foreach ($xmlrpc_server->signatures[$methodname] as $type) {
webmaster@1 299 $return[] = $type;
webmaster@1 300 }
webmaster@1 301 return $return;
webmaster@1 302 }
webmaster@1 303
webmaster@1 304 /**
webmaster@1 305 * XML-RPC method system.methodHelp maps to this function.
webmaster@1 306 *
webmaster@1 307 * @param $method
webmaster@1 308 * Name of method for which we return a help string.
webmaster@1 309 */
webmaster@1 310 function xmlrpc_server_method_help($method) {
webmaster@1 311 $xmlrpc_server = xmlrpc_server_get();
webmaster@1 312 return $xmlrpc_server->help[$method];
webmaster@1 313 }