MDL-76052 webservice_xmlrpc: Remove it completely from core

Normal removal procedure:
  - Remove the plugin completely from core.
  - Document it in the webservices upgrade.txt file.
  - Add a core upgrade step to proceed to remove any configuration
    if the plugin has not been re-installed manually.

Plus:
  - Remove a few remaining uses in the hub/sites registration scripts,
    that were moved from xmlrpc to hand.made rest calls by MDL-31436
    (Moodle 3.4.1 and up) and never removed then.
  - Remove the php-xmlrpc extension as a recommendation in composer.
  - Remove "xmlrpc" from various comments, trivial cleanup.

Note:
  - While working on this MDL-76078 has been created about to
    fix a serious design problem detected (it does not affect
    functionality). That's out from this issue scope.
This commit is contained in:
Eloy Lafuente (stronk7) 2022-10-21 19:30:07 +02:00
parent fee1b8ce5f
commit df227f3819
22 changed files with 38 additions and 1171 deletions

View file

@ -48,7 +48,6 @@
"ext-sqlsrv": "Needed when Moodle uses MS SQL Server database.", "ext-sqlsrv": "Needed when Moodle uses MS SQL Server database.",
"ext-oci8": "Needed when Moodle uses Oracle database.", "ext-oci8": "Needed when Moodle uses Oracle database.",
"ext-tokenizer": "Enabling Tokenizer PHP extension is recommended, it improves Moodle Networking functionality.", "ext-tokenizer": "Enabling Tokenizer PHP extension is recommended, it improves Moodle Networking functionality.",
"ext-xmlrpc": "Enabling XMLRPC PHP extension is useful for web services and Moodle networking.",
"ext-soap": "Enabling SOAP PHP extension is useful for web services and some plugins.", "ext-soap": "Enabling SOAP PHP extension is useful for web services and some plugins.",
"ext-sodium": "Enabling Sodium PHP extension is recommended, it is used by Moodle encryption API.", "ext-sodium": "Enabling Sodium PHP extension is recommended, it is used by Moodle encryption API.",
"ext-exif": "Enabling Exif PHP extension is recommended, it is used by Moodle to parse image meta data." "ext-exif": "Enabling Exif PHP extension is recommended, it is used by Moodle to parse image meta data."

View file

@ -25,7 +25,6 @@
namespace core\hub; namespace core\hub;
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
use webservice_xmlrpc_client;
use moodle_exception; use moodle_exception;
use curl; use curl;
use stdClass; use stdClass;
@ -370,4 +369,4 @@ class api {
public static function upload_course_backup($hubcourseid, \stored_file $backupfile) { public static function upload_course_backup($hubcourseid, \stored_file $backupfile) {
debugging("This function has been deprecated as part of the Moodle.net sunsetting process."); debugging("This function has been deprecated as part of the Moodle.net sunsetting process.");
} }
} }

View file

@ -1745,7 +1745,7 @@ class core_plugin_manager {
'binarius', 'boxxie', 'brick', 'canvas', 'formal_white', 'formfactor', 'fusion', 'leatherbound', 'binarius', 'boxxie', 'brick', 'canvas', 'formal_white', 'formfactor', 'fusion', 'leatherbound',
'magazine', 'mymobile', 'nimble', 'nonzero', 'overlay', 'serenity', 'sky_high', 'splash', 'magazine', 'mymobile', 'nimble', 'nonzero', 'overlay', 'serenity', 'sky_high', 'splash',
'standard', 'standardold'), 'standard', 'standardold'),
'webservice' => array('amf'), 'webservice' => array('amf', 'xmlrpc'),
); );
if (!isset($plugins[$type])) { if (!isset($plugins[$type])) {
@ -2047,7 +2047,7 @@ class core_plugin_manager {
), ),
'webservice' => array( 'webservice' => array(
'rest', 'soap', 'xmlrpc' 'rest', 'soap'
), ),
'workshopallocation' => array( 'workshopallocation' => array(

View file

@ -116,10 +116,6 @@ class webservice extends base {
} }
public function is_uninstall_allowed() { public function is_uninstall_allowed() {
// The xmlrpc plugin contains webservice_xmlrpc_client (used by core).
if ($this->name == 'xmlrpc') {
return false;
}
return true; return true;
} }
} }

