. */ if(basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__)) exit; // Debugging /*PhpWsdl::$Debugging=true;// Enable debugging PhpWsdl::$DebugFile='./cache/debug.log';// The logfile to write the debugging messages to PhpWsdl::$DebugBackTrace=false;// Include backtrace information in debugging messages?*/ // Initialize PhpWsdl PhpWsdl::Init(); // You don't require class.phpwsdlelement.php and class.phpwsdlcomplex.php, // as long as you don't use complex types. So you may comment those two // requires out. // You may also disable loading the class.phpwsdlproxy.php, if you don't plan // to use the proxy class for your webservice. require_once(dirname(__FILE__).'/class.phpwsdlformatter.php'); require_once(dirname(__FILE__).'/class.phpwsdlobject.php'); require_once(dirname(__FILE__).'/class.phpwsdlparser.php'); require_once(dirname(__FILE__).'/class.phpwsdlproxy.php'); require_once(dirname(__FILE__).'/class.phpwsdlparam.php'); require_once(dirname(__FILE__).'/class.phpwsdlmethod.php'); require_once(dirname(__FILE__).'/class.phpwsdlelement.php'); require_once(dirname(__FILE__).'/class.phpwsdlcomplex.php'); // Classe sobrescrita do SoapServer para gerar log das chamadas webservices require_once(dirname(__FILE__).'/../webServicesServer.class'); // Do things after the environment is configured PhpWsdl::PostInit(); /** * PhpWsdl class * * @author Andreas Zimmermann * @copyright ©2011 Andreas Zimmermann, wan24.de * @version 2.3 */ class PhpWsdl{ /** * The version number * * @var string */ public static $VERSION='2.3'; /** * Set this to TRUE to enable the autorun in quick mode * * @var boolean */ public static $AutoRun=false; /** * Global static configuration * * @var array */ public static $Config=Array(); /** * The webservice handler object * * @var object */ public static $ProxyObject=null; /** * The current PhpWsdl server * * @var PhpWsdl */ public static $ProxyServer=null; /** * Use WSDL with the proxy * * @var boolean */ public static $UseProxyWsdl=false; /** * The name * * @var string */ public $Name; /** * Documentation * * @var string */ public $Docs=null; /** * The namespace * * @var string */ public $NameSpace=null; /** * The SOAP endpoint URI * * @var string */ public $EndPoint=null; /** * Set this to the WSDL URI, if it's different from your SOAP endpoint + "?WSDL" * * @var string */ public $WsdlUri=null; /** * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPSOAPCLIENT" * * @var string */ public $PhpUri=null; /** * Set this to the HTML documentation URI, if it's different from your SOAP endpoint * * @var string */ public $DocUri=null; /** * The options for the PHP SoapServer * Note: "actor" and "uri" will be set at runtime * * @var array */ public $SoapServerOptions=null; /** * An array of file names to parse * * @var string[] */ public $Files=Array(); /** * An array of complex types * * @var PhpWsdlComplex[] */ public $Types=null; /** * An array of method * * @var PhpWsdlMethod[] */ public $Methods=null; /** * Remove tabs and line breaks? * Note: Unoptimized WSDL won't be cached * * @var boolean */ public $Optimize=true; /** * UTF-8 encoded WSDL from the last CreateWsdl method call * * @var string */ public $WSDL=null; /** * UTF-8 encoded HTML from the last OutputHtml method call * * @var string */ public $HTML=null; /** * UTF-8 encoded PHP from the last OutputPhp method call * * @var string */ public $PHP=null; /** * An array of basic types (these are just some of the XSD defined types * (see http://www.w3.org/TR/2001/PR-xmlschema-2-20010330/) * * @var string[] */ public static $BasicTypes=Array( 'anyType', 'anyURI', 'base64Binary', 'boolean', 'byte', 'date', 'decimal', 'double', 'duration', 'dateTime', 'float', 'gDay', 'gMonthDay', 'gYearMonth', 'gYear', 'hexBinary', 'int', 'integer', 'long', 'NOTATION', 'number', 'QName', 'short', 'string', 'time' ); /** * A list of non-nillable types * * @var string[] */ public static $NonNillable=Array( 'boolean', 'decimal', 'double', 'float', 'int', 'integer', 'long', 'number', 'short' ); /** * Set this to a writeable folder to enable caching the WSDL in files * * @var string */ public static $CacheFolder=null; /** * Is the cache folder writeable? * * @var boolean|NULL */ public static $CacheFolderWriteAble=null; /** * The cache timeout in seconds (set to zero to disable caching, too) * If you set the value to -1, the cache will never expire. Then you have * to use the PhpWsdl->TidyCache method for cleaning up the cache once * you've made changes to your webservice. * * @var int */ public static $CacheTime=3600; /** * Write even unoptimized and/or documented XML to the cache? * * @var boolean */ public static $CacheAllWsdl=false; /** * Parse documentation? * * @var boolean */ public $ParseDocs=true; /** * Include documentation tags in WSDL, if the optimizer is disabled? * * @var boolean */ public $IncludeDocs=true; /** * Force sending WSDL (has a higher priority than PhpWsdl->ForceNotOutputWsdl) * * @var boolean */ public $ForceOutputWsdl=false; /** * Force NOT sending WSDL (disable sending WSDL, has a higher priority than ?WSDL f.e.) * * @var boolean */ public $ForceNotOutputWsdl=false; /** * Force sending HTML (has a higher priority than PhpWsdl->ForceNotOutputHtml) * * @var boolean */ public $ForceOutputHtml=false; /** * Force NOT sending HTML (disable sending HTML) * * @var boolean */ public $ForceNotOutputHtml=false; /** * The headline for the HTML output or NULL to use the default * * @var string */ public $HtmlHeadLine=null; /** * Force sending PHP (has a higher priority than PhpWsdl->ForceNotOutputPhp) * * @var boolean */ public $ForceOutputPhp=false; /** * Force NOT sending PHP (disable sending PHP) * * @var boolean */ public $ForceNotOutputPhp=false; /** * Regular expression parse a class name * * @var string */ public static $classRx='/^.*class\s+([^\s]+)\s*\{.*$/is'; /** * The HTML2PDF license key (see www.htmltopdf.de) * * @var string */ public static $HTML2PDFLicenseKey=null; /** * The URI to the HTML2PDF http API * * @var string */ public static $HTML2PDFAPI='http://online.htmltopdf.de/'; /** * The HTML2PDF settings (only available when using a valid license key) * * @var array */ public static $HTML2PDFSettings=Array(); /** * Saves if the sources have been parsed * * @var boolean */ public $SourcesParsed=false; /** * Saves if the configuration has already been determined * * @var boolean */ public $ConfigurationDetermined=false; /** * The current PHP SoapServer object * * @var SoapServer */ public $SoapServer=null; /** * Is a http Auth login required to run the SOAP server? * * @var boolean */ public $RequireLogin=false; /** * Debugging messages * * @var string[] */ public static $DebugInfo=Array(); /** * En- / Disable the debugging mode * * @var boolean */ public static $Debugging=false; /** * The debug file to write to * * @var string */ public static $DebugFile=null; /** * Put backtrace information in debugging messages * * @var boolean */ public static $DebugBackTrace=false; /** * WSDL namespaces * * @var array */ public static $NameSpaces=null; /** * PhpWsdl constructor * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0. * Use PhpWsdl::RunQuickMode() instead * * @param string|boolean $nameSpace Namespace or NULL to let PhpWsdl determine it, or TRUE to run everything by determining all configuration -> quick mode (default: NULL) * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL) * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL) * @param string|string[] $file Filename or array of filenames or NULL (default: NULL) * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL) * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL) * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL) * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE) * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE) */ public function PhpWsdl( $nameSpace=null, $endPoint=null, $cacheFolder=null, $file=null, $name=null, $methods=null, $types=null, $outputOnRequest=false, $runServer=false ){ self::__construct( $nameSpace, $endPoint, $cacheFolder, $file, $name, $methods, $types, $outputOnRequest, $runServer ); } public function __construct( $nameSpace=null, $endPoint=null, $cacheFolder=null, $file=null, $name=null, $methods=null, $types=null, $outputOnRequest=false, $runServer=false ){ // Quick mode self::Debug('PhpWsdl constructor called'); $quickRun=false; if($nameSpace===true){ self::Debug('Quick mode detected'); $quickRun=true; $nameSpace=null; if(!is_null($endPoint)){ if(self::$Debugging) self::Debug('Filename(s): '.print_r($endPoint,true)); $endPoint=null; } } // SOAP server options $this->SoapServerOptions=Array( 'soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'compression' => SOAP_COMPRESSION_ACCEPT|SOAP_COMPRESSION_GZIP|9 ); // Optimizer settings $this->Optimize=!isset($_GET['readable']);// Call with "?WSDL&readable" to get human readable WSDL self::Debug('Optimizer is '.(($this->Optimize)?'enabled':'disabled')); // Cache settings if(!is_null($cacheFolder)){ self::Debug('Cache folder is '.$cacheFolder); self::$CacheFolder=$cacheFolder; } // Namespace $this->NameSpace=(is_null($nameSpace))?$this->DetermineNameSpace():$nameSpace; self::Debug('Namespace is '.$this->NameSpace); // Endpoint $this->EndPoint=((!is_null($endPoint)))?$endPoint:$this->DetermineEndPoint(); self::Debug('Endpoint is '.$this->EndPoint); // Name if(!is_null($name)){ self::Debug('Name is '.$name); $this->Name=$name; } // Source files if(!is_null($file)){ if(self::$Debugging) self::Debug('Filename(s): '.print_r($file,true)); $this->Files=array_merge($this->Files,(is_array($file))?$file:Array($file)); } // Methods $this->Methods=(!is_null($methods))?$methods:Array(); if(sizeof($this->Methods)>0&&self::$Debugging) self::Debug('Methods: '.print_r($this->Methods,true)); // Types $this->Types=(!is_null($types))?$types:Array(); if(sizeof($this->Types)>0&&self::$Debugging) self::Debug('Types: '.print_r($this->Types,true)); // Constructor hook self::CallHook( 'ConstructorHook', Array( 'server' => $this, 'output' => &$outputOnRequest, 'run' => &$runServer, 'quickmode' => &$quickRun ) ); // WSDL output if($outputOnRequest&&!$runServer) $this->OutputWsdlOnRequest(); // Run the server if($quickRun||$runServer) $this->RunServer(null,(is_bool($runServer))?null:$runServer); } /** * Create an instance of PhpWsdl * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0. * Use PhpWsdl::RunQuickMode() instead * * @param string|boolean $nameSpace Namespace or NULL to let PhpWsdl determine it, or TRUE to run everything by determining all configuration -> quick mode (default: NULL) * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL) * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL) * @param string|string[] $file Filename or array of filenames or NULL (default: NULL) * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL) * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL) * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL) * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE) * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE) * @return PhpWsdl The PhpWsdl object */ public static function CreateInstance( $nameSpace=null, $endPoint=null, $cacheFolder=null, $file=null, $name=null, $methods=null, $types=null, $outputOnRequest=false, $runServer=false ){ self::Debug('Create new PhpWsdl instance'); $obj=null; self::CallHook( 'BeforeCreateInstanceHook', Array( 'server' => &$obj, 'namespace' => &$nameSpace, 'endpoint' => &$endPoint, 'cachefolder' => &$cacheFolder, 'file' => &$file, 'name' => &$name, 'methods' => &$methods, 'types' => &$types, 'outputonrequest'=> &$outputOnRequest, 'runserver' => &$runServer ) ); if(is_null($obj)) $obj=new PhpWsdl($nameSpace,$endPoint,$cacheFolder,$file,$name,$methods,$types,$outputOnRequest,$runServer); self::CallHook( 'CreateInstanceHook', Array( 'server' => &$obj ) ); return $obj; } /** * Run the PhpWsdl SOAP server in quick mode * * @param string|string[] $file The webservice handler class file or a list of files or NULL (default: NULL) */ public static function RunQuickMode($file=null){ self::Debug('Run quick mode'); $server=self::CreateInstance(); if(!is_null($file)) $server->Files=(is_array($file))?$file:Array($file); $server->RunServer(); } /** * Determine if WSDL was requested by the client * * @return boolean WSDL requested? */ public function IsWsdlRequested(){ return $this->ForceOutputWsdl||((isset($_GET['wsdl'])||isset($_GET['WSDL']))&&!$this->ForceNotOutputWsdl); } /** * Determine if HTML was requested by the client * * @return boolean HTML requested? */ public function IsHtmlRequested(){ return $this->ForceOutputHtml||(strlen(file_get_contents('php://input'))<1&&!$this->ForceNotOutputHtml); } /** * Determine if PHP was requested by the client * * @return boolean PHP requested? */ public function IsPhpRequested(){ return $this->ForceOutputPhp||((isset($_GET['phpsoapclient'])||isset($_GET['PHPSOAPCLIENT']))&&!$this->ForceNotOutputPhp); } /** * Determine if this request is a SOAP request * * @return boolean */ public function IsSoapRequest(){ return !$this->IsHtmlRequested()&&!$this->IsWsdlRequested()&&!$this->IsPhpRequested(); } /** * Determine if only global methods are served * * @return boolean Only global methods? */ public function IsOnlyGlobal(){ $res=true; $i=-1; $len=sizeof($this->Methods); while(++$i<$len) if(!$this->Methods[$i]->IsGlobal){ $res=false; break; } return $res; } /** * Disble caching * * @param bool $allCaching Do not only set the timeout to zero? (default: TRUE) */ public static function DisableCache($allCaching=true){ self::Debug('Disable '.(($allCaching)?'all':'this').' caching'); if($allCaching) self::$CacheFolder=null; if(!$allCaching) self::$CacheTime=0; } /** * Enable caching * * @param string $folder The cache folder or NULL to use a system temporary directory (default: NULL) * @param int $timeout The caching timeout in seconds or NULL to use the previous value or the default (3600) (default: NULL) */ public static function EnableCache($folder=null,$timeout=null){ if(is_null($folder)){ if(self::IsCacheFolderWriteAble('./cache')){ $folder='./cache'; }else if(self::IsCacheFolderWriteAble(dirname(__FILE__).'/cache')){ $folder=dirname(__FILE__).'/cache'; }else if(self::IsCacheFolderWriteAble(sys_get_temp_dir())){ $folder=sys_get_temp_dir(); }else{ self::Debug('Could not find a cache folder'); } } if(is_null($timeout)) $timeout=(self::$CacheTime!=0)?self::$CacheTime:3600; self::Debug('Enable cache in folder "'.((is_null($folder))?'(none)':$folder).'" with timeout '.$timeout.' seconds'); self::$CacheFolder=$folder; self::$CacheTime=$timeout; } /** * Determine the configuration * * @return boolean Succeed? */ public function DetermineConfiguration(){ if(!is_null($this->GetWsdlFromCache())) return true; $this->ParseSource(); $mLen=sizeof($this->Methods); $tLen=sizeof($this->Types); $fLen=sizeof($this->Files); if($this->ConfigurationDetermined) return ($mLen>0||$tLen>0)&&!is_null($this->Name); self::Debug('Determine configuration'); $this->ConfigurationDetermined=true; $tryWebService= !$this->IsFileInList('class.webservice.php')&& ( file_exists('class.webservice.php')|| file_exists(dirname(__FILE__).'/class.webservice.php') ); // No methods or types? Try to parse them from the current script if($mLen<1&&$tLen<1){ $tryFiles=Array(); if($tryWebService){ if(file_exists('class.webservice.php')) $tryFiles[]='class.webservice.php'; if(file_exists(dirname(__FILE__).'/class.webservice.php')) $tryFiles[]=dirname(__FILE__).'/class.webservice.php'; } if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME'])) $tryFiles[]=$_SERVER['SCRIPT_FILENAME']; $i=-1; $len=sizeof($tryFiles); while(++$i<$len){ $file=$tryFiles[$i]; self::Debug('Try to load objects from '.$file); $this->ParseSource(false,file_get_contents($file)); $mLen=sizeof($this->Methods); $tLen=sizeof($this->Types); if($mLen<1&&$tLen<1) continue; self::Debug('Found objects, adding the file to list'); $this->Files[]=$file; $fLen++; break; } if($mLen<1&&$tLen<1) return false; } // No class name? Try to parse one from the current files if(!is_null($this->Name)) return true; $tryFiles=Array(); if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME'])) $tryFiles[]=$_SERVER['SCRIPT_FILENAME']; if($tryWebService){ if(file_exists('class.webservice.php')) $tryFiles[]='class.webservice.php'; if(file_exists(dirname(__FILE__).'/class.webservice.php')) $tryFiles[]=dirname(__FILE__).'/class.webservice.php'; } $tryFiles=array_merge($this->Files,$tryFiles); $i=-1; $len=sizeof($tryFiles); while(++$i<$len){ $file=$tryFiles[$i]; self::Debug('Try to determine the class name from '.$file); $temp=file_get_contents($file); if(!preg_match(self::$classRx,$temp)) continue; $class=preg_replace(self::$classRx,"$1",$temp); self::Debug('Found class name '.$class); break; } // No class name yet? Use the default if only global methods are present if(is_null($class)&&$this->IsOnlyGlobal()){ self::Debug('Using default webservice name'); $class='SoapWebService'; } $this->Name=$class; return !is_null($class); } /** * Determine the endpoint URI */ public function DetermineEndPoint(){ return ((isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']=='on')?'https':'http').'://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; } /** * Determine the namespace */ public function DetermineNameSpace() { $protocolo = 'http'; if( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ) { $protocolo = 'https'; } return $protocolo . '://'.$_SERVER['SERVER_NAME'].str_replace(basename($_SERVER['SCRIPT_NAME']),'',$_SERVER['SCRIPT_NAME']); } /** * Determine if a file is included in the list of files * * @param string $file The filename * @return boolean In the list? */ public function IsFileInList($file){ $file=preg_quote(basename($file)); $i=-1; $fLen=sizeof($this->Files); while(++$i<$fLen) if(preg_match('/^(.*\/)?'.$file.'$/i',$this->Files[$i])) return true; return false; } /** * Create the WSDL * * @param boolean $reCreate Don't use the cached WSDL? (default: FALSE) * @param boolean $optimize If TRUE, override the PhpWsdl->Optimizer property and force optimizing (default: FALSE) * @return string The UTF-8 encoded WSDL as string */ public function CreateWsdl($reCreate=false,$optimizer=false){ self::Debug('Create WSDL'); // Ask the cache if(!$reCreate&&(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize)){ self::Debug('Try to get WSDL from the cache'); $wsdl=$this->GetWsdlFromCache(); if(!is_null($wsdl)){ self::Debug('Using cached WSDL'); return (!$optimizer&&!$this->Optimize)?self::FormatXml($wsdl):$wsdl; } } // Prepare the WSDL generator if(!$this->DetermineConfiguration()){ $mLen=sizeof($this->Methods); $tLen=sizeof($this->Types); if($mLen<1&&$tLen<1){ self::Debug('No methods and types'); throw(new Exception('No methods and no complex types are available')); } if(is_null($this->Name)){ self::Debug('No name'); throw(new Exception('Could not determine webservice handler class name')); } } $res=Array(); // Create the XML Header self::CallHook( 'CreateWsdlHeaderHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Create types self::CallHook( 'CreateWsdlTypeSchemaHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Create messages self::CallHook( 'CreateWsdlMessagesHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Create port types self::CallHook( 'CreateWsdlPortsHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Create bindings self::CallHook( 'CreateWsdlBindingsHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Create the service self::CallHook( 'CreateWsdlServiceHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Finish the WSDL XML string self::CallHook( 'CreateWsdlFooterHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Run the optimizer self::CallHook( 'CreateWsdlOptimizeHook', Array( 'server' => $this, 'res' => &$res, 'optimizer' => &$optimizer ) ); // Fill the cache if(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize){ self::Debug('Cache created WSDL'); $this->WriteWsdlToCache( ( !self::$CacheAllWsdl&& !$optimizer&& !$this->Optimize ) ?self::OptimizeXml($res) :$res , null, null, true ); } return $this->WSDL; } /** * Create header * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlHeader($data){ self::Debug('CreateWsdlHeader'); $res=&$data['res']; $server=$data['server']; $res[]=''; $temp=Array(); $keys=array_keys(self::$NameSpaces); $i=-1; $len=sizeof($keys); while(++$i<$len) $temp[]='xmlns:'.$keys[$i].'="'.self::$NameSpaces[$keys[$i]].'"'; $res[]=''; return true; } /** * Create type schema * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlTypeSchema($data){ self::Debug('CreateWsdlTypeSchema'); $res=&$data['res']; $server=$data['server']; $tLen=sizeof($server->Types); if($tLen>0){ $res[]=''; $res[]=''; $i=-1; while(++$i<$tLen) $res[]=$server->Types[$i]->CreateType($server); self::CallHook( 'CreateWsdlTypesHook', $data ); $res[]=''; $res[]=''; } return true; } /** * Create messages * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlMessages($data){ self::Debug('CreateWsdlMessages'); $res=&$data['res']; $server=$data['server']; $i=-1; $mLen=sizeof($server->Methods); while(++$i<$mLen) $res[]=$server->Methods[$i]->CreateMessages($server); return true; } /** * Create port types * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlPorts($data){ self::Debug('CreateWsdlPorts'); $res=&$data['res']; $server=$data['server']; $res[]=''; $i=-1; $mLen=sizeof($server->Methods); while(++$i<$mLen) $res[]=$server->Methods[$i]->CreatePortType($server); self::CallHook( 'CreateWsdlPortsAddHook', $data ); $res[]=''; return true; } /** * Create bindings * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlBindings($data){ self::Debug('CreateWsdlBindings'); $res=&$data['res']; $server=$data['server']; $res[]=''; $res[]=''; $i=-1; $mLen=sizeof($server->Methods); while(++$i<$mLen) $res[]=$server->Methods[$i]->CreateBinding($server); self::CallHook( 'CreateWsdlBindingsAddHook', $data ); $res[]=''; return true; } /** * Create service port * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlService($data){ self::Debug('CreateWsdlService'); $res=&$data['res']; $server=$data['server']; $res[]=''; if($server->IncludeDocs&&!$server->Optimize&&!is_null($server->Docs)) $res[]='Docs.']]>'; $res[]=''; $res[]=''; $res[]=''; self::CallHook( 'CreateWsdlServiceAddHook', $data ); $res[]=''; return true; } /** * Create footer * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlFooter($data){ self::Debug('CreateWsdlFooter'); $res=&$data['res']; $res[]=''; return true; } /** * Optimize WSDL * * @param array $data Data array * @return boolean Response */ public static function CreateWsdlOptimize($data){ self::Debug('CreateWsdlOptimize'); $res=&$data['res']; $server=$data['server']; $optimizer=&$data['optimizer']; $res=implode('',$res); $res=(!$optimizer&&!$server->Optimize) ?self::FormatXml($res) :self::OptimizeXml($res); $server->WSDL=$res; return true; } /** * Remove tabs and newline from XML * * @param string $xml The unoptimized XML * @return string The optimized XML */ public static function OptimizeXml($xml){ self::Debug('Optimize XML'); return preg_replace('/[\n|\t]/','',$xml); } /** * Format XML human readable * * @param string $xml The XML * @return string Human readable XML */ public static function FormatXml($xml){ self::Debug('Produce human readable XML'); $input=fopen('data://text/plain,'.$xml,'r'); $output=fopen('php://temp','w'); $xf=new PhpWsdlFormatter($input,$output); $xf->format(); rewind($output); $xml=stream_get_contents($output); fclose($input); fclose($output); return $xml; } /** * Interpret the @service keyword * * @param $data The parser data * @return boolean Response */ public static function InterpretService($data){ self::Debug('Interpret service'); $server=$data['server']; $info=explode(' ',$data['keyword'][1],2); if(sizeof($info)<1){ self::Debug('WARNING: Invalid service definition'); return true; } $server->Name=$info[0]; if($server->ParseDocs&&sizeof($info)>1&&is_null($server->Docs)) $server->Docs=$info[1]; return true; } /** * Parse source files for WSDL definitions in comments * * @param boolean $init Empty the Methods and the Types properties? (default: FALSE) * @param string $str Source string or NULL to parse the defined files (default: NULL) */ public function ParseSource($init=false,$str=null){ self::Debug('Parse the source'); if($init){ self::Debug('Init methods and types'); $this->Methods=Array(); $this->Types=Array(); $this->SourcesParsed=false; } if(is_null($str)){ if($this->SourcesParsed) return; self::Debug('Load source files'); $this->SourcesParsed=true; $fLen=sizeof($this->Files); if($fLen<1) return; // Load the source $src=Array(); $i=-1; while(++$i<$fLen) $src[]=trim(file_get_contents($this->Files[$i])); }else{ self::Debug('Use given string'); $src=Array($str); } // Parse the source self::Debug('Run the parser'); $parser=new PhpWsdlParser($this); $parser->Parse(implode("\n",$src)); } /** * Output the WSDL to the client * * @param boolean $withHeaders Output XML headers? (default: TRUE) */ public function OutputWsdl($withHeaders=true){ if(!self::CallHook( 'OutputWsdlHook', Array( 'server' => $this ) ) ) return; self::Debug('Output WSDL'); if($withHeaders) header('Content-Type: text/xml; charset=UTF-8',true); echo $this->CreateWsdl(); } /** * Output the WSDL to the client, if requested * * @param boolean $andExit Exit after sending WSDL? (default: TRUE) * @return boolean Has the WSDL been sent to the client? */ public function OutputWsdlOnRequest($andExit=true){ if(!$this->IsWsdlRequested()) return false; $this->OutputWsdl(); if($andExit){ self::Debug('Exit script execution'); exit; } return true; } /** * Output the HTML to the client * * @param boolean $withHeaders Send HTML headers? (default: TRUE) * @param boolean $echo Print HTML (default: TRUE) * @param boolean $cache Cache the result (default: TRUE); * @return string The HTML */ public function OutputHtml($withHeaders=true,$echo=true,$cache=true){ self::Debug('Output HTML'); if(sizeof($this->Methods)<1) $this->CreateWsdl(); if(!self::CallHook( 'OutputHtmlHook', Array( 'server' => $this ) ) ) return; // Header if($withHeaders) header('Content-Type: text/html; charset=UTF-8',true); $this->GetWsdlFromCache(); if(!is_null($this->HTML)){ if($echo) echo $this->HTML; return $this->HTML; } $res=Array(); $res[]=''; $res[]=''; $res[]=''.((is_null($this->HtmlHeadLine))?$this->Name.' interface description':nl2br(htmlentities($this->HtmlHeadLine))).''; $res[]=''; $res[]=''; $res[]=''; $res[]=''; $types=$this->SortObjectsByName($this->Types); $methods=$this->SortObjectsByName($this->Methods); // General information self::CallHook( 'CreateHtmlGeneralHook', Array( 'server' => $this, 'res' => &$res, 'methods' => &$methods, 'types' => &$types ) ); // Index self::CallHook( 'CreateHtmlIndexHook', Array( 'server' => $this, 'res' => &$res, 'methods' => &$methods, 'types' => &$types ) ); // Complex types self::CallHook( 'CreateHtmlComplexTypesHook', Array( 'server' => $this, 'res' => &$res, 'methods' => &$methods, 'types' => &$types ) ); // Methods self::CallHook( 'CreateHtmlMethodsHook', Array( 'server' => $this, 'res' => &$res, 'methods' => &$methods, 'types' => &$types ) ); // HTML2PDF link $param=Array( 'plain' => '1', 'filename' => $this->Name.'-webservices.pdf', 'print' => '1' ); if(!is_null(self::$HTML2PDFLicenseKey)){ // Use advanced HTML2PDF API $temp=array_merge(self::$HTML2PDFSettings,Array( 'url' => $this->GetDocUri() )); if($temp['attachments']=='1'){ $temp['attachment_1']=$this->Name.'.wsdl:'.$this->GetWsdlUri(); $cnt=1; if($this->ParseDocs&&$this->IncludeDocs){ $cnt=2; $temp['attachment_2']=$this->Name.'-doc.wsdl:'.$this->GetWsdlUri().'&readable'; } $cnt++; $temp['attachment_'.$cnt]=$this->Name.'.soapclient.php:'.$this->GetPhpUri(); self::CallHook( 'PdfAttachmentHook', Array( 'server' => $this, 'cnt' => &$cnt, 'param' => &$temp, 'res' => &$res, 'methods' => &$methods, 'types' => &$types ) ); } $options=Array(); $keys=array_keys($temp); $i=-1; $len=sizeof($keys); while(++$i<$len) $options[]=$keys[$i].'='.$temp[$keys[$i]]; $options='$'.base64_encode(implode("\n",$options)); $license=sha1(self::$HTML2PDFLicenseKey.self::$HTML2PDFLicenseKey).'-'.sha1($options.self::$HTML2PDFLicenseKey); $param['url']=$options; $param['license']=$license; } $temp=$param; $param=Array(); $keys=array_keys($temp); $i=-1; $len=sizeof($keys); while(++$i<$len) $param[]=urlencode($keys[$i]).'='.urlencode($temp[$keys[$i]]); $pdfLink=self::$HTML2PDFAPI.'?'.implode('&',$param); // Footer $res[]='
'; $res[]='

