PageRenderTime 64ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/class.phpwsdl.php

http://php-wsdl-creator.googlecode.com/
PHP | 2853 lines | 1944 code | 75 blank | 834 comment | 240 complexity | 4f8fbaee998d7112dce3b6758a246c4c MD5 | raw file
Possible License(s): GPL-3.0

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

  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;

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