Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 18 /** 19 * REST web service implementation classes and methods. 20 * 21 * @package webservice_rest 22 * @copyright 2009 Jerome Mouneyrac 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 use core_external\external_multiple_structure; 27 use core_external\external_single_structure; 28 use core_external\external_value; 29 30 require_once("$CFG->dirroot/webservice/lib.php"); 31 32 /** 33 * REST service server implementation. 34 * 35 * @package webservice_rest 36 * @copyright 2009 Petr Skoda (skodak) 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class webservice_rest_server extends webservice_base_server { 40 41 /** @var string return method ('xml' or 'json') */ 42 protected $restformat; 43 44 /** 45 * Contructor 46 * 47 * @param string $authmethod authentication method of the web service (WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, ...) 48 * @param string $restformat Format of the return values: 'xml' or 'json' 49 */ 50 public function __construct($authmethod) { 51 parent::__construct($authmethod); 52 $this->wsname = 'rest'; 53 } 54 55 /** 56 * Set the request format to. 57 */ 58 public function set_rest_format(): void { 59 // Get GET and POST parameters. 60 $methodvariables = array_merge($_GET, $_POST); 61 62 // Retrieve REST format parameter - 'xml' (default) or 'json'. 63 $restformatisset = isset($methodvariables['moodlewsrestformat']) 64 && (($methodvariables['moodlewsrestformat'] == 'xml' || $methodvariables['moodlewsrestformat'] == 'json')); 65 $this->restformat = $restformatisset ? $methodvariables['moodlewsrestformat'] : 'xml'; 66 } 67 68 /** 69 * This method parses the $_POST and $_GET superglobals and looks for 70 * the following information: 71 * 1/ user authentication - username+password or token (wsusername, wspassword and wstoken parameters) 72 * 2/ function name (wsfunction parameter) 73 * 3/ function parameters (all other parameters except those above) 74 * 4/ text format parameters 75 * 5/ return rest format xml/json 76 */ 77 protected function parse_request() { 78 79 // Retrieve and clean the POST/GET parameters from the parameters specific to the server. 80 parent::set_web_service_call_settings(); 81 82 // Get GET and POST parameters. 83 $methodvariables = array_merge($_GET, $_POST); 84 $this->set_rest_format(); 85 unset($methodvariables['moodlewsrestformat']); 86 87 if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) { 88 $this->username = isset($methodvariables['wsusername']) ? $methodvariables['wsusername'] : null; 89 unset($methodvariables['wsusername']); 90 91 $this->password = isset($methodvariables['wspassword']) ? $methodvariables['wspassword'] : null; 92 unset($methodvariables['wspassword']); 93 94 $this->functionname = isset($methodvariables['wsfunction']) ? $methodvariables['wsfunction'] : null; 95 unset($methodvariables['wsfunction']); 96 97 $this->parameters = $methodvariables; 98 99 } else { 100 $this->token = isset($methodvariables['wstoken']) ? $methodvariables['wstoken'] : null; 101 unset($methodvariables['wstoken']); 102 103 $this->functionname = isset($methodvariables['wsfunction']) ? $methodvariables['wsfunction'] : null; 104 unset($methodvariables['wsfunction']); 105 106 $this->parameters = $methodvariables; 107 } 108 } 109 110 /** 111 * Send the result of function call to the WS client 112 * formatted as XML document. 113 */ 114 protected function send_response() { 115 116 //Check that the returned values are valid 117 try { 118 if ($this->function->returns_desc != null) { 119 $validatedvalues = \core_external\external_api::clean_returnvalue( 120 $this->function->returns_desc, 121 $this->returns 122 ); 123 } else { 124 $validatedvalues = null; 125 } 126 } catch (Exception $ex) { 127 $exception = $ex; 128 } 129 130 if (!empty($exception)) { 131 $response = $this->generate_error($exception); 132 } else { 133 //We can now convert the response to the requested REST format 134 if ($this->restformat == 'json') { 135 $response = json_encode($validatedvalues); 136 } else { 137 $response = '<?xml version="1.0" encoding="UTF-8" ?>'."\n"; 138 $response .= '<RESPONSE>'."\n"; 139 $response .= self::xmlize_result($validatedvalues, $this->function->returns_desc); 140 $response .= '</RESPONSE>'."\n"; 141 } 142 } 143 144 $this->send_headers(); 145 echo $response; 146 } 147 148 /** 149 * Send the error information to the WS client 150 * formatted as XML document. 151 * Note: the exception is never passed as null, 152 * it only matches the abstract function declaration. 153 * @param exception $ex the exception that we are sending 154 */ 155 protected function send_error($ex=null) { 156 // Unless debugging is completely off, log the error to server error log. 157 if (debugging('', DEBUG_MINIMAL)) { 158 $info = get_exception_info($ex); 159 // This format is the same as default_exception_handler() in setuplib.php but with the 160 // word 'REST' instead of 'Default', to make it easy to reuse any existing processing. 161 error_log('REST exception handler: ' . $info->message . ' Debug: ' . 162 $info->debuginfo . "\n" . format_backtrace($info->backtrace, true)); 163 } 164 165 $this->send_headers(); 166 echo $this->generate_error($ex); 167 } 168 169 /** 170 * Build the error information matching the REST returned value format (JSON or XML) 171 * @param exception $ex the exception we are converting in the server rest format 172 * @return string the error in the requested REST format 173 */ 174 protected function generate_error($ex) { 175 if ($this->restformat == 'json') { 176 $errorobject = new stdClass; 177 $errorobject->exception = get_class($ex); 178 if (isset($ex->errorcode)) { 179 $errorobject->errorcode = $ex->errorcode; 180 } 181 $errorobject->message = $ex->getMessage(); 182 if (debugging() and isset($ex->debuginfo)) { 183 $errorobject->debuginfo = $ex->debuginfo; 184 } 185 $error = json_encode($errorobject); 186 } else { 187 $error = '<?xml version="1.0" encoding="UTF-8" ?>'."\n"; 188 $error .= '<EXCEPTION class="'.get_class($ex).'">'."\n"; 189 if (isset($ex->errorcode)) { 190 $error .= '<ERRORCODE>' . htmlspecialchars($ex->errorcode, ENT_COMPAT, 'UTF-8') 191 . '</ERRORCODE>' . "\n"; 192 } 193 $error .= '<MESSAGE>'.htmlspecialchars($ex->getMessage(), ENT_COMPAT, 'UTF-8').'</MESSAGE>'."\n"; 194 if (debugging() and isset($ex->debuginfo)) { 195 $error .= '<DEBUGINFO>'.htmlspecialchars($ex->debuginfo, ENT_COMPAT, 'UTF-8').'</DEBUGINFO>'."\n"; 196 } 197 $error .= '</EXCEPTION>'."\n"; 198 } 199 return $error; 200 } 201 202 /** 203 * Internal implementation - sending of page headers. 204 */ 205 protected function send_headers() { 206 if ($this->restformat == 'json') { 207 header('Content-type: application/json'); 208 } else { 209 header('Content-Type: application/xml; charset=utf-8'); 210 header('Content-Disposition: inline; filename="response.xml"'); 211 } 212 header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); 213 header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT'); 214 header('Pragma: no-cache'); 215 header('Accept-Ranges: none'); 216 // Allow cross-origin requests only for Web Services. 217 // This allow to receive requests done by Web Workers or webapps in different domains. 218 header('Access-Control-Allow-Origin: *'); 219 } 220 221 /** 222 * Internal implementation - recursive function producing XML markup. 223 * 224 * @param mixed $returns the returned values 225 * @param external_description $desc 226 * @return string 227 */ 228 protected static function xmlize_result($returns, $desc) { 229 if ($desc === null) { 230 return ''; 231 232 } else if ($desc instanceof external_value) { 233 if (is_bool($returns)) { 234 // we want 1/0 instead of true/false here 235 $returns = (int)$returns; 236 } 237 if (is_null($returns)) { 238 return '<VALUE null="null"/>'."\n"; 239 } else { 240 return '<VALUE>'.htmlspecialchars($returns, ENT_COMPAT, 'UTF-8').'</VALUE>'."\n"; 241 } 242 243 } else if ($desc instanceof external_multiple_structure) { 244 $mult = '<MULTIPLE>'."\n"; 245 if (!empty($returns)) { 246 foreach ($returns as $val) { 247 $mult .= self::xmlize_result($val, $desc->content); 248 } 249 } 250 $mult .= '</MULTIPLE>'."\n"; 251 return $mult; 252 253 } else if ($desc instanceof external_single_structure) { 254 $single = '<SINGLE>'."\n"; 255 foreach ($desc->keys as $key=>$subdesc) { 256 $value = isset($returns[$key]) ? $returns[$key] : null; 257 $single .= '<KEY name="'.$key.'">'.self::xmlize_result($value, $subdesc).'</KEY>'."\n"; 258 } 259 $single .= '</SINGLE>'."\n"; 260 return $single; 261 } 262 } 263 } 264 265 266 /** 267 * REST test client class 268 * 269 * @package webservice_rest 270 * @copyright 2009 Petr Skoda (skodak) 271 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 272 */ 273 class webservice_rest_test_client implements webservice_test_client_interface { 274 /** 275 * Execute test client WS request 276 * @param string $serverurl server url (including token parameter or username/password parameters) 277 * @param string $function function name 278 * @param array $params parameters of the called function 279 * @return mixed 280 */ 281 public function simpletest($serverurl, $function, $params) { 282 return download_file_content($serverurl.'&wsfunction='.$function, null, $params); 283 } 284 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body