xmlrpc.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. <?php
  2. /**
  3. * @file
  4. * Drupal XML-RPC library.
  5. *
  6. * 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. * Turns a data structure into objects with 'data' and 'type' attributes.
  14. *
  15. * @param $data
  16. * The data structure.
  17. * @param $type
  18. * Optional type to assign to $data.
  19. *
  20. * @return object
  21. * An XML-RPC data object containing the input $data.
  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. * Maps a PHP type to an XML-RPC type.
  45. *
  46. * @param $xmlrpc_value
  47. * Variable whose type should be mapped.
  48. *
  49. * @return string
  50. * The corresponding XML-RPC type.
  51. *
  52. * @see 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
  56. // [...] Instead, use the is_* functions.
  57. if (is_bool($xmlrpc_value->data)) {
  58. return 'boolean';
  59. }
  60. if (is_double($xmlrpc_value->data)) {
  61. return 'double';
  62. }
  63. if (is_int($xmlrpc_value->data)) {
  64. return 'int';
  65. }
  66. if (is_array($xmlrpc_value->data)) {
  67. // empty or integer-indexed arrays are 'array', string-indexed arrays 'struct'
  68. return empty($xmlrpc_value->data) || range(0, count($xmlrpc_value->data) - 1) === array_keys($xmlrpc_value->data) ? 'array' : 'struct';
  69. }
  70. if (is_object($xmlrpc_value->data)) {
  71. if (isset($xmlrpc_value->data->is_date)) {
  72. return 'date';
  73. }
  74. if (isset($xmlrpc_value->data->is_base64)) {
  75. return 'base64';
  76. }
  77. $xmlrpc_value->data = get_object_vars($xmlrpc_value->data);
  78. return 'struct';
  79. }
  80. // default
  81. return 'string';
  82. }
  83. /**
  84. * Generates XML representing the given value.
  85. *
  86. * @param $xmlrpc_value
  87. * A value to be represented in XML.
  88. *
  89. * @return
  90. * XML representation of $xmlrpc_value.
  91. */
  92. function xmlrpc_value_get_xml($xmlrpc_value) {
  93. switch ($xmlrpc_value->type) {
  94. case 'boolean':
  95. return '<boolean>' . (($xmlrpc_value->data) ? '1' : '0') . '</boolean>';
  96. case 'int':
  97. return '<int>' . $xmlrpc_value->data . '</int>';
  98. case 'double':
  99. return '<double>' . $xmlrpc_value->data . '</double>';
  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. case 'array':
  105. $return = '<array><data>' . "\n";
  106. foreach ($xmlrpc_value->data as $item) {
  107. $return .= ' <value>' . xmlrpc_value_get_xml($item) . "</value>\n";
  108. }
  109. $return .= '</data></array>';
  110. return $return;
  111. case 'struct':
  112. $return = '<struct>' . "\n";
  113. foreach ($xmlrpc_value->data as $name => $value) {
  114. $return .= " <member><name>" . check_plain($name) . "</name><value>";
  115. $return .= xmlrpc_value_get_xml($value) . "</value></member>\n";
  116. }
  117. $return .= '</struct>';
  118. return $return;
  119. case 'date':
  120. return xmlrpc_date_get_xml($xmlrpc_value->data);
  121. case 'base64':
  122. return xmlrpc_base64_get_xml($xmlrpc_value->data);
  123. }
  124. return FALSE;
  125. }
  126. /**
  127. * Constructs an object representing an XML-RPC message.
  128. *
  129. * @param $message
  130. * A string containing an XML message.
  131. *
  132. * @return object
  133. * An XML-RPC object containing the message.
  134. *
  135. * @see http://www.xmlrpc.com/spec
  136. */
  137. function xmlrpc_message($message) {
  138. $xmlrpc_message = new stdClass();
  139. // The stack used to keep track of the current array/struct
  140. $xmlrpc_message->array_structs = array();
  141. // The stack used to keep track of if things are structs or array
  142. $xmlrpc_message->array_structs_types = array();
  143. // A stack as well
  144. $xmlrpc_message->current_struct_name = array();
  145. $xmlrpc_message->message = $message;
  146. return $xmlrpc_message;
  147. }
  148. /**
  149. * Parses an XML-RPC message.
  150. *
  151. * If parsing fails, the faultCode and faultString will be added to the message
  152. * object.
  153. *
  154. * @param $xmlrpc_message
  155. * An object generated by xmlrpc_message().
  156. *
  157. * @return
  158. * TRUE if parsing succeeded; FALSE otherwise.
  159. */
  160. function xmlrpc_message_parse($xmlrpc_message) {
  161. $xmlrpc_message->_parser = xml_parser_create();
  162. // Set XML parser to take the case of tags into account.
  163. xml_parser_set_option($xmlrpc_message->_parser, XML_OPTION_CASE_FOLDING, FALSE);
  164. // Set XML parser callback functions
  165. xml_set_element_handler($xmlrpc_message->_parser, 'xmlrpc_message_tag_open', 'xmlrpc_message_tag_close');
  166. xml_set_character_data_handler($xmlrpc_message->_parser, 'xmlrpc_message_cdata');
  167. xmlrpc_message_set($xmlrpc_message);
  168. // Strip XML declaration.
  169. $header = preg_replace('/<\?xml.*?\?'.'>/s', '', substr($xmlrpc_message->message, 0, 100), 1);
  170. $xml = trim(substr_replace($xmlrpc_message->message, $header, 0, 100));
  171. if ($xml == '') {
  172. return FALSE;
  173. }
  174. // Strip DTD.
  175. $header = preg_replace('/^<!DOCTYPE[^>]*+>/i', '', substr($xml, 0, 200), 1);
  176. $xml = trim(substr_replace($xml, $header, 0, 200));
  177. if ($xml == '') {
  178. return FALSE;
  179. }
  180. // Confirm the XML now starts with a valid root tag. A root tag can end in [> \t\r\n]
  181. $root_tag = substr($xml, 0, strcspn(substr($xml, 0, 20), "> \t\r\n"));
  182. // Reject a second DTD.
  183. if (strtoupper($root_tag) == '<!DOCTYPE') {
  184. return FALSE;
  185. }
  186. if (!in_array($root_tag, array('<methodCall', '<methodResponse', '<fault'))) {
  187. return FALSE;
  188. }
  189. // Skip parsing if there is an unreasonably large number of tags.
  190. try {
  191. $dom = new DOMDocument();
  192. @$dom->loadXML($xml);
  193. if ($dom->getElementsByTagName('*')->length > variable_get('xmlrpc_message_maximum_tag_count', 30000)) {
  194. return FALSE;
  195. }
  196. }
  197. catch (Exception $e) {
  198. return FALSE;
  199. }
  200. if (!xml_parse($xmlrpc_message->_parser, $xml)) {
  201. return FALSE;
  202. }
  203. xml_parser_free($xmlrpc_message->_parser);
  204. // Grab the error messages, if any.
  205. $xmlrpc_message = xmlrpc_message_get();
  206. if (!isset($xmlrpc_message->messagetype)) {
  207. return FALSE;
  208. }
  209. elseif ($xmlrpc_message->messagetype == 'fault') {
  210. $xmlrpc_message->fault_code = $xmlrpc_message->params[0]['faultCode'];
  211. $xmlrpc_message->fault_string = $xmlrpc_message->params[0]['faultString'];
  212. }
  213. return TRUE;
  214. }
  215. /**
  216. * Stores a copy of the most recent XML-RPC message object temporarily.
  217. *
  218. * @param $value
  219. * An XML-RPC message to store, or NULL to keep the last message.
  220. *
  221. * @return object
  222. * The most recently stored message.
  223. *
  224. * @see xmlrpc_message_get()
  225. */
  226. function xmlrpc_message_set($value = NULL) {
  227. static $xmlrpc_message;
  228. if ($value) {
  229. $xmlrpc_message = $value;
  230. }
  231. return $xmlrpc_message;
  232. }
  233. /**
  234. * Returns the most recently stored XML-RPC message object.
  235. *
  236. * @return object
  237. * The most recently stored message.
  238. *
  239. * @see xmlrpc_message_set()
  240. */
  241. function xmlrpc_message_get() {
  242. return xmlrpc_message_set();
  243. }
  244. /**
  245. * Handles opening tags for XML parsing in xmlrpc_message_parse().
  246. */
  247. function xmlrpc_message_tag_open($parser, $tag, $attr) {
  248. $xmlrpc_message = xmlrpc_message_get();
  249. $xmlrpc_message->current_tag_contents = '';
  250. $xmlrpc_message->last_open = $tag;
  251. switch ($tag) {
  252. case 'methodCall':
  253. case 'methodResponse':
  254. case 'fault':
  255. $xmlrpc_message->messagetype = $tag;
  256. break;
  257. // Deal with stacks of arrays and structs
  258. case 'data':
  259. $xmlrpc_message->array_structs_types[] = 'array';
  260. $xmlrpc_message->array_structs[] = array();
  261. break;
  262. case 'struct':
  263. $xmlrpc_message->array_structs_types[] = 'struct';
  264. $xmlrpc_message->array_structs[] = array();
  265. break;
  266. }
  267. xmlrpc_message_set($xmlrpc_message);
  268. }
  269. /**
  270. * Handles character data for XML parsing in xmlrpc_message_parse().
  271. */
  272. function xmlrpc_message_cdata($parser, $cdata) {
  273. $xmlrpc_message = xmlrpc_message_get();
  274. $xmlrpc_message->current_tag_contents .= $cdata;
  275. xmlrpc_message_set($xmlrpc_message);
  276. }
  277. /**
  278. * Handles closing tags for XML parsing in xmlrpc_message_parse().
  279. */
  280. function xmlrpc_message_tag_close($parser, $tag) {
  281. $xmlrpc_message = xmlrpc_message_get();
  282. $value_flag = FALSE;
  283. switch ($tag) {
  284. case 'int':
  285. case 'i4':
  286. $value = (int)trim($xmlrpc_message->current_tag_contents);
  287. $value_flag = TRUE;
  288. break;
  289. case 'double':
  290. $value = (double)trim($xmlrpc_message->current_tag_contents);
  291. $value_flag = TRUE;
  292. break;
  293. case 'string':
  294. $value = $xmlrpc_message->current_tag_contents;
  295. $value_flag = TRUE;
  296. break;
  297. case 'dateTime.iso8601':
  298. $value = xmlrpc_date(trim($xmlrpc_message->current_tag_contents));
  299. // $value = $iso->getTimestamp();
  300. $value_flag = TRUE;
  301. break;
  302. case 'value':
  303. // If no type is indicated, the type is string
  304. // We take special care for empty values
  305. if (trim($xmlrpc_message->current_tag_contents) != '' || (isset($xmlrpc_message->last_open) && ($xmlrpc_message->last_open == 'value'))) {
  306. $value = (string) $xmlrpc_message->current_tag_contents;
  307. $value_flag = TRUE;
  308. }
  309. unset($xmlrpc_message->last_open);
  310. break;
  311. case 'boolean':
  312. $value = (boolean)trim($xmlrpc_message->current_tag_contents);
  313. $value_flag = TRUE;
  314. break;
  315. case 'base64':
  316. $value = base64_decode(trim($xmlrpc_message->current_tag_contents));
  317. $value_flag = TRUE;
  318. break;
  319. // Deal with stacks of arrays and structs
  320. case 'data':
  321. case 'struct':
  322. $value = array_pop($xmlrpc_message->array_structs);
  323. array_pop($xmlrpc_message->array_structs_types);
  324. $value_flag = TRUE;
  325. break;
  326. case 'member':
  327. array_pop($xmlrpc_message->current_struct_name);
  328. break;
  329. case 'name':
  330. $xmlrpc_message->current_struct_name[] = trim($xmlrpc_message->current_tag_contents);
  331. break;
  332. case 'methodName':
  333. $xmlrpc_message->methodname = trim($xmlrpc_message->current_tag_contents);
  334. break;
  335. }
  336. if ($value_flag) {
  337. if (count($xmlrpc_message->array_structs) > 0) {
  338. // Add value to struct or array
  339. if ($xmlrpc_message->array_structs_types[count($xmlrpc_message->array_structs_types) - 1] == 'struct') {
  340. // Add to struct
  341. $xmlrpc_message->array_structs[count($xmlrpc_message->array_structs) - 1][$xmlrpc_message->current_struct_name[count($xmlrpc_message->current_struct_name) - 1]] = $value;
  342. }
  343. else {
  344. // Add to array
  345. $xmlrpc_message->array_structs[count($xmlrpc_message->array_structs) - 1][] = $value;
  346. }
  347. }
  348. else {
  349. // Just add as a parameter
  350. $xmlrpc_message->params[] = $value;
  351. }
  352. }
  353. if (!in_array($tag, array("data", "struct", "member"))) {
  354. $xmlrpc_message->current_tag_contents = '';
  355. }
  356. xmlrpc_message_set($xmlrpc_message);
  357. }
  358. /**
  359. * Constructs an object representing an XML-RPC request.
  360. *
  361. * @param $method
  362. * The name of the method to be called.
  363. * @param $args
  364. * An array of parameters to send with the method.
  365. *
  366. * @return object
  367. * An XML-RPC object representing the request.
  368. */
  369. function xmlrpc_request($method, $args) {
  370. $xmlrpc_request = new stdClass();
  371. $xmlrpc_request->method = $method;
  372. $xmlrpc_request->args = $args;
  373. $xmlrpc_request->xml = <<<EOD
  374. <?xml version="1.0"?>
  375. <methodCall>
  376. <methodName>{$xmlrpc_request->method}</methodName>
  377. <params>
  378. EOD;
  379. foreach ($xmlrpc_request->args as $arg) {
  380. $xmlrpc_request->xml .= '<param><value>';
  381. $v = xmlrpc_value($arg);
  382. $xmlrpc_request->xml .= xmlrpc_value_get_xml($v);
  383. $xmlrpc_request->xml .= "</value></param>\n";
  384. }
  385. $xmlrpc_request->xml .= '</params></methodCall>';
  386. return $xmlrpc_request;
  387. }
  388. /**
  389. * Generates, temporarily saves, and returns an XML-RPC error object.
  390. *
  391. * @param $code
  392. * The error code.
  393. * @param $message
  394. * The error message.
  395. * @param $reset
  396. * TRUE to empty the temporary error storage. Ignored if $code is supplied.
  397. *
  398. * @return object
  399. * An XML-RPC error object representing $code and $message, or the most
  400. * recently stored error object if omitted.
  401. */
  402. function xmlrpc_error($code = NULL, $message = NULL, $reset = FALSE) {
  403. static $xmlrpc_error;
  404. if (isset($code)) {
  405. $xmlrpc_error = new stdClass();
  406. $xmlrpc_error->is_error = TRUE;
  407. $xmlrpc_error->code = $code;
  408. $xmlrpc_error->message = $message;
  409. }
  410. elseif ($reset) {
  411. $xmlrpc_error = NULL;
  412. }
  413. return $xmlrpc_error;
  414. }
  415. /**
  416. * Converts an XML-RPC error object into XML.
  417. *
  418. * @param $xmlrpc_error
  419. * The XML-RPC error object.
  420. *
  421. * @return string
  422. * An XML representation of the error as an XML methodResponse.
  423. */
  424. function xmlrpc_error_get_xml($xmlrpc_error) {
  425. return <<<EOD
  426. <methodResponse>
  427. <fault>
  428. <value>
  429. <struct>
  430. <member>
  431. <name>faultCode</name>
  432. <value><int>{$xmlrpc_error->code}</int></value>
  433. </member>
  434. <member>
  435. <name>faultString</name>
  436. <value><string>{$xmlrpc_error->message}</string></value>
  437. </member>
  438. </struct>
  439. </value>
  440. </fault>
  441. </methodResponse>
  442. EOD;
  443. }
  444. /**
  445. * Converts a PHP or ISO date/time to an XML-RPC object.
  446. *
  447. * @param $time
  448. * A PHP timestamp or an ISO date-time string.
  449. *
  450. * @return object
  451. * An XML-RPC time/date object.
  452. */
  453. function xmlrpc_date($time) {
  454. $xmlrpc_date = new stdClass();
  455. $xmlrpc_date->is_date = TRUE;
  456. // $time can be a PHP timestamp or an ISO one
  457. if (is_numeric($time)) {
  458. $xmlrpc_date->year = gmdate('Y', $time);
  459. $xmlrpc_date->month = gmdate('m', $time);
  460. $xmlrpc_date->day = gmdate('d', $time);
  461. $xmlrpc_date->hour = gmdate('H', $time);
  462. $xmlrpc_date->minute = gmdate('i', $time);
  463. $xmlrpc_date->second = gmdate('s', $time);
  464. $xmlrpc_date->iso8601 = gmdate('Ymd\TH:i:s', $time);
  465. }
  466. else {
  467. $xmlrpc_date->iso8601 = $time;
  468. $time = str_replace(array('-', ':'), '', $time);
  469. $xmlrpc_date->year = substr($time, 0, 4);
  470. $xmlrpc_date->month = substr($time, 4, 2);
  471. $xmlrpc_date->day = substr($time, 6, 2);
  472. $xmlrpc_date->hour = substr($time, 9, 2);
  473. $xmlrpc_date->minute = substr($time, 11, 2);
  474. $xmlrpc_date->second = substr($time, 13, 2);
  475. }
  476. return $xmlrpc_date;
  477. }
  478. /**
  479. * Converts an XML-RPC date-time object into XML.
  480. *
  481. * @param $xmlrpc_date
  482. * The XML-RPC date-time object.
  483. *
  484. * @return string
  485. * An XML representation of the date/time as XML.
  486. */
  487. function xmlrpc_date_get_xml($xmlrpc_date) {
  488. return '<dateTime.iso8601>' . $xmlrpc_date->year . $xmlrpc_date->month . $xmlrpc_date->day . 'T' . $xmlrpc_date->hour . ':' . $xmlrpc_date->minute . ':' . $xmlrpc_date->second . '</dateTime.iso8601>';
  489. }
  490. /**
  491. * Returns an XML-RPC base 64 object.
  492. *
  493. * @param $data
  494. * Base 64 data to store in returned object.
  495. *
  496. * @return object
  497. * An XML-RPC base 64 object.
  498. */
  499. function xmlrpc_base64($data) {
  500. $xmlrpc_base64 = new stdClass();
  501. $xmlrpc_base64->is_base64 = TRUE;
  502. $xmlrpc_base64->data = $data;
  503. return $xmlrpc_base64;
  504. }
  505. /**
  506. * Converts an XML-RPC base 64 object into XML.
  507. *
  508. * @param $xmlrpc_base64
  509. * The XML-RPC base 64 object.
  510. *
  511. * @return string
  512. * An XML representation of the base 64 data as XML.
  513. */
  514. function xmlrpc_base64_get_xml($xmlrpc_base64) {
  515. return '<base64>' . base64_encode($xmlrpc_base64->data) . '</base64>';
  516. }
  517. /**
  518. * Performs one or more XML-RPC requests.
  519. *
  520. * @param $url
  521. * An absolute URL of the XML-RPC endpoint, e.g.,
  522. * http://example.com/xmlrpc.php
  523. * @param $args
  524. * An associative array whose keys are the methods to call and whose values
  525. * are the arguments to pass to the respective method. If multiple methods
  526. * are specified, a system.multicall is performed.
  527. * @param $options
  528. * (optional) An array of options to pass along to drupal_http_request().
  529. *
  530. * @return
  531. * A single response (single request) or an array of responses (multicall
  532. * request). Each response is the return value of the method, just as if it
  533. * has been a local function call, on success, or FALSE on failure. If FALSE
  534. * is returned, see xmlrpc_errno() and xmlrpc_error_msg() to get more
  535. * information.
  536. */
  537. function _xmlrpc($url, $args, $options = array()) {
  538. xmlrpc_clear_error();
  539. if (count($args) > 1) {
  540. $multicall_args = array();
  541. foreach ($args as $method => $call) {
  542. $multicall_args[] = array('methodName' => $method, 'params' => $call);
  543. }
  544. $method = 'system.multicall';
  545. $args = array($multicall_args);
  546. }
  547. else {
  548. $method = key($args);
  549. $args = $args[$method];
  550. }
  551. $xmlrpc_request = xmlrpc_request($method, $args);
  552. // Required options which will replace any that are passed in.
  553. $options['method'] = 'POST';
  554. $options['headers']['Content-Type'] = 'text/xml';
  555. $options['data'] = $xmlrpc_request->xml;
  556. $result = drupal_http_request($url, $options);
  557. if ($result->code != 200) {
  558. xmlrpc_error($result->code, $result->error);
  559. return FALSE;
  560. }
  561. $message = xmlrpc_message($result->data);
  562. // Now parse what we've got back
  563. if (!xmlrpc_message_parse($message)) {
  564. // XML error
  565. xmlrpc_error(-32700, t('Parse error. Not well formed'));
  566. return FALSE;
  567. }
  568. // Is the message a fault?
  569. if ($message->messagetype == 'fault') {
  570. xmlrpc_error($message->fault_code, $message->fault_string);
  571. return FALSE;
  572. }
  573. // We now know that the message is well-formed and a non-fault result.
  574. if ($method == 'system.multicall') {
  575. // Return per-method results or error objects.
  576. $return = array();
  577. foreach ($message->params[0] as $result) {
  578. if (array_keys($result) == array(0)) {
  579. $return[] = $result[0];
  580. }
  581. else {
  582. $return[] = xmlrpc_error($result['faultCode'], $result['faultString']);
  583. }
  584. }
  585. }
  586. else {
  587. $return = $message->params[0];
  588. }
  589. return $return;
  590. }
  591. /**
  592. * Returns the last XML-RPC client error number.
  593. */
  594. function xmlrpc_errno() {
  595. $error = xmlrpc_error();
  596. return ($error != NULL ? $error->code : NULL);
  597. }
  598. /**
  599. * Returns the last XML-RPC client error message.
  600. */
  601. function xmlrpc_error_msg() {
  602. $error = xmlrpc_error();
  603. return ($error != NULL ? $error->message : NULL);
  604. }
  605. /**
  606. * Clears any previously-saved errors.
  607. *
  608. * @see xmlrpc_error()
  609. */
  610. function xmlrpc_clear_error() {
  611. xmlrpc_error(NULL, NULL, TRUE);
  612. }