[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/includes/ -> xmlrpc.inc (source)

   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   */
  22  function 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   */
  53  function 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   */
  89  function 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   */
 140  function 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   */
 158  function 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    if (!xml_parse($xmlrpc_message->_parser, $xmlrpc_message->message)) {
 167      return FALSE;
 168    }
 169    xml_parser_free($xmlrpc_message->_parser);
 170    // Grab the error messages, if any
 171    $xmlrpc_message = xmlrpc_message_get();
 172    if (!isset($xmlrpc_message->messagetype)) {
 173      return FALSE;
 174    }
 175    elseif ($xmlrpc_message->messagetype == 'fault') {
 176      $xmlrpc_message->fault_code = $xmlrpc_message->params[0]['faultCode'];
 177      $xmlrpc_message->fault_string = $xmlrpc_message->params[0]['faultString'];
 178    }
 179    return TRUE;
 180  }
 181  
 182  /**
 183   * Store a copy of the $xmlrpc_message object temporarily.
 184   *
 185   * @param $value
 186   *   Object
 187   * @return
 188   *   The most recently stored $xmlrpc_message
 189   */
 190  function xmlrpc_message_set($value = NULL) {
 191    static $xmlrpc_message;
 192    if ($value) {
 193      $xmlrpc_message = $value;
 194    }
 195    return $xmlrpc_message;
 196  }
 197  
 198  function xmlrpc_message_get() {
 199    return xmlrpc_message_set();
 200  }
 201  
 202  function xmlrpc_message_tag_open($parser, $tag, $attr) {
 203    $xmlrpc_message = xmlrpc_message_get();
 204    $xmlrpc_message->current_tag_contents = '';
 205    $xmlrpc_message->last_open = $tag;
 206    switch ($tag) {
 207      case 'methodCall':
 208      case 'methodResponse':
 209      case 'fault':
 210        $xmlrpc_message->messagetype = $tag;
 211        break;
 212      // Deal with stacks of arrays and structs
 213      case 'data':
 214        $xmlrpc_message->array_structs_types[] = 'array';
 215        $xmlrpc_message->array_structs[] = array();
 216        break;
 217      case 'struct':
 218        $xmlrpc_message->array_structs_types[] = 'struct';
 219        $xmlrpc_message->array_structs[] = array();
 220        break;
 221    }
 222    xmlrpc_message_set($xmlrpc_message);
 223  }
 224  
 225  function xmlrpc_message_cdata($parser, $cdata) {
 226    $xmlrpc_message = xmlrpc_message_get();
 227    $xmlrpc_message->current_tag_contents .= $cdata;
 228    xmlrpc_message_set($xmlrpc_message);
 229  }
 230  
 231  function xmlrpc_message_tag_close($parser, $tag) {
 232    $xmlrpc_message = xmlrpc_message_get();
 233    $value_flag = FALSE;
 234    switch ($tag) {
 235      case 'int':
 236      case 'i4':
 237        $value = (int)trim($xmlrpc_message->current_tag_contents);
 238        $value_flag = TRUE;
 239        break;
 240      case 'double':
 241        $value = (double)trim($xmlrpc_message->current_tag_contents);
 242        $value_flag = TRUE;
 243        break;
 244      case 'string':
 245        $value = $xmlrpc_message->current_tag_contents;
 246        $value_flag = TRUE;
 247        break;
 248      case 'dateTime.iso8601':
 249        $value = xmlrpc_date(trim($xmlrpc_message->current_tag_contents));
 250        // $value = $iso->getTimestamp();
 251        $value_flag = TRUE;
 252        break;
 253      case 'value':
 254        // If no type is indicated, the type is string
 255        // We take special care for empty values
 256        if (trim($xmlrpc_message->current_tag_contents) != '' || (isset($xmlrpc_message->last_open) && ($xmlrpc_message->last_open == 'value'))) {
 257          $value = (string)$xmlrpc_message->current_tag_contents;
 258          $value_flag = TRUE;
 259        }
 260        unset($xmlrpc_message->last_open);
 261        break;
 262      case 'boolean':
 263        $value = (boolean)trim($xmlrpc_message->current_tag_contents);
 264        $value_flag = TRUE;
 265        break;
 266      case 'base64':
 267        $value = base64_decode(trim($xmlrpc_message->current_tag_contents));
 268        $value_flag = TRUE;
 269        break;
 270      // Deal with stacks of arrays and structs
 271      case 'data':
 272      case 'struct':
 273        $value = array_pop($xmlrpc_message->array_structs );
 274        array_pop($xmlrpc_message->array_structs_types);
 275        $value_flag = TRUE;
 276        break;
 277      case 'member':
 278        array_pop($xmlrpc_message->current_struct_name);
 279        break;
 280      case 'name':
 281        $xmlrpc_message->current_struct_name[] = trim($xmlrpc_message->current_tag_contents);
 282        break;
 283      case 'methodName':
 284        $xmlrpc_message->methodname = trim($xmlrpc_message->current_tag_contents);
 285        break;
 286    }
 287    if ($value_flag) {
 288      if (count($xmlrpc_message->array_structs ) > 0) {
 289        // Add value to struct or array
 290        if ($xmlrpc_message->array_structs_types[count($xmlrpc_message->array_structs_types)-1] == 'struct') {
 291          // Add to struct
 292          $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][$xmlrpc_message->current_struct_name[count($xmlrpc_message->current_struct_name)-1]] = $value;
 293        }
 294        else {
 295          // Add to array
 296          $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][] = $value;
 297        }
 298      }
 299      else {
 300        // Just add as a parameter
 301        $xmlrpc_message->params[] = $value;
 302      }
 303    }
 304    if (!in_array($tag, array("data", "struct", "member"))) {
 305      $xmlrpc_message->current_tag_contents = '';
 306    }
 307    xmlrpc_message_set($xmlrpc_message);
 308  }
 309  
 310  /**
 311   * Construct an object representing an XML-RPC request
 312   *
 313   * @param $method
 314   *   The name of the method to be called
 315   * @param $args
 316   *   An array of parameters to send with the method.
 317   * @return
 318   *   Object
 319   */
 320  function xmlrpc_request($method, $args) {
 321    $xmlrpc_request = new stdClass();
 322    $xmlrpc_request->method = $method;
 323    $xmlrpc_request->args = $args;
 324    $xmlrpc_request->xml = <<<EOD
 325  <?xml version="1.0"?>
 326  <methodCall>
 327  <methodName>{$xmlrpc_request->method}</methodName>
 328  <params>
 329  
 330  EOD;
 331    foreach ($xmlrpc_request->args as $arg) {
 332      $xmlrpc_request->xml .= '<param><value>';
 333      $v = xmlrpc_value($arg);
 334      $xmlrpc_request->xml .= xmlrpc_value_get_xml($v);
 335      $xmlrpc_request->xml .= "</value></param>\n";
 336    }
 337    $xmlrpc_request->xml .= '</params></methodCall>';
 338    return $xmlrpc_request;
 339  }
 340  
 341  
 342  function xmlrpc_error($code = NULL, $message = NULL, $reset = FALSE) {
 343    static $xmlrpc_error;
 344    if (isset($code)) {
 345      $xmlrpc_error = new stdClass();
 346      $xmlrpc_error->is_error = TRUE;
 347      $xmlrpc_error->code = $code;
 348      $xmlrpc_error->message = $message;
 349    }
 350    elseif ($reset) {
 351      $xmlrpc_error = NULL;
 352    }
 353    return $xmlrpc_error;
 354  }
 355  
 356  function xmlrpc_error_get_xml($xmlrpc_error) {
 357    return <<<EOD
 358  <methodResponse>
 359    <fault>
 360    <value>
 361      <struct>
 362      <member>
 363        <name>faultCode</name>
 364        <value><int>{$xmlrpc_error->code}</int></value>
 365      </member>
 366      <member>
 367        <name>faultString</name>
 368        <value><string>{$xmlrpc_error->message}</string></value>
 369      </member>
 370      </struct>
 371    </value>
 372    </fault>
 373  </methodResponse>
 374  
 375  EOD;
 376  }
 377  
 378  function xmlrpc_date($time) {
 379    $xmlrpc_date = new stdClass();
 380    $xmlrpc_date->is_date = TRUE;
 381    // $time can be a PHP timestamp or an ISO one
 382    if (is_numeric($time)) {
 383      $xmlrpc_date->year = gmdate('Y', $time);
 384      $xmlrpc_date->month = gmdate('m', $time);
 385      $xmlrpc_date->day = gmdate('d', $time);
 386      $xmlrpc_date->hour = gmdate('H', $time);
 387      $xmlrpc_date->minute = gmdate('i', $time);
 388      $xmlrpc_date->second = gmdate('s', $time);
 389      $xmlrpc_date->iso8601 = gmdate('Ymd\TH:i:s', $time);
 390    }
 391    else {
 392      $xmlrpc_date->iso8601 = $time;
 393      $time = str_replace(array('-', ':'), '', $time);
 394      $xmlrpc_date->year = substr($time, 0, 4);
 395      $xmlrpc_date->month = substr($time, 4, 2);
 396      $xmlrpc_date->day = substr($time, 6, 2);
 397      $xmlrpc_date->hour = substr($time, 9, 2);
 398      $xmlrpc_date->minute = substr($time, 11, 2);
 399      $xmlrpc_date->second = substr($time, 13, 2);
 400    }
 401    return $xmlrpc_date;
 402  }
 403  
 404  function xmlrpc_date_get_xml($xmlrpc_date) {
 405    return '<dateTime.iso8601>'. $xmlrpc_date->year . $xmlrpc_date->month . $xmlrpc_date->day .'T'. $xmlrpc_date->hour .':'. $xmlrpc_date->minute .':'. $xmlrpc_date->second .'</dateTime.iso8601>';
 406  }
 407  
 408  function xmlrpc_base64($data) {
 409    $xmlrpc_base64 = new stdClass();
 410    $xmlrpc_base64->is_base64 = TRUE;
 411    $xmlrpc_base64->data = $data;
 412    return $xmlrpc_base64;
 413  }
 414  
 415  function xmlrpc_base64_get_xml($xmlrpc_base64) {
 416    return '<base64>'. base64_encode($xmlrpc_base64->data) .'</base64>';
 417  }
 418  
 419  /**
 420   * Execute an XML remote procedural call. This is private function; call xmlrpc()
 421   * in common.inc instead of this function.
 422   *
 423   * @return
 424   *   A $xmlrpc_message object if the call succeeded; FALSE if the call failed
 425   */
 426  function _xmlrpc() {
 427    $args = func_get_args();
 428    $url = array_shift($args);
 429    xmlrpc_clear_error();
 430    if (is_array($args[0])) {
 431      $method = 'system.multicall';
 432      $multicall_args = array();
 433      foreach ($args[0] as $call) {
 434        $multicall_args[] = array('methodName' => array_shift($call), 'params' => $call);
 435      }
 436      $args = array($multicall_args);
 437    }
 438    else {
 439      $method = array_shift($args);
 440    }
 441    $xmlrpc_request = xmlrpc_request($method, $args);
 442    $result = drupal_http_request($url, array("Content-Type" => "text/xml"), 'POST', $xmlrpc_request->xml);
 443    if ($result->code != 200) {
 444      xmlrpc_error($result->code, $result->error);
 445      return FALSE;
 446    }
 447    $message = xmlrpc_message($result->data);
 448    // Now parse what we've got back
 449    if (!xmlrpc_message_parse($message)) {
 450      // XML error
 451      xmlrpc_error(-32700, t('Parse error. Not well formed'));
 452      return FALSE;
 453    }
 454    // Is the message a fault?
 455    if ($message->messagetype == 'fault') {
 456      xmlrpc_error($message->fault_code, $message->fault_string);
 457      return FALSE;
 458    }
 459    // Message must be OK
 460    return $message->params[0];
 461  }
 462  
 463  /**
 464   * Returns the last XML-RPC client error number
 465   */
 466  function xmlrpc_errno() {
 467    $error = xmlrpc_error();
 468    return ($error != NULL ? $error->code : NULL);
 469  }
 470  
 471  /**
 472   * Returns the last XML-RPC client error message
 473   */
 474  function xmlrpc_error_msg() {
 475    $error = xmlrpc_error();
 476    return ($error != NULL ? $error->message : NULL);
 477  }
 478  
 479  /**
 480   * Clears any previous error.
 481   */
 482  function xmlrpc_clear_error() {
 483    xmlrpc_error(NULL, NULL, TRUE);
 484  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7