AutoDiscover.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. $port = $wsdl->addPortType($class . 'Port');
  233. $binding = $wsdl->addBinding($class . 'Binding', 'tns:' .$class. 'Port');
  234. $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
  235. $wsdl->addService($class . 'Service', $class . 'Port', 'tns:' . $class . 'Binding', $uri);
  236. foreach ($this->_reflection->reflectClass($class)->getMethods() as $method) {
  237. /* <wsdl:portType>'s */
  238. $portOperation = $wsdl->addPortOperation($port, $method->getName(), 'tns:' .$method->getName(). 'Request', 'tns:' .$method->getName(). 'Response');
  239. $desc = $method->getDescription();
  240. if (strlen($desc) > 0) {
  241. /** @todo check, what should be done for portoperation documentation */
  242. //$wsdl->addDocumentation($portOperation, $desc);
  243. }
  244. /* </wsdl:portType>'s */
  245. $this->_functions[] = $method->getName();
  246. $selectedPrototype = null;
  247. $maxNumArgumentsOfPrototype = -1;
  248. foreach ($method->getPrototypes() as $prototype) {
  249. $numParams = count($prototype->getParameters());
  250. if($numParams > $maxNumArgumentsOfPrototype) {
  251. $maxNumArgumentsOfPrototype = $numParams;
  252. $selectedPrototype = $prototype;
  253. }
  254. }
  255. if($selectedPrototype != null) {
  256. $prototype = $selectedPrototype;
  257. $args = array();
  258. foreach($prototype->getParameters() as $param) {
  259. $args[$param->getName()] = $wsdl->getType($param->getType());
  260. }
  261. $message = $wsdl->addMessage($method->getName() . 'Request', $args);
  262. if (strlen($desc) > 0) {
  263. //$wsdl->addDocumentation($message, $desc);
  264. }
  265. if ($prototype->getReturnType() != "void") {
  266. $returnName = 'return';
  267. $message = $wsdl->addMessage($method->getName() . 'Response', array($returnName => $wsdl->getType($prototype->getReturnType())));
  268. }
  269. /* <wsdl:binding>'s */
  270. $operation = $wsdl->addBindingOperation($binding, $method->getName(), $this->_operationBodyStyle, $this->_operationBodyStyle);
  271. $wsdl->addSoapOperation($operation, $uri . '#' .$method->getName());
  272. /* </wsdl:binding>'s */
  273. }
  274. }
  275. $this->_wsdl = $wsdl;
  276. }
  277. /**
  278. * Add a Single or Multiple Functions to the WSDL
  279. *
  280. * @param string $function Function Name
  281. * @param string $namespace Function namespace - Not Used
  282. */
  283. public function addFunction($function, $namespace = '')
  284. {
  285. static $port;
  286. static $operation;
  287. static $binding;
  288. if (!is_array($function)) {
  289. $function = (array) $function;
  290. }
  291. $uri = $this->getUri();
  292. if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
  293. $parts = explode('.', basename($_SERVER['SCRIPT_NAME']));
  294. $name = $parts[0];
  295. $wsdl = new Zend_Soap_Wsdl($name, $uri, $this->_strategy);
  296. $port = $wsdl->addPortType($name . 'Port');
  297. $binding = $wsdl->addBinding($name . 'Binding', 'tns:' .$name. 'Port');
  298. $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
  299. $wsdl->addService($name . 'Service', $name . 'Port', 'tns:' . $name . 'Binding', $uri);
  300. } else {
  301. $wsdl = $this->_wsdl;
  302. }
  303. foreach ($function as $func) {
  304. $method = $this->_reflection->reflectFunction($func);
  305. foreach ($method->getPrototypes() as $prototype) {
  306. $args = array();
  307. foreach ($prototype->getParameters() as $param) {
  308. $args[$param->getName()] = $wsdl->getType($param->getType());
  309. }
  310. $message = $wsdl->addMessage($method->getName() . 'Request', $args);
  311. $desc = $method->getDescription();
  312. if (strlen($desc) > 0) {
  313. //$wsdl->addDocumentation($message, $desc);
  314. }
  315. if($prototype->getReturnType() != "void") {
  316. $returnName = "return";
  317. $message = $wsdl->addMessage($method->getName() . 'Response', array($returnName => $wsdl->getType($prototype->getReturnType())));
  318. }
  319. /* <wsdl:portType>'s */
  320. $portOperation = $wsdl->addPortOperation($port, $method->getName(), 'tns:' .$method->getName(). 'Request', 'tns:' .$method->getName(). 'Response');
  321. if (strlen($desc) > 0) {
  322. //$wsdl->addDocumentation($portOperation, $desc);
  323. }
  324. /* </wsdl:portType>'s */
  325. /* <wsdl:binding>'s */
  326. $operation = $wsdl->addBindingOperation($binding, $method->getName(), $this->_operationBodyStyle, $this->_operationBodyStyle);
  327. $wsdl->addSoapOperation($operation, $uri . '#' .$method->getName());
  328. /* </wsdl:binding>'s */
  329. $this->_functions[] = $method->getName();
  330. // We will only add one prototype
  331. break;
  332. }
  333. }
  334. $this->_wsdl = $wsdl;
  335. }
  336. /**
  337. * Action to take when an error occurs
  338. *
  339. * @param string $fault
  340. * @param string|int $code
  341. */
  342. public function fault($fault = null, $code = null)
  343. {
  344. require_once "Zend/Soap/AutoDiscover/Exception.php";
  345. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  346. }
  347. /**
  348. * Handle the Request
  349. *
  350. * @param string $request A non-standard request - Not Used
  351. */
  352. public function handle($request = false)
  353. {
  354. if (!headers_sent()) {
  355. header('Content-Type: text/xml');
  356. }
  357. $this->_wsdl->dump();
  358. }
  359. /**
  360. * Proxy to WSDL dump function
  361. *
  362. * @param string $filename
  363. */
  364. public function dump($filename)
  365. {
  366. if($this->_wsdl !== null) {
  367. return $this->_wsdl->dump($filename);
  368. } else {
  369. /**
  370. * @see Zend_Soap_AutoDiscover_Exception
  371. */
  372. require_once "Zend/Soap/AutoDiscover/Exception.php";
  373. throw new Zend_Soap_AutoDiscover_Exception("Cannot dump autodiscovered contents, WSDL file has not been generated yet.");
  374. }
  375. }
  376. /**
  377. * Proxy to WSDL toXml() function
  378. */
  379. public function toXml()
  380. {
  381. if($this->_wsdl !== null) {
  382. return $this->_wsdl->toXml();
  383. } else {
  384. /**
  385. * @see Zend_Soap_AutoDiscover_Exception
  386. */
  387. require_once "Zend/Soap/AutoDiscover/Exception.php";
  388. throw new Zend_Soap_AutoDiscover_Exception("Cannot return autodiscovered contents, WSDL file has not been generated yet.");
  389. }
  390. }
  391. /**
  392. * Return an array of functions in the WSDL
  393. *
  394. * @return array
  395. */
  396. public function getFunctions()
  397. {
  398. return $this->_functions;
  399. }
  400. /**
  401. * Load Functions
  402. *
  403. * @param unknown_type $definition
  404. */
  405. public function loadFunctions($definition)
  406. {
  407. require_once "Zend/Soap/AutoDiscover/Exception.php";
  408. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  409. }
  410. /**
  411. * Set Persistance
  412. *
  413. * @param int $mode
  414. */
  415. public function setPersistence($mode)
  416. {
  417. require_once "Zend/Soap/AutoDiscover/Exception.php";
  418. throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
  419. }
  420. /**
  421. * Returns an XSD Type for the given PHP type
  422. *
  423. * @param string $type PHP Type to get the XSD type for
  424. * @return string
  425. */
  426. public function getType($type)
  427. {
  428. if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
  429. /** @todo Exception throwing may be more correct */
  430. // WSDL is not defined yet, so we can't recognize type in context of current service
  431. return '';
  432. } else {
  433. return $this->_wsdl->getType($type);
  434. }
  435. }
  436. }