PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Zend/Amf/Server.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 936 lines | 462 code | 87 blank | 387 comment | 79 complexity | 9afc96bc31f7a03f0da3926b8728fc0a MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  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: Server.php 23256 2010-10-26 12:51:54Z alexander $
  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. }
  292. if (!isset($this->_table[$qualifiedName])) {
  293. // Source is null or doesn't contain specified method
  294. #require_once 'Zend/Amf/Server/Exception.php';
  295. throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist');
  296. }
  297. }
  298. $info = $this->_table[$qualifiedName];
  299. $argv = $info->getInvokeArguments();
  300. if (0 < count($argv)) {
  301. $params = array_merge($params, $argv);
  302. }
  303. if ($info instanceof Zend_Server_Reflection_Function) {
  304. $func = $info->getName();
  305. $this->_checkAcl(null, $func);
  306. $return = call_user_func_array($func, $params);
  307. } elseif ($info instanceof Zend_Server_Reflection_Method) {
  308. // Get class
  309. $class = $info->getDeclaringClass()->getName();
  310. if ('static' == $info->isStatic()) {
  311. // for some reason, invokeArgs() does not work the same as
  312. // invoke(), and expects the first argument to be an object.
  313. // So, using a callback if the method is static.
  314. $this->_checkAcl($class, $info->getName());
  315. $return = call_user_func_array(array($class, $info->getName()), $params);
  316. } else {
  317. // Object methods
  318. try {
  319. $object = $info->getDeclaringClass()->newInstance();
  320. } catch (Exception $e) {
  321. #require_once 'Zend/Amf/Server/Exception.php';
  322. throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621, $e);
  323. }
  324. $this->_checkAcl($object, $info->getName());
  325. $return = $info->invokeArgs($object, $params);
  326. }
  327. } else {
  328. #require_once 'Zend/Amf/Server/Exception.php';
  329. throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info));
  330. }
  331. return $return;
  332. }
  333. /**
  334. * Handles each of the 11 different command message types.
  335. *
  336. * A command message is a flex.messaging.messages.CommandMessage
  337. *
  338. * @see Zend_Amf_Value_Messaging_CommandMessage
  339. * @param Zend_Amf_Value_Messaging_CommandMessage $message
  340. * @return Zend_Amf_Value_Messaging_AcknowledgeMessage
  341. */
  342. protected function _loadCommandMessage(Zend_Amf_Value_Messaging_CommandMessage $message)
  343. {
  344. #require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
  345. switch($message->operation) {
  346. case Zend_Amf_Value_Messaging_CommandMessage::DISCONNECT_OPERATION :
  347. case Zend_Amf_Value_Messaging_CommandMessage::CLIENT_PING_OPERATION :
  348. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  349. break;
  350. case Zend_Amf_Value_Messaging_CommandMessage::LOGIN_OPERATION :
  351. $data = explode(':', base64_decode($message->body));
  352. $userid = $data[0];
  353. $password = isset($data[1])?$data[1]:"";
  354. if(empty($userid)) {
  355. #require_once 'Zend/Amf/Server/Exception.php';
  356. throw new Zend_Amf_Server_Exception('Login failed: username not supplied');
  357. }
  358. if(!$this->_handleAuth($userid, $password)) {
  359. #require_once 'Zend/Amf/Server/Exception.php';
  360. throw new Zend_Amf_Server_Exception('Authentication failed');
  361. }
  362. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  363. break;
  364. case Zend_Amf_Value_Messaging_CommandMessage::LOGOUT_OPERATION :
  365. if($this->_auth) {
  366. Zend_Auth::getInstance()->clearIdentity();
  367. }
  368. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  369. break;
  370. default :
  371. #require_once 'Zend/Amf/Server/Exception.php';
  372. throw new Zend_Amf_Server_Exception('CommandMessage::' . $message->operation . ' not implemented');
  373. break;
  374. }
  375. return $return;
  376. }
  377. /**
  378. * Create appropriate error message
  379. *
  380. * @param int $objectEncoding Current AMF encoding
  381. * @param string $message Message that was being processed when error happened
  382. * @param string $description Error description
  383. * @param mixed $detail Detailed data about the error
  384. * @param int $code Error code
  385. * @param int $line Error line
  386. * @return Zend_Amf_Value_Messaging_ErrorMessage|array
  387. */
  388. protected function _errorMessage($objectEncoding, $message, $description, $detail, $code, $line)
  389. {
  390. $return = null;
  391. switch ($objectEncoding) {
  392. case Zend_Amf_Constants::AMF0_OBJECT_ENCODING :
  393. return array (
  394. 'description' => ($this->isProduction ()) ? '' : $description,
  395. 'detail' => ($this->isProduction ()) ? '' : $detail,
  396. 'line' => ($this->isProduction ()) ? 0 : $line,
  397. 'code' => $code
  398. );
  399. case Zend_Amf_Constants::AMF3_OBJECT_ENCODING :
  400. #require_once 'Zend/Amf/Value/Messaging/ErrorMessage.php';
  401. $return = new Zend_Amf_Value_Messaging_ErrorMessage ( $message );
  402. $return->faultString = $this->isProduction () ? '' : $description;
  403. $return->faultCode = $code;
  404. $return->faultDetail = $this->isProduction () ? '' : $detail;
  405. break;
  406. }
  407. return $return;
  408. }
  409. /**
  410. * Handle AMF authentication
  411. *
  412. * @param string $userid
  413. * @param string $password
  414. * @return boolean
  415. */
  416. protected function _handleAuth( $userid, $password)
  417. {
  418. if (!$this->_auth) {
  419. return true;
  420. }
  421. $this->_auth->setCredentials($userid, $password);
  422. $auth = Zend_Auth::getInstance();
  423. $result = $auth->authenticate($this->_auth);
  424. if ($result->isValid()) {
  425. if (!$this->isSession()) {
  426. $this->setSession();
  427. }
  428. return true;
  429. } else {
  430. // authentication failed, good bye
  431. #require_once 'Zend/Amf/Server/Exception.php';
  432. throw new Zend_Amf_Server_Exception(
  433. "Authentication failed: " . join("\n",
  434. $result->getMessages()), $result->getCode());
  435. }
  436. }
  437. /**
  438. * Takes the deserialized AMF request and performs any operations.
  439. *
  440. * @todo should implement and SPL observer pattern for custom AMF headers
  441. * @todo DescribeService support
  442. * @param Zend_Amf_Request $request
  443. * @return Zend_Amf_Response
  444. * @throws Zend_Amf_server_Exception|Exception
  445. */
  446. protected function _handle(Zend_Amf_Request $request)
  447. {
  448. // Get the object encoding of the request.
  449. $objectEncoding = $request->getObjectEncoding();
  450. // create a response object to place the output from the services.
  451. $response = $this->getResponse();
  452. // set response encoding
  453. $response->setObjectEncoding($objectEncoding);
  454. $responseBody = $request->getAmfBodies();
  455. $handleAuth = false;
  456. if ($this->_auth) {
  457. $headers = $request->getAmfHeaders();
  458. if (isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]) &&
  459. isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid)) {
  460. $handleAuth = true;
  461. }
  462. }
  463. // Iterate through each of the service calls in the AMF request
  464. foreach($responseBody as $body)
  465. {
  466. try {
  467. if ($handleAuth) {
  468. if ($this->_handleAuth(
  469. $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid,
  470. $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password)) {
  471. // use RequestPersistentHeader to clear credentials
  472. $response->addAmfHeader(
  473. new Zend_Amf_Value_MessageHeader(
  474. Zend_Amf_Constants::PERSISTENT_HEADER,
  475. false,
  476. new Zend_Amf_Value_MessageHeader(
  477. Zend_Amf_Constants::CREDENTIALS_HEADER,
  478. false, null)));
  479. $handleAuth = false;
  480. }
  481. }
  482. if ($objectEncoding == Zend_Amf_Constants::AMF0_OBJECT_ENCODING) {
  483. // AMF0 Object Encoding
  484. $targetURI = $body->getTargetURI();
  485. $message = '';
  486. // Split the target string into its values.
  487. $source = substr($targetURI, 0, strrpos($targetURI, '.'));
  488. if ($source) {
  489. // Break off method name from namespace into source
  490. $method = substr(strrchr($targetURI, '.'), 1);
  491. $return = $this->_dispatch($method, $body->getData(), $source);
  492. } else {
  493. // Just have a method name.
  494. $return = $this->_dispatch($targetURI, $body->getData());
  495. }
  496. } else {
  497. // AMF3 read message type
  498. $message = $body->getData();
  499. if ($message instanceof Zend_Amf_Value_Messaging_CommandMessage) {
  500. // async call with command message
  501. $return = $this->_loadCommandMessage($message);
  502. } elseif ($message instanceof Zend_Amf_Value_Messaging_RemotingMessage) {
  503. #require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php';
  504. $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message);
  505. $return->body = $this->_dispatch($message->operation, $message->body, $message->source);
  506. } else {
  507. // Amf3 message sent with netConnection
  508. $targetURI = $body->getTargetURI();
  509. // Split the target string into its values.
  510. $source = substr($targetURI, 0, strrpos($targetURI, '.'));
  511. if ($source) {
  512. // Break off method name from namespace into source
  513. $method = substr(strrchr($targetURI, '.'), 1);
  514. $return = $this->_dispatch($method, $body->getData(), $source);
  515. } else {
  516. // Just have a method name.
  517. $return = $this->_dispatch($targetURI, $body->getData());
  518. }
  519. }
  520. }
  521. $responseType = Zend_AMF_Constants::RESULT_METHOD;
  522. } catch (Exception $e) {
  523. $return = $this->_errorMessage($objectEncoding, $message,
  524. $e->getMessage(), $e->getTraceAsString(),$e->getCode(), $e->getLine());
  525. $responseType = Zend_AMF_Constants::STATUS_METHOD;
  526. }
  527. $responseURI = $body->getResponseURI() . $responseType;
  528. $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return);
  529. $response->addAmfBody($newBody);
  530. }
  531. // Add a session header to the body if session is requested.
  532. if($this->isSession()) {
  533. $currentID = session_id();
  534. $joint = "?";
  535. if(isset($_SERVER['QUERY_STRING'])) {
  536. if(!strpos($_SERVER['QUERY_STRING'], $currentID) !== FALSE) {
  537. if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) {
  538. $joint = "&";
  539. }
  540. }
  541. }
  542. // create a new AMF message header with the session id as a variable.
  543. $sessionValue = $joint . $this->_sessionName . "=" . $currentID;
  544. $sessionHeader = new Zend_Amf_Value_MessageHeader(Zend_Amf_Constants::URL_APPEND_HEADER, false, $sessionValue);
  545. $response->addAmfHeader($sessionHeader);
  546. }
  547. // serialize the response and return serialized body.
  548. $response->finalize();
  549. }
  550. /**
  551. * Handle an AMF call from the gateway.
  552. *
  553. * @param null|Zend_Amf_Request $request Optional
  554. * @return Zend_Amf_Response
  555. */
  556. public function handle($request = null)
  557. {
  558. // Check if request was passed otherwise get it from the server
  559. if ($request === null || !$request instanceof Zend_Amf_Request) {
  560. $request = $this->getRequest();
  561. } else {
  562. $this->setRequest($request);
  563. }
  564. if ($this->isSession()) {
  565. // Check if a session is being sent from the amf call
  566. if (isset($_COOKIE[$this->_sessionName])) {
  567. session_id($_COOKIE[$this->_sessionName]);
  568. }
  569. }
  570. // Check for errors that may have happend in deserialization of Request.
  571. try {
  572. // Take converted PHP objects and handle service call.
  573. // Serialize to Zend_Amf_response for output stream
  574. $this->_handle($request);
  575. $response = $this->getResponse();
  576. } catch (Exception $e) {
  577. // Handle any errors in the serialization and service calls.
  578. #require_once 'Zend/Amf/Server/Exception.php';
  579. throw new Zend_Amf_Server_Exception('Handle error: ' . $e->getMessage() . ' ' . $e->getLine(), 0, $e);
  580. }
  581. // Return the Amf serialized output string
  582. return $response;
  583. }
  584. /**
  585. * Set request object
  586. *
  587. * @param string|Zend_Amf_Request $request
  588. * @return Zend_Amf_Server
  589. */
  590. public function setRequest($request)
  591. {
  592. if (is_string($request) && class_exists($request)) {
  593. $request = new $request();
  594. if (!$request instanceof Zend_Amf_Request) {
  595. #require_once 'Zend/Amf/Server/Exception.php';
  596. throw new Zend_Amf_Server_Exception('Invalid request class');
  597. }
  598. } elseif (!$request instanceof Zend_Amf_Request) {
  599. #require_once 'Zend/Amf/Server/Exception.php';
  600. throw new Zend_Amf_Server_Exception('Invalid request object');
  601. }
  602. $this->_request = $request;
  603. return $this;
  604. }
  605. /**
  606. * Return currently registered request object
  607. *
  608. * @return null|Zend_Amf_Request
  609. */
  610. public function getRequest()
  611. {
  612. if (null === $this->_request) {
  613. #require_once 'Zend/Amf/Request/Http.php';
  614. $this->setRequest(new Zend_Amf_Request_Http());
  615. }
  616. return $this->_request;
  617. }
  618. /**
  619. * Public access method to private Zend_Amf_Server_Response reference
  620. *
  621. * @param string|Zend_Amf_Server_Response $response
  622. * @return Zend_Amf_Server
  623. */
  624. public function setResponse($response)
  625. {
  626. if (is_string($response) && class_exists($response)) {
  627. $response = new $response();
  628. if (!$response instanceof Zend_Amf_Response) {
  629. #require_once 'Zend/Amf/Server/Exception.php';
  630. throw new Zend_Amf_Server_Exception('Invalid response class');
  631. }
  632. } elseif (!$response instanceof Zend_Amf_Response) {
  633. #require_once 'Zend/Amf/Server/Exception.php';
  634. throw new Zend_Amf_Server_Exception('Invalid response object');
  635. }
  636. $this->_response = $response;
  637. return $this;
  638. }
  639. /**
  640. * get a reference to the Zend_Amf_response instance
  641. *
  642. * @return Zend_Amf_Server_Response
  643. */
  644. public function getResponse()
  645. {
  646. if (null === ($response = $this->_response)) {
  647. #require_once 'Zend/Amf/Response/Http.php';
  648. $this->setResponse(new Zend_Amf_Response_Http());
  649. }
  650. return $this->_response;
  651. }
  652. /**
  653. * Attach a class or object to the server
  654. *
  655. * Class may be either a class name or an instantiated object. Reflection
  656. * is done on the class or object to determine the available public
  657. * methods, and each is attached to the server as and available method. If
  658. * a $namespace has been provided, that namespace is used to prefix
  659. * AMF service call.
  660. *
  661. * @param string|object $class
  662. * @param string $namespace Optional
  663. * @param mixed $arg Optional arguments to pass to a method
  664. * @return Zend_Amf_Server
  665. * @throws Zend_Amf_Server_Exception on invalid input
  666. */
  667. public function setClass($class, $namespace = '', $argv = null)
  668. {
  669. if (is_string($class) && !class_exists($class)){
  670. #require_once 'Zend/Amf/Server/Exception.php';
  671. throw new Zend_Amf_Server_Exception('Invalid method or class');
  672. } elseif (!is_string($class) && !is_object($class)) {
  673. #require_once 'Zend/Amf/Server/Exception.php';
  674. throw new Zend_Amf_Server_Exception('Invalid method or class; must be a classname or object');
  675. }
  676. $argv = null;
  677. if (2 < func_num_args()) {
  678. $argv = array_slice(func_get_args(), 2);
  679. }
  680. // Use the class name as the name space by default.
  681. if ($namespace == '') {
  682. $namespace = is_object($class) ? get_class($class) : $class;
  683. }
  684. $this->_classAllowed[is_object($class) ? get_class($class) : $class] = true;
  685. $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $argv, $namespace);
  686. $this->_buildDispatchTable();
  687. return $this;
  688. }
  689. /**
  690. * Attach a function to the server
  691. *
  692. * Additional arguments to pass to the function at dispatch may be passed;
  693. * any arguments following the namespace will be aggregated and passed at
  694. * dispatch time.
  695. *
  696. * @param string|array $function Valid callback
  697. * @param string $namespace Optional namespace prefix
  698. * @return Zend_Amf_Server
  699. * @throws Zend_Amf_Server_Exception
  700. */
  701. public function addFunction($function, $namespace = '')
  702. {
  703. if (!is_string($function) && !is_array($function)) {
  704. #require_once 'Zend/Amf/Server/Exception.php';
  705. throw new Zend_Amf_Server_Exception('Unable to attach function');
  706. }
  707. $argv = null;
  708. if (2 < func_num_args()) {
  709. $argv = array_slice(func_get_args(), 2);
  710. }
  711. $function = (array) $function;
  712. foreach ($function as $func) {
  713. if (!is_string($func) || !function_exists($func)) {
  714. #require_once 'Zend/Amf/Server/Exception.php';
  715. throw new Zend_Amf_Server_Exception('Unable to attach function');
  716. }
  717. $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace);
  718. }
  719. $this->_buildDispatchTable();
  720. return $this;
  721. }
  722. /**
  723. * Creates an array of directories in which services can reside.
  724. * TODO: add support for prefixes?
  725. *
  726. * @param string $dir
  727. */
  728. public function addDirectory($dir)
  729. {
  730. $this->getLoader()->addPrefixPath("", $dir);
  731. }
  732. /**
  733. * Returns an array of directories that can hold services.
  734. *
  735. * @return array
  736. */
  737. public function getDirectory()
  738. {
  739. return $this->getLoader()->getPaths("");
  740. }
  741. /**
  742. * (Re)Build the dispatch table
  743. *
  744. * The dispatch table consists of a an array of method name =>
  745. * Zend_Server_Reflection_Function_Abstract pairs
  746. *
  747. * @return void
  748. */
  749. protected function _buildDispatchTable()
  750. {
  751. $table = array();
  752. foreach ($this->_methods as $key => $dispatchable) {
  753. if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) {
  754. $ns = $dispatchable->getNamespace();
  755. $name = $dispatchable->getName();
  756. $name = empty($ns) ? $name : $ns . '.' . $name;
  757. if (isset($table[$name])) {
  758. #require_once 'Zend/Amf/Server/Exception.php';
  759. throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name);
  760. }
  761. $table[$name] = $dispatchable;
  762. continue;
  763. }
  764. if ($dispatchable instanceof Zend_Server_Reflection_Class) {
  765. foreach ($dispatchable->getMethods() as $method) {
  766. $ns = $method->getNamespace();
  767. $name = $method->getName();
  768. $name = empty($ns) ? $name : $ns . '.' . $name;
  769. if (isset($table[$name])) {
  770. #require_once 'Zend/Amf/Server/Exception.php';
  771. throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name);
  772. }
  773. $table[$name] = $method;
  774. continue;
  775. }
  776. }
  777. }
  778. $this->_table = $table;
  779. }
  780. /**
  781. * Raise a server fault
  782. *
  783. * Unimplemented
  784. *
  785. * @param string|Exception $fault
  786. * @return void
  787. */
  788. public function fault($fault = null, $code = 404)
  789. {
  790. }
  791. /**
  792. * Returns a list of registered methods
  793. *
  794. * Returns an array of dispatchables (Zend_Server_Reflection_Function,
  795. * _Method, and _Class items).
  796. *
  797. * @return array
  798. */
  799. public function getFunctions()
  800. {
  801. return $this->_table;
  802. }
  803. /**
  804. * Set server persistence
  805. *
  806. * Unimplemented
  807. *
  808. * @param mixed $mode
  809. * @return void
  810. */
  811. public function setPersistence($mode)
  812. {
  813. }
  814. /**
  815. * Load server definition
  816. *
  817. * Unimplemented
  818. *
  819. * @param array $definition
  820. * @return void
  821. */
  822. public function loadFunctions($definition)
  823. {
  824. }
  825. /**
  826. * Map ActionScript classes to PHP classes
  827. *
  828. * @param string $asClass
  829. * @param string $phpClass
  830. * @return Zend_Amf_Server
  831. */
  832. public function setClassMap($asClass, $phpClass)
  833. {
  834. #require_once 'Zend/Amf/Parse/TypeLoader.php';
  835. Zend_Amf_Parse_TypeLoader::setMapping($asClass, $phpClass);
  836. return $this;
  837. }
  838. /**
  839. * List all available methods
  840. *
  841. * Returns an array of method names.
  842. *
  843. * @return array
  844. */
  845. public function listMethods()
  846. {
  847. return array_keys($this->_table);
  848. }
  849. }