ILIAS  Release_3_10_x_branch Revision 61812
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.soapclient.php
Go to the documentation of this file.
1 <?php
2 
3 
4 
5 
25 class soap_client extends nusoap_base {
26 
27  var $username = '';
28  var $password = '';
29  var $authtype = '';
30  var $requestHeaders = false; // SOAP headers in request (text)
31  var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
32  var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
33  var $endpoint;
34  var $error_str = false;
35  var $proxyhost = '';
36  var $proxyport = '';
37  var $proxyusername = '';
38  var $proxypassword = '';
39  var $xml_encoding = ''; // character set encoding of incoming (response) messages
40  var $http_encoding = false;
41  var $timeout = 0; // HTTP connection timeout
42  var $response_timeout = 30; // HTTP response timeout
43  var $endpointType = '';
44  var $persistentConnection = false;
45  var $defaultRpcParams = false; // This is no longer used
46  var $request = ''; // HTTP request
47  var $response = ''; // HTTP response
48  var $responseData = ''; // SOAP payload of response
49  // toggles whether the parser decodes element content w/ utf8_decode()
50  var $decode_utf8 = true;
51 
62 
77  function soap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
78  $this->endpoint = $endpoint;
79  $this->proxyhost = $proxyhost;
80  $this->proxyport = $proxyport;
81  $this->proxyusername = $proxyusername;
82  $this->proxypassword = $proxypassword;
83  $this->timeout = $timeout;
84  $this->response_timeout = $response_timeout;
85 
86  // make values
87  if($wsdl){
88  $this->endpointType = 'wsdl';
89  if (is_object($endpoint) && is_a($endpoint, 'wsdl')) {
90  $this->wsdl = $endpoint;
91  $this->endpoint = $this->wsdl->wsdl;
92  $this->wsdlFile = $this->endpoint;
93  $this->debug('existing wsdl instance created from ' . $this->endpoint);
94  } else {
95  $this->wsdlFile = $this->endpoint;
96 
97  // instantiate wsdl object and parse wsdl file
98  $this->debug('instantiating wsdl class with doc: '.$endpoint);
99  $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
100  }
101  $this->debug("wsdl debug...\n".$this->wsdl->debug_str);
102  $this->wsdl->debug_str = '';
103  // catch errors
104  if($errstr = $this->wsdl->getError()){
105  $this->debug('got wsdl error: '.$errstr);
106  $this->setError('wsdl error: '.$errstr);
107  } elseif($this->operations = $this->wsdl->getOperations()){
108  $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
109  } else {
110  $this->debug( 'getOperations returned false');
111  $this->setError('no operations defined in the WSDL document!');
112  }
113  }
114  }
115 
141  function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
142  $this->operation = $operation;
143  $this->fault = false;
144  $this->error_str = '';
145  $this->request = '';
146  $this->response = '';
147  $this->responseData = '';
148  $this->faultstring = '';
149  $this->faultcode = '';
150  $this->opData = array();
151 
152  $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $style, $use; endpointType: $this->endpointType");
153  if ($headers) {
154  $this->requestHeaders = $headers;
155  }
156  // serialize parameters
157  if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
158  // use WSDL for operation
159  $this->opData = $opData;
160  foreach($opData as $key => $value){
161  $this->debug("$key -> $value");
162  }
163  if (isset($opData['soapAction'])) {
164  $soapAction = $opData['soapAction'];
165  }
166  $this->endpoint = $opData['endpoint'];
167  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : ($namespace != '' ? $namespace : 'http://testuri.org');
168  $style = $opData['style'];
169  $use = $opData['input']['use'];
170  // add ns to ns array
171  if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
172  $this->wsdl->namespaces['nu'] = $namespace;
173  }
174  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
175  // serialize payload
176  if (is_string($params)) {
177  $this->debug("serializing param string for WSDL operation $operation");
178  $payload = $params;
179  } elseif (is_array($params)) {
180  $this->debug("serializing param array for WSDL operation $operation");
181  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
182  } else {
183  $this->debug('params must be array or string');
184  $this->setError('params must be array or string');
185  return false;
186  }
187  $usedNamespaces = $this->wsdl->usedNamespaces;
188  // Partial fix for multiple encoding styles in the same function call
189  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
190  if (isset($opData['output']['encodingStyle']) && $encodingStyle != $opData['output']['encodingStyle']) {
191  $methodEncodingStyle = ' SOAP-ENV:encodingStyle="' . $opData['output']['encodingStyle'] . '"';
192  } else {
193  $methodEncodingStyle = '';
194  }
195  $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
196  $this->wsdl->debug_str = '';
197  if ($errstr = $this->wsdl->getError()) {
198  $this->debug('got wsdl error: '.$errstr);
199  $this->setError('wsdl error: '.$errstr);
200  return false;
201  }
202  } elseif($this->endpointType == 'wsdl') {
203  // operation not in WSDL
204  $this->setError( 'operation '.$operation.' not present.');
205  $this->debug("operation '$operation' not present.");
206  $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
207  $this->wsdl->debug_str = '';
208  return false;
209  } else {
210  // no WSDL
211  if($namespace == ''){
212  $namespace = 'http://testuri.org';
213  }
214  //$this->namespaces['ns1'] = $namespace;
215  $nsPrefix = 'ns1';
216  // serialize
217  $payload = '';
218  if (is_string($params)) {
219  $this->debug("serializing param string for operation $operation");
220  $payload = $params;
221  } elseif (is_array($params)) {
222  $this->debug("serializing param array for operation $operation");
223  foreach($params as $k => $v){
224  $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
225  }
226  } else {
227  $this->debug('params must be array or string');
228  $this->setError('params must be array or string');
229  return false;
230  }
231  $usedNamespaces = array();
232  $methodEncodingStyle = '';
233  }
234  // wrap RPC calls with method element
235  if ($style == 'rpc') {
236  if ($use == 'literal') {
237  $this->debug("wrapping RPC request with literal method element");
238  $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
239  } else {
240  $this->debug("wrapping RPC request with encoded method element");
241  $payload = "<$nsPrefix:$operation$methodEncodingStyle xmlns:$nsPrefix=\"$namespace\">" .
242  $payload .
243  "</$nsPrefix:$operation>";
244  }
245  }
246  // serialize envelope
247  $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use);
248  $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace, style: $style, use: $use");
249  $this->debug('SOAP message length: ' . strlen($soapmsg) . ' contents: ' . substr($soapmsg, 0, 1000));
250  // send
251  $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
252  if($errstr = $this->getError()){
253  $this->debug('Error: '.$errstr);
254  return false;
255  } else {
256  $this->return = $return;
257  $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
258 
259  // fault?
260  if(is_array($return) && isset($return['faultcode'])){
261  $this->debug('got fault');
262  $this->setError($return['faultcode'].': '.$return['faultstring']);
263  $this->fault = true;
264  foreach($return as $k => $v){
265  $this->$k = $v;
266  $this->debug("$k = $v<br>");
267  }
268  return $return;
269  } else {
270  // array of return values
271  if(is_array($return)){
272  // multiple 'out' parameters
273  if(sizeof($return) > 1){
274  return $return;
275  }
276  // single 'out' parameter
277  return array_shift($return);
278  // nothing returned (ie, echoVoid)
279  } else {
280  return "";
281  }
282  }
283  }
284  }
285 
293  function getOperationData($operation){
294  if(isset($this->operations[$operation])){
295  return $this->operations[$operation];
296  }
297  $this->debug("No data for operation: $operation");
298  }
299 
314  function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
315  // detect transport
316  switch(true){
317  // http(s)
318  case ereg('^http',$this->endpoint):
319  $this->debug('transporting via HTTP');
320  if($this->persistentConnection == true && is_object($this->persistentConnection)){
322  } else {
323  $http = new soap_transport_http($this->endpoint);
324  if ($this->persistentConnection) {
325  $http->usePersistentConnection();
326  }
327  }
328  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
329  $http->setSOAPAction($soapaction);
330  if($this->proxyhost && $this->proxyport){
331  $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
332  }
333  if($this->username != '' && $this->password != '') {
334  $http->setCredentials($this->username, $this->password, $this->authtype);
335  }
336  if($this->http_encoding != ''){
337  $http->setEncoding($this->http_encoding);
338  }
339  $this->debug('sending message, length: '.strlen($msg));
340  if(ereg('^http:',$this->endpoint)){
341  //if(strpos($this->endpoint,'http:')){
342  $this->responseData = $http->send($msg,$timeout,$response_timeout);
343  } elseif(ereg('^https',$this->endpoint)){
344  //} elseif(strpos($this->endpoint,'https:')){
345  //if(phpversion() == '4.3.0-dev'){
346  //$response = $http->send($msg,$timeout,$response_timeout);
347  //$this->request = $http->outgoing_payload;
348  //$this->response = $http->incoming_payload;
349  //} else
350  if (extension_loaded('curl')) {
351  $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout);
352  } else {
353  $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
354  }
355  } else {
356  $this->setError('no http/s in endpoint url');
357  }
358  $this->request = $http->outgoing_payload;
359  $this->response = $http->incoming_payload;
360  $this->debug("transport debug data...\n".$http->debug_str);
361 
362  // save transport object if using persistent connections
363  if ($this->persistentConnection) {
364  $http->debug_str = '';
365  if (!is_object($this->persistentConnection)) {
366  $this->persistentConnection = $http;
367  }
368  }
369 
370  if($err = $http->getError()){
371  $this->setError('HTTP Error: '.$err);
372  return false;
373  } elseif($this->getError()){
374  return false;
375  } else {
376  $this->debug('got response, length: '. strlen($this->responseData).' type: '.$http->incoming_headers['content-type']);
377  return $this->parseResponse($http->incoming_headers, $this->responseData);
378  }
379  break;
380  default:
381  $this->setError('no transport found, or selected transport is not yet supported!');
382  return false;
383  break;
384  }
385  }
386 
395  function parseResponse($headers, $data) {
396  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
397  if (!strstr($headers['content-type'], 'text/xml')) {
398  $this->setError('Response not of type text/xml');
399  return false;
400  }
401  if (strpos($headers['content-type'], '=')) {
402  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
403  $this->debug('Got response encoding: ' . $enc);
404  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
405  $this->xml_encoding = strtoupper($enc);
406  } else {
407  $this->xml_encoding = 'US-ASCII';
408  }
409  } else {
410  // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
411  $this->xml_encoding = 'UTF-8';
412  }
413  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
414  $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
415  // add parser debug data to our debug
416  $this->debug($parser->debug_str);
417  // if parse errors
418  if($errstr = $parser->getError()){
419  $this->setError( $errstr);
420  // destroy the parser object
421  unset($parser);
422  return false;
423  } else {
424  // get SOAP headers
425  $this->responseHeaders = $parser->getHeaders();
426  // get decoded message
427  $return = $parser->get_response();
428  // add document for doclit support
429  $this->document = $parser->document;
430  // destroy the parser object
431  unset($parser);
432  // return decode message
433  return $return;
434  }
435  }
436 
443  function setHeaders($headers){
444  $this->requestHeaders = $headers;
445  }
446 
453  function getHeaders(){
454  if($this->responseHeaders != '') {
455  return $this->responseHeaders;
456  }
457  }
458 
469  $this->proxyhost = $proxyhost;
470  $this->proxyport = $proxyport;
471  $this->proxyusername = $proxyusername;
472  $this->proxypassword = $proxypassword;
473  }
474 
483  function setCredentials($username, $password, $authtype = 'basic') {
484  $this->username = $username;
485  $this->password = $password;
486  $this->authtype = $authtype;
487  }
488 
495  function setHTTPEncoding($enc='gzip, deflate'){
496  $this->http_encoding = $enc;
497  }
498 
505  $this->persistentConnection = true;
506  }
507 
518  function getDefaultRpcParams() {
520  }
521 
530  function setDefaultRpcParams($rpcParams) {
531  $this->defaultRpcParams = $rpcParams;
532  }
533 
540  function getProxy(){
541  $evalStr = '';
542  foreach($this->operations as $operation => $opData){
543  if($operation != ''){
544  // create param string
545  $paramStr = '';
546  if(sizeof($opData['input']['parts']) > 0){
547  foreach($opData['input']['parts'] as $name => $type){
548  $paramStr .= "\$$name,";
549  }
550  $paramStr = substr($paramStr,0,strlen($paramStr)-1);
551  }
552  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
553  $evalStr .= "function $operation ($paramStr){
554  // load params into array
555  \$params = array($paramStr);
556  return \$this->call('$operation',\$params,'".$opData['namespace']."','".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
557  }";
558  unset($paramStr);
559  }
560  }
561  $r = rand();
562  $evalStr = 'class soap_proxy_'.$r.' extends soap_client {
563  '.$evalStr.'
564  }';
565  //print "proxy class:<pre>$evalStr</pre>";
566  // eval the class
567  eval($evalStr);
568  // instantiate proxy object
569  eval("\$proxy = new soap_proxy_$r('');");
570  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
571  $proxy->endpointType = 'wsdl';
572  $proxy->wsdlFile = $this->wsdlFile;
573  $proxy->wsdl = $this->wsdl;
574  $proxy->operations = $this->operations;
575  $proxy->defaultRpcParams = $this->defaultRpcParams;
576  // transfer other state
577  $proxy->username = $this->username;
578  $proxy->password = $this->password;
579  $proxy->proxyhost = $this->proxyhost;
580  $proxy->proxyport = $this->proxyport;
581  $proxy->proxyusername = $this->proxyusername;
582  $proxy->proxypassword = $this->proxypassword;
583  $proxy->timeout = $this->timeout;
584  $proxy->response_timeout = $this->response_timeout;
585  $proxy->http_encoding = $this->http_encoding;
586  $proxy->persistentConnection = $this->persistentConnection;
587  return $proxy;
588  }
589 
597  function getHTTPBody($soapmsg) {
598  return $soapmsg;
599  }
600 
609  function getHTTPContentType() {
610  return 'text/xml';
611  }
612 
624  }
625 
626  /*
627  * whether or not parser should decode utf8 element content
628  *
629  * @return always returns true
630  * @access public
631  */
632  function decodeUTF8($bool){
633  $this->decode_utf8 = $bool;
634  return true;
635  }
636 }
637 ?>