home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / CMS / drupal-6.0.exe / drupal-6.0 / includes / xmlrpc.inc < prev    next >
Encoding:
Text File  |  2008-01-09  |  14.1 KB  |  478 lines

  1. <?php
  2. // $Id: xmlrpc.inc,v 1.47 2008/01/09 21:52:43 goba 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.  */
  23. function xmlrpc_value($data, $type = FALSE) {
  24.   $xmlrpc_value = new stdClass();
  25.   $xmlrpc_value->data = $data;
  26.   if (!$type) {
  27.     $type = xmlrpc_value_calculate_type($xmlrpc_value);
  28.   }
  29.   $xmlrpc_value->type = $type;
  30.   if ($type == 'struct') {
  31.     // Turn all the values in the array into new xmlrpc_values
  32.     foreach ($xmlrpc_value->data as $key => $value) {
  33.       $xmlrpc_value->data[$key] = xmlrpc_value($value);
  34.     }
  35.   }
  36.   if ($type == 'array') {
  37.     for ($i = 0, $j = count($xmlrpc_value->data); $i < $j; $i++) {
  38.       $xmlrpc_value->data[$i] = xmlrpc_value($xmlrpc_value->data[$i]);
  39.     }
  40.   }
  41.   return $xmlrpc_value;
  42. }
  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.  */
  54. 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.
  56.   if (is_bool($xmlrpc_value->data)) {
  57.     return 'boolean';
  58.   }
  59.   if (is_double($xmlrpc_value->data)) {
  60.     return 'double';
  61.   }
  62.   if (is_int($xmlrpc_value->data)) {
  63.       return 'int';
  64.   }
  65.   if (is_array($xmlrpc_value->data)) {
  66.     // empty or integer-indexed arrays are 'array', string-indexed arrays 'struct'
  67.     return empty($xmlrpc_value->data) || range(0, count($xmlrpc_value->data) - 1) === array_keys($xmlrpc_value->data) ? 'array' : 'struct';
  68.   }
  69.   if (is_object($xmlrpc_value->data)) {
  70.     if ($xmlrpc_value->data->is_date) {
  71.       return 'date';
  72.     }
  73.     if ($xmlrpc_value->data->is_base64) {
  74.       return 'base64';
  75.     }
  76.     $xmlrpc_value->data = get_object_vars($xmlrpc_value->data);
  77.     return 'struct';
  78.   }
  79.   // default
  80.   return 'string';
  81. }
  82.  
  83. /**
  84.  * Generate XML representing the given value.
  85.  *
  86.  * @param $xmlrpc_value
  87.  * @return
  88.  *   XML representation of value.
  89.  */
  90. function xmlrpc_value_get_xml($xmlrpc_value) {
  91.   switch ($xmlrpc_value->type) {
  92.     case 'boolean':
  93.       return '<boolean>'. (($xmlrpc_value->data) ? '1' : '0') .'</boolean>';
  94.       break;
  95.     case 'int':
  96.       return '<int>'. $xmlrpc_value->data .'</int>';
  97.       break;
  98.     case 'double':
  99.       return '<double>'. $xmlrpc_value->data .'</double>';
  100.       break;
  101.     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.
  104.       return '<string>'. htmlspecialchars($xmlrpc_value->data) .'</string>';
  105.       break;
  106.     case 'array':
  107.       $return = '<array><data>'."\n";
  108.       foreach ($xmlrpc_value->data as $item) {
  109.         $return .= '  <value>'. xmlrpc_value_get_xml($item) ."</value>\n";
  110.       }
  111.       $return .= '</data></array>';
  112.       return $return;
  113.       break;
  114.     case 'struct':
  115.       $return = '<struct>'."\n";
  116.       foreach ($xmlrpc_value->data as $name => $value) {
  117.         $return .= "  <member><name>". check_plain($name) ."</name><value>";
  118.         $return .= xmlrpc_value_get_xml($value) ."</value></member>\n";
  119.       }
  120.       $return .= '</struct>';
  121.       return $return;
  122.       break;
  123.     case 'date':
  124.       return xmlrpc_date_get_xml($xmlrpc_value->data);
  125.       break;
  126.     case 'base64':
  127.       return xmlrpc_base64_get_xml($xmlrpc_value->data);
  128.       break;
  129.   }
  130.   return FALSE;
  131. }
  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.  */
  141. function xmlrpc_message($message) {
  142.   $xmlrpc_message = new stdClass();
  143.   $xmlrpc_message->array_structs = array();   // The stack used to keep track of the current array/struct
  144.   $xmlrpc_message->array_structs_types = array(); // The stack used to keep track of if things are structs or array
  145.   $xmlrpc_message->current_struct_name = array();  // A stack as well
  146.   $xmlrpc_message->message = $message;
  147.   return $xmlrpc_message;
  148. }
  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.  */
  159. function xmlrpc_message_parse(&$xmlrpc_message) {
  160.   // First remove the XML declaration
  161.   $xmlrpc_message->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $xmlrpc_message->message);
  162.   if (trim($xmlrpc_message->message) == '') {
  163.     return FALSE;
  164.   }
  165.   $xmlrpc_message->_parser = xml_parser_create();
  166.   // Set XML parser to take the case of tags into account.
  167.   xml_parser_set_option($xmlrpc_message->_parser, XML_OPTION_CASE_FOLDING, FALSE);
  168.   // Set XML parser callback functions
  169.   xml_set_element_handler($xmlrpc_message->_parser, 'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
  170.   xml_set_character_data_handler($xmlrpc_message->_parser, 'xmlrpc_message_cdata');
  171.   xmlrpc_message_set($xmlrpc_message);
  172.   if (!xml_parse($xmlrpc_message->_parser, $xmlrpc_message->message)) {
  173.     return FALSE;
  174.   }
  175.   xml_parser_free($xmlrpc_message->_parser);
  176.   // Grab the error messages, if any
  177.   $xmlrpc_message = xmlrpc_message_get();
  178.   if ($xmlrpc_message->messagetype == 'fault') {
  179.     $xmlrpc_message->fault_code = $xmlrpc_message->params[0]['faultCode'];
  180.     $xmlrpc_message->fault_string = $xmlrpc_message->params[0]['faultString'];
  181.   }
  182.   return TRUE;
  183. }
  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.  */
  193. function xmlrpc_message_set($value = NULL) {
  194.   static $xmlrpc_message;
  195.   if ($value) {
  196.     $xmlrpc_message = $value;
  197.   }
  198.   return $xmlrpc_message;
  199. }
  200.  
  201. function xmlrpc_message_get() {
  202.   return xmlrpc_message_set();
  203. }
  204.  
  205. function xmlrpc_message_tag_open($parser, $tag, $attr) {
  206.   $xmlrpc_message = xmlrpc_message_get();
  207.   $xmlrpc_message->current_tag_contents = '';
  208.   $xmlrpc_message->last_open = $tag;
  209.   switch ($tag) {
  210.     case 'methodCall':
  211.     case 'methodResponse':
  212.     case 'fault':
  213.       $xmlrpc_message->messagetype = $tag;
  214.       break;
  215.     // Deal with stacks of arrays and structs
  216.     case 'data':
  217.       $xmlrpc_message->array_structs_types[] = 'array';
  218.       $xmlrpc_message->array_structs[] = array();
  219.       break;
  220.     case 'struct':
  221.       $xmlrpc_message->array_structs_types[] = 'struct';
  222.       $xmlrpc_message->array_structs[] = array();
  223.       break;
  224.   }
  225.   xmlrpc_message_set($xmlrpc_message);
  226. }
  227.  
  228. function xmlrpc_message_cdata($parser, $cdata) {
  229.   $xmlrpc_message = xmlrpc_message_get();
  230.   $xmlrpc_message->current_tag_contents .= $cdata;
  231.   xmlrpc_message_set($xmlrpc_message);
  232. }
  233.  
  234. function xmlrpc_message_tag_close($parser, $tag) {
  235.   $xmlrpc_message = xmlrpc_message_get();
  236.   $value_flag = FALSE;
  237.   switch ($tag) {
  238.     case 'int':
  239.     case 'i4':
  240.       $value = (int)trim($xmlrpc_message->current_tag_contents);
  241.       $value_flag = TRUE;
  242.       break;
  243.     case 'double':
  244.       $value = (double)trim($xmlrpc_message->current_tag_contents);
  245.       $value_flag = TRUE;
  246.       break;
  247.     case 'string':
  248.       $value = $xmlrpc_message->current_tag_contents;
  249.       $value_flag = TRUE;
  250.       break;
  251.     case 'dateTime.iso8601':
  252.       $value = xmlrpc_date(trim($xmlrpc_message->current_tag_contents));
  253.       // $value = $iso->getTimestamp();
  254.       $value_flag = TRUE;
  255.       break;
  256.     case 'value':
  257.       // If no type is indicated, the type is string
  258.       // We take special care for empty values
  259.       if (trim($xmlrpc_message->current_tag_contents) != '' || $xmlrpc_message->last_open == 'value') {
  260.         $value = (string)$xmlrpc_message->current_tag_contents;
  261.         $value_flag = TRUE;
  262.       }
  263.       unset($xmlrpc_message->last_open);
  264.       break;
  265.     case 'boolean':
  266.       $value = (boolean)trim($xmlrpc_message->current_tag_contents);
  267.       $value_flag = TRUE;
  268.       break;
  269.     case 'base64':
  270.       $value = base64_decode(trim($xmlrpc_message->current_tag_contents));
  271.       $value_flag = TRUE;
  272.       break;
  273.     // Deal with stacks of arrays and structs
  274.     case 'data':
  275.     case 'struct':
  276.       $value = array_pop($xmlrpc_message->array_structs );
  277.       array_pop($xmlrpc_message->array_structs_types);
  278.       $value_flag = TRUE;
  279.       break;
  280.     case 'member':
  281.       array_pop($xmlrpc_message->current_struct_name);
  282.       break;
  283.     case 'name':
  284.       $xmlrpc_message->current_struct_name[] = trim($xmlrpc_message->current_tag_contents);
  285.       break;
  286.     case 'methodName':
  287.       $xmlrpc_message->methodname = trim($xmlrpc_message->current_tag_contents);
  288.       break;
  289.   }
  290.   if ($value_flag) {
  291.     if (count($xmlrpc_message->array_structs ) > 0) {
  292.       // Add value to struct or array
  293.       if ($xmlrpc_message->array_structs_types[count($xmlrpc_message->array_structs_types)-1] == 'struct') {
  294.         // Add to struct
  295.         $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][$xmlrpc_message->current_struct_name[count($xmlrpc_message->current_struct_name)-1]] = $value;
  296.       }
  297.       else {
  298.         // Add to array
  299.         $xmlrpc_message->array_structs [count($xmlrpc_message->array_structs )-1][] = $value;
  300.       }
  301.     }
  302.     else {
  303.       // Just add as a parameter
  304.       $xmlrpc_message->params[] = $value;
  305.     }
  306.   }
  307.   if (!in_array($tag, array("data", "struct", "member"))) {
  308.     $xmlrpc_message->current_tag_contents = '';
  309.   }
  310.   xmlrpc_message_set($xmlrpc_message);
  311. }
  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.  */
  323. function xmlrpc_request($method, $args) {
  324.   $xmlrpc_request = new stdClass();
  325.   $xmlrpc_request->method = $method;
  326.   $xmlrpc_request->args = $args;
  327.   $xmlrpc_request->xml = <<<EOD
  328. <?xml version="1.0"?>
  329. <methodCall>
  330. <methodName>{$xmlrpc_request->method}</methodName>
  331. <params>
  332.  
  333. EOD;
  334.   foreach ($xmlrpc_request->args as $arg) {
  335.     $xmlrpc_request->xml .= '<param><value>';
  336.     $v = xmlrpc_value($arg);
  337.     $xmlrpc_request->xml .= xmlrpc_value_get_xml($v);
  338.     $xmlrpc_request->xml .= "</value></param>\n";
  339.   }
  340.   $xmlrpc_request->xml .= '</params></methodCall>';
  341.   return $xmlrpc_request;
  342. }
  343.  
  344.  
  345. function xmlrpc_error($code = NULL, $message = NULL) {
  346.   static $xmlrpc_error;
  347.   if (isset($code)) {
  348.     $xmlrpc_error = new stdClass();
  349.     $xmlrpc_error->is_error = TRUE;
  350.     $xmlrpc_error->code = $code;
  351.     $xmlrpc_error->message = $message;
  352.     module_invoke('system', 'check_http_request');
  353.   }
  354.   return $xmlrpc_error;
  355. }
  356.  
  357. function xmlrpc_error_get_xml($xmlrpc_error) {
  358.   return <<<EOD
  359. <methodResponse>
  360.   <fault>
  361.   <value>
  362.     <struct>
  363.     <member>
  364.       <name>faultCode</name>
  365.       <value><int>{$xmlrpc_error->code}</int></value>
  366.     </member>
  367.     <member>
  368.       <name>faultString</name>
  369.       <value><string>{$xmlrpc_error->message}</string></value>
  370.     </member>
  371.     </struct>
  372.   </value>
  373.   </fault>
  374. </methodResponse>
  375.  
  376. EOD;
  377. }
  378.  
  379. function xmlrpc_date($time) {
  380.   $xmlrpc_date = new stdClass();
  381.   $xmlrpc_date->is_date = TRUE;
  382.   // $time can be a PHP timestamp or an ISO one
  383.   if (is_numeric($time)) {
  384.     $xmlrpc_date->year = date('Y', $time);
  385.     $xmlrpc_date->month = date('m', $time);
  386.     $xmlrpc_date->day = date('d', $time);
  387.     $xmlrpc_date->hour = date('H', $time);
  388.     $xmlrpc_date->minute = date('i', $time);
  389.     $xmlrpc_date->second = date('s', $time);
  390.     $xmlrpc_date->iso8601 = date('Ymd\TH:i:s', $time);
  391.   }
  392.   else {
  393.     $xmlrpc_date->iso8601 = $time;
  394.     $time = str_replace(array('-', ':'), '', $time);
  395.     $xmlrpc_date->year = substr($time, 0, 4);
  396.     $xmlrpc_date->month = substr($time, 4, 2);
  397.     $xmlrpc_date->day = substr($time, 6, 2);
  398.     $xmlrpc_date->hour = substr($time, 9, 2);
  399.     $xmlrpc_date->minute = substr($time, 11, 2);
  400.     $xmlrpc_date->second = substr($time, 13, 2);
  401.   }
  402.   return $xmlrpc_date;
  403. }
  404.  
  405. function xmlrpc_date_get_xml($xmlrpc_date) {
  406.   return '<dateTime.iso8601>'. $xmlrpc_date->year . $xmlrpc_date->month . $xmlrpc_date->day .'T'. $xmlrpc_date->hour .':'. $xmlrpc_date->minute .':'. $xmlrpc_date->second .'</dateTime.iso8601>';
  407. }
  408.  
  409. function xmlrpc_base64($data) {
  410.   $xmlrpc_base64 = new stdClass();
  411.   $xmlrpc_base64->is_base64 = TRUE;
  412.   $xmlrpc_base64->data = $data;
  413.   return $xmlrpc_base64;
  414. }
  415.  
  416. function xmlrpc_base64_get_xml($xmlrpc_base64) {
  417.   return '<base64>'. base64_encode($xmlrpc_base64->data) .'</base64>';
  418. }
  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.  */
  427. function _xmlrpc() {
  428.   $args = func_get_args();
  429.   $url = array_shift($args);
  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->code;
  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->message;
  477. }
  478.