Code coverage for /20081101/includes/xmlrpc.inc

Line #Times calledCode
1
<?php
2
// $Id: xmlrpc.inc,v 1.54 2008/10/15 13:56:07 dries Exp $
3
4
/**
5
 * @file
6
 * Drupal XML-RPC library. Based on the IXR - The Incutio XML-RPC Library -
(c) Incutio Ltd 2002-2005
7
 * Version 1.7 (beta) - Simon Willison, 23rd May 2005
8
 * Site:   http://scripts.incutio.com/xmlrpc/
9
 * Manual: http://scripts.incutio.com/xmlrpc/manual.php
10
 * This version is made available under the GNU GPL License
11
 */
12
13
/**
14
 * Recursively turn a data structure into objects with 'data' and 'type'
attributes.
15
 *
16
 * @param $data
17
 *   The data structure.
18
 * @param  $type
19
 *   Optional type assign to $data.
20
 * @return
21
 *   Object.
22
 */
2323
function xmlrpc_value($data, $type = FALSE) {
2423
  $xmlrpc_value = new stdClass();
2523
  $xmlrpc_value->data = $data;
2623
  if (!$type) {
2723
    $type = xmlrpc_value_calculate_type($xmlrpc_value);
2823
  }
2923
  $xmlrpc_value->type = $type;
3023
  if ($type == 'struct') {
31
    // Turn all the values in the array into new xmlrpc_values
3213
    foreach ($xmlrpc_value->data as $key => $value) {
3313
      $xmlrpc_value->data[$key] = xmlrpc_value($value);
3413
    }
3513
  }
3623
  if ($type == 'array') {
377
    for ($i = 0, $j = count($xmlrpc_value->data); $i < $j; $i++) {
387
      $xmlrpc_value->data[$i] = xmlrpc_value($xmlrpc_value->data[$i]);
397
    }
407
  }
4123
  return $xmlrpc_value;
420
}
43
44
/**
45
 * Map PHP type to XML-RPC type.
46
 *
47
 * @param $xmlrpc_value
48
 *   Variable whose type should be mapped.
49
 * @return
50
 *   XML-RPC type as string.
51
 * @see
52
 *   http://www.xmlrpc.com/spec#scalars
53
 */
5423
function xmlrpc_value_calculate_type(&$xmlrpc_value) {
55
  // http://www.php.net/gettype: Never use gettype() to test for a certain
type [...] Instead, use the is_* functions.
5623
  if (is_bool($xmlrpc_value->data)) {
578
    return 'boolean';
580
  }
5920
  if (is_double($xmlrpc_value->data)) {
603
    return 'double';
610
  }
6220
  if (is_int($xmlrpc_value->data)) {
6312
      return 'int';
640
  }
6516
  if (is_array($xmlrpc_value->data)) {
66
    // empty or integer-indexed arrays are 'array', string-indexed arrays
'struct'
6714
    return empty($xmlrpc_value->data) || range(0,
count($xmlrpc_value->data) - 1) === array_keys($xmlrpc_value->data) ?
'array' : 'struct';
680
  }
6914
  if (is_object($xmlrpc_value->data)) {
705
    if (isset($xmlrpc_value->data->is_date)) {
714
      return 'date';
720
    }
734
    if (isset($xmlrpc_value->data->is_base64)) {
744
      return 'base64';
750
    }
760
    $xmlrpc_value->data = get_object_vars($xmlrpc_value->data);
770
    return 'struct';
780
  }
79
  // default
8014
  return 'string';
810
}
82
83
/**
84
 * Generate XML representing the given value.
85
 *
86
 * @param $xmlrpc_value
87
 * @return
88
 *   XML representation of value.
89
 */
