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 }