MDL-76862 user: ensure user can only update own preferred start page.
[moodle.git] / webservice / soap / locallib.php
blobebfa5ca046ce06e1bb7b864ea6cd190899915a6d
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.
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/>.
18 /**
19 * SOAP web service implementation classes and methods.
21 * @package webservice_soap
22 * @copyright 2009 Petr Skodak
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 global $CFG;
26 require_once($CFG->dirroot . '/webservice/lib.php');
27 use webservice_soap\wsdl;
29 /**
30 * SOAP service server implementation.
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
37 class webservice_soap_server extends webservice_base_server {
39 /** @var moodle_url The server URL. */
40 protected $serverurl;
42 /** @var SoapServer The Soap */
43 protected $soapserver;
45 /** @var string The response. */
46 protected $response;
48 /** @var string The class name of the virtual class generated for this web service. */
49 protected $serviceclass;
51 /** @var bool WSDL mode flag. */
52 protected $wsdlmode;
54 /** @var \webservice_soap\wsdl The object for WSDL generation. */
55 protected $wsdl;
57 /**
58 * Contructor.
60 * @param string $authmethod authentication method of the web service (WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, ...)
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;
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)
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();
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);
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;
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);
96 $this->serverurl = new moodle_url('/webservice/soap/server.php');
97 $this->serverurl->param('wstoken', $this->token);
100 if ($wsdl = optional_param('wsdl', 0, PARAM_INT)) {
101 $this->wsdlmode = true;
106 * Runs the SOAP web service.
108 * @throws coding_exception
109 * @throws moodle_exception
110 * @throws webservice_access_exception
112 public function run() {
113 // We will probably need a lot of memory in some functions.
114 raise_memory_limit(MEMORY_EXTRA);
116 // Set some longer timeout since operations may need longer time to finish.
117 external_api::set_timeout();
119 // Set up exception handler.
120 set_exception_handler(array($this, 'exception_handler'));
122 // Init all properties from the request data.
123 $this->parse_request();
125 // Authenticate user, this has to be done after the request parsing. This also sets up $USER and $SESSION.
126 $this->authenticate_user();
128 // Make a list of all functions user is allowed to execute.
129 $this->init_service_class();
131 if ($this->wsdlmode) {
132 // Generate the WSDL.
133 $this->generate_wsdl();
136 // Log the web service request.
137 $params = array(
138 'other' => array(
139 'function' => 'unknown'
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();
147 // Handle the SOAP request.
148 $this->handle();
150 // Session cleanup.
151 $this->session_cleanup();
152 die;
156 * Generates the WSDL.
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);
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);
172 * Handles the web service function call.
174 protected function handle() {
175 if ($this->wsdlmode) {
176 // Prepare the response.
177 $this->response = $this->wsdl->to_xml();
179 // Send the results back in correct format.
180 $this->send_response();
181 } else {
182 $wsdlurl = clone($this->serverurl);
183 $wsdlurl->param('wsdl', 1);
185 $options = array(
186 'uri' => $this->serverurl->out(false)
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);
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);
209 * Send the error information to the WS client formatted as an XML document.
211 * @param Exception $ex the exception to send back
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;
219 } else {
220 $info = 'Unknown error';
223 // Initialise new DOM document object.
224 $dom = new DOMDocument('1.0', 'UTF-8');
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));
233 // Body node.
234 $body = $dom->createElement('SOAP-ENV:Body');
235 $body->appendChild($fault);
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);
243 $this->response = $dom->saveXML();
244 $this->send_response();
248 * Send the result of function call to the WS client.
250 protected function send_response() {
251 $this->send_headers();
252 echo $this->response;
256 * Internal implementation - sending of page headers.
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"');
269 * Generate a server fault.
271 * Note that the parameter order is the reverse of SoapFault's constructor parameters.
273 * Moodle note: basically we return the faultactor (errorcode) and faultdetails (debuginfo).
275 * If an exception is passed as the first argument, its message and code
276 * will be used to create the fault object.
278 * @link http://www.w3.org/TR/soap12-part1/#faultcodes
279 * @param string|Exception $fault
280 * @param string $code SOAP Fault Codes
282 public function fault($fault = null, $code = 'Receiver') {
283 $allowedfaultmodes = array(
284 'VersionMismatch', 'MustUnderstand', 'DataEncodingUnknown',
285 'Sender', 'Receiver', 'Server'
287 if (!in_array($code, $allowedfaultmodes)) {
288 $code = 'Receiver';
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;
304 } else if (is_string($fault)) {
305 $message = $fault;
308 $this->soapserver->fault($code, $message . ' | ERRORCODE: ' . $errorcode, $actor, $details);
313 * SOAP test client class
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
320 class webservice_soap_test_client implements webservice_test_client_interface {
323 * Execute test client WS request
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
330 public function simpletest($serverurl, $function, $params) {
331 global $CFG;
333 require_once($CFG->dirroot . '/webservice/soap/lib.php');
334 $client = new webservice_soap_client($serverurl);
335 return $client->call($function, $params);