PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/devblocks/libs/ZendFramework/Zend/XmlRpc/Server.php

https://github.com/sluther/portsensor
PHP | 728 lines | 360 code | 74 blank | 294 comment | 49 complexity | e86c5cd57c8cb4bdc3db7029c4a566dd MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to version 1.0 of the Zend Framework
  8. * license, that is bundled with this package in the file LICENSE.txt, and
  9. * is available through the world-wide-web at the following URL:
  10. * http://framework.zend.com/license/new-bsd. If you did not receive
  11. * a copy of the Zend Framework license and are unable to obtain it
  12. * through the world-wide-web, please send a note to license@zend.com
  13. * so we can mail you a copy immediately.
  14. *
  15. * @package Zend_XmlRpc
  16. * @subpackage Server
  17. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * Implement Zend_Server_Interface
  22. */
  23. require_once 'Zend/Server/Interface.php';
  24. /**
  25. * Exception this class throws
  26. */
  27. require_once 'Zend/XmlRpc/Server/Exception.php';
  28. /**
  29. * XMLRPC Request
  30. */
  31. require_once 'Zend/XmlRpc/Request.php';
  32. /**
  33. * XMLRPC Response
  34. */
  35. require_once 'Zend/XmlRpc/Response.php';
  36. /**
  37. * XMLRPC HTTP Response
  38. */
  39. require_once 'Zend/XmlRpc/Response/Http.php';
  40. /**
  41. * XMLRPC server fault class
  42. */
  43. require_once 'Zend/XmlRpc/Server/Fault.php';
  44. /**
  45. * Convert PHP to and from xmlrpc native types
  46. */
  47. require_once 'Zend/XmlRpc/Value.php';
  48. /**
  49. * Reflection API for function/method introspection
  50. */
  51. require_once 'Zend/Server/Reflection.php';
  52. /**
  53. * Zend_Server_Reflection_Function_Abstract
  54. */
  55. require_once 'Zend/Server/Reflection/Function/Abstract.php';
  56. /**
  57. * Specifically grab the Zend_Server_Reflection_Method for manually setting up
  58. * system.* methods and handling callbacks in {@link loadFunctions()}.
  59. */
  60. require_once 'Zend/Server/Reflection/Method.php';
  61. /**
  62. * An XML-RPC server implementation
  63. *
  64. * Example:
  65. * <code>
  66. * require_once 'Zend/XmlRpc/Server.php';
  67. * require_once 'Zend/XmlRpc/Server/Cache.php';
  68. * require_once 'Zend/XmlRpc/Server/Fault.php';
  69. * require_once 'My/Exception.php';
  70. * require_once 'My/Fault/Observer.php';
  71. *
  72. * // Instantiate server
  73. * $server = new Zend_XmlRpc_Server();
  74. *
  75. * // Allow some exceptions to report as fault responses:
  76. * Zend_XmlRpc_Server_Fault::attachFaultException('My_Exception');
  77. * Zend_XmlRpc_Server_Fault::attachObserver('My_Fault_Observer');
  78. *
  79. * // Get or build dispatch table:
  80. * if (!Zend_XmlRpc_Server_Cache::get($filename, $server)) {
  81. * require_once 'Some/Service/Class.php';
  82. * require_once 'Another/Service/Class.php';
  83. *
  84. * // Attach Some_Service_Class in 'some' namespace
  85. * $server->setClass('Some_Service_Class', 'some');
  86. *
  87. * // Attach Another_Service_Class in 'another' namespace
  88. * $server->setClass('Another_Service_Class', 'another');
  89. *
  90. * // Create dispatch table cache file
  91. * Zend_XmlRpc_Server_Cache::save($filename, $server);
  92. * }
  93. *
  94. * $response = $server->handle();
  95. * echo $response;
  96. * </code>
  97. *
  98. * @category Zend
  99. * @package Zend_XmlRpc
  100. * @subpackage Server
  101. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  102. * @license http://framework.zend.com/license/new-bsd New BSD License
  103. */
  104. class Zend_XmlRpc_Server
  105. {
  106. /**
  107. * Character encoding
  108. * @var string
  109. */
  110. protected $_encoding = 'UTF-8';
  111. /**
  112. * Array of dispatchables
  113. * @var array
  114. */
  115. protected $_methods = array();
  116. /**
  117. * Request processed
  118. * @var null|Zend_XmlRpc_Request
  119. */
  120. protected $_request = null;
  121. /**
  122. * Class to use for responses; defaults to {@link Zend_XmlRpc_Response_Http}
  123. * @var string
  124. */
  125. protected $_responseClass = 'Zend_XmlRpc_Response_Http';
  126. /**
  127. * Dispatch table of name => method pairs
  128. * @var array
  129. */
  130. protected $_table = array();
  131. /**
  132. * PHP types => XML-RPC types
  133. * @var array
  134. */
  135. protected $_typeMap = array(
  136. 'i4' => 'i4',
  137. 'int' => 'int',
  138. 'integer' => 'int',
  139. 'double' => 'double',
  140. 'float' => 'double',
  141. 'real' => 'double',
  142. 'boolean' => 'boolean',
  143. 'bool' => 'boolean',
  144. 'true' => 'boolean',
  145. 'false' => 'boolean',
  146. 'string' => 'string',
  147. 'str' => 'string',
  148. 'base64' => 'base64',
  149. 'dateTime.iso8601' => 'dateTime.iso8601',
  150. 'date' => 'dateTime.iso8601',
  151. 'time' => 'dateTime.iso8601',
  152. 'time' => 'dateTime.iso8601',
  153. 'array' => 'array',
  154. 'struct' => 'struct',
  155. 'null' => 'void',
  156. 'void' => 'void',
  157. 'mixed' => 'struct'
  158. );
  159. /**
  160. * Constructor
  161. *
  162. * Creates system.* methods.
  163. *
  164. * @return void
  165. */
  166. public function __construct()
  167. {
  168. // Setup system.* methods
  169. $system = array(
  170. 'listMethods',
  171. 'methodHelp',
  172. 'methodSignature',
  173. 'multicall'
  174. );
  175. $class = Zend_Server_Reflection::reflectClass($this);
  176. foreach ($system as $method) {
  177. $reflection = new Zend_Server_Reflection_Method($class, new ReflectionMethod($this, $method), 'system');
  178. $reflection->system = true;
  179. $this->_methods[] = $reflection;
  180. }
  181. $this->_buildDispatchTable();
  182. }
  183. /**
  184. * Map PHP parameter types to XML-RPC types
  185. *
  186. * @param Zend_Server_Reflection_Function_Abstract $method
  187. * @return void
  188. */
  189. protected function _fixTypes(Zend_Server_Reflection_Function_Abstract $method)
  190. {
  191. foreach ($method->getPrototypes() as $prototype) {
  192. foreach ($prototype->getParameters() as $param) {
  193. $pType = $param->getType();
  194. if (isset($this->_typeMap[$pType])) {
  195. $param->setType($this->_typeMap[$pType]);
  196. } else {
  197. $param->setType('void');
  198. }
  199. }
  200. }
  201. }
  202. /**
  203. * Re/Build the dispatch table
  204. *
  205. * The dispatch table consists of a an array of method name =>
  206. * Zend_Server_Reflection_Function_Abstract pairs
  207. *
  208. * @return void
  209. */
  210. protected function _buildDispatchTable()
  211. {
  212. $table = array();
  213. foreach ($this->_methods as $dispatchable) {
  214. if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) {
  215. // function/method call
  216. $ns = $dispatchable->getNamespace();
  217. $name = $dispatchable->getName();
  218. $name = empty($ns) ? $name : $ns . '.' . $name;
  219. if (isset($table[$name])) {
  220. throw new Zend_XmlRpc_Server_Exception('Duplicate method registered: ' . $name);
  221. }
  222. $table[$name] = $dispatchable;
  223. $this->_fixTypes($dispatchable);
  224. continue;
  225. }
  226. if ($dispatchable instanceof Zend_Server_Reflection_Class) {
  227. foreach ($dispatchable->getMethods() as $method) {
  228. $ns = $method->getNamespace();
  229. $name = $method->getName();
  230. $name = empty($ns) ? $name : $ns . '.' . $name;
  231. if (isset($table[$name])) {
  232. throw new Zend_XmlRpc_Server_Exception('Duplicate method registered: ' . $name);
  233. }
  234. $table[$name] = $method;
  235. $this->_fixTypes($method);
  236. continue;
  237. }
  238. }
  239. }
  240. $this->_table = $table;
  241. }
  242. /**
  243. * Set encoding
  244. *
  245. * @param string $encoding
  246. * @return Zend_XmlRpc_Server
  247. */
  248. public function setEncoding($encoding)
  249. {
  250. $this->_encoding = $encoding;
  251. return $this;
  252. }
  253. /**
  254. * Retrieve current encoding
  255. *
  256. * @return string
  257. */
  258. public function getEncoding()
  259. {
  260. return $this->_encoding;
  261. }
  262. /**
  263. * Attach a callback as an XMLRPC method
  264. *
  265. * Attaches a callback as an XMLRPC method, prefixing the XMLRPC method name
  266. * with $namespace, if provided. Reflection is done on the callback's
  267. * docblock to create the methodHelp for the XMLRPC method.
  268. *
  269. * Additional arguments to pass to the function at dispatch may be passed;
  270. * any arguments following the namespace will be aggregated and passed at
  271. * dispatch time.
  272. *
  273. * @param string|array $function Valid callback
  274. * @param string $namespace Optional namespace prefix
  275. * @return void
  276. * @throws Zend_XmlRpc_Server_Exception
  277. */
  278. public function addFunction($function, $namespace = '')
  279. {
  280. if (!is_string($function) && !is_array($function)) {
  281. throw new Zend_XmlRpc_Server_Exception('Unable to attach function; invalid', 611);
  282. }
  283. $argv = null;
  284. if (2 < func_num_args()) {
  285. $argv = func_get_args();
  286. $argv = array_slice($argv, 2);
  287. }
  288. $function = (array) $function;
  289. foreach ($function as $func) {
  290. if (!is_string($func) || !function_exists($func)) {
  291. throw new Zend_XmlRpc_Server_Exception('Unable to attach function; invalid', 611);
  292. }
  293. $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace);
  294. }
  295. $this->_buildDispatchTable();
  296. }
  297. /**
  298. * Load methods as returned from {@link getFunctions}
  299. *
  300. * Typically, you will not use this method; it will be called using the
  301. * results pulled from {@link Zend_XmlRpc_Server_Cache::get()}.
  302. *
  303. * @param array $array
  304. * @return void
  305. * @throws Zend_XmlRpc_Server_Exception on invalid input
  306. */
  307. public function loadFunctions($array)
  308. {
  309. if (!is_array($array)) {
  310. throw new Zend_XmlRpc_Server_Exception('Unable to load array; not an array', 612);
  311. }
  312. foreach ($array as $key => $value) {
  313. if (!$value instanceof Zend_Server_Reflection_Function_Abstract
  314. && !$value instanceof Zend_Server_Reflection_Class)
  315. {
  316. throw new Zend_XmlRpc_Server_Exception('One or more method records are corrupt or otherwise unusable', 613);
  317. }
  318. if ($value->system) {
  319. unset($array[$key]);
  320. }
  321. }
  322. foreach ($array as $dispatchable) {
  323. $this->_methods[] = $dispatchable;
  324. }
  325. $this->_buildDispatchTable();
  326. }
  327. /**
  328. * Do nothing; persistence is handled via {@link Zend_XmlRpc_Server_Cache}
  329. *
  330. * @param mixed $class
  331. * @return void
  332. */
  333. public function setPersistence($class = null)
  334. {
  335. }
  336. /**
  337. * Attach class methods as XMLRPC method handlers
  338. *
  339. * $class may be either a class name or an object. Reflection is done on the
  340. * class or object to determine the available public methods, and each is
  341. * attached to the server as an available method; if a $namespace has been
  342. * provided, that namespace is used to prefix the XMLRPC method names.
  343. *
  344. * Any additional arguments beyond $namespace will be passed to a method at
  345. * invocation.
  346. *
  347. * @param string|object $class
  348. * @param string $namespace Optional
  349. * @param mixed $argv Optional arguments to pass to methods
  350. * @return void
  351. * @throws Zend_XmlRpc_Server_Exception on invalid input
  352. */
  353. public function setClass($class, $namespace = '', $argv = null)
  354. {
  355. if (is_string($class) && !class_exists($class)) {
  356. if (!class_exists($class)) {
  357. throw new Zend_XmlRpc_Server_Exception('Invalid method class', 610);
  358. }
  359. }
  360. $argv = null;
  361. if (3 < func_num_args()) {
  362. $argv = func_get_args();
  363. $argv = array_slice($argv, 3);
  364. }
  365. $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $argv, $namespace);
  366. $this->_buildDispatchTable();
  367. }
  368. /**
  369. * Set the request object
  370. *
  371. * @param string|Zend_XmlRpc_Request $request
  372. * @return Zend_XmlRpc_Server
  373. * @throws Zend_XmlRpc_Server_Exception on invalid request class or object
  374. */
  375. public function setRequest($request)
  376. {
  377. if (is_string($request) && class_exists($request)) {
  378. $request = new $request();
  379. if (!$request instanceof Zend_XmlRpc_Request) {
  380. throw new Zend_XmlRpc_Server_Exception('Invalid request class');
  381. }
  382. $request->setEncoding($this->getEncoding());
  383. } elseif (!$request instanceof Zend_XmlRpc_Request) {
  384. throw new Zend_XmlRpc_Server_Exception('Invalid request object');
  385. }
  386. $this->_request = $request;
  387. return $this;
  388. }
  389. /**
  390. * Return currently registered request object
  391. *
  392. * @return null|Zend_XmlRpc_Request
  393. */
  394. public function getRequest()
  395. {
  396. return $this->_request;
  397. }
  398. /**
  399. * Raise an xmlrpc server fault
  400. *
  401. * @param string|Exception $fault
  402. * @param int $code
  403. * @return Zend_XmlRpc_Server_Fault
  404. */
  405. public function fault($fault, $code = 404)
  406. {
  407. if (!$fault instanceof Exception) {
  408. $fault = (string) $fault;
  409. $fault = new Zend_XmlRpc_Server_Exception($fault, $code);
  410. }
  411. return Zend_XmlRpc_Server_Fault::getInstance($fault);
  412. }
  413. /**
  414. * Handle an xmlrpc call (actual work)
  415. *
  416. * @param Zend_XmlRpc_Request $request
  417. * @return Zend_XmlRpc_Response
  418. * @throws Zend_XmlRpcServer_Exception|Exception
  419. * Zend_XmlRpcServer_Exceptions are thrown for internal errors; otherwise,
  420. * any other exception may be thrown by the callback
  421. */
  422. protected function _handle(Zend_XmlRpc_Request $request)
  423. {
  424. $method = $request->getMethod();
  425. // Check for valid method
  426. if (!isset($this->_table[$method])) {
  427. throw new Zend_XmlRpc_Server_Exception('Method "' . $method . '" does not exist', 620);
  428. }
  429. $info = $this->_table[$method];
  430. $params = $request->getParams();
  431. $argv = $info->getInvokeArguments();
  432. if (0 < count($argv)) {
  433. $params = array_merge($params, $argv);
  434. }
  435. // Check calling parameters against signatures
  436. $matched = false;
  437. $sigCalled = array();
  438. foreach ($params as $param) {
  439. $value = Zend_XmlRpc_Value::getXmlRpcValue($param);
  440. $sigCalled[] = $value->getType();
  441. }
  442. $signatures = $info->getPrototypes();
  443. foreach ($signatures as $signature) {
  444. $sigParams = $signature->getParameters();
  445. $tmpParams = array();
  446. foreach ($sigParams as $param) {
  447. $tmpParams[] = $param->getType();
  448. }
  449. if ($sigCalled === $tmpParams) {
  450. $matched = true;
  451. break;
  452. }
  453. }
  454. if (!$matched) {
  455. throw new Zend_XmlRpc_Server_Exception('Calling parameters do not match signature', 623);
  456. }
  457. if ($info instanceof Zend_Server_Reflection_Function) {
  458. $func = $info->getName();
  459. $return = call_user_func_array($func, $params);
  460. } elseif (($info instanceof Zend_Server_Reflection_Method) && $info->system) {
  461. // System methods
  462. $return = $info->invokeArgs($this, $params);
  463. } elseif ($info instanceof Zend_Server_Reflection_Method) {
  464. // Get class
  465. $class = $info->getDeclaringClass()->getName();
  466. if ('static' == $info->isStatic()) {
  467. // for some reason, invokeArgs() does not work the same as
  468. // invoke(), and expects the first argument to be an object.
  469. // So, using a callback if the method is static.
  470. $return = call_user_func_array(array($class, $info->getName()), $params);
  471. } else {
  472. // Object methods
  473. try {
  474. $object = $info->getDeclaringClass()->newInstance();
  475. } catch (Exception $e) {
  476. throw new Zend_XmlRpc_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName(), 621);
  477. }
  478. $return = $info->invokeArgs($object, $params);
  479. }
  480. } else {
  481. throw new Zend_XmlRpc_Server_Exception('Method missing implementation ' . get_class($info), 622);
  482. }
  483. $response = new ReflectionClass($this->_responseClass);
  484. return $response->newInstance($return);
  485. }
  486. /**
  487. * Handle an xmlrpc call
  488. *
  489. * @param Zend_XmlRpc_Request $request Optional
  490. * @return Zend_XmlRpc_Response|Zend_XmlRpc_Fault
  491. */
  492. public function handle(Zend_XmlRpc_Request $request = null)
  493. {
  494. // Get request
  495. if ((null === $request) && (null === ($request = $this->getRequest()))) {
  496. require_once 'Zend/XmlRpc/Request/Http.php';
  497. $request = new Zend_XmlRpc_Request_Http();
  498. $request->setEncoding($this->getEncoding());
  499. }
  500. $this->setRequest($request);
  501. if ($request->isFault()) {
  502. $response = $request->getFault();
  503. } else {
  504. try {
  505. $response = $this->_handle($request);
  506. } catch (Exception $e) {
  507. $response = $this->fault($e);
  508. }
  509. }
  510. // Set output encoding
  511. $response->setEncoding($this->getEncoding());
  512. return $response;
  513. }
  514. /**
  515. * Set the class to use for the response
  516. *
  517. * @param string $class
  518. * @return boolean True if class was set, false if not
  519. */
  520. public function setResponseClass($class)
  521. {
  522. if (class_exists($class)) {
  523. $reflection = new ReflectionClass($class);
  524. if ($reflection->isSubclassOf(new ReflectionClass('Zend_XmlRpc_Response'))) {
  525. $this->_responseClass = $class;
  526. return true;
  527. }
  528. }
  529. return false;
  530. }
  531. /**
  532. * Returns a list of registered methods
  533. *
  534. * Returns an array of dispatchables (Zend_Server_Reflection_Function,
  535. * _Method, and _Class items).
  536. *
  537. * @return array
  538. */
  539. public function getFunctions()
  540. {
  541. $return = array();
  542. foreach ($this->_methods as $method) {
  543. if ($method instanceof Zend_Server_Reflection_Class
  544. && ($method->system))
  545. {
  546. continue;
  547. }
  548. $return[] = $method;
  549. }
  550. return $return;
  551. }
  552. /**
  553. * List all available XMLRPC methods
  554. *
  555. * Returns an array of methods.
  556. *
  557. * @return array
  558. */
  559. public function listMethods()
  560. {
  561. return array_keys($this->_table);
  562. }
  563. /**
  564. * Display help message for an XMLRPC method
  565. *
  566. * @param string $method
  567. * @return string
  568. */
  569. public function methodHelp($method)
  570. {
  571. if (!isset($this->_table[$method])) {
  572. throw new Zend_Server_Exception('Method "' . $method . '"does not exist', 640);
  573. }
  574. return $this->_table[$method]->getDescription();
  575. }
  576. /**
  577. * Return a method signature
  578. *
  579. * @param string $method
  580. * @return array
  581. */
  582. public function methodSignature($method)
  583. {
  584. if (!isset($this->_table[$method])) {
  585. throw new Zend_Server_Exception('Method "' . $method . '"does not exist', 640);
  586. }
  587. $prototypes = $this->_table[$method]->getPrototypes();
  588. $signatures = array();
  589. foreach ($prototypes as $prototype) {
  590. $signature = array($prototype->getReturnType());
  591. foreach ($prototype->getParameters() as $parameter) {
  592. $signature[] = $parameter->getType();
  593. }
  594. $signatures[] = $signature;
  595. }
  596. return $signatures;
  597. }
  598. /**
  599. * Multicall - boxcar feature of XML-RPC for calling multiple methods
  600. * in a single request.
  601. *
  602. * Expects a an array of structs representing method calls, each element
  603. * having the keys:
  604. * - methodName
  605. * - params
  606. *
  607. * Returns an array of responses, one for each method called, with the value
  608. * returned by the method. If an error occurs for a given method, returns a
  609. * struct with a fault response.
  610. *
  611. * @see http://www.xmlrpc.com/discuss/msgReader$1208
  612. * @param array $methods
  613. * @return array
  614. */
  615. public function multicall($methods)
  616. {
  617. $responses = array();
  618. foreach ($methods as $method) {
  619. $fault = false;
  620. if (!is_array($method)) {
  621. $fault = $this->fault('system.multicall expects each method to be a struct', 601);
  622. } elseif (!isset($method['methodName'])) {
  623. $fault = $this->fault('Missing methodName', 602);
  624. } elseif (!isset($method['params'])) {
  625. $fault = $this->fault('Missing params', 603);
  626. } elseif (!is_array($method['params'])) {
  627. $fault = $this->fault('Params must be an array', 604);
  628. } else {
  629. if ('system.multicall' == $method['methodName']) {
  630. // don't allow recursive calls to multicall
  631. $fault = $this->fault('Recursive system.multicall forbidden', 605);
  632. }
  633. }
  634. if (!$fault) {
  635. try {
  636. $request = new Zend_XmlRpc_Request();
  637. $request->setMethod($method['methodName']);
  638. $request->setParams($method['params']);
  639. $response = $this->_handle($request);
  640. $responses[] = $response->getReturnValue();
  641. } catch (Exception $e) {
  642. $fault = $this->fault($e);
  643. }
  644. }
  645. if ($fault) {
  646. $responses[] = array(
  647. 'faultCode' => $fault->getCode(),
  648. 'faultString' => $fault->getMessage()
  649. );
  650. }
  651. }
  652. return $responses;
  653. }
  654. }