PageRenderTime 485ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/zend/Zend/Amf/Server.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 933 lines | 501 code | 86 blank | 346 comment | 79 complexity | a534ae765f0d1b20f76340e4c54fe300 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, LGPL-2.1, Apache-2.0, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Amf
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. /** @see Zend_Server_Interface */
  22. require_once 'Zend/Server/Interface.php';
  23. /** @see Zend_Server_Reflection */
  24. require_once 'Zend/Server/Reflection.php';
  25. /** @see Zend_Amf_Constants */
  26. require_once 'Zend/Amf/Constants.php';
  27. /** @see Zend_Amf_Value_MessageBody */
  28. require_once 'Zend/Amf/Value/MessageBody.php';
  29. /** @see Zend_Amf_Value_MessageHeader */
  30. require_once 'Zend/Amf/Value/MessageHeader.php';
  31. /** @see Zend_Amf_Value_Messaging_CommandMessage */
  32. require_once 'Zend/Amf/Value/Messaging/CommandMessage.php';
  33. /** @see Zend_Loader_PluginLoader */
  34. require_once 'Zend/Loader/PluginLoader.php';
  35. /** @see Zend_Amf_Parse_TypeLoader */
  36. require_once 'Zend/Amf/Parse/TypeLoader.php';
  37. /** @see Zend_Auth */
  38. require_once 'Zend/Auth.php';
  39. /**
  40. * An AMF gateway server implementation to allow the connection of the Adobe Flash Player to
  41. * Zend Framework
  42. *
  43. * @todo Make the reflection methods cache and autoload.
  44. * @package Zend_Amf
  45. * @subpackage Server
  46. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  47. * @license http://framework.zend.com/license/new-bsd New BSD License
  48. */
  49. class Zend_Amf_Server implements Zend_Server_Interface
  50. {
  51. /**
  52. * Array of dispatchables
  53. * @var array
  54. */
  55. protected $_methods = array();
  56. /**
  57. * Array of classes that can be called without being explicitly loaded
  58. *
  59. * Keys are class names.
  60. *
  61. * @var array
  62. */
  63. protected $_classAllowed = array();
  64. /**
  65. * Loader for classes in added directories
  66. * @var Zend_Loader_PluginLoader
  67. */
  68. protected $_loader;
  69. /**
  70. * @var bool Production flag; whether or not to return exception messages
  71. */
  72. protected $_production = true;
  73. /**
  74. * Request processed
  75. * @var null|Zend_Amf_Request
  76. */
  77. protected $_request = null;
  78. /**
  79. * Class to use for responses
  80. * @var null|Zend_Amf_Response
  81. */
  82. protected $_response;
  83. /**
  84. * Dispatch table of name => method pairs
  85. * @var array
  86. */
  87. protected $_table = array();
  88. /**
  89. *
  90. * @var bool session flag; whether or not to add a session to each response.
  91. */
  92. protected $_session = false;
  93. /**
  94. * Namespace allows all AMF calls to not clobber other php session variables
  95. * @var Zend_Session_NameSpace default session namespace zend_amf
  96. */
  97. protected $_sesionNamespace = 'zend_amf';
  98. /**
  99. * Set the default session.name if php_
  100. * @var string
  101. */
  102. protected $_sessionName = 'PHPSESSID';
  103. /**
  104. * Authentication handler object
  105. *
  106. * @var Zend_Amf_Auth_Abstract
  107. */
  108. protected $_auth;
  109. /**
  110. * ACL handler object
  111. *
  112. * @var Zend_Acl
  113. */
  114. protected $_acl;
  115. /**
  116. * The server constructor
  117. */
  118. public function __construct()
  119. {
  120. Zend_Amf_Parse_TypeLoader::setResourceLoader(new Zend_Loader_PluginLoader(array("Zend_Amf_Parse_Resource" => "Zend/Amf/Parse/Resource")));
  121. }
  122. /**
  123. * Set authentication adapter
  124. *
  125. * @param Zend_Amf_Auth_Abstract $auth
  126. * @return Zend_Amf_Server
  127. */
  128. public function setAuth(Zend_Amf_Auth_Abstract $auth)
  129. {
  130. $this->_auth = $auth;
  131. return $this;
  132. }
  133. /**
  134. * Get authentication adapter
  135. *
  136. * @return Zend_Amf_Auth_Abstract
  137. */
  138. public function getAuth()
  139. {
  140. return $this->_auth;
  141. }
  142. /**
  143. * Set ACL adapter
  144. *
  145. * @param Zend_Acl $acl
  146. * @return Zend_Amf_Server
  147. */
  148. public function setAcl(Zend_Acl $acl)
  149. {
  150. $this->_acl = $acl;
  151. return $this;
  152. }
  153. /**
  154. * Get ACL adapter
  155. *
  156. * @return Zend_Acl
  157. */
  158. public function getAcl()
  159. {
  160. return $this->_acl;
  161. }
  162. /**
  163. * Set production flag
  164. *
  165. * @param bool $flag
  166. * @return Zend_Amf_Server
  167. */
  168. public function setProduction($flag)
  169. {
  170. $this->_production = (bool) $flag;
  171. return $this;
  172. }
  173. /**
  174. * Whether or not the server is in production
  175. *
  176. * @return bool
  177. */
  178. public function isProduction()
  179. {
  180. return $this->_production;
  181. }
  182. /**
  183. * @param namespace of all incoming sessions defaults to Zend_Amf
  184. * @return Zend_Amf_Server
  185. */
  186. public function setSession($namespace = 'Zend_Amf')
  187. {
  188. require_once 'Zend/Session.php';
  189. $this->_session = true;
  190. $this->_sesionNamespace = new Zend_Session_Namespace($namespace);
  191. return $this;
  192. }
  193. /**
  194. * Whether of not the server is using sessions
  195. * @return bool
  196. */
  197. public function isSession()
  198. {
  199. return $this->_session;
  200. }
  201. /**
  202. * Check if the ACL allows accessing the function or method
  203. *
  204. * @param string|object $object Object or class being accessed
  205. * @param string $function Function or method being accessed
  206. * @return unknown_type
  207. */
  208. protected function _checkAcl($object, $function)
  209. {
  210. if(!$this->_acl) {
  211. return true;
  212. }
  213. if($object) {
  214. $class = is_object($object)?get_class($object):$object;
  215. if(!$this->_acl->has($class)) {
  216. require_once 'Zend/Acl/Resource.php';
  217. $this->_acl->add(new Zend_Acl_Resource($class));
  218. }
  219. $call = array($object, "initAcl");
  220. if(is_callable($call) && !call_user_func($call, $this->_acl)) {
  221. // if initAcl returns false, no ACL check
  222. return true;
  223. }
  224. } else {
  225. $class = null;
  226. }
  227. $auth = Zend_Auth::getInstance();
  228. if($auth->hasIdentity()) {
  229. $role = $auth->getIdentity()->role;
  230. } else {
  231. if($this->_acl->hasRole(Zend_Amf_Constants::GUEST_ROLE)) {
  232. $role = Zend_Amf_Constants::GUEST_ROLE;
  233. } else {
  234. require_once 'Zend/Amf/Server/Exception.php';
  235. throw new Zend_Amf_Server_Exception("Unauthenticated access not allowed");
  236. }
  237. }
  238. if($this->_acl->isAllowed($role, $class, $function)) {
  239. return true;
  240. } else {
  241. require_once 'Zend/Amf/Server/Exception.php';
  242. throw new Zend_Amf_Server_Exception("Access not allowed");
  243. }
  244. }
  245. /**
  246. * Get PluginLoader for the Server
  247. *
  248. * @return Zend_Loader_PluginLoader
  249. */
  250. protected function getLoader()
  251. {
  252. if(empty($this->_loader)) {
  253. require_once 'Zend/Loader/PluginLoader.php';
  254. $this->_loader = new Zend_Loader_PluginLoader();
  255. }
  256. return $this->_loader;
  257. }
  258. /**
  259. * Loads a remote class or method and executes the function and returns
  260. * the result
  261. *
  262. * @param string $method Is the method to execute
  263. * @param mixed $param values for the method
  264. * @return mixed $response the result of executing the method
  265. * @throws Zend_Amf_Server_Exception
  266. */
  267. protected function _dispatch($method, $params = null, $source = null)
  268. {
  269. if($source) {
  270. if(($mapped = Zend_Amf_Parse_TypeLoader::getMappedClassName($source)) !== false) {
  271. $source = $mapped;
  272. }
  273. }
  274. $qualifiedName = empty($source) ? $method : $source.".".$method;
  275. if (!isset($this->_table[$qualifiedName])) {
  276. // if source is null a method that was not defined was called.
  277. if ($source) {
  278. $className = str_replace(".", "_", $source);
  279. if(class_exists($className, false) && !isset($this->_classAllowed[$className])) {
  280. require_once 'Zend/Amf/Server/Exception.php';
  281. throw new Zend_Amf_Server_Exception('Can not call "' . $className . '" - use setClass()');
  282. }
  283. try {
  284. $this->getLoader()->load($className);
  285. } catch (Exception $e) {
  286. require_once 'Zend/Amf/Server/Exception.php';
  287. throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage(), 0, $e);
  288. }
  289. // Add the new loaded class to the server.
  290. $this->setClass($className, $source);
  291. } else {
  292. require_once 'Zend/Amf/Server/Exception.php';
  293. throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist');
  294. }
  295. }
  296. $info = $this->_table[$qualifiedName];
  297. $argv = $info->getInvokeArguments();
  298. if (0 < count($argv)) {
  299. $params = array_merge($params, $argv);
  300. }
  301. if ($info instanceof Zend_Server_Reflection_Function) {
  302. $func = $info->getName();
  303. $this->_checkAcl(null, $func);
  304. $return = call_user_func_array($func, $params);
  305. } elseif ($info instanceof Zend_Server_Reflection_Method) {
  306. // Get class
  307. $class = $info->getDeclaringClass()->getName();
  308. if ('static' == $info->isStatic()) {
  309. // for some reason, invokeArgs() does not work the same as
  310. // invoke(), and expects the first argument to be an object.
  311. // So, using a callback if the method is static.
  312. $this->_checkAcl($class, $info->getName());
  313. $return = call_user_func_array(array($class, $info->getName()), $params);
  314. } else {
  315. // Object methods
  316. try {
  317. $object = $info->getDeclaringClass()->newInstance();
  318. } catch (Exception $e) {
  319. require_once 'Zend/Amf/Server/Exception.php';
  320. throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621, $e);
  321. }
  322. $this->_checkAcl($object, $info->getName());
  323. $return = $info->invokeArgs($object, $params);
  324. }
  325. } else {
  326. require_once 'Zend/Amf/Server/Exception.php';
  327. throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info));
  328. }
  329. return $return;
  330. }
  331. /**
  332. * Handles each of the 11 different command message types.
  333. *
  334. * A command message is a flex.messaging.messages.CommandMessage
  335. *
  336. * @see Zend_Amf_Value_Messaging_CommandMessage
  337. * @param Zend_Amf_Value_Messaging_CommandMessage $message
  338. * @return Zend_Amf_Value_Messaging_AcknowledgeMessage
  339. */
  340. protected function _loadCommandMessage(Zend_Amf_Value_Messaging_CommandMessage $message)
  341. {
  342. require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
  343. switch($message->operation) {
  344. case Zend_Amf_Value_Messaging_CommandMessage::DISCONNECT_OPERATION :
  345. case Zend_Amf_Value_Messaging_CommandMessage::CLIENT_PING_OPERATION :
  346. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  347. break;
  348. case Zend_Amf_Value_Messaging_CommandMessage::LOGIN_OPERATION :
  349. $data = explode(':', base64_decode($message->body));
  350. $userid = $data[0];
  351. $password = isset($data[1])?$data[1]:"";
  352. if(empty($userid)) {
  353. require_once 'Zend/Amf/Server/Exception.php';
  354. throw new Zend_Amf_Server_Exception('Login failed: username not supplied');
  355. }
  356. if(!$this->_handleAuth($userid, $password)) {
  357. require_once 'Zend/Amf/Server/Exception.php';
  358. throw new Zend_Amf_Server_Exception('Authentication failed');
  359. }
  360. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  361. break;
  362. case Zend_Amf_Value_Messaging_CommandMessage::LOGOUT_OPERATION :
  363. if($this->_auth) {
  364. Zend_Auth::getInstance()->clearIdentity();
  365. }
  366. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  367. break;
  368. default :
  369. require_once 'Zend/Amf/Server/Exception.php';
  370. throw new Zend_Amf_Server_Exception('CommandMessage::' . $message->operation . ' not implemented');
  371. break;
  372. }
  373. return $return;
  374. }
  375. /**
  376. * Create appropriate error message
  377. *
  378. * @param int $objectEncoding Current AMF encoding
  379. * @param string $message Message that was being processed when error happened
  380. * @param string $description Error description
  381. * @param mixed $detail Detailed data about the error
  382. * @param int $code Error code
  383. * @param int $line Error line
  384. * @return Zend_Amf_Value_Messaging_ErrorMessage|array
  385. */
  386. protected function _errorMessage($objectEncoding, $message, $description, $detail, $code, $line)
  387. {
  388. $return = null;
  389. switch ($objectEncoding) {
  390. case Zend_Amf_Constants::AMF0_OBJECT_ENCODING :
  391. return array (
  392. 'description' => ($this->isProduction ()) ? '' : $description,
  393. 'detail' => ($this->isProduction ()) ? '' : $detail,
  394. 'line' => ($this->isProduction ()) ? 0 : $line,
  395. 'code' => $code
  396. );
  397. case Zend_Amf_Constants::AMF3_OBJECT_ENCODING :
  398. require_once 'Zend/Amf/Value/Messaging/ErrorMessage.php';
  399. $return = new Zend_Amf_Value_Messaging_ErrorMessage ( $message );
  400. $return->faultString = $this->isProduction () ? '' : $description;
  401. $return->faultCode = $code;
  402. $return->faultDetail = $this->isProduction () ? '' : $detail;
  403. break;
  404. }
  405. return $return;
  406. }
  407. /**
  408. * Handle AMF authentication
  409. *
  410. * @param string $userid
  411. * @param string $password
  412. * @return boolean
  413. */
  414. protected function _handleAuth( $userid, $password)
  415. {
  416. if (!$this->_auth) {
  417. return true;
  418. }
  419. $this->_auth->setCredentials($userid, $password);
  420. $auth = Zend_Auth::getInstance();
  421. $result = $auth->authenticate($this->_auth);
  422. if ($result->isValid()) {
  423. if (!$this->isSession()) {
  424. $this->setSession();
  425. }
  426. return true;
  427. } else {
  428. // authentication failed, good bye
  429. require_once 'Zend/Amf/Server/Exception.php';
  430. throw new Zend_Amf_Server_Exception(
  431. "Authentication failed: " . join("\n",
  432. $result->getMessages()), $result->getCode());
  433. }
  434. }
  435. /**
  436. * Takes the deserialized AMF request and performs any operations.
  437. *
  438. * @todo should implement and SPL observer pattern for custom AMF headers
  439. * @todo DescribeService support
  440. * @param Zend_Amf_Request $request
  441. * @return Zend_Amf_Response
  442. * @throws Zend_Amf_server_Exception|Exception
  443. */
  444. protected function _handle(Zend_Amf_Request $request)
  445. {
  446. // Get the object encoding of the request.
  447. $objectEncoding = $request->getObjectEncoding();
  448. // create a response object to place the output from the services.
  449. $response = $this->getResponse();
  450. // set response encoding
  451. $response->setObjectEncoding($objectEncoding);
  452. $responseBody = $request->getAmfBodies();
  453. $handleAuth = false;
  454. if ($this->_auth) {
  455. $headers = $request->getAmfHeaders();
  456. if (isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]) &&
  457. isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid)) {
  458. $handleAuth = true;
  459. }
  460. }
  461. // Iterate through each of the service calls in the AMF request
  462. foreach($responseBody as $body)
  463. {
  464. try {
  465. if ($handleAuth) {
  466. if ($this->_handleAuth(
  467. $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid,
  468. $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password)) {
  469. // use RequestPersistentHeader to clear credentials
  470. $response->addAmfHeader(
  471. new Zend_Amf_Value_MessageHeader(
  472. Zend_Amf_Constants::PERSISTENT_HEADER,
  473. false,
  474. new Zend_Amf_Value_MessageHeader(
  475. Zend_Amf_Constants::CREDENTIALS_HEADER,
  476. false, null)));
  477. $handleAuth = false;
  478. }
  479. }
  480. if ($objectEncoding == Zend_Amf_Constants::AMF0_OBJECT_ENCODING) {
  481. // AMF0 Object Encoding
  482. $targetURI = $body->getTargetURI();
  483. $message = '';
  484. // Split the target string into its values.
  485. $source = substr($targetURI, 0, strrpos($targetURI, '.'));
  486. if ($source) {
  487. // Break off method name from namespace into source
  488. $method = substr(strrchr($targetURI, '.'), 1);
  489. $return = $this->_dispatch($method, $body->getData(), $source);
  490. } else {
  491. // Just have a method name.
  492. $return = $this->_dispatch($targetURI, $body->getData());
  493. }
  494. } else {
  495. // AMF3 read message type
  496. $message = $body->getData();
  497. if ($message instanceof Zend_Amf_Value_Messaging_CommandMessage) {
  498. // async call with command message
  499. $return = $this->_loadCommandMessage($message);
  500. } elseif ($message instanceof Zend_Amf_Value_Messaging_RemotingMessage) {
  501. require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
  502. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  503. $return->body = $this->_dispatch($message->operation, $message->body, $message->source);
  504. } else {
  505. // Amf3 message sent with netConnection
  506. $targetURI = $body->getTargetURI();
  507. // Split the target string into its values.
  508. $source = substr($targetURI, 0, strrpos($targetURI, '.'));
  509. if ($source) {
  510. // Break off method name from namespace into source
  511. $method = substr(strrchr($targetURI, '.'), 1);
  512. $return = $this->_dispatch($method, $body->getData(), $source);
  513. } else {
  514. // Just have a method name.
  515. $return = $this->_dispatch($targetURI, $body->getData());
  516. }
  517. }
  518. }
  519. $responseType = Zend_AMF_Constants::RESULT_METHOD;
  520. } catch (Exception $e) {
  521. $return = $this->_errorMessage($objectEncoding, $message,
  522. $e->getMessage(), $e->getTraceAsString(),$e->getCode(), $e->getLine());
  523. $responseType = Zend_AMF_Constants::STATUS_METHOD;
  524. }
  525. $responseURI = $body->getResponseURI() . $responseType;
  526. $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return);
  527. $response->addAmfBody($newBody);
  528. }
  529. // Add a session header to the body if session is requested.
  530. if($this->isSession()) {
  531. $currentID = session_id();
  532. $joint = "?";
  533. if(isset($_SERVER['QUERY_STRING'])) {
  534. if(!strpos($_SERVER['QUERY_STRING'], $currentID) !== FALSE) {
  535. if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) {
  536. $joint = "&";
  537. }
  538. }
  539. }
  540. // create a new AMF message header with the session id as a variable.
  541. $sessionValue = $joint . $this->_sessionName . "=" . $currentID;
  542. $sessionHeader = new Zend_Amf_Value_MessageHeader(Zend_Amf_Constants::URL_APPEND_HEADER, false, $sessionValue);
  543. $response->addAmfHeader($sessionHeader);
  544. }
  545. // serialize the response and return serialized body.
  546. $response->finalize();
  547. }
  548. /**
  549. * Handle an AMF call from the gateway.
  550. *
  551. * @param null|Zend_Amf_Request $request Optional
  552. * @return Zend_Amf_Response
  553. */
  554. public function handle($request = null)
  555. {
  556. // Check if request was passed otherwise get it from the server
  557. if (is_null($request) || !$request instanceof Zend_Amf_Request) {
  558. $request = $this->getRequest();
  559. } else {
  560. $this->setRequest($request);
  561. }
  562. if ($this->isSession()) {
  563. // Check if a session is being sent from the amf call
  564. if (isset($_COOKIE[$this->_sessionName])) {
  565. session_id($_COOKIE[$this->_sessionName]);
  566. }
  567. }
  568. // Check for errors that may have happend in deserialization of Request.
  569. try {
  570. // Take converted PHP objects and handle service call.
  571. // Serialize to Zend_Amf_response for output stream
  572. $this->_handle($request);
  573. $response = $this->getResponse();
  574. } catch (Exception $e) {
  575. // Handle any errors in the serialization and service calls.
  576. require_once 'Zend/Amf/Server/Exception.php';
  577. throw new Zend_Amf_Server_Exception('Handle error: ' . $e->getMessage() . ' ' . $e->getLine(), 0, $e);
  578. }
  579. // Return the Amf serialized output string
  580. return $response;
  581. }
  582. /**
  583. * Set request object
  584. *
  585. * @param string|Zend_Amf_Request $request
  586. * @return Zend_Amf_Server
  587. */
  588. public function setRequest($request)
  589. {
  590. if (is_string($request) && class_exists($request)) {
  591. $request = new $request();
  592. if (!$request instanceof Zend_Amf_Request) {
  593. require_once 'Zend/Amf/Server/Exception.php';
  594. throw new Zend_Amf_Server_Exception('Invalid request class');
  595. }
  596. } elseif (!$request instanceof Zend_Amf_Request) {
  597. require_once 'Zend/Amf/Server/Exception.php';
  598. throw new Zend_Amf_Server_Exception('Invalid request object');
  599. }
  600. $this->_request = $request;
  601. return $this;
  602. }
  603. /**
  604. * Return currently registered request object
  605. *
  606. * @return null|Zend_Amf_Request
  607. */
  608. public function getRequest()
  609. {
  610. if (null === $this->_request) {
  611. require_once 'Zend/Amf/Request/Http.php';
  612. $this->setRequest(new Zend_Amf_Request_Http());
  613. }
  614. return $this->_request;
  615. }
  616. /**
  617. * Public access method to private Zend_Amf_Server_Response reference
  618. *
  619. * @param string|Zend_Amf_Server_Response $response
  620. * @return Zend_Amf_Server
  621. */
  622. public function setResponse($response)
  623. {
  624. if (is_string($response) && class_exists($response)) {
  625. $response = new $response();
  626. if (!$response instanceof Zend_Amf_Response) {
  627. require_once 'Zend/Amf/Server/Exception.php';
  628. throw new Zend_Amf_Server_Exception('Invalid response class');
  629. }
  630. } elseif (!$response instanceof Zend_Amf_Response) {
  631. require_once 'Zend/Amf/Server/Exception.php';
  632. throw new Zend_Amf_Server_Exception('Invalid response object');
  633. }
  634. $this->_response = $response;
  635. return $this;
  636. }
  637. /**
  638. * get a reference to the Zend_Amf_response instance
  639. *
  640. * @return Zend_Amf_Server_Response
  641. */
  642. public function getResponse()
  643. {
  644. if (null === ($response = $this->_response)) {
  645. require_once 'Zend/Amf/Response/Http.php';
  646. $this->setResponse(new Zend_Amf_Response_Http());
  647. }
  648. return $this->_response;
  649. }
  650. /**
  651. * Attach a class or object to the server
  652. *
  653. * Class may be either a class name or an instantiated object. Reflection
  654. * is done on the class or object to determine the available public
  655. * methods, and each is attached to the server as and available method. If
  656. * a $namespace has been provided, that namespace is used to prefix
  657. * AMF service call.
  658. *
  659. * @param string|object $class
  660. * @param string $namespace Optional
  661. * @param mixed $arg Optional arguments to pass to a method
  662. * @return Zend_Amf_Server
  663. * @throws Zend_Amf_Server_Exception on invalid input
  664. */
  665. public function setClass($class, $namespace = '', $argv = null)
  666. {
  667. if (is_string($class) && !class_exists($class)){
  668. require_once 'Zend/Amf/Server/Exception.php';
  669. throw new Zend_Amf_Server_Exception('Invalid method or class');
  670. } elseif (!is_string($class) && !is_object($class)) {
  671. require_once 'Zend/Amf/Server/Exception.php';
  672. throw new Zend_Amf_Server_Exception('Invalid method or class; must be a classname or object');
  673. }
  674. $argv = null;
  675. if (2 < func_num_args()) {
  676. $argv = array_slice(func_get_args(), 2);
  677. }
  678. // Use the class name as the name space by default.
  679. if ($namespace == '') {
  680. $namespace = is_object($class) ? get_class($class) : $class;
  681. }
  682. $this->_classAllowed[is_object($class) ? get_class($class) : $class] = true;
  683. $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $argv, $namespace);
  684. $this->_buildDispatchTable();
  685. return $this;
  686. }
  687. /**
  688. * Attach a function to the server
  689. *
  690. * Additional arguments to pass to the function at dispatch may be passed;
  691. * any arguments following the namespace will be aggregated and passed at
  692. * dispatch time.
  693. *
  694. * @param string|array $function Valid callback
  695. * @param string $namespace Optional namespace prefix
  696. * @return Zend_Amf_Server
  697. * @throws Zend_Amf_Server_Exception
  698. */
  699. public function addFunction($function, $namespace = '')
  700. {
  701. if (!is_string($function) && !is_array($function)) {
  702. require_once 'Zend/Amf/Server/Exception.php';
  703. throw new Zend_Amf_Server_Exception('Unable to attach function');
  704. }
  705. $argv = null;
  706. if (2 < func_num_args()) {
  707. $argv = array_slice(func_get_args(), 2);
  708. }
  709. $function = (array) $function;
  710. foreach ($function as $func) {
  711. if (!is_string($func) || !function_exists($func)) {
  712. require_once 'Zend/Amf/Server/Exception.php';
  713. throw new Zend_Amf_Server_Exception('Unable to attach function');
  714. }
  715. $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace);
  716. }
  717. $this->_buildDispatchTable();
  718. return $this;
  719. }
  720. /**
  721. * Creates an array of directories in which services can reside.
  722. * TODO: add support for prefixes?
  723. *
  724. * @param string $dir
  725. */
  726. public function addDirectory($dir)
  727. {
  728. $this->getLoader()->addPrefixPath("", $dir);
  729. }
  730. /**
  731. * Returns an array of directories that can hold services.
  732. *
  733. * @return array
  734. */
  735. public function getDirectory()
  736. {
  737. return $this->getLoader()->getPaths("");
  738. }
  739. /**
  740. * (Re)Build the dispatch table
  741. *
  742. * The dispatch table consists of a an array of method name =>
  743. * Zend_Server_Reflection_Function_Abstract pairs
  744. *
  745. * @return void
  746. */
  747. protected function _buildDispatchTable()
  748. {
  749. $table = array();
  750. foreach ($this->_methods as $key => $dispatchable) {
  751. if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) {
  752. $ns = $dispatchable->getNamespace();
  753. $name = $dispatchable->getName();
  754. $name = empty($ns) ? $name : $ns . '.' . $name;
  755. if (isset($table[$name])) {
  756. require_once 'Zend/Amf/Server/Exception.php';
  757. throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name);
  758. }
  759. $table[$name] = $dispatchable;
  760. continue;
  761. }
  762. if ($dispatchable instanceof Zend_Server_Reflection_Class) {
  763. foreach ($dispatchable->getMethods() as $method) {
  764. $ns = $method->getNamespace();
  765. $name = $method->getName();
  766. $name = empty($ns) ? $name : $ns . '.' . $name;
  767. if (isset($table[$name])) {
  768. require_once 'Zend/Amf/Server/Exception.php';
  769. throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name);
  770. }
  771. $table[$name] = $method;
  772. continue;
  773. }
  774. }
  775. }
  776. $this->_table = $table;
  777. }
  778. /**
  779. * Raise a server fault
  780. *
  781. * Unimplemented
  782. *
  783. * @param string|Exception $fault
  784. * @return void
  785. */
  786. public function fault($fault = null, $code = 404)
  787. {
  788. }
  789. /**
  790. * Returns a list of registered methods
  791. *
  792. * Returns an array of dispatchables (Zend_Server_Reflection_Function,
  793. * _Method, and _Class items).
  794. *
  795. * @return array
  796. */
  797. public function getFunctions()
  798. {
  799. return $this->_table;
  800. }
  801. /**
  802. * Set server persistence
  803. *
  804. * Unimplemented
  805. *
  806. * @param mixed $mode
  807. * @return void
  808. */
  809. public function setPersistence($mode)
  810. {
  811. }
  812. /**
  813. * Load server definition
  814. *
  815. * Unimplemented
  816. *
  817. * @param array $definition
  818. * @return void
  819. */
  820. public function loadFunctions($definition)
  821. {
  822. }
  823. /**
  824. * Map ActionScript classes to PHP classes
  825. *
  826. * @param string $asClass
  827. * @param string $phpClass
  828. * @return Zend_Amf_Server
  829. */
  830. public function setClassMap($asClass, $phpClass)
  831. {
  832. require_once 'Zend/Amf/Parse/TypeLoader.php';
  833. Zend_Amf_Parse_TypeLoader::setMapping($asClass, $phpClass);
  834. return $this;
  835. }
  836. /**
  837. * List all available methods
  838. *
  839. * Returns an array of method names.
  840. *
  841. * @return array
  842. */
  843. public function listMethods()
  844. {
  845. return array_keys($this->_table);
  846. }
  847. }