2
0

AutoDiscover.php 17 KB

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