View file

@ -3005,5 +3005,31 @@ privatefiles,moodle|/user/files.php';
upgrade_main_savepoint(true, 2022102800.01); upgrade_main_savepoint(true, 2022102800.01);
} }
if ($oldversion < 2022110600.00) {
// If webservice_xmlrpc isn't any longer installed, remove its configuration,
// capabilities and presence in other settings.
if (!file_exists($CFG->dirroot . '/webservice/xmlrpc/version.php')) {
// No DB structures to delete in this plugin.
// Remove capabilities.
capabilities_cleanup('webservice_xmlrpc');
// Remove own configuration.
unset_all_config_for_plugin('webservice_xmlrpc');
// Remove it from the enabled protocols if it was there.
$protos = get_config('core', 'webserviceprotocols');
$protoarr = explode(',', $protos);
$protoarr = array_filter($protoarr, function($ele) {
return trim($ele) !== 'xmlrpc';
});
$protos = implode(',', $protoarr);
set_config('webserviceprotocols', $protos);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2022110600.00);
}
return true; return true;
} }

View file

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$version = 2022110400.00; // YYYYMMDD = weekly release date of this DEV branch. $version = 2022110600.00; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches. // RR = release increments - 00 in DEV branches.
// .XX = incremental changes. // .XX = incremental changes.
$release = '4.1dev+ (Build: 20221104)'; // Human-friendly version name $release = '4.1dev+ (Build: 20221104)'; // Human-friendly version name

View file

