PageRenderTime 18ms CodeModel.GetById 134ms app.highlight 70ms RepoModel.GetById 1ms app.codeStats 0ms

/class.phpwsdl.php

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

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