PageRenderTime 107ms CodeModel.GetById 50ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/server/lib/php-wsdl-2.3/class.phpwsdl.php

https://github.com/abnemo/stalker_portal
PHP | 2445 lines | 1635 code | 67 blank | 743 comment | 202 complexity | 96d5700ec91a7a62929b0801fd5b52fe MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/*
   4PhpWsdl - Generate WSDL from PHP
   5Copyright (C) 2011  Andreas Zimmermann, wan24.de 
   6
   7This program is free software; you can redistribute it and/or modify it under 
   8the terms of the GNU General Public License as published by the Free Software 
   9Foundation; either version 3 of the License, or (at your option) any later 
  10version. 
  11
  12This program is distributed in the hope that it will be useful, but WITHOUT 
  13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  14FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 
  15
  16You should have received a copy of the GNU General Public License along with 
  17this program; if not, see <http://www.gnu.org/licenses/>.
  18*/
  19
  20if(basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__))
  21	exit;
  22
  23// Debugging
  24/*PhpWsdl::$Debugging=true;// Enable debugging
  25PhpWsdl::$DebugFile='./cache/debug.log';// The logfile to write the debugging messages to
  26PhpWsdl::$DebugBackTrace=false;// Include backtrace information in debugging messages?*/
  27
  28// Initialize PhpWsdl
  29PhpWsdl::Init();
  30	
  31// You don't require class.phpwsdlelement.php and class.phpwsdlcomplex.php, 
  32// as long as you don't use complex types. So you may comment those two 
  33// requires out.
  34// You may also disable loading the class.phpwsdlproxy.php, if you don't plan 
  35// to use the proxy class for your webservice.
  36require_once(dirname(__FILE__).'/class.phpwsdlformatter.php');
  37require_once(dirname(__FILE__).'/class.phpwsdlobject.php');
  38require_once(dirname(__FILE__).'/class.phpwsdlparser.php');
  39require_once(dirname(__FILE__).'/class.phpwsdlproxy.php');
  40require_once(dirname(__FILE__).'/class.phpwsdlparam.php');
  41require_once(dirname(__FILE__).'/class.phpwsdlmethod.php');
  42require_once(dirname(__FILE__).'/class.phpwsdlelement.php');
  43require_once(dirname(__FILE__).'/class.phpwsdlcomplex.php');
  44
  45// Do things after the environment is configured
  46PhpWsdl::PostInit();
  47
  48/**
  49 * PhpWsdl class
  50 * 
  51 * @author Andreas Zimmermann
  52 * @copyright �2011 Andreas Zimmermann, wan24.de
  53 * @version 2.3
  54 */
  55class PhpWsdl{
  56	/**
  57	 * The version number 
  58	 * 
  59	 * @var string
  60	 */
  61	public static $VERSION='2.3';
  62	/**
  63	 * Set this to TRUE to enable the autorun in quick mode
  64	 * 
  65	 * @var boolean
  66	 */
  67	public static $AutoRun=false;
  68	/**
  69	 * Global static configuration
  70	 * 
  71	 * @var array
  72	 */
  73	public static $Config=Array();
  74	/**
  75	 * The webservice handler object
  76	 * 
  77	 * @var object
  78	 */
  79	public static $ProxyObject=null;
  80	/**
  81	 * The current PhpWsdl server
  82	 * 
  83	 * @var PhpWsdl
  84	 */
  85	public static $ProxyServer=null;
  86	/**
  87	 * Use WSDL with the proxy
  88	 * 
  89	 * @var boolean
  90	 */
  91	public static $UseProxyWsdl=false;
  92	/**
  93	 * The name
  94	 * 
  95	 * @var string
  96	 */
  97	public $Name;
  98	/**
  99	 * Documentation
 100	 * 
 101	 * @var string
 102	 */
 103	public $Docs=null;
 104	/**
 105	 * The namespace
 106	 * 
 107	 * @var string
 108	 */
 109	public $NameSpace=null;
 110	/**
 111	 * The SOAP endpoint URI
 112	 * 
 113	 * @var string
 114	 */
 115	public $EndPoint=null;
 116	/**
 117	 * Set this to the WSDL URI, if it's different from your SOAP endpoint + "?WSDL"
 118	 * 
 119	 * @var string
 120	 */
 121	public $WsdlUri=null;
 122	/**
 123	 * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPSOAPCLIENT"
 124	 * 
 125	 * @var string
 126	 */
 127	public $PhpUri=null;
 128	/**
 129	 * Set this to the HTML documentation URI, if it's different from your SOAP endpoint
 130	 * 
 131	 * @var string
 132	 */
 133	public $DocUri=null;
 134	/**
 135	 * The options for the PHP SoapServer
 136	 * Note: "actor" and "uri" will be set at runtime
 137	 * 
 138	 * @var array
 139	 */
 140	public $SoapServerOptions=null;
 141	/**
 142	 * An array of file names to parse
 143	 * 
 144	 * @var string[]
 145	 */
 146	public $Files=Array();
 147	/**
 148	 * An array of complex types
 149	 * 
 150	 * @var PhpWsdlComplex[]
 151	 */
 152	public $Types=null;
 153	/**
 154	 * An array of method
 155	 * 
 156	 * @var PhpWsdlMethod[]
 157	 */
 158	public $Methods=null;
 159	/**
 160	 * Remove tabs and line breaks?
 161	 * Note: Unoptimized WSDL won't be cached
 162	 * 
 163	 * @var boolean
 164	 */
 165	public $Optimize=true;
 166	/**
 167	 * UTF-8 encoded WSDL from the last CreateWsdl method call
 168	 * 
 169	 * @var string
 170	 */
 171	public $WSDL=null;
 172	/**
 173	 * UTF-8 encoded HTML from the last OutputHtml method call
 174	 * 
 175	 * @var string
 176	 */
 177	public $HTML=null;
 178	/**
 179	 * UTF-8 encoded PHP from the last OutputPhp method call
 180	 * 
 181	 * @var string
 182	 */
 183	public $PHP=null;
 184	/**
 185	 * An array of basic types (these are just some of the XSD defined types 
 186	 * (see http://www.w3.org/TR/2001/PR-xmlschema-2-20010330/)
 187	 * 
 188	 * @var string[]
 189	 */
 190	public static $BasicTypes=Array(
 191		'anyType',
 192		'anyURI',
 193		'base64Binary',
 194		'boolean',
 195		'byte',
 196		'date',
 197		'decimal',
 198		'double',
 199		'duration',
 200		'dateTime',
 201		'float',
 202		'gDay',
 203		'gMonthDay',
 204		'gYearMonth',
 205		'gYear',
 206		'hexBinary',
 207		'int',
 208		'integer',
 209		'long',
 210		'NOTATION',
 211		'number',
 212		'QName',
 213		'short',
 214		'string',
 215		'time'
 216	);
 217	/**
 218	 * A list of non-nillable types
 219	 * 
 220	 * @var string[]
 221	 */
 222	public static $NonNillable=Array(
 223		'boolean',
 224		'decimal',
 225		'double',
 226		'float',
 227		'int',
 228		'integer',
 229		'long',
 230		'number',
 231		'short'
 232	);
 233	/**
 234	 * Set this to a writeable folder to enable caching the WSDL in files
 235	 * 
 236	 * @var string
 237	 */
 238	public static $CacheFolder=null;
 239	/**
 240	 * Is the cache folder writeable?
 241	 * 
 242	 * @var boolean|NULL
 243	 */
 244	public static $CacheFolderWriteAble=null;
 245	/**
 246	 * The cache timeout in seconds (set to zero to disable caching, too)
 247	 * If you set the value to -1, the cache will never expire. Then you have 
 248	 * to use the PhpWsdl->TidyCache method for cleaning up the cache once 
 249	 * you've made changes to your webservice.
 250	 * 
 251	 * @var int
 252	 */
 253	public static $CacheTime=3600;
 254	/**
 255	 * Write even unoptimized and/or documented XML to the cache?
 256	 * 
 257	 * @var boolean
 258	 */
 259	public static $CacheAllWsdl=false;
 260	/**
 261	 * Parse documentation?
 262	 * 
 263	 * @var boolean
 264	 */
 265	public $ParseDocs=true;
 266	/**
 267	 * Include documentation tags in WSDL, if the optimizer is disabled?
 268	 * 
 269	 * @var boolean
 270	 */
 271	public $IncludeDocs=true;
 272	/**
 273	 * Force sending WSDL (has a higher priority than PhpWsdl->ForceNotOutputWsdl)
 274	 * 
 275	 * @var boolean
 276	 */
 277	public $ForceOutputWsdl=false;
 278	/**
 279	 * Force NOT sending WSDL (disable sending WSDL, has a higher priority than ?WSDL f.e.)
 280	 * 
 281	 * @var boolean
 282	 */
 283	public $ForceNotOutputWsdl=false;
 284	/**
 285	 * Force sending HTML (has a higher priority than PhpWsdl->ForceNotOutputHtml)
 286	 * 
 287	 * @var boolean
 288	 */
 289	public $ForceOutputHtml=false;
 290	/**
 291	 * Force NOT sending HTML (disable sending HTML)
 292	 * 
 293	 * @var boolean
 294	 */
 295	public $ForceNotOutputHtml=false;
 296	/**
 297	 * The headline for the HTML output or NULL to use the default
 298	 * 
 299	 * @var string
 300	 */
 301	public $HtmlHeadLine=null;
 302	/**
 303	 * Force sending PHP (has a higher priority than PhpWsdl->ForceNotOutputPhp)
 304	 * 
 305	 * @var boolean
 306	 */
 307	public $ForceOutputPhp=false;
 308	/**
 309	 * Force NOT sending PHP (disable sending PHP)
 310	 * 
 311	 * @var boolean
 312	 */
 313	public $ForceNotOutputPhp=false;
 314	/**
 315	 * Regular expression parse a class name
 316	 * 
 317	 * @var string
 318	 */
 319	public static $classRx='/^.*class\s+([^\s]+)\s*\{.*$/is';
 320	/**
 321	 * The HTML2PDF license key (see www.htmltopdf.de)
 322	 * 
 323	 * @var string
 324	 */
 325	public static $HTML2PDFLicenseKey=null;
 326	/**
 327	 * The URI to the HTML2PDF http API
 328	 * 
 329	 * @var string
 330	 */
 331	public static $HTML2PDFAPI='http://online.htmltopdf.de/';
 332	/**
 333	 * The HTML2PDF settings (only available when using a valid license key)
 334	 * 
 335	 * @var array
 336	 */
 337	public static $HTML2PDFSettings=Array();
 338	/**
 339	 * Saves if the sources have been parsed
 340	 * 
 341	 * @var boolean
 342	 */
 343	public $SourcesParsed=false;
 344	/**
 345	 * Saves if the configuration has already been determined
 346	 * 
 347	 * @var boolean
 348	 */
 349	public $ConfigurationDetermined=false;
 350	/**
 351	 * The current PHP SoapServer object
 352	 * 
 353	 * @var SoapServer
 354	 */
 355	public $SoapServer=null;
 356	/**
 357	 * Is a http Auth login required to run the SOAP server?
 358	 * 
 359	 * @var boolean
 360	 */
 361	public $RequireLogin=false;
 362	/**
 363	 * Debugging messages
 364	 * 
 365	 * @var string[]
 366	 */
 367	public static $DebugInfo=Array();
 368	/**
 369	 * En- / Disable the debugging mode
 370	 * 
 371	 * @var boolean
 372	 */
 373	public static $Debugging=false;
 374	/**
 375	 * The debug file to write to
 376	 * 
 377	 * @var string
 378	 */
 379	public static $DebugFile=null;
 380	/**
 381	 * Put backtrace information in debugging messages
 382	 * 
 383	 * @var boolean
 384	 */
 385	public static $DebugBackTrace=false;
 386	/**
 387	 * WSDL namespaces
 388	 * 
 389	 * @var array
 390	 */
 391	public static $NameSpaces=null;
 392	
 393	/**
 394	 * PhpWsdl constructor
 395	 * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0.
 396	 * Use PhpWsdl::RunQuickMode() instead
 397	 * 
 398	 * @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)
 399	 * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL)
 400	 * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL)
 401	 * @param string|string[] $file Filename or array of filenames or NULL (default: NULL)
 402	 * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL)
 403	 * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL)
 404	 * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL)
 405	 * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE)
 406	 * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE)
 407	 */
 408	public function PhpWsdl(
 409		$nameSpace=null,
 410		$endPoint=null,
 411		$cacheFolder=null,
 412		$file=null,
 413		$name=null,
 414		$methods=null,
 415		$types=null,
 416		$outputOnRequest=false,
 417		$runServer=false
 418		){
 419		// Quick mode
 420		self::Debug('PhpWsdl constructor called');
 421		$quickRun=false;
 422		if($nameSpace===true){
 423			self::Debug('Quick mode detected');
 424			$quickRun=true;
 425			$nameSpace=null;
 426			if(!is_null($endPoint)){
 427				if(self::$Debugging)
 428					self::Debug('Filename(s): '.print_r($endPoint,true));
 429				$endPoint=null;
 430			}
 431		}
 432		// SOAP server options
 433		$this->SoapServerOptions=Array(
 434			'soap_version'	=>	SOAP_1_1|SOAP_1_2,
 435			'encoding'		=>	'UTF-8',
 436			'compression'	=>	SOAP_COMPRESSION_ACCEPT|SOAP_COMPRESSION_GZIP|9
 437		);
 438		// Optimizer settings
 439		$this->Optimize=!isset($_GET['readable']);// Call with "?WSDL&readable" to get human readable WSDL
 440		self::Debug('Optimizer is '.(($this->Optimize)?'enabled':'disabled'));
 441		// Cache settings
 442		if(!is_null($cacheFolder)){
 443			self::Debug('Cache folder is '.$cacheFolder);
 444			self::$CacheFolder=$cacheFolder;
 445		}
 446		// Namespace
 447		$this->NameSpace=(is_null($nameSpace))?$this->DetermineNameSpace():$nameSpace;
 448		self::Debug('Namespace is '.$this->NameSpace);
 449		// Endpoint
 450		$this->EndPoint=((!is_null($endPoint)))?$endPoint:$this->DetermineEndPoint();
 451		self::Debug('Endpoint is '.$this->EndPoint);
 452		// Name
 453		if(!is_null($name)){
 454			self::Debug('Name is '.$name);
 455			$this->Name=$name;
 456		}
 457		// Source files
 458		if(!is_null($file)){
 459			if(self::$Debugging)
 460				self::Debug('Filename(s): '.print_r($file,true));
 461			$this->Files=array_merge($this->Files,(is_array($file))?$file:Array($file));
 462		}
 463		// Methods
 464		$this->Methods=(!is_null($methods))?$methods:Array();
 465		if(sizeof($this->Methods)>0&&self::$Debugging)
 466			self::Debug('Methods: '.print_r($this->Methods,true));
 467		// Types
 468		$this->Types=(!is_null($types))?$types:Array();
 469		if(sizeof($this->Types)>0&&self::$Debugging)
 470			self::Debug('Types: '.print_r($this->Types,true));
 471		// Constructor hook
 472		self::CallHook(
 473			'ConstructorHook',
 474			Array(
 475				'server'		=>	$this,
 476				'output'		=>	&$outputOnRequest,
 477				'run'			=>	&$runServer,
 478				'quickmode'		=>	&$quickRun
 479			)
 480		);
 481		// WSDL output
 482		if($outputOnRequest&&!$runServer)
 483			$this->OutputWsdlOnRequest();
 484		// Run the server
 485		if($quickRun||$runServer)
 486			$this->RunServer(null,(is_bool($runServer))?null:$runServer);
 487	}
 488	
 489	/**
 490	 * Create an instance of PhpWsdl
 491	 * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0.
 492	 * Use PhpWsdl::RunQuickMode() instead
 493	 * 
 494	 * @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)
 495	 * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL)
 496	 * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL)
 497	 * @param string|string[] $file Filename or array of filenames or NULL (default: NULL)
 498	 * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL)
 499	 * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL)
 500	 * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL)
 501	 * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE)
 502	 * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE)
 503	 * @return PhpWsdl The PhpWsdl object
 504	 */
 505	public static function CreateInstance(
 506		$nameSpace=null,
 507		$endPoint=null,
 508		$cacheFolder=null,
 509		$file=null,
 510		$name=null,
 511		$methods=null,
 512		$types=null,
 513		$outputOnRequest=false,
 514		$runServer=false
 515		){
 516		self::Debug('Create new PhpWsdl instance');
 517		$obj=null;
 518		self::CallHook(
 519			'BeforeCreateInstanceHook',
 520			Array(
 521				'server'		=>	&$obj,
 522				'namespace'		=>	&$nameSpace,
 523				'endpoint'		=>	&$endPoint,
 524				'cachefolder'	=>	&$cacheFolder,
 525				'file'			=>	&$file,
 526				'name'			=>	&$name,
 527				'methods'		=>	&$methods,
 528				'types'			=>	&$types,
 529				'outputonrequest'=>	&$outputOnRequest,
 530				'runserver'		=>	&$runServer
 531			)
 532		);
 533		if(is_null($obj))
 534			$obj=new PhpWsdl($nameSpace,$endPoint,$cacheFolder,$file,$name,$methods,$types,$outputOnRequest,$runServer);
 535		self::CallHook(
 536			'CreateInstanceHook',
 537			Array(
 538				'server'		=>	&$obj
 539			)
 540		);
 541		return $obj;
 542	}
 543	
 544	/**
 545	 * Run the PhpWsdl SOAP server in quick mode
 546	 * 
 547	 * @param string|string[] $file The webservice handler class file or a list of files or NULL (default: NULL)
 548	 */
 549	public static function RunQuickMode($file=null){
 550		self::Debug('Run quick mode');
 551		$server=self::CreateInstance();
 552		if(!is_null($file))
 553			$server->Files=(is_array($file))?$file:Array($file);
 554		$server->RunServer();
 555	}
 556	
 557	/**
 558	 * Determine if WSDL was requested by the client
 559	 * 
 560	 * @return boolean WSDL requested?
 561	 */
 562	public function IsWsdlRequested(){
 563		return $this->ForceOutputWsdl||((isset($_GET['wsdl'])||isset($_GET['WSDL']))&&!$this->ForceNotOutputWsdl);
 564	}
 565	
 566	/**
 567	 * Determine if HTML was requested by the client
 568	 * 
 569	 * @return boolean HTML requested?
 570	 */
 571	public function IsHtmlRequested(){
 572		return $this->ForceOutputHtml||(strlen(file_get_contents('php://input'))<1&&!$this->ForceNotOutputHtml);
 573	}
 574
 575	/**
 576	 * Determine if PHP was requested by the client
 577	 * 
 578	 * @return boolean PHP requested?
 579	 */
 580	public function IsPhpRequested(){
 581		return $this->ForceOutputPhp||((isset($_GET['phpsoapclient'])||isset($_GET['PHPSOAPCLIENT']))&&!$this->ForceNotOutputPhp);
 582	}
 583
 584	/**
 585	 * Determine if this request is a SOAP request
 586	 * 
 587	 * @return boolean
 588	 */
 589	public function IsSoapRequest(){
 590		return !$this->IsHtmlRequested()&&!$this->IsWsdlRequested()&&!$this->IsPhpRequested();
 591	}
 592
 593	/**
 594	 * Determine if only global methods are served
 595	 * 
 596	 * @return boolean Only global methods?
 597	 */
 598	public function IsOnlyGlobal(){
 599		$res=true;
 600		$i=-1;
 601		$len=sizeof($this->Methods);
 602		while(++$i<$len)
 603			if(!$this->Methods[$i]->IsGlobal){
 604				$res=false;
 605				break;
 606			}
 607		return $res;
 608	}
 609	
 610	/**
 611	 * Disble caching
 612	 * 
 613	 * @param bool $allCaching Do not only set the timeout to zero? (default: TRUE)
 614	 */
 615	public static function DisableCache($allCaching=true){
 616		self::Debug('Disable '.(($allCaching)?'all':'this').' caching');
 617		if($allCaching)
 618			self::$CacheFolder=null;
 619		if(!$allCaching)
 620			self::$CacheTime=0;
 621	}
 622	
 623	/**
 624	 * Enable caching
 625	 * 
 626	 * @param string $folder The cache folder or NULL to use a system temporary directory (default: NULL)
 627	 * @param int $timeout The caching timeout in seconds or NULL to use the previous value or the default (3600) (default: NULL)
 628	 */
 629	public static function EnableCache($folder=null,$timeout=null){
 630		if(is_null($folder)){
 631			if(self::IsCacheFolderWriteAble('./cache')){
 632				$folder='./cache';
 633			}else if(self::IsCacheFolderWriteAble(dirname(__FILE__).'/cache')){
 634				$folder=dirname(__FILE__).'/cache';
 635			}else if(self::IsCacheFolderWriteAble(sys_get_temp_dir())){
 636				$folder=sys_get_temp_dir();
 637			}else{
 638				self::Debug('Could not find a cache folder');
 639			}
 640		}
 641		if(is_null($timeout))
 642			$timeout=(self::$CacheTime!=0)?self::$CacheTime:3600;
 643		self::Debug('Enable cache in folder "'.((is_null($folder))?'(none)':$folder).'" with timeout '.$timeout.' seconds');
 644		self::$CacheFolder=$folder;
 645		self::$CacheTime=$timeout;
 646	}
 647	
 648	/**
 649	 * Determine the configuration
 650	 * 
 651	 * @return boolean Succeed?
 652	 */
 653	public function DetermineConfiguration(){
 654		if(!is_null($this->GetWsdlFromCache()))
 655			return true;
 656		$this->ParseSource();
 657		$mLen=sizeof($this->Methods);
 658		$tLen=sizeof($this->Types);
 659		$fLen=sizeof($this->Files);
 660		if($this->ConfigurationDetermined)
 661			return ($mLen>0||$tLen>0)&&!is_null($this->Name);
 662		self::Debug('Determine configuration');
 663		$this->ConfigurationDetermined=true;
 664		$tryWebService=
 665			!$this->IsFileInList('class.webservice.php')&&
 666			(
 667				file_exists('class.webservice.php')||
 668				file_exists(dirname(__FILE__).'/class.webservice.php')
 669			);
 670		// No methods or types? Try to parse them from the current script
 671		if($mLen<1&&$tLen<1){
 672			$tryFiles=Array();
 673			if($tryWebService){
 674				if(file_exists('class.webservice.php'))
 675					$tryFiles[]='class.webservice.php';
 676				if(file_exists(dirname(__FILE__).'/class.webservice.php'))
 677					$tryFiles[]=dirname(__FILE__).'/class.webservice.php';
 678			}
 679			if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME']))
 680				$tryFiles[]=$_SERVER['SCRIPT_FILENAME'];
 681			$i=-1;
 682			$len=sizeof($tryFiles);
 683			while(++$i<$len){
 684				$file=$tryFiles[$i];
 685				self::Debug('Try to load objects from '.$file);
 686				$this->ParseSource(false,file_get_contents($file));
 687				$mLen=sizeof($this->Methods);
 688				$tLen=sizeof($this->Types);
 689				if($mLen<1&&$tLen<1)
 690					continue;
 691				self::Debug('Found objects, adding the file to list');
 692				$this->Files[]=$file;
 693				$fLen++;
 694				break;
 695			}
 696			if($mLen<1&&$tLen<1)
 697				return false;
 698		}
 699		// No class name? Try to parse one from the current files
 700		if(!is_null($this->Name))
 701			return true;
 702		$tryFiles=Array();
 703		if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME']))
 704			$tryFiles[]=$_SERVER['SCRIPT_FILENAME'];
 705		if($tryWebService){
 706			if(file_exists('class.webservice.php'))
 707				$tryFiles[]='class.webservice.php';
 708			if(file_exists(dirname(__FILE__).'/class.webservice.php'))
 709				$tryFiles[]=dirname(__FILE__).'/class.webservice.php';
 710		}
 711		$tryFiles=array_merge($this->Files,$tryFiles);
 712		$i=-1;
 713		$len=sizeof($tryFiles);
 714		while(++$i<$len){
 715			$file=$tryFiles[$i];
 716			self::Debug('Try to determine the class name from '.$file);
 717			$temp=file_get_contents($file);
 718			if(!preg_match(self::$classRx,$temp))
 719				continue;
 720			$class=preg_replace(self::$classRx,"$1",$temp);
 721			self::Debug('Found class name '.$class);
 722			break;
 723		}
 724		// No class name yet? Use the default if only global methods are present
 725		if(is_null($class)&&$this->IsOnlyGlobal()){
 726			self::Debug('Using default webservice name');
 727			$class='SoapWebService';
 728		}
 729		$this->Name=$class;
 730		return !is_null($class);
 731	}
 732	
 733	/**
 734	 * Determine the endpoint URI
 735	 */
 736	public function DetermineEndPoint(){
 737		return ((isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']=='on')?'https':'http').'://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'];
 738	}
 739
 740	/**
 741	 * Determine the namespace
 742	 */
 743	public function DetermineNameSpace(){
 744		return 'http://'.$_SERVER['SERVER_NAME'].str_replace(basename($_SERVER['SCRIPT_NAME']),'',$_SERVER['SCRIPT_NAME']);
 745	}
 746	
 747	/**
 748	 * Determine if a file is included in the list of files
 749	 * 
 750	 * @param string $file The filename
 751	 * @return boolean In the list?
 752	 */
 753	public function IsFileInList($file){
 754		$file=preg_quote(basename($file));
 755		$i=-1;
 756		$fLen=sizeof($this->Files);
 757		while(++$i<$fLen)
 758			if(preg_match('/^(.*\/)?'.$file.'$/i',$this->Files[$i]))
 759				return true;
 760		return false;
 761	}
 762	
 763	/**
 764	 * Create the WSDL
 765	 * 
 766	 * @param boolean $reCreate Don't use the cached WSDL? (default: FALSE)
 767	 * @param boolean $optimize If TRUE, override the PhpWsdl->Optimizer property and force optimizing (default: FALSE)
 768	 * @return string The UTF-8 encoded WSDL as string
 769	 */
 770	public function CreateWsdl($reCreate=false,$optimizer=false){
 771		self::Debug('Create WSDL');
 772		// Ask the cache
 773		if(!$reCreate&&(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize)){
 774			self::Debug('Try to get WSDL from the cache');
 775			$wsdl=$this->GetWsdlFromCache();
 776			if(!is_null($wsdl)){
 777				self::Debug('Using cached WSDL');
 778				return (!$optimizer&&!$this->Optimize)?self::FormatXml($wsdl):$wsdl;
 779			}
 780		}
 781		// Prepare the WSDL generator
 782		if(!$this->DetermineConfiguration()){
 783			$mLen=sizeof($this->Methods);
 784			$tLen=sizeof($this->Types);
 785			if($mLen<1&&$tLen<1){
 786				self::Debug('No methods and types');
 787				throw(new Exception('No methods and no complex types are available'));
 788			}
 789			if(is_null($this->Name)){
 790				self::Debug('No name');
 791				throw(new Exception('Could not determine webservice handler class name'));
 792			}
 793		}
 794		$res=Array();
 795		// Create the XML Header
 796		self::CallHook(
 797			'CreateWsdlHeaderHook',
 798			Array(
 799				'server'		=>	$this,
 800				'res'			=>	&$res,
 801				'optimizer'		=>	&$optimizer
 802			)
 803		);
 804		// Create types
 805		self::CallHook(
 806			'CreateWsdlTypeSchemaHook',
 807			Array(
 808				'server'		=>	$this,
 809				'res'			=>	&$res,
 810				'optimizer'		=>	&$optimizer
 811			)
 812		);
 813		// Create messages
 814		self::CallHook(
 815			'CreateWsdlMessagesHook',
 816			Array(
 817				'server'		=>	$this,
 818				'res'			=>	&$res,
 819				'optimizer'		=>	&$optimizer
 820			)
 821		);
 822		// Create port types
 823		self::CallHook(
 824			'CreateWsdlPortsHook',
 825			Array(
 826				'server'		=>	$this,
 827				'res'			=>	&$res,
 828				'optimizer'		=>	&$optimizer
 829			)
 830		);
 831		// Create bindings
 832		self::CallHook(
 833			'CreateWsdlBindingsHook',
 834			Array(
 835				'server'		=>	$this,
 836				'res'			=>	&$res,
 837				'optimizer'		=>	&$optimizer
 838			)
 839		);
 840		// Create the service
 841		self::CallHook(
 842			'CreateWsdlServiceHook',
 843			Array(
 844				'server'		=>	$this,
 845				'res'			=>	&$res,
 846				'optimizer'		=>	&$optimizer
 847			)
 848		);
 849		// Finish the WSDL XML string
 850		self::CallHook(
 851			'CreateWsdlFooterHook',
 852			Array(
 853				'server'		=>	$this,
 854				'res'			=>	&$res,
 855				'optimizer'		=>	&$optimizer
 856			)
 857		);
 858		// Run the optimizer
 859		self::CallHook(
 860			'CreateWsdlOptimizeHook',
 861			Array(
 862				'server'		=>	$this,
 863				'res'			=>	&$res,
 864				'optimizer'		=>	&$optimizer
 865			)
 866		);
 867		// Fill the cache
 868		if(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize){
 869			self::Debug('Cache created WSDL');
 870			$this->WriteWsdlToCache(
 871				(
 872					!self::$CacheAllWsdl&&
 873					!$optimizer&&
 874					!$this->Optimize
 875				)
 876					?self::OptimizeXml($res)
 877					:$res
 878				,
 879				null,
 880				null,
 881				true
 882			);
 883		}
 884		return $this->WSDL;
 885	}
 886
 887	/**
 888	 * Create header
 889	 * 
 890	 * @param array $data Data array
 891	 * @return boolean Response
 892	 */
 893	public static function CreateWsdlHeader($data){
 894		self::Debug('CreateWsdlHeader');
 895		$res=&$data['res'];
 896		$server=$data['server'];
 897		$res[]='<?xml version="1.0" encoding="UTF-8"?>';
 898		$temp=Array();
 899		$keys=array_keys(self::$NameSpaces);
 900		$i=-1;
 901		$len=sizeof($keys);
 902		while(++$i<$len)
 903			$temp[]='xmlns:'.$keys[$i].'="'.self::$NameSpaces[$keys[$i]].'"';
 904		$res[]='<wsdl:definitions xmlns:tns="'.$server->NameSpace.'" targetNamespace="'.$server->NameSpace.'" '.implode(' ',$temp).'>';
 905		return true;
 906	}
 907	
 908	/**
 909	 * Create type schema
 910	 * 
 911	 * @param array $data Data array
 912	 * @return boolean Response
 913	 */
 914	public static function CreateWsdlTypeSchema($data){
 915		self::Debug('CreateWsdlTypeSchema');
 916		$res=&$data['res'];
 917		$server=$data['server'];
 918		$tLen=sizeof($server->Types);
 919		if($tLen>0){
 920			$res[]='<wsdl:types>';
 921			$res[]='<s:schema targetNamespace="'.$server->NameSpace.'">';
 922			$i=-1;
 923			while(++$i<$tLen)
 924				$res[]=$server->Types[$i]->CreateType($server);
 925			self::CallHook(
 926				'CreateWsdlTypesHook',
 927				$data
 928			);
 929			$res[]='</s:schema>';
 930			$res[]='</wsdl:types>';
 931		}
 932		return true;
 933	}
 934	
 935	/**
 936	 * Create messages
 937	 * 
 938	 * @param array $data Data array
 939	 * @return boolean Response
 940	 */
 941	public static function CreateWsdlMessages($data){
 942		self::Debug('CreateWsdlMessages');
 943		$res=&$data['res'];
 944		$server=$data['server'];
 945		$i=-1;
 946		$mLen=sizeof($server->Methods);
 947		while(++$i<$mLen)
 948			$res[]=$server->Methods[$i]->CreateMessages($server);
 949		return true;
 950	}
 951	
 952	/**
 953	 * Create port types
 954	 * 
 955	 * @param array $data Data array
 956	 * @return boolean Response
 957	 */
 958	public static function CreateWsdlPorts($data){
 959		self::Debug('CreateWsdlPorts');
 960		$res=&$data['res'];
 961		$server=$data['server'];
 962		$res[]='<wsdl:portType name="'.$server->Name.'Soap">';
 963		$i=-1;
 964		$mLen=sizeof($server->Methods);
 965		while(++$i<$mLen)
 966			$res[]=$server->Methods[$i]->CreatePortType($server);
 967		self::CallHook(
 968			'CreateWsdlPortsAddHook',
 969			$data
 970		);
 971		$res[]='</wsdl:portType>';
 972		return true;
 973	}
 974	
 975	/**
 976	 * Create bindings
 977	 * 
 978	 * @param array $data Data array
 979	 * @return boolean Response
 980	 */
 981	public static function CreateWsdlBindings($data){
 982		self::Debug('CreateWsdlBindings');
 983		$res=&$data['res'];
 984		$server=$data['server'];
 985		$res[]='<wsdl:binding name="'.$server->Name.'Soap" type="tns:'.$server->Name.'Soap">';
 986		$res[]='<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />';
 987		$i=-1;
 988		$mLen=sizeof($server->Methods);
 989		while(++$i<$mLen)
 990			$res[]=$server->Methods[$i]->CreateBinding($server);
 991		self::CallHook(
 992			'CreateWsdlBindingsAddHook',
 993			$data
 994		);
 995		$res[]='</wsdl:binding>';
 996		return true;
 997	}
 998	
 999	/**
1000	 * Create service port
1001	 * 
1002	 * @param array $data Data array
1003	 * @return boolean Response
1004	 */
1005	public static function CreateWsdlService($data){
1006		self::Debug('CreateWsdlService');
1007		$res=&$data['res'];
1008		$server=$data['server'];
1009		$res[]='<wsdl:service name="'.$server->Name.'">';
1010		if($server->IncludeDocs&&!$server->Optimize&&!is_null($server->Docs))
1011			$res[]='<wsdl:documentation><![CDATA['.$server->Docs.']]></wsdl:documentation>';
1012		$res[]='<wsdl:port name="'.$server->Name.'Soap" binding="tns:'.$server->Name.'Soap">';
1013		$res[]='<soap:address location="'.$server->EndPoint.'" />';
1014		$res[]='</wsdl:port>';
1015		self::CallHook(
1016			'CreateWsdlServiceAddHook',
1017			$data
1018		);
1019		$res[]='</wsdl:service>';
1020		return true;
1021	}
1022	
1023	/**
1024	 * Create footer
1025	 * 
1026	 * @param array $data Data array
1027	 * @return boolean Response
1028	 */
1029	public static function CreateWsdlFooter($data){
1030		self::Debug('CreateWsdlFooter');
1031		$res=&$data['res'];
1032		$res[]='</wsdl:definitions>';
1033		return true;
1034	}
1035
1036	/**
1037	 * Optimize WSDL
1038	 * 
1039	 * @param array $data Data array
1040	 * @return boolean Response
1041	 */
1042	public static function CreateWsdlOptimize($data){
1043		self::Debug('CreateWsdlOptimize');
1044		$res=&$data['res'];
1045		$server=$data['server'];
1046		$optimizer=&$data['optimizer'];
1047		$res=utf8_encode(implode('',$res));
1048		$res=(!$optimizer&&!$server->Optimize)
1049			?self::FormatXml($res)
1050			:self::OptimizeXml($res);
1051		$server->WSDL=$res;
1052		return true;
1053	}
1054	
1055	/**
1056	 * Remove tabs and newline from XML
1057	 * 
1058	 * @param string $xml The unoptimized XML
1059	 * @return string The optimized XML
1060	 */
1061	public static function OptimizeXml($xml){
1062		self::Debug('Optimize XML');
1063		return preg_replace('/[\n|\t]/','',$xml);
1064	}
1065	
1066	/**
1067	 * Format XML human readable
1068	 * 
1069	 * @param string $xml The XML
1070	 * @return string Human readable XML
1071	 */
1072	public static function FormatXml($xml){
1073		self::Debug('Produce human readable XML');
1074		$input=fopen('data://text/plain,'.$xml,'r');
1075		$output=fopen('php://temp','w');
1076		$xf=new PhpWsdlFormatter($input,$output);
1077		$xf->format();
1078		rewind($output);
1079		$xml=stream_get_contents($output);
1080		fclose($input);
1081		fclose($output);
1082		return $xml;
1083	}
1084	
1085	/**
1086	 * Interpret the @service keyword
1087	 * 
1088	 * @param $data The parser data
1089	 * @return boolean Response
1090	 */
1091	public static function InterpretService($data){
1092		self::Debug('Interpret service');
1093		$server=$data['server'];
1094		$info=explode(' ',$data['keyword'][1],2);
1095		if(sizeof($info)<1){
1096			self::Debug('WARNING:  Invalid service definition');
1097			return true;
1098		}
1099		$server->Name=$info[0];
1100		if($server->ParseDocs&&sizeof($info)>1&&is_null($server->Docs))
1101			$server->Docs=$info[1];
1102		return true;
1103	}
1104	
1105	/**
1106	 * Parse source files for WSDL definitions in comments
1107	 * 
1108	 * @param boolean $init Empty the Methods and the Types properties? (default: FALSE)
1109	 * @param string $str Source string or NULL to parse the defined files (default: NULL)
1110	 */
1111	public function ParseSource($init=false,$str=null){
1112		self::Debug('Parse the source');
1113		if($init){
1114			self::Debug('Init methods and types');
1115			$this->Methods=Array();
1116			$this->Types=Array();
1117			$this->SourcesParsed=false;
1118		}
1119		if(is_null($str)){
1120			if($this->SourcesParsed)
1121				return;
1122			self::Debug('Load source files');
1123			$this->SourcesParsed=true;
1124			$fLen=sizeof($this->Files);
1125			if($fLen<1)
1126				return;
1127			// Load the source
1128			$src=Array();
1129			$i=-1;
1130			while(++$i<$fLen)
1131				$src[]=trim(file_get_contents($this->Files[$i]));
1132		}else{
1133			self::Debug('Use given string');
1134			$src=Array($str);
1135		}
1136		// Parse the source
1137		self::Debug('Run the parser');
1138		$parser=new PhpWsdlParser($this);
1139		$parser->Parse(implode("\n",$src));
1140	}
1141	
1142	/**
1143	 * Output the WSDL to the client
1144	 * 
1145	 * @param boolean $withHeaders Output XML headers? (default: TRUE)
1146	 */
1147	public function OutputWsdl($withHeaders=true){
1148		if(!self::CallHook(
1149				'OutputWsdlHook',
1150				Array(
1151					'server'		=>	$this
1152				)
1153			)
1154		)
1155			return;
1156		self::Debug('Output WSDL');
1157		if($withHeaders)
1158			header('Content-Type: text/xml; charset=UTF-8',true);
1159		echo $this->CreateWsdl();
1160	}
1161
1162	/**
1163	 * Output the WSDL to the client, if requested
1164	 * 
1165	 * @param boolean $andExit Exit after sending WSDL? (default: TRUE)
1166	 * @return boolean Has the WSDL been sent to the client?
1167	 */
1168	public function OutputWsdlOnRequest($andExit=true){
1169		if(!$this->IsWsdlRequested())
1170			return false;
1171		$this->OutputWsdl();
1172		if($andExit){
1173			self::Debug('Exit script execution');
1174			exit;
1175		}
1176		return true;
1177	}
1178	
1179	/**
1180	 * Output the HTML to the client
1181	 * 
1182	 * @param boolean $withHeaders Send HTML headers? (default: TRUE)
1183	 * @param boolean $echo Print HTML (default: TRUE)
1184	 * @param boolean $cache Cache the result (default: TRUE);
1185	 * @return string The HTML
1186	 */
1187	public function OutputHtml($withHeaders=true,$echo=true,$cache=true){
1188		self::Debug('Output HTML');
1189		if(sizeof($this->Methods)<1)
1190			$this->CreateWsdl();
1191		if(!self::CallHook(
1192				'OutputHtmlHook',
1193				Array(
1194					'server'		=>	$this
1195				)
1196			)
1197		)
1198			return;
1199		// Header
1200		if($withHeaders)
1201			header('Content-Type: text/html; charset=UTF-8',true);
1202		$this->GetWsdlFromCache();
1203		if(!is_null($this->HTML)){
1204			if($echo)
1205				echo $this->HTML;
1206			return $this->HTML;
1207		}
1208		$res=Array();
1209		$res[]='<html>';
1210		$res[]='<head>';
1211		$res[]='<title>'.((is_null($this->HtmlHeadLine))?$this->Name.' interface description':nl2br(htmlentities($this->HtmlHeadLine))).'</title>';
1212		$res[]='<style type="text/css" media="all">';
1213		$res[]='body{font-family:Calibri,Arial;background-color:#fefefe;}';
1214		$res[]='.pre{font-family:Courier;}';
1215		$res[]='.normal{font-family:Calibri,Arial;}';
1216		$res[]='.bold{font-weight:bold;}';
1217		$res[]='h1,h2,h3{font-family:Verdana,Times;}';
1218		$res[]='h1{border-bottom:1px solid gray;}';
1219		$res[]='h2{border-bottom:1px solid silver;}';
1220		$res[]='h3{border-bottom:1px dashed silver;}';
1221		$res[]='a{text-decoration:none;}';
1222		$res[]='a:hover{text-decoration:underline;}';
1223		$res[]='.blue{color:#3400FF;}';
1224		$res[]='.lightBlue{color:#5491AF;}';
1225		if(!is_null(self::$HTML2PDFLicenseKey)&&self::$HTML2PDFSettings['attachments']=='1')
1226			$res[]='.print{display:none;}';
1227		self::CallHook(
1228			'CreateHtmlCssHook',
1229			Array(
1230				'server'		=>	$this,
1231				'res'			=>	&$res
1232			)
1233		);
1234		$res[]='</style>';
1235		$res[]='<style type="text/css" media="print">';
1236		$res[]='.noprint{display:none;}';
1237		if(!is_null(self::$HTML2PDFLicenseKey)&&self::$HTML2PDFSettings['attachments']=='1')
1238			$res[]='.print{display:block;}';
1239		self::CallHook(
1240			'CreateHtmlCssPrintHook',
1241			Array(
1242				'server'		=>	$this,
1243				'res'			=>	&$res
1244			)
1245		);
1246		$res[]='</style>';
1247		$res[]='</head>';
1248		$res[]='<body>';
1249		$types=$this->SortObjectsByName($this->Types);
1250		$methods=$this->SortObjectsByName($this->Methods);
1251		// General information
1252		self::CallHook(
1253			'CreateHtmlGeneralHook',
1254			Array(
1255				'server'		=>	$this,
1256				'res'			=>	&$res,
1257				'methods'		=>	&$methods,
1258				'types'			=>	&$types
1259			)
1260		);
1261		// Index
1262		self::CallHook(
1263			'CreateHtmlIndexHook',
1264			Array(
1265				'server'		=>	$this,
1266				'res'			=>	&$res,
1267				'methods'		=>	&$methods,
1268				'types'			=>	&$types
1269			)
1270		);
1271		// Complex types
1272		self::CallHook(
1273			'CreateHtmlComplexTypesHook',
1274			Array(
1275				'server'		=>	$this,
1276				'res'			=>	&$res,
1277				'methods'		=>	&$methods,
1278				'types'			=>	&$types
1279			)
1280		);
1281		// Methods
1282		self::CallHook(
1283			'CreateHtmlMethodsHook',
1284			Array(
1285				'server'		=>	$this,
1286				'res'			=>	&$res,
1287				'methods'		=>	&$methods,
1288				'types'			=>	&$types
1289			)
1290		);
1291		// HTML2PDF link
1292		$param=Array(
1293			'plain'			=>	'1',
1294			'filename'		=>	$this->Name.'-webservices.pdf',
1295			'print'			=>	'1'
1296		);
1297		if(!is_null(self::$HTML2PDFLicenseKey)){
1298			// Use advanced HTML2PDF API
1299			$temp=array_merge(self::$HTML2PDFSettings,Array(
1300				'url'			=>	$this->GetDocUri()
1301			));
1302			if($temp['attachments']=='1'){
1303				$temp['attachment_1']=$this->Name.'.wsdl:'.$this->GetWsdlUri();
1304				$cnt=1;
1305				if($this->ParseDocs&&$this->IncludeDocs){
1306					$cnt=2;
1307					$temp['attachment_2']=$this->Name.'-doc.wsdl:'.$this->GetWsdlUri().'&readable';
1308				}
1309				$cnt++;
1310				$temp['attachment_'.$cnt]=$this->Name.'.soapclient.php:'.$this->GetPhpUri();
1311				self::CallHook(
1312					'PdfAttachmentHook',
1313					Array(
1314						'server'		=>	$this,
1315						'cnt'			=>	&$cnt,
1316						'param'			=>	&$temp,
1317						'res'			=>	&$res,
1318						'methods'		=>	&$methods,
1319						'types'			=>	&$types
1320					)
1321				);
1322			}
1323			$options=Array();
1324			$keys=array_keys($temp);
1325			$i=-1;
1326			$len=sizeof($keys);
1327			while(++$i<$len)
1328				$options[]=$keys[$i].'='.$temp[$keys[$i]];
1329			$options='$'.base64_encode(implode("\n",$options));
1330			$license=sha1(self::$HTML2PDFLicenseKey.self::$HTML2PDFLicenseKey).'-'.sha1($options.self::$HTML2PDFLicenseKey);
1331			$param['url']=$options;
1332			$param['license']=$license;
1333		}
1334		$temp=$param;
1335		$param=Array();
1336		$keys=array_keys($temp);
1337		$i=-1;
1338		$len=sizeof($keys);
1339		while(++$i<$len)
1340			$param[]=urlencode($keys[$i]).'='.urlencode($temp[$keys[$i]]);
1341		$pdfLink=self::$HTML2PDFAPI.'?'.implode('&',$param);
1342		// Footer
1343		$res[]='<hr>';
1344		//$res[]='<p><small>Powered by <a href="http://code.google.com/p/php-wsdl-creator/">PhpWsdl</a><span class="noprint"> - PDF download: <a href="'.$pdfLink.'">Download this page as PDF</a></span></small></p>';
1345		$res[]='</body>';
1346		$res[]='</html>';
1347		// Clean up the generated HTML and send it
1348		$res=implode("\n",$res);
1349		$res=str_replace('<br />','<br>',$res);// Because nl2br will produce XHTML (and nothing if the second parameter is FALSE!?)
1350		if(!self::CallHook(
1351				'SendHtmlHook',
1352				Array(
1353					'server'		=>	$this,
1354					'res'			=>	&$res
1355				)
1356			)
1357		)
1358			return;
1359		$res=utf8_encode($res);
1360		$this->HTML=$res;
1361		if($cache)
1362			$this->WriteWsdlToCache(null,null,null,true);
1363		if($echo)
1364			echo $res;
1365		return $res;
1366	}
1367	
1368	/**
1369	 * Create general information
1370	 * 
1371	 * @param array $data The information object
1372	 * @return boolean Response
1373	 */
1374	public static function CreateHtmlGeneral($data){
1375		self::Debug('CreateHtmlGeneral');
1376		$res=&$data['res'];
1377		$server=$data['server'];
1378		$res[]='<h1>'.$server->Name.' SOAP WebService interface description</h1>';
1379		$res[]='<p>Endpoint URI: <span class="pre">'.$server->EndPoint.'</span></p>';
1380		//$res[]='<p>WSDL URI: <span class="pre"><a href="'.$server->GetWsdlUri().'&readable">'.$server->GetWsdlUri().'</a></span></p>';
1381		$res[]='<p>WSDL URI: <span class="pre"><a href="'.$server->GetWsdlUri().'">'.$server->GetWsdlUri().'</a></span></p>';
1382		$res[]='<p>Readable WSDL URI: <span class="pre"><a href="'.$server->GetWsdlUri().'&readable">'.$server->GetWsdlUri().'&readable</a></span></p>';
1383		$res[]='<p>PHP SOAP client download URI: <span class="pre"><a href="'.$server->GetPhpUri().'">'.$server->GetPhpUri().'</a></span></p>';
1384		if(self::$HTML2PDFSettings['attachments']=='1'&&!is_null(self::$HTML2PDFLicenseKey))
1385			$res[]='<p class="print">The WSDL files and client proxy class(es) are attached to this PDF documentation.</p>';
1386		if(!is_null($server->Docs))
1387			$res[]='<p>'.nl2br(htmlentities($server->Docs)).'</p>';
1388		return true;
1389	}
1390	
1391	/**
1392	 * Create table of contents
1393	 * 
1394	 * @param array $data The information object
1395	 * @return boolean Response
1396	 */
1397	public static function CreateHtmlIndex($data){
1398		self::Debug('CreateHtmlIndex');
1399		$res=&$data['res'];
1400		$types=&$data['types'];
1401		$methods=&$data['methods'];
1402		$tLen=sizeof($types);
1403		$mLen=sizeof($methods);
1404		$res[]='<div class="noprint">';
1405		$res[]='<h2>Index</h2>';
1406		if($tLen>0){
1407			$res[]='<p>Complex types:</p>';
1408			$i=-1;
1409			$res[]='<ul>';
1410			while(++$i<$tLen)
1411				$res[]='<li><a href="#'.$types[$i]->Name.'"><span class="pre">'.$types[$i]->Name.'</span></a></li>';
1412			$res[]='</ul>';
1413		}
1414		if($mLen>0){
1415			$res[]='<p>Public methods:</p>';
1416			$i=-1;
1417			$res[]='<ul>';
1418			while(++$i<$mLen)
1419				$res[]='<li><a href="#'.$methods[$i]->Name.'"><span class="pre">'.$methods[$i]->Name.'</span></a></li>';
1420			$res[]='</ul>';
1421		}
1422		$res[]='</div>';
1423		return true;
1424	}
1425	
1426	/**
1427	 * Create method list
1428	 * 
1429	 * @param array $data The information object
1430	 * @return boolean Response
1431	 */
1432	public static function CreateHtmlMethods($data){
1433		self::Debug('CreateHtmlMethods');
1434		$res=&$data['res'];
1435		$methods=&$data['methods'];
1436		$mLen=sizeof($methods);
1437		if($mLen>0){
1438			$res[]='<h2>Public methods</h2>';
1439			$i=-1;
1440			while(++$i<$mLen)
1441				$methods[$i]->CreateMethodHtml(array_merge(
1442					$data,
1443					Array(
1444						'method'		=>	$methods[$i]
1445					)
1446				));
1447		}
1448		return true;
1449	}
1450
1451	/**
1452	 * Create complex types list
1453	 * 
1454	 * @param array $data The information object
1455	 * @return boolean Response
1456	 */
1457	public static function CreateHtmlComplexTypes($data){
1458		self::Debug('CreateHtmlComplexTypes');
1459		$res=&$data['res'];
1460		$types=&$data['types'];
1461		$server=$data['server'];
1462		$tLen=sizeof($server->Types);
1463		if($tLen>0){
1464			$res[]='<h2>Complex types</h2>';
1465			$i=-1;
1466			while(++$i<$tLen)
1467				$types[$i]->CreateTypeHtml(array_merge(
1468					$data,
1469					Array(
1470						'type'			=>	$types[$i]
1471					)
1472				));
1473		}
1474		return true;
1475	}
1476	
1477	/**
1478	 * Sort objects by name
1479	 * 
1480	 * @param PhpWsdlComplex[]|PhpWsdlMethod[] $obj
1481	 * @return PhpWsdlComplex[]|PhpWsdlMethod[] Sorted objects
1482	 */
1483	public function SortObjectsByName($obj){
1484		self::Debug('Sort objects by name');
1485		$temp=Array();
1486		$i=-1;
1487		$len=sizeof($obj);
1488		while(++$i<$len)
1489			$temp[$obj[$i]->Name]=$obj[$i];
1490		$keys=array_keys($temp);
1491		sort($keys);
1492		$res=Array();
1493		$i=-1;
1494		while(++$i<$len)
1495			$res[]=$temp[$keys[$i]];
1496		return $res;
1497	}
1498	
1499	/**
1500	 * Output the HTML to the client, if requested
1501	 * 
1502	 * @param boolean $andExit Exit after sending HTML? (default: TRUE)
1503	 * @return boolean Has the HTML been sent to the client?
1504	 */
1505	public function OutputHtmlOnRequest($andExit=true){
1506		if(!$this->IsHtmlRequested())
1507			return false;
1508		$this->OutputHtml();
1509		if($andExit){
1510			self::Debug('Exit script execution');
1511			exit;
1512		}
1513		return true;
1514	}
1515	
1516	/**
1517	 * Output the PHP SOAP client source for this webservice
1518	 * 
1519	 * @param boolean $withHeaders Send text headers? (default: TRUE)
1520	 * @param boolean $echo Print source (default: TRUE)
1521	 * @param array $options Options array (default: array)
1522	 * @param boolean $cache Cache the result (default: TRUE);
1523	 * @return string PHP source
1524	 */
1525	public function OutputPhp($withHeaders=true,$echo=true,$options=Array(),$cache=true){
1526		self::Debug('Output PHP');
1527		if(sizeof($this->Methods)<1)
1528			$this->CreateWsdl();
1529		if(!self::CallHook(
1530				'OutputPhpHook',
1531				Array(
1532					'server'		=>	$this,
1533					'withHeaders'	=>	&$withHeaders,
1534					'echo'			=>	&$echo,
1535					'options'		=>	&$options
1536				)
1537			)
1538		)
1539			return '';
1540		// Options
1541		$hasOptions=sizeof(array_keys($options))>0;
1542		if(!isset($options['class']))
1543			$options['class']=$this->Name.'SoapClient';
1544		if(!isset($options['openphp']))
1545			$options['openphp']=true;
1546		if(!isset($options['phpclient']))
1547			$options['phpclient']=true;
1548		$data=Array(
1549			'server'		=>	$this,
1550			'withHeaders'	=>	&$withHeaders,
1551			'echo'			=>	&$echo,
1552			'options'		=>	&$options,
1553			'res'			=>	&$res
1554		);
1555		// Header
1556		if($withHeaders){
1557			header('Content-Type: text/plain; charset=UTF-8',true);
1558			header('Content-Disposition: attachment; filename='.$options['class'].'.php');
1559		}
1560		if(!$hasOptions){
1561			if(is_null($this->PHP))
1562				$this->GetWsdlFromCache();
1563			if(!is_null($this->PHP)){
1564				if($echo)
1565					echo $this->PHP;
1566				return $this->PHP;
1567			}
1568		}else if(isset($options['php'])&&!is_null($options['php'])){
1569			echo $options['php'];
1570			return $options['php'];
1571		}
1572		$res=Array();
1573		if($options['openphp'])
1574			$res[]="<?php";
1575		$res[]="/**";
1576		if(!is_null($this->Docs)){
1577			$res[]=" * ".implode("\n * ",explode("\n",$this->Docs));
1578			$res[]=" *";
1579		}
1580		$res[]=" * @service ".$options['class'];
1581		$res[]=" */";
1582		$res[]="class ".$options['class']."{";
1583		$res[]="\t/**";
1584		$res[]="\t * The WSDL URI";
1585		$res[]="\t *";
1586		$res[]="\t * @var string";
1587		$res[]="\t */";
1588		$res[]="\tpublic static \$_WsdlUri='".(!is_null($this->WsdlUri)?$this->WsdlUri:$this->EndPoint.'?wsdl')."';";
1589		$res[]="\t/**";
1590		$res[]="\t * The PHP SoapClient object";
1591		$res[]="\t *";
1592		$res[]="\t * @var object";
1593		$res[]="\t */";
1594		$res[]="\tpublic static \$_Server=null;";
1595		self::CallHook('BeginCreatePhpHook',$data);
1596		$res[]='';
1597		$res[]="\t/**";
1598		$res[]="\t * Send a SOAP request to the server";
1599		$res[]="\t *";
1600		$res[]="\t * @param string \$method The method name";
1601		$res[]="\t * @param array \$param The parameters";
1602		$res[]="\t * @return mixed The server response";
1603		$res[]="\t */";
1604		$res[]="\tpublic static function _Call(\$method,\$param){";
1605		if(self::CallHook('CreatePhpCallHook',$data)){
1606			$res[]="\t\tif(is_null(self::\$_Server))";
1607			if($options['phpclient']){
1608				$res[]="\t\t\tself::\$_Server=new SoapClient(self::\$_WsdlUri);";
1609				$res[]="\t\treturn self::\$_Server->__soapCall(\$method,\$param);";
1610			}else{
1611				$res[]="\t\t\tself::\$_Server=new PhpWsdlClient(self::\$_WsdlUri);";
1612				$res[]="\t\treturn self::\$_Server->DoRequest(\$method,\$param);";
1613			}
1614		}
1615		$res[]="\t}";
1616		// Methods
1617		$i=-1;
1618		$len=sizeof($this->Methods);
1619		while(++$i<$len){
1620			$res[]='';
1621			$this->Methods[$i]->CreateMethodPhp($data);
1622		}
1623		$res[]="}";
1624		// Types
1625		$i=-1;
1626		$len=sizeof($this->Types);
1627		while(++$i<$len){
1628			$res[]='';
1629			$this->Types[$i]->CreateTypePhp($data);
1630		}
1631		self::CallHook('EndCreatePhpHook',$data);
1632		$res=utf8_encode(implode("\n",$res));
1633		if(!$hasOptions){
1634			if(is_null($this->PHP))
1635				$this->PHP=$res;
1636			if($cache)
1637				$this->WriteWsdlToCache(null,null,null,true);
1638		}
1639		if($echo)
1640			echo $res;
1641		return $res;
1642	}
1643	
1644	/**
1645	 * Output the PHP SOAP client source for this webservice, if requested
1646	 * 
1647	 * @param boolean $andExit Exit after sending the PHP source?
1648	 * @return boolean PHP sent?
1649	 */
1650	public function OutputPhpOnRequest($andExit=true){
1651		if(!$this->IsPhpRequested())
1652			return false;
1653		$this->OutputPhp();
1654		if($andExit){
1655			self::Debug('Exit script execution');
1656			exit;
1657		}
1658		return true;
1659	}
1660	
1661	/**
1662	 * Run the PHP SoapServer
1663	 * 
1664	 * @param string $wsdlFile The WSDL file name or NULL to let PhpWsdl decide (default: NULL)
1665	 * @param string|object|array $class The class name to serve, the classname and class as array or NULL (default: NULL)
1666	 * @param boolean $andExit Exit after running the server? (default: TRUE)
1667	 * @param boolean $forceNoWsdl Force no WSDL usage? (default: FALSE);
1668	 * @return boolean Did the server run?
1669	 */
1670	public function RunServer($wsdlFile=null,$class=null,$andExit=true,$forceNoWsdl=false){
1671		self::Debug('Run the server');
1672		if($forceNoWsdl)
1673			self::Debug('Forced non-WSDL mode');
1674		if(self::CallHook(
1675				'BeforeRunServerHook',
1676				Array(
1677					'server'		=>	$this,
1678					'wsdlfile'		=>	&$wsdlFile,
1679					'class'			=>	&$class,
1680					'andexit'		=>	&$andExit,
1681					'forcenowsdl'	=>	&$forceNoWsdl
1682				)
1683			)
1684		){
1685			// WSDL requested?
1686			if($this->OutputWsdlOnRequest($andExit))
1687				return false;
1688			// PHP requested?
1689			if($this->OutputPhpOnRequest($andExit))
1690				return false;
1691			// HTML requested?
1692			if($this->OutputHtmlOnRequest($andExit))
1693				return false;
1694		}
1695		// Login
1696		$user=null;
1697		$password=null;
1698		if($this->RequireLogin){
1699			if(isset($_SERVER['PHP_AUTH_USER'])||isset($_SERVER['PHP_AUTH_PW'])){
1700				$user=(isset($_SERVER['PHP_AUTH_USER']))?$_SERVER['PHP_AUTH_USER']:null;
1701				$password=(isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW']:null;
1702			}
1703			self::Debug('Check login '.$user.':'.str_repeat('*',strlen($password)));
1704			if(!self::CallHook(
1705					'LoginHook',
1706					Array(
1707						'server'		=>	$this,
1708						'user'			=>	&$user,
1709						'password'		=>	&$password
1710					)
1711				)
1712			){
1713				self::Debug('Login required');
1714				header('WWW-Authenticate: Basic realm="SOAP webservice login required"');
1715			    header('HTTP/1.0 401 Unauthorized');
1716				if($andExit){
1717					self::Debug('Exit script execution');
1718					exit;
1719				}
1720			    return false;
1721			}
1722		}
1723		// Load the proxy
1724		$useProxy=false;
1725		if(is_array($class)){
1726			self::Debug('Use the proxy for '.$class[0]);
1727			self::$ProxyObject=$class[1];
1728			self::$ProxyServer=$this;
1729			$class=$class[0];
1730			$useProxy=true;
1731		}
1732		// Ensure a webservice name
1733		if(is_null($class)){
1734			self::Debug('No webservice name yet');
1735			if(!$this->DetermineConfiguration())
1736				throw(new Exception('Invalid configuration'));
1737			if(!is_null($this->Name))
1738				$class=$this->Name;
1739		}else if(is_string($class)){
1740			self::Debug('Using '.$class.' as webservice name');
1741			$this->Name=$class;
1742		}
1743		self::Debug('Use class '.((!is_object($class))?$class:get_class($class)));
1744		// Load WSDL
1745		if(!$forceNoWsdl&&(!$useProxy||self::$UseProxyWsdl)){
1746			self::Debug('Load WSDL');
1747			$this->CreateWsdl(false,true);
1748			if(is_null($wsdlFile))
1749				$wsdlFile=$this->GetCacheFileName();
1750			if(!is_null($wsdlFile))
1751				if(!file_exists($wsdlFile)){
1752					self::Debug('WSDL file "'.$wsdlFile.'" does not exists');
1753					$wsdlFile=null;
1754				}
1755		}
1756		// Load the files, if the webservice handler class doesn't exist
1757		if(!is_object($class))
1758			if(!class_exists($class)&&!$this->IsOnlyGlobal()){
1759				self::Debug('Try to load the webservice handler class');
1760				$i=-1;
1761				$len=sizeof($this->Files);
1762				while(++$i<$len){
1763					self::Debug('Load '.$this->Files[$i]);
1764					require_once($this->Files[$i]);
1765				}
1766				if(!class_exists($class)){
1767					// Try class.webservice.php
1768					if(file_exists('class.webservice.php')){
1769						self::Debug('Try to load class.webservice.php');
1770						require_once('class.webservice.php');
1771						if(class_exists($class))
1772							$this->Files[]='class.webservice.php';
1773					}
1774					if(!class_exists($class))
1775						if(file_exists(dirname(__FILE__).'/class.webservice.php')){
1776							self::Debug('Try to load '.dirname(__FILE__).'/class.webservice.php');
1777							require_once(dirname(__FILE__).'/class.webservice.php');
1778							if(class_exists($class))
1779								$this->Files[]=dirname(__FILE__).'/class.webservice.php';
1780						}
1781					if(!class_exists($class))
1782						// A handler class or object is required when using non-global methods!
1783						throw(new Exception('Webservice handler class not present'));
1784				}
1785			}
1786		// Prepare the SOAP server
1787		$this->SoapServer=null;
1788		if(self::CallHook(
1789				'PrepareServerHook',
1790				Array(
1791					'server'		=>	$this,
1792					'soapserver'	=>	&$this->SoapServer,
1793					'wsdlfile'		=>	&$wsdlFile,
1794					'class'			=>	&$class,
1795					'useproxy'		=>	&$useProxy,
1796					'forcenowsdl'	=>	&$forceNoWsdl,
1797					'andexit'		=>	&$andExit,
1798					'user'			=>	&$user,
1799					'password'		=>	&$password
1800				)
1801			)
1802		){
1803			self::Debug('Prepare the SOAP server');
1804			// WSDL file
1805			$wsdlFile=($forceNoWsdl||($useProxy&&!self::$UseProxyWsdl))?null:$wsdlFile;
1806			if(!is_null($wsdlFile)){
1807				self::Debug('Using WSDL file '.$wsdlFile);
1808			}else{
1809				self::Debug('No WSDL file');
1810			}
1811			// Server options
1812			$temp=Array(
1813				'actor'			=>	$this->EndPoint,
1814				'uri'			=>	$this->NameSpace,
1815			);
1816			$temp=array_merge($this->SoapServerOptions,$temp);
1817			if(self::$Debugging)
1818				self::Debug('Server options: '.print_r($temp,true));
1819			// Create the server object
1820			self::Debug('Creating PHP SoapServer object');
1821			$this->SoapServer=new SoapServer(
1822				$wsdlFile,
1823				$temp
1824			);
1825			// Set the handler class or object
1826			if($useProxy||!is_object($class)){
1827				$temp=($useProxy)?'PhpWsdlProxy':$class;
1828				if(!is_null($temp)){
1829					self::Debug('Setting server class '.$temp);
1830					$this->SoapServer->setClass($temp);
1831				}else{
1832					self::Debug('No server class or object');
1833				}
1834			}else{
1835				self::Debug('Setting server object '.get_class($class));
1836				$this->SoapServer->setObject($class);
1837			}
1838			// Add global methods
1839			$i=-1;
1840			$len=sizeof($this->Methods);
1841			while(++$i<$len)
1842				if($this->Methods[$i]->IsGlobal){
1843					self::Debug('Adding global method '.$this->Methods[$i]->Name);
1844					$this->SoapServer->addFunction($this->Methods[$i]->Name);
1845				}
1846		}
1847		// Run the SOAP server
1848		if(self::CallHook(
1849				'RunServerHook',
1850				Array(
1851					'server'		=>	$this,
1852					'soapserver'	=>	&$this->SoapServer,
1853					'wsdlfile'		=>	&$wsdlFile,
1854					'class'			=>	&$class,
1855					'useproxy'		=>	&$useProxy,
1856					'forcenowsdl'	=>	&$forceNoWsdl,
1857					'andexit'		=>	&$andExit,
1858					'user'			=>	&$user,
1859					'password'		=>	&$password
1860				)
1861			)
1862		){
1863			self::Debug('Run the SOAP server');
1864			$this->SoapServer->handle();
1865			if($andExit){
1866				self::Debug('Exit script execution');
1867				exit;
1868			

Large files files are truncated, but you can click here to view the full file