|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00026 require_once("$CFG->dirroot/webservice/lib.php"); 00027 require_once 'Zend/Soap/Server.php'; 00028 00032 class moodle_zend_soap_server extends Zend_Soap_Server { 00033 00051 public function fault($fault = null, $code = "Receiver") 00052 { 00053 //intercept any exceptions with debug info and transform it in Moodle exception 00054 if ($fault instanceof Exception) { 00055 //add the debuginfo to the exception message if debuginfo must be returned 00056 if (debugging() and isset($fault->debuginfo)) { 00057 $fault = new SoapFault('Receiver', $fault->getMessage() . ' | DEBUG INFO: ' . $fault->debuginfo); 00058 } 00059 } 00060 00061 return parent::fault($fault, $code); 00062 } 00063 } 00064 00069 class webservice_soap_server extends webservice_zend_server { 00074 public function __construct($authmethod) { 00075 // must not cache wsdl - the list of functions is created on the fly 00076 ini_set('soap.wsdl_cache_enabled', '0'); 00077 require_once 'Zend/Soap/Server.php'; 00078 require_once 'Zend/Soap/AutoDiscover.php'; 00079 00080 if (optional_param('wsdl', 0, PARAM_BOOL)) { 00081 parent::__construct($authmethod, 'Zend_Soap_AutoDiscover'); 00082 } else { 00083 parent::__construct($authmethod, 'moodle_zend_soap_server'); 00084 } 00085 $this->wsname = 'soap'; 00086 } 00087 00092 protected function init_zend_server() { 00093 global $CFG; 00094 00095 parent::init_zend_server(); 00096 00097 if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) { 00098 $username = optional_param('wsusername', '', PARAM_RAW); 00099 $password = optional_param('wspassword', '', PARAM_RAW); 00100 // aparently some clients and zend soap server does not work well with "&" in urls :-( 00101 //TODO: the zend error has been fixed in the last Zend SOAP version, check that is fixed and remove obsolete code 00102 $url = $CFG->wwwroot.'/webservice/soap/simpleserver.php/'.urlencode($username).'/'.urlencode($password); 00103 // the Zend server is using this uri directly in xml - weird :-( 00104 $this->zend_server->setUri(htmlentities($url)); 00105 } else { 00106 $wstoken = optional_param('wstoken', '', PARAM_RAW); 00107 $url = $CFG->wwwroot.'/webservice/soap/server.php?wstoken='.urlencode($wstoken); 00108 // the Zend server is using this uri directly in xml - weird :-( 00109 $this->zend_server->setUri(htmlentities($url)); 00110 } 00111 00112 if (!optional_param('wsdl', 0, PARAM_BOOL)) { 00113 $this->zend_server->setReturnResponse(true); 00114 //TODO: the error handling in Zend Soap server is useless, XML-RPC is much, much better :-( 00115 $this->zend_server->registerFaultException('moodle_exception'); 00116 $this->zend_server->registerFaultException('webservice_parameter_exception'); //deprecated since Moodle 2.2 - kept for backward compatibility 00117 $this->zend_server->registerFaultException('invalid_parameter_exception'); 00118 $this->zend_server->registerFaultException('invalid_response_exception'); 00119 //when DEBUG >= NORMAL then the thrown exceptions are "casted" into a PHP SoapFault expception 00120 //in order to diplay the $debuginfo (see moodle_zend_soap_server class - MDL-29435) 00121 if (debugging()) { 00122 $this->zend_server->registerFaultException('SoapFault'); 00123 } 00124 } 00125 } 00126 00134 protected function parse_request() { 00135 parent::parse_request(); 00136 00137 if (!$this->username or !$this->password) { 00138 //note: this is the workaround for the trouble with & in soap urls 00139 $authdata = get_file_argument(); 00140 $authdata = explode('/', trim($authdata, '/')); 00141 if (count($authdata) == 2) { 00142 list($this->username, $this->password) = $authdata; 00143 } 00144 } 00145 } 00146 00153 protected function send_error($ex=null) { 00154 // Zend Soap server fault handling is incomplete compared to XML-RPC :-( 00155 // we can not use: echo $this->zend_server->fault($ex); 00156 //TODO: send some better response in XML 00157 if ($ex) { 00158 $info = $ex->getMessage(); 00159 if (debugging() and isset($ex->debuginfo)) { 00160 $info .= ' - '.$ex->debuginfo; 00161 } 00162 } else { 00163 $info = 'Unknown error'; 00164 } 00165 00166 $xml = '<?xml version="1.0" encoding="UTF-8"?> 00167 <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 00168 <SOAP-ENV:Body><SOAP-ENV:Fault> 00169 <faultcode>MOODLE:error</faultcode> 00170 <faultstring>'.$info.'</faultstring> 00171 </SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>'; 00172 00173 $this->send_headers(); 00174 header('Content-Type: application/xml; charset=utf-8'); 00175 header('Content-Disposition: inline; filename="response.xml"'); 00176 00177 echo $xml; 00178 } 00179 00180 protected function generate_simple_struct_class(external_single_structure $structdesc) { 00181 global $USER; 00182 // let's use unique class name, there might be problem in unit tests 00183 $classname = 'webservices_struct_class_000000'; 00184 while(class_exists($classname)) { 00185 $classname++; 00186 } 00187 00188 $fields = array(); 00189 foreach ($structdesc->keys as $name => $fieldsdesc) { 00190 $type = $this->get_phpdoc_type($fieldsdesc); 00191 $fields[] = ' /** @var '.$type." */\n" . 00192 ' public $'.$name.';'; 00193 } 00194 00195 $code = ' 00199 class '.$classname.' { 00200 '.implode("\n", $fields).' 00201 } 00202 '; 00203 eval($code); 00204 return $classname; 00205 } 00206 } 00207 00211 class webservice_soap_test_client implements webservice_test_client_interface { 00219 public function simpletest($serverurl, $function, $params) { 00220 //zend expects 0 based array with numeric indexes 00221 $params = array_values($params); 00222 require_once 'Zend/Soap/Client.php'; 00223 $client = new Zend_Soap_Client($serverurl.'&wsdl=1'); 00224 return $client->__call($function, $params); 00225 } 00226 }