File indexing completed on 2024-12-22 05:36:28
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Amf 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** @see Zend_Server_Interface */ 0023 // require_once 'Zend/Server/Interface.php'; 0024 0025 /** @see Zend_Server_Reflection */ 0026 // require_once 'Zend/Server/Reflection.php'; 0027 0028 /** @see Zend_Amf_Constants */ 0029 // require_once 'Zend/Amf/Constants.php'; 0030 0031 /** @see Zend_Amf_Value_MessageBody */ 0032 // require_once 'Zend/Amf/Value/MessageBody.php'; 0033 0034 /** @see Zend_Amf_Value_MessageHeader */ 0035 // require_once 'Zend/Amf/Value/MessageHeader.php'; 0036 0037 /** @see Zend_Amf_Value_Messaging_CommandMessage */ 0038 // require_once 'Zend/Amf/Value/Messaging/CommandMessage.php'; 0039 0040 /** @see Zend_Loader_PluginLoader */ 0041 // require_once 'Zend/Loader/PluginLoader.php'; 0042 0043 /** @see Zend_Amf_Parse_TypeLoader */ 0044 // require_once 'Zend/Amf/Parse/TypeLoader.php'; 0045 0046 /** @see Zend_Auth */ 0047 // require_once 'Zend/Auth.php'; 0048 /** 0049 * An AMF gateway server implementation to allow the connection of the Adobe Flash Player to 0050 * Zend Framework 0051 * 0052 * @todo Make the reflection methods cache and autoload. 0053 * @package Zend_Amf 0054 * @subpackage Server 0055 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0056 * @license http://framework.zend.com/license/new-bsd New BSD License 0057 */ 0058 class Zend_Amf_Server implements Zend_Server_Interface 0059 { 0060 /** 0061 * Array of dispatchables 0062 * @var array 0063 */ 0064 protected $_methods = array(); 0065 0066 /** 0067 * Array of classes that can be called without being explicitly loaded 0068 * 0069 * Keys are class names. 0070 * 0071 * @var array 0072 */ 0073 protected $_classAllowed = array(); 0074 0075 /** 0076 * Loader for classes in added directories 0077 * @var Zend_Loader_PluginLoader 0078 */ 0079 protected $_loader; 0080 0081 /** 0082 * @var bool Production flag; whether or not to return exception messages 0083 */ 0084 protected $_production = true; 0085 0086 /** 0087 * Request processed 0088 * @var null|Zend_Amf_Request 0089 */ 0090 protected $_request = null; 0091 0092 /** 0093 * Class to use for responses 0094 * @var null|Zend_Amf_Response 0095 */ 0096 protected $_response; 0097 0098 /** 0099 * Dispatch table of name => method pairs 0100 * @var array 0101 */ 0102 protected $_table = array(); 0103 0104 /** 0105 * 0106 * @var bool session flag; whether or not to add a session to each response. 0107 */ 0108 protected $_session = false; 0109 0110 /** 0111 * Namespace allows all AMF calls to not clobber other PHP session variables 0112 * @var Zend_Session_NameSpace default session namespace zend_amf 0113 */ 0114 protected $_sesionNamespace = 'zend_amf'; 0115 0116 /** 0117 * Set the default session.name if php_ 0118 * @var string 0119 */ 0120 protected $_sessionName = 'PHPSESSID'; 0121 0122 /** 0123 * Authentication handler object 0124 * 0125 * @var Zend_Amf_Auth_Abstract 0126 */ 0127 protected $_auth; 0128 /** 0129 * ACL handler object 0130 * 0131 * @var Zend_Acl 0132 */ 0133 protected $_acl; 0134 /** 0135 * The server constructor 0136 */ 0137 public function __construct() 0138 { 0139 Zend_Amf_Parse_TypeLoader::setResourceLoader(new Zend_Loader_PluginLoader(array("Zend_Amf_Parse_Resource" => "Zend/Amf/Parse/Resource"))); 0140 } 0141 0142 /** 0143 * Set authentication adapter 0144 * 0145 * If the authentication adapter implements a "getAcl()" method, populate 0146 * the ACL of this instance with it (if none exists already). 0147 * 0148 * @param Zend_Amf_Auth_Abstract $auth 0149 * @return Zend_Amf_Server 0150 */ 0151 public function setAuth(Zend_Amf_Auth_Abstract $auth) 0152 { 0153 $this->_auth = $auth; 0154 if ((null === $this->getAcl()) && method_exists($auth, 'getAcl')) { 0155 $this->setAcl($auth->getAcl()); 0156 } 0157 return $this; 0158 } 0159 /** 0160 * Get authentication adapter 0161 * 0162 * @return Zend_Amf_Auth_Abstract 0163 */ 0164 public function getAuth() 0165 { 0166 return $this->_auth; 0167 } 0168 0169 /** 0170 * Set ACL adapter 0171 * 0172 * @param Zend_Acl $acl 0173 * @return Zend_Amf_Server 0174 */ 0175 public function setAcl(Zend_Acl $acl) 0176 { 0177 $this->_acl = $acl; 0178 return $this; 0179 } 0180 /** 0181 * Get ACL adapter 0182 * 0183 * @return Zend_Acl 0184 */ 0185 public function getAcl() 0186 { 0187 return $this->_acl; 0188 } 0189 0190 /** 0191 * Set production flag 0192 * 0193 * @param bool $flag 0194 * @return Zend_Amf_Server 0195 */ 0196 public function setProduction($flag) 0197 { 0198 $this->_production = (bool) $flag; 0199 return $this; 0200 } 0201 0202 /** 0203 * Whether or not the server is in production 0204 * 0205 * @return bool 0206 */ 0207 public function isProduction() 0208 { 0209 return $this->_production; 0210 } 0211 0212 /** 0213 * @param namespace of all incoming sessions defaults to Zend_Amf 0214 * @return Zend_Amf_Server 0215 */ 0216 public function setSession($namespace = 'Zend_Amf') 0217 { 0218 // require_once 'Zend/Session.php'; 0219 $this->_session = true; 0220 $this->_sesionNamespace = new Zend_Session_Namespace($namespace); 0221 return $this; 0222 } 0223 0224 /** 0225 * Whether of not the server is using sessions 0226 * @return bool 0227 */ 0228 public function isSession() 0229 { 0230 return $this->_session; 0231 } 0232 0233 /** 0234 * Check if the ACL allows accessing the function or method 0235 * 0236 * @param string|object $object Object or class being accessed 0237 * @param string $function Function or method being accessed 0238 * @return unknown_type 0239 */ 0240 protected function _checkAcl($object, $function) 0241 { 0242 if(!$this->_acl) { 0243 return true; 0244 } 0245 if($object) { 0246 $class = is_object($object)?get_class($object):$object; 0247 if(!$this->_acl->has($class)) { 0248 // require_once 'Zend/Acl/Resource.php'; 0249 $this->_acl->add(new Zend_Acl_Resource($class)); 0250 } 0251 $call = array($object, "initAcl"); 0252 if(is_callable($call) && !call_user_func($call, $this->_acl)) { 0253 // if initAcl returns false, no ACL check 0254 return true; 0255 } 0256 } else { 0257 $class = null; 0258 } 0259 0260 $auth = Zend_Auth::getInstance(); 0261 if($auth->hasIdentity()) { 0262 $role = $auth->getIdentity()->role; 0263 } else { 0264 if($this->_acl->hasRole(Zend_Amf_Constants::GUEST_ROLE)) { 0265 $role = Zend_Amf_Constants::GUEST_ROLE; 0266 } else { 0267 // require_once 'Zend/Amf/Server/Exception.php'; 0268 throw new Zend_Amf_Server_Exception("Unauthenticated access not allowed"); 0269 } 0270 } 0271 if($this->_acl->isAllowed($role, $class, $function)) { 0272 return true; 0273 } else { 0274 // require_once 'Zend/Amf/Server/Exception.php'; 0275 throw new Zend_Amf_Server_Exception("Access not allowed"); 0276 } 0277 } 0278 0279 /** 0280 * Get PluginLoader for the Server 0281 * 0282 * @return Zend_Loader_PluginLoader 0283 */ 0284 protected function getLoader() 0285 { 0286 if(empty($this->_loader)) { 0287 // require_once 'Zend/Loader/PluginLoader.php'; 0288 $this->_loader = new Zend_Loader_PluginLoader(); 0289 } 0290 return $this->_loader; 0291 } 0292 0293 /** 0294 * Loads a remote class or method and executes the function and returns 0295 * the result 0296 * 0297 * @param string $method Is the method to execute 0298 * @param mixed $param values for the method 0299 * @return mixed $response the result of executing the method 0300 * @throws Zend_Amf_Server_Exception 0301 */ 0302 protected function _dispatch($method, $params = null, $source = null) 0303 { 0304 if($source) { 0305 if(($mapped = Zend_Amf_Parse_TypeLoader::getMappedClassName($source)) !== false) { 0306 $source = $mapped; 0307 } 0308 } 0309 $qualifiedName = empty($source) ? $method : $source . '.' . $method; 0310 0311 if (!isset($this->_table[$qualifiedName])) { 0312 // if source is null a method that was not defined was called. 0313 if ($source) { 0314 $className = str_replace('.', '_', $source); 0315 if(class_exists($className, false) && !isset($this->_classAllowed[$className])) { 0316 // require_once 'Zend/Amf/Server/Exception.php'; 0317 throw new Zend_Amf_Server_Exception('Can not call "' . $className . '" - use setClass()'); 0318 } 0319 try { 0320 $this->getLoader()->load($className); 0321 } catch (Exception $e) { 0322 // require_once 'Zend/Amf/Server/Exception.php'; 0323 throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage(), 0, $e); 0324 } 0325 // Add the new loaded class to the server. 0326 // require_once 'Zend/Amf/Server/Exception.php'; 0327 $this->setClass($className, $source); 0328 } 0329 0330 if (!isset($this->_table[$qualifiedName])) { 0331 // Source is null or doesn't contain specified method 0332 // require_once 'Zend/Amf/Server/Exception.php'; 0333 throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist'); 0334 } 0335 } 0336 0337 $info = $this->_table[$qualifiedName]; 0338 $argv = $info->getInvokeArguments(); 0339 0340 if (0 < count($argv)) { 0341 $params = array_merge($params, $argv); 0342 } 0343 0344 $params = $this->_castParameters($info, $params); 0345 0346 if ($info instanceof Zend_Server_Reflection_Function) { 0347 $func = $info->getName(); 0348 $this->_checkAcl(null, $func); 0349 $return = call_user_func_array($func, $params); 0350 } elseif ($info instanceof Zend_Server_Reflection_Method) { 0351 // Get class 0352 $class = $info->getDeclaringClass()->getName(); 0353 if ('static' == $info->isStatic()) { 0354 // for some reason, invokeArgs() does not work the same as 0355 // invoke(), and expects the first argument to be an object. 0356 // So, using a callback if the method is static. 0357 $this->_checkAcl($class, $info->getName()); 0358 $return = call_user_func_array(array($class, $info->getName()), $params); 0359 } else { 0360 // Object methods 0361 try { 0362 $object = $info->getDeclaringClass()->newInstance(); 0363 } catch (Exception $e) { 0364 // require_once 'Zend/Amf/Server/Exception.php'; 0365 throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621, $e); 0366 } 0367 $this->_checkAcl($object, $info->getName()); 0368 $return = $info->invokeArgs($object, $params); 0369 } 0370 } else { 0371 // require_once 'Zend/Amf/Server/Exception.php'; 0372 throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info)); 0373 } 0374 0375 return $return; 0376 } 0377 0378 /** 0379 * Handles each of the 11 different command message types. 0380 * 0381 * A command message is a flex.messaging.messages.CommandMessage 0382 * 0383 * @see Zend_Amf_Value_Messaging_CommandMessage 0384 * @param Zend_Amf_Value_Messaging_CommandMessage $message 0385 * @return Zend_Amf_Value_Messaging_AcknowledgeMessage 0386 */ 0387 protected function _loadCommandMessage(Zend_Amf_Value_Messaging_CommandMessage $message) 0388 { 0389 // require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php'; 0390 switch($message->operation) { 0391 case Zend_Amf_Value_Messaging_CommandMessage::DISCONNECT_OPERATION : 0392 case Zend_Amf_Value_Messaging_CommandMessage::CLIENT_PING_OPERATION : 0393 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 0394 break; 0395 case Zend_Amf_Value_Messaging_CommandMessage::LOGIN_OPERATION : 0396 $data = explode(':', base64_decode($message->body)); 0397 $userid = $data[0]; 0398 $password = isset($data[1])?$data[1]:""; 0399 if(empty($userid)) { 0400 // require_once 'Zend/Amf/Server/Exception.php'; 0401 throw new Zend_Amf_Server_Exception('Login failed: username not supplied'); 0402 } 0403 if(!$this->_handleAuth($userid, $password)) { 0404 // require_once 'Zend/Amf/Server/Exception.php'; 0405 throw new Zend_Amf_Server_Exception('Authentication failed'); 0406 } 0407 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 0408 break; 0409 case Zend_Amf_Value_Messaging_CommandMessage::LOGOUT_OPERATION : 0410 if($this->_auth) { 0411 Zend_Auth::getInstance()->clearIdentity(); 0412 } 0413 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 0414 break; 0415 default : 0416 // require_once 'Zend/Amf/Server/Exception.php'; 0417 throw new Zend_Amf_Server_Exception('CommandMessage::' . $message->operation . ' not implemented'); 0418 break; 0419 } 0420 return $return; 0421 } 0422 0423 /** 0424 * Create appropriate error message 0425 * 0426 * @param int $objectEncoding Current AMF encoding 0427 * @param string $message Message that was being processed when error happened 0428 * @param string $description Error description 0429 * @param mixed $detail Detailed data about the error 0430 * @param int $code Error code 0431 * @param int $line Error line 0432 * @return Zend_Amf_Value_Messaging_ErrorMessage|array 0433 */ 0434 protected function _errorMessage($objectEncoding, $message, $description, $detail, $code, $line) 0435 { 0436 $return = null; 0437 switch ($objectEncoding) { 0438 case Zend_Amf_Constants::AMF0_OBJECT_ENCODING : 0439 return array ( 0440 'description' => ($this->isProduction ()) ? '' : $description, 0441 'detail' => ($this->isProduction ()) ? '' : $detail, 0442 'line' => ($this->isProduction ()) ? 0 : $line, 0443 'code' => $code 0444 ); 0445 case Zend_Amf_Constants::AMF3_OBJECT_ENCODING : 0446 // require_once 'Zend/Amf/Value/Messaging/ErrorMessage.php'; 0447 $return = new Zend_Amf_Value_Messaging_ErrorMessage ( $message ); 0448 $return->faultString = $this->isProduction () ? '' : $description; 0449 $return->faultCode = $code; 0450 $return->faultDetail = $this->isProduction () ? '' : $detail; 0451 break; 0452 } 0453 return $return; 0454 } 0455 0456 /** 0457 * Handle AMF authentication 0458 * 0459 * @param string $userid 0460 * @param string $password 0461 * @return boolean 0462 */ 0463 protected function _handleAuth( $userid, $password) 0464 { 0465 if (!$this->_auth) { 0466 return true; 0467 } 0468 $this->_auth->setCredentials($userid, $password); 0469 $auth = Zend_Auth::getInstance(); 0470 $result = $auth->authenticate($this->_auth); 0471 if ($result->isValid()) { 0472 if (!$this->isSession()) { 0473 $this->setSession(); 0474 } 0475 return true; 0476 } else { 0477 // authentication failed, good bye 0478 // require_once 'Zend/Amf/Server/Exception.php'; 0479 throw new Zend_Amf_Server_Exception( 0480 "Authentication failed: " . join("\n", 0481 $result->getMessages()), $result->getCode()); 0482 } 0483 0484 } 0485 0486 /** 0487 * Takes the deserialized AMF request and performs any operations. 0488 * 0489 * @todo should implement and SPL observer pattern for custom AMF headers 0490 * @todo DescribeService support 0491 * @param Zend_Amf_Request $request 0492 * @return Zend_Amf_Response 0493 * @throws Zend_Amf_server_Exception|Exception 0494 */ 0495 protected function _handle(Zend_Amf_Request $request) 0496 { 0497 // Get the object encoding of the request. 0498 $objectEncoding = $request->getObjectEncoding(); 0499 0500 // create a response object to place the output from the services. 0501 $response = $this->getResponse(); 0502 0503 // set response encoding 0504 $response->setObjectEncoding($objectEncoding); 0505 0506 // Authenticate, if we have credential headers 0507 $error = false; 0508 $headers = $request->getAmfHeaders(); 0509 if (isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]) 0510 && isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid) 0511 && isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password) 0512 ) { 0513 try { 0514 if ($this->_handleAuth( 0515 $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid, 0516 $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password 0517 )) { 0518 // use RequestPersistentHeader to clear credentials 0519 $response->addAmfHeader( 0520 new Zend_Amf_Value_MessageHeader( 0521 Zend_Amf_Constants::PERSISTENT_HEADER, 0522 false, 0523 new Zend_Amf_Value_MessageHeader( 0524 Zend_Amf_Constants::CREDENTIALS_HEADER, 0525 false, null 0526 ) 0527 ) 0528 ); 0529 } 0530 } catch (Exception $e) { 0531 // Error during authentication; report it 0532 $error = $this->_errorMessage( 0533 $objectEncoding, 0534 '', 0535 $e->getMessage(), 0536 $e->getTraceAsString(), 0537 $e->getCode(), 0538 $e->getLine() 0539 ); 0540 $responseType = Zend_AMF_Constants::STATUS_METHOD; 0541 } 0542 } 0543 0544 // Iterate through each of the service calls in the AMF request 0545 foreach($request->getAmfBodies() as $body) 0546 { 0547 if ($error) { 0548 // Error during authentication; just report it and be done 0549 $responseURI = $body->getResponseURI() . $responseType; 0550 $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $error); 0551 $response->addAmfBody($newBody); 0552 continue; 0553 } 0554 try { 0555 switch ($objectEncoding) { 0556 case Zend_Amf_Constants::AMF0_OBJECT_ENCODING: 0557 // AMF0 Object Encoding 0558 $targetURI = $body->getTargetURI(); 0559 $message = ''; 0560 0561 // Split the target string into its values. 0562 $source = substr($targetURI, 0, strrpos($targetURI, '.')); 0563 0564 if ($source) { 0565 // Break off method name from namespace into source 0566 $method = substr(strrchr($targetURI, '.'), 1); 0567 $return = $this->_dispatch($method, $body->getData(), $source); 0568 } else { 0569 // Just have a method name. 0570 $return = $this->_dispatch($targetURI, $body->getData()); 0571 } 0572 break; 0573 case Zend_Amf_Constants::AMF3_OBJECT_ENCODING: 0574 default: 0575 // AMF3 read message type 0576 $message = $body->getData(); 0577 if ($message instanceof Zend_Amf_Value_Messaging_CommandMessage) { 0578 // async call with command message 0579 $return = $this->_loadCommandMessage($message); 0580 } elseif ($message instanceof Zend_Amf_Value_Messaging_RemotingMessage) { 0581 // require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php'; 0582 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 0583 $return->body = $this->_dispatch($message->operation, $message->body, $message->source); 0584 } else { 0585 // Amf3 message sent with netConnection 0586 $targetURI = $body->getTargetURI(); 0587 0588 // Split the target string into its values. 0589 $source = substr($targetURI, 0, strrpos($targetURI, '.')); 0590 0591 if ($source) { 0592 // Break off method name from namespace into source 0593 $method = substr(strrchr($targetURI, '.'), 1); 0594 $return = $this->_dispatch($method, $body->getData(), $source); 0595 } else { 0596 // Just have a method name. 0597 $return = $this->_dispatch($targetURI, $body->getData()); 0598 } 0599 } 0600 break; 0601 } 0602 $responseType = Zend_AMF_Constants::RESULT_METHOD; 0603 } catch (Exception $e) { 0604 $return = $this->_errorMessage($objectEncoding, $message, 0605 $e->getMessage(), $e->getTraceAsString(),$e->getCode(), $e->getLine()); 0606 $responseType = Zend_AMF_Constants::STATUS_METHOD; 0607 } 0608 0609 $responseURI = $body->getResponseURI() . $responseType; 0610 $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return); 0611 $response->addAmfBody($newBody); 0612 } 0613 // Add a session header to the body if session is requested. 0614 if($this->isSession()) { 0615 $currentID = session_id(); 0616 $joint = "?"; 0617 if(isset($_SERVER['QUERY_STRING'])) { 0618 if(!strpos($_SERVER['QUERY_STRING'], $currentID) !== FALSE) { 0619 if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) { 0620 $joint = "&"; 0621 } 0622 } 0623 } 0624 0625 // create a new AMF message header with the session id as a variable. 0626 $sessionValue = $joint . $this->_sessionName . "=" . $currentID; 0627 $sessionHeader = new Zend_Amf_Value_MessageHeader(Zend_Amf_Constants::URL_APPEND_HEADER, false, $sessionValue); 0628 $response->addAmfHeader($sessionHeader); 0629 } 0630 0631 // serialize the response and return serialized body. 0632 $response->finalize(); 0633 } 0634 0635 /** 0636 * Handle an AMF call from the gateway. 0637 * 0638 * @param null|Zend_Amf_Request $request Optional 0639 * @return Zend_Amf_Response 0640 */ 0641 public function handle($request = null) 0642 { 0643 // Check if request was passed otherwise get it from the server 0644 if ($request === null || !$request instanceof Zend_Amf_Request) { 0645 $request = $this->getRequest(); 0646 } else { 0647 $this->setRequest($request); 0648 } 0649 if ($this->isSession()) { 0650 // Check if a session is being sent from the amf call 0651 if (isset($_COOKIE[$this->_sessionName])) { 0652 session_id($_COOKIE[$this->_sessionName]); 0653 } 0654 } 0655 0656 // Check for errors that may have happend in deserialization of Request. 0657 try { 0658 // Take converted PHP objects and handle service call. 0659 // Serialize to Zend_Amf_response for output stream 0660 $this->_handle($request); 0661 $response = $this->getResponse(); 0662 } catch (Exception $e) { 0663 // Handle any errors in the serialization and service calls. 0664 // require_once 'Zend/Amf/Server/Exception.php'; 0665 throw new Zend_Amf_Server_Exception('Handle error: ' . $e->getMessage() . ' ' . $e->getLine(), 0, $e); 0666 } 0667 0668 // Return the Amf serialized output string 0669 return $response; 0670 } 0671 0672 /** 0673 * Set request object 0674 * 0675 * @param string|Zend_Amf_Request $request 0676 * @return Zend_Amf_Server 0677 */ 0678 public function setRequest($request) 0679 { 0680 if (is_string($request) && class_exists($request)) { 0681 $request = new $request(); 0682 if (!$request instanceof Zend_Amf_Request) { 0683 // require_once 'Zend/Amf/Server/Exception.php'; 0684 throw new Zend_Amf_Server_Exception('Invalid request class'); 0685 } 0686 } elseif (!$request instanceof Zend_Amf_Request) { 0687 // require_once 'Zend/Amf/Server/Exception.php'; 0688 throw new Zend_Amf_Server_Exception('Invalid request object'); 0689 } 0690 $this->_request = $request; 0691 return $this; 0692 } 0693 0694 /** 0695 * Return currently registered request object 0696 * 0697 * @return null|Zend_Amf_Request 0698 */ 0699 public function getRequest() 0700 { 0701 if (null === $this->_request) { 0702 // require_once 'Zend/Amf/Request/Http.php'; 0703 $this->setRequest(new Zend_Amf_Request_Http()); 0704 } 0705 0706 return $this->_request; 0707 } 0708 0709 /** 0710 * Public access method to private Zend_Amf_Server_Response reference 0711 * 0712 * @param string|Zend_Amf_Server_Response $response 0713 * @return Zend_Amf_Server 0714 */ 0715 public function setResponse($response) 0716 { 0717 if (is_string($response) && class_exists($response)) { 0718 $response = new $response(); 0719 if (!$response instanceof Zend_Amf_Response) { 0720 // require_once 'Zend/Amf/Server/Exception.php'; 0721 throw new Zend_Amf_Server_Exception('Invalid response class'); 0722 } 0723 } elseif (!$response instanceof Zend_Amf_Response) { 0724 // require_once 'Zend/Amf/Server/Exception.php'; 0725 throw new Zend_Amf_Server_Exception('Invalid response object'); 0726 } 0727 $this->_response = $response; 0728 return $this; 0729 } 0730 0731 /** 0732 * get a reference to the Zend_Amf_response instance 0733 * 0734 * @return Zend_Amf_Server_Response 0735 */ 0736 public function getResponse() 0737 { 0738 if (null === ($response = $this->_response)) { 0739 // require_once 'Zend/Amf/Response/Http.php'; 0740 $this->setResponse(new Zend_Amf_Response_Http()); 0741 } 0742 return $this->_response; 0743 } 0744 0745 /** 0746 * Attach a class or object to the server 0747 * 0748 * Class may be either a class name or an instantiated object. Reflection 0749 * is done on the class or object to determine the available public 0750 * methods, and each is attached to the server as and available method. If 0751 * a $namespace has been provided, that namespace is used to prefix 0752 * AMF service call. 0753 * 0754 * @param string|object $class 0755 * @param string $namespace Optional 0756 * @param mixed $arg Optional arguments to pass to a method 0757 * @return Zend_Amf_Server 0758 * @throws Zend_Amf_Server_Exception on invalid input 0759 */ 0760 public function setClass($class, $namespace = '', $argv = null) 0761 { 0762 if (is_string($class) && !class_exists($class)){ 0763 // require_once 'Zend/Amf/Server/Exception.php'; 0764 throw new Zend_Amf_Server_Exception('Invalid method or class'); 0765 } elseif (!is_string($class) && !is_object($class)) { 0766 // require_once 'Zend/Amf/Server/Exception.php'; 0767 throw new Zend_Amf_Server_Exception('Invalid method or class; must be a classname or object'); 0768 } 0769 0770 $args = null; 0771 if (2 < func_num_args()) { 0772 $args = array_slice(func_get_args(), 2); 0773 } 0774 0775 // Use the class name as the name space by default. 0776 0777 if ($namespace == '') { 0778 $namespace = is_object($class) ? get_class($class) : $class; 0779 } 0780 0781 $this->_classAllowed[is_object($class) ? get_class($class) : $class] = true; 0782 0783 $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $args, $namespace); 0784 $this->_buildDispatchTable(); 0785 0786 return $this; 0787 } 0788 0789 /** 0790 * Attach a function to the server 0791 * 0792 * Additional arguments to pass to the function at dispatch may be passed; 0793 * any arguments following the namespace will be aggregated and passed at 0794 * dispatch time. 0795 * 0796 * @param string|array $function Valid callback 0797 * @param string $namespace Optional namespace prefix 0798 * @return Zend_Amf_Server 0799 * @throws Zend_Amf_Server_Exception 0800 */ 0801 public function addFunction($function, $namespace = '') 0802 { 0803 if (!is_string($function) && !is_array($function)) { 0804 // require_once 'Zend/Amf/Server/Exception.php'; 0805 throw new Zend_Amf_Server_Exception('Unable to attach function'); 0806 } 0807 0808 $argv = null; 0809 if (2 < func_num_args()) { 0810 $argv = array_slice(func_get_args(), 2); 0811 } 0812 0813 $function = (array) $function; 0814 foreach ($function as $func) { 0815 if (!is_string($func) || !function_exists($func)) { 0816 // require_once 'Zend/Amf/Server/Exception.php'; 0817 throw new Zend_Amf_Server_Exception('Unable to attach function'); 0818 } 0819 $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace); 0820 } 0821 0822 $this->_buildDispatchTable(); 0823 return $this; 0824 } 0825 0826 0827 /** 0828 * Creates an array of directories in which services can reside. 0829 * TODO: add support for prefixes? 0830 * 0831 * @param string $dir 0832 */ 0833 public function addDirectory($dir) 0834 { 0835 $this->getLoader()->addPrefixPath("", $dir); 0836 } 0837 0838 /** 0839 * Returns an array of directories that can hold services. 0840 * 0841 * @return array 0842 */ 0843 public function getDirectory() 0844 { 0845 return $this->getLoader()->getPaths(""); 0846 } 0847 0848 /** 0849 * (Re)Build the dispatch table 0850 * 0851 * The dispatch table consists of a an array of method name => 0852 * Zend_Server_Reflection_Function_Abstract pairs 0853 * 0854 * @return void 0855 */ 0856 protected function _buildDispatchTable() 0857 { 0858 $table = array(); 0859 foreach ($this->_methods as $key => $dispatchable) { 0860 if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) { 0861 $ns = $dispatchable->getNamespace(); 0862 $name = $dispatchable->getName(); 0863 $name = empty($ns) ? $name : $ns . '.' . $name; 0864 0865 if (isset($table[$name])) { 0866 // require_once 'Zend/Amf/Server/Exception.php'; 0867 throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); 0868 } 0869 $table[$name] = $dispatchable; 0870 continue; 0871 } 0872 0873 if ($dispatchable instanceof Zend_Server_Reflection_Class) { 0874 foreach ($dispatchable->getMethods() as $method) { 0875 $ns = $method->getNamespace(); 0876 $name = $method->getName(); 0877 $name = empty($ns) ? $name : $ns . '.' . $name; 0878 0879 if (isset($table[$name])) { 0880 // require_once 'Zend/Amf/Server/Exception.php'; 0881 throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); 0882 } 0883 $table[$name] = $method; 0884 continue; 0885 } 0886 } 0887 } 0888 $this->_table = $table; 0889 } 0890 0891 0892 0893 /** 0894 * Raise a server fault 0895 * 0896 * Unimplemented 0897 * 0898 * @param string|Exception $fault 0899 * @return void 0900 */ 0901 public function fault($fault = null, $code = 404) 0902 { 0903 } 0904 0905 /** 0906 * Returns a list of registered methods 0907 * 0908 * Returns an array of dispatchables (Zend_Server_Reflection_Function, 0909 * _Method, and _Class items). 0910 * 0911 * @return array 0912 */ 0913 public function getFunctions() 0914 { 0915 return $this->_table; 0916 } 0917 0918 /** 0919 * Set server persistence 0920 * 0921 * Unimplemented 0922 * 0923 * @param mixed $mode 0924 * @return void 0925 */ 0926 public function setPersistence($mode) 0927 { 0928 } 0929 0930 /** 0931 * Load server definition 0932 * 0933 * Unimplemented 0934 * 0935 * @param array $definition 0936 * @return void 0937 */ 0938 public function loadFunctions($definition) 0939 { 0940 } 0941 0942 /** 0943 * Map ActionScript classes to PHP classes 0944 * 0945 * @param string $asClass 0946 * @param string $phpClass 0947 * @return Zend_Amf_Server 0948 */ 0949 public function setClassMap($asClass, $phpClass) 0950 { 0951 // require_once 'Zend/Amf/Parse/TypeLoader.php'; 0952 Zend_Amf_Parse_TypeLoader::setMapping($asClass, $phpClass); 0953 return $this; 0954 } 0955 0956 /** 0957 * List all available methods 0958 * 0959 * Returns an array of method names. 0960 * 0961 * @return array 0962 */ 0963 public function listMethods() 0964 { 0965 return array_keys($this->_table); 0966 } 0967 0968 /** 0969 * Cast parameters 0970 * 0971 * Takes the provided parameters from the request, and attempts to cast them 0972 * to objects, if the prototype defines any as explicit object types 0973 * 0974 * @param Reflection $reflectionMethod 0975 * @param array $params 0976 * @return array 0977 */ 0978 protected function _castParameters($reflectionMethod, array $params) 0979 { 0980 $prototypes = $reflectionMethod->getPrototypes(); 0981 $nonObjectTypes = array( 0982 'null', 0983 'mixed', 0984 'void', 0985 'unknown', 0986 'bool', 0987 'boolean', 0988 'number', 0989 'int', 0990 'integer', 0991 'double', 0992 'float', 0993 'string', 0994 'array', 0995 'object', 0996 'stdclass', 0997 ); 0998 $types = array(); 0999 foreach ($prototypes as $prototype) { 1000 foreach ($prototype->getParameters() as $parameter) { 1001 $type = $parameter->getType(); 1002 if (in_array(strtolower($type), $nonObjectTypes)) { 1003 continue; 1004 } 1005 $position = $parameter->getPosition(); 1006 $types[$position] = $type; 1007 } 1008 } 1009 1010 if (empty($types)) { 1011 return $params; 1012 } 1013 1014 foreach ($params as $position => $value) { 1015 if (!isset($types[$position])) { 1016 // No specific type to cast to? done 1017 continue; 1018 } 1019 1020 $type = $types[$position]; 1021 1022 if (!class_exists($type)) { 1023 // Not a class, apparently. done 1024 continue; 1025 } 1026 1027 if ($value instanceof $type) { 1028 // Already of the right type? done 1029 continue; 1030 } 1031 1032 if (!is_array($value) && !is_object($value)) { 1033 // Can't cast scalars to objects easily; done 1034 continue; 1035 } 1036 1037 // Create instance, and loop through value to set 1038 $object = new $type; 1039 foreach ($value as $property => $defined) { 1040 $object->{$property} = $defined; 1041 } 1042 1043 $params[$position] = $object; 1044 } 1045 1046 return $params; 1047 } 1048 }