PageRenderTime 62ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/manager/system/libraries/Xmlrpcs.php

https://bitbucket.org/jerwinse/iagh-cms
PHP | 612 lines | 361 code | 95 blank | 156 comment | 62 complexity | eae7d3b5be32964530a6840cc714c197 MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author ExpressionEngine Dev Team
  9. * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
  10. * @license http://codeigniter.com/user_guide/license.html
  11. * @link http://codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. if ( ! function_exists('xml_parser_create'))
  16. {
  17. show_error('Your PHP installation does not support XML');
  18. }
  19. if ( ! class_exists('CI_Xmlrpc'))
  20. {
  21. show_error('You must load the Xmlrpc class before loading the Xmlrpcs class in order to create a server.');
  22. }
  23. // ------------------------------------------------------------------------
  24. /**
  25. * XML-RPC server class
  26. *
  27. * @package CodeIgniter
  28. * @subpackage Libraries
  29. * @category XML-RPC
  30. * @author ExpressionEngine Dev Team
  31. * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html
  32. */
  33. class CI_Xmlrpcs extends CI_Xmlrpc
  34. {
  35. var $methods = array(); //array of methods mapped to function names and signatures
  36. var $debug_msg = ''; // Debug Message
  37. var $system_methods = array(); // XML RPC Server methods
  38. var $controller_obj;
  39. var $object = FALSE;
  40. /**
  41. * Constructor
  42. */
  43. public function __construct($config=array())
  44. {
  45. parent::__construct();
  46. $this->set_system_methods();
  47. if (isset($config['functions']) && is_array($config['functions']))
  48. {
  49. $this->methods = array_merge($this->methods, $config['functions']);
  50. }
  51. log_message('debug', "XML-RPC Server Class Initialized");
  52. }
  53. // --------------------------------------------------------------------
  54. /**
  55. * Initialize Prefs and Serve
  56. *
  57. * @access public
  58. * @param mixed
  59. * @return void
  60. */
  61. function initialize($config=array())
  62. {
  63. if (isset($config['functions']) && is_array($config['functions']))
  64. {
  65. $this->methods = array_merge($this->methods, $config['functions']);
  66. }
  67. if (isset($config['debug']))
  68. {
  69. $this->debug = $config['debug'];
  70. }
  71. if (isset($config['object']) && is_object($config['object']))
  72. {
  73. $this->object = $config['object'];
  74. }
  75. if (isset($config['xss_clean']))
  76. {
  77. $this->xss_clean = $config['xss_clean'];
  78. }
  79. }
  80. // --------------------------------------------------------------------
  81. /**
  82. * Setting of System Methods
  83. *
  84. * @access public
  85. * @return void
  86. */
  87. function set_system_methods()
  88. {
  89. $this->methods = array(
  90. 'system.listMethods' => array(
  91. 'function' => 'this.listMethods',
  92. 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString), array($this->xmlrpcArray)),
  93. 'docstring' => 'Returns an array of available methods on this server'),
  94. 'system.methodHelp' => array(
  95. 'function' => 'this.methodHelp',
  96. 'signature' => array(array($this->xmlrpcString, $this->xmlrpcString)),
  97. 'docstring' => 'Returns a documentation string for the specified method'),
  98. 'system.methodSignature' => array(
  99. 'function' => 'this.methodSignature',
  100. 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString)),
  101. 'docstring' => 'Returns an array describing the return type and required parameters of a method'),
  102. 'system.multicall' => array(
  103. 'function' => 'this.multicall',
  104. 'signature' => array(array($this->xmlrpcArray, $this->xmlrpcArray)),
  105. 'docstring' => 'Combine multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details')
  106. );
  107. }
  108. // --------------------------------------------------------------------
  109. /**
  110. * Main Server Function
  111. *
  112. * @access public
  113. * @return void
  114. */
  115. function serve()
  116. {
  117. $r = $this->parseRequest();
  118. $payload = '<?xml version="1.0" encoding="'.$this->xmlrpc_defencoding.'"?'.'>'."\n";
  119. $payload .= $this->debug_msg;
  120. $payload .= $r->prepare_response();
  121. header("Content-Type: text/xml");
  122. header("Content-Length: ".strlen($payload));
  123. exit($payload);
  124. }
  125. // --------------------------------------------------------------------
  126. /**
  127. * Add Method to Class
  128. *
  129. * @access public
  130. * @param string method name
  131. * @param string function
  132. * @param string signature
  133. * @param string docstring
  134. * @return void
  135. */
  136. function add_to_map($methodname, $function, $sig, $doc)
  137. {
  138. $this->methods[$methodname] = array(
  139. 'function' => $function,
  140. 'signature' => $sig,
  141. 'docstring' => $doc
  142. );
  143. }
  144. // --------------------------------------------------------------------
  145. /**
  146. * Parse Server Request
  147. *
  148. * @access public
  149. * @param string data
  150. * @return object xmlrpc response
  151. */
  152. function parseRequest($data='')
  153. {
  154. global $HTTP_RAW_POST_DATA;
  155. //-------------------------------------
  156. // Get Data
  157. //-------------------------------------
  158. if ($data == '')
  159. {
  160. $data = $HTTP_RAW_POST_DATA;
  161. }
  162. //-------------------------------------
  163. // Set up XML Parser
  164. //-------------------------------------
  165. $parser = xml_parser_create($this->xmlrpc_defencoding);
  166. $parser_object = new XML_RPC_Message("filler");
  167. $parser_object->xh[$parser] = array();
  168. $parser_object->xh[$parser]['isf'] = 0;
  169. $parser_object->xh[$parser]['isf_reason'] = '';
  170. $parser_object->xh[$parser]['params'] = array();
  171. $parser_object->xh[$parser]['stack'] = array();
  172. $parser_object->xh[$parser]['valuestack'] = array();
  173. $parser_object->xh[$parser]['method'] = '';
  174. xml_set_object($parser, $parser_object);
  175. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
  176. xml_set_element_handler($parser, 'open_tag', 'closing_tag');
  177. xml_set_character_data_handler($parser, 'character_data');
  178. //xml_set_default_handler($parser, 'default_handler');
  179. //-------------------------------------
  180. // PARSE + PROCESS XML DATA
  181. //-------------------------------------
  182. if ( ! xml_parse($parser, $data, 1))
  183. {
  184. // return XML error as a faultCode
  185. $r = new XML_RPC_Response(0,
  186. $this->xmlrpcerrxml + xml_get_error_code($parser),
  187. sprintf('XML error: %s at line %d',
  188. xml_error_string(xml_get_error_code($parser)),
  189. xml_get_current_line_number($parser)));
  190. xml_parser_free($parser);
  191. }
  192. elseif ($parser_object->xh[$parser]['isf'])
  193. {
  194. return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
  195. }
  196. else
  197. {
  198. xml_parser_free($parser);
  199. $m = new XML_RPC_Message($parser_object->xh[$parser]['method']);
  200. $plist='';
  201. for ($i=0; $i < count($parser_object->xh[$parser]['params']); $i++)
  202. {
  203. if ($this->debug === TRUE)
  204. {
  205. $plist .= "$i - " . print_r(get_object_vars($parser_object->xh[$parser]['params'][$i]), TRUE). ";\n";
  206. }
  207. $m->addParam($parser_object->xh[$parser]['params'][$i]);
  208. }
  209. if ($this->debug === TRUE)
  210. {
  211. echo "<pre>";
  212. echo "---PLIST---\n" . $plist . "\n---PLIST END---\n\n";
  213. echo "</pre>";
  214. }
  215. $r = $this->_execute($m);
  216. }
  217. //-------------------------------------
  218. // SET DEBUGGING MESSAGE
  219. //-------------------------------------
  220. if ($this->debug === TRUE)
  221. {
  222. $this->debug_msg = "<!-- DEBUG INFO:\n\n".$plist."\n END DEBUG-->\n";
  223. }
  224. return $r;
  225. }
  226. // --------------------------------------------------------------------
  227. /**
  228. * Executes the Method
  229. *
  230. * @access protected
  231. * @param object
  232. * @return mixed
  233. */
  234. function _execute($m)
  235. {
  236. $methName = $m->method_name;
  237. // Check to see if it is a system call
  238. $system_call = (strncmp($methName, 'system', 5) == 0) ? TRUE : FALSE;
  239. if ($this->xss_clean == FALSE)
  240. {
  241. $m->xss_clean = FALSE;
  242. }
  243. //-------------------------------------
  244. // Valid Method
  245. //-------------------------------------
  246. if ( ! isset($this->methods[$methName]['function']))
  247. {
  248. return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
  249. }
  250. //-------------------------------------
  251. // Check for Method (and Object)
  252. //-------------------------------------
  253. $method_parts = explode(".", $this->methods[$methName]['function']);
  254. $objectCall = (isset($method_parts['1']) && $method_parts['1'] != "") ? TRUE : FALSE;
  255. if ($system_call === TRUE)
  256. {
  257. if ( ! is_callable(array($this,$method_parts['1'])))
  258. {
  259. return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
  260. }
  261. }
  262. else
  263. {
  264. if ($objectCall && ! is_callable(array($method_parts['0'],$method_parts['1'])))
  265. {
  266. return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
  267. }
  268. elseif ( ! $objectCall && ! is_callable($this->methods[$methName]['function']))
  269. {
  270. return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
  271. }
  272. }
  273. //-------------------------------------
  274. // Checking Methods Signature
  275. //-------------------------------------
  276. if (isset($this->methods[$methName]['signature']))
  277. {
  278. $sig = $this->methods[$methName]['signature'];
  279. for ($i=0; $i<count($sig); $i++)
  280. {
  281. $current_sig = $sig[$i];
  282. if (count($current_sig) == count($m->params)+1)
  283. {
  284. for ($n=0; $n < count($m->params); $n++)
  285. {
  286. $p = $m->params[$n];
  287. $pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf();
  288. if ($pt != $current_sig[$n+1])
  289. {
  290. $pno = $n+1;
  291. $wanted = $current_sig[$n+1];
  292. return new XML_RPC_Response(0,
  293. $this->xmlrpcerr['incorrect_params'],
  294. $this->xmlrpcstr['incorrect_params'] .
  295. ": Wanted {$wanted}, got {$pt} at param {$pno})");
  296. }
  297. }
  298. }
  299. }
  300. }
  301. //-------------------------------------
  302. // Calls the Function
  303. //-------------------------------------
  304. if ($objectCall === TRUE)
  305. {
  306. if ($method_parts[0] == "this" && $system_call == TRUE)
  307. {
  308. return call_user_func(array($this, $method_parts[1]), $m);
  309. }
  310. else
  311. {
  312. if ($this->object === FALSE)
  313. {
  314. $CI =& get_instance();
  315. return $CI->$method_parts['1']($m);
  316. }
  317. else
  318. {
  319. return $this->object->$method_parts['1']($m);
  320. //return call_user_func(array(&$method_parts['0'],$method_parts['1']), $m);
  321. }
  322. }
  323. }
  324. else
  325. {
  326. return call_user_func($this->methods[$methName]['function'], $m);
  327. }
  328. }
  329. // --------------------------------------------------------------------
  330. /**
  331. * Server Function: List Methods
  332. *
  333. * @access public
  334. * @param mixed
  335. * @return object
  336. */
  337. function listMethods($m)
  338. {
  339. $v = new XML_RPC_Values();
  340. $output = array();
  341. foreach ($this->methods as $key => $value)
  342. {
  343. $output[] = new XML_RPC_Values($key, 'string');
  344. }
  345. foreach ($this->system_methods as $key => $value)
  346. {
  347. $output[]= new XML_RPC_Values($key, 'string');
  348. }
  349. $v->addArray($output);
  350. return new XML_RPC_Response($v);
  351. }
  352. // --------------------------------------------------------------------
  353. /**
  354. * Server Function: Return Signature for Method
  355. *
  356. * @access public
  357. * @param mixed
  358. * @return object
  359. */
  360. function methodSignature($m)
  361. {
  362. $parameters = $m->output_parameters();
  363. $method_name = $parameters[0];
  364. if (isset($this->methods[$method_name]))
  365. {
  366. if ($this->methods[$method_name]['signature'])
  367. {
  368. $sigs = array();
  369. $signature = $this->methods[$method_name]['signature'];
  370. for ($i=0; $i < count($signature); $i++)
  371. {
  372. $cursig = array();
  373. $inSig = $signature[$i];
  374. for ($j=0; $j<count($inSig); $j++)
  375. {
  376. $cursig[]= new XML_RPC_Values($inSig[$j], 'string');
  377. }
  378. $sigs[]= new XML_RPC_Values($cursig, 'array');
  379. }
  380. $r = new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
  381. }
  382. else
  383. {
  384. $r = new XML_RPC_Response(new XML_RPC_Values('undef', 'string'));
  385. }
  386. }
  387. else
  388. {
  389. $r = new XML_RPC_Response(0,$this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
  390. }
  391. return $r;
  392. }
  393. // --------------------------------------------------------------------
  394. /**
  395. * Server Function: Doc String for Method
  396. *
  397. * @access public
  398. * @param mixed
  399. * @return object
  400. */
  401. function methodHelp($m)
  402. {
  403. $parameters = $m->output_parameters();
  404. $method_name = $parameters[0];
  405. if (isset($this->methods[$method_name]))
  406. {
  407. $docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : '';
  408. return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string'));
  409. }
  410. else
  411. {
  412. return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
  413. }
  414. }
  415. // --------------------------------------------------------------------
  416. /**
  417. * Server Function: Multi-call
  418. *
  419. * @access public
  420. * @param mixed
  421. * @return object
  422. */
  423. function multicall($m)
  424. {
  425. // Disabled
  426. return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
  427. $parameters = $m->output_parameters();
  428. $calls = $parameters[0];
  429. $result = array();
  430. foreach ($calls as $value)
  431. {
  432. //$attempt = $this->_execute(new XML_RPC_Message($value[0], $value[1]));
  433. $m = new XML_RPC_Message($value[0]);
  434. $plist='';
  435. for ($i=0; $i < count($value[1]); $i++)
  436. {
  437. $m->addParam(new XML_RPC_Values($value[1][$i], 'string'));
  438. }
  439. $attempt = $this->_execute($m);
  440. if ($attempt->faultCode() != 0)
  441. {
  442. return $attempt;
  443. }
  444. $result[] = new XML_RPC_Values(array($attempt->value()), 'array');
  445. }
  446. return new XML_RPC_Response(new XML_RPC_Values($result, 'array'));
  447. }
  448. // --------------------------------------------------------------------
  449. /**
  450. * Multi-call Function: Error Handling
  451. *
  452. * @access public
  453. * @param mixed
  454. * @return object
  455. */
  456. function multicall_error($err)
  457. {
  458. $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString();
  459. $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode();
  460. $struct['faultCode'] = new XML_RPC_Values($code, 'int');
  461. $struct['faultString'] = new XML_RPC_Values($str, 'string');
  462. return new XML_RPC_Values($struct, 'struct');
  463. }
  464. // --------------------------------------------------------------------
  465. /**
  466. * Multi-call Function: Processes method
  467. *
  468. * @access public
  469. * @param mixed
  470. * @return object
  471. */
  472. function do_multicall($call)
  473. {
  474. if ($call->kindOf() != 'struct')
  475. {
  476. return $this->multicall_error('notstruct');
  477. }
  478. elseif ( ! $methName = $call->me['struct']['methodName'])
  479. {
  480. return $this->multicall_error('nomethod');
  481. }
  482. list($scalar_type,$scalar_value)=each($methName->me);
  483. $scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
  484. if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string')
  485. {
  486. return $this->multicall_error('notstring');
  487. }
  488. elseif ($scalar_value == 'system.multicall')
  489. {
  490. return $this->multicall_error('recursion');
  491. }
  492. elseif ( ! $params = $call->me['struct']['params'])
  493. {
  494. return $this->multicall_error('noparams');
  495. }
  496. elseif ($params->kindOf() != 'array')
  497. {
  498. return $this->multicall_error('notarray');
  499. }
  500. list($a,$b)=each($params->me);
  501. $numParams = count($b);
  502. $msg = new XML_RPC_Message($scalar_value);
  503. for ($i = 0; $i < $numParams; $i++)
  504. {
  505. $msg->params[] = $params->me['array'][$i];
  506. }
  507. $result = $this->_execute($msg);
  508. if ($result->faultCode() != 0)
  509. {
  510. return $this->multicall_error($result);
  511. }
  512. return new XML_RPC_Values(array($result->value()), 'array');
  513. }
  514. }
  515. // END XML_RPC_Server class
  516. /* End of file Xmlrpcs.php */
  517. /* Location: ./system/libraries/Xmlrpcs.php */