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