@ -898,7 +898,7 @@ class webservice_access_exception extends moodle_exception {
/** /**
* Check if a protocol is enabled * Check if a protocol is enabled
* *
* @param string $protocol name of WS protocol ('rest', 'soap', 'xmlrpc'...) * @param string $protocol name of WS protocol ('rest', 'soap', ...)
* @return bool true if the protocol is enabled * @return bool true if the protocol is enabled
*/ */
function webservice_protocol_is_enabled($protocol) { function webservice_protocol_is_enabled($protocol) {

View file

@ -3,10 +3,15 @@ information provided here is intended especially for developers.
This information is intended for authors of webservices, not people writing webservice clients. This information is intended for authors of webservices, not people writing webservice clients.
=== 4.1 ===
* The XMLRPC webservice (protocol) has been completely removed. It's now available in the plugins directory.
=== 4.0 === === 4.0 ===
* User access related exceptions have been changed to use the moodle_exception class instead of the generic webservice_access_exception, * User access related exceptions have been changed to use the moodle_exception class instead of the
the main reason for this change is to allow clients to implement some code logic against an access error. generic webservice_access_exception, the main reason for this change is to allow clients to
implement some code logic against an access error.
=== 3.11 === === 3.11 ===

View file

@ -1,46 +0,0 @@
<?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/>.
/**
* Privacy provider implementation for webservice_xmlrpc.
*
* @package webservice_xmlrpc
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace webservice_xmlrpc\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for webservice_xmlrpc.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}

View file

@ -1,36 +0,0 @@
<?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 server related capabilities
*
* @package webservice_xmlrpc
* @category access
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$capabilities = array(
'webservice/xmlrpc:use' => array(
'captype' => 'read', // in fact this may be considered read and write at the same time
'contextlevel' => CONTEXT_COURSE, // the context level should be probably CONTEXT_MODULE
'archetypes' => array(
),
),
);

View file

@ -1,29 +0,0 @@
<?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/>.
/**
* Strings for component 'webservice_xmlrpc', language 'en', branch 'MOODLE_20_STABLE'
*
* @package webservice_xmlrpc
* @category string
* @copyright 2010 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'XML-RPC protocol';
$string['privacy:metadata'] = 'The XML-RPC protocol plugin does not store any personal data.';
$string['xmlrpc:use'] = 'Use XML-RPC protocol';

View file

@ -1,138 +0,0 @@
<?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/>.
/**
* Moodle XML-RPC library
*
* @package webservice_xmlrpc
* @copyright 2009 Jerome Mouneyrac
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Moodle XML-RPC client
*
* @package webservice_xmlrpc
* @copyright 2010 Jerome Mouneyrac
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class webservice_xmlrpc_client {
/** @var moodle_url The XML-RPC server url. */
protected $serverurl;
/** @var string The token for the XML-RPC call. */
protected $token;
/**
* Constructor
*
* @param string $serverurl a Moodle URL
* @param string $token the token used to do the web service call
*/
public function __construct($serverurl, $token) {
$this->serverurl = new moodle_url($serverurl);
$this->token = $token;
}
/**
* Set the token used to do the XML-RPC call
*
* @param string $token the token used to do the web service call
*/
public function set_token($token) {
$this->token = $token;
}
/**
* Execute client WS request with token authentication
*
* @param string $functionname the function name
* @param array $params An associative array containing the the parameters of the function being called.
* @return mixed The decoded XML RPC response.
* @throws moodle_exception
*/
public function call($functionname, $params = array()) {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
if ($this->token) {
$this->serverurl->param('wstoken', $this->token);
}
$request = $this->encode_request($functionname, $params);
// Set the headers.
$headers = array(
'Content-Length' => strlen($request),
'Content-Type' => 'text/xml; charset=utf-8',
'Host' => $this->serverurl->get_host(),
'User-Agent' => 'Moodle XML-RPC Client/1.0',
);
// Get the response.
$response = download_file_content($this->serverurl->out(false), $headers, $request);
// Decode the response.
$result = $this->decode_response($response);
if (is_array($result) && xmlrpc_is_fault($result)) {
throw new Exception($result['faultString'], $result['faultCode']);
}
return $result;
}
/**
* Generates XML for a method request.
*
* @param string $functionname Name of the method to call.
* @param mixed $params Method parameters compatible with the method signature.
* @return string
*/
protected function encode_request($functionname, $params) {
$outputoptions = array(
'encoding' => 'utf-8',
'escaping' => 'markup',
);
// See MDL-53962 - needed for backwards compatibility on <= 3.0.
$params = array_values($params);
return xmlrpc_encode_request($functionname, $params, $outputoptions);
}
/**
* Parses and decodes the response XML
*
* @param string $response
* @return array
*/
protected function decode_response($response) {
// XMLRPC server in Moodle encodes response using function xmlrpc_encode_request() with method==null
// see {@link webservice_xmlrpc_server::prepare_response()} . We should use xmlrpc_decode_request() for decoding too.
$method = null;
$encoding = null;
if (preg_match('/^<\?xml version="1.0" encoding="([^"]*)"\?>/', $response, $matches)) {
// Sometimes xmlrpc_decode_request() fails to recognise encoding, let's help it.
$encoding = $matches[1];
}
$r = xmlrpc_decode_request($response, $method, $encoding);
return $r;
}
}

View file

@ -1,230 +0,0 @@
<?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);
}
}

View file

@ -1,57 +0,0 @@
<?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 entry point. The authentication is done via tokens.
*
* @package webservice_xmlrpc
* @copyright 2009 Jerome Mouneyrac
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* NO_DEBUG_DISPLAY - disable moodle specific debug messages and any errors in output
*/
define('NO_DEBUG_DISPLAY', true);
define('WS_SERVER', true);
require('../../config.php');
require_once("$CFG->dirroot/webservice/xmlrpc/locallib.php");
if (!webservice_protocol_is_enabled('xmlrpc')) {
debugging('The server died because the web services or the XMLRPC protocol are not enable',
DEBUG_DEVELOPER);
die;
}
$server = new webservice_xmlrpc_server(WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN);
$server->run();
die;
/**
* Raises Early WS Exception in XMLRPC format.
*
* @param Exception $ex Raised exception.
*/
function raise_early_ws_exception(Exception $ex): void {
global $CFG;
require_once("$CFG->dirroot/webservice/xmlrpc/locallib.php");
$server = new webservice_xmlrpc_server(WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN);
$server->exception_handler($ex);
}

View file

