[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
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 [email protected] so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Rest 17 * @subpackage Server 18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id$ 21 */ 22 23 /** 24 * @see Zend_Server_Interface 25 */ 26 require_once 'Zend/Server/Interface.php'; 27 28 /** 29 * @see Zend_Server_Reflection 30 */ 31 require_once 'Zend/Server/Reflection.php'; 32 33 /** 34 * @see Zend_Server_Abstract 35 */ 36 require_once 'Zend/Server/Abstract.php'; 37 38 /** 39 * @category Zend 40 * @package Zend_Rest 41 * @subpackage Server 42 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 43 * @license http://framework.zend.com/license/new-bsd New BSD License 44 */ 45 class Zend_Rest_Server implements Zend_Server_Interface 46 { 47 /** 48 * Class Constructor Args 49 * @var array 50 */ 51 protected $_args = array(); 52 53 /** 54 * @var string Encoding 55 */ 56 protected $_encoding = 'UTF-8'; 57 58 /** 59 * @var array An array of Zend_Server_Reflect_Method 60 */ 61 protected $_functions = array(); 62 63 /** 64 * @var array Array of headers to send 65 */ 66 protected $_headers = array(); 67 68 /** 69 * @var array PHP's Magic Methods, these are ignored 70 */ 71 protected static $magicMethods = array( 72 '__construct', 73 '__destruct', 74 '__get', 75 '__set', 76 '__call', 77 '__sleep', 78 '__wakeup', 79 '__isset', 80 '__unset', 81 '__tostring', 82 '__clone', 83 '__set_state', 84 ); 85 86 /** 87 * @var string Current Method 88 */ 89 protected $_method; 90 91 /** 92 * @var Zend_Server_Reflection 93 */ 94 protected $_reflection = null; 95 96 /** 97 * Whether or not {@link handle()} should send output or return the response. 98 * @var boolean Defaults to false 99 */ 100 protected $_returnResponse = false; 101 102 /** 103 * Constructor 104 */ 105 public function __construct() 106 { 107 set_exception_handler(array($this, "fault")); 108 $this->_reflection = new Zend_Server_Reflection(); 109 } 110 111 /** 112 * Set XML encoding 113 * 114 * @param string $encoding 115 * @return Zend_Rest_Server 116 */ 117 public function setEncoding($encoding) 118 { 119 $this->_encoding = (string) $encoding; 120 return $this; 121 } 122 123 /** 124 * Get XML encoding 125 * 126 * @return string 127 */ 128 public function getEncoding() 129 { 130 return $this->_encoding; 131 } 132 133 /** 134 * Lowercase a string 135 * 136 * Lowercase's a string by reference 137 * 138 * @param string $value 139 * @param string $key 140 * @return string Lower cased string 141 */ 142 public static function lowerCase(&$value, &$key) 143 { 144 return $value = strtolower($value); 145 } 146 147 /** 148 * Whether or not to return a response 149 * 150 * If called without arguments, returns the value of the flag. If called 151 * with an argument, sets the flag. 152 * 153 * When 'return response' is true, {@link handle()} will not send output, 154 * but will instead return the response from the dispatched function/method. 155 * 156 * @param boolean $flag 157 * @return boolean|Zend_Rest_Server Returns Zend_Rest_Server when used to set the flag; returns boolean flag value otherwise. 158 */ 159 public function returnResponse($flag = null) 160 { 161 if (null === $flag) { 162 return $this->_returnResponse; 163 } 164 165 $this->_returnResponse = ($flag) ? true : false; 166 return $this; 167 } 168 169 /** 170 * Implement Zend_Server_Interface::handle() 171 * 172 * @param array $request 173 * @throws Zend_Rest_Server_Exception 174 * @return string|void 175 */ 176 public function handle($request = false) 177 { 178 $this->_headers = array('Content-Type: text/xml'); 179 if (!$request) { 180 $request = $_REQUEST; 181 } 182 if (isset($request['method'])) { 183 $this->_method = $request['method']; 184 if (isset($this->_functions[$this->_method])) { 185 if ($this->_functions[$this->_method] instanceof Zend_Server_Reflection_Function || $this->_functions[$this->_method] instanceof Zend_Server_Reflection_Method && $this->_functions[$this->_method]->isPublic()) { 186 $request_keys = array_keys($request); 187 array_walk($request_keys, array(__CLASS__, "lowerCase")); 188 $request = array_combine($request_keys, $request); 189 190 $func_args = $this->_functions[$this->_method]->getParameters(); 191 192 $calling_args = array(); 193 $missing_args = array(); 194 foreach ($func_args as $arg) { 195 if (isset($request[strtolower($arg->getName())])) { 196 $calling_args[] = $request[strtolower($arg->getName())]; 197 } elseif ($arg->isOptional()) { 198 $calling_args[] = $arg->getDefaultValue(); 199 } else { 200 $missing_args[] = $arg->getName(); 201 } 202 } 203 204 foreach ($request as $key => $value) { 205 if (substr($key, 0, 3) == 'arg') { 206 $key = str_replace('arg', '', $key); 207 $calling_args[$key] = $value; 208 if (($index = array_search($key, $missing_args)) !== false) { 209 unset($missing_args[$index]); 210 } 211 } 212 } 213 214 // Sort arguments by key -- @see ZF-2279 215 ksort($calling_args); 216 217 $result = false; 218 if (count($calling_args) < count($func_args)) { 219 require_once 'Zend/Rest/Server/Exception.php'; 220 $result = $this->fault(new Zend_Rest_Server_Exception('Invalid Method Call to ' . $this->_method . '. Missing argument(s): ' . implode(', ', $missing_args) . '.'), 400); 221 } 222 223 if (!$result && $this->_functions[$this->_method] instanceof Zend_Server_Reflection_Method) { 224 // Get class 225 $class = $this->_functions[$this->_method]->getDeclaringClass()->getName(); 226 227 if ($this->_functions[$this->_method]->isStatic()) { 228 // for some reason, invokeArgs() does not work the same as 229 // invoke(), and expects the first argument to be an object. 230 // So, using a callback if the method is static. 231 $result = $this->_callStaticMethod($class, $calling_args); 232 } else { 233 // Object method 234 $result = $this->_callObjectMethod($class, $calling_args); 235 } 236 } elseif (!$result) { 237 try { 238 $result = call_user_func_array($this->_functions[$this->_method]->getName(), $calling_args); //$this->_functions[$this->_method]->invokeArgs($calling_args); 239 } catch (Exception $e) { 240 $result = $this->fault($e); 241 } 242 } 243 } else { 244 require_once "Zend/Rest/Server/Exception.php"; 245 $result = $this->fault( 246 new Zend_Rest_Server_Exception("Unknown Method '$this->_method'."), 247 404 248 ); 249 } 250 } else { 251 require_once "Zend/Rest/Server/Exception.php"; 252 $result = $this->fault( 253 new Zend_Rest_Server_Exception("Unknown Method '$this->_method'."), 254 404 255 ); 256 } 257 } else { 258 require_once "Zend/Rest/Server/Exception.php"; 259 $result = $this->fault( 260 new Zend_Rest_Server_Exception("No Method Specified."), 261 404 262 ); 263 } 264 265 if ($result instanceof SimpleXMLElement) { 266 $response = $result->asXML(); 267 } elseif ($result instanceof DOMDocument) { 268 $response = $result->saveXML(); 269 } elseif ($result instanceof DOMNode) { 270 $response = $result->ownerDocument->saveXML($result); 271 } elseif (is_array($result) || is_object($result)) { 272 $response = $this->_handleStruct($result); 273 } else { 274 $response = $this->_handleScalar($result); 275 } 276 277 if (!$this->returnResponse()) { 278 if (!headers_sent()) { 279 foreach ($this->_headers as $header) { 280 header($header); 281 } 282 } 283 284 echo $response; 285 return; 286 } 287 288 return $response; 289 } 290 291 /** 292 * Implement Zend_Server_Interface::setClass() 293 * 294 * @param string $classname Class name 295 * @param string $namespace Class namespace (unused) 296 * @param array $argv An array of Constructor Arguments 297 */ 298 public function setClass($classname, $namespace = '', $argv = array()) 299 { 300 $this->_args = $argv; 301 foreach ($this->_reflection->reflectClass($classname, $argv)->getMethods() as $method) { 302 $this->_functions[$method->getName()] = $method; 303 } 304 } 305 306 /** 307 * Handle an array or object result 308 * 309 * @param array|object $struct Result Value 310 * @return string XML Response 311 */ 312 protected function _handleStruct($struct) 313 { 314 $function = $this->_functions[$this->_method]; 315 if ($function instanceof Zend_Server_Reflection_Method) { 316 $class = $function->getDeclaringClass()->getName(); 317 } else { 318 $class = false; 319 } 320 321 $method = $function->getName(); 322 323 $dom = new DOMDocument('1.0', $this->getEncoding()); 324 if ($class) { 325 $root = $dom->createElement($class); 326 $method = $dom->createElement($method); 327 $root->appendChild($method); 328 } else { 329 $root = $dom->createElement($method); 330 $method = $root; 331 } 332 $root->setAttribute('generator', 'zend'); 333 $root->setAttribute('version', '1.0'); 334 $dom->appendChild($root); 335 336 $this->_structValue($struct, $dom, $method); 337 338 $struct = (array) $struct; 339 if (!isset($struct['status'])) { 340 $status = $dom->createElement('status', 'success'); 341 $method->appendChild($status); 342 } 343 344 return $dom->saveXML(); 345 } 346 347 /** 348 * Recursively iterate through a struct 349 * 350 * Recursively iterates through an associative array or object's properties 351 * to build XML response. 352 * 353 * @param mixed $struct 354 * @param DOMDocument $dom 355 * @param DOMElement $parent 356 * @return void 357 */ 358 protected function _structValue($struct, DOMDocument $dom, DOMElement $parent) 359 { 360 $struct = (array) $struct; 361 362 foreach ($struct as $key => $value) { 363 if ($value === false) { 364 $value = 0; 365 } elseif ($value === true) { 366 $value = 1; 367 } 368 369 if (ctype_digit((string) $key)) { 370 $key = 'key_' . $key; 371 } 372 373 if (is_array($value) || is_object($value)) { 374 $element = $dom->createElement($key); 375 $this->_structValue($value, $dom, $element); 376 } else { 377 $element = $dom->createElement($key); 378 $element->appendChild($dom->createTextNode($value)); 379 } 380 381 $parent->appendChild($element); 382 } 383 } 384 385 /** 386 * Handle a single value 387 * 388 * @param string|int|boolean $value Result value 389 * @return string XML Response 390 */ 391 protected function _handleScalar($value) 392 { 393 $function = $this->_functions[$this->_method]; 394 if ($function instanceof Zend_Server_Reflection_Method) { 395 $class = $function->getDeclaringClass()->getName(); 396 } else { 397 $class = false; 398 } 399 400 $method = $function->getName(); 401 402 $dom = new DOMDocument('1.0', $this->getEncoding()); 403 if ($class) { 404 $xml = $dom->createElement($class); 405 $methodNode = $dom->createElement($method); 406 $xml->appendChild($methodNode); 407 } else { 408 $xml = $dom->createElement($method); 409 $methodNode = $xml; 410 } 411 $xml->setAttribute('generator', 'zend'); 412 $xml->setAttribute('version', '1.0'); 413 $dom->appendChild($xml); 414 415 if ($value === false) { 416 $value = 0; 417 } elseif ($value === true) { 418 $value = 1; 419 } 420 421 if (isset($value)) { 422 $element = $dom->createElement('response'); 423 $element->appendChild($dom->createTextNode($value)); 424 $methodNode->appendChild($element); 425 } else { 426 $methodNode->appendChild($dom->createElement('response')); 427 } 428 429 $methodNode->appendChild($dom->createElement('status', 'success')); 430 431 return $dom->saveXML(); 432 } 433 434 /** 435 * Implement Zend_Server_Interface::fault() 436 * 437 * Creates XML error response, returning DOMDocument with response. 438 * 439 * @param string|Exception $fault Message 440 * @param int $code Error Code 441 * @return DOMDocument 442 */ 443 public function fault($exception = null, $code = null) 444 { 445 if (isset($this->_functions[$this->_method])) { 446 $function = $this->_functions[$this->_method]; 447 } elseif (isset($this->_method)) { 448 $function = $this->_method; 449 } else { 450 $function = 'rest'; 451 } 452 453 if ($function instanceof Zend_Server_Reflection_Method) { 454 $class = $function->getDeclaringClass()->getName(); 455 } else { 456 $class = false; 457 } 458 459 if ($function instanceof Zend_Server_Reflection_Function_Abstract) { 460 $method = $function->getName(); 461 } else { 462 $method = $function; 463 } 464 465 $dom = new DOMDocument('1.0', $this->getEncoding()); 466 if ($class) { 467 $xml = $dom->createElement($class); 468 $xmlMethod = $dom->createElement($method); 469 $xml->appendChild($xmlMethod); 470 } else { 471 $xml = $dom->createElement($method); 472 $xmlMethod = $xml; 473 } 474 $xml->setAttribute('generator', 'zend'); 475 $xml->setAttribute('version', '1.0'); 476 $dom->appendChild($xml); 477 478 $xmlResponse = $dom->createElement('response'); 479 $xmlMethod->appendChild($xmlResponse); 480 481 if ($exception instanceof Exception) { 482 $element = $dom->createElement('message'); 483 $element->appendChild($dom->createTextNode($exception->getMessage())); 484 $xmlResponse->appendChild($element); 485 $code = $exception->getCode(); 486 } elseif (($exception !== null) || 'rest' == $function) { 487 $xmlResponse->appendChild($dom->createElement('message', 'An unknown error occured. Please try again.')); 488 } else { 489 $xmlResponse->appendChild($dom->createElement('message', 'Call to ' . $method . ' failed.')); 490 } 491 492 $xmlMethod->appendChild($xmlResponse); 493 $xmlMethod->appendChild($dom->createElement('status', 'failed')); 494 495 // Headers to send 496 if ($code === null || (404 != $code)) { 497 $this->_headers[] = 'HTTP/1.0 400 Bad Request'; 498 } else { 499 $this->_headers[] = 'HTTP/1.0 404 File Not Found'; 500 } 501 502 return $dom; 503 } 504 505 /** 506 * Retrieve any HTTP extra headers set by the server 507 * 508 * @return array 509 */ 510 public function getHeaders() 511 { 512 return $this->_headers; 513 } 514 515 /** 516 * Implement Zend_Server_Interface::addFunction() 517 * 518 * @param string $function Function Name 519 * @param string $namespace Function namespace (unused) 520 */ 521 public function addFunction($function, $namespace = '') 522 { 523 if (!is_array($function)) { 524 $function = (array) $function; 525 } 526 527 foreach ($function as $func) { 528 if (is_callable($func) && !in_array($func, self::$magicMethods)) { 529 $this->_functions[$func] = $this->_reflection->reflectFunction($func); 530 } else { 531 require_once 'Zend/Rest/Server/Exception.php'; 532 throw new Zend_Rest_Server_Exception("Invalid Method Added to Service."); 533 } 534 } 535 } 536 537 /** 538 * Implement Zend_Server_Interface::getFunctions() 539 * 540 * @return array An array of Zend_Server_Reflection_Method's 541 */ 542 public function getFunctions() 543 { 544 return $this->_functions; 545 } 546 547 /** 548 * Implement Zend_Server_Interface::loadFunctions() 549 * 550 * @todo Implement 551 * @param array $functions 552 */ 553 public function loadFunctions($functions) 554 { 555 } 556 557 /** 558 * Implement Zend_Server_Interface::setPersistence() 559 * 560 * @todo Implement 561 * @param int $mode 562 */ 563 public function setPersistence($mode) 564 { 565 } 566 567 /** 568 * Call a static class method and return the result 569 * 570 * @param string $class 571 * @param array $args 572 * @return mixed 573 */ 574 protected function _callStaticMethod($class, array $args) 575 { 576 try { 577 $result = call_user_func_array(array($class, $this->_functions[$this->_method]->getName()), $args); 578 } catch (Exception $e) { 579 $result = $this->fault($e); 580 } 581 return $result; 582 } 583 584 /** 585 * Call an instance method of an object 586 * 587 * @param string $class 588 * @param array $args 589 * @return mixed 590 * @throws Zend_Rest_Server_Exception For invalid class name 591 */ 592 protected function _callObjectMethod($class, array $args) 593 { 594 try { 595 if ($this->_functions[$this->_method]->getDeclaringClass()->getConstructor()) { 596 $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstanceArgs($this->_args); 597 } else { 598 $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstance(); 599 } 600 } catch (Exception $e) { 601 require_once 'Zend/Rest/Server/Exception.php'; 602 throw new Zend_Rest_Server_Exception('Error instantiating class ' . $class . 603 ' to invoke method ' . $this->_functions[$this->_method]->getName() . 604 ' (' . $e->getMessage() . ') ', 605 500, $e); 606 } 607 608 try { 609 $result = $this->_functions[$this->_method]->invokeArgs($object, $args); 610 } catch (Exception $e) { 611 $result = $this->fault($e); 612 } 613 614 return $result; 615 } 616 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |