Handler.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. /**
  3. * This file is part of amfPHP
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the license that is bundled
  8. * with this package in the file license.txt.
  9. */
  10. /**
  11. * This is the default handler for the gateway. It's job is to handle everything that is specific to Amf for the gateway.
  12. *
  13. * @todo determine if indirection for serializer/deserializer necessary. Makes gateway code lighter, but is cumbersome
  14. * @package Amfphp_Core_Amf
  15. * @author Ariel Sommeria-Klein
  16. */
  17. class Amfphp_Core_Amf_Handler implements Amfphp_Core_Common_IDeserializer, Amfphp_Core_Common_IDeserializedRequestHandler, Amfphp_Core_Common_IExceptionHandler, Amfphp_Core_Common_ISerializer {
  18. /**
  19. * filter called for each amf request header, to give a plugin the chance to handle it.
  20. * Unless a plugin handles them, amf headers are ignored
  21. * Headers embedded in the serialized requests are regarded to be a Amf specific, so they get their filter in Amf Handler
  22. * @param Object $handler. null at call. Return if the plugin can handle
  23. * @param Amfphp_Core_Amf_Header $header the request header
  24. * @todo consider an interface for $handler. Maybe overkill here
  25. */
  26. const FILTER_AMF_REQUEST_HEADER_HANDLER = 'FILTER_AMF_REQUEST_HEADER_HANDLER';
  27. /**
  28. * filter called for each amf request message, to give a plugin the chance to handle it.
  29. * This is for the Flex Messaging plugin to be able to intercept the message and say it wants to handle it
  30. * @param Object $handler. null at call. Return if the plugin can handle
  31. * @param Amfphp_Core_Amf_Message $requestMessage the request message
  32. * @todo consider an interface for $handler. Maybe overkill here
  33. */
  34. const FILTER_AMF_REQUEST_MESSAGE_HANDLER = 'FILTER_AMF_REQUEST_MESSAGE_HANDLER';
  35. /**
  36. * filter called for exception handling an Amf packet/message, to give a plugin the chance to handle it.
  37. * This is for the Flex Messaging plugin to be able to intercept the exception and say it wants to handle it
  38. * @param Object $handler. null at call. Return if the plugin can handle
  39. * @todo consider an interface for $handler. Maybe overkill here
  40. */
  41. const FILTER_AMF_EXCEPTION_HANDLER = 'FILTER_AMF_EXCEPTION_HANDLER';
  42. /**
  43. * Amf specifies that an error message must be aimed at an end point. This stores the last message's response Uri to be able to give this end point
  44. * in case of an exception during the handling of the message. The default is '/1', because a response Uri is not always available
  45. * @var String
  46. */
  47. protected $lastRequestMessageResponseUri;
  48. /**
  49. * return error details
  50. * @see Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS
  51. * @var boolean
  52. */
  53. protected $returnErrorDetails = true;
  54. /**
  55. * Vo Converter.
  56. * @var Amfphp_Core_Common_IVoConverter
  57. */
  58. protected $voConverter;
  59. /**
  60. * use this to manipulate the packet directly from your services. This is an advanced option, and should be used with caution!
  61. * @var Amfphp_Core_Amf_Packet
  62. */
  63. public static $requestPacket;
  64. /**
  65. * use this to manipulate the packet directly from your services. This is an advanced option, and should be used with caution!
  66. * @var Amfphp_Core_Amf_Packet
  67. */
  68. public static $responsePacket;
  69. /**
  70. * constructor
  71. * @param array $sharedConfig
  72. */
  73. public function __construct($sharedConfig) {
  74. $this->lastRequestMessageResponseUri = '/1';
  75. if (isset($sharedConfig[Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS])) {
  76. $this->returnErrorDetails = $sharedConfig[Amfphp_Core_Config::CONFIG_RETURN_ERROR_DETAILS];
  77. }
  78. }
  79. /**
  80. * deserialize
  81. * @see Amfphp_Core_Common_IDeserializer
  82. * @param array $getData
  83. * @param array $postData
  84. * @param string $rawPostData
  85. * @return string
  86. */
  87. public function deserialize(array $getData, array $postData, $rawPostData) {
  88. $deserializer = new Amfphp_Core_Amf_Deserializer();
  89. //note: this has to be done here and not in the constructor to avoid
  90. //disabling scanning when it's another handler that ends up handling the request
  91. $this->voConverter = Amfphp_Core_FilterManager::getInstance()->callFilters(Amfphp_Core_Gateway::FILTER_VO_CONVERTER, null);
  92. if($this->voConverter){
  93. $this->voConverter->setScanEnabled(false);
  94. $deserializer->voConverter = $this->voConverter;
  95. }
  96. $requestPacket = $deserializer->deserialize($getData, $postData, $rawPostData);
  97. return $requestPacket;
  98. }
  99. /**
  100. * creates a ServiceCallParameters object from an Amfphp_Core_Amf_Message
  101. * supported separators in the targetUri are '/' and '.'
  102. * @param Amfphp_Core_Amf_Message $Amfphp_Core_Amf_Message
  103. * @return Amfphp_Core_Common_ServiceCallParameters
  104. */
  105. protected function getServiceCallParameters(Amfphp_Core_Amf_Message $Amfphp_Core_Amf_Message) {
  106. $targetUri = str_replace('.', '/', $Amfphp_Core_Amf_Message->targetUri);
  107. $split = explode('/', $targetUri);
  108. $ret = new Amfphp_Core_Common_ServiceCallParameters();
  109. $ret->methodName = array_pop($split);
  110. $ret->serviceName = join($split, '/');
  111. $ret->methodParameters = $Amfphp_Core_Amf_Message->data;
  112. return $ret;
  113. }
  114. /**
  115. * process a request and generate a response.
  116. * throws an Exception if anything fails, so caller must encapsulate in try/catch
  117. *
  118. * @param Amfphp_Core_Amf_Message $requestMessage
  119. * @param Amfphp_Core_Common_ServiceRouter $serviceRouter
  120. * @return Amfphp_Core_Amf_Message the response Message for the request
  121. */
  122. protected function handleRequestMessage(Amfphp_Core_Amf_Message $requestMessage, Amfphp_Core_Common_ServiceRouter $serviceRouter) {
  123. $filterManager = Amfphp_Core_FilterManager::getInstance();
  124. $fromFilters = $filterManager->callFilters(self::FILTER_AMF_REQUEST_MESSAGE_HANDLER, null, $requestMessage);
  125. if ($fromFilters) {
  126. $handler = $fromFilters;
  127. return $handler->handleRequestMessage($requestMessage, $serviceRouter);
  128. }
  129. //plugins didn't do any special handling. Assumes this is a simple Amfphp_Core_Amf_ RPC call
  130. $serviceCallParameters = $this->getServiceCallParameters($requestMessage);
  131. $ret = $serviceRouter->executeServiceCall($serviceCallParameters->serviceName, $serviceCallParameters->methodName, $serviceCallParameters->methodParameters);
  132. $responseMessage = new Amfphp_Core_Amf_Message();
  133. $responseMessage->data = $ret;
  134. $responseMessage->targetUri = $requestMessage->responseUri . Amfphp_Core_Amf_Constants::CLIENT_SUCCESS_METHOD;
  135. //not specified
  136. $responseMessage->responseUri = 'null';
  137. return $responseMessage;
  138. }
  139. /**
  140. * handle deserialized request
  141. * @see Amfphp_Core_Common_IDeserializedRequestHandler
  142. * @param mixed $deserializedRequest
  143. * @param Amfphp_Core_Common_ServiceRouter $serviceRouter
  144. * @return mixed
  145. */
  146. public function handleDeserializedRequest($deserializedRequest, Amfphp_Core_Common_ServiceRouter $serviceRouter) {
  147. self::$requestPacket = $deserializedRequest;
  148. self::$responsePacket = new Amfphp_Core_Amf_Packet();
  149. $numHeaders = count(self::$requestPacket->headers);
  150. for ($i = 0; $i < $numHeaders; $i++) {
  151. $requestHeader = self::$requestPacket->headers[$i];
  152. //handle a header. This is a job for plugins, unless comes a header that is so fundamental that it needs to be handled by the core
  153. $fromFilters = Amfphp_Core_FilterManager::getInstance()->callFilters(self::FILTER_AMF_REQUEST_HEADER_HANDLER, null, $requestHeader);
  154. if ($fromFilters) {
  155. $handler = $fromFilters;
  156. $handler->handleRequestHeader($requestHeader);
  157. }
  158. }
  159. $numMessages = count(self::$requestPacket->messages);
  160. //set amf version to the one detected in request
  161. self::$responsePacket->amfVersion = self::$requestPacket->amfVersion;
  162. //handle each message
  163. for ($i = 0; $i < $numMessages; $i++) {
  164. $requestMessage = self::$requestPacket->messages[$i];
  165. $this->lastRequestMessageResponseUri = $requestMessage->responseUri;
  166. $responseMessage = $this->handleRequestMessage($requestMessage, $serviceRouter);
  167. self::$responsePacket->messages[] = $responseMessage;
  168. }
  169. return self::$responsePacket;
  170. }
  171. /**
  172. * handle exception
  173. * @see Amfphp_Core_Common_IExceptionHandler
  174. * @param Exception $exception
  175. * @return Amfphp_Core_Amf_Packet
  176. */
  177. public function handleException(Exception $exception) {
  178. $errorPacket = new Amfphp_Core_Amf_Packet();
  179. $filterManager = Amfphp_Core_FilterManager::getInstance();
  180. $fromFilters = $filterManager->callFilters(self::FILTER_AMF_EXCEPTION_HANDLER, null);
  181. if ($fromFilters) {
  182. $handler = $fromFilters;
  183. return $handler->generateErrorResponse($exception);
  184. }
  185. //no special handling by plugins. generate a simple error response with information about the exception
  186. $errorResponseMessage = null;
  187. $errorResponseMessage = new Amfphp_Core_Amf_Message();
  188. $errorResponseMessage->targetUri = $this->lastRequestMessageResponseUri . Amfphp_Core_Amf_Constants::CLIENT_FAILURE_METHOD;
  189. //not specified
  190. $errorResponseMessage->responseUri = 'null';
  191. $data = new stdClass();
  192. $data->faultCode = $exception->getCode();
  193. $data->faultString = $exception->getMessage();
  194. if ($this->returnErrorDetails) {
  195. $data->faultDetail = $exception->getTraceAsString();
  196. $data->rootCause = $exception;
  197. } else {
  198. $data->faultDetail = '';
  199. }
  200. $errorResponseMessage->data = $data;
  201. $errorPacket->messages[] = $errorResponseMessage;
  202. return $errorPacket;
  203. }
  204. /**
  205. * serialize
  206. * @see Amfphp_Core_Common_ISerializer
  207. * @param mixed $data
  208. * @return mixed
  209. */
  210. public function serialize($data) {
  211. $serializer = new Amfphp_Core_Amf_Serializer();
  212. $serializer->voConverter = $this->voConverter;
  213. return $serializer->serialize($data);
  214. }
  215. }
  216. ?>