xmlrpc.inc

  1. drupal
    1. 4.6 includes/xmlrpc.inc
    2. 4.7 includes/xmlrpc.inc
    3. 5 includes/xmlrpc.inc
    4. 6 includes/xmlrpc.inc
    5. 7 includes/xmlrpc.inc
    6. 8 core/includes/xmlrpc.inc

Functions & methods

NameDescription
xmlrpc_base64
xmlrpc_base64_get_xml
xmlrpc_date
xmlrpc_date_get_xml
xmlrpc_errnoReturns the last XML-RPC client error number
xmlrpc_error
xmlrpc_error_get_xml
xmlrpc_error_msgReturns the last XML-RPC client error message
xmlrpc_messageConstruct an object representing an XML-RPC message.
xmlrpc_message_cdata
xmlrpc_message_get
xmlrpc_message_parseParse an XML-RPC message. If parsing fails, the faultCode and faultString will be added to the message object.
xmlrpc_message_setStore a copy of the $xmlrpc_message object temporarily.
xmlrpc_message_tag_close
xmlrpc_message_tag_open
xmlrpc_requestConstruct an object representing an XML-RPC request
xmlrpc_valueRecursively turn a data structure into objects with 'data' and 'type' attributes.
xmlrpc_value_calculate_typeMap PHP type to XML-RPC type.
xmlrpc_value_get_xmlGenerate XML representing the given value.
_xmlrpcExecute an XML remote procedural call. This is private function; call xmlrpc() in common.inc instead of this functino.

File

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