@ -1,44 +0,0 @@
<?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 entry point. The authentication is done via username/password.
*
* @package webservice_xmlrpc
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* NO_DEBUG_DISPLAY - disable moodle specific debug messages and any errors in output
*/
define('NO_DEBUG_DISPLAY', true);
define('WS_SERVER', true);
require('../../config.php');
require_once("$CFG->dirroot/webservice/xmlrpc/locallib.php");
if (!webservice_protocol_is_enabled('xmlrpc')) {
die;
}
$server = new webservice_xmlrpc_server(WEBSERVICE_AUTHMETHOD_USERNAME);
$server->run();
die;

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<methodResponse>
<params>
<param>
<value>
<array>
<data>
<value>
<int>1</int>
</value>
<value>
<string>Test string</string>
</value>
<value>
<double>3.1416</double>
</value>
</data>
</array>
</value>
</param>
</params>
</methodResponse>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value>
<int>23604497</int>
</value>
</member>
<member>
<name>faultString</name>
<value>
<string>Can not find data record in database table external_functions. | DEBUG INFO: SELECT * FROM {external_functions} WHERE name = ?&#10;[array (&#10; 0 =&#62; 'core_course_get_course',&#10;)] | ERRORCODE: invalidrecord</string>
</value>
</member>
</struct>
</value>
</fault>
</methodResponse>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<methodResponse>
<params>
<param>
<value>
<int>1</int>
</value>
</param>
</params>
</methodResponse>

View file

