forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
locallib.php
230 lines (204 loc) · 8.24 KB
/
locallib.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* XML-RPC web service implementation classes and methods.
*
* @package webservice_xmlrpc
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once("$CFG->dirroot/webservice/lib.php");
/**
* XML-RPC service server implementation.
*
* @package webservice_xmlrpc
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 2.0
*/
class webservice_xmlrpc_server extends webservice_base_server {
/** @var string $response The XML-RPC response string. */
private $response;
/**
* Contructor
*
* @param string $authmethod authentication method of the web service (WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, ...)
*/
public function __construct($authmethod) {
parent::__construct($authmethod);
$this->wsname = 'xmlrpc';
}
/**
* This method parses the request input, it needs to get:
* 1/ user authentication - username+password or token
* 2/ function name
* 3/ function parameters
*/
protected function parse_request() {
// Retrieve and clean the POST/GET parameters from the parameters specific to the server.
parent::set_web_service_call_settings();
if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) {
$this->username = isset($_GET['wsusername']) ? $_GET['wsusername'] : null;
$this->password = isset($_GET['wspassword']) ? $_GET['wspassword'] : null;
} else {
$this->token = isset($_GET['wstoken']) ? $_GET['wstoken'] : null;
}
// Get the XML-RPC request data.
$rawpostdata = $this->fetch_input_content();
$methodname = null;
// Decode the request to get the decoded parameters and the name of the method to be called.
$decodedparams = xmlrpc_decode_request($rawpostdata, $methodname, 'UTF-8');
$methodinfo = external_api::external_function_info($methodname);
$methodparams = array_keys($methodinfo->parameters_desc->keys);
$methodvariables = [];
// Add the decoded parameters to the methodvariables array.
if (is_array($decodedparams)) {
foreach ($decodedparams as $index => $param) {
// See MDL-53962 - XML-RPC requests will usually be sent as an array (as in, one with indicies).
// We need to use a bit of "magic" to add the correct index back. Zend used to do this for us.
$methodvariables[$methodparams[$index]] = $param;
}
}
$this->functionname = $methodname;
$this->parameters = $methodvariables;
}
/**
* Fetch content from the client.
*
* @return string
*/
protected function fetch_input_content() {
return file_get_contents('php://input');
}
/**
* Prepares the response.
*/
protected function prepare_response() {
try {
if (!empty($this->function->returns_desc)) {
$validatedvalues = external_api::clean_returnvalue($this->function->returns_desc, $this->returns);
$encodingoptions = array(
"encoding" => "UTF-8",
"verbosity" => "no_white_space",
// See MDL-54868.
"escaping" => ["markup"]
);
// We can now convert the response to the requested XML-RPC format.
$this->response = xmlrpc_encode_request(null, $validatedvalues, $encodingoptions);
}
} catch (invalid_response_exception $ex) {
$this->response = $this->generate_error($ex);
}
}
/**
* Send the result of function call to the WS client.
*/
protected function send_response() {
$this->prepare_response();
$this->send_headers();
echo $this->response;
}
/**
* Send the error information to the WS client.
*
* @param Exception $ex
*/
protected function send_error($ex = null) {
$this->response = $this->generate_error($ex);
$this->send_headers();
echo $this->response;
}
/**
* Sends the headers for the XML-RPC response.
*/
protected function send_headers() {
// Standard headers.
header('HTTP/1.1 200 OK');
header('Connection: close');
header('Content-Length: ' . strlen($this->response));
header('Content-Type: text/xml; charset=utf-8');
header('Date: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT');
header('Server: Moodle XML-RPC Server/1.0');
// Other headers.
header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
header('Pragma: no-cache');
header('Accept-Ranges: none');
// Allow cross-origin requests only for Web Services.
// This allow to receive requests done by Web Workers or webapps in different domains.
header('Access-Control-Allow-Origin: *');
}
/**
* Generate the XML-RPC fault response.
*
* @param Exception|Throwable $ex The exception.
* @param int $faultcode The faultCode to be included in the fault response
* @return string The XML-RPC fault response xml containing the faultCode and faultString.
*/
protected function generate_error($ex, $faultcode = 404) {
$error = $ex->getMessage();
if (!empty($ex->errorcode)) {
// The faultCode must be an int, so we obtain a hash of the errorcode then get an integer value of the hash.
$faultcode = base_convert(md5($ex->errorcode), 16, 10);
// We strip the $code to 8 digits (and hope for no error code collisions).
// Collisions should be pretty rare, and if needed the client can retrieve
// the accurate errorcode from the last | in the exception message.
$faultcode = substr($faultcode, 0, 8);
// Add the debuginfo to the exception message if debuginfo must be returned.
if (debugging() and isset($ex->debuginfo)) {
$error .= ' | DEBUG INFO: ' . $ex->debuginfo . ' | ERRORCODE: ' . $ex->errorcode;
} else {
$error .= ' | ERRORCODE: ' . $ex->errorcode;
}
}
$fault = array(
'faultCode' => (int) $faultcode,
'faultString' => $error
);
$encodingoptions = array(
"encoding" => "UTF-8",
"verbosity" => "no_white_space",
// See MDL-54868.
"escaping" => ["markup"]
);
return xmlrpc_encode_request(null, $fault, $encodingoptions);
}
}
/**
* XML-RPC test client class
*
* @package webservice_xmlrpc
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 2.0
*/
class webservice_xmlrpc_test_client implements webservice_test_client_interface {
/**
* Execute test client WS request
* @param string $serverurl server url (including token parameter or username/password parameters)
* @param string $function function name
* @param array $params parameters of the called function
* @return mixed
*/
public function simpletest($serverurl, $function, $params) {
global $CFG;
$url = new moodle_url($serverurl);
$token = $url->get_param('wstoken');
require_once($CFG->dirroot . '/webservice/xmlrpc/lib.php');
$client = new webservice_xmlrpc_client($serverurl, $token);
return $client->call($function, $params);
}
}