PageRenderTime 52ms CodeModel.GetById 3ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 1ms

/servers/class.phpwsdl.servers.php

http://php-wsdl-creator.googlecode.com/
PHP | 1762 lines | 1193 code | 54 blank | 515 comment | 140 complexity | 3938d2aa575a8c539bf73749aab145ec 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
  23PhpWsdl::Debug('Servers extension loaded');
  24
  25PhpWsdl::RegisterHook('InterpretKeywordpw_restHook','servers','PhpWsdlServers::InterpretRest');
  26PhpWsdl::RegisterHook('BeforeRunServerHook','servers','PhpWsdlServers::BeforeRunServerHook');
  27PhpWsdl::RegisterHook('PrepareServerHook','servers','PhpWsdlServers::PrepareServerHook');
  28PhpWsdl::RegisterHook('RunServerHook','servers','PhpWsdlServers::RunServerHook');
  29PhpWsdl::RegisterHook('BeginCreatePhpHook','servers','PhpWsdlServers::BeginCreatePhpHook');
  30PhpWsdl::RegisterHook('OutputPhpHook','servers','PhpWsdlServers::OutputPhpHook');
  31PhpWsdl::RegisterHook('CreatePhpCallHook','servers','PhpWsdlServers::CreatePhpCallHook');
  32PhpWsdl::RegisterHook('CreateMethodPhpHook','servers','PhpWsdlServers::CreateMethodPhpHook');
  33PhpWsdl::RegisterHook('CreateHtmlGeneralHook','servers','PhpWsdlServers::CreateHtmlGeneralHook');
  34PhpWsdl::RegisterHook('CreateMethodHtmlHook','servers','PhpWsdlServers::CreateMethodHtmlHook');
  35PhpWsdl::RegisterHook('PdfAttachmentHook','servers','PhpWsdlServers::PdfAttachmentHook');
  36PhpWsdl::RegisterHook('CreateInstanceHook','servers','PhpWsdlServers::ConstructorHook');
  37
  38/**
  39 * Some http protocol servers (JSON, http, REST and XML RPC)
  40 * 
  41 * @author Andreas Müller-Saala, wan24.de
  42 */
  43class PhpWsdlServers{
  44	/**
  45	 * The GUID
  46	 * 
  47	 * @var string
  48	 */
  49	public $GUID;
  50	/**
  51	 * Disable the client cache?
  52	 * 
  53	 * @var boolean
  54	 */
  55	public static $DisableClientCache=true;
  56	/**
  57	 * Enable response compression?
  58	 * 
  59	 * @var boolean
  60	 */
  61	public static $EnableCompression=true;
  62	/**
  63	 * Enable the JSON server
  64	 * 
  65	 * @var boolean
  66	 */
  67	public static $EnableJson=true;
  68	/**
  69	 * Enable the http server
  70	 * 
  71	 * @var boolean
  72	 */
  73	public static $EnableHttp=true;
  74	/**
  75	 * Enable the REST server
  76	 * 
  77	 * @var boolean
  78	 */
  79	public static $EnableRest=true;
  80	/**
  81	 * Enable the RPC server
  82	 * 
  83	 * @var boolean
  84	 */
  85	public static $EnableRpc=true;
  86	/**
  87	 * Enable parameter names in XML RPC requests?
  88	 * 
  89	 * @var boolean
  90	 */
  91	public static $EnableRpcNamedParameters=false;
  92	/**
  93	 * Disable recoding arrays as objects in XML RPC mode?
  94	 * 
  95	 * @var boolean
  96	 */
  97	public static $NoRpcRecode=false;
  98	/**
  99	 * Is this an RPC request?
 100	 * 
 101	 * @var boolean|NULL
 102	 */
 103	private static $IsRpcRequest=null;
 104	/**
 105	 * The server object that will be used to run the server
 106	 * 
 107	 * @var PhpWsdlServers
 108	 */
 109	public static $UseServer=null;
 110	/**
 111	 * Attach JavaScript to PDF?
 112	 * 
 113	 * Note: JavaScript can be attached, but the user can't save JavaScript attachments with 
 114	 * Adobe Acrobat Reader per default. To open them from Windows the registry at (f.e.) 
 115	 * HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Adobe\Adobe Reader\[VERSION]\FeatureLockDown\cDefaultLaunchAttachmentPerms 
 116	 * has to be touched manually!
 117	 * 
 118	 * @var boolean
 119	 */
 120	public static $AttachJsInPdf=false;
 121	/**
 122	 * The webservice handler class name
 123	 * 
 124	 * @var string
 125	 */
 126	public $ClassName=null;
 127	/**
 128	 * The webservice handler object
 129	 * 
 130	 * @var object
 131	 */
 132	public $Object=null;
 133	/**
 134	 * The PhpWsdl object
 135	 * 
 136	 * @var PhpWsdl
 137	 */
 138	public $Server=null;
 139	/**
 140	 * The cached PHP http client proxy
 141	 * 
 142	 * @var string
 143	 */
 144	public $HttpPhp=null;
 145	/**
 146	 * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPHTTPCLIENT"
 147	 * 
 148	 * @var string
 149	 */
 150	public $HttpPhpUri=null;
 151	/**
 152	 * Force sending HTTP PHP (has a higher priority than PhpWsdlServers->ForceNotOutputHttpPhp)
 153	 * 
 154	 * @var boolean
 155	 */
 156	public $ForceOutputHttpPhp=false;
 157	/**
 158	 * Force NOT sending HTTP PHP (disable sending HTTP PHP)
 159	 * 
 160	 * @var boolean
 161	 */
 162	public $ForceNotOutputHttpPhp=false;
 163	/**
 164	 * The cached PHP JSON client proxy
 165	 * 
 166	 * @var string
 167	 */
 168	public $JsonPhp=null;
 169	/**
 170	 * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPJSPNCLIENT"
 171	 * 
 172	 * @var string
 173	 */
 174	public $JsonPhpUri=null;
 175	/**
 176	 * Force sending JSON PHP (has a higher priority than PhpWsdlServers->ForceNotOutputJsonPhp)
 177	 * 
 178	 * @var boolean
 179	 */
 180	public $ForceOutputJsonPhp=false;
 181	/**
 182	 * Force NOT sending JSON PHP (disable sending JSON PHP)
 183	 * 
 184	 * @var boolean
 185	 */
 186	public $ForceNotOutputJsonPhp=false;
 187	/**
 188	 * The cached PHP REST client proxy
 189	 * 
 190	 * @var string
 191	 */
 192	public $RestPhp=null;
 193	/**
 194	 * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPRESTCLIENT"
 195	 * 
 196	 * @var string
 197	 */
 198	public $RestPhpUri=null;
 199	/**
 200	 * Force sending REST PHP (has a higher priority than PhpWsdlServers->ForceNotOutputRestPhp)
 201	 * 
 202	 * @var boolean
 203	 */
 204	public $ForceOutputRestPhp=false;
 205	/**
 206	 * Force NOT sending REST PHP (disable sending REST PHP)
 207	 * 
 208	 * @var boolean
 209	 */
 210	public $ForceNotOutputRestPhp=false;
 211	/**
 212	 * The cached PHP XML RPC client proxy
 213	 * 
 214	 * @var string
 215	 */
 216	public $RpcPhp=null;
 217	/**
 218	 * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPRPCCLIENT"
 219	 * 
 220	 * @var string
 221	 */
 222	public $RpcPhpUri=null;
 223	/**
 224	 * Force sending XML RPC PHP (has a higher priority than PhpWsdlServers->ForceNotOutputRpcPhp)
 225	 * 
 226	 * @var boolean
 227	 */
 228	public $ForceOutputRpcPhp=false;
 229	/**
 230	 * Force NOT sending XML RPC PHP (disable sending XML RPC PHP)
 231	 * 
 232	 * @var boolean
 233	 */
 234	public $ForceNotOutputRpcPhp=false;
 235	/**
 236	 * The cached JavaScript JSON client proxy
 237	 * 
 238	 * @var string
 239	 */
 240	public $JsonJs=null;
 241	/**
 242	 * Set this to the JavaScript URI, if it's different from your SOAP endpoint + "?JSJSONCLIENT"
 243	 * 
 244	 * @var string
 245	 */
 246	public $JsonJsUri=null;
 247	/**
 248	 * Force sending JSON JS (has a higher priority than PhpWsdlServers->ForceNotOutputJsonJs)
 249	 * 
 250	 * @var boolean
 251	 */
 252	public $ForceOutputJsonJs=false;
 253	/**
 254	 * Force NOT sending JSON JS (disable sending JSON JS)
 255	 * 
 256	 * @var boolean
 257	 */
 258	public $ForceNotOutputJsonJs=false;
 259	/**
 260	 * The cached and compressed JavaScript JSON client proxy
 261	 * 
 262	 * @var string
 263	 */
 264	public $JsonJsMin=null;
 265	/**
 266	 * Force the JSON JS compression (has a higher priority than PhpWsdlServers->ForceNotJsonJsMin)
 267	 * 
 268	 * @var boolean
 269	 */
 270	public $ForceJsonJsMin=false;
 271	/**
 272	 * Force NOT JSON JS compression (disable compression)
 273	 * 
 274	 * @var booleean
 275	 */
 276	public $ForceNotJsonJsMin=false;
 277	
 278	/**
 279	 * Constructor
 280	 * 
 281	 * @param PhpWsdl $server The PhpWsdl object
 282	 */
 283	public function PhpWsdlServers($server){
 284		$this->GUID=uniqid();
 285		PhpWsdl::Debug('New PhpWsdlServers "'.$this->GUID.'"');
 286		$this->Server=$server;
 287		self::$UseServer=$this;
 288		PhpWsdl::RegisterHook('ReadCacheHook','servers',Array($this,'ReadCacheHook'));
 289		PhpWsdl::RegisterHook('WriteCacheHook','servers',Array($this,'WriteCacheHook'));
 290	}
 291	
 292	/**
 293	 * Determine if the request is a JSON request
 294	 * 
 295	 * @return boolean JSON request?
 296	 */
 297	public static function IsJsonRequest(){
 298		return self::$EnableJson&&function_exists('json_encode')&&!self::HasParam('call')&&(self::HasParam('json')||self::HasParam('JSON'));
 299	}
 300	
 301	/**
 302	 * Determine if the request is a http request
 303	 * 
 304	 * @return boolean http request?
 305	 */
 306	public static function IsHttpRequest(){
 307		return self::$EnableHttp&&self::HasParam('call');
 308	}
 309	
 310	/**
 311	 * Determine if the request is a REST request
 312	 * 
 313	 * @return boolean REST request?
 314	 */
 315	public static function IsRestRequest(){
 316		return self::$EnableRest&&isset($_SERVER['PATH_INFO']);
 317	}
 318	
 319	/**
 320	 * Determine if the request is a RPC request
 321	 * 
 322	 * @return boolean RPC request?
 323	 */
 324	public static function IsRpcRequest(){
 325		if(!self::$EnableRpc||!is_null(self::$IsRpcRequest))
 326			return self::$EnableRpc&&self::$IsRpcRequest;
 327		if(function_exists('xmlrpc_server_create')){
 328			$in=file_get_contents('php://input');
 329			$xml=new DOMDocument();
 330			if($xml->loadXML($in)){
 331				$x=new DOMXPath($xml);
 332				$temp=$x->query('/*');
 333				self::$IsRpcRequest=$temp->length>0&&$temp->item(0)->nodeName=='methodCall';
 334			}else{
 335				self::$IsRpcRequest=false;
 336			}
 337		}else{
 338			self::$IsRpcRequest=false;
 339		}
 340		return self::$IsRpcRequest;
 341	}
 342	
 343	/**
 344	 * Determine if the PhpWsdlServers extension can handle this request
 345	 * 
 346	 * @return boolean Can handle?
 347	 */
 348	public static function CanHandleRequest(){
 349		return 
 350			self::IsHttpRequest()||
 351			self::IsJsonRequest()||
 352			self::IsRestRequest()||
 353			self::IsRpcRequest()||
 354			self::IsJsonPhpRequest()||
 355			self::IsJsonJsRequest()||
 356			self::IsHttpPhpRequest()||
 357			self::IsRestPhpRequest()||
 358			self::IsRpcPhpRequest();
 359	}
 360	
 361	/**
 362	 * Determine if the PHP JSON client proxy is requested
 363	 * 
 364	 * @return boolean Requested?
 365	 */
 366	public static function IsJsonPhpRequest(){
 367		return self::$EnableJson&&(self::$UseServer->ForceOutputJsonPhp||((self::HasParam('phpjsonclient')||self::HasParam('PHPJSONCLIENT'))&&!self::$UseServer->ForceNotOutputJsonPhp));
 368	}
 369	
 370	/**
 371	 * Determine if the JavaScript JSON client proxy is requested
 372	 * 
 373	 * @return boolean Requested?
 374	 */
 375	public static function IsJsonJsRequest(){
 376		return self::$EnableJson&&(self::$UseServer->ForceOutputJsonJs||((self::HasParam('jsjsonclient')||self::HasParam('JSJSONCLIENT'))&&!self::$UseServer->ForceNotOutputJsonJs));
 377	}
 378	
 379	/**
 380	 * Determine if the PHP XML RPC client proxy is requested
 381	 * 
 382	 * @return boolean Requested?
 383	 */
 384	public static function IsRpcPhpRequest(){
 385		return self::$EnableRpc&&(self::$UseServer->ForceOutputRpcPhp||((self::HasParam('phprpcclient')||self::HasParam('PHPRPCCLIENT'))&&!self::$UseServer->ForceNotOutputRpcPhp));
 386	}
 387
 388	/**
 389	 * Determine if the PHP http client proxy is requested
 390	 * 
 391	 * @return boolean Requested?
 392	 */
 393	public static function IsHttpPhpRequest(){
 394		return self::$EnableHttp&&(self::$UseServer->ForceOutputHttpPhp||((self::HasParam('phphttpclient')||self::HasParam('PHPHTTPCLIENT'))&&!self::$UseServer->ForceNotOutputHttpPhp));
 395	}
 396
 397	/**
 398	 * Determine if the PHP REST client proxy is requested
 399	 * 
 400	 * @return boolean Requested?
 401	 */
 402	public static function IsRestPhpRequest(){
 403		return self::$EnableRest&&(self::$UseServer->ForceOutputRestPhp||((self::HasParam('phprestclient')||self::HasParam('PHPRESTCLIENT'))&&!self::$UseServer->ForceNotOutputRestPhp));
 404	}
 405	
 406	/**
 407	 * Determine if we can handle the request
 408	 * 
 409	 * @param array $data The event data
 410	 * @return boolean Response
 411	 */
 412	public static function BeforeRunServerHook($data){
 413		if(!self::CanHandleRequest())
 414			return true;
 415		PhpWsdl::Debug('PhpWsdlServers will handle the request');
 416		$server=$data['server'];
 417		$server->GetWsdlFromCache();
 418		$srv=self::$UseServer;
 419		$jsonPhp=self::IsJsonPhpRequest();
 420		$jsonJs=self::IsJsonJsRequest();
 421		$rpcPhp=self::IsRpcPhpRequest();
 422		$httpPhp=self::IsHttpPhpRequest();
 423		$restPhp=self::IsRestPhpRequest();
 424		if(!$jsonPhp&&!$jsonJs&&!$rpcPhp&&!$httpPhp&&!$restPhp)
 425			return false;
 426		if($jsonJs){
 427			PhpWsdl::Debug('Output JavaScript requested');
 428			$srv->OutputJs();
 429		}else{
 430			PhpWsdl::Debug('Output PHP requested');
 431			$php=null;
 432			if($jsonPhp){
 433				$php=$srv->JsonPhp;
 434				$ext='json';
 435			}else if($rpcPhp){
 436				$php=$srv->RpcPhp;
 437				$ext='rpc';
 438			}else if($httpPhp){
 439				$php=$srv->HttpPhp;
 440				$ext='http';
 441			}else{
 442				$php=$srv->RestPhp;
 443				$ext='rest';
 444			}
 445			$cache=is_null($php);
 446			$php=$server->OutputPhp(
 447				true,
 448				true,
 449				Array(
 450					'serversext'	=>	$ext
 451				)
 452			);
 453			if($cache){
 454				switch($ext){
 455					case 'json':
 456						$srv->JsonPhp=$php;
 457						break;
 458					case 'http':
 459						$srv->HttpPhp=$php;
 460						break;
 461					case 'rest':
 462						$srv->RestPhp=$php;
 463						break;
 464					case 'rpc':
 465						$srv->RpcPhp=$php;
 466						break;
 467				}
 468				$server->WriteWsdlToCache(null,null,null,true);
 469			}
 470		}
 471		PhpWsdl::Debug('Quit script execution');
 472		exit;
 473	}
 474	
 475	/**
 476	 * Create a server object
 477	 * 
 478	 * @param array $data The event data
 479	 * @return boolean Response
 480	 */
 481	public static function PrepareServerHook($data){
 482		if(!self::CanHandleRequest())
 483			return true;
 484		PhpWsdl::Debug('Prepare a JSON/http/REST/RPC server');
 485		$server=&$data['server'];
 486		$srv=self::$UseServer;
 487		$data['soapserver']=$srv;
 488		$useProxy=&$data['useproxy'];
 489		$class=&$data['class'];
 490		if($useProxy||!is_object($class)){
 491			$temp=($useProxy)?'PhpWsdlProxy':$class;
 492			if(!is_null($temp)){
 493				PhpWsdl::Debug('Setting server class '.$temp);
 494				$srv->ClassName=$temp;
 495			}else{
 496				PhpWsdl::Debug('No server class or object');
 497			}
 498		}else{
 499			PhpWsdl::Debug('Setting server object '.get_class($class));
 500			$srv->Object=$class;
 501		}
 502		return false;
 503	}
 504	
 505	/**
 506	 * Run the server
 507	 * 
 508	 * @param array $data The event data
 509	 * @return boolean Response
 510	 */
 511	public static function RunServerHook($data){
 512		if(!self::CanHandleRequest())
 513			return true;
 514		if(get_class($data['soapserver'])!='PhpWsdlServers'){
 515			PhpWsdl::Debug('Not a valid server object');
 516			return true;
 517		}
 518		PhpWsdl::Debug('Handle the request');
 519		if(self::IsJsonRequest()){
 520			$res=$data['soapserver']->HandleJsonRequest();
 521		}else if(self::IsHttpRequest()){
 522			return $data['soapserver']->HandleHttpRequest();
 523		}else if(self::IsRestRequest()){
 524			return $data['soapserver']->HandleRestRequest();
 525		}else if(self::IsRpcRequest()){
 526			return $data['soapserver']->HandleRpcRequest();
 527		}else{
 528			throw(new Exception('Could not handle request'));
 529		}
 530		if($data['andexit']){
 531			PhpWsdl::Debug('Stopping script execution');
 532			exit;
 533		}
 534		return $res;
 535	}
 536	
 537	/**
 538	 * Interpret a REST declaration
 539	 * 
 540	 * @param array $data The event data
 541	 * @return boolean Response
 542	 */
 543	public static function InterpretRest($data){
 544		if($data['method']=='')
 545			return true;
 546		PhpWsdl::Debug('Interpret REST "'.$data['keyword'][1].'" for method "'.$data['method'].'"');
 547		$info=explode(' ',$data['keyword'][1],3);
 548		$iLen=sizeof($info);
 549		if($iLen<2){
 550			PhpWsdl::Debug('Invalid REST definition');
 551			return true;
 552		}
 553		$method=$info[0];
 554		$path=$info[1];
 555		$docs=($iLen>2)?$info[2]:null;
 556		$settings=&$data['settings'];
 557		if(!isset($settings['settings']))
 558			$settings['settings']=Array();
 559		$settings=&$settings['settings'];
 560		if(!isset($settings['rest']))
 561			$settings['rest']=Array();
 562		$settings=&$settings['rest'];
 563		if(!isset($settings[$method]))
 564			$settings[$method]=Array();
 565		$settings=&$settings[$method];
 566		$settings[]=Array(
 567			'path'			=>	$path,
 568			'docs'			=>	$docs
 569		);
 570		return false;
 571	}
 572	
 573	/**
 574	 * Create PHP properties
 575	 * 
 576	 * @param array $data The event data
 577	 * @return boolean Response
 578	 */
 579	public static function BeginCreatePhpHook($data){
 580		if(!isset($data['options']['serversext']))
 581			return true;
 582		$res=&$data['res'];
 583		$res[]="\t/**";
 584		$res[]="\t * The endpoint URI";
 585		$res[]="\t *";
 586		$res[]="\t * @var string";
 587		$res[]="\t */";
 588		$res[]="\tpublic static \$_EndPoint='".$data['server']->EndPoint."';";
 589		return false;
 590	}
 591	
 592	/**
 593	 * Change the class name
 594	 * 
 595	 * @param array $data The event data
 596	 * @return boolean Response
 597	 */
 598	public static function OutputPhpHook($data){
 599		if(!isset($data['options']['serversext'])||isset($options['class']))
 600			return true;
 601		switch($data['options']['serversext']){
 602			case 'http':
 603				$ext='Http';
 604				break;
 605			case 'json':
 606				$ext='Json';
 607				break;
 608			case 'rest':
 609				$ext='Rest';
 610				break;
 611			case 'rpc':
 612				$ext='XmlRpc';
 613				break;
 614			default:
 615				return true;
 616				break;
 617		}
 618		$data['options']['class']=$data['server']->Name.$ext.'Client';
 619		return true;
 620	}
 621	
 622	/**
 623	 * Create PHP code for a server request
 624	 * 
 625	 * @param array $data The event data
 626	 * @return boolean Response
 627	 */
 628	public static function CreatePhpCallHook($data){
 629		if(!isset($data['options']['serversext']))
 630			return true;
 631		$res=&$data['res'];
 632		switch($data['options']['serversext']){
 633			case 'json':
 634				PhpWsdl::Debug('Create PhpWsdlServers JSON PHP client code');
 635				$res[]="\t\t".'$call=Array(';
 636				$res[]="\t\t\t".'"call"=>$method,';
 637				$res[]="\t\t\t".'"param"=>$param';
 638				$res[]="\t\t".');';
 639				$res[]="\t\t".'return json_decode(file_get_contents(self::$_EndPoint."?JSON=".urlencode(json_encode($call))));';
 640				break;
 641			case 'rpc':
 642				PhpWsdl::Debug('Create PhpWsdlServers XML RPC PHP client code');
 643				$res[]="\t\t".'self::$_Server=stream_context_create(Array(';
 644				$res[]="\t\t\t".'"http"			=>	Array(';
 645				$res[]="\t\t\t\t".'"method"			=>	"POST",';
 646				$res[]="\t\t\t\t".'"header"			=>	"Content-Type: text/xml",';
 647				$res[]="\t\t\t\t".'"content"			=>	xmlrpc_encode_request($method,$param)';
 648				$res[]="\t\t\t".')';
 649				$res[]="\t\t".'));';
 650				$res[]="\t\t".'$res=xmlrpc_decode(file_get_contents(self::$_EndPoint,false,self::$_Server));';
 651				$res[]="\t\t".'if(is_array($res)&&xmlrpc_is_fault($res))';
 652				$res[]="\t\t\t".'throw(new Exception($res["faultString"],$res["faultCode"]));';
 653				$res[]="\t\t".'return $res;';
 654				break;
 655			case 'http':
 656				PhpWsdl::Debug('Create PhpWsdlServers http PHP client code');
 657				$res[]="\t\t".'$param["call"]=$method;';
 658				$res[]="\t\t".'$temp=Array();';
 659				$res[]="\t\t".'$keys=array_keys($param);';
 660				$res[]="\t\t".'$i=-1;';
 661				$res[]="\t\t".'$len=sizeof($keys);';
 662				$res[]="\t\t".'while(++$i<$len)';
 663				$res[]="\t\t\t".'$temp[]=urlencode($keys[$i])."=".urlencode($param[$keys[$i]]);';
 664				$res[]="\t\t".'return file_get_contents(self::$_EndPoint."?".implode("&",$temp));';
 665				break;
 666			case 'rest':
 667				PhpWsdl::Debug('Create PhpWsdlServers REST PHP client code');
 668				$res[]="\t\t".'$keys=array_keys($param);';
 669				$res[]="\t\t".'$i=-1;';
 670				$res[]="\t\t".'$len=sizeof($keys);';
 671				$res[]="\t\t".'while(++$i<$len)';
 672				$res[]="\t\t\t".'$method=str_replace(" ".$keys[$i]."/",urlencode($param[$keys[$i]])."/",$method);';
 673				$res[]="\t\t".'return file_get_contents(self::$_EndPoint.$method);';
 674				break;
 675			default:
 676				return true;
 677				break;
 678		}
 679		return false;
 680	}
 681
 682	/**
 683	 * Create PHP code for a method call
 684	 * 
 685	 * @param array $data The event data
 686	 * @return boolean Response
 687	 */
 688	public static function CreateMethodPhpHook($data){
 689		if(!isset($data['options']['serversext']))
 690			return true;
 691		$server=$data['server'];
 692		$m=$data['method'];
 693		$res=&$data['res'];
 694		switch($data['options']['serversext']){
 695			case 'rest':
 696			case 'http':
 697				PhpWsdl::Debug('Create PhpWsdlServers http/REST PHP method code');
 698				$basicType=true;
 699				if(!is_null($m->Return))
 700					$basicType=in_array($m->Return->Type,PhpWsdl::$BasicTypes);
 701				$pLen=sizeof($m->Param);
 702				if($data['options']['serversext']!='rest'){
 703					$name=$m->Name;
 704				}else{
 705					$temp=Array('/'.$m->Name);
 706					$i=-1;
 707					while(++$i<$pLen)
 708						$temp[]=' '.$m->Param[$i]->Name;
 709					$name=implode('/',$temp).'/';
 710				}
 711				$res[]="\t\treturn ".(($basicType)?"":"json_decode(")."self::_Call('".$name."',Array(";
 712				$i=-1;
 713				while(++$i<$pLen){
 714					$p=$m->Param[$i];
 715					$res[]="\t\t\t'".$p->Name."'=>".((in_array($p->Type,PhpWsdl::$BasicTypes))?"\$".$p->Name:"json_encode(\$".$p->Name.")");
 716				}
 717				$res[]="\t\t))".(($basicType)?"":")").";";
 718				break;
 719			case 'rpc':
 720				if(!self::$EnableRpcNamedParameters)
 721					return true;
 722				PhpWsdl::Debug('Create PhpWsdlServers XML RPC PHP method code for named parameters');
 723				$res[]="\t\treturn self::_Call('".$server->Name."',Array(";
 724				$i=-1;
 725				$len=sizeof($m->Param);
 726				while(++$i<$len)
 727					$res[]="\t\t\t".'"'.$m->Param[$i]->Name.'"=>$'.$m->Param[$i]->Name;
 728				$res[]="\t\t));";
 729				break;
 730			default:
 731				return true;
 732				break;
 733		}
 734		return false;
 735	}
 736	
 737	/**
 738	 * Extend general HTML documentation
 739	 * 
 740	 * @param array $data The event data
 741	 * @return boolean Response
 742	 */
 743	public static function CreateHtmlGeneralHook($data){
 744		if(!self::$EnableHttp&&!self::$EnableJson&&!self::$EnableRest&&!self::$EnableRpc)
 745			return true;
 746		PhpWsdl::Debug('Append HTML general information with PhpWsdlServers information');
 747		$server=$data['server'];
 748		$res=&$data['res'];
 749		$temp=Array('SOAP');
 750		if(self::$EnableJson){
 751			$temp[]='JSON';
 752			if(!$server->ForceNotOutputJsonPhp){
 753				$url=self::$UseServer->GetJsonPhpUri();
 754				$res[]='<p>PHP JSON client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 755			}
 756			if(!$server->ForceNotOutputJsonJs){
 757				$url=self::$UseServer->GetJsonJsUri();
 758				$res[]='<p>JavaScript JSON client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 759				if(self::IsJsPackerAvailable()){
 760					$url=self::$UseServer->GetJsonJsUri().'&min';
 761					$res[]='<p>Compressed JavaScript JSON client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 762				}
 763			}
 764		}
 765		if(self::$EnableRpc&&!$server->ForceNotOutputRpcPhp){
 766			$temp[]='XML RPC';
 767			$url=self::$UseServer->GetRpcPhpUri();
 768			$res[]='<p>PHP XML RPC client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 769		}
 770		if(self::$EnableHttp&&!$server->ForceNotOutputHttpPhp){
 771			$temp[]='http';
 772			$url=self::$UseServer->GetHttpPhpUri();
 773			$res[]='<p>PHP http client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 774		}
 775		if(self::$EnableRest&&!$server->ForceNotOutputRestPhp){
 776			$temp[]='REST';
 777			$url=self::$UseServer->GetRestPhpUri();
 778			$res[]='<p>PHP REST client download URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 779		}
 780		if(sizeof($temp)>1)
 781			$res[]='<p>The PhpWsdlServers extension allows PhpWsdl to serve these protocols: '.implode(', ',$temp).'</p>';
 782		return true;
 783	}
 784
 785	/**
 786	 * Extend method HTML documentation
 787	 * 
 788	 * @param array $data The event data
 789	 * @return boolean Response
 790	 */
 791	public static function CreateMethodHtmlHook($data){
 792		if(!self::$EnableRest)
 793			return true;
 794		PhpWsdl::Debug('Append HTML method information with PhpWsdlServers information');
 795		$res=&$data['res'];
 796		$server=$data['server'];
 797		$m=$data['method'];
 798		if(!is_null($m->Settings))
 799			if(isset($m->Settings['rest'])){
 800				$temp=$m->Settings['rest'];
 801				$keys=array_keys($temp);
 802				$i=-1;
 803				$len=sizeof($keys);
 804				while(++$i<$len){
 805					$method=$keys[$i];
 806					$rest=$temp[$keys[$i]];
 807					$rTemp=Array();
 808					$j=-1;
 809					$rLen=sizeof($rest);
 810					while(++$j<$rLen){
 811						$url=$server->EndPoint.$rest[$j]['path'];
 812						$rTemp[]='<span class="bold">'.$method.'</span> REST URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span>';
 813						if(!is_null($rest[$j]['docs']))
 814							$rTemp[]='('.nl2br(htmlentities($rest[$j]['docs'])).')';
 815					}
 816					$res[]='<p>'.implode("<br>\n",$rTemp).'</p>';
 817				}
 818			}
 819		$url=$server->EndPoint.'/'.$m->Name.'/';
 820		$pLen=sizeof($m->Param);
 821		if($pLen>0){
 822			$i=-1;
 823			while(++$i<$pLen)
 824				$url.=':'.$m->Param[$i]->Name.'/';
 825		}
 826		$res[]='<p>Default <span class="bold">GET</span> REST URI: <span class="pre"><a href="'.$url.'">'.$url.'</a></span></p>';
 827		return true;
 828	}
 829	
 830	/**
 831	 * Attach the PHP client sources
 832	 * 
 833	 * @param array $data The event data
 834	 * @return boolean Response
 835	 */
 836	public static function PdfAttachmentHook($data){
 837		$temp=&$data['param'];
 838		$cnt=&$data['cnt'];
 839		$server=$data['server'];
 840		if(self::$EnableJson){
 841			if(!$server->ForceNotOutputJsonPhp){
 842				$cnt++;
 843				$temp['attachment_'.$cnt]=$server->Name.'.jsonclient.php:'.self::$UseServer->GetJsonPhpUri();
 844			}
 845			if(self::$AttachJsInPdf&&!$server->ForceNotOutputJsonJs){
 846				$cnt++;
 847				$temp['attachment_'.$cnt]=$server->Name.'.jsonclient.js:'.self::$UseServer->GetJsonJsUri();
 848				if(self::IsJsPackerAvailable()){
 849					$cnt++;
 850					$temp['attachment_'.$cnt]=$server->Name.'.jsonclient.min.js:'.self::$UseServer->GetJsonJsUri().'&min';
 851				}
 852			}
 853		}
 854		if(self::$EnableRpc&&!$server->ForceNotOutputRpcPhp){
 855			$cnt++;
 856			$temp['attachment_'.$cnt]=$server->Name.'.xmlrpcclient.php:'.self::$UseServer->GetRpcPhpUri();
 857		}
 858		if(self::$EnableHttp&&!$server->ForceNotOutputHttpPhp){
 859			$cnt++;
 860			$temp['attachment_'.$cnt]=$server->Name.'.httpclient.php:'.self::$UseServer->GetHttpPhpUri();
 861		}
 862		if(self::$EnableRest&&!$server->ForceNotOutputRestPhp){
 863			$cnt++;
 864			$temp['attachment_'.$cnt]=$server->Name.'.restclient.php:'.self::$UseServer->GetRestPhpUri();
 865		}
 866		return true;
 867	}
 868	
 869	/**
 870	 * Constructor hook
 871	 * 
 872	 * @param array $data The event data
 873	 * @return boolean Response
 874	 */
 875	public static function ConstructorHook($data){
 876		new PhpWsdlServers($data['server']);
 877		return true;
 878	}
 879	
 880	/**
 881	 * Get the HTTP PHP download URI
 882	 * 
 883	 * @return string The URI
 884	 */
 885	public function GetHttpPhpUri(){
 886		return ((is_null($this->HttpPhpUri))?$this->Server->EndPoint:$this->HttpPhpUri).'?PHPHTTPCLIENT';
 887	}
 888
 889	/**
 890	 * Get the JSON PHP download URI
 891	 * 
 892	 * @return string The URI
 893	 */
 894	public function GetJsonPhpUri(){
 895		return ((is_null($this->JsonPhpUri))?$this->Server->EndPoint:$this->JsonPhpUri).'?PHPJSONCLIENT';
 896	}
 897	
 898	/**
 899	 * Get the REST PHP download URI
 900	 * 
 901	 * @return string The URI
 902	 */
 903	public function GetRestPhpUri(){
 904		return ((is_null($this->RestPhpUri))?$this->Server->EndPoint:$this->RestPhpUri).'?PHPRESTCLIENT';
 905	}
 906	
 907	/**
 908	 * Get the XML RPC PHP download URI
 909	 * 
 910	 * @return string The URI
 911	 */
 912	public function GetRpcPhpUri(){
 913		return ((is_null($this->RpcPhpUri))?$this->Server->EndPoint:$this->RpcPhpUri).'?PHPRPCCLIENT';
 914	}
 915	
 916	/**
 917	 * Get the JSON JavaScript download URI
 918	 * 
 919	 * @return string The URI
 920	 */
 921	public function GetJsonJsUri(){
 922		return ((is_null($this->JsonJsUri))?$this->Server->EndPoint:$this->JsonJsUri).'?JSJSONCLIENT';
 923	}
 924	
 925	/**
 926	 * Output the JavaScript JSON client source for this webservice
 927	 * 
 928	 * @param boolean $withHeaders Send JavaScript headers? (default: TRUE)
 929	 * @param boolean $echo Print source (default: TRUE)
 930	 * @param boolean $cache Cache the result (default: TRUE);
 931	 * @return string JavaScript source
 932	 */
 933	public function OutputJs($withHeaders=true,$echo=true,$cache=true){
 934		PhpWsdl::Debug('Output JavaScript');
 935		if(sizeof($this->Server->Methods)<1)
 936			$this->Server->CreateWsdl();
 937		if($withHeaders)
 938			$this->JavaScriptHeaders();
 939		if(is_null($this->JsonJs)){
 940			$res=Array();
 941			$data=Array(
 942				'server'		=>	$this,
 943				'res'			=>	&$data,
 944				'withheaders'	=>	&$withHeaders,
 945				'echo'			=>	&$echo,
 946				'cache'			=>	&$cache
 947			);
 948			if(PhpWsdl::CallHook('ServersBeginOutputJsHook',$data)){
 949				$res[]='var '.$this->Server->Name.'JsonClient=function(){';
 950				$res[]='	this._EndPoint="'.$this->Server->EndPoint.'";';
 951				$res[]='	this._Call=function(method,param,cb,cbData){';
 952				$res[]='		var server=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");';
 953				$res[]='		server.open("POST",this._EndPoint,cb!=null);';
 954				$res[]='		server.setRequestHeader("Content-Type","application/x-www-form-urlencoded");';
 955				$res[]='		var req="json="+encodeURIComponent(JSON.stringify({call:method,param:(typeof(param)!="undefined")?param:[]}));';
 956				$res[]='		if(cb){';
 957				$res[]='			server.onreadystatechange=this._EndCall;';
 958				$res[]='			server.cb=cb;';
 959				$res[]='			server.cbData=(typeof(cbData)!="undefined")?cbData:null;';
 960				$res[]='			server.send(req);';
 961				$res[]='			return server;';
 962				$res[]='		}else{';
 963				$res[]='			server.send(req);';
 964				$res[]='			var res=JSON.parse(server.responseText);';
 965				$res[]='			delete(server);';
 966				$res[]='			return res;';
 967				$res[]='		}';
 968				$res[]='	};';
 969				$res[]='	this._EndCall=function(e){';
 970				$res[]='		var server=e.currentTarget;';
 971				$res[]='		if(server.readyState!=4)';
 972				$res[]='			return;';
 973				$res[]='		if(server.status!=200)';
 974				$res[]='			throw(new Exception("AJAX error "+server.status+": "+server.statusText));';
 975				$res[]='		if(server.cb)';
 976				$res[]='			server.cb(JSON.parse(server.responseText),server.cbData);';
 977				$res[]='		server.cb=null;';
 978				$res[]='		server.cbData=null;';
 979				$res[]='		delete(server);';
 980				$res[]='	};';
 981			}
 982			$i=-1;
 983			$len=sizeof($this->Server->Methods);
 984			while(++$i<$len){
 985				$m=$this->Server->Methods[$i];
 986				if(PhpWsdl::CallHook(
 987						'ServersOutputMethodJsHook',
 988						array_merge(
 989							$data,
 990							Array(
 991								'method'		=>	&$m
 992							)
 993						)
 994					)
 995				){
 996					$temp=Array();
 997					$j=-1;
 998					$pLen=sizeof($m->Param);
 999					while(++$j<$pLen)
1000						$temp[]=$m->Param[$j]->Name;
1001					$temp=implode(',',$temp);
1002					$res[]='	this.'.$m->Name.'=function('.$temp.(($temp!='')?',':'').'_cb,_cbData){';
1003					$res[]='		return this._Call("'.$m->Name.'",['.$temp.'],(typeof(_cb)!="undefined")?_cb:null,(typeof(_cbData)!="undefined")?_cbData:null);';
1004					$res[]='	};';
1005				}
1006			}
1007			$i=-1;
1008			$len=sizeof($this->Server->Types);
1009			while(++$i<$len){
1010				$t=$this->Server->Types[$i];
1011				if($t->IsArray)
1012					continue;
1013				if(PhpWsdl::CallHook(
1014						'ServersOutputTypeJsHook',
1015						array_merge(
1016							$data,
1017							Array(
1018								'type'			=>	&$t
1019							)
1020						)
1021					)
1022				){
1023					$eLen=sizeof($t->Elements);
1024					$j=-1;
1025					$class=get_class($t);
1026					switch($class){
1027						case 'PhpWsdlComplex':
1028							$temp=Array();
1029							if(!is_null($t->Inherit)){
1030								$it=$this->Server->GetType($t->Inherit);
1031								$j=-1;
1032								$tLen=sizeof($it->Elements);
1033								while(++$j<$tLen)
1034									$temp[]=$it->Elements[$j]->Name;
1035							}else{
1036								$tLen=0;
1037							}
1038							$j=-1;
1039							while(++$j<$eLen)
1040								$temp[]=$t->Elements[$j]->Name;
1041							$tLen+=$eLen;
1042							$res[]='	this.'.$t->Name.'=function('.implode(',',$temp).'){';
1043							$j=-1;
1044							while(++$j<$tLen)
1045								$res[]='		this.'.$temp[$j].'=(typeof('.$temp[$j].')!="undefined")?'.$temp[$j].':null;';
1046							$res[]='	};';
1047							break;
1048						case 'PhpWsdlEnum':
1049							$res[]='	this.'.$t->Name.'={';
1050							while(++$j<$eLen){
1051								$temp=explode('=',$t->Elements[$j],2);
1052								if(sizeof($temp)==1) $temp[]=$temp[0];
1053								$res[]='		"'.$temp[0].'":"'.addslashes($temp[1]).'"'.(($j<$eLen-1)?',':'');
1054							}
1055							$res[]='	};';
1056							break;
1057						default:
1058							PhpWsdl::Debug('WARNING: Could not create JavaScript code for unknown type "'.$class.'"!');
1059							break;
1060					}
1061				}
1062			}
1063			PhpWsdl::CallHook('ServersEndOutputJsHook',$data);
1064			$res[]='};';
1065			$res=utf8_encode(implode("\n",$res));
1066			$this->JsonJs=$res;
1067		}
1068		$min=$this->ForceJsonJsMin||(self::HasParam('min')&&self::IsJsPackerAvailable()&&!$this->ForceNotJsonJsMin);
1069		if($min){
1070			if(is_null($this->JsonJsMin))
1071				$this->JsonJsMin=$this->PackJavaScript($this->JsonJs);
1072			$res=$this->JsonJsMin;
1073		}else if(!$min){
1074			$res=$this->JsonJs;
1075		}
1076		if($cache)
1077			$this->Server->WriteWsdlToCache(null,null,null,true);
1078		if($echo)
1079			echo $res;
1080		return $res;
1081	}
1082	
1083	/**
1084	 * Get data from cache
1085	 * 
1086	 * @param array $data The event data
1087	 * @return boolean Response
1088	 */
1089	public function ReadCacheHook($data){
1090		$d=&$data['data'];
1091		$this->HttpPhp=$d['phphttp'];
1092		$this->JsonPhp=$d['phpjson'];
1093		$this->JsonJs=$d['jsjson'];
1094		$this->JsonJsMin=$d['jsjsonmin'];
1095		$this->RestPhp=$d['phprest'];
1096		$this->RpcPhp=$d['phprpc'];
1097		return true;
1098	}
1099	
1100	/**
1101	 * Write data to the cache
1102	 * 
1103	 * @param array $data The event data
1104	 * @return boolean Response
1105	 */
1106	public function WriteCacheHook($data){
1107		$d=&$data['data'];
1108		$d['phphttp']=$this->HttpPhp;
1109		$d['phpjson']=$this->JsonPhp;
1110		$d['jsjson']=$this->JsonJs;
1111		$d['jsjsonmin']=$this->JsonJsMin;
1112		$d['phprest']=$this->RestPhp;
1113		$d['phprpc']=$this->RpcPhp;
1114		return true;
1115	}
1116	
1117	/**
1118	 * Handle a REST request
1119	 * 
1120	 * @return boolean Response
1121	 */
1122	public function HandleRestRequest(){
1123		// Find the requested method
1124		$path=$_SERVER['PATH_INFO'];
1125		$temp=self::GetParam('method');
1126		$method=($temp=='')?$_SERVER['REQUEST_METHOD']:$temp;
1127		PhpWsdl::Debug('REST call "'.$method.'" at "'.$path.'"');
1128		$temp=$this->GetRestMethod($method,$path);
1129		if(is_null($temp))
1130			throw(new Exception('Method not found'));
1131		list($method,$target)=$temp;
1132    	$req=Array(
1133    		'call'		=>	$method->Name,
1134    		'param'		=>	Array()
1135    	);
1136    	PhpWsdl::CallHook(
1137    		'RestCallHook',
1138    		Array(
1139    			'server'		=>	$this,
1140    			'req'			=>	&$req,
1141    			'path'			=>	&$path,
1142    			'method'		=>	&$method,
1143    			'target'		=>	&$target
1144    		)
1145    	);
1146		// Collect the parameters
1147		if(PhpWsdl::CallHook(
1148				'RestParametersHook',
1149				Array(
1150	    			'server'		=>	$this,
1151	    			'req'			=>	&$req,
1152					'path'			=>	&$path,
1153	    			'method'		=>	&$method,
1154	    			'target'		=>	&$target
1155				)
1156			)
1157		){
1158			$pLen=sizeof($method->Param);
1159			if(is_null($target)){
1160				// Unknown parameter handling
1161				PhpWsdl::Debug('Undefined parameter handling');
1162				$temp=explode('/',$path);
1163				$tLen=sizeof($temp)-2;
1164				// Collect parameters from the path info
1165				$i=-1;
1166				while(++$i<$pLen){
1167					$p=$method->Param[$i];
1168					if($i>$tLen)
1169						break;
1170					PhpWsdl::Debug('Found parameter "'.$p->Name.'"');
1171					$req['param'][]=self::DecodeType($p->Type,urldecode($temp[$i+2]),true);
1172				}
1173			}else{
1174				// Fixed parameter handling
1175				PhpWsdl::Debug('Fixed parameter handling');
1176				if(strpos($target,':')>-1){
1177					PhpWsdl::Debug('Method with parameters');
1178					list($mTemp,$pTemp)=explode(':',$target,2);
1179				}else{
1180					PhpWsdl::Debug('Method without parameters');
1181					$mTemp=$target;
1182					$pTemp=false;
1183				}
1184				if($pTemp!==false){
1185					// Map input parameters to their names
1186					$temp=explode('/',substr($path,strlen($mTemp)));
1187					$tLen=sizeof($temp);
1188					$iMap=explode('/',str_replace(':','',$pTemp));
1189					$map=Array();
1190					$i=-1;
1191					$len=sizeof($iMap);
1192					while(++$i<$len)
1193						$map[$iMap[$i]]=$temp[$i];
1194					// Sort parameters
1195					$temp=Array();
1196					$i=-1;
1197					$lastValue=-1;
1198					while(++$i<$pLen){
1199						$p=$method->Param[$i];
1200						$name=$p->Name;
1201						if(isset($map[$name])){
1202							$temp[]=self::DecodeType($p->Type,urldecode($map[$name]),true);
1203							$lastValue=$i;
1204						}else{
1205							PhpWsdl::Debug('Parameter "'.$p->Name.'" not found');
1206							$temp[]=null;
1207						}
1208					}
1209					// Remove all parameters that are not present in the request
1210					if($lastValue>-1&&$lastValue<$pLen){
1211						$i=$lastValue;
1212						$req['param']=array_slice($temp,0,$lastValue+1);
1213					}else{
1214						$req['param']=$temp;
1215					}
1216				}else{
1217					$i=-1;
1218				}
1219			}
1220			// Collect the last parameter from the request body
1221			$in=file_get_contents('php://input');
1222			if($in!=''&&$i<$pLen&&$pLen>0){
1223				if(PhpWsdl::CallHook(
1224						'RestRequestHook',
1225						Array(
1226			    			'server'		=>	$this,
1227			    			'req'			=>	&$req,
1228			    			'path'			=>	&$path,
1229			    			'method'		=>	&$method,
1230			    			'target'		=>	&$target,
1231							'in'			=>	&$in,
1232							'index'			=>	$i
1233						)
1234					)
1235				){
1236					PhpWsdl::Debug('Use request body as parameter #'.($i+1));
1237					$req['param'][]=json_decode($temp);
1238				}
1239			}
1240		}
1241		if(PhpWsdl::$Debugging)
1242    		PhpWsdl::Debug('Parameters: '.print_r($req['param'],true));
1243    	// Execute the method and output the response
1244    	$temp=$this->HandleRequest($req,$method);
1245    	if(is_null($method->Return))
1246    		return false;// No return value -> no output
1247    	if(PhpWsdl::CallHook(
1248    			'RestResponseHook',
1249    			Array(
1250    				'server'		=>	$this,
1251    				'req'			=>	&$req,
1252    				'res'			=>	&$temp,
1253	    			'path'			=>	&$path,
1254	    			'method'		=>	&$method,
1255	    			'target'		=>	&$target
1256    			)
1257    		)
1258    	){
1259    		if(self::$EnableCompression)
1260    			ob_start('ob_gzhandler');
1261			$this->PlainTextHeaders();
1262			echo self::EncodeType($method->Return->Type,$temp);
1263    	}
1264    	return false;
1265	}
1266	
1267	/**
1268	 * Handle a JSON request
1269	 * 
1270	 * @return boolean Response
1271	 */
1272	public function HandleJsonRequest(){
1273    	// Decode the JSON request
1274    	$json=(self::HasParam('json'))?'json':'JSON';
1275    	$json=preg_replace('/([^\\])\\n/','\\n',$json);
1276    	$req=json_decode(self::GetParam($json));
1277		if(is_null($req)||!is_object($req))
1278			throw(new Exception('Invalid JSON object'));
1279		if(!isset($req->param))
1280    		$req->param=Array();
1281    	if(!isset($req->call))
1282    		throw(new Exception('Invalid JSON request'));
1283    	PhpWsdl::Debug('JSON call "'.$req->call.'"');
1284    	if(PhpWsdl::$Debugging)
1285    		PhpWsdl::Debug('Parameters: '.print_r($req->param,true));
1286    	$req=Array(
1287    		'call'			=>	$req->call,
1288    		'param'			=>	$req->param
1289    	);
1290    	// Find the requested method object
1291    	$method=$this->Server->GetMethod($req['call']);
1292    	if(is_null($method))
1293    		throw(new Exception('Method "'.$req['call'].'" not exists'));
1294    	// Execute the method and output the response
1295    	$temp=$this->HandleRequest($req,$method);
1296    	if(self::$EnableCompression)
1297    		ob_start('ob_gzhandler');
1298		$this->PlainTextHeaders();
1299		echo json_encode($temp);
1300    	return false;
1301	}
1302	
1303	/**
1304	 * Handle a http request
1305	 * 
1306	 * @return boolean Response
1307	 */
1308	public function HandleHttpRequest(){
1309    	// Initialize the method call
1310    	$req=Array(
1311    		'call'		=>	self::GetParam('call'),
1312    		'param'		=>	Array()
1313    	);
1314    	PhpWsdl::Debug('http call "'.$req['call'].'"');
1315    	// Find the requested method object and parameters
1316    	$method=$this->Server->GetMethod($req['call']);
1317    	if(is_null($method))
1318    		throw(new Exception('Method "'.$req['call'].'" not exists'));
1319    	if(PhpWsdl::CallHook(
1320    			'HttpParametersHook',
1321    			Array(
1322    				'server'		=>	$this,
1323    				'req'			=>	&$req,
1324    				'method'		=>	&$method
1325    			)
1326    		)
1327    	){
1328	    	$i=-1;
1329	    	$len=sizeof($method->Param);
1330	    	while(++$i<$len){
1331	    		$p=$method->Param[$i];
1332	    		if(!self::HasParam($method->Param[$i]->Name)){
1333	    			PhpWsdl::Debug('Collecting parameters stopped at missing "'.$method->Param[$i]->Name.'"');
1334	    			break;
1335	    		}
1336	    		$temp=self::GetParam($method->Param[$i]->Name);
1337	    		$req['param'][]=self::DecodeType($p->Type,$temp,true);
1338	    	}
1339    	}
1340    	if(PhpWsdl::$Debugging)
1341    		PhpWsdl::Debug('Parameters: '.print_r($req['param'],true));
1342    	// Execute the method and output the response
1343    	$temp=$this->HandleRequest($req,$method);
1344    	if(is_null($method->Return))
1345    		return false;// No return value -> no output
1346    	if(PhpWsdl::CallHook(
1347    			'HttpResponseHook',
1348    			Array(
1349    				'server'		=>	$this,
1350    				'req'			=>	&$req,
1351    				'res'			=>	&$temp,
1352    				'method'		=>	&$method
1353    			)
1354    		)
1355    	){
1356    		if(self::$EnableCompression)
1357				ob_start('ob_gzhandler');
1358			$this->PlainTextHeaders();
1359			echo self::EncodeType($method->Return->Type,$temp);
1360    	}
1361    	return false;
1362	}
1363	
1364	/**
1365	 * Handle a RPC request
1366	 * 
1367	 * @return boolean Response
1368	 */
1369	public function HandleRpcRequest(){
1370		if(!self::IsRpcRequest())
1371			return true;
1372		PhpWsdl::Debug('Run XML RPC server');
1373		$rpc=xmlrpc_server_create();
1374		$i=-1;
1375		$len=sizeof($this->Server->Methods);
1376		while(++$i<$len)
1377			xmlrpc_server_register_method($rpc,$this->Server->Methods[$i]->Name,Array($this,'RpcCallHandler'));
1378		$temp=xmlrpc_server_call_method($rpc,file_get_contents('php://input'),null);
1379		$this->XmlHeaders();
1380    	if(self::$EnableCompression)
1381			ob_start('ob_gzhandler');
1382		echo $temp;
1383		return false;
1384	}
1385	
1386	/**
1387	 * (Internal) handle a RPC call
1388	 * 
1389	 * @param string $method The method name
1390	 * @param array $param The parameters
1391	 * @return mixed The response
1392	 */
1393	public function RpcCallHandler($method,$param){
1394    	PhpWsdl::Debug('XML RPC call "'.$method.'"');
1395		$m=$this->Server->GetMethod($method);
1396		if(is_null($m))
1397			throw(new Exception('Method "'.$method.'" not exists'));
1398		if(!self::$EnableRpcNamedParameters){
1399			// Unnamed parameters
1400			PhpWsdl::Debug('Unnamed parameters');
1401			$req=Array(
1402				'call'			=>	$m->Name,
1403				'param'			=>	$param
1404			);
1405		}else{
1406			// Named parameters
1407			PhpWsdl::Debug('Named parameters');
1408			$req=Array(
1409				'call'			=>	$m->Name,
1410				'param'			=>	Array()
1411			);
1412			$map=Array();
1413			$i=-1;
1414			$pLen=sizeof($param);
1415			while(++$i<$pLen){
1416				$p=$param[$i];
1417				$keys=array_keys($p);
1418				PhpWsdl::Debug('Found parameter "'.$keys[0].'"');
1419				$map[$keys[0]]=$p[$keys[0]];
1420			}
1421			$lastValue=-1;
1422			$i=-1;
1423			$pLen=sizeof($m->Param);
1424			while(++$i<$pLen){
1425				$p=$m->Param[$i];
1426				if(isset($map[$p->Name])){
1427					$req['param'][]=$map[$p->Name];
1428					$lastValue=$i;
1429				}else{
1430					PhpWsdl::Debug('Missing parameter "'.$p->Name.'"');
1431					$req['param'][]=null;
1432				}
1433			}
1434			if($lastValue<$pLen-1){
1435				PhpWsdl::Debug('Slice parameters array from index #'.$lastValue);
1436				$req['param']=array_slice($req['param'],0,$lastValue+1);
1437			}
1438		}
1439		// Do recoding
1440		if(!self::$NoRpcRecode){
1441			PhpWsdl::Debug('Recoding parameters');
1442			$i=-1;
1443			$len=sizeof($req['param']);
1444			while(++$i<$len){
1445				if(is_null($req['param'][$i]))
1446					continue;
1447				$p=$m->Param[$i];
1448				if(in_array($p->Type,PhpWsdl::$BasicTypes)){
1449					PhpWsdl::Debug('"'.$p->Name.'" is a basic type');
1450					continue;
1451				}
1452				$t=$this->Server->GetType($p->Type);
1453				if($t->IsArray){
1454					PhpWsdl::Debug('"'.$p->Name.'" is an array');
1455					continue;
1456				}
1457				if(get_class($t)=='PhpWsdlEnum'&&in_array($p->Type,PhpWsdl::$BasicTypes)){
1458					PhpWsdl::Debug('"'.$p->Name.'" is an basic type enumeration');
1459					continue;
1460				}
1461				PhpWsdl::Debug('Recoding of "'.$p->Name.'" required');
1462				$req['param'][$i]=$this->RecodeParameter($req['param'][$i],$t,$server);
1463			}
1464		}
1465    	if(PhpWsdl::$Debugging)
1466    		PhpWsdl::Debug('Parameters: '.print_r($req['param'],true));
1467		return $this->HandleRequest($req,$m);
1468	}
1469	
1470	/**
1471	 * Recode an hash array into an object
1472	 * 
1473	 * @param array $received The received hash array
1474	 * @param PhpWsdlObject $type The type
1475	 * @param PhpWsdl $server The PhpWsdl object
1476	 * @return object The object
1477	 */
1478	private function RecodeParameter($received,$type,$server){
1479		PhpWsdl::Debug('Recode "'.$type->Name.'"');
1480		$obj=new stdClass();
1481		$i=-1;
1482		$len=sizeof($type->Elements);
1483		while(++$i<$len){
1484			$e=$type->Elements[$i];
1485			$name=$e->Name;
1486			if(!in_array($e->Type,PhpWsdl::$BasicTypes)){
1487				$t=$server->GetType($e->Type);
1488				if(is_null($t))
1489					throw(new Exception('Could not recode "'.$e->Type.'"'));
1490				if(get_class($t)=='PhpWsdlEnum'){
1491					$basic=in_array($t->Type,PhpWsdl::$BasicTypes);
1492				}else{
1493					$basic=false;
1494					$t=null;
1495				}
1496			}else{
1497				$basic=true;
1498				$t=null;
1499			}
1500			if(!$basic){
1501				PhpWsdl::Debug('Recode element "'.$name.'" as object');
1502				$obj[$name]=$this->RecodeParameter($received[$name],$t,$server);
1503			}else{
1504				PhpWsdl::Debug('Set element "'.$name.'"');
1505				$obj[$name]=$received[$name];
1506			}
1507		}
1508		return $obj;
1509	}
1510	
1511	/**
1512	 * Handle a request
1513	 * 
1514	 * @param array $req The request data
1515	 * @param PhpWsdlMethod $method The method object
1516	 * @return mixed The response
1517	 */
1518	private function HandleRequest($req,$method){
1519    	// Get the handler object
1520    	$res=null;
1521    	$obj=$this->Object;
1522    	if(is_null($obj))
1523	    	if(!is_null($this->ClassName))
1524	    		if(class_exists($this->ClassName))
1525	    			eval("\$obj=new ".$this->ClassName."();");
1526	    PhpWsdl::Debug('Handler object: '.print_r($obj,true));
1527	    // Prepare the call
1528	    $call=($method->IsGlobal)
1529	    	?$method->Name
1530	    	:Array(
1531	    		$obj,
1532	    		$method->Name
1533	    	);
1534	    PhpWsdl::Debug('Call: '.print_r($call,true));
1535	    // Call the method
1536        $pLen=sizeof($req['param']);
1537    	if($pLen<1){
1538    		return call_user_func($call);
1539    	}else if($pLen<2){
1540    		return call_user_func($call,$req['param'][0]);
1541    	}else{
1542    		return call_user_func_array($call,$req['param']);
1543    	}
1544	}
1545	
1546	/**
1547	 * Output plain text response headers
1548	 */
1549	private function PlainTextHeaders(){
1550		header('Content-Type: text/plain; encoding=UTF-8');
1551		if(self::$DisableClientCache)
1552			$this->NoCacheHeaders();
1553	}
1554
1555	/**
1556	 * Output XML response headers
1557	 */
1558	private function XmlHeaders(){
1559		header('Content-Type: text/xml; encoding=UTF-8');
1560		if(self::$DisableClientCache)
1561			$this->NoCacheHeaders();
1562	}
1563
1564	/**
1565	 * Output JavaScript response headers
1566	 */
1567	private function JavaScriptHeaders(){
1568		header('Content-Type: text/javascript; encoding=UTF-8');
1569		header('Content-Disposition: attachment; filename='.$this->Server->Name.'JsonClient.js');
1570		if(self::$DisableClientCache)
1571			$this->NoCacheHeaders();
1572	}
1573	
1574	/**
1575	 * Output headers to disable the client cache
1576	 */
1577	private function NoCacheHeaders(){
1578    	header('Expires: Tue, 03 Jul 2001 06:00:00 GMT');   
1579    	header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
1580    	header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
1581    	header('Cache-Control: post-check=0, pre-check=0',false);
1582    	header('Pragma: no-cache');
1583	}
1584	
1585	/**
1586	 * Get a http parameter
1587	 * 
1588	 * @param string $name The key
1589	 * @return string The value
1590	 */
1591	private static function GetParam($name){
1592		$name=addslashes($name);
1593		if(isset($_GET[$name]))
1594			return stripslashes($_GET[$name]);
1595		if(isset($_POST[$name]))
1596			return stripslashes($_POST[$name]);
1597		return '';
1598	}
1599	
1600	/**
1601	 * Determine if we got a GET/POST parameter
1602	 * 
1603	 * @param string $name
1604	 * @return boolean Parameter exists?
1605	 */
1606	private static function HasParam($name){
1607		return isset($_GET[$name])||isset($_POST[$name]);
1608	} 
1609	
1610	/**
1611	 * Find the handler method for a REST request
1612	 * 
1613	 * @param string $method The method (GET/POST/...)
1614	 * @param string $path The REST server path
1615	 * @return array The handler method and the path or NULL, if not found
1616	 */
1617	private function GetRestMethod($method,$path){
1618		if(substr($path,strlen($path)-1)!='/')
1619			$path.='/';
1620		// Find a REST method
1621		PhpWsdl::Debug('Find REST method "'.$method.'" at "'.$path.'"');
1622		$i=-1;
1623		$mLen=sizeof($this->Server->Methods);
1624		while(++$i<$mLen){
1625			$m=$this->Server->Methods[$i];
1626			if(is_null($m->Settings))
1627				continue;
1628			if(!isset($m->Settings['rest']))
1629				continue;
1630			if(!isset($m->Settings['rest'][$method]))
1631				continue;
1632			$rest=$m->Settings['rest'][$method];
1633			$j=-1;
1634			$rLen=sizeof($rest);
1635			while(++$j<$rLen){
1636				$call=$rest[$j]['path'];
1637				$param=null;
1638				if(strpos($call,':')>-1)
1639					list($call,$param)=explode(':',$call,2);
1640				if(substr($call,strlen($call)-1)!='/')
1641					$call.='/';
1642				if((!is_null($param)&&substr($path,0,strlen($call))==$call)||$path==$call){
1643					PhpWsdl::Debug('Method found at index #'.$i.' with target "'.$rest[$j]['path'].'"');
1644					return Array($m,$rest[$j]['path']);
1645				}
1646			}
1647		}
1648		// Find a method without REST declaration
1649		$temp=explode('/',$path);
1650		$res=$this->Server->GetMethod($temp[1]);
1651		return (is_null($res))
1652			?null
1653			:Array($res,null);
1654	}
1655	
1656	/**
1657	 * Compress a JavaScript
1658	 * 
1659	 * @param string $js The uncompressed JavaScript
1660	 * @return string The compressed JavaScript
1661	 */
1662	private function PackJavaScript($js){
1663		if(!self::IsJsPackerAvailable())
1664			return $js;
1665		PhpWsdl::Debug('Compress a JavaScript');
1666		if(PhpWsdl::HasHookHandler('ServersPackJsHook'))
1667			return PhpWsdl::CallHook(
1668				'ServersPackJsHook',
1669				Array(
1670					'server'		=>	$this,
1671					'js'			=>	&$js
1672				)
1673			);
1674		$packer=new PhpWsdlJavaScriptPacker(utf8_decode($js),62,true,true);
1675		return utf8_encode($packer->pack());
1676	}
1677	
1678	/**
1679	 * Determine if the JavaScript packer is available
1680	 * 
1681	 * @return boolean Available?
1682	 */
1683	public static function IsJsPackerAvailable(){
1684		return PhpWsdl::HasHookHandler('ServersPackJsHook')||class_exists('PhpWsdlJavaScriptPacker');
1685	}
1686	
1687	/**
1688	 * Encode a value as parameter or return value
1689	 * 
1690	 * @param string $type The type name
1691	 * @param mixed $value The value to be encoded
1692	 * @param boolean $parameter Is this a parameter value? (default: FALSE)
1693	 * @return mixed The encoded value
1694	 */
1695	public static function EncodeType($type,$value,$parameter=false){
1696		$res=null;
1697		$data=Array(
1698			'type'			=>	&$type,
1699			'value'			=>	&$value,
1700			'parameter'		=>	&$parameter,
1701			'res'			=>	&$res
1702		);
1703		if(!PhpWsdl::CallHook(
1704				'EncodeTypeHook',
1705				$data
1706			)
1707		)
1708			return $res;
1709		if(!PhpWsdl::CallHook(
1710				'EncodeType'.(($parameter)?'Parameter':'Return').'Hook',
1711				$data
1712			)
1713		)
1714			return $res;
1715		if(in_array($type,PhpWsdl::$BasicTypes))
1716			return $value;
1717		$t=self::$UseServer->Server->GetType($type);
1718		if(is_null($t))
1719			throw(new Exception('Could not encode type "'.$type.'"'));
1720		if(get_class($t)=='PhpWsdlEnum')
1721			$type=$t->Type;
1722		return (in_array($type,PhpWsdl::$BasicTypes))?$value:json_encode($value);
1723	}
1724	
1725	/**
1726	 * Decode a parameter or a return value
1727	 * 
1728	 * @param string $type The type name
1729	 * @param mixed $value The value to b…

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