/class.phpwsdlclient.php
PHP | 692 lines | 410 code | 18 blank | 264 comment | 59 complexity | 899e3aab9528f04b00e6e9449b1cbb58 MD5 | raw file
Possible License(s): GPL-3.0
- <?php
-
- /*
- PhpWsdl - Generate WSDL from PHP
- Copyright (C) 2011 Andreas Müller-Saala, wan24.de
-
- 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 3 of the License, or (at your option) any later
- version.
-
- 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.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
- if(basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__))
- exit;
-
- // To use PhpWsdlClient, you need to load it seperatly from PhpWsdl. Or you
- // just load this class and let it autoload PhpWsdl
-
- require_once(dirname(__FILE__).'/class.phpwsdl.php');
-
- /**
- * A SOAP client class for PhpWsdl
- *
- * @author Andreas Müller-Saala, wan24.de
- * @version 2.4
- */
- class PhpWsdlClient{
- /**
- * The version number
- *
- * @var string
- */
- public static $VERSION='2.4';
- /**
- * Parse a method
- * 1: Type
- * 2: Method
- * 3: Parameters
- *
- * @var string
- */
- public static $methodRx='/^([^\s]+)\s+([^\(]+)\(([^\)]+)?\).*$/';
- /**
- * Parse a type
- * 1: Type
- * 2: Name
- *
- * @var string
- */
- public static $typeRx='/^([^\s]+)\s([^\[|\{|\s]+)([\[|\{|\s].*$)?/s';
- /**
- * Parse an element
- * 1: Type
- * 2: Name
- *
- * @var string
- */
- public static $elementRx='/^\s*([^\s]+)\s+([^\s|;]+);.*$/';
- /**
- * The WSDL URI
- *
- * @var string
- */
- public $WsdlUri;
- /**
- * The PHP SoapClient object
- *
- * @var SoapClient
- */
- public $Client=null;
- /**
- * SOAP call options
- *
- * @var array
- */
- public $Options;
- /**
- * SOAP call request headers
- *
- * @var array
- */
- public $RequestHeaders;
- /**
- * PHP SoapClient options array
- *
- * @var array
- */
- public $ClientOptions;
- /**
- * The webservice name
- *
- * @var string
- */
- public $ServiceName=null;
- /**
- * The SOAP endpoint
- *
- * @var string
- */
- public $EndPoint=null;
- /**
- * The SOAP namespace
- *
- * @var string
- */
- public $NameSpace=null;
- /**
- * A PhpWsdl object
- *
- * @var PhpWsdl
- */
- public $Server=null;
- /**
- * The WSDL
- *
- * @var string
- */
- public $WSDL=null;
- /**
- * A list of warnings
- *
- * @var string[]
- */
- public $Warnings=Array();
- /**
- * The http Auth username for fetching the WSDL (and sending SOAP requests, if PhpWsdlClient->UseSoapHttpAuth is TRUE)
- * If you need a different login for SOAP requests, use the PhpWsdlClient->ClientOptions array for the SOAP request
- * authentification values (login/password)
- *
- * @var string
- */
- public $HttpUser=null;
- /**
- * The http Auth password
- *
- * @var string
- */
- public $HttpPassword=null;
- /**
- * Use http Auth for SOAP requests, too? If FALSE, the login will only be used to fetch the WSDL from the given URI
- *
- * @var boolean
- */
- public $UseSoapHttpAuth=true;
- /**
- * Enable debugging of the RAW request/response?
- *
- * @var boolean
- */
- public $Debugging=false;
- /**
- * Encode parameters?
- * Note: This will only work if it's possible to build a PhpWsdl object from the target webservice WSDL
- *
- * @var boolean
- */
- public $EncodeParameters=false;
-
- /**
- * Constructor
- *
- * @param string $wsdlUri The WSDL URI
- * @param array $options SOAP call options (default: NULL)
- * @param array $requestHeaders SOAP call request headers (default: NULL)
- */
- public function PhpWsdlClient($wsdlUri,$options=null,$requestHeaders=null,$clientOptions=Array()){
- PhpWsdl::Debug('New PhpWsdlClient '.$wsdlUri);
- $this->WsdlUri=$wsdlUri;
- $this->Options=$options;
- $this->RequestHeaders=$requestHeaders;
- $this->ClientOptions=array_merge(
- Array(
- 'soap_version' => SOAP_1_1|SOAP_1_2,
- 'encoding' => 'UTF-8',
- 'compression' => SOAP_COMPRESSION_ACCEPT|SOAP_COMPRESSION_GZIP|9,
- 'connection_timeout'=>5
- ),
- $clientOptions
- );
- $this->GetWsdlFromCache();
- }
-
- /**
- * Fetch the WSDL (supports http Auth if CURL is enabled)
- *
- * @param string $wsdlUri The WSDL URI or NULL to use the PhpWsdlClient->WaslUri property (default: NULL)
- * @param array $options The CURL options (default: array)
- * @return string The WSDL XML
- */
- public function FetchWsdl($wsdlUri=null,$options=Array()){
- if(is_null($wsdlUri))
- $wsdlUri=$this->WsdlUri;
- PhpWsdl::Debug('Fetch WSDL from '.$wsdlUri);
- if(!is_file($wsdlUri)&&function_exists('curl_init')&&!is_null($this->HttpUser)){
- // Fetch with http Auth (credits to faebu :)
- PhpWsdl::Debug('Try CURL for http Auth');
- $ch=curl_init();
- $credit=$this->HttpUser.':'.$this->HttpPassword;
- curl_setopt_array($ch,array_merge(
- Array(
- CURLOPT_URL => $wsdlUri,
- CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
- CURLOPT_USERPWD => $credit,
- CURLOPT_TIMEOUT => 10,
- CURLOPT_RETURNTRANSFER => 1
- ),
- $options
- ));
- $wsdl=curl_exec($ch);
- if($wsdl===false){
- PhpWsdl::Debug('WARNING: Could not fetch WSDL with CURL: '.curl_error($ch));
- @curl_close($ch);
- }else{
- curl_close($ch);
- return $wsdl;
- }
- }
- // Fetch without authentification
- return file_get_contents($wsdlUri);
- }
-
- /**
- * Do a SOAP request
- *
- * @param string $method The method name
- * @param array $param The method parameters
- * @param array $options The call options (default: array)
- * @param array $requestHeaders The request headers (default: array)
- * @return mixed The server response
- */
- public function DoRequest($method,$param,$options=Array(),$requestHeaders=Array()){
- PhpWsdl::Debug('Sending request '.$method);
- $options=array_merge($this->Options,$options);
- $requestHeaders=array_merge($this->RequestHeaders,$requestHeaders);
- $client=$this->GetClient();
- if($this->EncodeParameters){
- $server=$this->CreateServerFromWsdl();
- $m=$server->GetMethod($method);
- if(!is_null($m)){
- PhpWsdl::Debug('Encode parameters');
- $temp=Array();
- $i=-1;
- $len=sizeof($param);
- while(++$i<$len)
- $temp[]=PhpWsdl::DoEncoding($m->Param[$i]->Type,$param[$i],true,$server);
- $param=$temp;
- }else{
- PhpWsdl::Debug('Can not encode parameters because the method was not found');
- }
- }
- $res=$client->__soapCall($method,$param,$options,$requestHeaders);
- if(is_soap_fault($res))
- PhpWsdl::Debug('SOAP error #'.$res->faultcode.': '.$res->faultstring);
- if($this->Debugging){
- PhpWsdl::Debug('Parameters: '.print_r($param,true));
- PhpWsdl::Debug('Options: '.print_r($options,true));
- PhpWsdl::Debug('Headers: '.print_r($requestHeaders,true));
- PhpWsdl::Debug('Result: '.print_r($res,true));
- PhpWsdl::Debug('Request: '.$client->__getLastRequest());
- PhpWsdl::Debug('Request headers: '.$client->__getLastRequestHeaders());
- PhpWsdl::Debug('Response: '.$client->__getLastResponse());
- PhpWsdl::Debug('Response headers: '.$client->__getLastResponseHeaders());
- }
- return $res;
- }
-
- /**
- * Get the PHP SoapClient object
- *
- * @param string $uri The WSDL URI or NULL to use the PhpWsdlClient->WsdlUri property (default: NULL)
- * @param array $options The additional PHP SoapClient options (default: array)
- * @return SoapClient The PHP SoapClient object
- */
- public function GetClient($uri=null,$options=Array()){
- if(is_null($this->Client)){
- if(is_null($uri))
- $uri=$this->WsdlUri;
- PhpWsdl::Debug('Create a PHP SoapClient object in PhpWsdlClient from '.$uri);
- if(!is_null(PhpWsdl::$CacheFolder)){
- $wsdlFile=$this->GetCacheFileName($uri);
- if(!is_null($this->GetWsdlFromCache($wsdlFile))){
- PhpWsdl::Debug('Use cached WSDL from '.$wsdlFile);
- $uri=$wsdlFile;
- }else{
- $wsdl=$this->FetchWsdl($uri);
- if($wsdl!==false)
- if($this->WriteWsdlToCache($wsdl,$uri,$wsdlFile,true)){
- PhpWsdl::Debug('Using cached WSDL from '.$wsdlFile);
- $uri=$wsdlFile;
- }
- }
- }
- if(
- !is_null($this->HttpUser)&&
- !isset($this->ClientOptions['login'])&&
- !isset($options['login'])&&
- $this->UseSoapHttpAuth
- ){
- PhpWsdl::Debug('Using http Auth options');
- $options['login']=$this->HttpUser;
- $options['password']=$this->HttpPassword;
- }
- if($this->Debugging){
- PhpWsdl::Debug('Debugging enabled');
- $options['trace']=true;
- }
- $this->Client=new SoapClient($uri,array_merge(
- $this->ClientOptions,
- $options
- ));
- }
- return $this->Client;
- }
-
- /**
- * Create/Fill a PhpWsdl object from WSDL
- *
- * @param PhpWsdl An existing PhpWsdl object (default: NULL)
- * @return PhpWsdl The PhpWsdl object
- */
- public function CreateServerFromWsdl($soap=null){
- PhpWsdl::Debug('Create/Fill a PhpWsdl object from WSDL');
- if(is_null($soap)){
- if(!is_null($this->Server)){
- PhpWsdl::Debug('Return existing object');
- return $this->Server;
- }
- $soap=PhpWsdl::CreateInstance();
- }else{
- PhpWsdl::Debug('Use existing object');
- }
- if(!is_null($soap->GetWsdlFromCache())){
- PhpWsdl::Debug('Server created from cached values');
- if(is_null($this->Server))
- $this->Server=$soap;
- return $soap;
- }
- // Configuration
- $soap->WsdlUri=$this->WsdlUri;
- $this->ParseWsdl();
- if(!is_null($this->ServiceName))
- $soap->Name=$this->ServiceName;
- if(!is_null($this->NameSpace))
- $soap->NameSpace=$this->NameSpace;
- $client=$this->GetClient();
- // Methods
- $fnc=$client->__getFunctions();
- $i=-1;
- $len=sizeof($fnc);
- while(++$i<$len){
- $f=$fnc[$i];
- list(
- $type,
- $method,
- $temp
- )=explode("\t",preg_replace(self::$methodRx,"$1\t$2\t$3",$f));
- PhpWsdl::Debug('Found method #'.$i.' '.$method);
- if(!is_null($soap->GetMethod($method))){
- $this->Warn('WARNING: Double method detected!');
- continue;
- }
- $m=new PhpWsdlMethod($method);
- $temp=explode(' ',$temp);
- $pLen=sizeof($temp);
- for($j=0;$j<$pLen-1;$j++){
- list(
- $t,
- $n
- )=Array(
- $temp[$j],
- $temp[$j+1]
- );
- PhpWsdl::Debug('Found parameter #'.$j.' '.$n.' type of '.$t);
- $m->Param[]=new PhpWsdlParam(substr($n,1),$t);
- }
- if($type!='void')
- $m->Return=new PhpWsdlParam('return',$type);
- $soap->Methods[]=$m;
- }
- // Types
- $typ=$client->__getTypes();
- $i=-1;
- $len=sizeof($typ);
- while(++$i<$len){
- $t=$typ[$i];
- list(
- $type,
- $name
- )=explode("\t",preg_replace(self::$typeRx,"$1\t$2",$t));
- PhpWsdl::Debug('Found type #'.$i.' '.$name.' type of '.$type);
- if(!is_null($soap->GetType($name))){
- $this->Warn('WARNING: Double type detected!');
- continue;
- }
- $arr=strpos($t,'[]')>-1;
- $enum=!$arr&&strpos($t,'{')<0;
- if($arr){
- PhpWsdl::Debug('Array type');
- $y=new PhpWsdlComplex($name);
- $y->Type=$type;
- $y->IsArray=true;
- $soap->Types[]=$y;
- }else if(!$enum&&$type=='struct'){
- PhpWsdl::Debug('Complex type');
- // Note: Inherited types are not supported since the PHP SoapClient object doesn't provide parent class
- // informations of a complex type, so PhpWsdlClient doesn't support inherited complex types at all!
- $el=Array();
- $temp=explode("\n",$t);
- $j=0;
- $eLen=sizeof($temp)-1;
- while(++$j<$eLen){
- list(
- $p,
- $n
- )=explode("\t",preg_replace(self::$elementRx,"$1\t$2",$temp[$j]),2);
- PhpWsdl::Debug('Found element #'.$j.' '.$n.' type of '.$p);
- $el[]=new PhpWsdlElement($n,$p);
- }
- $y=new PhpWsdlComplex($name,$el);
- $y->IsArray=false;
- $soap->Types[]=$y;
- }else if($enum){
- PhpWsdl::Debug('Enumeration');
- PhpWsdl::Debug('WARNING: Enumeration values are unknown!');
- $y=new PhpWsdlEnum($name,$type);
- $soap->Types[]=$y;
- }else{
- $this->Warn('WARNING: Could not create type '.$t);
- }
- }
- if(is_null($this->Server))
- $this->Server=$soap;
- return $soap;
- }
-
- /**
- * Parse the WSDL for webservice name, namespace and endpoint URI
- */
- public function ParseWsdl(){
- if(!is_null($this->ServiceName)&&!is_null($this->EndPoint)&&!is_null($this->NameSpace))
- return;
- PhpWsdl::Debug('Parse WSDL');
- $wsdl=$this->WSDL;
- $writeCache=false;
- if(is_null($wsdl)){
- $wsdl=$this->FetchWsdl();
- if($wsdl===false)
- throw(new Exception('Could not fetch WSDL'));
- $writeCache=true;
- }
- $xml=new DOMDocument();
- if(!$xml->loadXML($wsdl))
- throw(new Exception('Invalid WSDL'));
- $x=new DOMXPath($xml);
- // Namespace
- $temp=$x->query("/*[local-name()='definitions']/@targetNamespace");
- if($temp->length>0){
- $temp=$temp->item(0);
- PhpWsdl::Debug('Namespace '.$temp->value);
- $this->NameSpace=$temp->value;
- }else{
- $this->Warn('WARNING: No namespace found');
- }
- // Webservice name
- $temp=$x->query("/*[local-name()='definitions']/*[local-name()='service']/@name");
- if($temp->length>0){
- $temp=$temp->item(0);
- PhpWsdl::Debug('Name '.$temp->value);
- $this->ServiceName=$temp->value;
- }else{
- $this->Warn('WARNING: No name found');
- }
- // Endpoint URI
- $temp=$x->query("/*[local-name()='definitions']/*[local-name()='service']/*[local-name()='port']/*[local-name()='address']/@location");
- if($temp->length>0){
- $temp=$temp->item(0);
- PhpWsdl::Debug('Endpoint '.$temp->value);
- $this->EndPoint=$temp->value;
- }else{
- $this->Warn('WARNING: No endpoint found');
- }
- // Caching
- $this->WriteWsdlToCache($wsdl,null,null,$writeCache);
- }
-
- /**
- * Create a PHP SOAP client for this webservice
- *
- * @param string $filename Name of the file to save the PHP code (default: NULL)
- * @param array $options The options array for the PhpWsdl->OutputPhp method (default: array)
- * @return string The UTF-8 encoded PHP code of the SOAP client
- */
- public function CreatePhpSoapClient($filename=null,$options=Array()){
- $php=$this->CreateServerFromWsdl()->OutputPhp(false,false,$options);
- if(!is_null($filename))
- if(file_put_contents($filename,$php)===false)
- PhpWsdl::Debug('Could not write file '.$filename);
- return $php;
- }
-
- /**
- * Add a warning message
- *
- * @param string $str The message
- */
- private function Warn($str){
- $this->Warnings[]=$str;
- PhpWsdl::Debug($str);
- }
-
- /**
- * Get the cache filename
- *
- * @param string $wsdluri The WSDL URI or NULL to use the PhpWsdlAjax->WsdlUri property (default: NULL)
- * @return string The cache filename or NULL, if caching is disabled
- */
- public function GetCacheFileName($wsdluri=null){
- $data=Array(
- 'client' => $this,
- 'wsdluri' => $wsdluri,
- 'filename' => (is_null(PhpWsdl::$CacheFolder))?null:PhpWsdl::$CacheFolder.'/client-'.sha1((is_null($wsdluri))?$this->WsdlUri:$wsdluri).'.wsdl'
- );
- PhpWsdl::CallHook(
- 'ClientCacheFileNameHook',
- $data
- );
- return $data['filename'];
- }
-
- /**
- * Determine if the cache file exists
- *
- * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
- * @return boolean Are the cache files present?
- */
- public function CacheFileExists($file=null){
- if(is_null($file))
- $file=$this->GetCacheFileName();
- PhpWsdl::Debug('Check cache file exists '.$file);
- return file_exists($file)&&file_exists($file.'.cache');
- }
-
- /**
- * Determine if the existing cache files are still valid
- *
- * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
- * @return boolean Valid?
- */
- public function IsCacheValid($file=null){
- PhpWsdl::Debug('Check cache valid');
- if(is_null($file))
- $file=$this->GetCacheFileName();
- if(!$this->CacheFileExists($file))
- return false;
- return PhpWsdl::$CacheTime<0||time()-file_get_contents($file.'.cache')<=PhpWsdl::$CacheTime;
- }
-
- /**
- * Get the WSDL from the cache
- *
- * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
- * @param boolean $force Force this even if the cache is timed out? (default: FALSE)
- * @param boolean $nounserialize Don't unserialize the PhpWsdl* objects? (default: FALSE)
- * @return string The cached WSDL
- */
- public function GetWsdlFromCache($file=null,$force=false,$nounserialize=false){
- PhpWsdl::Debug('Get WSDL from cache');
- if(!is_null($this->WSDL))
- return $this->WSDL;
- if(is_null($file))
- $file=$this->GetCacheFileName();
- if(!$force){
- if(!$this->IsCacheValid($file))
- return null;
- }else if(!$this->CacheFileExists($file)){
- return null;
- }
- $this->WSDL=file_get_contents($file);
- if(!$nounserialize){
- PhpWsdl::Debug('Unserialize data');
- $data=unserialize(file_get_contents($file.'.obj'));
- $this->ServiceName=$data['servicename'];
- $this->EndPoint=$data['endpoint'];
- $this->NameSpace=$data['namespace'];
- PhpWsdl::CallHook(
- 'ClientReadCacheHook',
- Array(
- 'client' => $this,
- 'data' => &$data
- )
- );
- if($data['version']!=self::$VERSION){
- PhpWsdl::Debug('Could not use cache from version '.$data['version']);
- $this->ServiceName=null;
- $this->EndPoint=null;
- $this->NameSpace=null;
- $this->WSDL=null;
- return null;
- }
- }
- return $this->WSDL;
- }
-
- /**
- * Write WSDL to cache
- *
- * @param string $wsdl The UTF-8 encoded WSDL string (default: NULL)
- * @param string $wsdluri The SOAP WSDL URI or NULL to use the default (default: NULL)
- * @param string $file The target filename or NULL to use the default (default: NULL)
- * @param boolean $force Force refresh (default: FALSE)
- * @return boolean Succeed?
- */
- public function WriteWsdlToCache($wsdl=null,$wsdluri=null,$file=null,$force=false){
- PhpWsdl::Debug('Write WSDL to the cache');
- if(is_null($wsdluri))
- $wsdluri=$this->WsdlUri;
- if($wsdluri==$this->WsdlUri&&!is_null($wsdl))
- $this->WSDL=$wsdl;
- if(is_null($wsdl)){
- if(is_null($this->WSDL)){
- PhpWsdl::Debug('No WSDL');
- return false;// WSDL not defined
- }
- $wsdl=$this->WSDL;
- }
- if(is_null($file)){
- $file=$this->GetCacheFileName($wsdluri);
- if(is_null($file)){
- PhpWsdl::Debug('No cache file');
- return false;// No cache file
- }
- }
- $temp=substr($file,0,1);
- if($temp!='/'&&$temp!='.'){
- if(is_null(PhpWsdl::$CacheFolder)){
- PhpWsdl::Debug('No cache folder');
- return false;// No cache folder
- }
- $file=PhpWsdl::$CacheFolder.'/'.$file;
- }
- if(!$force)
- if($this->IsCacheValid($file)){
- PhpWsdl::Debug('Cache is still valid');
- return true;// Existing cache is still valid
- }
- PhpWsdl::Debug('Write to '.$file);
- if(file_put_contents($file,$wsdl)===false){
- PhpWsdl::Debug('Could not write to cache');
- return false;// Error writing to cache
- }
- if(file_put_contents($file.'.cache',time())===false){
- PhpWsdl::Debug('Could not write cache time file');
- return false;// Error writing to cache
- }
- $data=Array(
- 'version' => self::$VERSION,
- 'servicename' => $this->ServiceName,
- 'endpoint' => $this->EndPoint,
- 'namespace' => $this->NameSpace
- );
- PhpWsdl::CallHook(
- 'ClientWriteCacheHook',
- Array(
- 'client' => $this,
- 'data' => &$data
- )
- );
- if(file_put_contents($file.'.obj',serialize($data))===false){
- PhpWsdl::Debug('Could not write serialized cache');
- return false;
- }
- return true;
- }
-
- /**
- * SOAP method call proxy method
- *
- * @param string $method The method name
- * @param array $param The method parameters
- * @return mixed The server response
- */
- public function __call($method,$param){
- return $this->DoRequest($method,$param);
- }
- }