See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
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 * SOAP web service implementation classes and methods. 20 * 21 * @package webservice_soap 22 * @copyright 2009 Petr Skodak 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 global $CFG; 26 require_once($CFG->dirroot . '/webservice/lib.php'); 27 use webservice_soap\wsdl; 28 29 /** 30 * SOAP service server implementation. 31 * 32 * @package webservice_soap 33 * @copyright 2009 Petr Skodak 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 * @since Moodle 2.0 36 */ 37 class webservice_soap_server extends webservice_base_server { 38 39 /** @var moodle_url The server URL. */ 40 protected $serverurl; 41 42 /** @var SoapServer The Soap */ 43 protected $soapserver; 44 45 /** @var string The response. */ 46 protected $response; 47 48 /** @var string The class name of the virtual class generated for this web service. */ 49 protected $serviceclass; 50 51 /** @var bool WSDL mode flag. */ 52 protected $wsdlmode; 53 54 /** @var \webservice_soap\wsdl The object for WSDL generation. */ 55 protected $wsdl; 56 57 /** 58 * Contructor. 59 * 60 * @param string $authmethod authentication method of the web service (WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, ...) 61 */ 62 public function __construct($authmethod) { 63 parent::__construct($authmethod); 64 // Must not cache wsdl - the list of functions is created on the fly. 65 ini_set('soap.wsdl_cache_enabled', '0'); 66 $this->wsname = 'soap'; 67 $this->wsdlmode = false; 68 } 69 70 /** 71 * This method parses the $_POST and $_GET superglobals and looks for the following information: 72 * - User authentication parameters: 73 * - Username + password (wsusername and wspassword), or 74 * - Token (wstoken) 75 */ 76 protected function parse_request() { 77 // Retrieve and clean the POST/GET parameters from the parameters specific to the server. 78 parent::set_web_service_call_settings(); 79 80 if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) { 81 $this->username = optional_param('wsusername', null, PARAM_RAW); 82 $this->password = optional_param('wspassword', null, PARAM_RAW); 83 84 if (!$this->username or !$this->password) { 85 // Workaround for the trouble with & in soap urls. 86 $authdata = get_file_argument(); 87 $authdata = explode('/', trim($authdata, '/')); 88 if (count($authdata) == 2) { 89 list($this->username, $this->password) = $authdata; 90 } 91 } 92 $this->serverurl = new moodle_url('/webservice/soap/simpleserver.php/' . $this->username . '/' . $this->password); 93 } else { 94 $this->token = optional_param('wstoken', null, PARAM_RAW); 95 96 $this->serverurl = new moodle_url('/webservice/soap/server.php'); 97 $this->serverurl->param('wstoken', $this->token); 98 } 99 100 if ($wsdl = optional_param('wsdl', 0, PARAM_INT)) { 101 $this->wsdlmode = true; 102 } 103 } 104 105 /** 106 * Runs the SOAP web service. 107 * 108 * @throws coding_exception 109 * @throws moodle_exception 110 * @throws webservice_access_exception 111 */ 112 public function run() { 113 // We will probably need a lot of memory in some functions. 114 raise_memory_limit(MEMORY_EXTRA); 115 116 // Set some longer timeout since operations may need longer time to finish. 117 external_api::set_timeout(); 118 119 // Set up exception handler. 120 set_exception_handler(array($this, 'exception_handler')); 121 122 // Init all properties from the request data. 123 $this->parse_request(); 124 125 // Authenticate user, this has to be done after the request parsing. This also sets up $USER and $SESSION. 126 $this->authenticate_user(); 127 128 // Make a list of all functions user is allowed to execute. 129 $this->init_service_class(); 130 131 if ($this->wsdlmode) { 132 // Generate the WSDL. 133 $this->generate_wsdl(); 134 } 135 136 // Log the web service request. 137 $params = array( 138 'other' => array( 139 'function' => 'unknown' 140 ) 141 ); 142 $event = \core\event\webservice_function_called::create($params); 143 $logdataparams = array(SITEID, 'webservice_soap', '', '', $this->serviceclass . ' ' . getremoteaddr(), 0, $this->userid); 144 $event->set_legacy_logdata($logdataparams); 145 $event->trigger(); 146 147 // Handle the SOAP request. 148 $this->handle(); 149 150 // Session cleanup. 151 $this->session_cleanup(); 152 die; 153 } 154 155 /** 156 * Generates the WSDL. 157 */ 158 protected function generate_wsdl() { 159 // Initialise WSDL. 160 $this->wsdl = new wsdl($this->serviceclass, $this->serverurl); 161 // Register service struct classes as complex types. 162 foreach ($this->servicestructs as $structinfo) { 163 $this->wsdl->add_complex_type($structinfo->classname, $structinfo->properties); 164 } 165 // Register the method for the WSDL generation. 166 foreach ($this->servicemethods as $methodinfo) { 167 $this->wsdl->register($methodinfo->name, $methodinfo->inputparams, $methodinfo->outputparams, $methodinfo->description); 168 } 169 } 170 171 /** 172 * Handles the web service function call. 173 */ 174 protected function handle() { 175 if ($this->wsdlmode) { 176 // Prepare the response. 177 $this->response = $this->wsdl->to_xml(); 178 179 // Send the results back in correct format. 180 $this->send_response(); 181 } else { 182 $wsdlurl = clone($this->serverurl); 183 $wsdlurl->param('wsdl', 1); 184 185 $options = array( 186 'uri' => $this->serverurl->out(false) 187 ); 188 // Initialise the SOAP server. 189 $this->soapserver = new SoapServer($wsdlurl->out(false), $options); 190 if (!empty($this->serviceclass)) { 191 $this->soapserver->setClass($this->serviceclass); 192 // Get all the methods for the generated service class then register to the SOAP server. 193 $functions = get_class_methods($this->serviceclass); 194 $this->soapserver->addFunction($functions); 195 } 196 197 // Get soap request from raw POST data. 198 $soaprequest = file_get_contents('php://input'); 199 // Handle the request. 200 try { 201 $this->soapserver->handle($soaprequest); 202 } catch (Exception $e) { 203 $this->fault($e); 204 } 205 } 206 } 207 208 /** 209 * Send the error information to the WS client formatted as an XML document. 210 * 211 * @param Exception $ex the exception to send back 212 */ 213 protected function send_error($ex = null) { 214 if ($ex) { 215 $info = $ex->getMessage(); 216 if (debugging() and isset($ex->debuginfo)) { 217 $info .= ' - '.$ex->debuginfo; 218 } 219 } else { 220 $info = 'Unknown error'; 221 } 222 223 // Initialise new DOM document object. 224 $dom = new DOMDocument('1.0', 'UTF-8'); 225 226 // Fault node. 227 $fault = $dom->createElement('SOAP-ENV:Fault'); 228 // Faultcode node. 229 $fault->appendChild($dom->createElement('faultcode', 'MOODLE:error')); 230 // Faultstring node. 231 $fault->appendChild($dom->createElement('faultstring', $info)); 232 233 // Body node. 234 $body = $dom->createElement('SOAP-ENV:Body'); 235 $body->appendChild($fault); 236 237 // Envelope node. 238 $envelope = $dom->createElement('SOAP-ENV:Envelope'); 239 $envelope->setAttribute('xmlns:SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/'); 240 $envelope->appendChild($body); 241 $dom->appendChild($envelope); 242 243 $this->response = $dom->saveXML(); 244 $this->send_response(); 245 } 246 247 /** 248 * Send the result of function call to the WS client. 249 */ 250 protected function send_response() { 251 $this->send_headers(); 252 echo $this->response; 253 } 254 255 /** 256 * Internal implementation - sending of page headers. 257 */ 258 protected function send_headers() { 259 header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0'); 260 header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); 261 header('Pragma: no-cache'); 262 header('Accept-Ranges: none'); 263 header('Content-Length: ' . strlen($this->response)); 264 header('Content-Type: application/xml; charset=utf-8'); 265 header('Content-Disposition: inline; filename="response.xml"'); 266 } 267 268 /** 269 * Generate a server fault. 270 * 271 * Note that the parameter order is the reverse of SoapFault's constructor parameters. 272 * 273 * Moodle note: basically we return the faultactor (errorcode) and faultdetails (debuginfo). 274 * 275 * If an exception is passed as the first argument, its message and code 276 * will be used to create the fault object. 277 * 278 * @link http://www.w3.org/TR/soap12-part1/#faultcodes 279 * @param string|Exception $fault 280 * @param string $code SOAP Fault Codes 281 */ 282 public function fault($fault = null, $code = 'Receiver') { 283 $allowedfaultmodes = array( 284 'VersionMismatch', 'MustUnderstand', 'DataEncodingUnknown', 285 'Sender', 'Receiver', 'Server' 286 ); 287 if (!in_array($code, $allowedfaultmodes)) { 288 $code = 'Receiver'; 289 } 290 291 // Intercept any exceptions and add the errorcode and debuginfo (optional). 292 $actor = null; 293 $details = null; 294 $errorcode = 'unknownerror'; 295 $message = get_string($errorcode); 296 if ($fault instanceof Exception) { 297 // Add the debuginfo to the exception message if debuginfo must be returned. 298 $actor = isset($fault->errorcode) ? $fault->errorcode : null; 299 $errorcode = $actor; 300 if (debugging()) { 301 $message = $fault->getMessage(); 302 $details = isset($fault->debuginfo) ? $fault->debuginfo : null; 303 } 304 } else if (is_string($fault)) { 305 $message = $fault; 306 } 307 308 $this->soapserver->fault($code, $message . ' | ERRORCODE: ' . $errorcode, $actor, $details); 309 } 310 } 311 312 /** 313 * SOAP test client class 314 * 315 * @package webservice_soap 316 * @copyright 2009 Petr Skodak 317 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 318 * @since Moodle 2.0 319 */ 320 class webservice_soap_test_client implements webservice_test_client_interface { 321 322 /** 323 * Execute test client WS request 324 * 325 * @param string $serverurl server url (including token parameter or username/password parameters) 326 * @param string $function function name 327 * @param array $params parameters of the called function 328 * @return mixed 329 */ 330 public function simpletest($serverurl, $function, $params) { 331 global $CFG; 332 333 require_once($CFG->dirroot . '/webservice/soap/lib.php'); 334 $client = new webservice_soap_client($serverurl); 335 return $client->call($function, $params); 336 } 337 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body