@ -1,218 +0,0 @@
<?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/>.
/**
* Unit tests for the XML-RPC web service.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2015 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace webservice_xmlrpc;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/xmlrpc/lib.php');
/**
* Unit tests for the XML-RPC web service.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2015 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends \advanced_testcase {
/**
* Setup.
*/
public function setUp(): void {
$this->resetAfterTest();
// All tests require xmlrpc. Skip tests, if xmlrpc is not installed.
if (!function_exists('xmlrpc_decode')) {
$this->markTestSkipped('XMLRPC is not installed.');
}
}
/**
* Test for array response.
*/
public function test_client_with_array_response() {
global $CFG;
$client = new webservice_xmlrpc_client_mock('/webservice/xmlrpc/server.php', 'anytoken');
$mockresponse = file_get_contents($CFG->dirroot . '/webservice/xmlrpc/tests/fixtures/array_response.xml');
$client->set_mock_response($mockresponse);
$result = $client->call('testfunction');
$this->assertEquals(xmlrpc_decode($mockresponse), $result);
}
/**
* Test for value response.
*/
public function test_client_with_value_response() {
global $CFG;
$client = new webservice_xmlrpc_client_mock('/webservice/xmlrpc/server.php', 'anytoken');
$mockresponse = file_get_contents($CFG->dirroot . '/webservice/xmlrpc/tests/fixtures/value_response.xml');
$client->set_mock_response($mockresponse);
$result = $client->call('testfunction');
$this->assertEquals(xmlrpc_decode($mockresponse), $result);
}
/**
* Test for fault response.
*/
public function test_client_with_fault_response() {
global $CFG;
$client = new webservice_xmlrpc_client_mock('/webservice/xmlrpc/server.php', 'anytoken');
$mockresponse = file_get_contents($CFG->dirroot . '/webservice/xmlrpc/tests/fixtures/fault_response.xml');
$client->set_mock_response($mockresponse);
$this->expectException('\moodle_exception');
$client->call('testfunction');
}
/**
* Test the XML-RPC request encoding.
*/
public function test_encode_request() {
$client = new webservice_xmlrpc_client_mock('/webservice/xmlrpc/server.php', 'anytoken');
// Encode the request with the proper encoding and escaping options.
$xml = $client->encode_request('do_it', ['foo' => '<bar>ŠČŘŽÝÁÍÉ</bar>']);
// Assert that decoding with explicit encoding will work. This appeared
// to fail if the markup escaping was not set.
$this->assertEquals(['<bar>ŠČŘŽÝÁÍÉ</bar>'], xmlrpc_decode($xml, 'UTF-8'));
// Decoding also works with our wrapper method.
$this->assertEquals(['<bar>ŠČŘŽÝÁÍÉ</bar>'], $client->decode_response($xml));
// Our experiments show that even with default/implicit encoding,
// requests encoded with markup escaping set are also decoded
// correctly. This is known to be used in some servers so we test it
// here, too.
// However, this does not work for all strings, see next test.
$this->assertEquals(['<bar>ŠČŘŽÝÁÍÉ</bar>'], xmlrpc_decode($xml));
}
/**
* Test the XML-RPC response decoding
*/
public function test_decode_response() {
$client = new webservice_xmlrpc_client_mock('/webservice/xmlrpc/server.php', 'anytoken');
$teststring = '<bar>Recherche thématique:Villes & Développement durable</bar>';
// Encode the string with the proper encoding and escaping options. Assert that decoding will work.
$xml = $client->encode_request('do_it', [$teststring]);
$this->assertEquals([$teststring], $client->decode_response($xml));
// For this particular string bare decoding function does not work.
// It can't really be explained why it works for the string 'ŠČŘŽÝÁÍÉ' in the previous test but not this one.
// Symbol é comes as chr(233) . It looks like '<bar>Recherche th<74>matique:Villes & D<>veloppement durable</bar>'.
$this->assertEquals([preg_replace('/é/', chr(233), $teststring)], xmlrpc_decode($xml));
// Encode the string without any options (default encoding "iso-8859-1" is used). Assert that decoding will work.
$xml = xmlrpc_encode_request('do_it', [$teststring]);
$this->assertEquals([$teststring], $client->decode_response($xml));
$this->assertEquals([$teststring], xmlrpc_decode($xml));
// Another example of the string where bare xmlrpc_decode() does not work but our wrapper does.
$teststring = 'Formación Docente';
$xml = $client->encode_request('do_it', [$teststring]);
$this->assertEquals([$teststring], $client->decode_response($xml));
// Bare decoding function xmlrpc_decode() does not work.
// Symbol ó comes as chr(243), it looks like 'Formaci<63>n Docente'.
$this->assertEquals([preg_replace('/ó/', chr(243), $teststring)], xmlrpc_decode($xml));
}
}
/**
* Class webservice_xmlrpc_client_mock.
*
* Mock class that returns the processed XML-RPC response.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2015 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class webservice_xmlrpc_client_mock extends \webservice_xmlrpc_client {
/** @var string The mock XML-RPC response string. */
private $mockresponse;
/**
* XML-RPC mock response setter.
*
* @param string $mockresponse
*/
public function set_mock_response($mockresponse) {
$this->mockresponse = $mockresponse;
}
/**
* Since the call method uses download_file_content and it is hard to make an actual call to a web service,
* we'll just have to simulate the receipt of the response from the server using the mock response so we
* can test the processing result of this method.
*
* @param string $functionname the function name
* @param array $params the parameters of the function
* @return mixed The decoded XML RPC response.
* @throws \moodle_exception
*/
public function call($functionname, $params = array()) {
// Get the response.
$response = $this->mockresponse;
// This is the part of the code in webservice_xmlrpc_client::call() what we would like to test.
// Decode the response.
$result = xmlrpc_decode($response);
if (is_array($result) && xmlrpc_is_fault($result)) {
throw new \moodle_exception($result['faultString']);
}
return $result;
}
/**
* Allows to test the request encoding.
*
* @param string $functionname Name of the method to call.
* @param mixed $params Method parameters compatible with the method signature.
* @return string
*/
public function encode_request($functionname, $params) {
return parent::encode_request($functionname, $params);
}
/**
* Allows to test the response decoding.
*
* @param string $response
* @return array
*/
public function decode_response($response) {
return parent::decode_response($response);
}
}

View file