Powered by PhpWsdl - PDF download: Download this page as PDF

'; $res[]=''; $res[]=''; // Clean up the generated HTML and send it $res=implode("\n",$res); $res=str_replace('
','
',$res);// Because nl2br will produce XHTML (and nothing if the second parameter is FALSE!?) if(!self::CallHook( 'SendHtmlHook', Array( 'server' => $this, 'res' => &$res ) ) ) return; $res=$res; $this->HTML=$res; if($cache) $this->WriteWsdlToCache(null,null,null,true); if($echo) echo $res; return $res; } /** * Create general information * * @param array $data The information object * @return boolean Response */ public static function CreateHtmlGeneral($data){ self::Debug('CreateHtmlGeneral'); $res=&$data['res']; $server=$data['server']; $res[]='

'.$server->Name.' SOAP WebService interface description

'; $res[]='

Endpoint URI: '.$server->EndPoint.'

'; $res[]='

WSDL URI: '.$server->GetWsdlUri().'

'; $res[]='

PHP SOAP client download URI: '.$server->GetPhpUri().'

'; if(self::$HTML2PDFSettings['attachments']=='1'&&!is_null(self::$HTML2PDFLicenseKey)) $res[]='

The WSDL files and client proxy class(es) are attached to this PDF documentation.

'; if(!is_null($server->Docs)) $res[]='

