PageRenderTime 68ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

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

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