@ -1,163 +0,0 @@
<?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/>.
/**
* Unit tests for the XML-RPC web service server.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2016 Cameron Ball
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace webservice_xmlrpc;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/xmlrpc/locallib.php');
/**
* Unit tests for the XML-RPC web service server.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2016 Cameron Ball
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class locallib_test extends \advanced_testcase {
/**
* Setup.
*/
public function setUp(): void {
if (!function_exists('xmlrpc_decode')) {
$this->markTestSkipped('XMLRPC is not installed.');
}
}
/**
* Test that the response generated is correct
*
* There is a bug in PHP that causes the xml_rpc library to
* incorrectly escape multibyte characters. See https://bugs.php.net/bug.php?id=41650
*
* @dataProvider prepare_response_provider
* @param string $returnsdesc Webservice function return description
* @param string $returns Webservice function description
* @param string $expected The expected XML-RPC response
*/
public function test_prepare_response($returnsdesc, $returns, $expected) {
$server = $this->getMockBuilder('webservice_xmlrpc_server')
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
$rc = new \ReflectionClass('webservice_xmlrpc_server');
$rcm = $rc->getMethod('prepare_response');
$rcm->setAccessible(true);
$func = $rc->getProperty('function');
$func->setAccessible(true);
$func->setValue($server, (object) ['returns_desc' => new \external_value(PARAM_RAW, $returnsdesc, VALUE_OPTIONAL)]);
$ret = $rc->getProperty('returns');
$ret->setAccessible(true);
$ret->setValue($server, $returns);
$rcm->invokeArgs($server, []);
$response = $rc->getProperty('response');
$response->setAccessible(true);
$this->assertEquals($expected, $response->getValue($server));
}
/**
* Test that the response generated is correct
*
* There is a bug in PHP that causes the xml_rpc library to
* incorrectly escape multibyte characters. See https://bugs.php.net/bug.php?id=41650
*
* @dataProvider generate_error_provider
* @param Exception $exception An exception to be provided to generate_error
* @param string $code An error code to be provided to generate_error
* @param string $expected The expected XML-RPC response
*/
public function test_generate_error($exception, $code, $expected) {
$server = $this->getMockBuilder('webservice_xmlrpc_server')
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
$rc = new \ReflectionClass('webservice_xmlrpc_server');
$rcm = $rc->getMethod('generate_error');
$rcm->setAccessible(true);
if ($code === null) {
$result = $rcm->invokeArgs($server, [$exception]);
} else {
$result = $rcm->invokeArgs($server, [$exception, $code]);
}
$this->assertEquals($expected, $result);
}
/**
* Data provider for the prepare_response testcase
*
* @return array of testcases
*/
public function prepare_response_provider() {
return [
'Description written with Latin script' => [
'Ennyn Durin, Aran Moria: pedo mellon a minno',
'Mellon!',
'<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><string>Mellon!</string></value>'
. '</param></params></methodResponse>'
],
'Description with non-Latin glyphs' => [
'What biscuits do you have?',
// V Unicode 9! V.
'😂🤵😂 𝒪𝓃𝓁𝓎 𝓉𝒽𝑒 𝒻𝒾𝓃𝑒𝓈𝓉 𝐼𝓉𝒶𝓁𝒾𝒶𝓃 𝒷𝒾𝓈𝒸𝓊𝒾𝓉𝓈 😂🤵😂',
'<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><string>'
. '😂🤵😂 𝒪𝓃𝓁𝓎 𝓉𝒽𝑒 𝒻𝒾𝓃𝑒𝓈𝓉 𝐼𝓉𝒶𝓁𝒾𝒶𝓃 𝒷𝒾𝓈𝒸𝓊𝒾𝓉𝓈 😂🤵😂</string></value></param></params></methodResponse>'
]
];
}
/**
* Data provider for the generate_error testcase
*
* @return array of testcases
*/
public function generate_error_provider() {
return [
'Standard exception with default faultcode' => [
new \Exception(),
null,
'<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string/></value></member></struct></value></fault></methodResponse>'
],
'Standard exception with default faultcode and exception content' => [
new \Exception('PC LOAD LETTER'),
null,
'<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string>PC LOAD LETTER</string></value></member></struct></value></fault></methodResponse>'
],
'Standard exception with really messed up non-Latin glyphs' => [
new \Exception('P̫̬̳̫̓͊̇r̨͎̜ͧa͚̬̙̺͎̙ͬẏ͎̲̦̲e̶̞͎͙̻͐̉r͙̙ͮ̓̈ͧ̔̃ ̠ͨ́ͭ̎̎̇̿n̗̥̞͗o̼̖͛̂̒̿ͮ͘t̷̞͎̘̘̝̥̲͂̌ͭ ͕̹͚̪͖̖̊̆́̒ͫ̓̀fͤͦͭͥ͊ͩo̼̱̻̹͒̿͒u̡͕̞͕̜̠͕ͥͭ̈̄̈́͐ń̘̼̇͜d̸̰̻͎͉̱̰̥̿͒'),
null,
'<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string>P̫̬̳̫̓͊̇r̨͎̜ͧa͚̬̙̺͎̙ͬẏ͎̲̦̲e̶̞͎͙̻͐̉r͙̙ͮ̓̈ͧ̔̃ ̠ͨ́ͭ̎̎̇̿n̗̥̞͗o̼̖͛̂̒̿ͮ͘t̷̞͎̘̘̝̥̲͂̌ͭ ͕̹͚̪͖̖̊̆́̒ͫ̓̀fͤͦͭͥ͊ͩo̼̱̻̹͒̿͒u̡͕̞͕̜̠͕ͥͭ̈̄̈́͐ń̘̼̇͜d̸̰̻͎͉̱̰̥̿͒</string></value></member></struct></value></fault></methodResponse>'
]
];
}
}