'.nl2br(htmlentities($server->Docs)).'

'; return true; } /** * Create table of contents * * @param array $data The information object * @return boolean Response */ public static function CreateHtmlIndex($data){ self::Debug('CreateHtmlIndex'); $res=&$data['res']; $types=&$data['types']; $methods=&$data['methods']; $tLen=sizeof($types); $mLen=sizeof($methods); $res[]='
'; $res[]='

Index

'; if($tLen>0){ $res[]='

Complex types:

'; $i=-1; $res[]=''; } if($mLen>0){ $res[]='

Public methods:

'; $i=-1; $res[]=''; } $res[]='
'; return true; } /** * Create method list * * @param array $data The information object * @return boolean Response */ public static function CreateHtmlMethods($data){ self::Debug('CreateHtmlMethods'); $res=&$data['res']; $methods=&$data['methods']; $mLen=sizeof($methods); if($mLen>0){ $res[]='

Public methods

'; $i=-1; while(++$i<$mLen) $methods[$i]->CreateMethodHtml(array_merge( $data, Array( 'method' => $methods[$i] ) )); } return true; } /** * Create complex types list * * @param array $data The information object * @return boolean Response */ public static function CreateHtmlComplexTypes($data){ self::Debug('CreateHtmlComplexTypes'); $res=&$data['res']; $types=&$data['types']; $server=$data['server']; $tLen=sizeof($server->Types); if($tLen>0){ $res[]='

