File indexing completed on 2024-12-22 05:36:48
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_Json 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 /** 0023 * @see Zend_Server_Abstract 0024 */ 0025 // require_once 'Zend/Server/Abstract.php'; 0026 0027 /** 0028 * @category Zend 0029 * @package Zend_Json 0030 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0031 * @license http://framework.zend.com/license/new-bsd New BSD License 0032 */ 0033 class Zend_Json_Server extends Zend_Server_Abstract 0034 { 0035 /**#@+ 0036 * Version Constants 0037 */ 0038 const VERSION_1 = '1.0'; 0039 const VERSION_2 = '2.0'; 0040 /**#@-*/ 0041 0042 /** 0043 * Flag: whether or not to auto-emit the response 0044 * @var bool 0045 */ 0046 protected $_autoEmitResponse = true; 0047 0048 /** 0049 * @var bool Flag; allow overwriting existing methods when creating server definition 0050 */ 0051 protected $_overwriteExistingMethods = true; 0052 0053 /** 0054 * Request object 0055 * @var Zend_Json_Server_Request 0056 */ 0057 protected $_request; 0058 0059 /** 0060 * Response object 0061 * @var Zend_Json_Server_Response 0062 */ 0063 protected $_response; 0064 0065 /** 0066 * SMD object 0067 * @var Zend_Json_Server_Smd 0068 */ 0069 protected $_serviceMap; 0070 0071 /** 0072 * SMD class accessors 0073 * @var array 0074 */ 0075 protected $_smdMethods; 0076 0077 /** 0078 * @var Zend_Server_Description 0079 */ 0080 protected $_table; 0081 0082 /** 0083 * Attach a function or callback to the server 0084 * 0085 * @param string|array $function Valid PHP callback 0086 * @param string $namespace Ignored 0087 * @return Zend_Json_Server 0088 */ 0089 public function addFunction($function, $namespace = '') 0090 { 0091 if (!is_string($function) && (!is_array($function) || (2 > count($function)))) { 0092 // require_once 'Zend/Json/Server/Exception.php'; 0093 throw new Zend_Json_Server_Exception('Unable to attach function; invalid'); 0094 } 0095 0096 if (!is_callable($function)) { 0097 // require_once 'Zend/Json/Server/Exception.php'; 0098 throw new Zend_Json_Server_Exception('Unable to attach function; does not exist'); 0099 } 0100 0101 $argv = null; 0102 if (2 < func_num_args()) { 0103 $argv = func_get_args(); 0104 $argv = array_slice($argv, 2); 0105 } 0106 0107 // require_once 'Zend/Server/Reflection.php'; 0108 if (is_string($function)) { 0109 $method = Zend_Server_Reflection::reflectFunction($function, $argv, $namespace); 0110 } else { 0111 $class = array_shift($function); 0112 $action = array_shift($function); 0113 $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); 0114 $methods = $reflection->getMethods(); 0115 $found = false; 0116 foreach ($methods as $method) { 0117 if ($action == $method->getName()) { 0118 $found = true; 0119 break; 0120 } 0121 } 0122 if (!$found) { 0123 $this->fault('Method not found', -32601); 0124 return $this; 0125 } 0126 } 0127 0128 $definition = $this->_buildSignature($method); 0129 $this->_addMethodServiceMap($definition); 0130 0131 return $this; 0132 } 0133 0134 /** 0135 * Register a class with the server 0136 * 0137 * @param string $class 0138 * @param string $namespace Ignored 0139 * @param mixed $argv Ignored 0140 * @return Zend_Json_Server 0141 */ 0142 public function setClass($class, $namespace = '', $argv = null) 0143 { 0144 $argv = null; 0145 if (3 < func_num_args()) { 0146 $argv = func_get_args(); 0147 $argv = array_slice($argv, 3); 0148 } 0149 0150 // require_once 'Zend/Server/Reflection.php'; 0151 $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); 0152 0153 foreach ($reflection->getMethods() as $method) { 0154 $definition = $this->_buildSignature($method, $class); 0155 $this->_addMethodServiceMap($definition); 0156 } 0157 return $this; 0158 } 0159 0160 /** 0161 * Indicate fault response 0162 * 0163 * @param string $fault 0164 * @param int $code 0165 * @return false 0166 */ 0167 public function fault($fault = null, $code = 404, $data = null) 0168 { 0169 // require_once 'Zend/Json/Server/Error.php'; 0170 $error = new Zend_Json_Server_Error($fault, $code, $data); 0171 $this->getResponse()->setError($error); 0172 return $error; 0173 } 0174 0175 /** 0176 * Handle request 0177 * 0178 * @param Zend_Json_Server_Request $request 0179 * @return null|Zend_Json_Server_Response 0180 */ 0181 public function handle($request = false) 0182 { 0183 if ((false !== $request) && (!$request instanceof Zend_Json_Server_Request)) { 0184 // require_once 'Zend/Json/Server/Exception.php'; 0185 throw new Zend_Json_Server_Exception('Invalid request type provided; cannot handle'); 0186 } elseif ($request) { 0187 $this->setRequest($request); 0188 } 0189 0190 // Handle request 0191 $this->_handle(); 0192 0193 // Get response 0194 $response = $this->_getReadyResponse(); 0195 0196 // Emit response? 0197 if ($this->autoEmitResponse()) { 0198 echo $response; 0199 return; 0200 } 0201 0202 // or return it? 0203 return $response; 0204 } 0205 0206 /** 0207 * Load function definitions 0208 * 0209 * @param array|Zend_Server_Definition $definition 0210 * @return void 0211 */ 0212 public function loadFunctions($definition) 0213 { 0214 if (!is_array($definition) && (!$definition instanceof Zend_Server_Definition)) { 0215 // require_once 'Zend/Json/Server/Exception.php'; 0216 throw new Zend_Json_Server_Exception('Invalid definition provided to loadFunctions()'); 0217 } 0218 0219 foreach ($definition as $key => $method) { 0220 $this->_table->addMethod($method, $key); 0221 $this->_addMethodServiceMap($method); 0222 } 0223 } 0224 0225 public function setPersistence($mode) 0226 { 0227 } 0228 0229 /** 0230 * Set request object 0231 * 0232 * @param Zend_Json_Server_Request $request 0233 * @return Zend_Json_Server 0234 */ 0235 public function setRequest(Zend_Json_Server_Request $request) 0236 { 0237 $this->_request = $request; 0238 return $this; 0239 } 0240 0241 /** 0242 * Get JSON-RPC request object 0243 * 0244 * @return Zend_Json_Server_Request 0245 */ 0246 public function getRequest() 0247 { 0248 if (null === ($request = $this->_request)) { 0249 // require_once 'Zend/Json/Server/Request/Http.php'; 0250 $this->setRequest(new Zend_Json_Server_Request_Http()); 0251 } 0252 return $this->_request; 0253 } 0254 0255 /** 0256 * Set response object 0257 * 0258 * @param Zend_Json_Server_Response $response 0259 * @return Zend_Json_Server 0260 */ 0261 public function setResponse(Zend_Json_Server_Response $response) 0262 { 0263 $this->_response = $response; 0264 return $this; 0265 } 0266 0267 /** 0268 * Get response object 0269 * 0270 * @return Zend_Json_Server_Response 0271 */ 0272 public function getResponse() 0273 { 0274 if (null === ($response = $this->_response)) { 0275 // require_once 'Zend/Json/Server/Response/Http.php'; 0276 $this->setResponse(new Zend_Json_Server_Response_Http()); 0277 } 0278 return $this->_response; 0279 } 0280 0281 /** 0282 * Set flag indicating whether or not to auto-emit response 0283 * 0284 * @param bool $flag 0285 * @return Zend_Json_Server 0286 */ 0287 public function setAutoEmitResponse($flag) 0288 { 0289 $this->_autoEmitResponse = (bool) $flag; 0290 return $this; 0291 } 0292 0293 /** 0294 * Will we auto-emit the response? 0295 * 0296 * @return bool 0297 */ 0298 public function autoEmitResponse() 0299 { 0300 return $this->_autoEmitResponse; 0301 } 0302 0303 // overloading for SMD metadata 0304 /** 0305 * Overload to accessors of SMD object 0306 * 0307 * @param string $method 0308 * @param array $args 0309 * @return mixed 0310 */ 0311 public function __call($method, $args) 0312 { 0313 if (preg_match('/^(set|get)/', $method, $matches)) { 0314 if (in_array($method, $this->_getSmdMethods())) { 0315 if ('set' == $matches[1]) { 0316 $value = array_shift($args); 0317 $this->getServiceMap()->$method($value); 0318 return $this; 0319 } else { 0320 return $this->getServiceMap()->$method(); 0321 } 0322 } 0323 } 0324 return null; 0325 } 0326 0327 /** 0328 * Retrieve SMD object 0329 * 0330 * @return Zend_Json_Server_Smd 0331 */ 0332 public function getServiceMap() 0333 { 0334 if (null === $this->_serviceMap) { 0335 // require_once 'Zend/Json/Server/Smd.php'; 0336 $this->_serviceMap = new Zend_Json_Server_Smd(); 0337 } 0338 return $this->_serviceMap; 0339 } 0340 0341 /** 0342 * Add service method to service map 0343 * 0344 * @param Zend_Server_Reflection_Function $method 0345 * @return void 0346 */ 0347 protected function _addMethodServiceMap(Zend_Server_Method_Definition $method) 0348 { 0349 $serviceInfo = array( 0350 'name' => $method->getName(), 0351 'return' => $this->_getReturnType($method), 0352 ); 0353 $params = $this->_getParams($method); 0354 $serviceInfo['params'] = $params; 0355 $serviceMap = $this->getServiceMap(); 0356 if (false !== $serviceMap->getService($serviceInfo['name'])) { 0357 $serviceMap->removeService($serviceInfo['name']); 0358 } 0359 $serviceMap->addService($serviceInfo); 0360 } 0361 0362 /** 0363 * Translate PHP type to JSON type 0364 * 0365 * @param string $type 0366 * @return string 0367 */ 0368 protected function _fixType($type) 0369 { 0370 return $type; 0371 } 0372 0373 /** 0374 * Get default params from signature 0375 * 0376 * @param array $args 0377 * @param array $params 0378 * @return array 0379 */ 0380 protected function _getDefaultParams(array $args, array $params) 0381 { 0382 $defaultParams = array_slice($params, count($args)); 0383 foreach ($defaultParams as $param) { 0384 $value = null; 0385 if (array_key_exists('default', $param)) { 0386 $value = $param['default']; 0387 } 0388 array_push($args, $value); 0389 } 0390 return $args; 0391 } 0392 0393 /** 0394 * Get method param type 0395 * 0396 * @param Zend_Server_Reflection_Function_Abstract $method 0397 * @return string|array 0398 */ 0399 protected function _getParams(Zend_Server_Method_Definition $method) 0400 { 0401 $params = array(); 0402 foreach ($method->getPrototypes() as $prototype) { 0403 foreach ($prototype->getParameterObjects() as $key => $parameter) { 0404 if (!isset($params[$key])) { 0405 $params[$key] = array( 0406 'type' => $parameter->getType(), 0407 'name' => $parameter->getName(), 0408 'optional' => $parameter->isOptional(), 0409 ); 0410 if (null !== ($default = $parameter->getDefaultValue())) { 0411 $params[$key]['default'] = $default; 0412 } 0413 $description = $parameter->getDescription(); 0414 if (!empty($description)) { 0415 $params[$key]['description'] = $description; 0416 } 0417 continue; 0418 } 0419 $newType = $parameter->getType(); 0420 if (!is_array($params[$key]['type'])) { 0421 if ($params[$key]['type'] == $newType) { 0422 continue; 0423 } 0424 $params[$key]['type'] = (array) $params[$key]['type']; 0425 } elseif (in_array($newType, $params[$key]['type'])) { 0426 continue; 0427 } 0428 array_push($params[$key]['type'], $parameter->getType()); 0429 } 0430 } 0431 return $params; 0432 } 0433 0434 /** 0435 * Set response state 0436 * 0437 * @return Zend_Json_Server_Response 0438 */ 0439 protected function _getReadyResponse() 0440 { 0441 $request = $this->getRequest(); 0442 $response = $this->getResponse(); 0443 0444 $response->setServiceMap($this->getServiceMap()); 0445 if (null !== ($id = $request->getId())) { 0446 $response->setId($id); 0447 } 0448 if (null !== ($version = $request->getVersion())) { 0449 $response->setVersion($version); 0450 } 0451 0452 return $response; 0453 } 0454 0455 /** 0456 * Get method return type 0457 * 0458 * @param Zend_Server_Reflection_Function_Abstract $method 0459 * @return string|array 0460 */ 0461 protected function _getReturnType(Zend_Server_Method_Definition $method) 0462 { 0463 $return = array(); 0464 foreach ($method->getPrototypes() as $prototype) { 0465 $return[] = $prototype->getReturnType(); 0466 } 0467 if (1 == count($return)) { 0468 return $return[0]; 0469 } 0470 return $return; 0471 } 0472 0473 /** 0474 * Retrieve list of allowed SMD methods for proxying 0475 * 0476 * @return array 0477 */ 0478 protected function _getSmdMethods() 0479 { 0480 if (null === $this->_smdMethods) { 0481 $this->_smdMethods = array(); 0482 // require_once 'Zend/Json/Server/Smd.php'; 0483 $methods = get_class_methods('Zend_Json_Server_Smd'); 0484 foreach ($methods as $key => $method) { 0485 if (!preg_match('/^(set|get)/', $method)) { 0486 continue; 0487 } 0488 if (strstr($method, 'Service')) { 0489 continue; 0490 } 0491 $this->_smdMethods[] = $method; 0492 } 0493 } 0494 return $this->_smdMethods; 0495 } 0496 0497 /** 0498 * Internal method for handling request 0499 * 0500 * @return void 0501 */ 0502 protected function _handle() 0503 { 0504 $request = $this->getRequest(); 0505 0506 if (!$request->isMethodError() && (null === $request->getMethod())) { 0507 return $this->fault('Invalid Request', -32600); 0508 } 0509 0510 if ($request->isMethodError()) { 0511 return $this->fault('Invalid Request', -32600); 0512 } 0513 0514 $method = $request->getMethod(); 0515 if (!$this->_table->hasMethod($method)) { 0516 return $this->fault('Method not found', -32601); 0517 } 0518 0519 $params = $request->getParams(); 0520 $invocable = $this->_table->getMethod($method); 0521 $serviceMap = $this->getServiceMap(); 0522 $service = $serviceMap->getService($method); 0523 $serviceParams = $service->getParams(); 0524 0525 if (count($params) < count($serviceParams)) { 0526 $params = $this->_getDefaultParams($params, $serviceParams); 0527 } 0528 0529 //Make sure named parameters are passed in correct order 0530 if ( is_string( key( $params ) ) ) { 0531 0532 $callback = $invocable->getCallback(); 0533 if ('function' == $callback->getType()) { 0534 $reflection = new ReflectionFunction( $callback->getFunction() ); 0535 $refParams = $reflection->getParameters(); 0536 } else { 0537 0538 $reflection = new ReflectionMethod( 0539 $callback->getClass(), 0540 $callback->getMethod() 0541 ); 0542 $refParams = $reflection->getParameters(); 0543 } 0544 0545 $orderedParams = array(); 0546 foreach( $reflection->getParameters() as $refParam ) { 0547 if( isset( $params[ $refParam->getName() ] ) ) { 0548 $orderedParams[ $refParam->getName() ] = $params[ $refParam->getName() ]; 0549 } elseif( $refParam->isOptional() ) { 0550 $orderedParams[ $refParam->getName() ] = $refParam->getDefaultValue(); 0551 } else { 0552 throw new Zend_Server_Exception( 0553 'Method ' . $request->getMethod() . ' is missing required parameter: ' . $refParam->getName() 0554 ); 0555 } 0556 } 0557 $params = $orderedParams; 0558 } 0559 0560 try { 0561 $result = $this->_dispatch($invocable, $params); 0562 } catch (Exception $e) { 0563 return $this->fault($e->getMessage(), $e->getCode(), $e); 0564 } 0565 0566 $this->getResponse()->setResult($result); 0567 } 0568 }