PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/class.phpwsdl.php

http://php-wsdl-creator.googlecode.com/
PHP | 2853 lines | 1944 code | 75 blank | 834 comment | 240 complexity | 4f8fbaee998d7112dce3b6758a246c4c MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /*
  3. PhpWsdl - Generate WSDL from PHP
  4. Copyright (C) 2011 Andreas Müller-Saala, wan24.de
  5. This program is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free Software
  7. Foundation; either version 3 of the License, or (at your option) any later
  8. version.
  9. This program is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along with
  13. this program; if not, see <http://www.gnu.org/licenses/>.
  14. */
  15. if(basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__))
  16. exit;
  17. // Debugging
  18. /*PhpWsdl::$Debugging=true;// Enable debugging
  19. PhpWsdl::$DebugFile='./cache/debug.log';// The logfile to write the debugging messages to
  20. PhpWsdl::$DebugBackTrace=false;// Include backtrace information in debugging messages?*/
  21. // Initialize PhpWsdl
  22. PhpWsdl::Init();
  23. // You don't require class.phpwsdlelement.php and class.phpwsdlcomplex.php,
  24. // as long as you don't use complex types. So you may comment those two
  25. // requires out.
  26. // You may also disable loading the class.phpwsdlproxy.php, if you don't plan
  27. // to use the proxy class for your webservice.
  28. require_once(dirname(__FILE__).'/class.phpwsdlformatter.php');
  29. require_once(dirname(__FILE__).'/class.phpwsdlobject.php');
  30. require_once(dirname(__FILE__).'/class.phpwsdlparser.php');
  31. require_once(dirname(__FILE__).'/class.phpwsdlproxy.php');
  32. require_once(dirname(__FILE__).'/class.phpwsdlparam.php');
  33. require_once(dirname(__FILE__).'/class.phpwsdlmethod.php');
  34. require_once(dirname(__FILE__).'/class.phpwsdlelement.php');
  35. require_once(dirname(__FILE__).'/class.phpwsdlcomplex.php');
  36. require_once(dirname(__FILE__).'/class.phpwsdlenum.php');
  37. // Do things after the environment is configured
  38. PhpWsdl::PostInit();
  39. /**
  40. * PhpWsdl class
  41. *
  42. * @author Andreas Müller-Saala
  43. * @copyright Š2011 Andreas Müller-Saala, wan24.de
  44. * @version 2.4
  45. */
  46. class PhpWsdl{
  47. /**
  48. * The version number
  49. *
  50. * @var string
  51. */
  52. public static $VERSION='2.4';
  53. /**
  54. * Set this to TRUE to enable the autorun in quick mode
  55. *
  56. * @var boolean
  57. */
  58. public static $AutoRun=false;
  59. /**
  60. * Global static configuration
  61. *
  62. * @var array
  63. */
  64. public static $Config=Array();
  65. /**
  66. * The webservice handler object
  67. *
  68. * @var object
  69. */
  70. public static $ProxyObject=null;
  71. /**
  72. * The current PhpWsdl server
  73. *
  74. * @var PhpWsdl
  75. */
  76. public static $ProxyServer=null;
  77. /**
  78. * Use WSDL with the proxy
  79. *
  80. * @var boolean
  81. */
  82. public static $UseProxyWsdl=false;
  83. /**
  84. * Type encoding settings
  85. *
  86. * @var array
  87. */
  88. public static $TypeEncoding=null;
  89. /**
  90. * Encode return values when using the proxy class?
  91. * Note: All encoding have to be defined in the PhpWsdl::$TypeEncoding
  92. *
  93. * @var boolean
  94. */
  95. public static $EncodeProxyReturn=false;
  96. /**
  97. * The name
  98. *
  99. * @var string
  100. */
  101. public $Name;
  102. /**
  103. * Documentation
  104. *
  105. * @var string
  106. */
  107. public $Docs=null;
  108. /**
  109. * The namespace
  110. *
  111. * @var string
  112. */
  113. public $NameSpace=null;
  114. /**
  115. * The SOAP endpoint URI
  116. *
  117. * @var string
  118. */
  119. public $EndPoint=null;
  120. /**
  121. * Set this to the WSDL URI, if it's different from your SOAP endpoint + "?WSDL"
  122. *
  123. * @var string
  124. */
  125. public $WsdlUri=null;
  126. /**
  127. * Set this to the PHP URI, if it's different from your SOAP endpoint + "?PHPSOAPCLIENT"
  128. *
  129. * @var string
  130. */
  131. public $PhpUri=null;
  132. /**
  133. * Set this to the HTML documentation URI, if it's different from your SOAP endpoint
  134. *
  135. * @var string
  136. */
  137. public $DocUri=null;
  138. /**
  139. * The options for the PHP SoapServer
  140. * Note: "actor" and "uri" will be set at runtime
  141. *
  142. * @var array
  143. */
  144. public $SoapServerOptions=null;
  145. /**
  146. * An array of file names to parse
  147. *
  148. * @var string[]
  149. */
  150. public $Files=Array();
  151. /**
  152. * An array of complex types
  153. *
  154. * @var PhpWsdlComplex[]
  155. */
  156. public $Types=null;
  157. /**
  158. * An array of method
  159. *
  160. * @var PhpWsdlMethod[]
  161. */
  162. public $Methods=null;
  163. /**
  164. * Remove tabs and line breaks?
  165. * Note: Unoptimized WSDL won't be cached
  166. *
  167. * @var boolean
  168. */
  169. public $Optimize=true;
  170. /**
  171. * UTF-8 encoded WSDL from the last CreateWsdl method call
  172. *
  173. * @var string
  174. */
  175. public $WSDL=null;
  176. /**
  177. * Create a webservice handler class at runtime?
  178. *
  179. * @var boolean
  180. */
  181. public $CreateHandler=false;
  182. /**
  183. * The created handler class
  184. *
  185. * @var PhpWsdlHandler
  186. */
  187. public $Handler=null;
  188. /**
  189. * The handler class PHP code
  190. *
  191. * @var string
  192. */
  193. public $HandlerPhp=null;
  194. /**
  195. * UTF-8 encoded HTML from the last OutputHtml method call
  196. *
  197. * @var string
  198. */
  199. public $HTML=null;
  200. /**
  201. * UTF-8 encoded PHP from the last OutputPhp method call
  202. *
  203. * @var string
  204. */
  205. public $PHP=null;
  206. /**
  207. * An array of basic types (these are just some of the XSD defined types
  208. * (see http://www.w3.org/TR/2001/PR-xmlschema-2-20010330/)
  209. *
  210. * @var string[]
  211. */
  212. public static $BasicTypes=Array(
  213. 'anyType',
  214. 'anyURI',
  215. 'base64Binary',
  216. 'boolean',
  217. 'byte',
  218. 'date',
  219. 'decimal',
  220. 'double',
  221. 'duration',
  222. 'dateTime',
  223. 'float',
  224. 'gDay',
  225. 'gMonth',
  226. 'gMonthDay',
  227. 'gYearMonth',
  228. 'gYear',
  229. 'hexBinary',
  230. 'int',
  231. 'integer',
  232. 'long',
  233. 'NOTATION',
  234. 'number',
  235. 'QName',
  236. 'short',
  237. 'string',
  238. 'time'
  239. );
  240. /**
  241. * A list of non-nillable types
  242. *
  243. * @var string[]
  244. */
  245. public static $NonNillable=Array(
  246. 'boolean',
  247. 'decimal',
  248. 'double',
  249. 'float',
  250. 'int',
  251. 'integer',
  252. 'long',
  253. 'number',
  254. 'short'
  255. );
  256. /**
  257. * Set this to a writeable folder to enable caching the WSDL in files
  258. *
  259. * @var string
  260. */
  261. public static $CacheFolder=null;
  262. /**
  263. * Is the cache folder writeable?
  264. *
  265. * @var boolean|NULL
  266. */
  267. public static $CacheFolderWriteAble=null;
  268. /**
  269. * The cache timeout in seconds (set to zero to disable caching, too)
  270. * If you set the value to -1, the cache will never expire. Then you have
  271. * to use the PhpWsdl->TidyCache method for cleaning up the cache once
  272. * you've made changes to your webservice.
  273. *
  274. * @var int
  275. */
  276. public static $CacheTime=3600;
  277. /**
  278. * Write even unoptimized and/or documented XML to the cache?
  279. *
  280. * @var boolean
  281. */
  282. public static $CacheAllWsdl=false;
  283. /**
  284. * Parse documentation?
  285. *
  286. * @var boolean
  287. */
  288. public $ParseDocs=true;
  289. /**
  290. * Include documentation tags in WSDL, if the optimizer is disabled?
  291. *
  292. * @var boolean
  293. */
  294. public $IncludeDocs=true;
  295. /**
  296. * Force sending WSDL (has a higher priority than PhpWsdl->ForceNotOutputWsdl)
  297. *
  298. * @var boolean
  299. */
  300. public $ForceOutputWsdl=false;
  301. /**
  302. * Force NOT sending WSDL (disable sending WSDL, has a higher priority than ?WSDL f.e.)
  303. *
  304. * @var boolean
  305. */
  306. public $ForceNotOutputWsdl=false;
  307. /**
  308. * Force sending HTML (has a higher priority than PhpWsdl->ForceNotOutputHtml)
  309. *
  310. * @var boolean
  311. */
  312. public $ForceOutputHtml=false;
  313. /**
  314. * Force NOT sending HTML (disable sending HTML)
  315. *
  316. * @var boolean
  317. */
  318. public $ForceNotOutputHtml=false;
  319. /**
  320. * The headline for the HTML output or NULL to use the default
  321. *
  322. * @var string
  323. */
  324. public $HtmlHeadLine=null;
  325. /**
  326. * Force sending PHP (has a higher priority than PhpWsdl->ForceNotOutputPhp)
  327. *
  328. * @var boolean
  329. */
  330. public $ForceOutputPhp=false;
  331. /**
  332. * Force NOT sending PHP (disable sending PHP)
  333. *
  334. * @var boolean
  335. */
  336. public $ForceNotOutputPhp=false;
  337. /**
  338. * Regular expression parse a class name
  339. *
  340. * @var string
  341. */
  342. public static $classRx='/^.*class\s+([^\s]+)\s*\{.*$/is';
  343. /**
  344. * The HTML2PDF license key (see www.htmltopdf.de)
  345. *
  346. * @var string
  347. */
  348. public static $HTML2PDFLicenseKey=null;
  349. /**
  350. * The URI to the HTML2PDF http API
  351. *
  352. * @var string
  353. */
  354. public static $HTML2PDFAPI='http://online.htmltopdf.de/';
  355. /**
  356. * The HTML2PDF settings (only available when using a valid license key)
  357. *
  358. * @var array
  359. */
  360. public static $HTML2PDFSettings=Array();
  361. /**
  362. * Saves if the sources have been parsed
  363. *
  364. * @var boolean
  365. */
  366. public $SourcesParsed=false;
  367. /**
  368. * Saves if the configuration has already been determined
  369. *
  370. * @var boolean
  371. */
  372. public $ConfigurationDetermined=false;
  373. /**
  374. * The current PHP SoapServer object
  375. *
  376. * @var SoapServer
  377. */
  378. public $SoapServer=null;
  379. /**
  380. * Is a http Auth login required to run the SOAP server?
  381. *
  382. * @var boolean
  383. */
  384. public $RequireLogin=false;
  385. /**
  386. * Debugging messages
  387. *
  388. * @var string[]
  389. */
  390. public static $DebugInfo=Array();
  391. /**
  392. * En- / Disable the debugging mode
  393. *
  394. * @var boolean
  395. */
  396. public static $Debugging=false;
  397. /**
  398. * The debug file to write to
  399. *
  400. * @var string
  401. */
  402. public static $DebugFile=null;
  403. /**
  404. * Put backtrace information in debugging messages
  405. *
  406. * @var boolean
  407. */
  408. public static $DebugBackTrace=false;
  409. /**
  410. * A debugging handler
  411. *
  412. * @var string|array
  413. */
  414. public static $DebugHandler=null;
  415. /**
  416. * WSDL namespaces
  417. *
  418. * @var array
  419. */
  420. public static $NameSpaces=null;
  421. /**
  422. * PhpWsdl constructor
  423. * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0.
  424. * Use PhpWsdl::RunQuickMode() instead
  425. *
  426. * @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)
  427. * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL)
  428. * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL)
  429. * @param string|string[] $file Filename or array of filenames or NULL (default: NULL)
  430. * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL)
  431. * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL)
  432. * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL)
  433. * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE)
  434. * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE)
  435. */
  436. public function PhpWsdl(
  437. $nameSpace=null,
  438. $endPoint=null,
  439. $cacheFolder=null,
  440. $file=null,
  441. $name=null,
  442. $methods=null,
  443. $types=null,
  444. $outputOnRequest=false,
  445. $runServer=false
  446. ){
  447. // Quick mode
  448. self::Debug('PhpWsdl constructor called');
  449. $quickRun=false;
  450. if($nameSpace===true){
  451. self::Debug('Quick mode detected');
  452. $quickRun=true;
  453. $nameSpace=null;
  454. if(!is_null($endPoint)){
  455. if(self::$Debugging)
  456. self::Debug('Filename(s): '.print_r($endPoint,true));
  457. $endPoint=null;
  458. }
  459. }
  460. // SOAP server options
  461. $this->SoapServerOptions=Array(
  462. 'soap_version' => (defined('SOAP_1_2'))?SOAP_1_2:SOAP_1_1,
  463. 'encoding' => 'UTF-8',
  464. 'compression' => SOAP_COMPRESSION_ACCEPT|SOAP_COMPRESSION_GZIP|9
  465. );
  466. // Optimizer settings
  467. $this->Optimize=!isset($_GET['readable']);// Call with "?WSDL&readable" to get human readable WSDL
  468. self::Debug('Optimizer is '.(($this->Optimize)?'enabled':'disabled'));
  469. // Cache settings
  470. if(!is_null($cacheFolder)){
  471. self::Debug('Cache folder is '.$cacheFolder);
  472. self::$CacheFolder=$cacheFolder;
  473. }
  474. // Namespace
  475. $this->NameSpace=(is_null($nameSpace))?$this->DetermineNameSpace():$nameSpace;
  476. self::Debug('Namespace is '.$this->NameSpace);
  477. // Endpoint
  478. $this->EndPoint=((!is_null($endPoint)))?$endPoint:$this->DetermineEndPoint();
  479. self::Debug('Endpoint is '.$this->EndPoint);
  480. // Name
  481. if(!is_null($name)){
  482. self::Debug('Name is '.$name);
  483. $this->Name=$name;
  484. }
  485. // Source files
  486. if(!is_null($file)){
  487. if(self::$Debugging)
  488. self::Debug('Filename(s): '.print_r($file,true));
  489. $this->Files=array_merge($this->Files,(is_array($file))?$file:Array($file));
  490. }
  491. // Methods
  492. $this->Methods=(!is_null($methods))?$methods:Array();
  493. if(sizeof($this->Methods)>0&&self::$Debugging)
  494. self::Debug('Methods: '.print_r($this->Methods,true));
  495. // Types
  496. $this->Types=(!is_null($types))?$types:Array();
  497. if(sizeof($this->Types)>0&&self::$Debugging)
  498. self::Debug('Types: '.print_r($this->Types,true));
  499. // Constructor hook
  500. self::CallHook(
  501. 'ConstructorHook',
  502. Array(
  503. 'server' => $this,
  504. 'output' => &$outputOnRequest,
  505. 'run' => &$runServer,
  506. 'quickmode' => &$quickRun
  507. )
  508. );
  509. // WSDL output
  510. if($outputOnRequest&&!$runServer)
  511. $this->OutputWsdlOnRequest();
  512. // Run the server
  513. if($quickRun||$runServer)
  514. $this->RunServer(null,(is_bool($runServer))?null:$runServer);
  515. }
  516. /**
  517. * Create an instance of PhpWsdl
  518. * Note: The quick mode by giving TRUE as first parameter is deprecated and will be removed from version 3.0.
  519. * Use PhpWsdl::RunQuickMode() instead
  520. *
  521. * @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)
  522. * @param string|string[] $endPoint Endpoint URI or NULL to let PhpWsdl determine it - or, in quick mode, the webservice class filename(s) (default: NULL)
  523. * @param string $cacheFolder The folder for caching WSDL or NULL to use the systems default (default: NULL)
  524. * @param string|string[] $file Filename or array of filenames or NULL (default: NULL)
  525. * @param string $name Webservice name or NULL to let PhpWsdl determine it (default: NULL)
  526. * @param PhpWsdlMethod[] $methods Array of methods or NULL (default: NULL)
  527. * @param PhpWsdlComplex[] $types Array of complex types or NULL (default: NULL)
  528. * @param boolean $outputOnRequest Output WSDL on request? (default: FALSE)
  529. * @param boolean|string|object|array $runServer Run SOAP server? (default: FALSE)
  530. * @return PhpWsdl The PhpWsdl object
  531. */
  532. public static function CreateInstance(
  533. $nameSpace=null,
  534. $endPoint=null,
  535. $cacheFolder=null,
  536. $file=null,
  537. $name=null,
  538. $methods=null,
  539. $types=null,
  540. $outputOnRequest=false,
  541. $runServer=false
  542. ){
  543. self::Debug('Create new PhpWsdl instance');
  544. $obj=null;
  545. self::CallHook(
  546. 'BeforeCreateInstanceHook',
  547. Array(
  548. 'server' => &$obj,
  549. 'namespace' => &$nameSpace,
  550. 'endpoint' => &$endPoint,
  551. 'cachefolder' => &$cacheFolder,
  552. 'file' => &$file,
  553. 'name' => &$name,
  554. 'methods' => &$methods,
  555. 'types' => &$types,
  556. 'outputonrequest'=> &$outputOnRequest,
  557. 'runserver' => &$runServer
  558. )
  559. );
  560. if(is_null($obj))
  561. $obj=new PhpWsdl($nameSpace,$endPoint,$cacheFolder,$file,$name,$methods,$types,$outputOnRequest,$runServer);
  562. self::CallHook(
  563. 'CreateInstanceHook',
  564. Array(
  565. 'server' => &$obj
  566. )
  567. );
  568. return $obj;
  569. }
  570. /**
  571. * Run the PhpWsdl SOAP server in quick mode
  572. *
  573. * @param string|string[] $file The webservice handler class file or a list of files or NULL (default: NULL)
  574. */
  575. public static function RunQuickMode($file=null){
  576. self::Debug('Run quick mode');
  577. $server=self::CreateInstance();
  578. if(!is_null($file))
  579. $server->Files=(is_array($file))?$file:Array($file);
  580. $server->RunServer();
  581. }
  582. /**
  583. * Determine if WSDL was requested by the client
  584. *
  585. * @return boolean WSDL requested?
  586. */
  587. public function IsWsdlRequested(){
  588. return $this->ForceOutputWsdl||((isset($_GET['wsdl'])||isset($_GET['WSDL']))&&!$this->ForceNotOutputWsdl);
  589. }
  590. /**
  591. * Determine if HTML was requested by the client
  592. *
  593. * @return boolean HTML requested?
  594. */
  595. public function IsHtmlRequested(){
  596. return $this->ForceOutputHtml||(strlen(file_get_contents('php://input'))<1&&!$this->ForceNotOutputHtml);
  597. }
  598. /**
  599. * Determine if PHP was requested by the client
  600. *
  601. * @return boolean PHP requested?
  602. */
  603. public function IsPhpRequested(){
  604. return $this->ForceOutputPhp||((isset($_GET['phpsoapclient'])||isset($_GET['PHPSOAPCLIENT']))&&!$this->ForceNotOutputPhp);
  605. }
  606. /**
  607. * Determine if this request is a SOAP request
  608. *
  609. * @return boolean
  610. */
  611. public function IsSoapRequest(){
  612. return !$this->IsHtmlRequested()&&!$this->IsWsdlRequested()&&!$this->IsPhpRequested();
  613. }
  614. /**
  615. * Determine if only global methods are served
  616. *
  617. * @return boolean Only global methods?
  618. */
  619. public function IsOnlyGlobal(){
  620. $res=true;
  621. $i=-1;
  622. $len=sizeof($this->Methods);
  623. while(++$i<$len)
  624. if(!$this->Methods[$i]->IsGlobal){
  625. $res=false;
  626. break;
  627. }
  628. return $res;
  629. }
  630. /**
  631. * Disble caching
  632. *
  633. * @param bool $allCaching Do not only set the timeout to zero? (default: TRUE)
  634. */
  635. public static function DisableCache($allCaching=true){
  636. self::Debug('Disable '.(($allCaching)?'all':'this').' caching');
  637. if($allCaching)
  638. self::$CacheFolder=null;
  639. if(!$allCaching)
  640. self::$CacheTime=0;
  641. }
  642. /**
  643. * Enable caching
  644. *
  645. * @param string $folder The cache folder or NULL to use a system temporary directory (default: NULL)
  646. * @param int $timeout The caching timeout in seconds or NULL to use the previous value or the default (3600) (default: NULL)
  647. */
  648. public static function EnableCache($folder=null,$timeout=null){
  649. if(is_null($folder)&&is_null(self::$CacheFolder)){
  650. if(self::IsCacheFolderWriteAble('./cache')){
  651. $folder='./cache';
  652. }else if(self::IsCacheFolderWriteAble(dirname(__FILE__).'/cache')){
  653. $folder=dirname(__FILE__).'/cache';
  654. }else if(self::IsCacheFolderWriteAble(sys_get_temp_dir())){
  655. $folder=sys_get_temp_dir();
  656. }else{
  657. self::Debug('Could not find a cache folder');
  658. }
  659. }
  660. if(is_null($timeout))
  661. $timeout=(self::$CacheTime!=0)?self::$CacheTime:3600;
  662. self::Debug('Enable cache in folder "'.((is_null($folder))?'(none)':$folder).'" with timeout '.$timeout.' seconds');
  663. self::$CacheFolder=$folder;
  664. self::$CacheTime=$timeout;
  665. }
  666. /**
  667. * Determine the configuration
  668. *
  669. * @return boolean Succeed?
  670. */
  671. public function DetermineConfiguration(){
  672. if(!is_null($this->GetWsdlFromCache()))
  673. return true;
  674. $this->ParseSource();
  675. $mLen=sizeof($this->Methods);
  676. $tLen=sizeof($this->Types);
  677. $fLen=sizeof($this->Files);
  678. if($this->ConfigurationDetermined)
  679. return ($mLen>0||$tLen>0)&&!is_null($this->Name);
  680. self::Debug('Determine configuration');
  681. $this->ConfigurationDetermined=true;
  682. $tryWebService=
  683. !$this->IsFileInList('class.webservice.php')&&
  684. (
  685. file_exists('class.webservice.php')||
  686. file_exists(dirname(__FILE__).'/class.webservice.php')
  687. );
  688. // No methods or types? Try to parse them from the current script
  689. if($mLen<1&&$tLen<1){
  690. $tryFiles=Array();
  691. if($tryWebService){
  692. if(file_exists('class.webservice.php'))
  693. $tryFiles[]='class.webservice.php';
  694. if(file_exists(dirname(__FILE__).'/class.webservice.php'))
  695. $tryFiles[]=dirname(__FILE__).'/class.webservice.php';
  696. }
  697. if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME']))
  698. $tryFiles[]=$_SERVER['SCRIPT_FILENAME'];
  699. $i=-1;
  700. $len=sizeof($tryFiles);
  701. while(++$i<$len){
  702. $file=$tryFiles[$i];
  703. self::Debug('Try to load objects from '.$file);
  704. $this->ParseSource(false,file_get_contents($file));
  705. $mLen=sizeof($this->Methods);
  706. $tLen=sizeof($this->Types);
  707. if($mLen<1&&$tLen<1)
  708. continue;
  709. self::Debug('Found objects, adding the file to list');
  710. $this->Files[]=$file;
  711. $fLen++;
  712. break;
  713. }
  714. if($mLen<1&&$tLen<1)
  715. return false;
  716. }
  717. // No class name? Try to parse one from the current files
  718. if(!is_null($this->Name))
  719. return true;
  720. $tryFiles=Array();
  721. if(!$this->IsFileInList($_SERVER['SCRIPT_FILENAME']))
  722. $tryFiles[]=$_SERVER['SCRIPT_FILENAME'];
  723. if($tryWebService){
  724. if(file_exists('class.webservice.php'))
  725. $tryFiles[]='class.webservice.php';
  726. if(file_exists(dirname(__FILE__).'/class.webservice.php'))
  727. $tryFiles[]=dirname(__FILE__).'/class.webservice.php';
  728. }
  729. $tryFiles=array_merge($this->Files,$tryFiles);
  730. $i=-1;
  731. $len=sizeof($tryFiles);
  732. $class=null;
  733. while(++$i<$len){
  734. $file=$tryFiles[$i];
  735. self::Debug('Try to determine the class name from '.$file);
  736. $temp=file_get_contents($file);
  737. if(!preg_match(self::$classRx,$temp))
  738. continue;
  739. $class=preg_replace(self::$classRx,"$1",$temp);
  740. self::Debug('Found class name '.$class);
  741. break;
  742. }
  743. // No class name yet? Use the default if only global methods are present
  744. if(is_null($class)&&$this->IsOnlyGlobal()){
  745. self::Debug('Using default webservice name');
  746. $class='SoapWebService';
  747. }
  748. $this->Name=$class;
  749. return !is_null($class);
  750. }
  751. /**
  752. * Determine the endpoint URI
  753. */
  754. public function DetermineEndPoint(){
  755. $ssl=isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']=='on';
  756. $res='http'.(($ssl)?'s':'').'://'.$_SERVER['SERVER_NAME'];
  757. if(((!$ssl&&$_SERVER['SERVER_PORT']!=80)||($ssl&&$_SERVER['SERVER_PORT']!=443)))
  758. $res.=':'.$_SERVER['SERVER_PORT'];// Append the non-default server port
  759. return $res.$_SERVER['SCRIPT_NAME'];
  760. }
  761. /**
  762. * Determine the namespace
  763. */
  764. public function DetermineNameSpace(){
  765. return 'http://'.$_SERVER['SERVER_NAME'].str_replace(basename($_SERVER['SCRIPT_NAME']),'',$_SERVER['SCRIPT_NAME']);
  766. }
  767. /**
  768. * Determine if a file is included in the list of files
  769. *
  770. * @param string $file The filename
  771. * @return boolean In the list?
  772. */
  773. public function IsFileInList($file){
  774. $file=preg_quote(basename($file));
  775. $i=-1;
  776. $fLen=sizeof($this->Files);
  777. while(++$i<$fLen)
  778. if(preg_match('/^(.*\/)?'.$file.'$/i',$this->Files[$i]))
  779. return true;
  780. return false;
  781. }
  782. /**
  783. * Determine if a type is used as exception type for a method
  784. *
  785. * @param string|PhpWsdlComplex $type A type name or object instance
  786. * @return boolean Used as exception type?
  787. */
  788. public function IsException($type){
  789. if(is_object($type))
  790. $type=$type->Name;
  791. if(PhpWsdlMethod::$DefaultException==$type)
  792. return true;
  793. $i=-1;
  794. $len=sizeof($this->Methods);
  795. while(++$i<$len)
  796. if($this->Methods[$i]->Exception==$type)
  797. return true;
  798. return false;
  799. }
  800. /**
  801. * Create the WSDL
  802. *
  803. * @param boolean $reCreate Don't use the cached WSDL? (default: FALSE)
  804. * @param boolean $optimize If TRUE, override the PhpWsdl->Optimizer property and force optimizing (default: FALSE)
  805. * @return string The UTF-8 encoded WSDL as string
  806. */
  807. public function CreateWsdl($reCreate=false,$optimizer=false){
  808. self::Debug('Create WSDL');
  809. // Ask the cache
  810. if(!$reCreate&&(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize)){
  811. self::Debug('Try to get WSDL from the cache');
  812. $wsdl=$this->GetWsdlFromCache();
  813. if(!is_null($wsdl)){
  814. self::Debug('Using cached WSDL');
  815. return (!$optimizer&&!$this->Optimize)?self::FormatXml($wsdl):$wsdl;
  816. }
  817. }
  818. // Prepare the WSDL generator
  819. if(!$this->DetermineConfiguration()){
  820. $mLen=sizeof($this->Methods);
  821. $tLen=sizeof($this->Types);
  822. if($mLen<1&&$tLen<1){
  823. self::Debug('No methods and types');
  824. throw(new Exception('No methods and no complex types are available'));
  825. }
  826. if(is_null($this->Name)){
  827. self::Debug('No name');
  828. throw(new Exception('Could not determine webservice handler class name'));
  829. }
  830. }
  831. $res=Array();
  832. // Create the XML Header
  833. self::CallHook(
  834. 'CreateWsdlHeaderHook',
  835. Array(
  836. 'server' => $this,
  837. 'res' => &$res,
  838. 'optimizer' => &$optimizer
  839. )
  840. );
  841. // Create types
  842. self::CallHook(
  843. 'CreateWsdlTypeSchemaHook',
  844. Array(
  845. 'server' => $this,
  846. 'res' => &$res,
  847. 'optimizer' => &$optimizer
  848. )
  849. );
  850. // Create messages
  851. self::CallHook(
  852. 'CreateWsdlMessagesHook',
  853. Array(
  854. 'server' => $this,
  855. 'res' => &$res,
  856. 'optimizer' => &$optimizer
  857. )
  858. );
  859. // Create port types
  860. self::CallHook(
  861. 'CreateWsdlPortsHook',
  862. Array(
  863. 'server' => $this,
  864. 'res' => &$res,
  865. 'optimizer' => &$optimizer
  866. )
  867. );
  868. // Create bindings
  869. self::CallHook(
  870. 'CreateWsdlBindingsHook',
  871. Array(
  872. 'server' => $this,
  873. 'res' => &$res,
  874. 'optimizer' => &$optimizer
  875. )
  876. );
  877. // Create the service
  878. self::CallHook(
  879. 'CreateWsdlServiceHook',
  880. Array(
  881. 'server' => $this,
  882. 'res' => &$res,
  883. 'optimizer' => &$optimizer
  884. )
  885. );
  886. // Finish the WSDL XML string
  887. self::CallHook(
  888. 'CreateWsdlFooterHook',
  889. Array(
  890. 'server' => $this,
  891. 'res' => &$res,
  892. 'optimizer' => &$optimizer
  893. )
  894. );
  895. // Run the optimizer
  896. self::CallHook(
  897. 'CreateWsdlOptimizeHook',
  898. Array(
  899. 'server' => $this,
  900. 'res' => &$res,
  901. 'optimizer' => &$optimizer
  902. )
  903. );
  904. // Fill the cache
  905. if(self::$CacheAllWsdl||!$this->IncludeDocs||$optimizer||$this->Optimize){
  906. self::Debug('Cache created WSDL');
  907. $this->WriteWsdlToCache(
  908. (
  909. !self::$CacheAllWsdl&&
  910. !$optimizer&&
  911. !$this->Optimize
  912. )
  913. ?self::OptimizeXml($res)
  914. :$res
  915. ,
  916. null,
  917. null,
  918. true
  919. );
  920. }
  921. return $this->WSDL;
  922. }
  923. /**
  924. * Create header
  925. *
  926. * @param array $data Data array
  927. * @return boolean Response
  928. */
  929. public static function CreateWsdlHeader($data){
  930. self::Debug('CreateWsdlHeader');
  931. $res=&$data['res'];
  932. $server=$data['server'];
  933. $res[]='<?xml version="1.0" encoding="UTF-8"?>';
  934. $temp=Array();
  935. $keys=array_keys(self::$NameSpaces);
  936. $i=-1;
  937. $len=sizeof($keys);
  938. while(++$i<$len)
  939. $temp[]='xmlns:'.$keys[$i].'="'.self::$NameSpaces[$keys[$i]].'"';
  940. $res[]='<wsdl:definitions xmlns:tns="'.$server->NameSpace.'" targetNamespace="'.$server->NameSpace.'" '.implode(' ',$temp).'>';
  941. return true;
  942. }
  943. /**
  944. * Create type schema
  945. *
  946. * @param array $data Data array
  947. * @return boolean Response
  948. */
  949. public static function CreateWsdlTypeSchema($data){
  950. self::Debug('CreateWsdlTypeSchema');
  951. $res=&$data['res'];
  952. $server=$data['server'];
  953. $tLen=sizeof($server->Types);
  954. if($tLen>0){
  955. $res[]='<wsdl:types>';
  956. $res[]='<s:schema targetNamespace="'.$server->NameSpace.'">';
  957. $i=-1;
  958. while(++$i<$tLen)
  959. $res[]=$server->Types[$i]->CreateType($server);
  960. self::CallHook(
  961. 'CreateWsdlTypesHook',
  962. $data
  963. );
  964. $res[]='</s:schema>';
  965. $res[]='</wsdl:types>';
  966. }
  967. return true;
  968. }
  969. /**
  970. * Create messages
  971. *
  972. * @param array $data Data array
  973. * @return boolean Response
  974. */
  975. public static function CreateWsdlMessages($data){
  976. self::Debug('CreateWsdlMessages');
  977. $res=&$data['res'];
  978. $server=$data['server'];
  979. $i=-1;
  980. $mLen=sizeof($server->Methods);
  981. while(++$i<$mLen)
  982. $res[]=$server->Methods[$i]->CreateMessages($server);
  983. return true;
  984. }
  985. /**
  986. * Create port types
  987. *
  988. * @param array $data Data array
  989. * @return boolean Response
  990. */
  991. public static function CreateWsdlPorts($data){
  992. self::Debug('CreateWsdlPorts');
  993. $res=&$data['res'];
  994. $server=$data['server'];
  995. $res[]='<wsdl:portType name="'.$server->Name.'Soap">';
  996. $i=-1;
  997. $mLen=sizeof($server->Methods);
  998. while(++$i<$mLen)
  999. $res[]=$server->Methods[$i]->CreatePortType($server);
  1000. self::CallHook(
  1001. 'CreateWsdlPortsAddHook',
  1002. $data
  1003. );
  1004. $res[]='</wsdl:portType>';
  1005. return true;
  1006. }
  1007. /**
  1008. * Create bindings
  1009. *
  1010. * @param array $data Data array
  1011. * @return boolean Response
  1012. */
  1013. public static function CreateWsdlBindings($data){
  1014. self::Debug('CreateWsdlBindings');
  1015. $res=&$data['res'];
  1016. $server=$data['server'];
  1017. $res[]='<wsdl:binding name="'.$server->Name.'Soap" type="tns:'.$server->Name.'Soap">';
  1018. $res[]='<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />';
  1019. $i=-1;
  1020. $mLen=sizeof($server->Methods);
  1021. while(++$i<$mLen)
  1022. $res[]=$server->Methods[$i]->CreateBinding($server);
  1023. self::CallHook(
  1024. 'CreateWsdlBindingsAddHook',
  1025. $data
  1026. );
  1027. $res[]='</wsdl:binding>';
  1028. return true;
  1029. }
  1030. /**
  1031. * Create service port
  1032. *
  1033. * @param array $data Data array
  1034. * @return boolean Response
  1035. */
  1036. public static function CreateWsdlService($data){
  1037. self::Debug('CreateWsdlService');
  1038. $res=&$data['res'];
  1039. $server=$data['server'];
  1040. $res[]='<wsdl:service name="'.$server->Name.'">';
  1041. if($server->IncludeDocs&&!$server->Optimize&&!is_null($server->Docs))
  1042. $res[]='<wsdl:documentation><![CDATA['.$server->Docs.']]></wsdl:documentation>';
  1043. $res[]='<wsdl:port name="'.$server->Name.'Soap" binding="tns:'.$server->Name.'Soap">';
  1044. $res[]='<soap:address location="'.$server->EndPoint.'" />';
  1045. $res[]='</wsdl:port>';
  1046. self::CallHook(
  1047. 'CreateWsdlServiceAddHook',
  1048. $data
  1049. );
  1050. $res[]='</wsdl:service>';
  1051. return true;
  1052. }
  1053. /**
  1054. * Create footer
  1055. *
  1056. * @param array $data Data array
  1057. * @return boolean Response
  1058. */
  1059. public static function CreateWsdlFooter($data){
  1060. self::Debug('CreateWsdlFooter');
  1061. $res=&$data['res'];
  1062. $res[]='</wsdl:definitions>';
  1063. return true;
  1064. }
  1065. /**
  1066. * Optimize WSDL
  1067. *
  1068. * @param array $data Data array
  1069. * @return boolean Response
  1070. */
  1071. public static function CreateWsdlOptimize($data){
  1072. self::Debug('CreateWsdlOptimize');
  1073. $res=&$data['res'];
  1074. $server=$data['server'];
  1075. $optimizer=&$data['optimizer'];
  1076. $res=utf8_encode(implode('',$res));
  1077. $res=(!$optimizer&&!$server->Optimize)
  1078. ?self::FormatXml($res)
  1079. :self::OptimizeXml($res);
  1080. $server->WSDL=$res;
  1081. return true;
  1082. }
  1083. /**
  1084. * Remove tabs and newline from XML
  1085. *
  1086. * @param string $xml The unoptimized XML
  1087. * @return string The optimized XML
  1088. */
  1089. public static function OptimizeXml($xml){
  1090. self::Debug('Optimize XML');
  1091. return preg_replace('/[\n|\t]/','',$xml);
  1092. }
  1093. /**
  1094. * Format XML human readable
  1095. *
  1096. * @param string $xml The XML
  1097. * @return string Human readable XML
  1098. */
  1099. public static function FormatXml($xml){
  1100. self::Debug('Produce human readable XML');
  1101. $input=fopen('data://text/plain,'.$xml,'r');
  1102. $output=fopen('php://temp','w');
  1103. $xf=new PhpWsdlFormatter($input,$output);
  1104. $xf->format();
  1105. rewind($output);
  1106. $xml=stream_get_contents($output);
  1107. fclose($input);
  1108. fclose($output);
  1109. return $xml;
  1110. }
  1111. /**
  1112. * Interpret the @service keyword
  1113. *
  1114. * @param $data The parser data
  1115. * @return boolean Response
  1116. */
  1117. public static function InterpretService($data){
  1118. self::Debug('Interpret service');
  1119. $server=$data['server'];
  1120. $info=explode(' ',$data['keyword'][1],2);
  1121. if(sizeof($info)<1){
  1122. self::Debug('WARNING: Invalid service definition');
  1123. return true;
  1124. }
  1125. $server->Name=$info[0];
  1126. if($server->ParseDocs&&sizeof($info)>1&&is_null($server->Docs))
  1127. $server->Docs=$info[1];
  1128. return true;
  1129. }
  1130. /**
  1131. * Interpret a setting
  1132. *
  1133. * @param array $data The parser data
  1134. * @return boolean Response
  1135. */
  1136. public static function InterpretSetting($data){
  1137. $info=explode(' ',$data['keyword'][1],2);
  1138. if(sizeof($info)<1)
  1139. return true;
  1140. self::Debug('Interpret setting '.$info[0]);
  1141. $info=explode('=',$info[0],2);
  1142. if(sizeof($info)>1){
  1143. $data['settings'][$info[0]]=$info[1];
  1144. }else if(isset($data['settings'][$info[0]])){
  1145. unset($data['settings'][$info[0]]);
  1146. }
  1147. return false;
  1148. }
  1149. /**
  1150. * Parse source files for WSDL definitions in comments
  1151. *
  1152. * @param boolean $init Empty the Methods and the Types properties? (default: FALSE)
  1153. * @param string $str Source string or NULL to parse the defined files (default: NULL)
  1154. */
  1155. public function ParseSource($init=false,$str=null){
  1156. self::Debug('Parse the source');
  1157. if($init){
  1158. self::Debug('Init methods and types');
  1159. $this->Methods=Array();
  1160. $this->Types=Array();
  1161. $this->SourcesParsed=false;
  1162. }
  1163. if(is_null($str)){
  1164. if($this->SourcesParsed)
  1165. return;
  1166. self::Debug('Load source files');
  1167. $this->SourcesParsed=true;
  1168. $fLen=sizeof($this->Files);
  1169. if($fLen<1)
  1170. return;
  1171. // Load the source
  1172. $src=Array();
  1173. $i=-1;
  1174. while(++$i<$fLen)
  1175. $src[]=trim(file_get_contents($this->Files[$i]));
  1176. }else{
  1177. self::Debug('Use given string');
  1178. $src=Array($str);
  1179. }
  1180. // Parse the source
  1181. self::Debug('Run the parser');
  1182. $parser=new PhpWsdlParser($this);
  1183. $parser->Parse(implode("\n",$src));
  1184. }
  1185. /**
  1186. * Output the WSDL to the client
  1187. *
  1188. * @param boolean $withHeaders Output XML headers? (default: TRUE)
  1189. */
  1190. public function OutputWsdl($withHeaders=true){
  1191. if(!self::CallHook(
  1192. 'OutputWsdlHook',
  1193. Array(
  1194. 'server' => $this
  1195. )
  1196. )
  1197. )
  1198. return;
  1199. self::Debug('Output WSDL');
  1200. if($withHeaders)
  1201. header('Content-Type: text/xml; charset=UTF-8',true);
  1202. echo $this->CreateWsdl();
  1203. }
  1204. /**
  1205. * Output the WSDL to the client, if requested
  1206. *
  1207. * @param boolean $andExit Exit after sending WSDL? (default: TRUE)
  1208. * @return boolean Has the WSDL been sent to the client?
  1209. */
  1210. public function OutputWsdlOnRequest($andExit=true){
  1211. if(!$this->IsWsdlRequested())
  1212. return false;
  1213. $this->OutputWsdl();
  1214. if($andExit){
  1215. self::Debug('Exit script execution');
  1216. exit;
  1217. }
  1218. return true;
  1219. }
  1220. /**
  1221. * Output the HTML to the client
  1222. *
  1223. * @param boolean $withHeaders Send HTML headers? (default: TRUE)
  1224. * @param boolean $echo Print HTML (default: TRUE)
  1225. * @param boolean $cache Cache the result (default: TRUE);
  1226. * @return string The HTML
  1227. */
  1228. public function OutputHtml($withHeaders=true,$echo=true,$cache=true){
  1229. self::Debug('Output HTML');
  1230. if(sizeof($this->Methods)<1)
  1231. $this->CreateWsdl();
  1232. if(!self::CallHook(
  1233. 'OutputHtmlHook',
  1234. Array(
  1235. 'server' => $this
  1236. )
  1237. )
  1238. )
  1239. return;
  1240. // Header
  1241. if($withHeaders)
  1242. header('Content-Type: text/html; charset=UTF-8',true);
  1243. $this->GetWsdlFromCache();
  1244. if(!is_null($this->HTML)){
  1245. if($echo)
  1246. echo $this->HTML;
  1247. return $this->HTML;
  1248. }
  1249. $res=Array();
  1250. $res[]='<html>';
  1251. $res[]='<head>';
  1252. $res[]='<title>'.((is_null($this->HtmlHeadLine))?$this->Name.' interface description':nl2br(htmlentities($this->HtmlHeadLine))).'</title>';
  1253. $res[]='<style type="text/css" media="all">';
  1254. $res[]='body{font-family:Calibri,Arial;background-color:#fefefe;}';
  1255. $res[]='.pre{font-family:Courier;}';
  1256. $res[]='.normal{font-family:Calibri,Arial;}';
  1257. $res[]='.bold{font-weight:bold;}';
  1258. $res[]='h1,h2,h3{font-family:Verdana,Times;}';
  1259. $res[]='h1{border-bottom:1px solid gray;}';
  1260. $res[]='h2{border-bottom:1px solid silver;}';
  1261. $res[]='h3{border-bottom:1px dashed silver;}';
  1262. $res[]='a{text-decoration:none;}';
  1263. $res[]='a:hover{text-decoration:underline;}';
  1264. $res[]='.blue{color:#3400FF;}';
  1265. $res[]='.lightBlue{color:#5491AF;}';
  1266. if(!is_null(self::$HTML2PDFLicenseKey)&&self::$HTML2PDFSettings['attachments']=='1')
  1267. $res[]='.print{display:none;}';
  1268. self::CallHook(
  1269. 'CreateHtmlCssHook',
  1270. Array(
  1271. 'server' => $this,
  1272. 'res' => &$res
  1273. )
  1274. );
  1275. $res[]='</style>';
  1276. $res[]='<style type="text/css" media="print">';
  1277. $res[]='.noprint{display:none;}';
  1278. if(!is_null(self::$HTML2PDFLicenseKey)&&self::$HTML2PDFSettings['attachments']=='1')
  1279. $res[]='.print{display:block;}';
  1280. self::CallHook(
  1281. 'CreateHtmlCssPrintHook',
  1282. Array(
  1283. 'server' => $this,
  1284. 'res' => &$res
  1285. )
  1286. );
  1287. $res[]='</style>';
  1288. $res[]='</head>';
  1289. $res[]='<body>';
  1290. $types=$this->SortObjectsByName($this->Types);
  1291. $methods=$this->SortObjectsByName($this->Methods);
  1292. // General information
  1293. self::CallHook(
  1294. 'CreateHtmlGeneralHook',
  1295. Array(
  1296. 'server' => $this,
  1297. 'res' => &$res,
  1298. 'methods' => &$methods,
  1299. 'types' => &$types
  1300. )
  1301. );
  1302. // Index
  1303. self::CallHook(
  1304. 'CreateHtmlIndexHook',
  1305. Array(
  1306. 'server' => $this,
  1307. 'res' => &$res,
  1308. 'methods' => &$methods,
  1309. 'types' => &$types
  1310. )
  1311. );
  1312. // Complex types
  1313. self::CallHook(
  1314. 'CreateHtmlComplexTypesHook',
  1315. Array(
  1316. 'server' => $this,
  1317. 'res' => &$res,
  1318. 'methods' => &$methods,
  1319. 'types' => &$types
  1320. )
  1321. );
  1322. // Methods
  1323. self::CallHook(
  1324. 'CreateHtmlMethodsHook',
  1325. Array(
  1326. 'server' => $this,
  1327. 'res' => &$res,
  1328. 'methods' => &$methods,
  1329. 'types' => &$types
  1330. )
  1331. );
  1332. // HTML2PDF link
  1333. $param=Array(
  1334. 'plain' => '1',
  1335. 'filename' => $this->Name.'-webservices.pdf',
  1336. 'print' => '1'
  1337. );
  1338. if(!is_null(self::$HTML2PDFLicenseKey)){
  1339. // Use advanced HTML2PDF API
  1340. $temp=array_merge(self::$HTML2PDFSettings,Array(
  1341. 'url' => $this->GetDocUri()
  1342. ));
  1343. if($temp['attachments']=='1'){
  1344. $cnt=0;
  1345. if(!$this->ForceNotOutputWsdl){
  1346. $cnt++;
  1347. $temp['attachment_'.$cnt]=$this->Name.'.wsdl:'.$this->GetWsdlUri();
  1348. if($this->ParseDocs&&$this->IncludeDocs){
  1349. $cnt++;
  1350. $temp['attachment_'.$cnt]=$this->Name.'-doc.wsdl:'.$this->GetWsdlUri().'&readable';
  1351. }
  1352. }
  1353. if(!$this->ForceNotOutputPhp){
  1354. $cnt++;
  1355. $temp['attachment_'.$cnt]=$this->Name.'.soapclient.php:'.$this->GetPhpUri();
  1356. }
  1357. self::CallHook(
  1358. 'PdfAttachmentHook',
  1359. Array(
  1360. 'server' => $this,
  1361. 'cnt' => &$cnt,
  1362. 'param' => &$temp,
  1363. 'res' => &$res,
  1364. 'methods' => &$methods,
  1365. 'types' => &$types
  1366. )
  1367. );
  1368. if($cnt<1)
  1369. unset($temp['attachments']);
  1370. }
  1371. $options=Array();
  1372. $keys=array_keys($temp);
  1373. $i=-1;
  1374. $len=sizeof($keys);
  1375. while(++$i<$len)
  1376. $options[]=$keys[$i].'='.$temp[$keys[$i]];
  1377. $options='$'.base64_encode(implode("\n",$options));
  1378. $license=sha1(self::$HTML2PDFLicenseKey.self::$HTML2PDFLicenseKey).'-'.sha1($options.self::$HTML2PDFLicenseKey);
  1379. $param['url']=$options;
  1380. $param['license']=$license;
  1381. }
  1382. $temp=$param;
  1383. $param=Array();
  1384. $keys=array_keys($temp);
  1385. $i=-1;
  1386. $len=sizeof($keys);
  1387. while(++$i<$len)
  1388. $param[]=urlencode($keys[$i]).'='.urlencode($temp[$keys[$i]]);
  1389. $pdfLink=self::$HTML2PDFAPI.'?'.implode('&',$param);
  1390. // Footer
  1391. $res[]='<hr>';
  1392. $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>';
  1393. $res[]='</body>';
  1394. $res[]='</html>';
  1395. // Clean up the generated HTML and send it
  1396. $res=implode("\n",$res);
  1397. $res=str_replace('<br />','<br>',$res);// Because nl2br will produce XHTML (and nothing if the second parameter is FALSE!?)
  1398. if(!self::CallHook(
  1399. 'SendHtmlHook',
  1400. Array(
  1401. 'server' => $this,
  1402. 'res' => &$res
  1403. )
  1404. )
  1405. )
  1406. return;
  1407. $res=utf8_encode($res);
  1408. $this->HTML=$res;
  1409. if($cache)
  1410. $this->WriteWsdlToCache(null,null,null,true);
  1411. if($echo)
  1412. echo $res;
  1413. return $res;
  1414. }
  1415. /**
  1416. * Create general information
  1417. *
  1418. * @param array $data The information object
  1419. * @return boolean Response
  1420. */
  1421. public static function CreateHtmlGeneral($data){
  1422. self::Debug('CreateHtmlGeneral');
  1423. $res=&$data['res'];
  1424. $server=$data['server'];
  1425. $res[]='<h1>'.$server->Name.' SOAP WebService interface description</h1>';
  1426. $res[]='<p>Endpoint URI: <span class="pre">'.$server->EndPoint.'</span></p>';
  1427. if(!$server->ForceNotOutputWsdl)
  1428. $res[]='<p>WSDL URI: <span class="pre"><a href="'.$server->GetWsdlUri().'&readable">'.$server->GetWsdlUri().'</a></span></p>';
  1429. if(!$server->ForceNotOutputPhp)
  1430. $res[]='<p>PHP SOAP client download URI: <span class="pre"><a href="'.$server->GetPhpUri().'">'.$server->GetPhpUri().'</a></span></p>';
  1431. //FIXME There may be attachments if a hooking method (PdfAttachmentHook) adds a file!
  1432. if(self::$HTML2PDFSettings['attachments']=='1'&&!is_null(self::$HTML2PDFLicenseKey)&&($server->ForceNotOutputWsdl||$server->ForceNotOutputPhp))
  1433. $res[]='<p class="print">Additional files are attached to this PDF documentation.</p>';
  1434. if(!is_null($server->Docs))
  1435. $res[]='<p>'.nl2br(htmlentities($server->Docs)).'</p>';
  1436. return true;
  1437. }
  1438. /**
  1439. * Create table of contents
  1440. *
  1441. * @param array $data The information object
  1442. * @return boolean Response
  1443. */
  1444. public static function CreateHtmlIndex($data){
  1445. self::Debug('CreateHtmlIndex');
  1446. $res=&$data['res'];
  1447. $types=&$data['types'];
  1448. $methods=&$data['methods'];
  1449. $tLen=sizeof($types);
  1450. $mLen=sizeof($methods);
  1451. $res[]='<div class="noprint">';
  1452. $res[]='<h2>Index</h2>';
  1453. if($tLen>0){
  1454. $res[]='<p>Exported types:</p>';
  1455. $i=-1;
  1456. $res[]='<ul>';
  1457. while(++$i<$tLen)
  1458. $res[]='<li><a href="#'.$types[$i]->Name.'"><span class="pre">'.$types[$i]->Name.'</span></a></li>';
  1459. $res[]='</ul>';
  1460. }
  1461. if($mLen>0){
  1462. $res[]='<p>Public methods:</p>';
  1463. $i=-1;
  1464. $res[]='<ul>';
  1465. while(++$i<$mLen)
  1466. $res[]='<li><a href="#'.$methods[$i]->Name.'"><span class="pre">'.$methods[$i]->Name.'</span></a></li>';
  1467. $res[]='</ul>';
  1468. }
  1469. $res[]='</div>';
  1470. return true;
  1471. }
  1472. /**
  1473. * Create method list
  1474. *
  1475. * @param array $data The information object
  1476. * @return boolean Response
  1477. */
  1478. public static function CreateHtmlMethods($data){
  1479. self::Debug('CreateHtmlMethods');
  1480. $res=&$data['res'];
  1481. $methods=&$data['methods'];
  1482. $mLen=sizeof($methods);
  1483. if($mLen>0){
  1484. $res[]='<h2>Public methods</h2>';
  1485. $i=-1;
  1486. while(++$i<$mLen)
  1487. $methods[$i]->CreateMethodHtml(array_merge(
  1488. $data,
  1489. Array(
  1490. 'method' => $methods[$i]
  1491. )
  1492. ));
  1493. }
  1494. return true;
  1495. }
  1496. /**
  1497. * Create complex types list
  1498. *
  1499. * @param array $data The information object
  1500. * @return boolean Response
  1501. */
  1502. public static function CreateHtmlComplexTypes($data){
  1503. self::Debug('CreateHtmlComplexTypes');
  1504. $res=&$data['res'];
  1505. $types=&$data['types'];
  1506. $server=$data['server'];
  1507. $tLen=sizeof($server->Types);
  1508. if($tLen>0){
  1509. $res[]='<h2>Exported types</h2>';
  1510. $i=-1;
  1511. while(++$i<$tLen)
  1512. $types[$i]->CreateTypeHtml(array_merge(
  1513. $data,
  1514. Array(
  1515. 'type' => $types[$i]
  1516. )
  1517. ));
  1518. }
  1519. return true;
  1520. }
  1521. /**
  1522. * Sort objects by name
  1523. *
  1524. * @param PhpWsdlComplex[]|PhpWsdlMethod[] $obj
  1525. * @return PhpWsdlComplex[]|PhpWsdlMethod[] Sorted objects
  1526. */
  1527. public function SortObjectsByName($obj){
  1528. self::Debug('Sort objects by name');
  1529. $temp=Array();
  1530. $i=-1;
  1531. $len=sizeof($obj);
  1532. while(++$i<$len)
  1533. $temp[$obj[$i]->Name]=$obj[$i];
  1534. $keys=array_keys($temp);
  1535. sort($keys);
  1536. $res=Array();
  1537. $i=-1;
  1538. while(++$i<$len)
  1539. $res[]=$temp[$keys[$i]];
  1540. return $res;
  1541. }
  1542. /**
  1543. * Output the HTML to the client, if requested
  1544. *
  1545. * @param boolean $andExit Exit after sending HTML? (default: TRUE)
  1546. * @return boolean Has the HTML been sent to the client?
  1547. */
  1548. public function OutputHtmlOnRequest($andExit=true){
  1549. if(!$this->IsHtmlRequested())
  1550. return false;
  1551. $this->OutputHtml();
  1552. if($andExit){
  1553. self::Debug('Exit script execution');
  1554. exit;
  1555. }
  1556. return true;
  1557. }
  1558. /**
  1559. * Output the PHP SOAP client source for this webservice
  1560. *
  1561. * @param boolean $withHeaders Send text headers? (default: TRUE)
  1562. * @param boolean $echo Print source (default: TRUE)
  1563. * @param array $options Options array (default: array)
  1564. * @param boolean $cache Cache the result (default: TRUE);
  1565. * @return string PHP source
  1566. */
  1567. public function OutputPhp($withHeaders=true,$echo=true,$options=Array(),$cache=true){
  1568. self::Debug('Output PHP');
  1569. if(sizeof($this->Methods)<1)
  1570. $this->CreateWsdl();
  1571. if(!self::CallHook(
  1572. 'OutputPhpHook',
  1573. Array(
  1574. 'server' => $this,
  1575. 'withHeaders' => &$withHeaders,
  1576. 'echo' => &$echo,
  1577. 'options' => &$options
  1578. )
  1579. )
  1580. )
  1581. return '';
  1582. // Options
  1583. $hasOptions=sizeof(array_keys($options))>0;
  1584. if(!isset($options['class']))
  1585. $options['class']=$this->Name.'SoapClient';
  1586. if(!isset($options['openphp']))
  1587. $options['openphp']=true;
  1588. if(!isset($options['phpclient']))
  1589. $options['phpclient']=true;
  1590. $data=Array(
  1591. 'server' => $this,
  1592. 'withHeaders' => &$withHeaders,
  1593. 'echo' => &$echo,
  1594. 'options' => &$options,
  1595. 'res' => &$res
  1596. );
  1597. // Header
  1598. if($withHeaders){
  1599. header('Content-Type: text/plain; charset=UTF-8',true);
  1600. header('Content-Disposition: attachment; filename='.$options['class'].'.php');
  1601. }
  1602. if(!$hasOptions){
  1603. if(is_null($this->PHP))
  1604. $this->GetWsdlFromCache();
  1605. if(!is_null($this->PHP)){
  1606. if($echo)
  1607. echo $this->PHP;
  1608. return $this->PHP;
  1609. }
  1610. }else if(isset($options['php'])&&!is_null($options['php'])){
  1611. echo $options['php'];
  1612. return $options['php'];
  1613. }
  1614. $res=Array();
  1615. if($options['openphp'])
  1616. $res[]="<?php";
  1617. $res[]="/**";
  1618. if(!is_null($this->Docs)){
  1619. $res[]=" * ".implode("\n * ",explode("\n",$this->Docs));
  1620. $res[]=" *";
  1621. }
  1622. $res[]=" * @service ".$options['class'];
  1623. $res[]=" */";
  1624. $res[]="class ".$options['class']."{";
  1625. $res[]="\t/**";
  1626. $res[]="\t * The WSDL URI";
  1627. $res[]="\t *";
  1628. $res[]="\t * @var string";
  1629. $res[]="\t */";
  1630. $res[]="\tpublic static \$_WsdlUri='".(!is_null($this->WsdlUri)?$this->WsdlUri:$this->EndPoint.'?WSDL')."';";
  1631. $res[]="\t/**";
  1632. $res[]="\t * The PHP SoapClient object";
  1633. $res[]="\t *";
  1634. $res[]="\t * @var object";
  1635. $res[]="\t */";
  1636. $res[]="\tpublic static \$_Server=null;";
  1637. self::CallHook('BeginCreatePhpHook',$data);
  1638. $res[]='';
  1639. $res[]="\t/**";
  1640. $res[]="\t * Send a SOAP request to the server";
  1641. $res[]="\t *";
  1642. $res[]="\t * @param string \$method The method name";
  1643. $res[]="\t * @param array \$param The parameters";
  1644. $res[]="\t * @return mixed The server response";
  1645. $res[]="\t */";
  1646. $res[]="\tpublic static function _Call(\$method,\$param){";
  1647. if(self::CallHook('CreatePhpCallHook',$data)){
  1648. $res[]="\t\tif(is_null(self::\$_Server))";
  1649. if($options['phpclient']){
  1650. $res[]="\t\t\tself::\$_Server=new SoapClient(self::\$_WsdlUri);";
  1651. $res[]="\t\treturn self::\$_Server->__soapCall(\$method,\$param);";
  1652. }else{
  1653. $res[]="\t\t\tself::\$_Server=new PhpWsdlClient(self::\$_WsdlUri);";
  1654. $res[]="\t\treturn self::\$_Server->DoRequest(\$method,\$param);";
  1655. }
  1656. }
  1657. $res[]="\t}";
  1658. // Methods
  1659. $i=-1;
  1660. $len=sizeof($this->Methods);
  1661. while(++$i<$len){
  1662. $res[]='';
  1663. $this->Methods[$i]->CreateMethodPhp($data);
  1664. }
  1665. $res[]="}";
  1666. // Types
  1667. $i=-1;
  1668. $len=sizeof($this->Types);
  1669. while(++$i<$len){
  1670. $res[]='';
  1671. $this->Types[$i]->CreateTypePhp($data);
  1672. }
  1673. self::CallHook('EndCreatePhpHook',$data);
  1674. $res=utf8_encode(implode("\n",$res));
  1675. if(!$hasOptions){
  1676. if(is_null($this->PHP))
  1677. $this->PHP=$res;
  1678. if($cache)
  1679. $this->WriteWsdlToCache(null,null,null,true);
  1680. }
  1681. if($echo)
  1682. echo $res;
  1683. return $res;
  1684. }
  1685. /**
  1686. * Output the PHP SOAP client source for this webservice, if requested
  1687. *
  1688. * @param boolean $andExit Exit after sending the PHP source?
  1689. * @return boolean PHP sent?
  1690. */
  1691. public function OutputPhpOnRequest($andExit=true){
  1692. if(!$this->IsPhpRequested())
  1693. return false;
  1694. $this->OutputPhp();
  1695. if($andExit){
  1696. self::Debug('Exit script execution');
  1697. exit;
  1698. }
  1699. return true;
  1700. }
  1701. /**
  1702. * Run the PHP SoapServer
  1703. *
  1704. * @param string $wsdlFile The WSDL file name or NULL to let PhpWsdl decide (default: NULL)
  1705. * @param string|object|array $class The class name to serve, the classname and class as array or NULL (default: NULL)
  1706. * @param boolean $andExit Exit after running the server? (default: TRUE)
  1707. * @param boolean $forceNoWsdl Force no WSDL usage? (default: FALSE);
  1708. * @return boolean Did the server run?
  1709. */
  1710. public function RunServer($wsdlFile=null,$class=null,$andExit=true,$forceNoWsdl=false){
  1711. self::Debug('Run the server');
  1712. if($forceNoWsdl)
  1713. self::Debug('Forced non-WSDL mode');
  1714. if(self::CallHook(
  1715. 'BeforeRunServerHook',
  1716. Array(
  1717. 'server' => $this,
  1718. 'wsdlfile' => &$wsdlFile,
  1719. 'class' => &$class,
  1720. 'andexit' => &$andExit,
  1721. 'forcenowsdl' => &$forceNoWsdl
  1722. )
  1723. )
  1724. ){
  1725. // WSDL requested?
  1726. if($this->OutputWsdlOnRequest($andExit))
  1727. return false;
  1728. // PHP requested?
  1729. if($this->OutputPhpOnRequest($andExit))
  1730. return false;
  1731. // HTML requested?
  1732. if($this->OutputHtmlOnRequest($andExit))
  1733. return false;
  1734. }
  1735. // Login
  1736. $user=null;
  1737. $password=null;
  1738. if($this->RequireLogin){
  1739. if(isset($_SERVER['PHP_AUTH_USER'])||isset($_SERVER['PHP_AUTH_PW'])){
  1740. $user=(isset($_SERVER['PHP_AUTH_USER']))?$_SERVER['PHP_AUTH_USER']:null;
  1741. $password=(isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW']:null;
  1742. }
  1743. self::Debug('Check login '.$user.':'.str_repeat('*',strlen($password)));
  1744. if(!self::CallHook(
  1745. 'LoginHook',
  1746. Array(
  1747. 'server' => $this,
  1748. 'user' => &$user,
  1749. 'password' => &$password
  1750. )
  1751. )
  1752. ){
  1753. self::Debug('Login required');
  1754. header('WWW-Authenticate: Basic realm="Webservice login required"');
  1755. header('HTTP/1.0 401 Unauthorized');
  1756. if($andExit){
  1757. self::Debug('Exit script execution');
  1758. exit;
  1759. }
  1760. return false;
  1761. }
  1762. }
  1763. // Load the proxy
  1764. $useProxy=false;
  1765. if(is_array($class)){
  1766. self::Debug('Use the proxy for '.$class[0]);
  1767. self::$ProxyObject=$class[1];
  1768. self::$ProxyServer=$this;
  1769. $class=$class[0];
  1770. $useProxy=true;
  1771. }
  1772. // Ensure a webservice name
  1773. if(is_null($class)){
  1774. self::Debug('No webservice name yet');
  1775. if(!$this->DetermineConfiguration())
  1776. throw(new Exception('Invalid configuration'));
  1777. if(!is_null($this->Name))
  1778. $class=$this->Name;
  1779. }else if(is_string($class)){
  1780. self::Debug('Using '.$class.' as webservice name');
  1781. $this->Name=$class;
  1782. }
  1783. self::Debug('Use class '.((!is_object($class))?$class:get_class($class)));
  1784. // Load WSDL
  1785. if(!$forceNoWsdl&&(!$useProxy||self::$UseProxyWsdl)){
  1786. self::Debug('Load WSDL');
  1787. $this->CreateWsdl(false,true);
  1788. if(is_null($wsdlFile))
  1789. $wsdlFile=$this->GetCacheFileName();
  1790. if(!is_null($wsdlFile))
  1791. if(!file_exists($wsdlFile)){
  1792. self::Debug('WSDL file "'.$wsdlFile.'" does not exists');
  1793. $wsdlFile=null;
  1794. }
  1795. }
  1796. // Load the files, if the webservice handler class doesn't exist
  1797. if(!is_object($class))
  1798. if(!class_exists($class)&&!$this->IsOnlyGlobal()){
  1799. self::Debug('Try to load the webservice handler class');
  1800. $i=-1;
  1801. $len=sizeof($this->Files);
  1802. while(++$i<$len){
  1803. self::Debug('Load '.$this->Files[$i]);
  1804. require_once($this->Files[$i]);
  1805. }
  1806. if(!class_exists($class)){
  1807. // Try class.webservice.php
  1808. if(file_exists('class.webservice.php')){
  1809. self::Debug('Try to load class.webservice.php');
  1810. require_once('class.webservice.php');
  1811. if(class_exists($class))
  1812. $this->Files[]='class.webservice.php';
  1813. }
  1814. if(!class_exists($class))
  1815. if(file_exists(dirname(__FILE__).'/class.webservice.php')){
  1816. self::Debug('Try to load '.dirname(__FILE__).'/class.webservice.php');
  1817. require_once(dirname(__FILE__).'/class.webservice.php');
  1818. if(class_exists($class))
  1819. $this->Files[]=dirname(__FILE__).'/class.webservice.php';
  1820. }
  1821. if(!class_exists($class))
  1822. // A handler class or object is required when using non-global methods!
  1823. throw(new Exception('Webservice handler class not present'));
  1824. }
  1825. }
  1826. // Prepare the PhpWsdlHandler
  1827. if($this->CreateHandler){
  1828. self::Debug('Use PhpWsdlHandler');
  1829. if(is_null($class))
  1830. $class=$this->Name;
  1831. $class=$this->CreateHandler($class);
  1832. }
  1833. // Prepare the SOAP server
  1834. $this->SoapServer=null;
  1835. if(self::CallHook(
  1836. 'PrepareServerHook',
  1837. Array(
  1838. 'server' => $this,
  1839. 'soapserver' => &$this->SoapServer,
  1840. 'wsdlfile' => &$wsdlFile,
  1841. 'class' => &$class,
  1842. 'useproxy' => &$useProxy,
  1843. 'forcenowsdl' => &$forceNoWsdl,
  1844. 'andexit' => &$andExit,
  1845. 'user' => &$user,
  1846. 'password' => &$password
  1847. )
  1848. )
  1849. ){
  1850. self::Debug('Prepare the SOAP server');
  1851. // WSDL file
  1852. $wsdlFile=($forceNoWsdl||($useProxy&&!self::$UseProxyWsdl))?null:$wsdlFile;
  1853. if(!is_null($wsdlFile)){
  1854. self::Debug('Using WSDL file '.$wsdlFile);
  1855. }else{
  1856. self::Debug('No WSDL file');
  1857. }
  1858. // Server options
  1859. $temp=Array(
  1860. 'actor' => $this->EndPoint,
  1861. 'uri' => $this->NameSpace,
  1862. );
  1863. $temp=array_merge($this->SoapServerOptions,$temp);
  1864. if(self::$Debugging)
  1865. self::Debug('Server options: '.print_r($temp,true));
  1866. // Create the server object
  1867. self::Debug('Creating PHP SoapServer object');
  1868. $this->SoapServer=new SoapServer(
  1869. $wsdlFile,
  1870. $temp
  1871. );
  1872. // Set the handler class or object
  1873. if($useProxy||!is_object($class)){
  1874. $temp=($useProxy)?'PhpWsdlProxy':$class;
  1875. if(!is_null($temp)){
  1876. self::Debug('Setting server class '.$temp);
  1877. $this->SoapServer->setClass($temp);
  1878. }else{
  1879. self::Debug('No server class or object');
  1880. }
  1881. }else{
  1882. self::Debug('Setting server object '.get_class($class));
  1883. $this->SoapServer->setObject($class);
  1884. }
  1885. // Add global methods
  1886. if(!$useProxy&&!$this->CreateHandler){
  1887. $i=-1;
  1888. $len=sizeof($this->Methods);
  1889. while(++$i<$len)
  1890. if($this->Methods[$i]->IsGlobal){
  1891. self::Debug('Adding global method '.$this->Methods[$i]->Name);
  1892. $this->SoapServer->addFunction($this->Methods[$i]->Name);
  1893. }
  1894. }else{
  1895. self::Debug('Omit adding global methods to the SoapServer object since they will be called by the proxy or the PhpWsdlHandler object');
  1896. }
  1897. }
  1898. // Run the SOAP server
  1899. if(self::CallHook(
  1900. 'RunServerHook',
  1901. Array(
  1902. 'server' => $this,
  1903. 'soapserver' => &$this->SoapServer,
  1904. 'wsdlfile' => &$wsdlFile,
  1905. 'class' => &$class,
  1906. 'useproxy' => &$useProxy,
  1907. 'forcenowsdl' => &$forceNoWsdl,
  1908. 'andexit' => &$andExit,
  1909. 'user' => &$user,
  1910. 'password' => &$password
  1911. )
  1912. )
  1913. ){
  1914. self::Debug('Run the SOAP server');
  1915. $this->SoapServer->handle();
  1916. if($andExit){
  1917. self::Debug('Exit script execution');
  1918. exit;
  1919. }
  1920. }
  1921. return true;
  1922. }
  1923. /**
  1924. * Get the WSDL download URI
  1925. *
  1926. * @return string The Uri
  1927. */
  1928. public function GetWsdlUri(){
  1929. return ((is_null($this->WsdlUri))?$this->EndPoint:$this->WsdlUri).'?WSDL';
  1930. }
  1931. /**
  1932. * Get the PHP download URI
  1933. *
  1934. * @return string The URI
  1935. */
  1936. public function GetPhpUri(){
  1937. return ((is_null($this->PhpUri))?$this->EndPoint:$this->PhpUri).'?PHPSOAPCLIENT';
  1938. }
  1939. /**
  1940. * Get the HTML documentation URI
  1941. *
  1942. * @return string The Uri
  1943. */
  1944. public function GetDocUri(){
  1945. return (is_null($this->PhpUri))?$this->EndPoint:$this->DocUri;
  1946. }
  1947. /**
  1948. * Find a method
  1949. *
  1950. * @param string $name The method name
  1951. * @return PhpWsdlMethod The method object or NULL
  1952. */
  1953. public function GetMethod($name){
  1954. self::Debug('Find method '.$name);
  1955. $i=-1;
  1956. $len=sizeof($this->Methods);
  1957. while(++$i<$len)
  1958. if($this->Methods[$i]->Name==$name){
  1959. self::Debug('Found method at index '.$i);
  1960. return $this->Methods[$i];
  1961. }
  1962. return null;
  1963. }
  1964. /**
  1965. * Find a complex type
  1966. *
  1967. * @param string $name The type name
  1968. * @return PhpWsdlComplex The type object or NULL
  1969. */
  1970. public function GetType($name){
  1971. self::Debug('Find type '.$name);
  1972. $i=-1;
  1973. $len=sizeof($this->Types);
  1974. while(++$i<$len)
  1975. if($this->Types[$i]->Name==$name){
  1976. self::Debug('Found type at index '.$i);
  1977. return $this->Types[$i];
  1978. }
  1979. return null;
  1980. }
  1981. /**
  1982. * Set a object for all methods from a class
  1983. *
  1984. * @param string $class The class name
  1985. * @param object $obj An instance of the class
  1986. */
  1987. public function SetMethodObject($class,$obj){
  1988. $i=-1;
  1989. $len=sizeof($this->Methods);
  1990. while(++$i<$len){
  1991. $m=$this->Methods[$i];
  1992. if($m->Class!=$class)
  1993. continue;
  1994. $m->Class=$obj;
  1995. }
  1996. }
  1997. /**
  1998. * Get the cache filename
  1999. *
  2000. * @param string $endpoint The endpoint URI or NULL to use the PhpWsdl->EndPoint property (default: NULL)
  2001. * @return string The cache filename or NULL, if caching is disabled
  2002. */
  2003. public function GetCacheFileName($endpoint=null){
  2004. $data=Array(
  2005. 'server' => $this,
  2006. 'endpoint' => $endpoint,
  2007. 'filename' => (is_null(self::$CacheFolder))?null:self::$CacheFolder.'/'.sha1((is_null($endpoint))?$this->EndPoint:$endpoint).'.wsdl'
  2008. );
  2009. self::CallHook(
  2010. 'CacheFileNameHook',
  2011. $data
  2012. );
  2013. return $data['filename'];
  2014. }
  2015. /**
  2016. * Determine if the cache file exists
  2017. *
  2018. * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
  2019. * @return boolean Are the cache files present?
  2020. */
  2021. public function CacheFileExists($file=null){
  2022. if(is_null($file))
  2023. $file=$this->GetCacheFileName();
  2024. self::Debug('Check cache file exists '.$file);
  2025. return file_exists($file)&&file_exists($file.'.cache');
  2026. }
  2027. /**
  2028. * Determine if the existing cache files are still valid
  2029. *
  2030. * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
  2031. * @return boolean Valid?
  2032. */
  2033. public function IsCacheValid($file=null){
  2034. self::Debug('Check cache valid');
  2035. if(is_null($file))
  2036. $file=$this->GetCacheFileName();
  2037. if(!$this->CacheFileExists($file))
  2038. return false;
  2039. return self::$CacheTime<0||time()-file_get_contents($file.'.cache')<=self::$CacheTime;
  2040. }
  2041. /**
  2042. * Get the WSDL from the cache
  2043. *
  2044. * @param string $file The WSDL cache filename or NULL to use the default (default: NULL)
  2045. * @param boolean $force Force this even if the cache is timed out? (default: FALSE)
  2046. * @param boolean $nounserialize Don't unserialize the PhpWsdl* objects? (default: FALSE)
  2047. * @return string The cached WSDL
  2048. */
  2049. public function GetWsdlFromCache($file=null,$force=false,$nounserialize=false){
  2050. self::Debug('Get WSDL from cache');
  2051. if(!is_null($this->WSDL))
  2052. return $this->WSDL;
  2053. if(is_null($file))
  2054. $file=$this->GetCacheFileName();
  2055. if(!$force){
  2056. if(!$this->IsCacheValid($file))
  2057. return null;
  2058. }else if(!$this->CacheFileExists($file)){
  2059. return null;
  2060. }
  2061. $this->WSDL=file_get_contents($file);
  2062. if(!$nounserialize){
  2063. self::Debug('Unserialize methods, types and files');
  2064. $data=unserialize(file_get_contents($file.'.obj'));
  2065. $this->Methods=$data['methods'];
  2066. $this->Types=$data['types'];
  2067. $this->Files=$data['files'];
  2068. $this->Name=$data['name'];
  2069. $this->Docs=$data['docs'];
  2070. $this->HTML=$data['html'];
  2071. $this->PHP=$data['php'];
  2072. $this->WsdlUri=$data['wsdluri'];
  2073. $this->PhpUri=$data['phpuri'];
  2074. $this->DocUri=$data['docuri'];
  2075. $this->HandlerPhp=$data['handler'];
  2076. self::CallHook(
  2077. 'ReadCacheHook',
  2078. Array(
  2079. 'server' => $this,
  2080. 'data' => &$data
  2081. )
  2082. );
  2083. if($data['version']!=self::$VERSION){
  2084. self::Debug('Could not use cache from version '.$data['version']);
  2085. $this->Methods=Array();
  2086. $this->Types=Array();
  2087. $this->Files=Array();
  2088. $this->Name=null;
  2089. $this->Docs=null;
  2090. $this->HTML=null;
  2091. $this->PHP=null;
  2092. $this->WsdlUri=null;
  2093. $this->PhpUri=null;
  2094. $this->DocUri=null;
  2095. $this->WSDL=null;
  2096. $this->TidyCacheFolder(true);
  2097. return null;
  2098. }
  2099. }
  2100. $this->ConfigurationDetermined=true;
  2101. $this->SourcesParsed=true;
  2102. return $this->WSDL;
  2103. }
  2104. /**
  2105. * Write WSDL to cache
  2106. *
  2107. * @param string $wsdl The UTF-8 encoded WSDL string (default: NULL)
  2108. * @param string $endpoint The SOAP endpoint or NULL to use the default (default: NULL)
  2109. * @param string $file The target filename or NULL to use the default (default: NULL)
  2110. * @param boolean $force Force refresh (default: FALSE)
  2111. * @return boolean Succeed?
  2112. */
  2113. public function WriteWsdlToCache($wsdl=null,$endpoint=null,$file=null,$force=false){
  2114. self::Debug('Write WSDL to the cache');
  2115. if(is_null($endpoint))
  2116. $endpoint=$this->EndPoint;
  2117. if($endpoint==$this->EndPoint&&!is_null($wsdl))
  2118. $this->WSDL=$wsdl;
  2119. if(is_null($wsdl)){
  2120. if(is_null($this->WSDL)){
  2121. self::Debug('No WSDL');
  2122. return false;// WSDL not defined
  2123. }
  2124. $wsdl=$this->WSDL;
  2125. }
  2126. if(is_null($file)){
  2127. $file=$this->GetCacheFileName($endpoint);
  2128. if(is_null($file)){
  2129. self::Debug('No cache file');
  2130. return false;// No cache file
  2131. }
  2132. }
  2133. $temp=substr($file,0,1);
  2134. if($temp!='/'&&$temp!='.'){
  2135. if(is_null(self::$CacheFolder)){
  2136. self::Debug('No cache folder');
  2137. return false;// No cache folder
  2138. }
  2139. $file=self::$CacheFolder.'/'.$file;
  2140. }
  2141. if(!$force)
  2142. if($this->IsCacheValid($file)){
  2143. self::Debug('Cache is still valid');
  2144. return true;// Existing cache is still valid
  2145. }
  2146. self::Debug('Write to '.$file);
  2147. if(file_put_contents($file,$wsdl)===false){
  2148. self::Debug('Could not write to cache');
  2149. return false;// Error writing to cache
  2150. }
  2151. if(file_put_contents($file.'.cache',time())===false){
  2152. self::Debug('Could not write cache time file');
  2153. return false;// Error writing to cache
  2154. }
  2155. $data=Array(
  2156. 'version' => self::$VERSION,
  2157. 'methods' => $this->Methods,
  2158. 'types' => $this->Types,
  2159. 'files' => $this->Files,
  2160. 'name' => $this->Name,
  2161. 'docs' => $this->Docs,
  2162. 'html' => $this->HTML,
  2163. 'php' => $this->PHP,
  2164. 'wsdluri' => $this->WsdlUri,
  2165. 'phpuri' => $this->PhpUri,
  2166. 'docuri' => $this->DocUri,
  2167. 'handler' => ($this->CreateHandler)?$this->HandlerPhp:null
  2168. );
  2169. self::CallHook(
  2170. 'WriteCacheHook',
  2171. Array(
  2172. 'server' => $this,
  2173. 'data' => &$data
  2174. )
  2175. );
  2176. if(file_put_contents($file.'.obj',serialize($data))===false){
  2177. self::Debug('Could not write serialized cache');
  2178. return false;// Error writing to cache
  2179. }
  2180. return true;
  2181. }
  2182. /**
  2183. * Determine if the cache folder is writeable
  2184. *
  2185. * @param string $folder The folder or NULL to use the static property CacheFolder (default: NULL)
  2186. * @return boolean Writeable?
  2187. */
  2188. public static function IsCacheFolderWriteAble($folder=null){
  2189. if(!is_null(self::$CacheFolderWriteAble))
  2190. return self::$CacheFolderWriteAble;
  2191. if(is_null($folder))
  2192. $folder=self::$CacheFolder;
  2193. if(is_null($folder)){
  2194. self::$CacheFolderWriteAble=false;
  2195. return false;
  2196. }
  2197. if(!is_dir($folder)){
  2198. self::Debug('Invalid cache folder (not a directory?)');
  2199. self::$CacheFolderWriteAble=false;
  2200. return;
  2201. }
  2202. $file=uniqid();
  2203. while(file_exists($folder.'/'.$file))
  2204. $file=uniqid();
  2205. $file=$folder.'/'.$file;
  2206. $temp=uniqid();
  2207. if(file_put_contents($file,$temp)===false){
  2208. self::$CacheFolderWriteAble=false;
  2209. return false;
  2210. }
  2211. $res=file_get_contents($file)===$temp;
  2212. unlink($file);
  2213. self::$CacheFolderWriteAble=$res;
  2214. return $res;
  2215. }
  2216. /**
  2217. * Determine if the cache is different from the current version of your webservice handler class.
  2218. * Status: Untested
  2219. *
  2220. * @return boolean Differences detected?
  2221. */
  2222. public function IsCacheDifferent(){
  2223. self::Debug('Determine if the cache is different from this instance');
  2224. // Load the cache
  2225. $temp=new PhpWsdl(null,$this->EndPoint);
  2226. $temp->GetWsdlFromCache();
  2227. if(is_null($temp->WSDL))
  2228. return true;// Not cached yet
  2229. // Initialize this instance
  2230. $this->DetermineConfiguration();
  2231. $this->ParseSource();
  2232. // Compare the cache with this instance
  2233. $res=serialize(
  2234. Array(
  2235. $this->Methods,
  2236. $this->Types
  2237. )
  2238. )!=serialize(
  2239. Array(
  2240. $temp->Methods,
  2241. $temp->Types
  2242. )
  2243. );
  2244. self::Debug('Cache is '.(($res)?'equal':'different'));
  2245. return $res;
  2246. }
  2247. /**
  2248. * Delete cache files from the cache folder
  2249. *
  2250. * @param boolean $mineOnly Only delete the cache files for this definition? (default: FALSE)
  2251. * @param boolean $cleanUp Only delete the cache files that are timed out? (default: FALSE)
  2252. * @param string $wsdlFile The WSDL filename (default: NULL)
  2253. * @return string[] The deleted filenames
  2254. */
  2255. public function TidyCacheFolder($mineOnly=false,$cleanUp=false,$wsdlFile=null){
  2256. if(is_null(self::$CacheFolder))
  2257. return Array();
  2258. $deleted=Array();
  2259. if($cleanUp){
  2260. self::Debug('Cleanup cache');
  2261. }else if($mineOnly){
  2262. self::Debug('Clean own cache');
  2263. }else{
  2264. self::Debug('Clean all cache');
  2265. }
  2266. if($mineOnly){
  2267. self::Debug('Delete own cache');
  2268. $file=(is_null($wsdlFile))?$this->GetCacheFileName():$wsdlFile;
  2269. if($cleanUp)
  2270. if($this->IsCacheValid($file))
  2271. return $deleted;
  2272. if(file_exists($file))
  2273. if(unlink($file))
  2274. $deleted[]=$file;
  2275. if(file_exists($file.'.cache'))
  2276. if(unlink($file.'.cache'))
  2277. $deleted[]=$file.'.cache';
  2278. if(file_exists($file.'.obj'))
  2279. if(unlink($file.'.obj'))
  2280. $deleted[]=$file.'.obj';
  2281. self::Debug(sizeof($deleted).' files deleted');
  2282. }else{
  2283. self::Debug('Delete whole cache');
  2284. $files=glob(self::$CacheFolder.(($cleanUp)?'/*.wsdl':'/*.wsd*'));
  2285. if($files!==false){
  2286. $toDelete=Array();
  2287. $i=-1;
  2288. $len=sizeof($files);
  2289. while(++$i<$len){
  2290. $file=$files[$i];
  2291. if($cleanUp){
  2292. if(!$this->IsCacheValid($file))
  2293. continue;
  2294. $toDelete[]=$file;
  2295. $toDelete[]=$file.'.cache';
  2296. $toDelete[]=$file.'.obj';
  2297. }else{
  2298. if(!preg_match('/\.wsdl(\.cache|\.obj)?$/',$file))
  2299. continue;
  2300. if(unlink($files[$i]))
  2301. $deleted[]=$files[$i];
  2302. }
  2303. }
  2304. if($cleanUp){
  2305. $i=-1;
  2306. $len=sizeof($toDelete);
  2307. while(++$i<$len)
  2308. if(file_exists($toDelete[$i]))
  2309. if(unlink($toDelete[$i]))
  2310. $deleted[]=$toDelete[$i];
  2311. }
  2312. self::Debug(sizeof($deleted).' files deleted');
  2313. }else{
  2314. self::Debug('"glob" failed');
  2315. }
  2316. }
  2317. return $deleted;
  2318. }
  2319. /**
  2320. * Create the handler object for this webservice
  2321. *
  2322. * @param string|object $targetHandler The target handler class name or object or NULL
  2323. * @return PhpWsdlHandler The handler object
  2324. */
  2325. public function CreateHandler($targetHandler=null){
  2326. if(!is_null($this->Handler))
  2327. return $this->Handler;
  2328. self::Debug('Create the handler object');
  2329. if(class_exists('PhpWsdlHandler')){
  2330. self::Debug('PhpWsdlHandler exists');
  2331. $this->Handler=new PhpWsdlHandler($this,$targetHandler);
  2332. self::Debug('Handler object created');
  2333. return $this->Handler;
  2334. }
  2335. self::Debug('Create PhpWsdlHandler');
  2336. if(is_null($this->HandlerPhp)){
  2337. $php=Array();
  2338. $php[]='class PhpWsdlHandler{';
  2339. // Variables
  2340. $php[]='public $_Server=null;';
  2341. $php[]='public $_TargetHandler=null;';
  2342. // Constructor
  2343. $php[]='public function PhpWsdlHandler($server,$targetHandler){';
  2344. $php[]='$this->_Server=$server;';
  2345. $php[]='$this->_TargetHandler=$targetHandler;';
  2346. $php[]='}';
  2347. // Caller method
  2348. $php[]='public function _Call($method,$param){';
  2349. $php[]='$obj=null;';
  2350. $php[]='$m=$this->_Server->GetMethod($method);';
  2351. $php[]='if(!$m->IsGlobal) $obj=(is_null($m->Class))?$this->_TargetHandler:$m->Class;';
  2352. $php[]='$call=(is_null($obj))?$m->Name:Array($obj,$m->Name);';
  2353. $php[]='return call_user_func_array($call,$param);';
  2354. $php[]='}';
  2355. // Webservice methods
  2356. $i=-1;
  2357. $len=sizeof($this->Methods);
  2358. while(++$i<$len){
  2359. $m=$this->Methods[$i];
  2360. $temp=Array();
  2361. $j=-1;
  2362. $pLen=sizeof($m->Param);
  2363. while(++$j<$pLen)
  2364. $temp[]='$'.$m->Param[$j]->Name;
  2365. $temp=implode(',',$temp);
  2366. $php[]='public function '.$m->Name.'('.$temp.'){';
  2367. $php[]='return $this->_Call("'.$m->Name.'",Array('.$temp.'));';
  2368. $php[]='}';
  2369. }
  2370. $php[]='}';
  2371. $php=implode("\n",$php);
  2372. $this->HandlerPhp=$php;
  2373. $this->WriteWsdlToCache(null,null,null,true);
  2374. }else{
  2375. $php=$this->HandlerPhp;
  2376. }
  2377. eval($php);
  2378. $this->Handler=new PhpWsdlHandler($this,$targetHandler);
  2379. self::Debug('Handler object created');
  2380. return $this->Handler;
  2381. }
  2382. /**
  2383. * Translate a type name for WSDL
  2384. *
  2385. * @param string $type The type name
  2386. * @return string The translated type name
  2387. */
  2388. public static function TranslateType($type){
  2389. if(!self::CallHook(
  2390. 'TranslateTypeHook',
  2391. Array(
  2392. 'type' => &$type
  2393. )
  2394. )
  2395. )
  2396. return $type;
  2397. return ((in_array($type,self::$BasicTypes))?self::$Config['xsd']:self::$Config['tns']).':'.$type;
  2398. }
  2399. /**
  2400. * Translate a target type name for WSDL
  2401. *
  2402. * @param string $type The type name
  2403. * @return string The translated target type name
  2404. */
  2405. public function TranslateTargetType($type){
  2406. if(!self::CallHook(
  2407. 'TranslateTargetTypeHook',
  2408. Array(
  2409. 'type' => &$type
  2410. )
  2411. )
  2412. )
  2413. return $type;
  2414. if(in_array($type,self::$BasicTypes))
  2415. return self::TranslateType($type);
  2416. $t=$this->GetType($type);
  2417. if(is_null($t))
  2418. return self::TranslateType($type);
  2419. switch(get_class($t)){
  2420. case 'PhpWsdlEnum':
  2421. return self::TranslateType($t->Type);
  2422. break;
  2423. default:
  2424. return self::TranslateType($type);
  2425. break;
  2426. }
  2427. }
  2428. /**
  2429. * Call a hook function
  2430. *
  2431. * @param string $name The hook name
  2432. * @param mixed $data The parameter (default: NULL)
  2433. * @return boolean Response
  2434. */
  2435. public static function CallHook($name,$data=null){
  2436. self::Debug('Call hook '.$name);
  2437. if(!self::HasHookHandler($name))
  2438. return true;
  2439. $keys=array_keys(self::$Config['extensions'][$name]);
  2440. $i=-1;
  2441. $len=sizeof($keys);
  2442. while(++$i<$len){
  2443. $fnc=self::$Config['extensions'][$name][$keys[$i]];
  2444. self::Debug('Call '.$fnc);
  2445. if(is_string($fnc)&&strpos($fnc,'::')>-1) $fnc=explode('::',$fnc);
  2446. if(!call_user_func($fnc,$data)){
  2447. self::Debug('Handler stopped hook execution');
  2448. return false;
  2449. }
  2450. }
  2451. return true;
  2452. }
  2453. /**
  2454. * Register a hook
  2455. *
  2456. * @param string $hook The hook name
  2457. * @param string $name The call name
  2458. * @param mixed $data The hook call data
  2459. */
  2460. public static function RegisterHook($hook,$name,$data){
  2461. if(!self::HasHookHandler($hook))
  2462. self::$Config['extensions'][$hook]=Array();
  2463. if(self::$Debugging){
  2464. $handler=$data;
  2465. if(is_array($handler)){
  2466. $class=$handler[0];
  2467. $method=$handler[1];
  2468. if(is_object($class))
  2469. $class=get_class($class);
  2470. $handler=$class.'.'.$method;
  2471. }
  2472. self::Debug('Register hook '.$hook.' handler '.$name.': '.$handler);
  2473. }
  2474. self::$Config['extensions'][$hook][$name]=$data;
  2475. }
  2476. /**
  2477. * Unregister a hook
  2478. *
  2479. * @param string $hook The hook name
  2480. * @param string $name The call name or NULL to unregister the whole hook
  2481. */
  2482. public static function UnregisterHook($hook,$name=null){
  2483. if(!self::HasHookHandler($hook))
  2484. return;
  2485. if(!is_null($name)){
  2486. if(!isset(self::$Config['extensions'][$hook][$name]))
  2487. return;
  2488. }else{
  2489. unset(self::$Config['extensions'][$hook]);
  2490. return;
  2491. }
  2492. unset(self::$Config['extensions'][$hook][$name]);
  2493. if(self::$Debugging)
  2494. self::Debug('Unregister hook '.$hook.' handler '.$name);
  2495. if(sizeof(self::$Config['extensions'][$hook])<1)
  2496. unset(self::$Config['extensions'][$hook]);
  2497. }
  2498. /**
  2499. * Determine if a hook has a registered handler
  2500. *
  2501. * @param string $hook The hook name
  2502. * @return boolean Has handler?
  2503. */
  2504. public static function HasHookHandler($hook){
  2505. return isset(self::$Config['extensions'][$hook]);
  2506. }
  2507. /**
  2508. * Get the encoding data for a type
  2509. *
  2510. * @param string $type The type name
  2511. * @param boolean $parameter Get the parameter definition? (default: FALSE)
  2512. * @param boolean $defaults Fall back to defaults? (default: TRUE)
  2513. * @param PhpWsdl $server The PhpWsdl object (default: NULL)
  2514. * @return array The encoding data or NULL, if not found
  2515. */
  2516. public static function GetEncoding($type,$parameter=false,$defaults=true,$server=null){
  2517. if($parameter){
  2518. if(isset(self::$TypeEncoding['parameter'][$type]))
  2519. return self::$TypeEncoding['parameter'][$type];
  2520. }else{
  2521. if(isset(self::$TypeEncoding['return'][$type]))
  2522. return self::$TypeEncoding['return'][$type];
  2523. }
  2524. if(!in_array($type,self::$BasicTypes)){
  2525. $t=null;
  2526. if(!is_null($server))
  2527. $t=$server->GetType($type);
  2528. return Array(
  2529. 'encoding' => (is_null($t)||!$t->IsArray)?SOAP_ENC_OBJECT:SOAP_ENC_ARRAY
  2530. );
  2531. }
  2532. if(!$defaults)
  2533. return null;
  2534. return (isset(self::$TypeEncoding['default'][$type]))
  2535. ?self::$TypeEncoding['default'][$type]
  2536. :null;
  2537. }
  2538. /**
  2539. * Set the SOAP encoding for a type
  2540. *
  2541. * @param string $type The type name
  2542. * @param string|int $encoding The SOAP encoding
  2543. * @param boolean $parameter Set the parameter definition? (default: FALSE)
  2544. */
  2545. public static function SetEncoding($type,$encoding,$parameter=false){
  2546. self::$TypeEncoding[($parameter)?'parameter':'return'][$type]=Array(
  2547. 'encoding' => $encoding
  2548. );
  2549. }
  2550. /**
  2551. * Encode some data for SOAP
  2552. *
  2553. * @param string $type The type name
  2554. * @param mixed $data The data to be encoded
  2555. * @param boolean $parameter Get the parameter definition? (default: FALSE)
  2556. * @param PhpWsdl $server The PhpWsdl object (default: NULL)
  2557. * @return mixed|SoapVar The SoapVar object
  2558. */
  2559. public static function DoEncoding($type,$data,$parameter=false,$server=null){
  2560. $res=null;
  2561. if(!self::CallHook(
  2562. 'EncodeHook',
  2563. Array(
  2564. 'server' => &$server,
  2565. 'type' => &$type,
  2566. 'data' => &$data,
  2567. 'parameter' => &$parameter,
  2568. 'res' => &$res
  2569. )
  2570. )
  2571. )
  2572. return $res;
  2573. if(!self::CallHook(
  2574. 'Encode'.$type.'Hook',
  2575. Array(
  2576. 'server' => &$server,
  2577. 'type' => &$type,
  2578. 'data' => &$data,
  2579. 'parameter' => &$parameter,
  2580. 'res' => &$res
  2581. )
  2582. )
  2583. )
  2584. return $res;
  2585. $t=null;
  2586. if(!is_null($server)&&!in_array($type,self::$BasicTypes)){
  2587. $t=$server->GetType($type);
  2588. if(get_class($t)=='PhpWsdlEnum')
  2589. if(!in_array($t->Type,self::$BasicTypes)){
  2590. $t=$server->GetType($t->Type);
  2591. }else{
  2592. $type=$t->Type;
  2593. $t=null;
  2594. }
  2595. }
  2596. $enc=self::GetEncoding($type,$parameter,true,$server);
  2597. if(is_null($enc))
  2598. $enc=Array(
  2599. 'encoding' => (is_null($t)||!$t->IsArray)?SOAP_ENC_OBJECT:SOAP_ENC_ARRAY
  2600. );
  2601. if(!is_null($server))
  2602. $enc['ns']=$server->NameSpace;
  2603. if(isset($enc['ns']))
  2604. return new SoapVar($data,$enc['encoding'],$type,$enc['ns']);
  2605. return new SoapVar($data,$enc['encoding']);
  2606. }
  2607. /**
  2608. * Add a debugging message
  2609. *
  2610. * @param string $str The message to add to the debug protocol
  2611. */
  2612. public static function Debug($str){
  2613. if(!self::$Debugging)
  2614. return;
  2615. if(!is_null(self::$DebugHandler)){
  2616. call_user_func(self::$DebugHandler,$str);
  2617. return;
  2618. }
  2619. $temp=date('Y-m-d H:i:s')."\t".$str;
  2620. if(self::$DebugBackTrace){
  2621. $trace=debug_backtrace();
  2622. $temp.=" ('".$trace[1]['function']."' in '".basename($trace[1]['file'])."' at line #".$trace[1]['line'].")";
  2623. }
  2624. self::$DebugInfo[]=$temp;
  2625. if(!is_null(self::$DebugFile))
  2626. if(file_put_contents(self::$DebugFile,$temp."\n",FILE_APPEND)===false){
  2627. $temp=self::$DebugFile;
  2628. self::$DebugFile=null;
  2629. self::Debug('Could not write to debug file "'.$temp.'"');
  2630. }
  2631. }
  2632. /**
  2633. * Initialize PhpWsdl
  2634. */
  2635. public static function Init(){
  2636. self::Debug('Init');
  2637. // Configuration
  2638. self::$HTML2PDFSettings=Array(
  2639. 'attachments' => '1',
  2640. 'outline' => '1'
  2641. );
  2642. self::$NameSpaces=Array(
  2643. 'soap' => 'http://schemas.xmlsoap.org/wsdl/soap/',
  2644. 's' => 'http://www.w3.org/2001/XMLSchema',
  2645. 'wsdl' => 'http://schemas.xmlsoap.org/wsdl/',
  2646. 'soapenc' => 'http://schemas.xmlsoap.org/soap/encoding/'
  2647. );
  2648. //TODO How to encode the missing basic types?
  2649. self::$TypeEncoding=Array(
  2650. 'parameter' => Array(),
  2651. 'return' => Array(),
  2652. 'default' => Array(
  2653. 'string' => Array(
  2654. 'encoding' => XSD_STRING
  2655. ),
  2656. 'boolean' => Array(
  2657. 'encoding' => XSD_BOOLEAN
  2658. ),
  2659. 'decimal' => Array(
  2660. 'encoding' => XSD_DECIMAL
  2661. ),
  2662. 'float' => Array(
  2663. 'encoding' => XSD_FLOAT
  2664. ),
  2665. 'double' => Array(
  2666. 'encoding' => XSD_DOUBLE
  2667. ),
  2668. 'duration' => Array(
  2669. 'encoding' => XSD_DURATION
  2670. ),
  2671. 'dateTime' => Array(
  2672. 'encoding' => XSD_DATETIME
  2673. ),
  2674. 'time' => Array(
  2675. 'encoding' => XSD_TIME
  2676. ),
  2677. 'date' => Array(
  2678. 'encoding' => XSD_DATE
  2679. ),
  2680. 'gYearMonth' => Array(
  2681. 'encoding' => XSD_GYEARMONTH
  2682. ),
  2683. 'gYear' => Array(
  2684. 'encoding' => XSD_GYEAR
  2685. ),
  2686. 'gMonthDay' => Array(
  2687. 'encoding' => XSD_GMONTHDAY
  2688. ),
  2689. 'gDay' => Array(
  2690. 'encoding' => XSD_GDAY
  2691. ),
  2692. 'gMonth' => Array(
  2693. 'encoding' => XSD_GMONTH
  2694. ),
  2695. 'hexBinary' => Array(
  2696. 'encoding' => XSD_HEXBINARY
  2697. ),
  2698. 'base64Binary' => Array(
  2699. 'encoding' => XSD_BASE64BINARY
  2700. ),
  2701. 'anyURI' => Array(
  2702. 'encoding' => XSD_ANYURI
  2703. ),
  2704. 'QName' => Array(
  2705. 'encoding' => XSD_QNAME
  2706. ),
  2707. 'NOTATION' => Array(
  2708. 'encoding' => XSD_NOTATION
  2709. ),
  2710. 'int' => Array(
  2711. 'encoding' => XSD_INT
  2712. ),
  2713. 'integer' => Array(
  2714. 'encoding' => XSD_INTEGER
  2715. ),
  2716. 'long' => Array(
  2717. 'encoding' => XSD_LONG
  2718. ),
  2719. 'short' => Array(
  2720. 'encoding' => XSD_SHORT
  2721. ),
  2722. 'byte' => Array(
  2723. 'encoding' => XSD_BYTE
  2724. ),
  2725. 'anyType' => Array(
  2726. 'encoding' => XSD_ANYTYPE
  2727. )
  2728. )
  2729. );
  2730. self::EnableCache();
  2731. self::$Config['extensions']=Array();// A configuration space for extensions
  2732. self::$Config['tns']='tns'; // The xmlns name for the target namespace
  2733. self::$Config['xsd']='s'; // The xmlns name for the XSD namespace
  2734. // Parser hooks
  2735. self::RegisterHook('InterpretKeywordserviceHook','internal','PhpWsdl::InterpretService');
  2736. self::RegisterHook('InterpretKeywordpw_setHook','internal','PhpWsdl::InterpretSetting');
  2737. // WSDL hooks
  2738. self::RegisterHook('CreateWsdlHeaderHook','internal','PhpWsdl::CreateWsdlHeader');
  2739. self::RegisterHook('CreateWsdlTypeSchemaHook','internal','PhpWsdl::CreateWsdlTypeSchema');
  2740. self::RegisterHook('CreateWsdlMessagesHook','internal','PhpWsdl::CreateWsdlMessages');
  2741. self::RegisterHook('CreateWsdlPortsHook','internal','PhpWsdl::CreateWsdlPorts');
  2742. self::RegisterHook('CreateWsdlBindingsHook','internal','PhpWsdl::CreateWsdlBindings');
  2743. self::RegisterHook('CreateWsdlServiceHook','internal','PhpWsdl::CreateWsdlService');
  2744. self::RegisterHook('CreateWsdlFooterHook','internal','PhpWsdl::CreateWsdlFooter');
  2745. self::RegisterHook('CreateWsdlOptimizeHook','internal','PhpWsdl::CreateWsdlOptimize');
  2746. // HTML hooks
  2747. self::RegisterHook('CreateHtmlGeneralHook','internal','PhpWsdl::CreateHtmlGeneral');
  2748. self::RegisterHook('CreateHtmlIndexHook','internal','PhpWsdl::CreateHtmlIndex');
  2749. self::RegisterHook('CreateHtmlMethodsHook','internal','PhpWsdl::CreateHtmlMethods');
  2750. self::RegisterHook('CreateHtmlComplexTypesHook','internal','PhpWsdl::CreateHtmlComplexTypes');
  2751. // Extensions
  2752. self::Debug('Load extensions');
  2753. $files=glob(dirname(__FILE__).'/'.'class.phpwsdl.*.php');
  2754. if($files!==false){
  2755. $i=-1;
  2756. $len=sizeof($files);
  2757. while(++$i<$len){
  2758. self::Debug('Load '.$files[$i]);
  2759. require_once($files[$i]);
  2760. }
  2761. }else{
  2762. self::Debug('"glob" failed');
  2763. }
  2764. }
  2765. /**
  2766. * Do things after the environment is configured
  2767. */
  2768. public static function PostInit(){
  2769. self::CallHook('PostInitHook');
  2770. // Autorun
  2771. global $PhpWsdlAutoRun;
  2772. if(self::$AutoRun||$PhpWsdlAutoRun)
  2773. self::RunQuickMode();
  2774. }
  2775. }