Complex types

'; $i=-1; while(++$i<$tLen) $types[$i]->CreateTypeHtml(array_merge( $data, Array( 'type' => $types[$i] ) )); } return true; } /** * Sort objects by name * * @param PhpWsdlComplex[]|PhpWsdlMethod[] $obj * @return PhpWsdlComplex[]|PhpWsdlMethod[] Sorted objects */ public function SortObjectsByName($obj){ self::Debug('Sort objects by name'); $temp=Array(); $i=-1; $len=sizeof($obj); while(++$i<$len) $temp[$obj[$i]->Name]=$obj[$i]; $keys=array_keys($temp); sort($keys); $res=Array(); $i=-1; while(++$i<$len) $res[]=$temp[$keys[$i]]; return $res; } /** * Output the HTML to the client, if requested * * @param boolean $andExit Exit after sending HTML? (default: TRUE) * @return boolean Has the HTML been sent to the client? */ public function OutputHtmlOnRequest($andExit=true){ if(!$this->IsHtmlRequested()) return false; $this->OutputHtml(); if($andExit){ self::Debug('Exit script execution'); exit; } return true; } /** * Output the PHP SOAP client source for this webservice * * @param boolean $withHeaders Send text headers? (default: TRUE) * @param boolean $echo Print source (default: TRUE) * @param array $options Options array (default: array) * @param boolean $cache Cache the result (default: TRUE); * @return string PHP source */ public function OutputPhp($withHeaders=true,$echo=true,$options=Array(),$cache=true){ self::Debug('Output PHP'); if(sizeof($this->Methods)<1) $this->CreateWsdl(); if(!self::CallHook( 'OutputPhpHook', Array( 'server' => $this, 'withHeaders' => &$withHeaders, 'echo' => &$echo, 'options' => &$options ) ) ) return ''; // Options $hasOptions=sizeof(array_keys($options))>0; if(!isset($options['class'])) $options['class']=$this->Name.'SoapClient'; if(!isset($options['openphp'])) $options['openphp']=true; if(!isset($options['phpclient'])) $options['phpclient']=true; $data=Array( 'server' => $this, 'withHeaders' => &$withHeaders, 'echo' => &$echo, 'options' => &$options, 'res' => &$res ); // Header if($withHeaders){ header('Content-Type: text/plain; charset=UTF-8',true); header('Content-Disposition: attachment; filename='.$options['class'].'.php'); } if(!$hasOptions){ if(is_null($this->PHP)) $this->GetWsdlFromCache(); if(!is_null($this->PHP)){ if($echo) echo $this->PHP; return $this->PHP; } }else if(isset($options['php'])&&!is_null($options['php'])){ echo $options['php']; return $options['php']; } $res=Array(); if($options['openphp']) $res[]="Docs)){ $res[]=" * ".implode("\n * ",explode("\n",$this->Docs)); $res[]=" *"; } $res[]=" * @service ".$options['class']; $res[]=" */"; $res[]="class ".$options['class']."{"; $res[]="\t/**"; $res[]="\t * The WSDL URI"; $res[]="\t *"; $res[]="\t * @var string"; $res[]="\t */"; $res[]="\tpublic static \$_WsdlUri='".(!is_null($this->WsdlUri)?$this->WsdlUri:$this->EndPoint.'?WSDL')."';"; $res[]="\t/**"; $res[]="\t * The PHP SoapClient object"; $res[]="\t *"; $res[]="\t * @var object"; $res[]="\t */"; $res[]="\tpublic static \$_Server=null;"; self::CallHook('BeginCreatePhpHook',$data); $res[]=''; $res[]="\t/**"; $res[]="\t * Send a SOAP request to the server"; $res[]="\t *"; $res[]="\t * @param string \$method The method name"; $res[]="\t * @param array \$param The parameters"; $res[]="\t * @return mixed The server response"; $res[]="\t */"; $res[]="\tpublic static function _Call(\$method,\$param){"; if(self::CallHook('CreatePhpCallHook',$data)){ $res[]="\t\tif(is_null(self::\$_Server))"; if($options['phpclient']){ $res[]="\t\t\tself::\$_Server=new SoapClient(self::\$_WsdlUri);"; $res[]="\t\treturn self::\$_Server->__soapCall(\$method,\$param);"; }else{ $res[]="\t\t\tself::\$_Server=new PhpWsdlClient(self::\$_WsdlUri);"; $res[]="\t\treturn self::\$_Server->DoRequest(\$method,\$param);"; } } $res[]="\t}"; // Methods $i=-1; $len=sizeof($this->Methods); while(++$i<$len){ $res[]=''; $this->Methods[$i]->CreateMethodPhp($data); } $res[]="}"; // Types $i=-1; $len=sizeof($this->Types); while(++$i<$len){ $res[]=''; $this->Types[$i]->CreateTypePhp($data); } self::CallHook('EndCreatePhpHook',$data); $res=implode("\n",$res); if(!$hasOptions){ if(is_null($this->PHP)) $this->PHP=$res; if($cache) $this->WriteWsdlToCache(null,null,null,true); } if($echo) echo $res; return $res; } /** * Output the PHP SOAP client source for this webservice, if requested * * @param boolean $andExit Exit after sending the PHP source? * @return boolean PHP sent? */ public function OutputPhpOnRequest($andExit=true){ if(!$this->IsPhpRequested()) return false; $this->OutputPhp(); if($andExit){ self::Debug('Exit script execution'); exit; } return true; } /** * Run the PHP SoapServer * * @param string $wsdlFile The WSDL file name or NULL to let PhpWsdl decide (default: NULL) * @param string|object|array $class The class name to serve, the classname and class as array or NULL (default: NULL) * @param boolean $andExit Exit after running the server? (default: TRUE) * @param boolean $forceNoWsdl Force no WSDL usage? (default: FALSE); * @return boolean Did the server run? */ public function RunServer($wsdlFile=null,$class=null,$andExit=true,$forceNoWsdl=false){ self::Debug('Run the server'); if($forceNoWsdl) self::Debug('Forced non-WSDL mode'); if(self::CallHook( 'BeforeRunServerHook', Array( 'server' => $this, 'wsdlfile' => &$wsdlFile, 'class' => &$class, 'andexit' => &$andExit, 'forcenowsdl' => &$forceNoWsdl ) ) ){ // WSDL requested? if($this->OutputWsdlOnRequest($andExit)) return false; // PHP requested? if($this->OutputPhpOnRequest($andExit)) return false; // HTML requested? if($this->OutputHtmlOnRequest($andExit)) return false; } // Login $user=null; $password=null; if($this->RequireLogin){ if(isset($_SERVER['PHP_AUTH_USER'])||isset($_SERVER['PHP_AUTH_PW'])){ $user=(isset($_SERVER['PHP_AUTH_USER']))?$_SERVER['PHP_AUTH_USER']:null; $password=(isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW']:null; } self::Debug('Check login '.$user.':'.str_repeat('*',strlen($password))); if(!self::CallHook( 'LoginHook', Array( 'server' => $this, 'user' => &$user, 'password' => &$password ) ) ){ self::Debug('Login required'); header('WWW-Authenticate: Basic realm="SOAP webservice login required"'); header('HTTP/1.0 401 Unauthorized'); if($andExit){ self::Debug('Exit script execution'); exit; } return false; } } // Load the proxy $useProxy=false; if(is_array($class)){ self::Debug('Use the proxy for '.$class[0]); self::$ProxyObject=$class[1]; self::$ProxyServer=$this; $class=$class[0]; $useProxy=true; } // Ensure a webservice name if(is_null($class)){ self::Debug('No webservice name yet'); if(!$this->DetermineConfiguration()) throw(new Exception('Invalid configuration')); if(!is_null($this->Name)) $class=$this->Name; }else if(is_string($class)){ self::Debug('Using '.$class.' as webservice name'); $this->Name=$class; } self::Debug('Use class '.((!is_object($class))?$class:get_class($class))); // Load WSDL if(!$forceNoWsdl&&(!$useProxy||self::$UseProxyWsdl)){ self::Debug('Load WSDL'); $this->CreateWsdl(false,true); if(is_null($wsdlFile)) $wsdlFile=$this->GetCacheFileName(); if(!is_null($wsdlFile)) if(!file_exists($wsdlFile)){ self::Debug('WSDL file "'.$wsdlFile.'" does not exists'); $wsdlFile=null; } } // Load the files, if the webservice handler class doesn't exist if(!is_object($class)) if(!class_exists($class)&&!$this->IsOnlyGlobal()){ self::Debug('Try to load the webservice handler class'); $i=-1; $len=sizeof($this->Files); while(++$i<$len){ self::Debug('Load '.$this->Files[$i]); require_once($this->Files[$i]); } if(!class_exists($class)){ // Try class.webservice.php if(file_exists('class.webservice.php')){ self::Debug('Try to load class.webservice.php'); require_once('class.webservice.php'); if(class_exists($class)) $this->Files[]='class.webservice.php'; } if(!class_exists($class)) if(file_exists(dirname(__FILE__).'/class.webservice.php')){ self::Debug('Try to load '.dirname(__FILE__).'/class.webservice.php'); require_once(dirname(__FILE__).'/class.webservice.php'); if(class_exists($class)) $this->Files[]=dirname(__FILE__).'/class.webservice.php'; } if(!class_exists($class)) // A handler class or object is required when using non-global methods! throw(new Exception('Webservice handler class not present')); } } // Prepare the SOAP server $this->SoapServer=null; if(self::CallHook( 'PrepareServerHook', Array( 'server' => $this, 'soapserver' => &$this->SoapServer, 'wsdlfile' => &$wsdlFile, 'class' => &$class, 'useproxy' => &$useProxy, 'forcenowsdl' => &$forceNoWsdl, 'andexit' => &$andExit, 'user' => &$user, 'password' => &$password ) ) ){ self::Debug('Prepare the SOAP server'); // WSDL file $wsdlFile=($forceNoWsdl||($useProxy&&!self::$UseProxyWsdl))?null:$wsdlFile; if(!is_null($wsdlFile)){ self::Debug('Using WSDL file '.$wsdlFile); }else{ self::Debug('No WSDL file'); } // Server options $temp=Array( 'actor' => $this->EndPoint, 'uri' => $this->NameSpace, ); $temp=array_merge($this->SoapServerOptions,$temp); if(self::$Debugging) self::Debug('Server options: '.print_r($temp,true)); // Create the server object self::Debug('Creating PHP SoapServer object'); $this->SoapServer=new webServicesServer( $wsdlFile, $temp ); // Set the handler class or object if($useProxy||!is_object($class)){ $temp=($useProxy)?'PhpWsdlProxy':$class; if(!is_null($temp)){ self::Debug('Setting server class '.$temp); $this->SoapServer->setClass($temp); }else{ self::Debug('No server class or object'); } }else{ self::Debug('Setting server object '.get_class($class)); $this->SoapServer->setObject($class); } // Add global methods $i=-1; $len=sizeof($this->Methods); while(++$i<$len) if($this->Methods[$i]->IsGlobal){ self::Debug('Adding global method '.$this->Methods[$i]->Name); $this->SoapServer->addFunction($this->Methods[$i]->Name); } } // Run the SOAP server if(self::CallHook( 'RunServerHook', Array( 'server' => $this, 'soapserver' => &$this->SoapServer, 'wsdlfile' => &$wsdlFile, 'class' => &$class, 'useproxy' => &$useProxy, 'forcenowsdl' => &$forceNoWsdl, 'andexit' => &$andExit, 'user' => &$user, 'password' => &$password ) ) ){ self::Debug('Run the SOAP server'); $this->SoapServer->handle(); if($andExit){ self::Debug('Exit script execution'); exit; } } return true; } /** * Get the WSDL download URI * * @return string The Uri */ public function GetWsdlUri(){ return ((is_null($this->WsdlUri))?$this->EndPoint:$this->WsdlUri).'?WSDL'; } /** * Get the PHP download URI * * @return string The URI */ public function GetPhpUri(){ return ((is_null($this->PhpUri))?$this->EndPoint:$this->PhpUri).'?PHPSOAPCLIENT'; } /** * Get the HTML documentation URI * * @return string The Uri */ public function GetDocUri(){ return (is_null($this->PhpUri))?$this->EndPoint:$this->DocUri; } /** * Find a method * * @param string $name The method name * @return PhpWsdlMethod The method object or NULL */ public function GetMethod($name){ self::Debug('Find method '.$name); $i=-1; $len=sizeof($this->Methods); while(++$i<$len) if($this->Methods[$i]->Name==$name){ self::Debug('Found method at index '.$i); return $this->Methods[$i]; } return null; } /** * Find a complex type * * @param string $name The type name * @return PhpWsdlComplex The type object or NULL */ public function GetType($name){ self::Debug('Find type '.$name); $i=-1; $len=sizeof($this->Types); while(++$i<$len) if($this->Types[$i]->Name==$name){ self::Debug('Found type at index '.$i); return $this->Types[$i]; } return null; } /** * Get the cache filename * * @param string $endpoint The endpoint URI or NULL to use the PhpWsdl->EndPoint property (default: NULL) * @return string The cache filename or NULL, if caching is disabled */ public function GetCacheFileName($endpoint=null){ $data=Array( 'server' => $this, 'endpoint' => $endpoint, 'filename' => (is_null(self::$CacheFolder))?null:self::$CacheFolder.'/'.sha1((is_null($endpoint))?$this->EndPoint:$endpoint).'.wsdl' ); self::CallHook( 'CacheFileNameHook', $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(); self::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){ self::Debug('Check cache valid'); if(is_null($file)) $file=$this->GetCacheFileName(); if(!$this->CacheFileExists($file)) return false; return self::$CacheTime<0||time()-file_get_contents($file.'.cache')<=self::$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){ self::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){ self::Debug('Unserialize methods, types and files'); $data=unserialize(file_get_contents($file.'.obj')); $this->Methods=$data['methods']; $this->Types=$data['types']; $this->Files=$data['files']; $this->Name=$data['name']; $this->Docs=$data['docs']; $this->HTML=$data['html']; $this->PHP=$data['php']; $this->WsdlUri=$data['wsdluri']; $this->PhpUri=$data['phpuri']; $this->DocUri=$data['docuri']; self::CallHook( 'ReadCacheHook', Array( 'server' => $this, 'data' => &$data ) ); if($data['version']!=self::$VERSION){ self::Debug('Could not use cache from version '.$data['version']); $this->Methods=Array(); $this->Types=Array(); $this->Files=Array(); $this->Name=null; $this->Docs=null; $this->HTML=null; $this->PHP=null; $this->WsdlUri=null; $this->PhpUri=null; $this->DocUri=null; $this->WSDL=null; $this->TidyCacheFolder(true); return null; } } $this->ConfigurationDetermined=true; $this->SourcesParsed=true; return $this->WSDL; } /** * Write WSDL to cache * * @param string $wsdl The UTF-8 encoded WSDL string (default: NULL) * @param string $endpoint The SOAP endpoint 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,$endpoint=null,$file=null,$force=false){ self::Debug('Write WSDL to the cache'); if(is_null($endpoint)) $endpoint=$this->EndPoint; if($endpoint==$this->EndPoint&&!is_null($wsdl)) $this->WSDL=$wsdl; if(is_null($wsdl)){ if(is_null($this->WSDL)){ self::Debug('No WSDL'); return false;// WSDL not defined } $wsdl=$this->WSDL; } if(is_null($file)){ $file=$this->GetCacheFileName($endpoint); if(is_null($file)){ self::Debug('No cache file'); return false;// No cache file } } $temp=substr($file,0,1); if($temp!='/'&&$temp!='.'){ if(is_null(self::$CacheFolder)){ self::Debug('No cache folder'); return false;// No cache folder } $file=self::$CacheFolder.'/'.$file; } if(!$force) if($this->IsCacheValid($file)){ self::Debug('Cache is still valid'); return true;// Existing cache is still valid } self::Debug('Write to '.$file); if(file_put_contents($file,$wsdl)===false){ self::Debug('Could not write to cache'); return false;// Error writing to cache } if(file_put_contents($file.'.cache',time())===false){ self::Debug('Could not write cache time file'); return false;// Error writing to cache } $data=Array( 'version' => self::$VERSION, 'methods' => $this->Methods, 'types' => $this->Types, 'files' => $this->Files, 'name' => $this->Name, 'docs' => $this->Docs, 'html' => $this->HTML, 'php' => $this->PHP, 'wsdluri' => $this->WsdlUri, 'phpuri' => $this->PhpUri, 'docuri' => $this->DocUri ); self::CallHook( 'WriteCacheHook', Array( 'server' => $this, 'data' => &$data ) ); if(file_put_contents($file.'.obj',serialize($data))===false){ self::Debug('Could not write serialized cache'); return false;// Error writing to cache } return true; } /** * Determine if the cache folder is writeable * * @param string $folder The folder or NULL to use the static property CacheFolder (default: NULL) * @return boolean Writeable? */ public static function IsCacheFolderWriteAble($folder=null){ if(!is_null(self::$CacheFolderWriteAble)) return self::$CacheFolderWriteAble; if(is_null($folder)) $folder=self::$CacheFolder; if(is_null($folder)){ self::$CacheFolderWriteAble=false; return false; } if(!is_dir($folder)){ self::Debug('Invalid cache folder (not a directory?)'); self::$CacheFolderWriteAble=false; return; } $file=uniqid(); while(file_exists($folder.'/'.$file)) $file=uniqid(); $file=$folder.'/'.$file; $temp=uniqid(); if(file_put_contents($file,$temp)===false){ self::$CacheFolderWriteAble=false; return false; } $res=file_get_contents($file)===$temp; unlink($file); self::$CacheFolderWriteAble=$res; return $res; } /** * Determine if the cache is different from the current version of your webservice handler class. * Status: Untested * * @return boolean Differences detected? */ public function IsCacheDifferent(){ self::Debug('Determine if the cache is different from this instance'); // Load the cache $temp=new PhpWsdl(null,$this->EndPoint); $temp->GetWsdlFromCache(); if(is_null($temp->WSDL)) return true;// Not cached yet // Initialize this instance $this->DetermineConfiguration(); $this->ParseSource(); // Compare the cache with this instance $res=serialize( Array( $this->Methods, $this->Types ) )!=serialize( Array( $temp->Methods, $temp->Types ) ); self::Debug('Cache is '.(($res)?'equal':'different')); return $res; } /** * Delete cache files from the cache folder * * @param boolean $mineOnly Only delete the cache files for this definition? (default: FALSE) * @param boolean $cleanUp Only delete the cache files that are timed out? (default: FALSE) * @param string $wsdlFile The WSDL filename (default: NULL) * @return string[] The deleted filenames */ public function TidyCacheFolder($mineOnly=false,$cleanUp=false,$wsdlFile=null){ if(is_null(self::$CacheFolder)) return Array(); $deleted=Array(); if($cleanUp){ self::Debug('Cleanup cache'); }else if($mineOnly){ self::Debug('Clean own cache'); }else{ self::Debug('Clean all cache'); } if($mineOnly){ self::Debug('Delete own cache'); $file=(is_null($wsdlFile))?$this->GetCacheFileName():$wsdlFile; if($cleanUp) if($this->IsCacheValid($file)) return $deleted; if(file_exists($file)) if(unlink($file)) $deleted[]=$file; if(file_exists($file.'.cache')) if(unlink($file.'.cache')) $deleted[]=$file.'.cache'; if(file_exists($file.'.obj')) if(unlink($file.'.obj')) $deleted[]=$file.'.obj'; self::Debug(sizeof($deleted).' files deleted'); }else{ self::Debug('Delete whole cache'); $files=glob(self::$CacheFolder.(($cleanUp)?'/*.wsdl':'/*.wsd*')); if($files!==false){ $toDelete=Array(); $i=-1; $len=sizeof($files); while(++$i<$len){ $file=$files[$i]; if($cleanUp){ if(!$this->IsCacheValid($file)) continue; $toDelete[]=$file; $toDelete[]=$file.'.cache'; $toDelete[]=$file.'.obj'; }else{ if(!preg_match('/\.wsdl(\.cache|\.obj)?$/',$file)) continue; if(unlink($files[$i])) $deleted[]=$files[$i]; } } if($cleanUp){ $i=-1; $len=sizeof($toDelete); while(++$i<$len) if(file_exists($toDelete[$i])) if(unlink($toDelete[$i])) $deleted[]=$toDelete[$i]; } self::Debug(sizeof($deleted).' files deleted'); }else{ self::Debug('"glob" failed'); } } return $deleted; } /** * Translate a type name for WSDL * * @param string $type The type name * @return string The translates type name */ public static function TranslateType($type){ if(!self::CallHook( 'TranslateTypeHook', Array( 'type' => &$type ) ) ) return $type; return ((in_array($type,self::$BasicTypes))?self::$Config['xsd']:self::$Config['tns']).':'.$type; } /** * Call a hook function * * @param string $name The hook name * @param mixed $data The parameter (default: NULL) * @return boolean Response */ public static function CallHook($name,$data=null){ self::Debug('Call hook '.$name); if(!self::HasHookHandler($name)) return true; $keys=array_keys(self::$Config['extensions'][$name]); $i=-1; $len=sizeof($keys); while(++$i<$len){ self::Debug('Call '.self::$Config['extensions'][$name][$keys[$i]]); if(!call_user_func(self::$Config['extensions'][$name][$keys[$i]],$data)){ self::Debug('Handler stopped hook execution'); return false; } } return true; } /** * Register a hook * * @param string $hook The hook name * @param string $name The call name * @param mixed $data The hook call data */ public static function RegisterHook($hook,$name,$data){ if(!self::HasHookHandler($hook)) self::$Config['extensions'][$hook]=Array(); if(self::$Debugging){ $handler=$data; if(is_array($handler)){ $class=$handler[0]; $method=$handler[1]; if(is_object($class)) $class=get_class($class); $handler=$class.'.'.$method; } self::Debug('Register hook '.$hook.' handler '.$name.': '.$handler); } self::$Config['extensions'][$hook][$name]=$data; } /** * Unregister a hook * * @param string $hook The hook name * @param string $name The call name or NULL to unregister the whole hook */ public static function UnregisterHook($hook,$name=null){ if(!self::HasHookHandler($hook)) return; if(!is_null($name)){ if(!isset(self::$Config['extensions'][$hook][$name])) return; }else{ unset(self::$Config['extensions'][$hook]); return; } unset(self::$Config['extensions'][$hook][$name]); if(self::$Debugging) self::Debug('Unregister hook '.$hook.' handler '.$name); if(sizeof(self::$Config['extensions'][$hook])<1) unset(self::$Config['extensions'][$hook]); } /** * Determine if a hook has a registered handler * * @param string $hook The hook name * @return boolean Has handler? */ public static function HasHookHandler($hook){ return isset(self::$Config['extensions'][$hook]); } /** * Add a debugging message * * @param string $str The message to add to the debug protocol */ public static function Debug($str){ if(!self::$Debugging) return; $temp=date('Y-m-d H:i:s')."\t".$str; if(self::$DebugBackTrace){ $trace=debug_backtrace(); $temp.=" ('".$trace[1]['function']."' in '".basename($trace[1]['file'])."' at line #".$trace[1]['line'].")"; } self::$DebugInfo[]=$temp; if(!is_null(self::$DebugFile)) if(file_put_contents(self::$DebugFile,$temp."\n",FILE_APPEND)===false){ self::Debug('Could not write to debug file '.self::$DebugFile); self::$DebugFile=null; } } /** * Initialize PhpWsdl */ public static function Init(){ self::Debug('Init'); // Configuration self::$HTML2PDFSettings=Array( 'attachments' => '1', 'outline' => '1' ); self::$NameSpaces=Array( 'soap' => 'http://schemas.xmlsoap.org/wsdl/soap/', 's' => 'http://www.w3.org/2001/XMLSchema', 'wsdl' => 'http://schemas.xmlsoap.org/wsdl/', 'soapenc' => 'http://schemas.xmlsoap.org/soap/encoding/' ); self::EnableCache(); self::$Config['extensions']=Array();// A configuration space for extensions self::$Config['tns']='tns'; // The xmlns name for the target namespace self::$Config['xsd']='s'; // The xmlns name for the XSD namespace // Parser hooks self::RegisterHook('InterpretKeywordserviceHook','internal','PhpWsdl::InterpretService'); // WSDL hooks self::RegisterHook('CreateWsdlHeaderHook','internal','PhpWsdl::CreateWsdlHeader'); self::RegisterHook('CreateWsdlTypeSchemaHook','internal','PhpWsdl::CreateWsdlTypeSchema'); self::RegisterHook('CreateWsdlMessagesHook','internal','PhpWsdl::CreateWsdlMessages'); self::RegisterHook('CreateWsdlPortsHook','internal','PhpWsdl::CreateWsdlPorts'); self::RegisterHook('CreateWsdlBindingsHook','internal','PhpWsdl::CreateWsdlBindings'); self::RegisterHook('CreateWsdlServiceHook','internal','PhpWsdl::CreateWsdlService'); self::RegisterHook('CreateWsdlFooterHook','internal','PhpWsdl::CreateWsdlFooter'); self::RegisterHook('CreateWsdlOptimizeHook','internal','PhpWsdl::CreateWsdlOptimize'); // HTML hooks self::RegisterHook('CreateHtmlGeneralHook','internal','PhpWsdl::CreateHtmlGeneral'); self::RegisterHook('CreateHtmlIndexHook','internal','PhpWsdl::CreateHtmlIndex'); self::RegisterHook('CreateHtmlMethodsHook','internal','PhpWsdl::CreateHtmlMethods'); self::RegisterHook('CreateHtmlComplexTypesHook','internal','PhpWsdl::CreateHtmlComplexTypes'); // Extensions self::Debug('Load extensions'); $files=glob(dirname(__FILE__).'/'.'class.phpwsdl.*.php'); if($files!==false){ $i=-1; $len=sizeof($files); while(++$i<$len){ self::Debug('Load '.$files[$i]); require_once($files[$i]); } }else{ self::Debug('"glob" failed'); } } /** * Do things after the environment is configured */ public static function PostInit(){ self::CallHook('PostInitHook'); // Autorun global $PhpWsdlAutoRun; if(self::$AutoRun||$PhpWsdlAutoRun) self::RunQuickMode(); } }