xmlrpc.inc

Drupal XML-RPC library. Based on the IXR - The Incutio XML-RPC Library - (c) Incutio Ltd 2002-2005 Version 1.7 (beta) - Simon Willison, 23rd May 2005 Site: http://scripts.incutio.com/xmlrpc/ Manual: http://scripts.incutio.com/xmlrpc/manual.php This version is made available under the GNU GPL License

Archivo

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

Functions

Nombreorden descendente Descripción
xmlrpc_base64
xmlrpc_base64_get_xml
xmlrpc_clear_error Clears any previous error.
xmlrpc_date
xmlrpc_date_get_xml
xmlrpc_errno Returns the last XML-RPC client error number
xmlrpc_error
xmlrpc_error_get_xml
xmlrpc_error_msg Returns the last XML-RPC client error message
xmlrpc_message Construct an object representing an XML-RPC message.
xmlrpc_message_cdata
xmlrpc_message_get
xmlrpc_message_parse Parse an XML-RPC message. If parsing fails, the faultCode and faultString will be added to the message object.
xmlrpc_message_set Store a copy of the $xmlrpc_message object temporarily.
xmlrpc_message_tag_close
xmlrpc_message_tag_open
xmlrpc_request Construct an object representing an XML-RPC request
xmlrpc_value Recursively turn a data structure into objects with 'data' and 'type' attributes.
xmlrpc_value_calculate_type Map PHP type to XML-RPC type.
xmlrpc_value_get_xml Generate XML representing the given value.
_xmlrpc Execute an XML remote procedural call. This is private function; call xmlrpc() in common.inc instead of this function.