PageRenderTime 74ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/XML/RPC.php

https://github.com/chregu/fluxcms
PHP | 1958 lines | 1066 code | 203 blank | 689 comment | 201 complexity | 794b0adb94827b1f564370f5e58baf6f MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, Apache-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * PHP implementation of the XML-RPC protocol
  5. *
  6. * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
  7. * It has support for HTTP transport, proxies and authentication.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * LICENSE: License is granted to use or modify this software
  12. * ("XML-RPC for PHP") for commercial or non-commercial use provided the
  13. * copyright of the author is preserved in any distributed or derivative work.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESSED OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. * @category Web Services
  27. * @package XML_RPC
  28. * @author Edd Dumbill <edd@usefulinc.com>
  29. * @author Stig Bakken <stig@php.net>
  30. * @author Martin Jansen <mj@php.net>
  31. * @author Daniel Convissor <danielc@php.net>
  32. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  33. * @version CVS: $Id$
  34. * @link http://pear.php.net/package/XML_RPC
  35. */
  36. if (!function_exists('xml_parser_create')) {
  37. PEAR::loadExtension('xml');
  38. }
  39. /**#@+
  40. * Error constants
  41. */
  42. /**
  43. * Parameter values don't match parameter types
  44. */
  45. define('XML_RPC_ERROR_INVALID_TYPE', 101);
  46. /**
  47. * Parameter declared to be numeric but the values are not
  48. */
  49. define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
  50. /**
  51. * Communication error
  52. */
  53. define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
  54. /**
  55. * The array or struct has already been started
  56. */
  57. define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
  58. /**
  59. * Incorrect parameters submitted
  60. */
  61. define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
  62. /**
  63. * Programming error by developer
  64. */
  65. define('XML_RPC_ERROR_PROGRAMMING', 106);
  66. /**#@-*/
  67. /**
  68. * Data types
  69. * @global string $GLOBALS['XML_RPC_I4']
  70. */
  71. $GLOBALS['XML_RPC_I4'] = 'i4';
  72. /**
  73. * Data types
  74. * @global string $GLOBALS['XML_RPC_Int']
  75. */
  76. $GLOBALS['XML_RPC_Int'] = 'int';
  77. /**
  78. * Data types
  79. * @global string $GLOBALS['XML_RPC_Boolean']
  80. */
  81. $GLOBALS['XML_RPC_Boolean'] = 'boolean';
  82. /**
  83. * Data types
  84. * @global string $GLOBALS['XML_RPC_Double']
  85. */
  86. $GLOBALS['XML_RPC_Double'] = 'double';
  87. /**
  88. * Data types
  89. * @global string $GLOBALS['XML_RPC_String']
  90. */
  91. $GLOBALS['XML_RPC_String'] = 'string';
  92. /**
  93. * Data types
  94. * @global string $GLOBALS['XML_RPC_DateTime']
  95. */
  96. $GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
  97. /**
  98. * Data types
  99. * @global string $GLOBALS['XML_RPC_Base64']
  100. */
  101. $GLOBALS['XML_RPC_Base64'] = 'base64';
  102. /**
  103. * Data types
  104. * @global string $GLOBALS['XML_RPC_Array']
  105. */
  106. $GLOBALS['XML_RPC_Array'] = 'array';
  107. /**
  108. * Data types
  109. * @global string $GLOBALS['XML_RPC_Struct']
  110. */
  111. $GLOBALS['XML_RPC_Struct'] = 'struct';
  112. /**
  113. * Data type meta-types
  114. * @global array $GLOBALS['XML_RPC_Types']
  115. */
  116. $GLOBALS['XML_RPC_Types'] = array(
  117. $GLOBALS['XML_RPC_I4'] => 1,
  118. $GLOBALS['XML_RPC_Int'] => 1,
  119. $GLOBALS['XML_RPC_Boolean'] => 1,
  120. $GLOBALS['XML_RPC_String'] => 1,
  121. $GLOBALS['XML_RPC_Double'] => 1,
  122. $GLOBALS['XML_RPC_DateTime'] => 1,
  123. $GLOBALS['XML_RPC_Base64'] => 1,
  124. $GLOBALS['XML_RPC_Array'] => 2,
  125. $GLOBALS['XML_RPC_Struct'] => 3,
  126. );
  127. /**
  128. * Error message numbers
  129. * @global array $GLOBALS['XML_RPC_err']
  130. */
  131. $GLOBALS['XML_RPC_err'] = array(
  132. 'unknown_method' => 1,
  133. 'invalid_return' => 2,
  134. 'incorrect_params' => 3,
  135. 'introspect_unknown' => 4,
  136. 'http_error' => 5,
  137. 'not_response_object' => 6,
  138. 'invalid_request' => 7,
  139. );
  140. /**
  141. * Error message strings
  142. * @global array $GLOBALS['XML_RPC_str']
  143. */
  144. $GLOBALS['XML_RPC_str'] = array(
  145. 'unknown_method' => 'Unknown method',
  146. 'invalid_return' => 'Invalid return payload: enable debugging to examine incoming payload',
  147. 'incorrect_params' => 'Incorrect parameters passed to method',
  148. 'introspect_unknown' => 'Can\'t introspect: method unknown',
  149. 'http_error' => 'Didn\'t receive 200 OK from remote server.',
  150. 'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
  151. 'invalid_request' => 'Invalid request payload',
  152. );
  153. /**
  154. * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
  155. * @global string $GLOBALS['XML_RPC_defencoding']
  156. */
  157. $GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
  158. /**
  159. * User error codes start at 800
  160. * @global int $GLOBALS['XML_RPC_erruser']
  161. */
  162. $GLOBALS['XML_RPC_erruser'] = 800;
  163. /**
  164. * XML parse error codes start at 100
  165. * @global int $GLOBALS['XML_RPC_errxml']
  166. */
  167. $GLOBALS['XML_RPC_errxml'] = 100;
  168. /**
  169. * Compose backslashes for escaping regexp
  170. * @global string $GLOBALS['XML_RPC_backslash']
  171. */
  172. $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
  173. /**
  174. * Valid parents of XML elements
  175. * @global array $GLOBALS['XML_RPC_valid_parents']
  176. */
  177. $GLOBALS['XML_RPC_valid_parents'] = array(
  178. 'BOOLEAN' => array('VALUE'),
  179. 'I4' => array('VALUE'),
  180. 'INT' => array('VALUE'),
  181. 'STRING' => array('VALUE'),
  182. 'DOUBLE' => array('VALUE'),
  183. 'DATETIME.ISO8601' => array('VALUE'),
  184. 'BASE64' => array('VALUE'),
  185. 'ARRAY' => array('VALUE'),
  186. 'STRUCT' => array('VALUE'),
  187. 'PARAM' => array('PARAMS'),
  188. 'METHODNAME' => array('METHODCALL'),
  189. 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
  190. 'MEMBER' => array('STRUCT'),
  191. 'NAME' => array('MEMBER'),
  192. 'DATA' => array('ARRAY'),
  193. 'FAULT' => array('METHODRESPONSE'),
  194. 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
  195. );
  196. /**
  197. * Stores state during parsing
  198. *
  199. * quick explanation of components:
  200. * + ac = accumulates values
  201. * + qt = decides if quotes are needed for evaluation
  202. * + cm = denotes struct or array (comma needed)
  203. * + isf = indicates a fault
  204. * + lv = indicates "looking for a value": implements the logic
  205. * to allow values with no types to be strings
  206. * + params = stores parameters in method calls
  207. * + method = stores method name
  208. *
  209. * @global array $GLOBALS['XML_RPC_xh']
  210. */
  211. $GLOBALS['XML_RPC_xh'] = array();
  212. /**
  213. * Start element handler for the XML parser
  214. *
  215. * @return void
  216. */
  217. function XML_RPC_se($parser_resource, $name, $attrs)
  218. {
  219. global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String, $XML_RPC_valid_parents;
  220. $parser = (int) $parser_resource;
  221. // if invalid xmlrpc already detected, skip all processing
  222. if ($XML_RPC_xh[$parser]['isf'] >= 2) {
  223. return;
  224. }
  225. // check for correct element nesting
  226. // top level element can only be of 2 types
  227. if (count($XML_RPC_xh[$parser]['stack']) == 0) {
  228. if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
  229. $XML_RPC_xh[$parser]['isf'] = 2;
  230. $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
  231. return;
  232. }
  233. } else {
  234. // not top level element: see if parent is OK
  235. if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
  236. $name = preg_replace('[^a-zA-Z0-9._-]', '', $name);
  237. $XML_RPC_xh[$parser]['isf'] = 2;
  238. $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
  239. return;
  240. }
  241. }
  242. switch ($name) {
  243. case 'STRUCT':
  244. $XML_RPC_xh[$parser]['cm']++;
  245. // turn quoting off
  246. $XML_RPC_xh[$parser]['qt'] = 0;
  247. $cur_val = array();
  248. $cur_val['value'] = array();
  249. $cur_val['members'] = 1;
  250. array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
  251. break;
  252. case 'ARRAY':
  253. $XML_RPC_xh[$parser]['cm']++;
  254. // turn quoting off
  255. $XML_RPC_xh[$parser]['qt'] = 0;
  256. $cur_val = array();
  257. $cur_val['value'] = array();
  258. $cur_val['members'] = 0;
  259. array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
  260. break;
  261. case 'NAME':
  262. $XML_RPC_xh[$parser]['ac'] = '';
  263. break;
  264. case 'FAULT':
  265. $XML_RPC_xh[$parser]['isf'] = 1;
  266. break;
  267. case 'PARAM':
  268. $XML_RPC_xh[$parser]['valuestack'] = array();
  269. break;
  270. case 'VALUE':
  271. $XML_RPC_xh[$parser]['lv'] = 1;
  272. $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
  273. $XML_RPC_xh[$parser]['ac'] = '';
  274. $XML_RPC_xh[$parser]['qt'] = 0;
  275. // look for a value: if this is still 1 by the
  276. // time we reach the first data segment then the type is string
  277. // by implication and we need to add in a quote
  278. break;
  279. case 'I4':
  280. case 'INT':
  281. case 'STRING':
  282. case 'BOOLEAN':
  283. case 'DOUBLE':
  284. case 'DATETIME.ISO8601':
  285. case 'BASE64':
  286. $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
  287. if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
  288. $XML_RPC_xh[$parser]['qt'] = 1;
  289. if ($name == 'DATETIME.ISO8601') {
  290. $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
  291. }
  292. } elseif ($name == 'BASE64') {
  293. $XML_RPC_xh[$parser]['qt'] = 2;
  294. } else {
  295. // No quoting is required here -- but
  296. // at the end of the element we must check
  297. // for data format errors.
  298. $XML_RPC_xh[$parser]['qt'] = 0;
  299. }
  300. break;
  301. case 'MEMBER':
  302. $XML_RPC_xh[$parser]['ac'] = '';
  303. break;
  304. case 'DATA':
  305. case 'METHODCALL':
  306. case 'METHODNAME':
  307. case 'METHODRESPONSE':
  308. case 'PARAMS':
  309. // valid elements that add little to processing
  310. break;
  311. }
  312. // Save current element to stack
  313. array_unshift($XML_RPC_xh[$parser]['stack'], $name);
  314. if ($name != 'VALUE') {
  315. $XML_RPC_xh[$parser]['lv'] = 0;
  316. }
  317. }
  318. /**
  319. * End element handler for the XML parser
  320. *
  321. * @return void
  322. */
  323. function XML_RPC_ee($parser_resource, $name)
  324. {
  325. global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
  326. $parser = (int) $parser_resource;
  327. if ($XML_RPC_xh[$parser]['isf'] >= 2) {
  328. return;
  329. }
  330. // push this element from stack
  331. // NB: if XML validates, correct opening/closing is guaranteed and
  332. // we do not have to check for $name == $curr_elem.
  333. // we also checked for proper nesting at start of elements...
  334. $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
  335. switch ($name) {
  336. case 'STRUCT':
  337. case 'ARRAY':
  338. $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
  339. $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
  340. $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  341. $XML_RPC_xh[$parser]['cm']--;
  342. break;
  343. case 'NAME':
  344. $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
  345. break;
  346. case 'BOOLEAN':
  347. // special case here: we translate boolean 1 or 0 into PHP
  348. // constants true or false
  349. if ($XML_RPC_xh[$parser]['ac'] == '1') {
  350. $XML_RPC_xh[$parser]['ac'] = 'true';
  351. } else {
  352. $XML_RPC_xh[$parser]['ac'] = 'false';
  353. }
  354. $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  355. // Drop through intentionally.
  356. case 'I4':
  357. case 'INT':
  358. case 'STRING':
  359. case 'DOUBLE':
  360. case 'DATETIME.ISO8601':
  361. case 'BASE64':
  362. if ($XML_RPC_xh[$parser]['qt'] == 1) {
  363. // we use double quotes rather than single so backslashification works OK
  364. $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
  365. } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
  366. $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
  367. } elseif ($name == 'BOOLEAN') {
  368. $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
  369. } else {
  370. // we have an I4, INT or a DOUBLE
  371. // we must check that only 0123456789-.<space> are characters here
  372. if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
  373. XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
  374. XML_RPC_ERROR_NON_NUMERIC_FOUND);
  375. $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
  376. } else {
  377. // it's ok, add it on
  378. $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
  379. }
  380. }
  381. $XML_RPC_xh[$parser]['ac'] = '';
  382. $XML_RPC_xh[$parser]['qt'] = 0;
  383. $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
  384. break;
  385. case 'VALUE':
  386. if ($XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
  387. if (strlen($XML_RPC_xh[$parser]['ac']) > 0) {
  388. $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
  389. } elseif ($XML_RPC_xh[$parser]['lv'] == 1) {
  390. // The <value> element was empty.
  391. $XML_RPC_xh[$parser]['value'] = '';
  392. }
  393. }
  394. $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
  395. $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
  396. if (is_array($cur_val)) {
  397. if ($cur_val['members']==0) {
  398. $cur_val['value'][] = $temp;
  399. } else {
  400. $XML_RPC_xh[$parser]['value'] = $temp;
  401. }
  402. array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
  403. } else {
  404. $XML_RPC_xh[$parser]['value'] = $temp;
  405. }
  406. break;
  407. case 'MEMBER':
  408. $XML_RPC_xh[$parser]['ac'] = '';
  409. $XML_RPC_xh[$parser]['qt'] = 0;
  410. $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
  411. if (is_array($cur_val)) {
  412. if ($cur_val['members']==1) {
  413. $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
  414. }
  415. array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
  416. }
  417. break;
  418. case 'DATA':
  419. $XML_RPC_xh[$parser]['ac'] = '';
  420. $XML_RPC_xh[$parser]['qt'] = 0;
  421. break;
  422. case 'PARAM':
  423. $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
  424. break;
  425. case 'METHODNAME':
  426. case 'RPCMETHODNAME':
  427. $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
  428. $XML_RPC_xh[$parser]['ac']);
  429. break;
  430. }
  431. // if it's a valid type name, set the type
  432. if (isset($XML_RPC_Types[strtolower($name)])) {
  433. $XML_RPC_xh[$parser]['vt'] = strtolower($name);
  434. }
  435. }
  436. /**
  437. * Character data handler for the XML parser
  438. *
  439. * @return void
  440. */
  441. function XML_RPC_cd($parser_resource, $data)
  442. {
  443. global $XML_RPC_xh, $XML_RPC_backslash;
  444. $parser = (int) $parser_resource;
  445. if ($XML_RPC_xh[$parser]['lv'] != 3) {
  446. // "lookforvalue==3" means that we've found an entire value
  447. // and should discard any further character data
  448. if ($XML_RPC_xh[$parser]['lv'] == 1) {
  449. // if we've found text and we're just in a <value> then
  450. // turn quoting on, as this will be a string
  451. $XML_RPC_xh[$parser]['qt'] = 1;
  452. // and say we've found a value
  453. $XML_RPC_xh[$parser]['lv'] = 2;
  454. }
  455. // replace characters that eval would
  456. // do special things with
  457. if (!isset($XML_RPC_xh[$parser]['ac'])) {
  458. $XML_RPC_xh[$parser]['ac'] = '';
  459. }
  460. $XML_RPC_xh[$parser]['ac'] .= $data;
  461. }
  462. }
  463. /**
  464. * The common methods and properties for all of the XML_RPC classes
  465. *
  466. * @category Web Services
  467. * @package XML_RPC
  468. * @author Edd Dumbill <edd@usefulinc.com>
  469. * @author Stig Bakken <stig@php.net>
  470. * @author Martin Jansen <mj@php.net>
  471. * @author Daniel Convissor <danielc@php.net>
  472. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  473. * @version Release: 1.4.5
  474. * @link http://pear.php.net/package/XML_RPC
  475. */
  476. class XML_RPC_Base {
  477. /**
  478. * PEAR Error handling
  479. *
  480. * @return object PEAR_Error object
  481. */
  482. function raiseError($msg, $code)
  483. {
  484. include_once 'PEAR.php';
  485. if (is_object(@$this)) {
  486. return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
  487. } else {
  488. return PEAR::raiseError('XML_RPC: ' . $msg, $code);
  489. }
  490. }
  491. /**
  492. * Tell whether something is a PEAR_Error object
  493. *
  494. * @param mixed $value the item to check
  495. *
  496. * @return bool whether $value is a PEAR_Error object or not
  497. *
  498. * @access public
  499. */
  500. function isError($value)
  501. {
  502. return is_a($value, 'PEAR_Error');
  503. }
  504. }
  505. /**
  506. * The methods and properties for submitting XML RPC requests
  507. *
  508. * @category Web Services
  509. * @package XML_RPC
  510. * @author Edd Dumbill <edd@usefulinc.com>
  511. * @author Stig Bakken <stig@php.net>
  512. * @author Martin Jansen <mj@php.net>
  513. * @author Daniel Convissor <danielc@php.net>
  514. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  515. * @version Release: 1.4.5
  516. * @link http://pear.php.net/package/XML_RPC
  517. */
  518. class XML_RPC_Client extends XML_RPC_Base {
  519. /**
  520. * The path and name of the RPC server script you want the request to go to
  521. * @var string
  522. */
  523. var $path = '';
  524. /**
  525. * The name of the remote server to connect to
  526. * @var string
  527. */
  528. var $server = '';
  529. /**
  530. * The protocol to use in contacting the remote server
  531. * @var string
  532. */
  533. var $protocol = 'http://';
  534. /**
  535. * The port for connecting to the remote server
  536. *
  537. * The default is 80 for http:// connections
  538. * and 443 for https:// and ssl:// connections.
  539. *
  540. * @var integer
  541. */
  542. var $port = 80;
  543. /**
  544. * A user name for accessing the RPC server
  545. * @var string
  546. * @see XML_RPC_Client::setCredentials()
  547. */
  548. var $username = '';
  549. /**
  550. * A password for accessing the RPC server
  551. * @var string
  552. * @see XML_RPC_Client::setCredentials()
  553. */
  554. var $password = '';
  555. /**
  556. * The name of the proxy server to use, if any
  557. * @var string
  558. */
  559. var $proxy = '';
  560. /**
  561. * The protocol to use in contacting the proxy server, if any
  562. * @var string
  563. */
  564. var $proxy_protocol = 'http://';
  565. /**
  566. * The port for connecting to the proxy server
  567. *
  568. * The default is 8080 for http:// connections
  569. * and 443 for https:// and ssl:// connections.
  570. *
  571. * @var integer
  572. */
  573. var $proxy_port = 8080;
  574. /**
  575. * A user name for accessing the proxy server
  576. * @var string
  577. */
  578. var $proxy_user = '';
  579. /**
  580. * A password for accessing the proxy server
  581. * @var string
  582. */
  583. var $proxy_pass = '';
  584. /**
  585. * The error number, if any
  586. * @var integer
  587. */
  588. var $errno = 0;
  589. /**
  590. * The error message, if any
  591. * @var string
  592. */
  593. var $errstr = '';
  594. /**
  595. * The current debug mode (1 = on, 0 = off)
  596. * @var integer
  597. */
  598. var $debug = 0;
  599. /**
  600. * The HTTP headers for the current request.
  601. * @var string
  602. */
  603. var $headers = '';
  604. /**
  605. * Sets the object's properties
  606. *
  607. * @param string $path the path and name of the RPC server script
  608. * you want the request to go to
  609. * @param string $server the URL of the remote server to connect to.
  610. * If this parameter doesn't specify a
  611. * protocol and $port is 443, ssl:// is
  612. * assumed.
  613. * @param integer $port a port for connecting to the remote server.
  614. * Defaults to 80 for http:// connections and
  615. * 443 for https:// and ssl:// connections.
  616. * @param string $proxy the URL of the proxy server to use, if any.
  617. * If this parameter doesn't specify a
  618. * protocol and $port is 443, ssl:// is
  619. * assumed.
  620. * @param integer $proxy_port a port for connecting to the remote server.
  621. * Defaults to 8080 for http:// connections and
  622. * 443 for https:// and ssl:// connections.
  623. * @param string $proxy_user a user name for accessing the proxy server
  624. * @param string $proxy_pass a password for accessing the proxy server
  625. *
  626. * @return void
  627. */
  628. function XML_RPC_Client($path, $server, $port = 0,
  629. $proxy = '', $proxy_port = 0,
  630. $proxy_user = '', $proxy_pass = '')
  631. {
  632. $this->path = $path;
  633. $this->proxy_user = $proxy_user;
  634. $this->proxy_pass = $proxy_pass;
  635. preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
  636. if ($match[1] == '') {
  637. if ($port == 443) {
  638. $this->server = $match[2];
  639. $this->protocol = 'ssl://';
  640. $this->port = 443;
  641. } else {
  642. $this->server = $match[2];
  643. if ($port) {
  644. $this->port = $port;
  645. }
  646. }
  647. } elseif ($match[1] == 'http://') {
  648. $this->server = $match[2];
  649. if ($port) {
  650. $this->port = $port;
  651. }
  652. } else {
  653. $this->server = $match[2];
  654. $this->protocol = 'ssl://';
  655. if ($port) {
  656. $this->port = $port;
  657. } else {
  658. $this->port = 443;
  659. }
  660. }
  661. if ($proxy) {
  662. preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
  663. if ($match[1] == '') {
  664. if ($proxy_port == 443) {
  665. $this->proxy = $match[2];
  666. $this->proxy_protocol = 'ssl://';
  667. $this->proxy_port = 443;
  668. } else {
  669. $this->proxy = $match[2];
  670. if ($proxy_port) {
  671. $this->proxy_port = $proxy_port;
  672. }
  673. }
  674. } elseif ($match[1] == 'http://') {
  675. $this->proxy = $match[2];
  676. if ($proxy_port) {
  677. $this->proxy_port = $proxy_port;
  678. }
  679. } else {
  680. $this->proxy = $match[2];
  681. $this->proxy_protocol = 'ssl://';
  682. if ($proxy_port) {
  683. $this->proxy_port = $proxy_port;
  684. } else {
  685. $this->proxy_port = 443;
  686. }
  687. }
  688. }
  689. }
  690. /**
  691. * Change the current debug mode
  692. *
  693. * @param int $in where 1 = on, 0 = off
  694. *
  695. * @return void
  696. */
  697. function setDebug($in)
  698. {
  699. if ($in) {
  700. $this->debug = 1;
  701. } else {
  702. $this->debug = 0;
  703. }
  704. }
  705. /**
  706. * Set username and password properties for connecting to the RPC server
  707. *
  708. * @param string $u the user name
  709. * @param string $p the password
  710. *
  711. * @return void
  712. *
  713. * @see XML_RPC_Client::$username, XML_RPC_Client::$password
  714. */
  715. function setCredentials($u, $p)
  716. {
  717. $this->username = $u;
  718. $this->password = $p;
  719. }
  720. /**
  721. * Transmit the RPC request via HTTP 1.0 protocol
  722. *
  723. * @param object $msg the XML_RPC_Message object
  724. * @param int $timeout how many seconds to wait for the request
  725. *
  726. * @return object an XML_RPC_Response object. 0 is returned if any
  727. * problems happen.
  728. *
  729. * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
  730. * XML_RPC_Client::setCredentials()
  731. */
  732. function send($msg, $timeout = 0)
  733. {
  734. if (!is_a($msg, 'XML_RPC_Message')) {
  735. $this->errstr = 'send()\'s $msg parameter must be an'
  736. . ' XML_RPC_Message object.';
  737. $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
  738. return 0;
  739. }
  740. $msg->debug = $this->debug;
  741. return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
  742. $timeout, $this->username,
  743. $this->password);
  744. }
  745. /**
  746. * Transmit the RPC request via HTTP 1.0 protocol
  747. *
  748. * Requests should be sent using XML_RPC_Client send() rather than
  749. * calling this method directly.
  750. *
  751. * @param object $msg the XML_RPC_Message object
  752. * @param string $server the server to send the request to
  753. * @param int $port the server port send the request to
  754. * @param int $timeout how many seconds to wait for the request
  755. * before giving up
  756. * @param string $username a user name for accessing the RPC server
  757. * @param string $password a password for accessing the RPC server
  758. *
  759. * @return object an XML_RPC_Response object. 0 is returned if any
  760. * problems happen.
  761. *
  762. * @access protected
  763. * @see XML_RPC_Client::send()
  764. */
  765. function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
  766. $username = '', $password = '')
  767. {
  768. /*
  769. * If we're using a proxy open a socket to the proxy server
  770. * instead to the xml-rpc server
  771. */
  772. if ($this->proxy) {
  773. if ($this->proxy_protocol == 'http://') {
  774. $protocol = '';
  775. } else {
  776. $protocol = $this->proxy_protocol;
  777. }
  778. if ($timeout > 0) {
  779. $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
  780. $this->errno, $this->errstr, $timeout);
  781. } else {
  782. $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
  783. $this->errno, $this->errstr);
  784. }
  785. } else {
  786. if ($this->protocol == 'http://') {
  787. $protocol = '';
  788. } else {
  789. $protocol = $this->protocol;
  790. }
  791. if ($timeout > 0) {
  792. $fp = @fsockopen($protocol . $server, $port,
  793. $this->errno, $this->errstr, $timeout);
  794. } else {
  795. $fp = @fsockopen($protocol . $server, $port,
  796. $this->errno, $this->errstr);
  797. }
  798. }
  799. /*
  800. * Just raising the error without returning it is strange,
  801. * but keep it here for backwards compatibility.
  802. */
  803. if (!$fp && $this->proxy) {
  804. $this->raiseError('Connection to proxy server '
  805. . $this->proxy . ':' . $this->proxy_port
  806. . ' failed. ' . $this->errstr,
  807. XML_RPC_ERROR_CONNECTION_FAILED);
  808. return 0;
  809. } elseif (!$fp) {
  810. $this->raiseError('Connection to RPC server '
  811. . $server . ':' . $port
  812. . ' failed. ' . $this->errstr,
  813. XML_RPC_ERROR_CONNECTION_FAILED);
  814. return 0;
  815. }
  816. if ($timeout) {
  817. /*
  818. * Using socket_set_timeout() because stream_set_timeout()
  819. * was introduced in 4.3.0, but we need to support 4.2.0.
  820. */
  821. socket_set_timeout($fp, $timeout);
  822. }
  823. // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
  824. if ($username != $this->username) {
  825. $this->setCredentials($username, $password);
  826. }
  827. // Only create the payload if it was not created previously
  828. if (empty($msg->payload)) {
  829. $msg->createPayload();
  830. }
  831. $this->createHeaders($msg);
  832. $op = $this->headers . "\r\n\r\n";
  833. $op .= $msg->payload;
  834. if (!fputs($fp, $op, strlen($op))) {
  835. $this->errstr = 'Write error';
  836. return 0;
  837. }
  838. $resp = $msg->parseResponseFile($fp);
  839. $meta = socket_get_status($fp);
  840. if ($meta['timed_out']) {
  841. fclose($fp);
  842. $this->errstr = 'RPC server did not send response before timeout.';
  843. $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
  844. return 0;
  845. }
  846. fclose($fp);
  847. return $resp;
  848. }
  849. /**
  850. * Determines the HTTP headers and puts it in the $headers property
  851. *
  852. * @param object $msg the XML_RPC_Message object
  853. *
  854. * @return boolean TRUE if okay, FALSE if the message payload isn't set.
  855. *
  856. * @access protected
  857. */
  858. function createHeaders($msg)
  859. {
  860. if (empty($msg->payload)) {
  861. return false;
  862. }
  863. if ($this->proxy) {
  864. $this->headers = 'POST ' . $this->protocol . $this->server;
  865. if ($this->proxy_port) {
  866. $this->headers .= ':' . $this->port;
  867. }
  868. } else {
  869. $this->headers = 'POST ';
  870. }
  871. $this->headers .= $this->path. " HTTP/1.0\r\n";
  872. $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
  873. $this->headers .= 'Host: ' . $this->server . "\r\n";
  874. if ($this->proxy && $this->proxy_user) {
  875. $this->headers .= 'Proxy-Authorization: Basic '
  876. . base64_encode("$this->proxy_user:$this->proxy_pass")
  877. . "\r\n";
  878. }
  879. // thanks to Grant Rauscher <grant7@firstworld.net> for this
  880. if ($this->username) {
  881. $this->headers .= 'Authorization: Basic '
  882. . base64_encode("$this->username:$this->password")
  883. . "\r\n";
  884. }
  885. $this->headers .= "Content-Type: text/xml\r\n";
  886. $this->headers .= 'Content-Length: ' . strlen($msg->payload);
  887. return true;
  888. }
  889. }
  890. /**
  891. * The methods and properties for interpreting responses to XML RPC requests
  892. *
  893. * @category Web Services
  894. * @package XML_RPC
  895. * @author Edd Dumbill <edd@usefulinc.com>
  896. * @author Stig Bakken <stig@php.net>
  897. * @author Martin Jansen <mj@php.net>
  898. * @author Daniel Convissor <danielc@php.net>
  899. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  900. * @version Release: 1.4.5
  901. * @link http://pear.php.net/package/XML_RPC
  902. */
  903. class XML_RPC_Response extends XML_RPC_Base
  904. {
  905. var $xv;
  906. var $fn;
  907. var $fs;
  908. var $hdrs;
  909. /**
  910. * @return void
  911. */
  912. function XML_RPC_Response($val, $fcode = 0, $fstr = '')
  913. {
  914. if ($fcode != 0) {
  915. $this->fn = $fcode;
  916. $this->fs = htmlspecialchars($fstr);
  917. } else {
  918. $this->xv = $val;
  919. }
  920. }
  921. /**
  922. * @return int the error code
  923. */
  924. function faultCode()
  925. {
  926. if (isset($this->fn)) {
  927. return $this->fn;
  928. } else {
  929. return 0;
  930. }
  931. }
  932. /**
  933. * @return string the error string
  934. */
  935. function faultString()
  936. {
  937. return $this->fs;
  938. }
  939. /**
  940. * @return mixed the value
  941. */
  942. function value()
  943. {
  944. return $this->xv;
  945. }
  946. /**
  947. * @return string the error message in XML format
  948. */
  949. function serialize()
  950. {
  951. $rs = "<methodResponse>\n";
  952. if ($this->fn) {
  953. $rs .= "<fault>
  954. <value>
  955. <struct>
  956. <member>
  957. <name>faultCode</name>
  958. <value><int>" . $this->fn . "</int></value>
  959. </member>
  960. <member>
  961. <name>faultString</name>
  962. <value><string>" . $this->fs . "</string></value>
  963. </member>
  964. </struct>
  965. </value>
  966. </fault>";
  967. } else {
  968. $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
  969. "</param>\n</params>";
  970. }
  971. $rs .= "\n</methodResponse>";
  972. return $rs;
  973. }
  974. }
  975. /**
  976. * The methods and properties for composing XML RPC messages
  977. *
  978. * @category Web Services
  979. * @package XML_RPC
  980. * @author Edd Dumbill <edd@usefulinc.com>
  981. * @author Stig Bakken <stig@php.net>
  982. * @author Martin Jansen <mj@php.net>
  983. * @author Daniel Convissor <danielc@php.net>
  984. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  985. * @version Release: 1.4.5
  986. * @link http://pear.php.net/package/XML_RPC
  987. */
  988. class XML_RPC_Message extends XML_RPC_Base
  989. {
  990. /**
  991. * The current debug mode (1 = on, 0 = off)
  992. * @var integer
  993. */
  994. var $debug = 0;
  995. /**
  996. * The encoding to be used for outgoing messages
  997. *
  998. * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
  999. *
  1000. * @var string
  1001. * @see XML_RPC_Message::setSendEncoding(),
  1002. * $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
  1003. */
  1004. var $send_encoding = '';
  1005. /**
  1006. * The method presently being evaluated
  1007. * @var string
  1008. */
  1009. var $methodname = '';
  1010. /**
  1011. * @var array
  1012. */
  1013. var $params = array();
  1014. /**
  1015. * The XML message being generated
  1016. * @var string
  1017. */
  1018. var $payload = '';
  1019. /**
  1020. * @return void
  1021. */
  1022. function XML_RPC_Message($meth, $pars = 0)
  1023. {
  1024. $this->methodname = $meth;
  1025. if (is_array($pars) && sizeof($pars) > 0) {
  1026. for ($i = 0; $i < sizeof($pars); $i++) {
  1027. $this->addParam($pars[$i]);
  1028. }
  1029. }
  1030. }
  1031. /**
  1032. * Produces the XML declaration including the encoding attribute
  1033. *
  1034. * The encoding is determined by this class' <var>$send_encoding</var>
  1035. * property. If the <var>$send_encoding</var> property is not set, use
  1036. * <var>$GLOBALS['XML_RPC_defencoding']</var>.
  1037. *
  1038. * @return string the XML declaration and <methodCall> element
  1039. *
  1040. * @see XML_RPC_Message::setSendEncoding(),
  1041. * XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
  1042. */
  1043. function xml_header()
  1044. {
  1045. global $XML_RPC_defencoding;
  1046. if (!$this->send_encoding) {
  1047. $this->send_encoding = $XML_RPC_defencoding;
  1048. }
  1049. return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
  1050. . "\n<methodCall>\n";
  1051. }
  1052. /**
  1053. * @return string the closing </methodCall> tag
  1054. */
  1055. function xml_footer()
  1056. {
  1057. return "</methodCall>\n";
  1058. }
  1059. /**
  1060. * @return void
  1061. *
  1062. * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
  1063. */
  1064. function createPayload()
  1065. {
  1066. $this->payload = $this->xml_header();
  1067. $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
  1068. $this->payload .= "<params>\n";
  1069. for ($i = 0; $i < sizeof($this->params); $i++) {
  1070. $p = $this->params[$i];
  1071. $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
  1072. }
  1073. $this->payload .= "</params>\n";
  1074. $this->payload .= $this->xml_footer();
  1075. $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
  1076. }
  1077. /**
  1078. * @return string the name of the method
  1079. */
  1080. function method($meth = '')
  1081. {
  1082. if ($meth != '') {
  1083. $this->methodname = $meth;
  1084. }
  1085. return $this->methodname;
  1086. }
  1087. /**
  1088. * @return string the payload
  1089. */
  1090. function serialize()
  1091. {
  1092. $this->createPayload();
  1093. return $this->payload;
  1094. }
  1095. /**
  1096. * @return void
  1097. */
  1098. function addParam($par)
  1099. {
  1100. $this->params[] = $par;
  1101. }
  1102. /**
  1103. * Obtains an XML_RPC_Value object for the given parameter
  1104. *
  1105. * @param int $i the index number of the parameter to obtain
  1106. *
  1107. * @return object the XML_RPC_Value object.
  1108. * If the parameter doesn't exist, an XML_RPC_Response object.
  1109. *
  1110. * @since Returns XML_RPC_Response object on error since Release 1.3.0
  1111. */
  1112. function getParam($i)
  1113. {
  1114. global $XML_RPC_err, $XML_RPC_str;
  1115. if (isset($this->params[$i])) {
  1116. return $this->params[$i];
  1117. } else {
  1118. $this->raiseError('The submitted request did not contain this parameter',
  1119. XML_RPC_ERROR_INCORRECT_PARAMS);
  1120. return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
  1121. $XML_RPC_str['incorrect_params']);
  1122. }
  1123. }
  1124. /**
  1125. * @return int the number of parameters
  1126. */
  1127. function getNumParams()
  1128. {
  1129. return sizeof($this->params);
  1130. }
  1131. /**
  1132. * Sets the XML declaration's encoding attribute
  1133. *
  1134. * @param string $type the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
  1135. *
  1136. * @return void
  1137. *
  1138. * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
  1139. * @since Method available since Release 1.2.0
  1140. */
  1141. function setSendEncoding($type)
  1142. {
  1143. $this->send_encoding = $type;
  1144. }
  1145. /**
  1146. * Determine the XML's encoding via the encoding attribute
  1147. * in the XML declaration
  1148. *
  1149. * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
  1150. * or US-ASCII, $XML_RPC_defencoding will be returned.
  1151. *
  1152. * @param string $data the XML that will be parsed
  1153. *
  1154. * @return string the encoding to be used
  1155. *
  1156. * @link http://php.net/xml_parser_create
  1157. * @since Method available since Release 1.2.0
  1158. */
  1159. function getEncoding($data)
  1160. {
  1161. global $XML_RPC_defencoding;
  1162. if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
  1163. $data, $match))
  1164. {
  1165. $match[1] = trim(strtoupper($match[1]));
  1166. switch ($match[1]) {
  1167. case 'ISO-8859-1':
  1168. case 'UTF-8':
  1169. case 'US-ASCII':
  1170. return $match[1];
  1171. break;
  1172. default:
  1173. return $XML_RPC_defencoding;
  1174. }
  1175. } else {
  1176. return $XML_RPC_defencoding;
  1177. }
  1178. }
  1179. /**
  1180. * @return object a new XML_RPC_Response object
  1181. */
  1182. function parseResponseFile($fp)
  1183. {
  1184. $ipd = '';
  1185. while ($data = @fread($fp, 8192)) {
  1186. $ipd .= $data;
  1187. }
  1188. return $this->parseResponse($ipd);
  1189. }
  1190. /**
  1191. * @return object a new XML_RPC_Response object
  1192. */
  1193. function parseResponse($data = '')
  1194. {
  1195. global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
  1196. $encoding = $this->getEncoding($data);
  1197. $parser_resource = xml_parser_create($encoding);
  1198. $parser = (int) $parser_resource;
  1199. $XML_RPC_xh = array();
  1200. $XML_RPC_xh[$parser] = array();
  1201. $XML_RPC_xh[$parser]['cm'] = 0;
  1202. $XML_RPC_xh[$parser]['isf'] = 0;
  1203. $XML_RPC_xh[$parser]['ac'] = '';
  1204. $XML_RPC_xh[$parser]['qt'] = '';
  1205. $XML_RPC_xh[$parser]['stack'] = array();
  1206. $XML_RPC_xh[$parser]['valuestack'] = array();
  1207. xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
  1208. xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
  1209. xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
  1210. $hdrfnd = 0;
  1211. if ($this->debug) {
  1212. print "\n<pre>---GOT---\n";
  1213. print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
  1214. print "\n---END---</pre>\n";
  1215. }
  1216. // See if response is a 200 or a 100 then a 200, else raise error.
  1217. // But only do this if we're using the HTTP protocol.
  1218. if (ereg('^HTTP', $data) &&
  1219. !ereg('^HTTP/[0-9\.]+ 200 ', $data) &&
  1220. !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data))
  1221. {
  1222. $errstr = substr($data, 0, strpos($data, "\n") - 1);
  1223. error_log('HTTP error, got response: ' . $errstr);
  1224. $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
  1225. $XML_RPC_str['http_error'] . ' (' .
  1226. $errstr . ')');
  1227. xml_parser_free($parser_resource);
  1228. return $r;
  1229. }
  1230. // gotta get rid of headers here
  1231. if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
  1232. $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
  1233. $data = substr($data, $brpos + 4);
  1234. $hdrfnd = 1;
  1235. }
  1236. /*
  1237. * be tolerant of junk after methodResponse
  1238. * (e.g. javascript automatically inserted by free hosts)
  1239. * thanks to Luca Mariano <luca.mariano@email.it>
  1240. */
  1241. $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
  1242. if (!xml_parse($parser_resource, $data, sizeof($data))) {
  1243. // thanks to Peter Kocks <peter.kocks@baygate.com>
  1244. if (xml_get_current_line_number($parser_resource) == 1) {
  1245. $errstr = 'XML error at line 1, check URL';
  1246. } else {
  1247. $errstr = sprintf('XML error: %s at line %d',
  1248. xml_error_string(xml_get_error_code($parser_resource)),
  1249. xml_get_current_line_number($parser_resource));
  1250. }
  1251. error_log($errstr);
  1252. $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
  1253. $XML_RPC_str['invalid_return']);
  1254. xml_parser_free($parser_resource);
  1255. return $r;
  1256. }
  1257. xml_parser_free($parser_resource);
  1258. if ($this->debug) {
  1259. print "\n<pre>---PARSED---\n";
  1260. var_dump($XML_RPC_xh[$parser]['value']);
  1261. print "---END---</pre>\n";
  1262. }
  1263. if ($XML_RPC_xh[$parser]['isf'] > 1) {
  1264. $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
  1265. $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
  1266. } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
  1267. // then something odd has happened
  1268. // and it's time to generate a client side error
  1269. // indicating something odd went on
  1270. $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
  1271. $XML_RPC_str['invalid_return']);
  1272. } else {
  1273. $v = $XML_RPC_xh[$parser]['value'];
  1274. $allOK=1;
  1275. if ($XML_RPC_xh[$parser]['isf']) {
  1276. $f = $v->structmem('faultCode');
  1277. $fs = $v->structmem('faultString');
  1278. $r = new XML_RPC_Response($v, $f->scalarval(),
  1279. $fs->scalarval());
  1280. } else {
  1281. $r = new XML_RPC_Response($v);
  1282. }
  1283. }
  1284. $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
  1285. return $r;
  1286. }
  1287. }
  1288. /**
  1289. * The methods and properties that represent data in XML RPC format
  1290. *
  1291. * @category Web Services
  1292. * @package XML_RPC
  1293. * @author Edd Dumbill <edd@usefulinc.com>
  1294. * @author Stig Bakken <stig@php.net>
  1295. * @author Martin Jansen <mj@php.net>
  1296. * @author Daniel Convissor <danielc@php.net>
  1297. * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  1298. * @version Release: 1.4.5
  1299. * @link http://pear.php.net/package/XML_RPC
  1300. */
  1301. class XML_RPC_Value extends XML_RPC_Base
  1302. {
  1303. var $me = array();
  1304. var $mytype = 0;
  1305. /**
  1306. * @return void
  1307. */
  1308. function XML_RPC_Value($val = -1, $type = '')
  1309. {
  1310. global $XML_RPC_Types;
  1311. $this->me = array();
  1312. $this->mytype = 0;
  1313. if ($val != -1 || $type != '') {
  1314. if ($type == '') {
  1315. $type = 'string';
  1316. }
  1317. if (!array_key_exists($type, $XML_RPC_Types)) {
  1318. // XXX
  1319. // need some way to report this error
  1320. } elseif ($XML_RPC_Types[$type] == 1) {
  1321. $this->addScalar($val, $type);
  1322. } elseif ($XML_RPC_Types[$type] == 2) {
  1323. $this->addArray($val);
  1324. } elseif ($XML_RPC_Types[$type] == 3) {
  1325. $this->addStruct($val);
  1326. }
  1327. }
  1328. }
  1329. /**
  1330. * @return int returns 1 if successful or 0 if there are problems
  1331. */
  1332. function addScalar($val, $type = 'string')
  1333. {
  1334. global $XML_RPC_Types, $XML_RPC_Boolean;
  1335. if ($this->mytype == 1) {
  1336. $this->raiseError('Scalar can have only one value',
  1337. XML_RPC_ERROR_INVALID_TYPE);
  1338. return 0;
  1339. }
  1340. $typeof = $XML_RPC_Types[$type];
  1341. if ($typeof != 1) {
  1342. $this->raiseError("Not a scalar type (${typeof})",
  1343. XML_RPC_ERROR_INVALID_TYPE);
  1344. return 0;
  1345. }
  1346. if ($type == $XML_RPC_Boolean) {
  1347. if (strcasecmp($val, 'true') == 0
  1348. || $val == 1
  1349. || ($val == true && strcasecmp($val, 'false')))
  1350. {
  1351. $val = 1;
  1352. } else {
  1353. $val = 0;
  1354. }
  1355. }
  1356. if ($this->mytype == 2) {
  1357. // we're adding to an array here
  1358. $ar = $this->me['array'];
  1359. $ar[] = new XML_RPC_Value($val, $type);
  1360. $this->me['array'] = $ar;
  1361. } else {
  1362. // a scalar, so set the value and remember we're scalar
  1363. $this->me[$type] = $val;
  1364. $this->mytype = $typeof;
  1365. }
  1366. return 1;
  1367. }
  1368. /**
  1369. * @return int returns 1 if successful or 0 if there are problems
  1370. */
  1371. function addArray($vals)
  1372. {
  1373. global $XML_RPC_Types;
  1374. if ($this->mytype != 0) {
  1375. $this->raiseError(
  1376. 'Already initialized as a [' . $this->kindOf() . ']',
  1377. XML_RPC_ERROR_ALREADY_INITIALIZED);
  1378. return 0;
  1379. }
  1380. $this->mytype = $XML_RPC_Types['array'];
  1381. $this->me['array'] = $vals;
  1382. return 1;
  1383. }
  1384. /**
  1385. * @return int returns 1 if successful or 0 if there are problems
  1386. */
  1387. function addStruct($vals)
  1388. {
  1389. global $XML_RPC_Types;
  1390. if ($this->mytype != 0) {
  1391. $this->raiseError(
  1392. 'Already initialized as a [' . $this->kindOf() . ']',
  1393. XML_RPC_ERROR_ALREADY_INITIALIZED);
  1394. return 0;
  1395. }
  1396. $this->mytype = $XML_RPC_Types['struct'];
  1397. $this->me['struct'] = $vals;
  1398. return 1;
  1399. }
  1400. /**
  1401. * @return void
  1402. */
  1403. function dump($ar)
  1404. {
  1405. reset($ar);
  1406. foreach ($ar as $key => $val) {
  1407. echo "$key => $val<br />";
  1408. if ($key == 'array') {
  1409. foreach ($val as $key2 => $val2) {
  1410. echo "-- $key2 => $val2<br />";
  1411. }
  1412. }
  1413. }
  1414. }
  1415. /**
  1416. * @return string the data type of the current value
  1417. */
  1418. function kindOf()
  1419. {
  1420. switch ($this->mytype) {
  1421. case 3:
  1422. return 'struct';
  1423. case 2:
  1424. return 'array';
  1425. case 1:
  1426. return 'scalar';
  1427. default:
  1428. return 'undef';
  1429. }
  1430. }
  1431. /**
  1432. * @return string the data in XML format
  1433. */
  1434. function serializedata($typ, $val)
  1435. {
  1436. $rs = '';
  1437. global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean;
  1438. if (!array_key_exists($typ, $XML_RPC_Types)) {
  1439. // XXX
  1440. // need some way to report this error
  1441. return;
  1442. }
  1443. switch ($XML_RPC_Types[$typ]) {
  1444. case 3:
  1445. // struct
  1446. $rs .= "<struct>\n";
  1447. reset($val);
  1448. foreach ($val as $key2 => $val2) {
  1449. $rs .= "<member><name>${key2}</name>\n";
  1450. $rs .= $this->serializeval($val2);
  1451. $rs .= "</member>\n";
  1452. }
  1453. $rs .= '</struct>';
  1454. break;
  1455. case 2:
  1456. // array
  1457. $rs .= "<array>\n<data>\n";
  1458. for ($i = 0; $i < sizeof($val); $i++) {
  1459. $rs .= $this->serializeval($val[$i]);
  1460. }
  1461. $rs .= "</data>\n</array>";
  1462. break;
  1463. case 1:
  1464. switch ($typ) {
  1465. case $XML_RPC_Base64:
  1466. $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
  1467. break;
  1468. case $XML_RPC_Boolean:
  1469. $rs .= "<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
  1470. break;
  1471. case $XML_RPC_String:
  1472. $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
  1473. break;
  1474. default:
  1475. $rs .= "<${typ}>${val}</${typ}>";
  1476. }
  1477. }
  1478. return $rs;
  1479. }
  1480. /**
  1481. * @return string the data in XML format
  1482. */
  1483. function serialize()
  1484. {
  1485. return $this->serializeval($this);
  1486. }
  1487. /**
  1488. * @return string the data in XML format
  1489. */
  1490. function serializeval($o)
  1491. {
  1492. if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
  1493. return '';
  1494. }
  1495. $ar = $o->me;
  1496. reset($ar);
  1497. list($typ, $val) = each($ar);
  1498. return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
  1499. }
  1500. /**
  1501. * @return mixed the contents of the element requested
  1502. */
  1503. function structmem($m)
  1504. {
  1505. return $this->me['struct'][$m];
  1506. }
  1507. /**
  1508. * @return void
  1509. */
  1510. function structreset()
  1511. {
  1512. reset($this->me['struct']);
  1513. }
  1514. /**
  1515. * @return the key/value pair of the struct's current element
  1516. */
  1517. function structeach()
  1518. {
  1519. return each($this->me['struct']);
  1520. }

Large files files are truncated, but you can click here to view the full file