From b107e64716c7174a65b196f3b2687a46e2cabc23 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sat, 24 Oct 2009 20:59:59 +0000 Subject: [PATCH] MDL-12886 zend based Soap server class --- webservice/lib.php | 21 +- webservice/soap/db/access.php | 12 ++ webservice/soap/lib.php | 151 -------------- webservice/soap/locallib.php | 151 ++++++++++++++ webservice/soap/server.php | 54 +++-- webservice/soap/simpleserver.php | 47 +++++ .../soap/testclient/zend/zend_soap_client.php | 195 ------------------ webservice/soap/version.php | 3 + webservice/xmlrpc/locallib.php | 2 +- 9 files changed, 255 insertions(+), 381 deletions(-) create mode 100644 webservice/soap/db/access.php delete mode 100644 webservice/soap/lib.php create mode 100644 webservice/soap/locallib.php create mode 100644 webservice/soap/simpleserver.php delete mode 100644 webservice/soap/testclient/zend/zend_soap_client.php create mode 100644 webservice/soap/version.php diff --git a/webservice/lib.php b/webservice/lib.php index 2ad5ea3e03..3d236e7d6e 100644 --- a/webservice/lib.php +++ b/webservice/lib.php @@ -101,7 +101,7 @@ abstract class webservice_zend_server implements webservice_server { /** @property string $password password of the local user */ protected $password = null; - + /** @property bool $simple true if simple auth used */ protected $simple; @@ -158,8 +158,7 @@ abstract class webservice_zend_server implements webservice_server { $response = $this->zend_server->handle(); /* - $grrr = ob_get_clean(); - error_log($grrr); + error_log(ob_get_clean()); error_log($response); */ // session cleanup @@ -340,7 +339,7 @@ class '.$classname.' { } /** - * Set up zend serice class + * Set up zend service class * @return void */ protected function init_zend_server() { @@ -467,13 +466,23 @@ class '.$classname.' { $this->session_cleanup($ex); // now let the plugin send the exception to client - $this->send_headers(); - echo $this->zend_server->fault($ex); + $this->send_error($ex); // not much else we can do now, add some logging later exit(1); } + /** + * Send the error information to the WS client + * formatted as XML document. + * @param exception $ex + * @return void + */ + protected function send_error($ex=null) { + $this->send_headers(); + echo $this->zend_server->fault($ex); + } + /** * Future hook needed for emulated sessions. * @param exception $exception null means normal termination, $exception received when WS call failed diff --git a/webservice/soap/db/access.php b/webservice/soap/db/access.php new file mode 100644 index 0000000000..fb2d705a6c --- /dev/null +++ b/webservice/soap/db/access.php @@ -0,0 +1,12 @@ + 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 + 'legacy' => array( + ), + ), + +); diff --git a/webservice/soap/lib.php b/webservice/soap/lib.php deleted file mode 100644 index 26e64295ce..0000000000 --- a/webservice/soap/lib.php +++ /dev/null @@ -1,151 +0,0 @@ -dirroot.'/webservice/lib.php'); - -final class soap_server extends webservice_server { - - public function __construct() { - $this->set_protocolname("Soap"); - $this->set_protocolid("soap"); - } - - - /** - * Run Zend SOAP server - * @global $CFG - * @global $USER - */ - public function run() { - $enable = $this->get_enable(); - if (empty($enable)) { - die; - } - global $CFG, $DB; - //include_once "Zend/Loader/Autoloader.php"; - //Zend_Loader_Autoloader::autoload('Zend_Loader'); - - include_once "Zend/Soap/Server.php"; - include_once "Zend/Soap/AutoDiscover.php"; - - // retrieve the token from the url - // if the token doesn't exist, set a class containing only get_token() - $token = optional_param('token',null,PARAM_ALPHANUM); - - - ///this is a hack, because there is a bug in Zend framework (http://framework.zend.com/issues/browse/ZF-5736) - if (empty($token)) { - $relativepath = get_file_argument(); - $args = explode('/', trim($relativepath, '/')); - if (count($args) == 2) { - $token = (integer)$args[0]; - $classpath = $args[1]; - } - } - - if (empty($token)) { - - if(isset($_GET['wsdl'])) { - $autodiscover = new Zend_Soap_AutoDiscover(); - /* - $autodiscover->setComplexTypeStrategy('Zend_Soap_Wsdl_Strategy_ArrayOfTypeComplex'); - $autodiscover->setOperationBodyStyle( - array('use' => 'literal', - 'namespace' => $CFG->wwwroot) - ); - - $autodiscover->setBindingStyle( - array('style' => 'rpc') - ); -*/ - $autodiscover->setClass('ws_authentication'); - $autodiscover->handle(); - } else { - $soap = new Zend_Soap_Server($CFG->wwwroot."/webservice/soap/server.php?wsdl=true"); // this current file here - - $soap->registerFaultException('moodle_exception'); - - $soap->setClass('ws_authentication'); - $soap->handle(); - } - } else { // if token exist, do the authentication here - /// TODO: following function will need to be modified - $user = webservice_lib::mock_check_token($token); - // varlog($user); - if (empty($user)) { - throw new moodle_exception('wrongidentification'); - } else { - /// TODO: probably change this - global $USER; - $USER = $user; - } - - //load the service functions that the user can access - $sql = 'SELECT f.id, f.classname, f.classpath, f.methodname FROM {external_functions} f, {external_services} s, {external_services_functions} sf, {external_services_users} su - WHERE s.enabled = 1 AND f.id = sf.id AND sf.externalserviceid = su.externalserviceid AND s.id = su.externalserviceid AND su.userid = ?'; - $functions = $DB->get_records_sql($sql,array($USER->id)); - $classlist = array(); //key is the classname, value is the class path - foreach($functions as $function) { - $classlist[$function->classname] = $function->classpath; - } - //varlog('List of services that '.$USER->username.' can access:'); - //varlog($classlist); - - /// run the server - if(isset($_GET['wsdl'])) { - $autodiscover = new Zend_Soap_AutoDiscover(); - - //this is a hack, because there is a bug in Zend framework (http://framework.zend.com/issues/browse/ZF-5736) - $autodiscover->setUri($CFG->wwwroot."/webservice/soap/server.php/".$token); - - //we loading all class contaning the requested function - foreach ($classlist as $classname => $classpath) { - require_once($CFG->dirroot."/".$classpath); - $autodiscover->setClass($classname); - } - - //$autodiscover->setClass($classpath."_external"); - $autodiscover->handle(); - } else { - $soap = new Zend_Soap_Server($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&wsdl"); // this current file here - foreach ($classlist as $classname => $classpath) { - require_once($CFG->dirroot."/".$classpath); - $soap->setClass($classname); - } - $soap->registerFaultException('moodle_exception'); - $soap->handle(); - } - } - } - -} - - -?> diff --git a/webservice/soap/locallib.php b/webservice/soap/locallib.php new file mode 100644 index 0000000000..ae439601fe --- /dev/null +++ b/webservice/soap/locallib.php @@ -0,0 +1,151 @@ +. + +/** + * SOAP web service implementation classes and methods. + * + * @package webservice + * @copyright 2009 Moodle Pty Ltd (http://moodle.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once("$CFG->dirroot/webservice/lib.php"); + +/** + * SOAP service server implementation. + * @author Petr Skoda (skodak) + */ +class webservice_soap_server extends webservice_zend_server { + /** + * Contructor + * @param bool $simple use simple authentication + */ + public function __construct($simple) { + // must not cache wsdl - the list of functions is created on the fly + ini_set('soap.wsdl_cache_enabled', '0'); + require_once 'Zend/Soap/Server.php'; + require_once 'Zend/Soap/AutoDiscover.php'; + + if (optional_param('wsdl', 0, PARAM_BOOL)) { + parent::__construct($simple, 'Zend_Soap_AutoDiscover'); + } else { + parent::__construct($simple, 'Zend_Soap_Server'); + } + $this->wsname = 'soap'; + } + + /** + * Set up zend service class + * @return void + */ + protected function init_zend_server() { + global $CFG; + + parent::init_zend_server(); + + if ($this->simple) { + $username = optional_param('wsusername', '', PARAM_RAW); + $password = optional_param('wspassword', '', PARAM_RAW); + // aparently some clients and zend soap server does not work well with "&" in urls :-( + //TODO: report error if slasharguments disabled + $url = $CFG->wwwroot.'/webservice/soap/simpleserver.php/'.urlencode($username).'/'.urlencode($password); + // the Zend server is using this uri directly in xml - weird :-( + $this->zend_server->setUri(htmlentities($url)); + } else { + die('TODO: not implemented yet'); + } + + if (!optional_param('wsdl', 0, PARAM_BOOL)) { + $this->zend_server->setReturnResponse(true); + //TODO: the error handling in Zend Soap server is useless, XML-RPC is much, much better :-( + $this->zend_server->registerFaultException('moodle_exception'); + } + } + + /** + * This method parses the $_REQUEST superglobal and looks for + * the following information: + * 1/ user authentication - username+password or token (wsusername, wspassword and wstoken parameters) + * + * @return void + */ + protected function parse_request() { + parent::parse_request(); + + if (!$this->username or !$this->password) { + //note: this is the workaround for the trouble with & in soap urls + $authdata = get_file_argument(); + $authdata = explode('/', trim($authdata, '/')); + if (count($authdata) == 2) { + list($this->username, $this->password) = $authdata; + } + } + } + + /** + * Send the error information to the WS client + * formatted as XML document. + * @param exception $ex + * @return void + */ + protected function send_error($ex=null) { + // Zend Soap server fault handling is incomplete compared to XML-RPC :-( + // we can not use: echo $this->zend_server->fault($ex); + //TODO: send some better response in XML + if ($ex) { + $info = $ex->getMessage(); + if (debugging() and isset($ex->debuginfo)) { + $info .= ' - '.$ex->debuginfo; + } + } else { + $info = 'Unknown error'; + } + + $xml = ' + + +MOODLE:error +'.$info.' +'; + + $this->send_headers(); + header('Content-Type: application/xml'); + header('Content-Disposition: inline; filename="response.xml"'); + + echo $xml; + } +} + +/** + * SOAP test client class + */ +class webservice_soap_test_client implements webservice_test_client_interface { + /** + * Execute test client WS request + * @param string $serverurl + * @param string $function + * @param array $params + * @return mixed + */ + public function simpletest($serverurl, $function, $params) { + //zend expects 0 based array with numeric indexes + $params = array_values($params); + require_once 'Zend/Soap/Client.php'; + $client = new Zend_Soap_Client($serverurl.'&wsdl=1'); + return $client->__call($function, $params); + } +} diff --git a/webservice/soap/server.php b/webservice/soap/server.php index c2afd845b4..a7c1ff95c6 100644 --- a/webservice/soap/server.php +++ b/webservice/soap/server.php @@ -1,40 +1,38 @@ . + /** - * Moodle - Modular Object-Oriented Dynamic Learning Environment - * http://moodle.com - * - * LICENSE - * - * This program 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 2 of the License, or - * (at your option) any later version. + * SOAP web service entry point. The authentication is done via tokens. * - * This program 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: - * - * http://www.gnu.org/copyleft/gpl.html - * - * @category Moodle * @package webservice - * @copyright Copyright (c) 1999 onwards Martin Dougiamas http://dougiamas.com - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL License + * @copyright 2009 Moodle Pty Ltd (http://moodle.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +define('NO_MOODLE_COOKIES', true); -/* - * SOAP server - */ -require_once(dirname(__FILE__) . '/../../config.php'); -require_once('lib.php'); -ini_set("soap.wsdl_cache_enabled", "0"); //must not cache wsdl -if (empty($CFG->enablewebservices)) { +require('../../config.php'); +require_once("$CFG->dirroot/webservice/soap/locallib.php"); + +if (!webservice_protocol_is_enabled('soap')) { die; } -$server = new soap_server(); +$server = new webservice_soap_server(true); $server->run(); +die; -?> \ No newline at end of file diff --git a/webservice/soap/simpleserver.php b/webservice/soap/simpleserver.php new file mode 100644 index 0000000000..e1b6b5ce90 --- /dev/null +++ b/webservice/soap/simpleserver.php @@ -0,0 +1,47 @@ +. + +/** + * XML-RPC web service entry point. The authentication is done via tokens. + * + * @package webservice + * @copyright 2009 Moodle Pty Ltd (http://moodle.com) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('NO_MOODLE_COOKIES', true); + +require('../../config.php'); +require_once("$CFG->dirroot/webservice/soap/locallib.php"); + +//ob_start(); + +//TODO: for now disable all mess in xml +/* +ini_set('display_errors', '0'); +ini_set('log_errors', '1'); +$CFG->debugdisplay = false; +*/ +if (!webservice_protocol_is_enabled('soap')) { + die; +} + +$server = new webservice_soap_server(true); +$server->run(); +die; + + diff --git a/webservice/soap/testclient/zend/zend_soap_client.php b/webservice/soap/testclient/zend/zend_soap_client.php deleted file mode 100644 index b15461dd6e..0000000000 --- a/webservice/soap/testclient/zend/zend_soap_client.php +++ /dev/null @@ -1,195 +0,0 @@ -set_course($COURSE); -$PAGE->set_url('webservice/soap/testclient/zend/zend_soap_client.php'); -$PAGE->set_generaltype("form"); - -///Display Moodle page header -$PAGE->set_title('Soap test client'); -$PAGE->set_heading('Soap test client'); -echo $OUTPUT->header(); -//print_header('Soap test client', 'Soap test client'.":", true); - -/// check that webservices are enable into your Moodle -/// WARNING: it makes sens here only because this client runs on the same machine as the -/// server, if you change the WSDL url, please comment the following if statement -if (!webservice_lib::display_webservices_availability("soap")) { - echo "

"; - echo "Please fix the previous problem(s), the testing session has been interupted."; - echo $OUTPUT->footer(); - // print_footer(); - exit(); -} - -/// Following some code in order to print the authentication WSDL into the end of the source code page -/* - $client = new Zend_Http_Client($CFG->wwwroot."/webservice/soap/server.php?wsdl", array( - 'maxredirects' => 0, - 'timeout' => 30)); - $response = $client->request(); - $wsdl = $response->getBody(); - print $wsdl; - exit(); -*/ - - -/// authenticate => get a conversation token from the server -/// You need a wsuser/wspassword user in the remote Moodle -$client = new Zend_Soap_Client($CFG->wwwroot."/webservice/soap/server.php?wsdl=true"); -try { - - $params = new stdClass(); - $params->username = 'wsuser'; - $params->password = 'wspassword'; - $token = $client->get_token($params); - - print "
\n";
-    print "

Token: ".$token; - print "
"; -} catch (exception $exception) { - print "

An exception occured during authentication: \n"; - print "
\n";
-    print $exception;
-    print "
"; - printLastRequestResponse($client); -} - -/// Following some code in order to print the WSDL into the end of the source code page -/// Change the classpath to get specific service -/** - $client = new Zend_Http_Client($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&classpath=user&wsdl", array( - 'maxredirects' => 0, - 'timeout' => 30)); - $response = $client->request(); - $wsdl = $response->getBody(); - print $wsdl; - exit(); - **/ - - -/// build the Zend SOAP client from the remote WSDL -$client = new Zend_Soap_Client($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&wsdl=true"); -print "

You are accessing the WSDL: "; -print "

".$CFG->wwwroot."/webservice/soap/server.php?token=".$token."&classpath=user&wsdl
"; - -/// Get any user with string "admin" -//print "

Get users:"; -//print "
\n";
-//try {
-//    $params = new stdClass();
-//    $params->search = "admin";
-//    var_dump($client->get_users($params));
-//} catch (exception $exception) {
-//    print $exception;
-//    print "

An exception occured: \n"; -// printLastRequestResponse($client); -//} -//print "
"; - -/// Create a user with "mockuser66" username -print "

Create user:"; -print "
\n";
-try {
-    $user = array();
-    $user['password'] = "password6";
-    $user['email'] = "mockuser6@mockuser6.com";
-    $user['username'] = "mockuser66";
-    $user['firstname'] = "firstname6";
-    $user['lastname'] = "lastname6";
-    $params = new stdClass();
-    $params->users = array($user);
-    $userlist = array();
-    $userlist[] = $user;
-    var_dump($client->create_users($userlist));
-} catch (exception $exception) {
-    print $exception;
-    print "

An exception occured: \n"; - //printLastRequestResponse($client); -} -print "
"; - -///// Update this user -//print "

Update user:"; -//print "
\n";
-//try {
-//    $usertoupdate = new stdClass();
-//    $usertoupdate->email = "mockuser6@mockuser6.com";
-//    $usertoupdate->username = "mockuser66";
-//    $usertoupdate->newusername = 'mockuser6b';
-//    $usertoupdate->firstname = "firstname6b";
-//    $params = new stdClass();
-//    $params->users = array($usertoupdate);
-//    var_dump($client->update_users($params));
-//} catch (exception $exception) {
-//    print $exception;
-//    print "

An exception occured: \n"; -// printLastRequestResponse($client); -//} -//print "
"; -// -///// Delete this user -//print "

Delete user:"; -//print "
\n";
-//try {
-//    $params = new stdClass();
-//    $params->usernames = array("mockuser6b");
-//    var_dump($client->delete_users($params));
-//} catch (exception $exception) {
-//    print $exception;
-//    print "

An exception occured: \n"; -// printLastRequestResponse($client); -//} -//print "
"; - -/// Display Moodle page footer -echo $OUTPUT->footer(); -//print_footer(); - - -/** - * Display the last request - * @param $client - */ -function printLastRequestResponse($client) { - print "
\n";
-    print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n";
-    print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n";
-    print "
"; -} - -?> \ No newline at end of file diff --git a/webservice/soap/version.php b/webservice/soap/version.php new file mode 100644 index 0000000000..f15e31b9c5 --- /dev/null +++ b/webservice/soap/version.php @@ -0,0 +1,3 @@ +version = 2009101900; diff --git a/webservice/xmlrpc/locallib.php b/webservice/xmlrpc/locallib.php index d356a4c597..33005fbda8 100644 --- a/webservice/xmlrpc/locallib.php +++ b/webservice/xmlrpc/locallib.php @@ -41,7 +41,7 @@ class webservice_xmlrpc_server extends webservice_zend_server { } /** - * Set up zend serice class + * Set up zend service class * @return void */ protected function init_zend_server() { -- 2.39.5