AutoDiscover.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Soap
  17. * @subpackage AutoDiscover
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /**
  23. * @see Zend_Server_Interface
  24. */
  25. #require_once 'Zend/Server/Interface.php';
  26. /**
  27. * @see Zend_Soap_Wsdl
  28. */
  29. #require_once 'Zend/Soap/Wsdl.php';
  30. /**
  31. * @see Zend_Server_Reflection
  32. */
  33. #require_once 'Zend/Server/Reflection.php';
  34. /**
  35. * @see Zend_Server_Abstract
  36. */
  37. #require_once 'Zend/Server/Abstract.php';
  38. /**
  39. * @see Zend_Uri
  40. */
  41. #require_once 'Zend/Uri.php';
  42. /**
  43. * Zend_Soap_AutoDiscover
  44. *
  45. * @category Zend
  46. * @package Zend_Soap
  47. * @subpackage AutoDiscover
  48. */
  49. class Zend_Soap_AutoDiscover implements Zend_Server_Interface
  50. {
  51. /**
  52. * @var Zend_Soap_Wsdl
  53. */
  54. protected $_wsdl = null;
  55. /**
  56. * @var Zend_Server_Reflection
  57. */
  58. protected $_reflection = null;
  59. /**
  60. * @var array
  61. */
  62. protected $_functions = array();
  63. /**
  64. * @var boolean
  65. */
  66. protected $_strategy;
  67. /**
  68. * Url where the WSDL file will be available at.
  69. *
  70. * @var WSDL Uri
  71. */
  72. protected $_uri;
  73. /**
  74. * soap:body operation style options
  75. *
  76. * @var array
  77. */
  78. protected $_operationBodyStyle = array('use' => 'encoded', 'encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/");
  79. /**
  80. * soap:operation style
  81. *
  82. * @var array
  83. */
  84. protected $_bindingStyle = array('style' => 'rpc', 'transport' => 'http://schemas.xmlsoap.org/soap/http');
  85. /**
  86. * Name of the class to handle the WSDL creation.
  87. *
  88. * @var string
  89. */
  90. protected $_wsdlClass = 'Zend_Soap_Wsdl';
  91. /**
  92. * Constructor
  93. *
  94. * @param boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
  95. * @param string|Zend_Uri $uri
  96. * @param string $wsdlClass
  97. */
  98. public function __construct($strategy = true, $uri=null, $wsdlClass=null)
  99. {
  100. $this->_reflection = new Zend_Server_Reflection();
  101. $this->setComplexTypeStrategy($strategy);
  102. if($uri !== null) {
  103. $this->setUri($uri);
  104. }
  105. if($wsdlClass !== null) {
  106. $this->setWsdlClass($wsdlClass);
  107. }
  108. }
  109. /**
  110. * Set the location at which the WSDL file will be availabe.
  111. *
  112. * @see Zend_Soap_Exception
  113. * @param Zend_Uri|string $uri
  114. * @return Zend_Soap_AutoDiscover
  115. * @throws Zend_Soap_AutoDiscover_Exception
  116. */
  117. public function setUri($uri)
  118. {
  119. if (!is_string($uri) && !($uri instanceof Zend_Uri)) {
  120. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  121. throw new Zend_Soap_AutoDiscover_Exception("No uri given to Zend_Soap_AutoDiscover::setUri as string or Zend_Uri instance.");
  122. }
  123. $this->_uri = $uri;
  124. // change uri in WSDL file also if existant
  125. if ($this->_wsdl instanceof Zend_Soap_Wsdl) {
  126. $this->_wsdl->setUri($uri);
  127. }
  128. return $this;
  129. }
  130. /**
  131. * Return the current Uri that the SOAP WSDL Service will be located at.
  132. *
  133. * @return Zend_Uri
  134. */
  135. public function getUri()
  136. {
  137. if($this->_uri !== null) {
  138. $uri = $this->_uri;
  139. } else {
  140. $schema = $this->getSchema();
  141. $host = $this->getHostName();
  142. $scriptName = $this->getRequestUriWithoutParameters();
  143. $uri = Zend_Uri::factory($schema . '://' . $host . $scriptName);
  144. $this->setUri($uri);
  145. }
  146. return $uri;
  147. }
  148. /**
  149. * Set the name of the WSDL handling class.
  150. *
  151. * @see Zend_Soap_Exception
  152. * @see Zend_Soap_Exception
  153. * @param string $wsdlClass
  154. * @return Zend_Soap_AutoDiscover
  155. * @throws Zend_Soap_AutoDiscover_Exception
  156. */
  157. public function setWsdlClass($wsdlClass)
  158. {
  159. if (!is_string($wsdlClass) && !is_subclass_of($wsdlClass, 'Zend_Soap_Wsdl')) {
  160. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  161. throw new Zend_Soap_AutoDiscover_Exception("No Zend_Soap_Wsdl subclass given to Zend_Soap_AutoDiscover::setWsdlClass as string.");
  162. }
  163. $this->_wsdlClass = $wsdlClass;
  164. return $this;
  165. }
  166. /**
  167. * Return the name of the WSDL handling class.
  168. *
  169. * @return string
  170. */
  171. public function getWsdlClass()
  172. {
  173. return $this->_wsdlClass;
  174. }
  175. /**
  176. * Set options for all the binding operations soap:body elements.
  177. *
  178. * By default the options are set to 'use' => 'encoded' and
  179. * 'encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/".
  180. *
  181. * @see Zend_Soap_AutoDiscover_Exception
  182. * @param array $operationStyle
  183. * @return Zend_Soap_AutoDiscover
  184. * @throws Zend_Soap_AutoDiscover_Exception
  185. */
  186. public function setOperationBodyStyle(array $operationStyle=array())
  187. {
  188. if(!isset($operationStyle['use'])) {
  189. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  190. throw new Zend_Soap_AutoDiscover_Exception("Key 'use' is required in Operation soap:body style.");
  191. }
  192. $this->_operationBodyStyle = $operationStyle;
  193. return $this;
  194. }
  195. /**
  196. * Set Binding soap:binding style.
  197. *
  198. * By default 'style' is 'rpc' and 'transport' is 'http://schemas.xmlsoap.org/soap/http'.
  199. *
  200. * @param array $bindingStyle
  201. * @return Zend_Soap_AutoDiscover
  202. */
  203. public function setBindingStyle(array $bindingStyle=array())
  204. {
  205. if(isset($bindingStyle['style'])) {
  206. $this->_bindingStyle['style'] = $bindingStyle['style'];
  207. }
  208. if(isset($bindingStyle['transport'])) {
  209. $this->_bindingStyle['transport'] = $bindingStyle['transport'];
  210. }
  211. return $this;
  212. }
  213. /**
  214. * Detect and returns the current HTTP/HTTPS Schema
  215. *
  216. * @return string
  217. */
  218. protected function getSchema()
  219. {
  220. $schema = "http";
  221. if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
  222. $schema = 'https';
  223. }
  224. return $schema;
  225. }
  226. /**
  227. * Detect and return the current hostname
  228. *
  229. * @return string
  230. */
  231. protected function getHostName()
  232. {
  233. if(isset($_SERVER['HTTP_HOST'])) {
  234. $host = $_SERVER['HTTP_HOST'];
  235. } else {
  236. $host = $_SERVER['SERVER_NAME'];
  237. }
  238. return $host;
  239. }
  240. /**
  241. * Detect and return the current script name without parameters
  242. *
  243. * @return string
  244. */
  245. protected function getRequestUriWithoutParameters()
  246. {
  247. if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { // IIS with Microsoft Rewrite Module
  248. $requestUri = $_SERVER['HTTP_X_ORIGINAL_URL'];
  249. } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
  250. $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
  251. } elseif (isset($_SERVER['REQUEST_URI'])) {
  252. $requestUri = $_SERVER['REQUEST_URI'];
  253. } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
  254. $requestUri = $_SERVER['ORIG_PATH_INFO'];
  255. } else {
  256. $requestUri = $_SERVER['SCRIPT_NAME'];
  257. }
  258. if( ($pos = strpos($requestUri, "?")) !== false) {
  259. $requestUri = substr($requestUri, 0, $pos);
  260. }
  261. return $requestUri;
  262. }
  263. /**
  264. * Set the strategy that handles functions and classes that are added AFTER this call.
  265. *
  266. * @param boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
  267. * @return Zend_Soap_AutoDiscover
  268. */
  269. public function setComplexTypeStrategy($strategy)
  270. {
  271. $this->_strategy = $strategy;
  272. if($this->_wsdl instanceof Zend_Soap_Wsdl) {
  273. $this->_wsdl->setComplexTypeStrategy($strategy);
  274. }
  275. return $this;
  276. }
  277. /**
  278. * Set the Class the SOAP server will use
  279. *
  280. * @param string $class Class Name
  281. * @param string $namespace Class Namspace - Not Used
  282. * @param array $argv Arguments to instantiate the class - Not Used
  283. * @return Zend_Soap_AutoDiscover
  284. */
  285. public function setClass($class, $namespace = '', $argv = null)
  286. {
  287. $uri = $this->getUri();
  288. $wsdl = new $this->_wsdlClass($class, $uri, $this->_strategy);
  289. // The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
  290. $wsdl->addSchemaTypeSection();
  291. $port = $wsdl->addPortType($class . 'Port');
  292. $binding = $wsdl->addBinding($class . 'Binding', 'tns:' .$class. 'Port');
  293. $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
  294. $wsdl->addService($class . 'Service', $class . 'Port', 'tns:' . $class . 'Binding', $uri);
  295. foreach ($this->_reflection->reflectClass($class)->getMethods() as $method) {
  296. $this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
  297. }
  298. $this->_wsdl = $wsdl;
  299. return $this;
  300. }
  301. /**
  302. * Add a Single or Multiple Functions to the WSDL
  303. *
  304. * @param string $function Function Name
  305. * @param string $namespace Function namespace - Not Used
  306. * @return Zend_Soap_AutoDiscover
  307. */
  308. public function addFunction($function, $namespace = '')
  309. {
  310. static $port;
  311. static $operation;
  312. static $binding;
  313. if (!is_array($function)) {
  314. $function = (array) $function;
  315. }
  316. $uri = $this->getUri();
  317. if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
  318. $parts = explode('.', basename($_SERVER['SCRIPT_NAME']));
  319. $name = $parts[0];
  320. $wsdl = new Zend_Soap_Wsdl($name, $uri, $this->_strategy);
  321. // The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
  322. $wsdl->addSchemaTypeSection();
  323. $port = $wsdl->addPortType($name . 'Port');
  324. $binding = $wsdl->addBinding($name . 'Binding', 'tns:' .$name. 'Port');
  325. $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
  326. $wsdl->addService($name . 'Service', $name . 'Port', 'tns:' . $name . 'Binding', $uri);
  327. } else {
  328. $wsdl = $this->_wsdl;
  329. }
  330. foreach ($function as $func) {
  331. $method = $this->_reflection->reflectFunction($func);
  332. $this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
  333. }
  334. $this->_wsdl = $wsdl;
  335. return $this;
  336. }
  337. /**
  338. * Add a function to the WSDL document.
  339. *
  340. * @param Zend_Server_Reflection_Function_Abstract $function function to add
  341. * @param Zend_Soap_Wsdl $wsdl WSDL document
  342. * @param object $port wsdl:portType
  343. * @param object $binding wsdl:binding
  344. * @return void
  345. */
  346. protected function _addFunctionToWsdl($function, $wsdl, $port, $binding)
  347. {
  348. $uri = $this->getUri();
  349. // We only support one prototype: the one with the maximum number of arguments
  350. $prototype = null;
  351. $maxNumArgumentsOfPrototype = -1;
  352. foreach ($function->getPrototypes() as $tmpPrototype) {
  353. $numParams = count($tmpPrototype->getParameters());
  354. if ($numParams > $maxNumArgumentsOfPrototype) {
  355. $maxNumArgumentsOfPrototype = $numParams;
  356. $prototype = $tmpPrototype;
  357. }
  358. }
  359. if ($prototype === null) {
  360. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  361. throw new Zend_Soap_AutoDiscover_Exception("No prototypes could be found for the '" . $function->getName() . "' function");
  362. }
  363. // Add the input message (parameters)
  364. $args = array();
  365. if ($this->_bindingStyle['style'] == 'document') {
  366. // Document style: wrap all parameters in a sequence element
  367. $sequence = array();
  368. foreach ($prototype->getParameters() as $param) {
  369. $sequenceElement = array(
  370. 'name' => $param->getName(),
  371. 'type' => $wsdl->getType($param->getType())
  372. );
  373. if ($param->isOptional()) {
  374. $sequenceElement['nillable'] = 'true';
  375. }
  376. $sequence[] = $sequenceElement;
  377. }
  378. $element = array(
  379. 'name' => $function->getName(),
  380. 'sequence' => $sequence
  381. );
  382. // Add the wrapper element part, which must be named 'parameters'
  383. $args['parameters'] = array('element' => $wsdl->addElement($element));
  384. } else {
  385. // RPC style: add each parameter as a typed part
  386. foreach ($prototype->getParameters() as $param) {
  387. $args[$param->getName()] = array('type' => $wsdl->getType($param->getType()));
  388. }
  389. }
  390. $wsdl->addMessage($function->getName() . 'In', $args);
  391. $isOneWayMessage = false;
  392. if($prototype->getReturnType() == "void") {
  393. $isOneWayMessage = true;
  394. }
  395. if($isOneWayMessage == false) {
  396. // Add the output message (return value)
  397. $args = array();
  398. if ($this->_bindingStyle['style'] == 'document') {
  399. // Document style: wrap the return value in a sequence element
  400. $sequence = array();
  401. if ($prototype->getReturnType() != "void") {
  402. $sequence[] = array(
  403. 'name' => $function->getName() . 'Result',
  404. 'type' => $wsdl->getType($prototype->getReturnType())
  405. );
  406. }
  407. $element = array(
  408. 'name' => $function->getName() . 'Response',
  409. 'sequence' => $sequence
  410. );
  411. // Add the wrapper element part, which must be named 'parameters'
  412. $args['parameters'] = array('element' => $wsdl->addElement($element));
  413. } else if ($prototype->getReturnType() != "void") {
  414. // RPC style: add the return value as a typed part
  415. $args['return'] = array('type' => $wsdl->getType($prototype->getReturnType()));
  416. }
  417. $wsdl->addMessage($function->getName() . 'Out', $args);
  418. }
  419. // Add the portType operation
  420. if($isOneWayMessage == false) {
  421. $portOperation = $wsdl->addPortOperation($port, $function->getName(), 'tns:' . $function->getName() . 'In', 'tns:' . $function->getName() . 'Out');
  422. } else {
  423. $portOperation = $wsdl->addPortOperation($port, $function->getName(), 'tns:' . $function->getName() . 'In', false);
  424. }
  425. $desc = $function->getDescription();
  426. if (strlen($desc) > 0) {
  427. $wsdl->addDocumentation($portOperation, $desc);
  428. }
  429. // When using the RPC style, make sure the operation style includes a 'namespace' attribute (WS-I Basic Profile 1.1 R2717)
  430. if ($this->_bindingStyle['style'] == 'rpc' && !isset($this->_operationBodyStyle['namespace'])) {
  431. $this->_operationBodyStyle['namespace'] = ''.$uri;
  432. }
  433. // Add the binding operation
  434. if($isOneWayMessage == false) {
  435. $operation = $wsdl->addBindingOperation($binding, $function->getName(), $this->_operationBodyStyle, $this->_operationBodyStyle);
  436. } else {
  437. $operation = $wsdl->addBindingOperation($binding, $function->getName(), $this->_operationBodyStyle);
  438. }
  439. $wsdl->addSoapOperation($operation, $uri . '#' .$function->getName());
  440. // Add the function name to the list
  441. $this->_functions[] = $function->getName();
  442. }
  443. /**
  444. * Action to take when an error occurs
  445. *
  446. * @param string $fault
  447. * @param string|int $code
  448. * @throws Zend_Soap_AutoDiscover_Exception
  449. */
  450. public function fault($fault = null, $code = null)
  451. {
  452. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  453. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  454. }
  455. /**
  456. * Handle the Request
  457. *
  458. * @param string $request A non-standard request - Not Used
  459. */
  460. public function handle($request = false)
  461. {
  462. if (!headers_sent()) {
  463. header('Content-Type: text/xml');
  464. }
  465. $this->_wsdl->dump();
  466. }
  467. /**
  468. * Proxy to WSDL dump function
  469. *
  470. * @param string $filename
  471. * @return boolean
  472. * @throws Zend_Soap_AutoDiscover_Exception
  473. */
  474. public function dump($filename)
  475. {
  476. if($this->_wsdl !== null) {
  477. return $this->_wsdl->dump($filename);
  478. } else {
  479. /**
  480. * @see Zend_Soap_AutoDiscover_Exception
  481. */
  482. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  483. throw new Zend_Soap_AutoDiscover_Exception("Cannot dump autodiscovered contents, WSDL file has not been generated yet.");
  484. }
  485. }
  486. /**
  487. * Proxy to WSDL toXml() function
  488. *
  489. * @return string
  490. * @throws Zend_Soap_AutoDiscover_Exception
  491. */
  492. public function toXml()
  493. {
  494. if($this->_wsdl !== null) {
  495. return $this->_wsdl->toXml();
  496. } else {
  497. /**
  498. * @see Zend_Soap_AutoDiscover_Exception
  499. */
  500. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  501. throw new Zend_Soap_AutoDiscover_Exception("Cannot return autodiscovered contents, WSDL file has not been generated yet.");
  502. }
  503. }
  504. /**
  505. * Return an array of functions in the WSDL
  506. *
  507. * @return array
  508. */
  509. public function getFunctions()
  510. {
  511. return $this->_functions;
  512. }
  513. /**
  514. * Load Functions
  515. *
  516. * @param unknown_type $definition
  517. * @throws Zend_Soap_AutoDiscover_Exception
  518. */
  519. public function loadFunctions($definition)
  520. {
  521. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  522. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  523. }
  524. /**
  525. * Set Persistance
  526. *
  527. * @param int $mode
  528. * @throws Zend_Soap_AutoDiscover_Exception
  529. */
  530. public function setPersistence($mode)
  531. {
  532. #require_once "Zend/Soap/AutoDiscover/Exception.php";
  533. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  534. }
  535. /**
  536. * Returns an XSD Type for the given PHP type
  537. *
  538. * @param string $type PHP Type to get the XSD type for
  539. * @return string
  540. */
  541. public function getType($type)
  542. {
  543. if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
  544. /** @todo Exception throwing may be more correct */
  545. // WSDL is not defined yet, so we can't recognize type in context of current service
  546. return '';
  547. } else {
  548. return $this->_wsdl->getType($type);
  549. }
  550. }
  551. }