PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/webservice/amf/locallib.php

http://github.com/moodle/moodle
PHP | 202 lines | 111 code | 21 blank | 70 comment | 22 complexity | d0a3c67cba8cb62b9f9f0add85c9ea31 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * AMF web service implementation classes and methods.
  18. *
  19. * @package webservice
  20. * @copyright 2009 Moodle Pty Ltd (http://moodle.com)
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. require_once("$CFG->dirroot/webservice/lib.php");
  24. require_once( "{$CFG->dirroot}/webservice/amf/introspector.php");
  25. require_once 'Zend/Amf/Server.php';
  26. /**
  27. * Exception indicating an invalid return value from a function.
  28. * Used when an externallib function does not return values of the expected structure.
  29. */
  30. class invalid_return_value_exception extends moodle_exception {
  31. /**
  32. * Constructor
  33. * @param string $debuginfo some detailed information
  34. */
  35. function __construct($debuginfo=null) {
  36. parent::__construct('invalidreturnvalue', 'webservice_amf', '', $debuginfo, $debuginfo);
  37. }
  38. }
  39. /**
  40. * AMF service server implementation.
  41. * @author Petr Skoda (skodak)
  42. */
  43. class webservice_amf_server extends webservice_zend_server {
  44. /**
  45. * Contructor
  46. * @param integer $authmethod authentication method - one of WEBSERVICE_AUTHMETHOD_*
  47. */
  48. public function __construct($authmethod) {
  49. parent::__construct($authmethod, 'Moodle_Amf_Server');
  50. $this->wsname = 'amf';
  51. }
  52. protected function init_service_class(){
  53. parent::init_service_class();
  54. //allow access to data about methods available.
  55. $this->zend_server->setClass( "MethodDescriptor" );
  56. MethodDescriptor::$classnametointrospect = $this->service_class;
  57. }
  58. protected function service_class_method_body($function, $params){
  59. //cast the param from object to array (validate_parameters except array only)
  60. $castingcode = '';
  61. if ($params){
  62. $paramstocast = explode(',', $params);
  63. foreach ($paramstocast as $paramtocast) {
  64. $paramtocast = trim($paramtocast);
  65. $castingcode .= $paramtocast .
  66. '=webservice_zend_server::cast_objects_to_array('.$paramtocast.');';
  67. }
  68. }
  69. $externallibcall = $function->classname.'::'.$function->methodname.'('.$params.')';
  70. $descriptionmethod = $function->methodname.'_returns()';
  71. $callforreturnvaluedesc = $function->classname.'::'.$descriptionmethod;
  72. return $castingcode .
  73. ' return webservice_amf_server::validate_and_cast_values('.$callforreturnvaluedesc.', '.$externallibcall.');';
  74. }
  75. /**
  76. * Validates submitted value, comparing it to a description. If anything is incorrect
  77. * invalid_return_value_exception is thrown. Also casts the values to the type specified in
  78. * the description.
  79. * @param mixed $description description of parameters or null if no return value
  80. * @param mixed $value the actual values
  81. * @param boolean $singleasobject specifies whether a external_single_structure should be cast to a stdClass object
  82. * should always be false for use in validating parameters in externallib functions.
  83. * @return mixed params with added defaults for optional items, invalid_parameters_exception thrown if any problem found
  84. */
  85. public static function validate_and_cast_values($description, $value) {
  86. if (is_null($description)){
  87. return;
  88. }
  89. if ($description instanceof external_value) {
  90. if (is_array($value) or is_object($value)) {
  91. throw new invalid_return_value_exception('Scalar type expected, array or object received.');
  92. }
  93. if ($description->type == PARAM_BOOL) {
  94. // special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
  95. if (is_bool($value) or $value === 0 or $value === 1 or $value === '0' or $value === '1') {
  96. return (bool)$value;
  97. }
  98. }
  99. return validate_param($value, $description->type, $description->allownull, 'Invalid external api parameter');
  100. } else if ($description instanceof external_single_structure) {
  101. if (!is_array($value)) {
  102. throw new invalid_return_value_exception('Only arrays accepted.');
  103. }
  104. $result = array();
  105. foreach ($description->keys as $key=>$subdesc) {
  106. if (!array_key_exists($key, $value)) {
  107. if ($subdesc->required == VALUE_REQUIRED) {
  108. throw new invalid_return_value_exception('Missing required key in single structure: '.$key);
  109. }
  110. if ($subdesc instanceof external_value) {
  111. if ($subdesc->required == VALUE_DEFAULT) {
  112. $result[$key] = self::validate_and_cast_values($subdesc, $subdesc->default);
  113. }
  114. }
  115. } else {
  116. $result[$key] = self::validate_and_cast_values($subdesc, $value[$key]);
  117. }
  118. unset($value[$key]);
  119. }
  120. /* Was decided that extra keys should just be ignored and not returned.
  121. * if (!empty($value)) {
  122. throw new invalid_return_value_exception('Unexpected keys detected in parameter array.');
  123. }*/
  124. return (object)$result;
  125. } else if ($description instanceof external_multiple_structure) {
  126. if (!is_array($value)) {
  127. throw new invalid_return_value_exception('Only arrays accepted.');
  128. }
  129. $result = array();
  130. foreach ($value as $param) {
  131. $result[] = self::validate_and_cast_values($description->content, $param);
  132. }
  133. return $result;
  134. } else {
  135. throw new invalid_return_value_exception('Invalid external api description.');
  136. }
  137. }
  138. /**
  139. * Set up zend service class
  140. * @return void
  141. */
  142. protected function init_zend_server() {
  143. parent::init_zend_server();
  144. $this->zend_server->setProduction(false); //set to false for development mode
  145. //(complete error message displayed into your AMF client)
  146. // TODO: add some exception handling
  147. }
  148. }
  149. class Moodle_Amf_Server extends Zend_Amf_Server{
  150. /**
  151. * Raise a server fault
  152. *
  153. * @param string|Exception $fault
  154. * @return void
  155. */
  156. public function fault($fault = null, $code = 404)
  157. {
  158. if (!$fault instanceof Exception) {
  159. $fault = new Exception($fault);
  160. }
  161. $request = $this->getRequest();
  162. // Get the object encoding of the request.
  163. $objectEncoding = $request->getObjectEncoding();
  164. // create a response object to place the output from the services.
  165. $response = $this->getResponse();
  166. // set reponse encoding
  167. $response->setObjectEncoding($objectEncoding);
  168. $responseBody = $request->getAmfBodies();
  169. foreach($responseBody as $body){
  170. $return = $this->_errorMessage($objectEncoding, $fault->getMessage(),
  171. $fault->getMessage(), $fault->getTraceAsString(),$fault->getCode(), $fault->getLine());
  172. $responseType = Zend_AMF_Constants::STATUS_METHOD;
  173. $responseURI = $body->getResponseURI() . $responseType;
  174. $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return);
  175. $response->addAmfBody($newBody);
  176. }
  177. $response->finalize();
  178. echo $response;
  179. }
  180. }
  181. // TODO: implement AMF test client somehow, maybe we could use moodle form to feed the data to the flash app somehow