9023
function xmlrpc_value_get_xml($xmlrpc_value) {
9123
  switch ($xmlrpc_value->type) {
9223
    case 'boolean':
938
      return '<boolean>' . (($xmlrpc_value->data) ? '1' : '0') .
'</boolean>';
940
      break;
9520
    case 'int':
9612
      return '<int>' . $xmlrpc_value->data . '</int>';
970
      break;
9816
    case 'double':
993
      return '<double>' . $xmlrpc_value->data . '</double>';
1000
      break;
10116
    case 'string':
102
      // Note: we don't escape apostrophes because of the many blogging
clients
103
      // that don't support numerical entities (and XML in general)
properly.
10414
      return '<string>' . htmlspecialchars($xmlrpc_value->data) .
'</string>';
1050
      break;
10614
    case 'array':
1077
      $return = '<array><data>' . "\n";
1087
      foreach ($xmlrpc_value->data as $item) {
1097
        $return .= '  <value>' . xmlrpc_value_get_xml($item) .
"</value>\n";
1107
      }
1117
      $return .= '</data></array>';
1127
      return $return;
1130
      break;
11414
    case 'struct':
11513
      $return = '<struct>' . "\n";
11613
      foreach ($xmlrpc_value->data as $name => $value) {
11713
        $return .= "  <member><name>" . check_plain($name) .
"</name><value>";
11813
        $return .= xmlrpc_value_get_xml($value) . "</value></member>\n";
11913
      }
12013
      $return .= '</struct>';
12113
      return $return;
1220
      break;
1235
    case 'date':
1244
      return xmlrpc_date_get_xml($xmlrpc_value->data);
1250
      break;
1264
    case 'base64':
1274
      return xmlrpc_base64_get_xml($xmlrpc_value->data);
1280
      break;
1290
  }
1300
  return FALSE;
1310
}
132
133
/**
134
 * Construct an object representing an XML-RPC message.
135
 *
136
 * @param $message
137
 *   String containing XML as defined at http://www.xmlrpc.com/spec
138
 * @return
139
 *   Object
140
 */
14123
function xmlrpc_message($message) {
14223
  $xmlrpc_message = new stdClass();
14323
  $xmlrpc_message->array_structs = array();   // The stack used to keep
track of the current array/struct
14423
  $xmlrpc_message->array_structs_types = array(); // The stack used to keep
track of if things are structs or array
14523
  $xmlrpc_message->current_struct_name = array();  // A stack as well
14623
  $xmlrpc_message->message = $message;
14723
  return $xmlrpc_message;
1480
}
149
150
/**
151
 * Parse an XML-RPC message. If parsing fails, the faultCode and
faultString
152
 * will be added to the message object.
153
 *
154
 * @param $xmlrpc_message
155
 *   Object generated by xmlrpc_message()
156
 * @return
157
 *   TRUE if parsing succeeded; FALSE otherwise
158
 */
