source: sipes/cord/includes/xmlrpc.inc @ a149f73

stableversion-3.0
Last change on this file since a149f73 was 6627152, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se actualizo el cord

  • Propiedad mode establecida a 100755
File size: 15.4 KB
Línea 
1<?php
2
3/**
4 * @file
5 * Drupal XML-RPC library. Based on the IXR - The Incutio XML-RPC Library - (c) Incutio Ltd 2002-2005
6 * Version 1.7 (beta) - Simon Willison, 23rd May 2005
7 * Site:   http://scripts.incutio.com/xmlrpc/
8 * Manual: http://scripts.incutio.com/xmlrpc/manual.php
9 * This version is made available under the GNU GPL License
10 */
11
12/**
13 * Recursively turn a data structure into objects with 'data' and 'type' attributes.
14 *
15 * @param $data
16 *   The data structure.
17 * @param  $type
18 *   Optional type assign to $data.
19 * @return
20 *   Object.
21 */
22function xmlrpc_value($data, $type = FALSE) {
23  $xmlrpc_value = new stdClass();
24  $xmlrpc_value->data = $data;
25  if (!$type) {
26    $type = xmlrpc_value_calculate_type($xmlrpc_value);
27  }
28  $xmlrpc_value->type = $type;
29  if ($type == 'struct') {
30    // Turn all the values in the array into new xmlrpc_values
31    foreach ($xmlrpc_value->data as $key => $value) {
32      $xmlrpc_value->data[$key] = xmlrpc_value($value);
33    }
34  }
35  if ($type == 'array') {
36    for ($i = 0, $j = count($xmlrpc_value->data); $i < $j; $i++) {
37      $xmlrpc_value->data[$i] = xmlrpc_value($xmlrpc_value->data[$i]);
38    }
39  }
40  return $xmlrpc_value;
41}
42
43/**
44 * Map PHP type to XML-RPC type.
45 *
46 * @param $xmlrpc_value
47 *   Variable whose type should be mapped.
48 * @return
49 *   XML-RPC type as string.
50 * @see
51 *   http://www.xmlrpc.com/spec#scalars
52 */
53function xmlrpc_value_calculate_type(&$xmlrpc_value) {
54  // http://www.php.net/gettype: Never use gettype() to test for a certain type [...] Instead, use the is_* functions.
55  if (is_bool($xmlrpc_value->data)) {
56    return 'boolean';
57  }
58  if (is_double($xmlrpc_value->data)) {
59    return 'double';
60  }
61  if (is_int($xmlrpc_value->data)) {
62      return 'int';
63  }
64  if (is_array($xmlrpc_value->data)) {
65    // empty or integer-indexed arrays are 'array', string-indexed arrays 'struct'
66    return empty($xmlrpc_value->data) || range(0, count($xmlrpc_value->data) - 1) === array_keys($xmlrpc_value->data) ? 'array' : 'struct';
67  }
68  if (is_object($xmlrpc_value->data)) {
69    if ($xmlrpc_value->data->is_date) {
70      return 'date';
71    }
72    if ($xmlrpc_value->data->is_base64) {
73      return 'base64';
74    }
75    $xmlrpc_value->data = get_object_vars($xmlrpc_value->data);
76    return 'struct';
77  }
78  // default
79  return 'string';
80}
81
82/**
83 * Generate XML representing the given value.
84 *
85 * @param $xmlrpc_value
86 * @return
87 *   XML representation of value.
88 */
89function xmlrpc_value_get_xml($xmlrpc_value) {
90  switch ($xmlrpc_value->type) {
91    case 'boolean':
92      return '<boolean>'. (($xmlrpc_value->data) ? '1' : '0') .'</boolean>';
93      break;
94    case 'int':
95      return '<int>'. $xmlrpc_value->data .'</int>';
96      break;
97    case 'double':
98      return '<double>'. $xmlrpc_value->data .'</double>';
99      break;
100    case 'string':
101      // Note: we don't escape apostrophes because of the many blogging clients
102      // that don't support numerical entities (and XML in general) properly.
103      return '<string>'. htmlspecialchars($xmlrpc_value->data) .'</string>';
104      break;
105    case 'array':
106      $return = '<array><data>'."\n";
107      foreach ($xmlrpc_value->data as $item) {
108        $return .= '  <value>'. xmlrpc_value_get_xml($item) ."</value>\n";
109      }
110      $return .= '</data></array>';
111      return $return;
112      break;
113    case 'struct':
114      $return = '<struct>'."\n";
115      foreach ($xmlrpc_value->data as $name => $value) {
116        $return .= "  <member><name>". check_plain($name) ."</name><value>";
117        $return .= xmlrpc_value_get_xml($value) ."</value></member>\n";
118      }
119      $return .= '</struct>';
120      return $return;
121      break;
122    case 'date':
123      return xmlrpc_date_get_xml($xmlrpc_value->data);
124      break;
125    case 'base64':
126      return xmlrpc_base64_get_xml($xmlrpc_value->data);
127      break;
128  }
129  return FALSE;
130}
131
132/**
133 * Construct an object representing an XML-RPC message.
134 *
135 * @param $message
136 *   String containing XML as defined at http://www.xmlrpc.com/spec
137 * @return
138 *   Object
139 */
140function xmlrpc_message($message) {
141  $xmlrpc_message = new stdClass();
142  $xmlrpc_message->array_structs = array();   // The stack used to keep track of the current array/struct
143  $xmlrpc_message->array_structs_types = array(); // The stack used to keep track of if things are structs or array
144  $xmlrpc_message->current_struct_name = array();  // A stack as well
145  $xmlrpc_message->message = $message;
146  return $xmlrpc_message;
147}
148
149/**
150 * Parse an XML-RPC message. If parsing fails, the faultCode and faultString
151 * will be added to the message object.
152 *
153 * @param $xmlrpc_message
154 *   Object generated by xmlrpc_message()
155 * @return
156 *   TRUE if parsing succeeded; FALSE otherwise
157 */
158function xmlrpc_message_parse(&$xmlrpc_message) {
159  $xmlrpc_message->_parser = xml_parser_create();
160  // Set XML parser to take the case of tags into account.
161  xml_parser_set_option($xmlrpc_message->_parser, XML_OPTION_CASE_FOLDING, FALSE);
162  // Set XML parser callback functions
163  xml_set_element_handler($xmlrpc_message->_parser, 'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
164  xml_set_character_data_handler($xmlrpc_message->_parser, 'xmlrpc_message_cdata');
165  xmlrpc_message_set($xmlrpc_message);
166
167  // Strip XML declaration.
168  $header = preg_replace('/<\?xml.*?\?'.'>/s', '', substr($xmlrpc_message->message, 0, 100), 1);
169  $xml = trim(substr_replace($xmlrpc_message->message, $header, 0, 100));
170  if ($xml == '') {
171    return FALSE;
172  }
173  // Strip DTD.
174  $header = preg_replace('/^<!DOCTYPE[^>]*+>/i', '', substr($xml, 0, 200), 1);
175  $xml = trim(substr_replace($xml, $header, 0, 200));
176  if ($xml == '') {
177    return FALSE;
178  }
179  // Confirm the XML now starts with a valid root tag. A root tag can end in [> \t\r\n]
180  $root_tag = substr($xml, 0, strcspn(substr($xml, 0, 20), "> \t\r\n"));
181  // Reject a second DTD.
182  if (strtoupper($root_tag) == '<!DOCTYPE') {
183    return FALSE;
184  }
185  if (!in_array($root_tag, array('<methodCall', '<methodResponse', '<fault'))) {
186    return FALSE;
187  }
188  // Skip parsing if there is an unreasonably large number of tags.
189  // substr_count() has much better performance (compared to preg_match_all())
190  // for large payloads but is less accurate, so we check for twice the desired
191  // number of allowed tags (to take into account opening/closing tags as well
192  // as false positives).
193  if (substr_count($xml, '<') > 2 * variable_get('xmlrpc_message_maximum_tag_count', 30000)) {
194    return FALSE;
195  }
196
197  if (!xml_parse($xmlrpc_message->_parser, $xml)) {
198    return FALSE;
199  }
200  xml_parser_free($xmlrpc_message->_parser);
201  // Grab the error messages, if any
202  $xmlrpc_message = xmlrpc_message_get();
203  if (!isset($xmlrpc_message->messagetype)) {
204    return FALSE;
205  }
206  elseif ($xmlrpc_message->messagetype == 'fault') {
207    $xmlrpc_message->fault_code = $xmlrpc_message->params[0]['faultCode'];
208    $xmlrpc_message->fault_string = $xmlrpc_message->params[0]['faultString'];
209  }
210  return TRUE;
211}
212
213/**
214 * Store a copy of the $xmlrpc_message object temporarily.
215 *
216 * @param $value
217 *   Object
218 * @return
219 *   The most recently stored $xmlrpc_message
220 */
221function xmlrpc_message_set($value = NULL) {
222  static $xmlrpc_message;
223  if ($value) {
224    $xmlrpc_message = $value;
225  }
226  return $xmlrpc_message;
227}
228
229function xmlrpc_message_get() {
230  return xmlrpc_message_set();
231}
232
233function xmlrpc_message_tag_open($parser, $tag, $attr) {
234  $xmlrpc_message = xmlrpc_message_get();
235  $xmlrpc_message->current_tag_contents = '';
236  $xmlrpc_message->last_open = $tag;
237  switch ($tag) {
238    case 'methodCall':
239    case 'methodResponse':
240    case 'fault':
241      $xmlrpc_message->messagetype = $tag;
242      break;
243    // Deal with stacks of arrays and structs
244    case 'data':
245      $xmlrpc_message->array_structs_types[] = 'array';
246      $xmlrpc_message->array_structs[] = array();
247      break;
248    case 'struct':
249      $xmlrpc_message->array_structs_types[] = 'struct';
250      $xmlrpc_message->array_structs[] = array();
251      break;
252  }
253  xmlrpc_message_set($xmlrpc_message);
254}
255
256function xmlrpc_message_cdata($parser, $cdata) {
257  $xmlrpc_message = xmlrpc_message_get();
258  $xmlrpc_message->current_tag_contents .= $cdata;
259  xmlrpc_message_set($xmlrpc_message);
260}
261
262function xmlrpc_message_tag_close($parser, $tag) {
263  $xmlrpc_message = xmlrpc_message_get();
264  $value_flag = FALSE;
265  switch ($tag) {
266    case 'int':
267    case 'i4':
268      $value = (int)trim($xmlrpc_message->current_tag_contents);
269      $value_flag = TRUE;
270      break;
271    case 'double':
272      $value = (double)trim($xmlrpc_message->current_tag_contents);
273      $value_flag = TRUE;
274      break;
275    case 'string':
276      $value = $xmlrpc_message->current_tag_contents;
277      $value_flag = TRUE;
278      break;
279    case 'dateTime.iso8601':
280      $value = xmlrpc_date(trim($xmlrpc_message->current_tag_contents));
281      // $value = $iso->getTimestamp();
282      $value_flag = TRUE;
283      break;
284    case 'value':
285      // If no type is indicated, the type is string
286      // We take special care for empty values
287      if (trim($xmlrpc_message->current_tag_contents) != '' || (isset($xmlrpc_message->last_open) && ($xmlrpc_message->last_open == 'value'))) {
288        $value = (string)$xmlrpc_message->current_tag_contents;
289        $value_flag = TRUE;
290      }
291      unset($xmlrpc_message->last_open);
292      break;
293    case 'boolean':
294      $value = (boolean)trim($xmlrpc_message->current_tag_contents);
295      $value_flag = TRUE;
296      break;
297    case 'base64':
298      $value = base64_decode(trim($xmlrpc_message->current_tag_contents));
299      $value_flag = TRUE;
300      break;
301    // Deal with stacks of arrays and structs
302    case 'data':
303    case 'struct':
304      $value = array_pop($xmlrpc_message->array_structs );
305      array_pop($xmlrpc_message->array_structs_types);
306      $value_flag = TRUE;
307      break;
308    case 'member':
309      array_pop($xmlrpc_message->current_struct_name);
310      break;
311    case 'name':
312      $xmlrpc_message->current_struct_name[] = trim($xmlrpc_message->current_tag_contents);
313      break;
314    case 'methodName':
315      $xmlrpc_message->methodname = trim($xmlrpc_message->current_tag_contents);
316      break;
317  }
318  if ($value_flag) {
319    if (count($xmlrpc_message->array_structs ) > 0) {
320      // Add value to struct or array
321      if ($xmlrpc_message->array_structs_types[count($xmlrpc_message->array_structs_types)-1] == 'struct') {
322        // Add to struct
323        $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][$xmlrpc_message->current_struct_name[count($xmlrpc_message->current_struct_name)-1]] = $value;
324      }
325      else {
326        // Add to array
327        $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][] = $value;
328      }
329    }
330    else {
331      // Just add as a parameter
332      $xmlrpc_message->params[] = $value;
333    }
334  }
335  if (!in_array($tag, array("data", "struct", "member"))) {
336    $xmlrpc_message->current_tag_contents = '';
337  }
338  xmlrpc_message_set($xmlrpc_message);
339}
340
341/**
342 * Construct an object representing an XML-RPC request
343 *
344 * @param $method
345 *   The name of the method to be called
346 * @param $args
347 *   An array of parameters to send with the method.
348 * @return
349 *   Object
350 */
351function xmlrpc_request($method, $args) {
352  $xmlrpc_request = new stdClass();
353  $xmlrpc_request->method = $method;
354  $xmlrpc_request->args = $args;
355  $xmlrpc_request->xml = <<<EOD
356<?xml version="1.0"?>
357<methodCall>
358<methodName>{$xmlrpc_request->method}</methodName>
359<params>
360
361EOD;
362  foreach ($xmlrpc_request->args as $arg) {
363    $xmlrpc_request->xml .= '<param><value>';
364    $v = xmlrpc_value($arg);
365    $xmlrpc_request->xml .= xmlrpc_value_get_xml($v);
366    $xmlrpc_request->xml .= "</value></param>\n";
367  }
368  $xmlrpc_request->xml .= '</params></methodCall>';
369  return $xmlrpc_request;
370}
371
372
373function xmlrpc_error($code = NULL, $message = NULL, $reset = FALSE) {
374  static $xmlrpc_error;
375  if (isset($code)) {
376    $xmlrpc_error = new stdClass();
377    $xmlrpc_error->is_error = TRUE;
378    $xmlrpc_error->code = $code;
379    $xmlrpc_error->message = $message;
380  }
381  elseif ($reset) {
382    $xmlrpc_error = NULL;
383  }
384  return $xmlrpc_error;
385}
386
387function xmlrpc_error_get_xml($xmlrpc_error) {
388  return <<<EOD
389<methodResponse>
390  <fault>
391  <value>
392    <struct>
393    <member>
394      <name>faultCode</name>
395      <value><int>{$xmlrpc_error->code}</int></value>
396    </member>
397    <member>
398      <name>faultString</name>
399      <value><string>{$xmlrpc_error->message}</string></value>
400    </member>
401    </struct>
402  </value>
403  </fault>
404</methodResponse>
405
406EOD;
407}
408
409function xmlrpc_date($time) {
410  $xmlrpc_date = new stdClass();
411  $xmlrpc_date->is_date = TRUE;
412  // $time can be a PHP timestamp or an ISO one
413  if (is_numeric($time)) {
414    $xmlrpc_date->year = gmdate('Y', $time);
415    $xmlrpc_date->month = gmdate('m', $time);
416    $xmlrpc_date->day = gmdate('d', $time);
417    $xmlrpc_date->hour = gmdate('H', $time);
418    $xmlrpc_date->minute = gmdate('i', $time);
419    $xmlrpc_date->second = gmdate('s', $time);
420    $xmlrpc_date->iso8601 = gmdate('Ymd\TH:i:s', $time);
421  }
422  else {
423    $xmlrpc_date->iso8601 = $time;
424    $time = str_replace(array('-', ':'), '', $time);
425    $xmlrpc_date->year = substr($time, 0, 4);
426    $xmlrpc_date->month = substr($time, 4, 2);
427    $xmlrpc_date->day = substr($time, 6, 2);
428    $xmlrpc_date->hour = substr($time, 9, 2);
429    $xmlrpc_date->minute = substr($time, 11, 2);
430    $xmlrpc_date->second = substr($time, 13, 2);
431  }
432  return $xmlrpc_date;
433}
434
435function xmlrpc_date_get_xml($xmlrpc_date) {
436  return '<dateTime.iso8601>'. $xmlrpc_date->year . $xmlrpc_date->month . $xmlrpc_date->day .'T'. $xmlrpc_date->hour .':'. $xmlrpc_date->minute .':'. $xmlrpc_date->second .'</dateTime.iso8601>';
437}
438
439function xmlrpc_base64($data) {
440  $xmlrpc_base64 = new stdClass();
441  $xmlrpc_base64->is_base64 = TRUE;
442  $xmlrpc_base64->data = $data;
443  return $xmlrpc_base64;
444}
445
446function xmlrpc_base64_get_xml($xmlrpc_base64) {
447  return '<base64>'. base64_encode($xmlrpc_base64->data) .'</base64>';
448}
449
450/**
451 * Execute an XML remote procedural call. This is private function; call xmlrpc()
452 * in common.inc instead of this function.
453 *
454 * @return
455 *   A $xmlrpc_message object if the call succeeded; FALSE if the call failed
456 */
457function _xmlrpc() {
458  $args = func_get_args();
459  $url = array_shift($args);
460  xmlrpc_clear_error();
461  if (is_array($args[0])) {
462    $method = 'system.multicall';
463    $multicall_args = array();
464    foreach ($args[0] as $call) {
465      $multicall_args[] = array('methodName' => array_shift($call), 'params' => $call);
466    }
467    $args = array($multicall_args);
468  }
469  else {
470    $method = array_shift($args);
471  }
472  $xmlrpc_request = xmlrpc_request($method, $args);
473  $result = drupal_http_request($url, array("Content-Type" => "text/xml"), 'POST', $xmlrpc_request->xml);
474  if ($result->code != 200) {
475    xmlrpc_error($result->code, $result->error);
476    return FALSE;
477  }
478  $message = xmlrpc_message($result->data);
479  // Now parse what we've got back
480  if (!xmlrpc_message_parse($message)) {
481    // XML error
482    xmlrpc_error(-32700, t('Parse error. Not well formed'));
483    return FALSE;
484  }
485  // Is the message a fault?
486  if ($message->messagetype == 'fault') {
487    xmlrpc_error($message->fault_code, $message->fault_string);
488    return FALSE;
489  }
490  // Message must be OK
491  return $message->params[0];
492}
493
494/**
495 * Returns the last XML-RPC client error number
496 */
497function xmlrpc_errno() {
498  $error = xmlrpc_error();
499  return ($error != NULL ? $error->code : NULL);
500}
501
502/**
503 * Returns the last XML-RPC client error message
504 */
505function xmlrpc_error_msg() {
506  $error = xmlrpc_error();
507  return ($error != NULL ? $error->message : NULL);
508}
509
510/**
511 * Clears any previous error.
512 */
513function xmlrpc_clear_error() {
514  xmlrpc_error(NULL, NULL, TRUE);
515}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.