View file

@ -1,114 +0,0 @@
<?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/>.
/**
* Unit tests for the XML-RPC web service server.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/xmlrpc/locallib.php');
/**
* Unit tests for the XML-RPC web service server.
*
* @package webservice_xmlrpc
* @category test
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class xmlrpc_server_test extends advanced_testcase {
/**
* Setup.
*/
public function setUp(): void {
if (!function_exists('xmlrpc_decode')) {
$this->markTestSkipped('XMLRPC is not installed.');
}
}
/**
* Test parameter parsing.
*
* @dataProvider parse_request_provider
* @param string $input The XML-RPC request
* @param string $expectfunction The expected value for the function after decoding the request
* @param array $expectparams The expected value for the params after decoding the request
*/
public function test_parse_request($input, $expectfunction, $expectparams) {
$server = $this->getMockBuilder('\webservice_xmlrpc_server')
->onlyMethods(['fetch_input_content'])
->disableOriginalConstructor()
->getMock();
$server->method('fetch_input_content')
->willReturn($input);
$rc = new \ReflectionClass('\webservice_xmlrpc_server');
$rcm = $rc->getMethod('parse_request');
$rcm->setAccessible(true);
$rcm->invoke($server);
$rcp = $rc->getProperty('functionname');
$rcp->setAccessible(true);
$this->assertEquals($expectfunction, $rcp->getValue($server));
$rcp = $rc->getProperty('parameters');
$rcp->setAccessible(true);
$this->assertEquals($expectparams, $rcp->getValue($server));
}
/**
* Data provider for testing parse_request.
*
* @return array
*/
public function parse_request_provider() {
$xml = '<?xml version="1.0" encoding="UTF-8"?>';
// This valid webservice call has one required param ('component'), and one optional param ('lang').
$validmethod = '<methodName>core_get_component_strings</methodName>';
$requiredparams = '<params><param><value><string>moodle</string></value></param></params>';
$allparams = '<params><param><value><string>moodle</string></value></param><param><value><string>en</string></value>'
. '</param></params>';
$requiredparamsnonlatin = '<params><param><value><string>ᛞᛞᛃᛟᚢᚾᛟᚹᛈᚺᛈᛋᚢᛈᛈᛟᚱᛏᛋᚢᛏᚠ8ᚡᚨᚱᚨᛒᛚᚾᚨᛗᛋ</string></value></param></params>';
return [
'Valid method, required params only' => [
"{$xml}<methodCall>{$validmethod}{$requiredparams}</methodCall>",
'core_get_component_strings',
['component' => 'moodle'],
],
'Valid method, all params' => [
"{$xml}<methodCall>{$validmethod}{$allparams}</methodCall>",
'core_get_component_strings',
['component' => 'moodle', 'lang' => 'en'],
],
'Valid method required params only (non Latin)' => [
"{$xml}<methodCall>{$validmethod}{$requiredparamsnonlatin}</methodCall>",
'core_get_component_strings',
['component' => 'ᛞᛞᛃᛟᚢᚾᛟᚹᛈᚺᛈᛋᚢᛈᛈᛟᚱᛏᛋᚢᛏᚠ8ᚡᚨᚱᚨᛒᛚᚾᚨᛗᛋ'],
],
];
}
}

View file

@ -1,30 +0,0 @@
<?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/>.
/**
* Version details
*
* @package webservice_xmlrpc
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2022041900; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2022041200; // Requires this Moodle version.
$plugin->component = 'webservice_xmlrpc'; // Full name of the plugin (used for diagnostics)