Disco.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Dmitri Vinogradov <dimitri@vinogradov.de> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Disco.php,v 1.8 2003/09/08 17:30:29 arnaud Exp $
  20. require_once 'SOAP/Base.php';
  21. class SOAP_DISCO_Server extends SOAP_Base_Object
  22. {
  23. var $namespaces = array(SCHEMA_WSDL => 'wsdl', SCHEMA_SOAP => 'soap');
  24. var $import_ns = array();
  25. var $wsdl = '';
  26. var $disco = '';
  27. var $_wsdl = array();
  28. var $_disco = array();
  29. var $_service_name = '';
  30. var $_service_ns = '';
  31. var $_service_desc = '';
  32. var $_portname = '';
  33. var $_bindingname = '';
  34. var $soap_server = NULL;
  35. function SOAP_DISCO_Server($soap_server, $service_name, $service_desc = '', $import_ns = null)
  36. {
  37. parent::SOAP_Base_Object('Server');
  38. if ( !is_object($soap_server)
  39. || !get_class($soap_server) == 'soap_server') return;
  40. $this->_service_name = $service_name;
  41. $this->_service_ns = "urn:$service_name";
  42. $this->_service_desc = $service_desc;
  43. $this->import_ns = isset($import_ns) ? $import_ns : $this->import_ns;
  44. $this->soap_server = $soap_server;
  45. $this->host = isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:'localhost';
  46. }
  47. function getDISCO()
  48. {
  49. $this->_generate_DISCO();
  50. return $this->disco;
  51. }
  52. function getWSDL()
  53. {
  54. $this->_generate_WSDL();
  55. return $this->wsdl;
  56. }
  57. function _generate_DISCO()
  58. {
  59. # DISCO
  60. $this->_disco['disco:discovery']['attr']['xmlns:disco'] = SCHEMA_DISCO;
  61. $this->_disco['disco:discovery']['attr']['xmlns:scl'] = SCHEMA_DISCO_SCL;
  62. $this->_disco['disco:discovery']['scl:contractRef']['attr']['ref'] =
  63. (array_key_exists('HTTPS',$_SERVER) && $_SERVER['HTTPS']=='on')
  64. ? 'https://' . $this->host . $_SERVER['PHP_SELF'] . '?wsdl'
  65. : 'http://' . $this->host . $_SERVER['PHP_SELF'] . '?wsdl';
  66. # generate disco xml
  67. $this->_generate_DISCO_XML($this->_disco);
  68. }
  69. function _generate_WSDL()
  70. {
  71. # WSDL
  72. if (is_array($this->soap_server->_namespaces)) {
  73. # need to get: typens, xsd & SOAP-ENC
  74. $flipped = array_flip($this->soap_server->_namespaces);
  75. $this->namespaces[$this->_service_ns] = 'tns';
  76. $this->namespaces[$flipped['xsd']] = 'xsd';
  77. $this->namespaces[$flipped['SOAP-ENC']] = 'SOAP-ENC';
  78. }
  79. # DEFINITIONS
  80. $this->_wsdl['definitions']['attr']['name'] = $this->_service_name;
  81. $this->_wsdl['definitions']['attr']['targetNamespace'] = $this->_service_ns;
  82. foreach ($this->namespaces as $ns => $prefix) {
  83. $this->_wsdl['definitions']['attr']['xmlns:' . $prefix] = $ns;
  84. }
  85. $this->_wsdl['definitions']['attr']['xmlns'] = SCHEMA_WSDL;
  86. # import namespaces
  87. # seems to not work yet: wsdl.exe fom .NET cant handle imported complete wsdl-definitions
  88. #
  89. if (count($this->import_ns)>0) {
  90. $i = 0;
  91. foreach ($this->import_ns as $_ns => $_location) {
  92. $this->_wsdl['definitions']['import'][$i]['attr']['location'] = $_location;
  93. $this->_wsdl['definitions']['import'][$i]['attr']['namespace'] = $_ns;
  94. $i++;
  95. }
  96. }
  97. $this->_wsdl['definitions']['types']['attr']['xmlns']='http://schemas.xmlsoap.org/wsdl/';
  98. $this->_wsdl['definitions']['types']['schema']=array();
  99. # PORTTYPE-NAME
  100. $this->_portname = $this->_service_name . 'Port';
  101. $this->_wsdl['definitions']['portType']['attr']['name'] = $this->_portname;
  102. # BINDING-NAME
  103. $this->_bindingname = $this->_service_name . 'Binding';
  104. $this->_wsdl['definitions']['binding']['attr']['name'] = $this->_bindingname;
  105. $this->_wsdl['definitions']['binding']['attr']['type'] = 'tns:' . $this->_portname;
  106. $this->_wsdl['definitions']['binding']['soap:binding']['attr']['style'] = 'rpc';
  107. $this->_wsdl['definitions']['binding']['soap:binding']['attr']['transport'] = SCHEMA_SOAP_HTTP;
  108. # SERVICE
  109. $this->_wsdl['definitions']['service']['attr']['name'] = $this->_service_name . 'Service';
  110. $this->_wsdl['definitions']['service']['documentation']['attr'] = '';
  111. $this->_wsdl['definitions']['service']['documentation'] = htmlentities($this->_service_desc);
  112. $this->_wsdl['definitions']['service']['port']['attr']['name'] = $this->_portname;
  113. $this->_wsdl['definitions']['service']['port']['attr']['binding'] = 'tns:' . $this->_bindingname;
  114. $this->_wsdl['definitions']['service']['port']['soap:address']['attr']['location'] =
  115. (array_key_exists('HTTPS',$_SERVER) && $_SERVER['HTTPS']=='on')
  116. ? 'https://' . $this->host . $_SERVER['PHP_SELF']
  117. : 'http://' . $this->host . $_SERVER['PHP_SELF'];
  118. #
  119. $dispatch_keys = array_keys($this->soap_server->dispatch_objects);
  120. $dc = count($dispatch_keys);
  121. for ($di=0; $di < $dc; $di++) {
  122. $namespace = $dispatch_keys[$di];
  123. $namespace_objects =& $this->soap_server->dispatch_objects[$namespace];
  124. $oc = count($namespace_objects);
  125. for ($oi = 0; $oi < $oc; $oi++) {
  126. $object = $namespace_objects[$oi];
  127. # types definitions
  128. $this->addSchemaFromMap($object->__typedef);
  129. # MESSAGES
  130. $this->addMethodsFromMap($object->__dispatch_map,$namespace,get_class($object));
  131. }
  132. }
  133. if (isset($server->dispatch_map))
  134. $this->addMethodsFromMap($server->dispatch_map,$namespace);
  135. # generate wsdl
  136. $this->_generate_WSDL_XML($this->_wsdl);
  137. }
  138. function &_getSchema($namespace) {
  139. # SCHEMA
  140. $c = count($this->_wsdl['definitions']['types']['schema']);
  141. for($i = 0; $i < $c; $i++) {
  142. if ($this->_wsdl['definitions']['types']['schema'][$i]['attr']['targetNamespace'] == $namespace)
  143. return $this->_wsdl['definitions']['types']['schema'][$i];
  144. }
  145. # don't have this namespace
  146. $schema = array();
  147. $schema['attr'] = array();
  148. $schema['complexType'] = array();
  149. $schema['attr']['xmlns'] = array_search('xsd',$this->namespaces);
  150. $schema['attr']['targetNamespace'] = $namespace;
  151. $this->_wsdl['definitions']['types']['schema'][] =& $schema;
  152. return $schema;
  153. }
  154. function addSchemaFromMap(&$map) {
  155. if (!$map) return;
  156. foreach ($map as $_type_name => $_type_def) {
  157. list($typens,$type) = $this->_getTypeNs($_type_name);
  158. if ($typens == 'xsd') {
  159. // cannot add to xsd, lets use method_namespace
  160. $typens = 'tns';
  161. }
  162. $schema =& $this->_getSchema(array_search($typens,$this->namespaces));
  163. if (!$this->_ifComplexTypeExists($schema['complexType'], $type)) {
  164. $ctype =& $schema['complexType'][];
  165. $ctype['attr']['name'] = $type;
  166. foreach ($_type_def as $_varname => $_vartype) {
  167. if (!is_int($_varname)) {
  168. list($_vartypens,$_vartype) = $this->_getTypeNs($_vartype);
  169. $ctype['all']['attr'] = '';
  170. $el =& $ctype['all']['element'][];
  171. $el['attr']['name'] = $_varname;
  172. $el['attr']['type'] = $_vartypens . ':' . $_vartype;
  173. } else {
  174. $ctype['complexContent']['attr'] = '';
  175. $ctype['complexContent']['restriction']['attr']['base'] = 'SOAP-ENC:Array';
  176. foreach ($_vartype as $array_var => $array_type) {
  177. list($_vartypens,$_vartype) = $this->_getTypeNs($array_type);
  178. $ctype['complexContent']['restriction']['attribute']['attr']['ref'] = 'SOAP-ENC:arrayType';
  179. $ctype['complexContent']['restriction']['attribute']['attr']['wsdl:arrayType'] = $_vartypens . ':' . $_vartype . '[]';
  180. }
  181. }
  182. }
  183. }
  184. }
  185. }
  186. function addMethodsFromMap(&$map, $namespace, $classname = null)
  187. {
  188. if (!$map) {
  189. return;
  190. }
  191. foreach ($map as $method_name => $method_types) {
  192. if (array_key_exists('namespace',$method_types)) {
  193. $method_namespace = $method_types['namespace'];
  194. } else {
  195. $method_namespace = $namespace;
  196. }
  197. # INPUT
  198. if (isset($method_types['in']) && is_array($method_types['in'])) {
  199. $input_message =& $this->_wsdl['definitions']['message'][];
  200. $input_message['attr']['name'] = $method_name . 'Request';
  201. foreach ($method_types['in'] as $name => $type) {
  202. list($typens,$type) = $this->_getTypeNs($type);
  203. $part =& $input_message['part'][];
  204. $part['attr']['name'] = $name;
  205. $part['attr']['type'] = $typens . ':' . $type;
  206. }
  207. }
  208. # OUTPUT
  209. if (isset($method_types['out']) && is_array($method_types['out'])) {
  210. $output_message =& $this->_wsdl['definitions']['message'][];
  211. $output_message['attr']['name'] = $method_name . 'Response';
  212. foreach ($method_types['out'] as $name => $type) {
  213. list($typens,$type) = $this->_getTypeNs($type);
  214. $part =& $output_message['part'][];
  215. $part['attr']['name'] = $name;
  216. $part['attr']['type'] = $typens . ':' . $type;
  217. }
  218. }
  219. # PORTTYPES
  220. $operation =& $this->_wsdl['definitions']['portType']['operation'][];
  221. $operation['attr']['name'] = $method_name;
  222. # INPUT
  223. $operation['input']['attr']['message'] = 'tns:'
  224. . $input_message['attr']['name'];
  225. # OUTPUT
  226. $operation['output']['attr']['message'] = 'tns:'
  227. . $output_message['attr']['name'];
  228. # BINDING
  229. $binding =& $this->_wsdl['definitions']['binding']['operation'][];
  230. $binding['attr']['name'] = $method_name;
  231. $action = $method_namespace . '#' . ($classname?$classname . '#':'') . $method_name;
  232. $binding['soap:operation']['attr']['soapAction'] = $action;
  233. # INPUT
  234. $binding['input']['attr'] = '';
  235. $binding['input']['soap:body']['attr']['use'] = 'encoded';
  236. $binding['input']['soap:body']['attr']['namespace'] = $method_namespace;
  237. $binding['input']['soap:body']['attr']['encodingStyle'] = SOAP_SCHEMA_ENCODING;
  238. # OUTPUT
  239. $binding['output']['attr'] = '';
  240. $binding['output']['soap:body']['attr']['use'] = 'encoded';
  241. $binding['output']['soap:body']['attr']['namespace'] = $method_namespace;
  242. $binding['output']['soap:body']['attr']['encodingStyle'] = SOAP_SCHEMA_ENCODING;
  243. }
  244. }
  245. function _generate_DISCO_XML($disco_array) {
  246. $disco = '<?xml version="1.0"?>';
  247. foreach ($disco_array as $key => $val) {
  248. $disco .= $this->_arrayToNode($key,$val);
  249. }
  250. $this->disco = $disco;
  251. }
  252. function _generate_WSDL_XML($wsdl_array) {
  253. $wsdl = '<?xml version="1.0"?>';
  254. foreach ($wsdl_array as $key => $val) {
  255. $wsdl .= $this->_arrayToNode($key,$val);
  256. }
  257. $this->wsdl = $wsdl;
  258. }
  259. function _arrayToNode($node_name = '', $array) {
  260. $return = '';
  261. if (is_array($array)) {
  262. # we have a node if there's key 'attr'
  263. if (array_key_exists('attr',$array)) {
  264. $return .= "<$node_name";
  265. if (is_array($array['attr'])) {
  266. foreach ($array['attr'] as $attr_name => $attr_value) {
  267. $return .= " $attr_name=\"$attr_value\"";
  268. }
  269. }
  270. # unset 'attr' and proceed other childs...
  271. unset($array['attr']);
  272. if (count($array) > 0) {
  273. $i = 0;
  274. foreach ($array as $child_node_name => $child_node_value) {
  275. $return .= $i == 0 ? ">\n" : '';
  276. $return .= $this->_arrayToNode($child_node_name,$child_node_value);
  277. $i++;
  278. }
  279. $return .= "</$node_name>\n";
  280. } else {
  281. $return .= " />\n";
  282. }
  283. } else {
  284. # we have no 'attr' key in array - so it's list of nodes with the same name ...
  285. foreach ($array as $child_node_name => $child_node_value) {
  286. $return .= $this->_arrayToNode($node_name,$child_node_value);
  287. }
  288. }
  289. } else {
  290. # $array is not an array
  291. if ($array !='') {
  292. # and its not empty
  293. $return .= "<$node_name>$array</$node_name>\n";
  294. } else {
  295. # and its empty...
  296. $return .= "<$node_name />\n";
  297. }
  298. }
  299. return $return;
  300. }
  301. function _getTypeNs($type) {
  302. preg_match_all("'\{(.*)\}'sm",$type,$m);
  303. if (isset($m[1][0]) && $m[1][0] != '') {
  304. if (!array_key_exists($m[1][0],$this->namespaces)) {
  305. $ns_pref = 'ns' . count($this->namespaces);
  306. $this->namespaces[$m[1][0]] = $ns_pref;
  307. $this->_wsdl['definitions']['attr']['xmlns:' . $ns_pref] = $m[1][0];
  308. }
  309. $typens = $this->namespaces[$m[1][0]];
  310. $type = ereg_replace($m[0][0],'',$type);
  311. } else {
  312. $typens = 'xsd';
  313. }
  314. return array($typens,$type);
  315. }
  316. function _ifComplexTypeExists($typesArray, $type_name) {
  317. if (is_array($typesArray)) {
  318. foreach ($typesArray as $index => $type_data) {
  319. if ($typesArray[$index]['attr']['name'] == $type_name) {
  320. return true;
  321. }
  322. }
  323. }
  324. return false;
  325. }
  326. }
  327. ?>