|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00023 require_once 'Zend/Server/Interface.php'; 00024 00026 require_once 'Zend/Server/Reflection.php'; 00027 00029 require_once 'Zend/Amf/Constants.php'; 00030 00032 require_once 'Zend/Amf/Value/MessageBody.php'; 00033 00035 require_once 'Zend/Amf/Value/MessageHeader.php'; 00036 00038 require_once 'Zend/Amf/Value/Messaging/CommandMessage.php'; 00039 00041 require_once 'Zend/Loader/PluginLoader.php'; 00042 00044 require_once 'Zend/Amf/Parse/TypeLoader.php'; 00045 00047 require_once 'Zend/Auth.php'; 00058 class Zend_Amf_Server implements Zend_Server_Interface 00059 { 00064 protected $_methods = array(); 00065 00073 protected $_classAllowed = array(); 00074 00079 protected $_loader; 00080 00084 protected $_production = true; 00085 00090 protected $_request = null; 00091 00096 protected $_response; 00097 00102 protected $_table = array(); 00103 00108 protected $_session = false; 00109 00114 protected $_sesionNamespace = 'zend_amf'; 00115 00120 protected $_sessionName = 'PHPSESSID'; 00121 00127 protected $_auth; 00133 protected $_acl; 00137 public function __construct() 00138 { 00139 Zend_Amf_Parse_TypeLoader::setResourceLoader(new Zend_Loader_PluginLoader(array("Zend_Amf_Parse_Resource" => "Zend/Amf/Parse/Resource"))); 00140 } 00141 00148 public function setAuth(Zend_Amf_Auth_Abstract $auth) 00149 { 00150 $this->_auth = $auth; 00151 return $this; 00152 } 00158 public function getAuth() 00159 { 00160 return $this->_auth; 00161 } 00162 00169 public function setAcl(Zend_Acl $acl) 00170 { 00171 $this->_acl = $acl; 00172 return $this; 00173 } 00179 public function getAcl() 00180 { 00181 return $this->_acl; 00182 } 00183 00190 public function setProduction($flag) 00191 { 00192 $this->_production = (bool) $flag; 00193 return $this; 00194 } 00195 00201 public function isProduction() 00202 { 00203 return $this->_production; 00204 } 00205 00210 public function setSession($namespace = 'Zend_Amf') 00211 { 00212 require_once 'Zend/Session.php'; 00213 $this->_session = true; 00214 $this->_sesionNamespace = new Zend_Session_Namespace($namespace); 00215 return $this; 00216 } 00217 00222 public function isSession() 00223 { 00224 return $this->_session; 00225 } 00226 00234 protected function _checkAcl($object, $function) 00235 { 00236 if(!$this->_acl) { 00237 return true; 00238 } 00239 if($object) { 00240 $class = is_object($object)?get_class($object):$object; 00241 if(!$this->_acl->has($class)) { 00242 require_once 'Zend/Acl/Resource.php'; 00243 $this->_acl->add(new Zend_Acl_Resource($class)); 00244 } 00245 $call = array($object, "initAcl"); 00246 if(is_callable($call) && !call_user_func($call, $this->_acl)) { 00247 // if initAcl returns false, no ACL check 00248 return true; 00249 } 00250 } else { 00251 $class = null; 00252 } 00253 00254 $auth = Zend_Auth::getInstance(); 00255 if($auth->hasIdentity()) { 00256 $role = $auth->getIdentity()->role; 00257 } else { 00258 if($this->_acl->hasRole(Zend_Amf_Constants::GUEST_ROLE)) { 00259 $role = Zend_Amf_Constants::GUEST_ROLE; 00260 } else { 00261 require_once 'Zend/Amf/Server/Exception.php'; 00262 throw new Zend_Amf_Server_Exception("Unauthenticated access not allowed"); 00263 } 00264 } 00265 if($this->_acl->isAllowed($role, $class, $function)) { 00266 return true; 00267 } else { 00268 require_once 'Zend/Amf/Server/Exception.php'; 00269 throw new Zend_Amf_Server_Exception("Access not allowed"); 00270 } 00271 } 00272 00278 protected function getLoader() 00279 { 00280 if(empty($this->_loader)) { 00281 require_once 'Zend/Loader/PluginLoader.php'; 00282 $this->_loader = new Zend_Loader_PluginLoader(); 00283 } 00284 return $this->_loader; 00285 } 00286 00296 protected function _dispatch($method, $params = null, $source = null) 00297 { 00298 if($source) { 00299 if(($mapped = Zend_Amf_Parse_TypeLoader::getMappedClassName($source)) !== false) { 00300 $source = $mapped; 00301 } 00302 } 00303 $qualifiedName = empty($source) ? $method : $source.".".$method; 00304 00305 if (!isset($this->_table[$qualifiedName])) { 00306 // if source is null a method that was not defined was called. 00307 if ($source) { 00308 $className = str_replace(".", "_", $source); 00309 if(class_exists($className, false) && !isset($this->_classAllowed[$className])) { 00310 require_once 'Zend/Amf/Server/Exception.php'; 00311 throw new Zend_Amf_Server_Exception('Can not call "' . $className . '" - use setClass()'); 00312 } 00313 try { 00314 $this->getLoader()->load($className); 00315 } catch (Exception $e) { 00316 require_once 'Zend/Amf/Server/Exception.php'; 00317 throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage(), 0, $e); 00318 } 00319 // Add the new loaded class to the server. 00320 $this->setClass($className, $source); 00321 } else { 00322 require_once 'Zend/Amf/Server/Exception.php'; 00323 throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist'); 00324 } 00325 } 00326 00327 $info = $this->_table[$qualifiedName]; 00328 $argv = $info->getInvokeArguments(); 00329 00330 if (0 < count($argv)) { 00331 $params = array_merge($params, $argv); 00332 } 00333 00334 if ($info instanceof Zend_Server_Reflection_Function) { 00335 $func = $info->getName(); 00336 $this->_checkAcl(null, $func); 00337 $return = call_user_func_array($func, $params); 00338 } elseif ($info instanceof Zend_Server_Reflection_Method) { 00339 // Get class 00340 $class = $info->getDeclaringClass()->getName(); 00341 if ('static' == $info->isStatic()) { 00342 // for some reason, invokeArgs() does not work the same as 00343 // invoke(), and expects the first argument to be an object. 00344 // So, using a callback if the method is static. 00345 $this->_checkAcl($class, $info->getName()); 00346 $return = call_user_func_array(array($class, $info->getName()), $params); 00347 } else { 00348 // Object methods 00349 try { 00350 $object = $info->getDeclaringClass()->newInstance(); 00351 } catch (Exception $e) { 00352 require_once 'Zend/Amf/Server/Exception.php'; 00353 throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621, $e); 00354 } 00355 $this->_checkAcl($object, $info->getName()); 00356 $return = $info->invokeArgs($object, $params); 00357 } 00358 } else { 00359 require_once 'Zend/Amf/Server/Exception.php'; 00360 throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info)); 00361 } 00362 00363 return $return; 00364 } 00365 00375 protected function _loadCommandMessage(Zend_Amf_Value_Messaging_CommandMessage $message) 00376 { 00377 require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php'; 00378 switch($message->operation) { 00379 case Zend_Amf_Value_Messaging_CommandMessage::DISCONNECT_OPERATION : 00380 case Zend_Amf_Value_Messaging_CommandMessage::CLIENT_PING_OPERATION : 00381 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 00382 break; 00383 case Zend_Amf_Value_Messaging_CommandMessage::LOGIN_OPERATION : 00384 $data = explode(':', base64_decode($message->body)); 00385 $userid = $data[0]; 00386 $password = isset($data[1])?$data[1]:""; 00387 if(empty($userid)) { 00388 require_once 'Zend/Amf/Server/Exception.php'; 00389 throw new Zend_Amf_Server_Exception('Login failed: username not supplied'); 00390 } 00391 if(!$this->_handleAuth($userid, $password)) { 00392 require_once 'Zend/Amf/Server/Exception.php'; 00393 throw new Zend_Amf_Server_Exception('Authentication failed'); 00394 } 00395 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 00396 break; 00397 case Zend_Amf_Value_Messaging_CommandMessage::LOGOUT_OPERATION : 00398 if($this->_auth) { 00399 Zend_Auth::getInstance()->clearIdentity(); 00400 } 00401 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 00402 break; 00403 default : 00404 require_once 'Zend/Amf/Server/Exception.php'; 00405 throw new Zend_Amf_Server_Exception('CommandMessage::' . $message->operation . ' not implemented'); 00406 break; 00407 } 00408 return $return; 00409 } 00410 00422 protected function _errorMessage($objectEncoding, $message, $description, $detail, $code, $line) 00423 { 00424 $return = null; 00425 switch ($objectEncoding) { 00426 case Zend_Amf_Constants::AMF0_OBJECT_ENCODING : 00427 return array ( 00428 'description' => ($this->isProduction ()) ? '' : $description, 00429 'detail' => ($this->isProduction ()) ? '' : $detail, 00430 'line' => ($this->isProduction ()) ? 0 : $line, 00431 'code' => $code 00432 ); 00433 case Zend_Amf_Constants::AMF3_OBJECT_ENCODING : 00434 require_once 'Zend/Amf/Value/Messaging/ErrorMessage.php'; 00435 $return = new Zend_Amf_Value_Messaging_ErrorMessage ( $message ); 00436 $return->faultString = $this->isProduction () ? '' : $description; 00437 $return->faultCode = $code; 00438 $return->faultDetail = $this->isProduction () ? '' : $detail; 00439 break; 00440 } 00441 return $return; 00442 } 00443 00451 protected function _handleAuth( $userid, $password) 00452 { 00453 if (!$this->_auth) { 00454 return true; 00455 } 00456 $this->_auth->setCredentials($userid, $password); 00457 $auth = Zend_Auth::getInstance(); 00458 $result = $auth->authenticate($this->_auth); 00459 if ($result->isValid()) { 00460 if (!$this->isSession()) { 00461 $this->setSession(); 00462 } 00463 return true; 00464 } else { 00465 // authentication failed, good bye 00466 require_once 'Zend/Amf/Server/Exception.php'; 00467 throw new Zend_Amf_Server_Exception( 00468 "Authentication failed: " . join("\n", 00469 $result->getMessages()), $result->getCode()); 00470 } 00471 00472 } 00473 00483 protected function _handle(Zend_Amf_Request $request) 00484 { 00485 // Get the object encoding of the request. 00486 $objectEncoding = $request->getObjectEncoding(); 00487 00488 // create a response object to place the output from the services. 00489 $response = $this->getResponse(); 00490 00491 // set response encoding 00492 $response->setObjectEncoding($objectEncoding); 00493 00494 $responseBody = $request->getAmfBodies(); 00495 00496 $handleAuth = false; 00497 if ($this->_auth) { 00498 $headers = $request->getAmfHeaders(); 00499 if (isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]) && 00500 isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid)) { 00501 $handleAuth = true; 00502 } 00503 } 00504 00505 // Iterate through each of the service calls in the AMF request 00506 foreach($responseBody as $body) 00507 { 00508 try { 00509 if ($handleAuth) { 00510 if ($this->_handleAuth( 00511 $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid, 00512 $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password)) { 00513 // use RequestPersistentHeader to clear credentials 00514 $response->addAmfHeader( 00515 new Zend_Amf_Value_MessageHeader( 00516 Zend_Amf_Constants::PERSISTENT_HEADER, 00517 false, 00518 new Zend_Amf_Value_MessageHeader( 00519 Zend_Amf_Constants::CREDENTIALS_HEADER, 00520 false, null))); 00521 $handleAuth = false; 00522 } 00523 } 00524 00525 if ($objectEncoding == Zend_Amf_Constants::AMF0_OBJECT_ENCODING) { 00526 // AMF0 Object Encoding 00527 $targetURI = $body->getTargetURI(); 00528 $message = ''; 00529 00530 // Split the target string into its values. 00531 $source = substr($targetURI, 0, strrpos($targetURI, '.')); 00532 00533 if ($source) { 00534 // Break off method name from namespace into source 00535 $method = substr(strrchr($targetURI, '.'), 1); 00536 $return = $this->_dispatch($method, $body->getData(), $source); 00537 } else { 00538 // Just have a method name. 00539 $return = $this->_dispatch($targetURI, $body->getData()); 00540 } 00541 } else { 00542 // AMF3 read message type 00543 $message = $body->getData(); 00544 if ($message instanceof Zend_Amf_Value_Messaging_CommandMessage) { 00545 // async call with command message 00546 $return = $this->_loadCommandMessage($message); 00547 } elseif ($message instanceof Zend_Amf_Value_Messaging_RemotingMessage) { 00548 require_once 'Zend/Amf/Value/Messaging/AcknowledgeMessage.php'; 00549 $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); 00550 $return->body = $this->_dispatch($message->operation, $message->body, $message->source); 00551 } else { 00552 // Amf3 message sent with netConnection 00553 $targetURI = $body->getTargetURI(); 00554 00555 // Split the target string into its values. 00556 $source = substr($targetURI, 0, strrpos($targetURI, '.')); 00557 00558 if ($source) { 00559 // Break off method name from namespace into source 00560 $method = substr(strrchr($targetURI, '.'), 1); 00561 $return = $this->_dispatch($method, $body->getData(), $source); 00562 } else { 00563 // Just have a method name. 00564 $return = $this->_dispatch($targetURI, $body->getData()); 00565 } 00566 } 00567 } 00568 $responseType = Zend_AMF_Constants::RESULT_METHOD; 00569 } catch (Exception $e) { 00570 $return = $this->_errorMessage($objectEncoding, $message, 00571 $e->getMessage(), $e->getTraceAsString(),$e->getCode(), $e->getLine()); 00572 $responseType = Zend_AMF_Constants::STATUS_METHOD; 00573 } 00574 00575 $responseURI = $body->getResponseURI() . $responseType; 00576 $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return); 00577 $response->addAmfBody($newBody); 00578 } 00579 // Add a session header to the body if session is requested. 00580 if($this->isSession()) { 00581 $currentID = session_id(); 00582 $joint = "?"; 00583 if(isset($_SERVER['QUERY_STRING'])) { 00584 if(!strpos($_SERVER['QUERY_STRING'], $currentID) !== FALSE) { 00585 if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) { 00586 $joint = "&"; 00587 } 00588 } 00589 } 00590 00591 // create a new AMF message header with the session id as a variable. 00592 $sessionValue = $joint . $this->_sessionName . "=" . $currentID; 00593 $sessionHeader = new Zend_Amf_Value_MessageHeader(Zend_Amf_Constants::URL_APPEND_HEADER, false, $sessionValue); 00594 $response->addAmfHeader($sessionHeader); 00595 } 00596 00597 // serialize the response and return serialized body. 00598 $response->finalize(); 00599 } 00600 00607 public function handle($request = null) 00608 { 00609 // Check if request was passed otherwise get it from the server 00610 if (is_null($request) || !$request instanceof Zend_Amf_Request) { 00611 $request = $this->getRequest(); 00612 } else { 00613 $this->setRequest($request); 00614 } 00615 if ($this->isSession()) { 00616 // Check if a session is being sent from the amf call 00617 if (isset($_COOKIE[$this->_sessionName])) { 00618 session_id($_COOKIE[$this->_sessionName]); 00619 } 00620 } 00621 00622 // Check for errors that may have happend in deserialization of Request. 00623 try { 00624 // Take converted PHP objects and handle service call. 00625 // Serialize to Zend_Amf_response for output stream 00626 $this->_handle($request); 00627 $response = $this->getResponse(); 00628 } catch (Exception $e) { 00629 // Handle any errors in the serialization and service calls. 00630 require_once 'Zend/Amf/Server/Exception.php'; 00631 throw new Zend_Amf_Server_Exception('Handle error: ' . $e->getMessage() . ' ' . $e->getLine(), 0, $e); 00632 } 00633 00634 // Return the Amf serialized output string 00635 return $response; 00636 } 00637 00644 public function setRequest($request) 00645 { 00646 if (is_string($request) && class_exists($request)) { 00647 $request = new $request(); 00648 if (!$request instanceof Zend_Amf_Request) { 00649 require_once 'Zend/Amf/Server/Exception.php'; 00650 throw new Zend_Amf_Server_Exception('Invalid request class'); 00651 } 00652 } elseif (!$request instanceof Zend_Amf_Request) { 00653 require_once 'Zend/Amf/Server/Exception.php'; 00654 throw new Zend_Amf_Server_Exception('Invalid request object'); 00655 } 00656 $this->_request = $request; 00657 return $this; 00658 } 00659 00665 public function getRequest() 00666 { 00667 if (null === $this->_request) { 00668 require_once 'Zend/Amf/Request/Http.php'; 00669 $this->setRequest(new Zend_Amf_Request_Http()); 00670 } 00671 00672 return $this->_request; 00673 } 00674 00681 public function setResponse($response) 00682 { 00683 if (is_string($response) && class_exists($response)) { 00684 $response = new $response(); 00685 if (!$response instanceof Zend_Amf_Response) { 00686 require_once 'Zend/Amf/Server/Exception.php'; 00687 throw new Zend_Amf_Server_Exception('Invalid response class'); 00688 } 00689 } elseif (!$response instanceof Zend_Amf_Response) { 00690 require_once 'Zend/Amf/Server/Exception.php'; 00691 throw new Zend_Amf_Server_Exception('Invalid response object'); 00692 } 00693 $this->_response = $response; 00694 return $this; 00695 } 00696 00702 public function getResponse() 00703 { 00704 if (null === ($response = $this->_response)) { 00705 require_once 'Zend/Amf/Response/Http.php'; 00706 $this->setResponse(new Zend_Amf_Response_Http()); 00707 } 00708 return $this->_response; 00709 } 00710 00726 public function setClass($class, $namespace = '', $argv = null) 00727 { 00728 if (is_string($class) && !class_exists($class)){ 00729 require_once 'Zend/Amf/Server/Exception.php'; 00730 throw new Zend_Amf_Server_Exception('Invalid method or class'); 00731 } elseif (!is_string($class) && !is_object($class)) { 00732 require_once 'Zend/Amf/Server/Exception.php'; 00733 throw new Zend_Amf_Server_Exception('Invalid method or class; must be a classname or object'); 00734 } 00735 00736 $argv = null; 00737 if (2 < func_num_args()) { 00738 $argv = array_slice(func_get_args(), 2); 00739 } 00740 00741 // Use the class name as the name space by default. 00742 00743 if ($namespace == '') { 00744 $namespace = is_object($class) ? get_class($class) : $class; 00745 } 00746 00747 $this->_classAllowed[is_object($class) ? get_class($class) : $class] = true; 00748 00749 $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); 00750 $this->_buildDispatchTable(); 00751 00752 return $this; 00753 } 00754 00767 public function addFunction($function, $namespace = '') 00768 { 00769 if (!is_string($function) && !is_array($function)) { 00770 require_once 'Zend/Amf/Server/Exception.php'; 00771 throw new Zend_Amf_Server_Exception('Unable to attach function'); 00772 } 00773 00774 $argv = null; 00775 if (2 < func_num_args()) { 00776 $argv = array_slice(func_get_args(), 2); 00777 } 00778 00779 $function = (array) $function; 00780 foreach ($function as $func) { 00781 if (!is_string($func) || !function_exists($func)) { 00782 require_once 'Zend/Amf/Server/Exception.php'; 00783 throw new Zend_Amf_Server_Exception('Unable to attach function'); 00784 } 00785 $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace); 00786 } 00787 00788 $this->_buildDispatchTable(); 00789 return $this; 00790 } 00791 00792 00799 public function addDirectory($dir) 00800 { 00801 $this->getLoader()->addPrefixPath("", $dir); 00802 } 00803 00809 public function getDirectory() 00810 { 00811 return $this->getLoader()->getPaths(""); 00812 } 00813 00822 protected function _buildDispatchTable() 00823 { 00824 $table = array(); 00825 foreach ($this->_methods as $key => $dispatchable) { 00826 if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) { 00827 $ns = $dispatchable->getNamespace(); 00828 $name = $dispatchable->getName(); 00829 $name = empty($ns) ? $name : $ns . '.' . $name; 00830 00831 if (isset($table[$name])) { 00832 require_once 'Zend/Amf/Server/Exception.php'; 00833 throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); 00834 } 00835 $table[$name] = $dispatchable; 00836 continue; 00837 } 00838 00839 if ($dispatchable instanceof Zend_Server_Reflection_Class) { 00840 foreach ($dispatchable->getMethods() as $method) { 00841 $ns = $method->getNamespace(); 00842 $name = $method->getName(); 00843 $name = empty($ns) ? $name : $ns . '.' . $name; 00844 00845 if (isset($table[$name])) { 00846 require_once 'Zend/Amf/Server/Exception.php'; 00847 throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); 00848 } 00849 $table[$name] = $method; 00850 continue; 00851 } 00852 } 00853 } 00854 $this->_table = $table; 00855 } 00856 00857 00858 00867 public function fault($fault = null, $code = 404) 00868 { 00869 } 00870 00879 public function getFunctions() 00880 { 00881 return $this->_table; 00882 } 00883 00892 public function setPersistence($mode) 00893 { 00894 } 00895 00904 public function loadFunctions($definition) 00905 { 00906 } 00907 00915 public function setClassMap($asClass, $phpClass) 00916 { 00917 require_once 'Zend/Amf/Parse/TypeLoader.php'; 00918 Zend_Amf_Parse_TypeLoader::setMapping($asClass, $phpClass); 00919 return $this; 00920 } 00921 00929 public function listMethods() 00930 { 00931 return array_keys($this->_table); 00932 } 00933 }