15923
function xmlrpc_message_parse(&$xmlrpc_message) {
160
  // First remove the XML declaration
16123
  $xmlrpc_message->message = preg_replace('/<\?xml(.*)?\?' . '>/', '',
$xmlrpc_message->message);
16223
  if (trim($xmlrpc_message->message) == '') {
1630
    return FALSE;
1640
  }
16523
  $xmlrpc_message->_parser = xml_parser_create();
166
  // Set XML parser to take the case of tags into account.
16723
  xml_parser_set_option($xmlrpc_message->_parser, XML_OPTION_CASE_FOLDING,
FALSE);
168
  // Set XML parser callback functions
16923
  xml_set_element_handler($xmlrpc_message->_parser,
'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
17023
  xml_set_character_data_handler($xmlrpc_message->_parser,
'xmlrpc_message_cdata');
17123
  xmlrpc_message_set($xmlrpc_message);
17223
  if (!xml_parse($xmlrpc_message->_parser, $xmlrpc_message->message)) {
1730
    return FALSE;
1740
  }
17523
  xml_parser_free($xmlrpc_message->_parser);
176
  // Grab the error messages, if any
17723
  $xmlrpc_message = xmlrpc_message_get();
17823
  if ($xmlrpc_message->messagetype == 'fault') {
1790
    $xmlrpc_message->fault_code = $xmlrpc_message->params[0]['faultCode'];
1800
    $xmlrpc_message->fault_string =
$xmlrpc_message->params[0]['faultString'];
1810
  }
18223
  return TRUE;
1830
}
184
185
/**
186
 * Store a copy of the $xmlrpc_message object temporarily.
187
 *
188
 * @param $value
189
 *   Object
190
 * @return
191
 *   The most recently stored $xmlrpc_message
192
 */
19323
function xmlrpc_message_set($value = NULL) {
19423
  static $xmlrpc_message;
19523
  if ($value) {
19623
    $xmlrpc_message = $value;
19723
  }
19823
  return $xmlrpc_message;
1990
}
200
20123
function xmlrpc_message_get() {
20223
  return xmlrpc_message_set();
2030
}
204
20523
function xmlrpc_message_tag_open($parser, $tag, $attr) {
20623
  $xmlrpc_message = xmlrpc_message_get();
20723
  $xmlrpc_message->current_tag_contents = '';
20823
  $xmlrpc_message->last_open = $tag;
209
  switch ($tag) {
21023
    case 'methodCall':
21123
    case 'methodResponse':
21223
    case 'fault':
21323
      $xmlrpc_message->messagetype = $tag;
21423
      break;
215
    // Deal with stacks of arrays and structs
21623
    case 'data':
2176
      $xmlrpc_message->array_structs_types[] = 'array';
2186
      $xmlrpc_message->array_structs[] = array();
2196
      break;
22023
    case 'struct':
22110
      $xmlrpc_message->array_structs_types[] = 'struct';
22210
      $xmlrpc_message->array_structs[] = array();
22310
      break;
2240
  }
22523
  xmlrpc_message_set($xmlrpc_message);
22623
}
227
22823
function xmlrpc_message_cdata($parser, $cdata) {
22923
  $xmlrpc_message = xmlrpc_message_get();
23023
  $xmlrpc_message->current_tag_contents .= $cdata;
23123
  xmlrpc_message_set($xmlrpc_message);
23223
}
233
23423
function xmlrpc_message_tag_close($parser, $tag) {
23523
  $xmlrpc_message = xmlrpc_message_get();
23623
  $value_flag = FALSE;
237
  switch ($tag) {
23823
    case 'int':
23923
    case 'i4':
24013
      $value = (int)trim($xmlrpc_message->current_tag_contents);
24113
      $value_flag = TRUE;
24213
      break;
24323
    case 'double':
2443
      $value = (double)trim($xmlrpc_message->current_tag_contents);
2453
      $value_flag = TRUE;
2463
      break;
24723
    case 'string':
24816
      $value = $xmlrpc_message->current_tag_contents;
24916
      $value_flag = TRUE;
25016
      break;
25123
    case 'dateTime.iso8601':
2524
      $value = xmlrpc_date(trim($xmlrpc_message->current_tag_contents));
253
      // $value = $iso->getTimestamp();
2544
      $value_flag = TRUE;
2554
      break;
25623
    case 'value':
257
      // If no type is indicated, the type is string
258
      // We take special care for empty values
25923
      if (trim($xmlrpc_message->current_tag_contents) != '' ||
(isset($xmlrpc_message->last_open) && ($xmlrpc_message->last_open ==
'value'))) {
2600
        $value = (string)$xmlrpc_message->current_tag_contents;
2610
        $value_flag = TRUE;
2620
      }
26323
      unset($xmlrpc_message->last_open);
26423
      break;
26523
    case 'boolean':
2667
      $value = (boolean)trim($xmlrpc_message->current_tag_contents);
2677
      $value_flag = TRUE;
2687
      break;
26923
    case 'base64':
2704
      $value = base64_decode(trim($xmlrpc_message->current_tag_contents));
2714
      $value_flag = TRUE;
2724
      break;
273
    // Deal with stacks of arrays and structs
27423
    case 'data':
27523
    case 'struct':
27611
      $value = array_pop($xmlrpc_message->array_structs );
27711
      array_pop($xmlrpc_message->array_structs_types);
27811
      $value_flag = TRUE;
27911
      break;
28023
    case 'member':
28110
      array_pop($xmlrpc_message->current_struct_name);
28210
      break;
28323
    case 'name':
28410
      $xmlrpc_message->current_struct_name[] =
trim($xmlrpc_message->current_tag_contents);
28510
      break;
28623
    case 'methodName':
28720
      $xmlrpc_message->methodname =
trim($xmlrpc_message->current_tag_contents);
28820
      break;
2890
  }
29023
  if ($value_flag) {
29123
    if (count($xmlrpc_message->array_structs ) > 0) {
292
      // Add value to struct or array
29311
      if
($xmlrpc_message->array_structs_types[count($xmlrpc_message->array_structs_types)-1]
== 'struct') {
294
        // Add to struct
29510
        $xmlrpc_message->array_structs
[count($xmlrpc_message->array_structs
)-1][$xmlrpc_message->current_struct_name[count($xmlrpc_message->current_struct_name)-1]]
= $value;
29610
      }
297
      else {
298
        // Add to array
2996
        $xmlrpc_message->array_structs
[count($xmlrpc_message->array_structs )-1][] = $value;
300
      }
30111
    }
302
    else {
303
      // Just add as a parameter
30423
      $xmlrpc_message->params[] = $value;
305
    }
30623
  }
30723
  if (!in_array($tag, array("data", "struct", "member"))) {
30823
    $xmlrpc_message->current_tag_contents = '';
30923
  }
31023
  xmlrpc_message_set($xmlrpc_message);
31123
}
312
313
/**
314
 * Construct an object representing an XML-RPC request
315
 *
316
 * @param $method
317
 *   The name of the method to be called
318
 * @param $args
319
 *   An array of parameters to send with the method.
320
 * @return
321
 *   Object
322
 */
32323
function xmlrpc_request($method, $args) {
3243
  $xmlrpc_request = new stdClass();
3253
  $xmlrpc_request->method = $method;
3263
  $xmlrpc_request->args = $args;
3270
  $xmlrpc_request->xml = <<<EOD
3283
<?xml version="1.0"?>
329
<methodCall>
3303
<methodName>{$xmlrpc_request->method}</methodName>
331
<params>
3323
333
EOD;
3343
  foreach ($xmlrpc_request->args as $arg) {
3353
    $xmlrpc_request->xml .= '<param><value>';
3363
    $v = xmlrpc_value($arg);
3373
    $xmlrpc_request->xml .= xmlrpc_value_get_xml($v);
3383
    $xmlrpc_request->xml .= "</value></param>\n";
3393
  }
3403
  $xmlrpc_request->xml .= '</params></methodCall>';
3413
  return $xmlrpc_request;
3420
}
343
344
34523
function xmlrpc_error($code = NULL, $message = NULL) {
3460
  static $xmlrpc_error;
3470
  if (isset($code)) {
3480
    $xmlrpc_error = new stdClass();
3490
    $xmlrpc_error->is_error = TRUE;
3500
    $xmlrpc_error->code = $code;
3510
    $xmlrpc_error->message = $message;
3520
    module_invoke('system', 'check_http_request');
3530
  }
3540
  return $xmlrpc_error;
3550
}
356
35723
function xmlrpc_error_get_xml($xmlrpc_error) {
358
  return <<<EOD
3590
<methodResponse>
360
  <fault>
361
  <value>
362
    <struct>
363
    <member>
364
      <name>faultCode</name>
3650
      <value><int>{$xmlrpc_error->code}</int></value>
366
    </member>
367
    <member>
368
      <name>faultString</name>
3690
      <value><string>{$xmlrpc_error->message}</string></value>
370
    </member>
371
    </struct>
372
  </value>
373
  </fault>
374
</methodResponse>
3750
3760
EOD;
3770
}
378
37923
function xmlrpc_date($time) {
3805
  $xmlrpc_date = new stdClass();
3815
  $xmlrpc_date->is_date = TRUE;
382
  // $time can be a PHP timestamp or an ISO one
3835
  if (is_numeric($time)) {
3844
    $xmlrpc_date->year = gmdate('Y', $time);
3854
    $xmlrpc_date->month = gmdate('m', $time);
3864
    $xmlrpc_date->day = gmdate('d', $time);
3874
    $xmlrpc_date->hour = gmdate('H', $time);
3884
    $xmlrpc_date->minute = gmdate('i', $time);
3894
    $xmlrpc_date->second = gmdate('s', $time);
3904
    $xmlrpc_date->iso8601 = gmdate('Ymd\TH:i:s', $time);
3914
  }
392
  else {
3934
    $xmlrpc_date->iso8601 = $time;
3944
    $time = str_replace(array('-', ':'), '', $time);
3954
    $xmlrpc_date->year = substr($time, 0, 4);
3964
    $xmlrpc_date->month = substr($time, 4, 2);
3974
    $xmlrpc_date->day = substr($time, 6, 2);
3984
    $xmlrpc_date->hour = substr($time, 9, 2);
3994
    $xmlrpc_date->minute = substr($time, 11, 2);
4004
    $xmlrpc_date->second = substr($time, 13, 2);
401
  }
4025
  return $xmlrpc_date;
4030
}
404
40523
function xmlrpc_date_get_xml($xmlrpc_date) {
4064
  return '<dateTime.iso8601>' . $xmlrpc_date->year . $xmlrpc_date->month .
$xmlrpc_date->day . 'T' . $xmlrpc_date->hour . ':' . $xmlrpc_date->minute .
':' . $xmlrpc_date->second . '</dateTime.iso8601>';
4070
}
408
40923
function xmlrpc_base64($data) {
4104
  $xmlrpc_base64 = new stdClass();
4114
  $xmlrpc_base64->is_base64 = TRUE;
4124
  $xmlrpc_base64->data = $data;
4134
  return $xmlrpc_base64;
4140
}
415
41623
function xmlrpc_base64_get_xml($xmlrpc_base64) {
4174
  return '<base64>' . base64_encode($xmlrpc_base64->data) . '</base64>';
4180
}
419
420
/**
421
 * Execute an XML remote procedural call. This is private function; call
xmlrpc()
422
 * in common.inc instead of this function.
423
 *
424
 * @return
425
 *   A $xmlrpc_message object if the call succeeded; FALSE if the call
failed
426
 */
42723
function _xmlrpc() {
4283
  $args = func_get_args();
4293
  $url = array_shift($args);
4303
  if (is_array($args[0])) {
4311
    $method = 'system.multicall';
4321
    $multicall_args = array();
4331
    foreach ($args[0] as $call) {
4341
      $multicall_args[] = array('methodName' => array_shift($call),
'params' => $call);
4351
    }
4361
    $args = array($multicall_args);
4371
  }
438
  else {
4393
    $method = array_shift($args);
440
  }
4413
  $xmlrpc_request = xmlrpc_request($method, $args);
4423
  $result = drupal_http_request($url, array("Content-Type" => "text/xml"),
'POST', $xmlrpc_request->xml);
4433
  if ($result->code != 200) {
4440
    xmlrpc_error($result->code, $result->error);
4450
    return FALSE;
4460
  }
4473
  $message = xmlrpc_message($result->data);
448
  // Now parse what we've got back
4493
  if (!xmlrpc_message_parse($message)) {
450
    // XML error
4510
    xmlrpc_error(-32700, t('Parse error. Not well formed'));
4520
    return FALSE;
4530
  }
454
  // Is the message a fault?
4553
  if ($message->messagetype == 'fault') {
4560
    xmlrpc_error($message->fault_code, $message->fault_string);
4570
    return FALSE;
4580
  }
459
  // Message must be OK
4603
  return $message->params[0];
4610
}
462
463
/**
464
 * Returns the last XML-RPC client error number
465
 */
46623
function xmlrpc_errno() {
4670
  $error = xmlrpc_error();
4680
  return ($error != NULL ? $error->code : NULL);
4690
}
470
471
/**
472
 * Returns the last XML-RPC client error message
473
 */
47423
function xmlrpc_error_msg() {
4750
  $error = xmlrpc_error();
4760
  return ($error != NULL ? $error->message : NULL);
4770
}
47823