wsdl

Parses a WSDL file, allows access to it's data, other utility methods.

Defined (2)

The class is defined in the following location(s).

/lib/class.wsdl.php  
  1. class wsdl extends nusoap_base { 
  2. // URL or filename of the root of this WSDL 
  3. var $wsdl;  
  4. // define internal arrays of bindings, ports, operations, messages, etc. 
  5. var $schemas = array(); 
  6. var $currentSchema; 
  7. var $message = array(); 
  8. var $complexTypes = array(); 
  9. var $messages = array(); 
  10. var $currentMessage; 
  11. var $currentOperation; 
  12. var $portTypes = array(); 
  13. var $currentPortType; 
  14. var $bindings = array(); 
  15. var $currentBinding; 
  16. var $ports = array(); 
  17. var $currentPort; 
  18. var $opData = array(); 
  19. var $status = ''; 
  20. var $documentation = false; 
  21. var $endpoint = '';  
  22. // array of wsdl docs to import 
  23. var $import = array();  
  24. // parser vars 
  25. var $parser; 
  26. var $position = 0; 
  27. var $depth = 0; 
  28. var $depth_array = array(); 
  29. // for getting wsdl 
  30. var $proxyhost = ''; 
  31. var $proxyport = ''; 
  32. var $proxyusername = ''; 
  33. var $proxypassword = ''; 
  34. var $timeout = 0; 
  35. var $response_timeout = 30; 
  36. var $curl_options = array(); // User-specified cURL options 
  37. var $use_curl = false; // whether to always try to use cURL 
  38. // for HTTP authentication 
  39. var $username = ''; // Username for HTTP authentication 
  40. var $password = ''; // Password for HTTP authentication 
  41. var $authtype = ''; // Type of HTTP authentication 
  42. var $certRequest = array(); // Certificate for HTTP SSL authentication 
  43.  
  44. /** 
  45. * constructor 
  46. *  
  47. * @param string $wsdl WSDL document URL 
  48. * @param string $proxyhost 
  49. * @param string $proxyport 
  50. * @param string $proxyusername 
  51. * @param string $proxypassword 
  52. * @param integer $timeout set the connection timeout 
  53. * @param integer $response_timeout set the response timeout 
  54. * @param array $curl_options user-specified cURL options 
  55. * @param boolean $use_curl try to use cURL 
  56. * @access public  
  57. */ 
  58. function wsdl($wsdl = '', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $curl_options=null, $use_curl=false) { 
  59. parent::nusoap_base(); 
  60. $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 
  61. $this->proxyhost = $proxyhost; 
  62. $this->proxyport = $proxyport; 
  63. $this->proxyusername = $proxyusername; 
  64. $this->proxypassword = $proxypassword; 
  65. $this->timeout = $timeout; 
  66. $this->response_timeout = $response_timeout; 
  67. if (is_array($curl_options)) 
  68. $this->curl_options = $curl_options; 
  69. $this->use_curl = $use_curl; 
  70. $this->fetchWSDL($wsdl); 
  71.  
  72. /** 
  73. * fetches the WSDL document and parses it 
  74. * @access public 
  75. */ 
  76. function fetchWSDL($wsdl) { 
  77. $this->debug("parse and process WSDL path=$wsdl"); 
  78. $this->wsdl = $wsdl; 
  79. // parse wsdl file 
  80. if ($this->wsdl != "") { 
  81. $this->parseWSDL($this->wsdl); 
  82. // imports 
  83. // TODO: handle imports more properly, grabbing them in-line and nesting them 
  84. $imported_urls = array(); 
  85. $imported = 1; 
  86. while ($imported > 0) { 
  87. $imported = 0; 
  88. // Schema imports 
  89. foreach ($this->schemas as $ns => $list) { 
  90. foreach ($list as $xs) { 
  91. $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 
  92. foreach ($xs->imports as $ns2 => $list2) { 
  93. for ($ii = 0; $ii < count($list2); $ii++) { 
  94. if (! $list2[$ii]['loaded']) { 
  95. $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 
  96. $url = $list2[$ii]['location']; 
  97. if ($url != '') { 
  98. $urlparts = parse_url($url); 
  99. if (!isset($urlparts['host'])) { 
  100. $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 
  101. substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path']; 
  102. if (! in_array($url, $imported_urls)) { 
  103. $this->parseWSDL($url); 
  104. $imported++; 
  105. $imported_urls[] = $url; 
  106. } else { 
  107. $this->debug("Unexpected scenario: empty URL for unloaded import"); 
  108. }  
  109. // WSDL imports 
  110. $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 
  111. foreach ($this->import as $ns => $list) { 
  112. for ($ii = 0; $ii < count($list); $ii++) { 
  113. if (! $list[$ii]['loaded']) { 
  114. $this->import[$ns][$ii]['loaded'] = true; 
  115. $url = $list[$ii]['location']; 
  116. if ($url != '') { 
  117. $urlparts = parse_url($url); 
  118. if (!isset($urlparts['host'])) { 
  119. $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 
  120. substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path']; 
  121. if (! in_array($url, $imported_urls)) { 
  122. $this->parseWSDL($url); 
  123. $imported++; 
  124. $imported_urls[] = $url; 
  125. } else { 
  126. $this->debug("Unexpected scenario: empty URL for unloaded import"); 
  127. }  
  128. // add new data to operation data 
  129. foreach($this->bindings as $binding => $bindingData) { 
  130. if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 
  131. foreach($bindingData['operations'] as $operation => $data) { 
  132. $this->debug('post-parse data gathering for ' . $operation); 
  133. $this->bindings[$binding]['operations'][$operation]['input'] =  
  134. isset($this->bindings[$binding]['operations'][$operation]['input']) ?  
  135. array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 
  136. $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 
  137. $this->bindings[$binding]['operations'][$operation]['output'] =  
  138. isset($this->bindings[$binding]['operations'][$operation]['output']) ? 
  139. array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 
  140. $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 
  141. if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])) { 
  142. $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 
  143. if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])) { 
  144. $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 
  145. // Set operation style if necessary, but do not override one already provided 
  146. if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { 
  147. $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 
  148. $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 
  149. $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 
  150. $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 
  151. }  
  152. }  
  153.  
  154. /** 
  155. * parses the wsdl document 
  156. *  
  157. * @param string $wsdl path or URL 
  158. * @access private  
  159. */ 
  160. function parseWSDL($wsdl = '') { 
  161. $this->debug("parse WSDL at path=$wsdl"); 
  162.  
  163. if ($wsdl == '') { 
  164. $this->debug('no wsdl passed to parseWSDL()!!'); 
  165. $this->setError('no wsdl passed to parseWSDL()!!'); 
  166. return false; 
  167.  
  168. // parse $wsdl for url format 
  169. $wsdl_props = parse_url($wsdl); 
  170.  
  171. if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 
  172. $this->debug('getting WSDL http(s) URL ' . $wsdl); 
  173. // get wsdl 
  174. $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); 
  175. $tr->request_method = 'GET'; 
  176. $tr->useSOAPAction = false; 
  177. if($this->proxyhost && $this->proxyport) { 
  178. $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword); 
  179. if ($this->authtype != '') { 
  180. $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 
  181. $tr->setEncoding('gzip, deflate'); 
  182. $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 
  183. //$this->debug("WSDL request\n" . $tr->outgoing_payload); 
  184. //$this->debug("WSDL response\n" . $tr->incoming_payload); 
  185. $this->appendDebug($tr->getDebug()); 
  186. // catch errors 
  187. if($err = $tr->getError() ) { 
  188. $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; 
  189. $this->debug($errstr); 
  190. $this->setError($errstr); 
  191. unset($tr); 
  192. return false; 
  193. unset($tr); 
  194. $this->debug("got WSDL URL"); 
  195. } else { 
  196. // $wsdl is not http(s), so treat it as a file URL or plain file path 
  197. if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 
  198. $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 
  199. } else { 
  200. $path = $wsdl; 
  201. $this->debug('getting WSDL file ' . $path); 
  202. if ($fp = @fopen($path, 'r')) { 
  203. $wsdl_string = ''; 
  204. while ($data = fread($fp, 32768)) { 
  205. $wsdl_string .= $data; 
  206. }  
  207. fclose($fp); 
  208. } else { 
  209. $errstr = "Bad path to WSDL file $path"; 
  210. $this->debug($errstr); 
  211. $this->setError($errstr); 
  212. return false; 
  213. }  
  214. $this->debug('Parse WSDL'); 
  215. // end new code added 
  216. // Create an XML parser. 
  217. $this->parser = xml_parser_create();  
  218. // Set the options for parsing the XML data. 
  219. // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
  220. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);  
  221. // Set the object for the parser. 
  222. xml_set_object($this->parser, $this);  
  223. // Set the element handlers for the parser. 
  224. xml_set_element_handler($this->parser, 'start_element', 'end_element'); 
  225. xml_set_character_data_handler($this->parser, 'character_data'); 
  226. // Parse the XML file. 
  227. if (!xml_parse($this->parser, $wsdl_string, true)) { 
  228. // Display an error message. 
  229. $errstr = sprintf( 
  230. 'XML error parsing WSDL from %s on line %d: %s',  
  231. $wsdl,  
  232. xml_get_current_line_number($this->parser),  
  233. xml_error_string(xml_get_error_code($this->parser)) 
  234. ); 
  235. $this->debug($errstr); 
  236. $this->debug("XML payload:\n" . $wsdl_string); 
  237. $this->setError($errstr); 
  238. return false; 
  239. }  
  240. // free the parser 
  241. xml_parser_free($this->parser); 
  242. $this->debug('Parsing WSDL done'); 
  243. // catch wsdl parse errors 
  244. if($this->getError()) { 
  245. return false; 
  246. return true; 
  247. }  
  248.  
  249. /** 
  250. * start-element handler 
  251. *  
  252. * @param string $parser XML parser object 
  253. * @param string $name element name 
  254. * @param string $attrs associative array of attributes 
  255. * @access private  
  256. */ 
  257. function start_element($parser, $name, $attrs) 
  258. if ($this->status == 'schema') { 
  259. $this->currentSchema->schemaStartElement($parser, $name, $attrs); 
  260. $this->appendDebug($this->currentSchema->getDebug()); 
  261. $this->currentSchema->clearDebug(); 
  262. } elseif (preg_match('/schema$/', $name)) { 
  263. $this->debug('Parsing WSDL schema'); 
  264. // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 
  265. $this->status = 'schema'; 
  266. $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); 
  267. $this->currentSchema->schemaStartElement($parser, $name, $attrs); 
  268. $this->appendDebug($this->currentSchema->getDebug()); 
  269. $this->currentSchema->clearDebug(); 
  270. } else { 
  271. // position in the total number of elements, starting from 0 
  272. $pos = $this->position++; 
  273. $depth = $this->depth++;  
  274. // set self as current value for this depth 
  275. $this->depth_array[$depth] = $pos; 
  276. $this->message[$pos] = array('cdata' => '');  
  277. // process attributes 
  278. if (count($attrs) > 0) { 
  279. // register namespace declarations 
  280. foreach($attrs as $k => $v) { 
  281. if (preg_match('/^xmlns/', $k)) { 
  282. if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 
  283. $this->namespaces[$ns_prefix] = $v; 
  284. } else { 
  285. $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 
  286. }  
  287. if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 
  288. $this->XMLSchemaVersion = $v; 
  289. $this->namespaces['xsi'] = $v . '-instance'; 
  290. }  
  291. // expand each attribute prefix to its namespace 
  292. foreach($attrs as $k => $v) { 
  293. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  294. if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 
  295. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  296. }  
  297. $eAttrs[$k] = $v; 
  298. }  
  299. $attrs = $eAttrs; 
  300. } else { 
  301. $attrs = array(); 
  302. }  
  303. // get element prefix, namespace and name 
  304. if (preg_match('/:/', $name)) { 
  305. // get ns prefix 
  306. $prefix = substr($name, 0, strpos($name, ':'));  
  307. // get ns 
  308. $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';  
  309. // get unqualified name 
  310. $name = substr(strstr($name, ':'), 1); 
  311. }  
  312. // process attributes, expanding any prefixes to namespaces 
  313. // find status, register data 
  314. switch ($this->status) { 
  315. case 'message': 
  316. if ($name == 'part') { 
  317. if (isset($attrs['type'])) { 
  318. $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(', ', $attrs)); 
  319. $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 
  320. }  
  321. if (isset($attrs['element'])) { 
  322. $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(', ', $attrs)); 
  323. $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; 
  324. }  
  325. }  
  326. break; 
  327. case 'portType': 
  328. switch ($name) { 
  329. case 'operation': 
  330. $this->currentPortOperation = $attrs['name']; 
  331. $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 
  332. if (isset($attrs['parameterOrder'])) { 
  333. $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 
  334. }  
  335. break; 
  336. case 'documentation': 
  337. $this->documentation = true; 
  338. break;  
  339. // merge input/output data 
  340. default: 
  341. $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 
  342. $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 
  343. break; 
  344. }  
  345. break; 
  346. case 'binding': 
  347. switch ($name) { 
  348. case 'binding':  
  349. // get ns prefix 
  350. if (isset($attrs['style'])) { 
  351. $this->bindings[$this->currentBinding]['prefix'] = $prefix; 
  352. }  
  353. $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 
  354. break; 
  355. case 'header': 
  356. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 
  357. break; 
  358. case 'operation': 
  359. if (isset($attrs['soapAction'])) { 
  360. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 
  361. }  
  362. if (isset($attrs['style'])) { 
  363. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 
  364. }  
  365. if (isset($attrs['name'])) { 
  366. $this->currentOperation = $attrs['name']; 
  367. $this->debug("current binding operation: $this->currentOperation"); 
  368. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 
  369. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 
  370. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 
  371. }  
  372. break; 
  373. case 'input': 
  374. $this->opStatus = 'input'; 
  375. break; 
  376. case 'output': 
  377. $this->opStatus = 'output'; 
  378. break; 
  379. case 'body': 
  380. if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 
  381. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 
  382. } else { 
  383. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 
  384. }  
  385. break; 
  386. }  
  387. break; 
  388. case 'service': 
  389. switch ($name) { 
  390. case 'port': 
  391. $this->currentPort = $attrs['name']; 
  392. $this->debug('current port: ' . $this->currentPort); 
  393. $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 
  394.  
  395. break; 
  396. case 'address': 
  397. $this->ports[$this->currentPort]['location'] = $attrs['location']; 
  398. $this->ports[$this->currentPort]['bindingType'] = $namespace; 
  399. $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 
  400. $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 
  401. break; 
  402. }  
  403. break; 
  404. }  
  405. // set status 
  406. switch ($name) { 
  407. case 'import': 
  408. if (isset($attrs['location'])) { 
  409. $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 
  410. $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 
  411. } else { 
  412. $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 
  413. if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 
  414. $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 
  415. $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 
  416. break; 
  417. //wait for schema 
  418. //case 'types': 
  419. // $this->status = 'schema'; 
  420. // break; 
  421. case 'message': 
  422. $this->status = 'message'; 
  423. $this->messages[$attrs['name']] = array(); 
  424. $this->currentMessage = $attrs['name']; 
  425. break; 
  426. case 'portType': 
  427. $this->status = 'portType'; 
  428. $this->portTypes[$attrs['name']] = array(); 
  429. $this->currentPortType = $attrs['name']; 
  430. break; 
  431. case "binding": 
  432. if (isset($attrs['name'])) { 
  433. // get binding name 
  434. if (strpos($attrs['name'], ':')) { 
  435. $this->currentBinding = $this->getLocalPart($attrs['name']); 
  436. } else { 
  437. $this->currentBinding = $attrs['name']; 
  438. }  
  439. $this->status = 'binding'; 
  440. $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 
  441. $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 
  442. }  
  443. break; 
  444. case 'service': 
  445. $this->serviceName = $attrs['name']; 
  446. $this->status = 'service'; 
  447. $this->debug('current service: ' . $this->serviceName); 
  448. break; 
  449. case 'definitions': 
  450. foreach ($attrs as $name => $value) { 
  451. $this->wsdl_info[$name] = $value; 
  452. }  
  453. break; 
  454. }  
  455. }  
  456. }  
  457.  
  458. /** 
  459. * end-element handler 
  460. *  
  461. * @param string $parser XML parser object 
  462. * @param string $name element name 
  463. * @access private  
  464. */ 
  465. function end_element($parser, $name) {  
  466. // unset schema status 
  467. if (/**preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { 
  468. $this->status = ""; 
  469. $this->appendDebug($this->currentSchema->getDebug()); 
  470. $this->currentSchema->clearDebug(); 
  471. $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 
  472. $this->debug('Parsing WSDL schema done'); 
  473. }  
  474. if ($this->status == 'schema') { 
  475. $this->currentSchema->schemaEndElement($parser, $name); 
  476. } else { 
  477. // bring depth down a notch 
  478. $this->depth--; 
  479. }  
  480. // end documentation 
  481. if ($this->documentation) { 
  482. //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 
  483. //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 
  484. $this->documentation = false; 
  485. }  
  486. }  
  487.  
  488. /** 
  489. * element content handler 
  490. *  
  491. * @param string $parser XML parser object 
  492. * @param string $data element content 
  493. * @access private  
  494. */ 
  495. function character_data($parser, $data) 
  496. $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 
  497. if (isset($this->message[$pos]['cdata'])) { 
  498. $this->message[$pos]['cdata'] .= $data; 
  499. }  
  500. if ($this->documentation) { 
  501. $this->documentation .= $data; 
  502. }  
  503. }  
  504.  
  505. /** 
  506. * if authenticating, set user credentials here 
  507. * @param string $username 
  508. * @param string $password 
  509. * @param string $authtype (basic|digest|certificate|ntlm) 
  510. * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 
  511. * @access public 
  512. */ 
  513. function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 
  514. $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 
  515. $this->appendDebug($this->varDump($certRequest)); 
  516. $this->username = $username; 
  517. $this->password = $password; 
  518. $this->authtype = $authtype; 
  519. $this->certRequest = $certRequest; 
  520.  
  521. function getBindingData($binding) 
  522. if (is_array($this->bindings[$binding])) { 
  523. return $this->bindings[$binding]; 
  524. }  
  525.  
  526. /** 
  527. * returns an assoc array of operation names => operation data 
  528. *  
  529. * @param string $portName WSDL port name 
  530. * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) 
  531. * @return array  
  532. * @access public  
  533. */ 
  534. function getOperations($portName = '', $bindingType = 'soap') { 
  535. $ops = array(); 
  536. if ($bindingType == 'soap') { 
  537. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  538. } elseif ($bindingType == 'soap12') { 
  539. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  540. } else { 
  541. $this->debug("getOperations bindingType $bindingType may not be supported"); 
  542. $this->debug("getOperations for port '$portName' bindingType $bindingType"); 
  543. // loop thru ports 
  544. foreach($this->ports as $port => $portData) { 
  545. $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); 
  546. if ($portName == '' || $port == $portName) { 
  547. // binding type of port matches parameter 
  548. if ($portData['bindingType'] == $bindingType) { 
  549. $this->debug("getOperations found port $port bindingType $bindingType"); 
  550. //$this->debug("port data: " . $this->varDump($portData)); 
  551. //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 
  552. // merge bindings 
  553. if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 
  554. $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 
  555. if (count($ops) == 0) { 
  556. $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); 
  557. return $ops; 
  558. }  
  559.  
  560. /** 
  561. * returns an associative array of data necessary for calling an operation 
  562. *  
  563. * @param string $operation name of operation 
  564. * @param string $bindingType type of binding eg: soap, soap12 
  565. * @return array  
  566. * @access public  
  567. */ 
  568. function getOperationData($operation, $bindingType = 'soap') 
  569. if ($bindingType == 'soap') { 
  570. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  571. } elseif ($bindingType == 'soap12') { 
  572. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  573. // loop thru ports 
  574. foreach($this->ports as $port => $portData) { 
  575. // binding type of port matches parameter 
  576. if ($portData['bindingType'] == $bindingType) { 
  577. // get binding 
  578. //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 
  579. foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 
  580. // note that we could/should also check the namespace here 
  581. if ($operation == $bOperation) { 
  582. $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 
  583. return $opData; 
  584. }  
  585. }  
  586. }  
  587.  
  588. /** 
  589. * returns an associative array of data necessary for calling an operation 
  590. *  
  591. * @param string $soapAction soapAction for operation 
  592. * @param string $bindingType type of binding eg: soap, soap12 
  593. * @return array  
  594. * @access public  
  595. */ 
  596. function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 
  597. if ($bindingType == 'soap') { 
  598. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  599. } elseif ($bindingType == 'soap12') { 
  600. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  601. // loop thru ports 
  602. foreach($this->ports as $port => $portData) { 
  603. // binding type of port matches parameter 
  604. if ($portData['bindingType'] == $bindingType) { 
  605. // loop through operations for the binding 
  606. foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 
  607. if ($opData['soapAction'] == $soapAction) { 
  608. return $opData; 
  609. }  
  610. }  
  611. }  
  612.  
  613. /** 
  614. * returns an array of information about a given type 
  615. * returns false if no type exists by the given name 
  616. * typeDef = array( 
  617. * 'elements' => array(), // refs to elements array 
  618. * 'restrictionBase' => '',  
  619. * 'phpType' => '',  
  620. * 'order' => '(sequence|all)',  
  621. * 'attrs' => array() // refs to attributes array 
  622. * ) 
  623. * @param string $type the type 
  624. * @param string $ns namespace (not prefix) of the type 
  625. * @return mixed 
  626. * @access public 
  627. * @see nusoap_xmlschema 
  628. */ 
  629. function getTypeDef($type, $ns) { 
  630. $this->debug("in getTypeDef: type=$type, ns=$ns"); 
  631. if ((! $ns) && isset($this->namespaces['tns'])) { 
  632. $ns = $this->namespaces['tns']; 
  633. $this->debug("in getTypeDef: type namespace forced to $ns"); 
  634. if (!isset($this->schemas[$ns])) { 
  635. foreach ($this->schemas as $ns0 => $schema0) { 
  636. if (strcasecmp($ns, $ns0) == 0) { 
  637. $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); 
  638. $ns = $ns0; 
  639. break; 
  640. if (isset($this->schemas[$ns])) { 
  641. $this->debug("in getTypeDef: have schema for namespace $ns"); 
  642. for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 
  643. $xs = &$this->schemas[$ns][$i]; 
  644. $t = $xs->getTypeDef($type); 
  645. $this->appendDebug($xs->getDebug()); 
  646. $xs->clearDebug(); 
  647. if ($t) { 
  648. $this->debug("in getTypeDef: found type $type"); 
  649. if (!isset($t['phpType'])) { 
  650. // get info for type to tack onto the element 
  651. $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 
  652. $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 
  653. $etype = $this->getTypeDef($uqType, $ns); 
  654. if ($etype) { 
  655. $this->debug("found type for [element] $type:"); 
  656. $this->debug($this->varDump($etype)); 
  657. if (isset($etype['phpType'])) { 
  658. $t['phpType'] = $etype['phpType']; 
  659. if (isset($etype['elements'])) { 
  660. $t['elements'] = $etype['elements']; 
  661. if (isset($etype['attrs'])) { 
  662. $t['attrs'] = $etype['attrs']; 
  663. } else { 
  664. $this->debug("did not find type for [element] $type"); 
  665. return $t; 
  666. $this->debug("in getTypeDef: did not find type $type"); 
  667. } else { 
  668. $this->debug("in getTypeDef: do not have schema for namespace $ns"); 
  669. return false; 
  670.  
  671. /** 
  672. * prints html description of services 
  673. * @access private 
  674. */ 
  675. function webDescription() { 
  676. global $HTTP_SERVER_VARS; 
  677.  
  678. if (isset($_SERVER)) { 
  679. $PHP_SELF = $_SERVER['PHP_SELF']; 
  680. } elseif (isset($HTTP_SERVER_VARS)) { 
  681. $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 
  682. } else { 
  683. $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 
  684.  
  685. $b = ' 
  686. <html><head><title>NuSOAP: '.$this->serviceName.'</title> 
  687. <style type="text/css"> 
  688. body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 
  689. p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 
  690. pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 
  691. ul { margin-top: 10px; margin-left: 20px; } 
  692. li { list-style-type: none; margin-top: 10px; color: #000000; } 
  693. .content{ 
  694. margin-left: 0px; padding-bottom: 2em; } 
  695. .nav { 
  696. padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 
  697. margin-top: 10px; margin-left: 0px; color: #000000; 
  698. background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 
  699. .title { 
  700. font-family: arial; font-size: 26px; color: #ffffff; 
  701. background-color: #999999; width: 100%; 
  702. margin-left: 0px; margin-right: 0px; 
  703. padding-top: 10px; padding-bottom: 10px;} 
  704. .hidden { 
  705. position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 
  706. font-family: arial; overflow: hidden; width: 600; 
  707. padding: 20px; font-size: 10px; background-color: #999999; 
  708. layer-background-color:#FFFFFF; } 
  709. a, a:active { color: charcoal; font-weight: bold; } 
  710. a:visited { color: #666666; font-weight: bold; } 
  711. a:hover { color: cc3300; font-weight: bold; } 
  712. </style> 
  713. <script language="JavaScript" type="text/javascript"> 
  714. <!-- 
  715. // POP-UP CAPTIONS... 
  716. function lib_bwcheck() { //Browsercheck (needed) 
  717. this.ver=navigator.appVersion 
  718. this.agent=navigator.userAgent 
  719. this.dom=document.getElementById?1:0 
  720. this.opera5=this.agent.indexOf("Opera 5")>-1 
  721. this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 
  722. this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 
  723. this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 
  724. this.ie=this.ie4||this.ie5||this.ie6 
  725. this.mac=this.agent.indexOf("Mac")>-1 
  726. this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 
  727. this.ns4=(document.layers && !this.dom)?1:0; 
  728. this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 
  729. return this 
  730. var bw = new lib_bwcheck() 
  731. //Makes crossbrowser object. 
  732. function makeObj(obj) { 
  733. this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 
  734. if(!this.evnt) return false 
  735. this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 
  736. this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 
  737. this.writeIt=b_writeIt; 
  738. return this 
  739. // A unit of measure that will be added when setting the position of a layer. 
  740. //var px = bw.ns4||window.opera?"":"px"; 
  741. function b_writeIt(text) { 
  742. if (bw.ns4) {this.wref.write(text);this.wref.close()} 
  743. else this.wref.innerHTML = text 
  744. //Shows the messages 
  745. var oDesc; 
  746. function popup(divid) { 
  747. if(oDesc = new makeObj(divid)) { 
  748. oDesc.css.visibility = "visible" 
  749. function popout() { // Hides message 
  750. if(oDesc) oDesc.css.visibility = "hidden" 
  751. //--> 
  752. </script> 
  753. </head> 
  754. <body> 
  755. <div class=content> 
  756. <br><br> 
  757. <div class=title>'.$this->serviceName.'</div> 
  758. <div class=nav> 
  759. <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 
  760. Click on an operation name to view it's details.</p> 
  761. <ul>'; 
  762. foreach($this->getOperations() as $op => $data) { 
  763. $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 
  764. // create hidden div 
  765. $b .= "<div id='$op' class='hidden'> 
  766. <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 
  767. foreach($data as $donnie => $marie) { // loop through opdata 
  768. if($donnie == 'input' || $donnie == 'output') { // show input/output data 
  769. $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 
  770. foreach($marie as $captain => $tenille) { // loop through data 
  771. if($captain == 'parts') { // loop thru parts 
  772. $b .= "  $captain:<br>"; 
  773. //if(is_array($tenille)) { 
  774. foreach($tenille as $joanie => $chachi) { 
  775. $b .= "    $joanie: $chachi<br>"; 
  776. //} 
  777. } else { 
  778. $b .= "  $captain: $tenille<br>"; 
  779. } else { 
  780. $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 
  781. $b .= '</div>'; 
  782. $b .= ' 
  783. <ul> 
  784. </div> 
  785. </div></body></html>'; 
  786. return $b; 
  787.  
  788. /** 
  789. * serialize the parsed wsdl 
  790. * @param mixed $debug whether to put debug=1 in endpoint URL 
  791. * @return string serialization of WSDL 
  792. * @access public  
  793. */ 
  794. function serialize($debug = 0) 
  795. $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 
  796. $xml .= "\n<definitions"; 
  797. foreach($this->namespaces as $k => $v) { 
  798. $xml .= " xmlns:$k=\"$v\""; 
  799. }  
  800. // 10.9.02 - add poulter fix for wsdl and tns declarations 
  801. if (isset($this->namespaces['wsdl'])) { 
  802. $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 
  803. }  
  804. if (isset($this->namespaces['tns'])) { 
  805. $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 
  806. }  
  807. $xml .= '>';  
  808. // imports 
  809. if (sizeof($this->import) > 0) { 
  810. foreach($this->import as $ns => $list) { 
  811. foreach ($list as $ii) { 
  812. if ($ii['location'] != '') { 
  813. $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 
  814. } else { 
  815. $xml .= '<import namespace="' . $ns . '" />'; 
  816. }  
  817. }  
  818. // types 
  819. if (count($this->schemas)>=1) { 
  820. $xml .= "\n<types>\n"; 
  821. foreach ($this->schemas as $ns => $list) { 
  822. foreach ($list as $xs) { 
  823. $xml .= $xs->serializeSchema(); 
  824. $xml .= '</types>'; 
  825. }  
  826. // messages 
  827. if (count($this->messages) >= 1) { 
  828. foreach($this->messages as $msgName => $msgParts) { 
  829. $xml .= "\n<message name=\"" . $msgName . '">'; 
  830. if(is_array($msgParts)) { 
  831. foreach($msgParts as $partName => $partType) { 
  832. // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 
  833. if (strpos($partType, ':')) { 
  834. $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 
  835. } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 
  836. // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 
  837. $typePrefix = 'xsd'; 
  838. } else { 
  839. foreach($this->typemap as $ns => $types) { 
  840. if (isset($types[$partType])) { 
  841. $typePrefix = $this->getPrefixFromNamespace($ns); 
  842. }  
  843. }  
  844. if (!isset($typePrefix)) { 
  845. die("$partType has no namespace!"); 
  846. }  
  847. $ns = $this->getNamespaceFromPrefix($typePrefix); 
  848. $localPart = $this->getLocalPart($partType); 
  849. $typeDef = $this->getTypeDef($localPart, $ns); 
  850. if ($typeDef['typeClass'] == 'element') { 
  851. $elementortype = 'element'; 
  852. if (substr($localPart, -1) == '^') { 
  853. $localPart = substr($localPart, 0, -1); 
  854. } else { 
  855. $elementortype = 'type'; 
  856. $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; 
  857. $xml .= '</message>'; 
  858. }  
  859. }  
  860. // bindings & porttypes 
  861. if (count($this->bindings) >= 1) { 
  862. $binding_xml = ''; 
  863. $portType_xml = ''; 
  864. foreach($this->bindings as $bindingName => $attrs) { 
  865. $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 
  866. $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 
  867. $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 
  868. foreach($attrs['operations'] as $opName => $opParts) { 
  869. $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; 
  870. $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 
  871. if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 
  872. $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 
  873. } else { 
  874. $enc_style = ''; 
  875. $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 
  876. if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 
  877. $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 
  878. } else { 
  879. $enc_style = ''; 
  880. $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 
  881. $binding_xml .= "\n" . ' </operation>'; 
  882. $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; 
  883. if (isset($opParts['parameterOrder'])) { 
  884. $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 
  885. }  
  886. $portType_xml .= '>'; 
  887. if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 
  888. $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 
  889. $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; 
  890. $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; 
  891. $portType_xml .= "\n" . ' </operation>'; 
  892. }  
  893. $portType_xml .= "\n" . '</portType>'; 
  894. $binding_xml .= "\n" . '</binding>'; 
  895. }  
  896. $xml .= $portType_xml . $binding_xml; 
  897. }  
  898. // services 
  899. $xml .= "\n<service name=\"" . $this->serviceName . '">'; 
  900. if (count($this->ports) >= 1) { 
  901. foreach($this->ports as $pName => $attrs) { 
  902. $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 
  903. $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 
  904. $xml .= "\n" . ' </port>'; 
  905. }  
  906. }  
  907. $xml .= "\n" . '</service>'; 
  908. return $xml . "\n</definitions>"; 
  909. }  
  910.  
  911. /** 
  912. * determine whether a set of parameters are unwrapped 
  913. * when they are expect to be wrapped, Microsoft-style. 
  914. * @param string $type the type (element name) of the wrapper 
  915. * @param array $parameters the parameter values for the SOAP call 
  916. * @return boolean whether they parameters are unwrapped (and should be wrapped) 
  917. * @access private 
  918. */ 
  919. function parametersMatchWrapped($type, &$parameters) { 
  920. $this->debug("in parametersMatchWrapped type=$type, parameters="); 
  921. $this->appendDebug($this->varDump($parameters)); 
  922.  
  923. // split type into namespace:unqualified-type 
  924. if (strpos($type, ':')) { 
  925. $uqType = substr($type, strrpos($type, ':') + 1); 
  926. $ns = substr($type, 0, strrpos($type, ':')); 
  927. $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); 
  928. if ($this->getNamespaceFromPrefix($ns)) { 
  929. $ns = $this->getNamespaceFromPrefix($ns); 
  930. $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); 
  931. } else { 
  932. // TODO: should the type be compared to types in XSD, and the namespace 
  933. // set to XSD if the type matches? 
  934. $this->debug("in parametersMatchWrapped: No namespace for type $type"); 
  935. $ns = ''; 
  936. $uqType = $type; 
  937.  
  938. // get the type information 
  939. if (!$typeDef = $this->getTypeDef($uqType, $ns)) { 
  940. $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); 
  941. return false; 
  942. $this->debug("in parametersMatchWrapped: found typeDef="); 
  943. $this->appendDebug($this->varDump($typeDef)); 
  944. if (substr($uqType, -1) == '^') { 
  945. $uqType = substr($uqType, 0, -1); 
  946. $phpType = $typeDef['phpType']; 
  947. $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); 
  948. $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); 
  949.  
  950. // we expect a complexType or element of complexType 
  951. if ($phpType != 'struct') { 
  952. $this->debug("in parametersMatchWrapped: not a struct"); 
  953. return false; 
  954.  
  955. // see whether the parameter names match the elements 
  956. if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 
  957. $elements = 0; 
  958. $matches = 0; 
  959. foreach ($typeDef['elements'] as $name => $attrs) { 
  960. if (isset($parameters[$name])) { 
  961. $this->debug("in parametersMatchWrapped: have parameter named $name"); 
  962. $matches++; 
  963. } else { 
  964. $this->debug("in parametersMatchWrapped: do not have parameter named $name"); 
  965. $elements++; 
  966.  
  967. $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); 
  968. if ($matches == 0) { 
  969. return false; 
  970. return true; 
  971.  
  972. // since there are no elements for the type, if the user passed no 
  973. // parameters, the parameters match wrapped. 
  974. $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); 
  975. return count($parameters) == 0; 
  976.  
  977. /** 
  978. * serialize PHP values according to a WSDL message definition 
  979. * contrary to the method name, this is not limited to RPC 
  980. * TODO 
  981. * - multi-ref serialization 
  982. * - validate PHP values against type definitions, return errors if invalid 
  983. *  
  984. * @param string $operation operation name 
  985. * @param string $direction (input|output) 
  986. * @param mixed $parameters parameter value(s) 
  987. * @param string $bindingType (soap|soap12) 
  988. * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 
  989. * @access public 
  990. */ 
  991. function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { 
  992. $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); 
  993. $this->appendDebug('parameters=' . $this->varDump($parameters)); 
  994.  
  995. if ($direction != 'input' && $direction != 'output') { 
  996. $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 
  997. $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 
  998. return false; 
  999. }  
  1000. if (!$opData = $this->getOperationData($operation, $bindingType)) { 
  1001. $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 
  1002. $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 
  1003. return false; 
  1004. $this->debug('in serializeRPCParameters: opData:'); 
  1005. $this->appendDebug($this->varDump($opData)); 
  1006.  
  1007. // Get encoding style for output and set to current 
  1008. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1009. if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 
  1010. $encodingStyle = $opData['output']['encodingStyle']; 
  1011. $enc_style = $encodingStyle; 
  1012.  
  1013. // set input params 
  1014. $xml = ''; 
  1015. if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 
  1016. $parts = &$opData[$direction]['parts']; 
  1017. $part_count = sizeof($parts); 
  1018. $style = $opData['style']; 
  1019. $use = $opData[$direction]['use']; 
  1020. $this->debug("have $part_count part(s) to serialize using $style/$use"); 
  1021. if (is_array($parameters)) { 
  1022. $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 
  1023. $parameter_count = count($parameters); 
  1024. $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); 
  1025. // check for Microsoft-style wrapped parameters 
  1026. if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { 
  1027. $this->debug('check whether the caller has wrapped the parameters'); 
  1028. if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { 
  1029. // TODO: consider checking here for double-wrapping, when 
  1030. // service function wraps, then NuSOAP wraps again 
  1031. $this->debug("change simple array to associative with 'parameters' element"); 
  1032. $parameters['parameters'] = $parameters[0]; 
  1033. unset($parameters[0]); 
  1034. if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { 
  1035. $this->debug('check whether caller\'s parameters match the wrapped ones'); 
  1036. if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { 
  1037. $this->debug('wrap the parameters for the caller'); 
  1038. $parameters = array('parameters' => $parameters); 
  1039. $parameter_count = 1; 
  1040. foreach ($parts as $name => $type) { 
  1041. $this->debug("serializing part $name of type $type"); 
  1042. // Track encoding style 
  1043. if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 
  1044. $encodingStyle = $opData[$direction]['encodingStyle'];  
  1045. $enc_style = $encodingStyle; 
  1046. } else { 
  1047. $enc_style = false; 
  1048. // NOTE: add error handling here 
  1049. // if serializeType returns false, then catch global error and fault 
  1050. if ($parametersArrayType == 'arraySimple') { 
  1051. $p = array_shift($parameters); 
  1052. $this->debug('calling serializeType w/indexed param'); 
  1053. $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 
  1054. } elseif (isset($parameters[$name])) { 
  1055. $this->debug('calling serializeType w/named param'); 
  1056. $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 
  1057. } else { 
  1058. // TODO: only send nillable 
  1059. $this->debug('calling serializeType w/null param'); 
  1060. $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 
  1061. } else { 
  1062. $this->debug('no parameters passed.'); 
  1063. $this->debug("serializeRPCParameters returning: $xml"); 
  1064. return $xml; 
  1065. }  
  1066.  
  1067. /** 
  1068. * serialize a PHP value according to a WSDL message definition 
  1069. *  
  1070. * TODO 
  1071. * - multi-ref serialization 
  1072. * - validate PHP values against type definitions, return errors if invalid 
  1073. *  
  1074. * @param string $operation operation name 
  1075. * @param string $direction (input|output) 
  1076. * @param mixed $parameters parameter value(s) 
  1077. * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 
  1078. * @access public 
  1079. * @deprecated 
  1080. */ 
  1081. function serializeParameters($operation, $direction, $parameters) 
  1082. $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");  
  1083. $this->appendDebug('parameters=' . $this->varDump($parameters)); 
  1084.  
  1085. if ($direction != 'input' && $direction != 'output') { 
  1086. $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 
  1087. $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 
  1088. return false; 
  1089. }  
  1090. if (!$opData = $this->getOperationData($operation)) { 
  1091. $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 
  1092. $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 
  1093. return false; 
  1094. $this->debug('opData:'); 
  1095. $this->appendDebug($this->varDump($opData)); 
  1096.  
  1097. // Get encoding style for output and set to current 
  1098. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1099. if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 
  1100. $encodingStyle = $opData['output']['encodingStyle']; 
  1101. $enc_style = $encodingStyle; 
  1102.  
  1103. // set input params 
  1104. $xml = ''; 
  1105. if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 
  1106.  
  1107. $use = $opData[$direction]['use']; 
  1108. $this->debug("use=$use"); 
  1109. $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 
  1110. if (is_array($parameters)) { 
  1111. $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 
  1112. $this->debug('have ' . $parametersArrayType . ' parameters'); 
  1113. foreach($opData[$direction]['parts'] as $name => $type) { 
  1114. $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 
  1115. // Track encoding style 
  1116. if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 
  1117. $encodingStyle = $opData[$direction]['encodingStyle'];  
  1118. $enc_style = $encodingStyle; 
  1119. } else { 
  1120. $enc_style = false; 
  1121. // NOTE: add error handling here 
  1122. // if serializeType returns false, then catch global error and fault 
  1123. if ($parametersArrayType == 'arraySimple') { 
  1124. $p = array_shift($parameters); 
  1125. $this->debug('calling serializeType w/indexed param'); 
  1126. $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 
  1127. } elseif (isset($parameters[$name])) { 
  1128. $this->debug('calling serializeType w/named param'); 
  1129. $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 
  1130. } else { 
  1131. // TODO: only send nillable 
  1132. $this->debug('calling serializeType w/null param'); 
  1133. $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 
  1134. } else { 
  1135. $this->debug('no parameters passed.'); 
  1136. $this->debug("serializeParameters returning: $xml"); 
  1137. return $xml; 
  1138. }  
  1139.  
  1140. /** 
  1141. * serializes a PHP value according a given type definition 
  1142. *  
  1143. * @param string $name name of value (part or element) 
  1144. * @param string $type XML schema type of value (type or element) 
  1145. * @param mixed $value a native PHP value (parameter value) 
  1146. * @param string $use use for part (encoded|literal) 
  1147. * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 
  1148. * @param boolean $unqualified a kludge for what should be XML namespace form handling 
  1149. * @return string value serialized as an XML string 
  1150. * @access private 
  1151. */ 
  1152. function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 
  1153. $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 
  1154. $this->appendDebug("value=" . $this->varDump($value)); 
  1155. if($use == 'encoded' && $encodingStyle) { 
  1156. $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 
  1157.  
  1158. // if a soapval has been supplied, let its type override the WSDL 
  1159. if (is_object($value) && get_class($value) == 'soapval') { 
  1160. if ($value->type_ns) { 
  1161. $type = $value->type_ns . ':' . $value->type; 
  1162. $forceType = true; 
  1163. $this->debug("in serializeType: soapval overrides type to $type"); 
  1164. } elseif ($value->type) { 
  1165. $type = $value->type; 
  1166. $forceType = true; 
  1167. $this->debug("in serializeType: soapval overrides type to $type"); 
  1168. } else { 
  1169. $forceType = false; 
  1170. $this->debug("in serializeType: soapval does not override type"); 
  1171. $attrs = $value->attributes; 
  1172. $value = $value->value; 
  1173. $this->debug("in serializeType: soapval overrides value to $value"); 
  1174. if ($attrs) { 
  1175. if (!is_array($value)) { 
  1176. $value['!'] = $value; 
  1177. foreach ($attrs as $n => $v) { 
  1178. $value['!' . $n] = $v; 
  1179. $this->debug("in serializeType: soapval provides attributes"); 
  1180. } else { 
  1181. $forceType = false; 
  1182.  
  1183. $xml = ''; 
  1184. if (strpos($type, ':')) { 
  1185. $uqType = substr($type, strrpos($type, ':') + 1); 
  1186. $ns = substr($type, 0, strrpos($type, ':')); 
  1187. $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 
  1188. if ($this->getNamespaceFromPrefix($ns)) { 
  1189. $ns = $this->getNamespaceFromPrefix($ns); 
  1190. $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 
  1191.  
  1192. if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') { 
  1193. $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 
  1194. if ($unqualified && $use == 'literal') { 
  1195. $elementNS = " xmlns=\"\""; 
  1196. } else { 
  1197. $elementNS = ''; 
  1198. if (is_null($value)) { 
  1199. if ($use == 'literal') { 
  1200. // TODO: depends on minOccurs 
  1201. $xml = "<$name$elementNS/>"; 
  1202. } else { 
  1203. // TODO: depends on nillable, which should be checked before calling this method 
  1204. $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 
  1205. $this->debug("in serializeType: returning: $xml"); 
  1206. return $xml; 
  1207. if ($uqType == 'Array') { 
  1208. // JBoss/Axis does this sometimes 
  1209. return $this->serialize_val($value, $name, false, false, false, false, $use); 
  1210. if ($uqType == 'boolean') { 
  1211. if ((is_string($value) && $value == 'false') || (! $value)) { 
  1212. $value = 'false'; 
  1213. } else { 
  1214. $value = 'true'; 
  1215. }  
  1216. if ($uqType == 'string' && gettype($value) == 'string') { 
  1217. $value = $this->expandEntities($value); 
  1218. if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 
  1219. $value = sprintf("%.0lf", $value); 
  1220. // it's a scalar 
  1221. // TODO: what about null/nil values? 
  1222. // check type isn't a custom type extending xmlschema namespace 
  1223. if (!$this->getTypeDef($uqType, $ns)) { 
  1224. if ($use == 'literal') { 
  1225. if ($forceType) { 
  1226. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 
  1227. } else { 
  1228. $xml = "<$name$elementNS>$value</$name>"; 
  1229. } else { 
  1230. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 
  1231. $this->debug("in serializeType: returning: $xml"); 
  1232. return $xml; 
  1233. $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 
  1234. } else if ($ns == 'http://xml.apache.org/xml-soap') { 
  1235. $this->debug('in serializeType: appears to be Apache SOAP type'); 
  1236. if ($uqType == 'Map') { 
  1237. $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 
  1238. if (! $tt_prefix) { 
  1239. $this->debug('in serializeType: Add namespace for Apache SOAP type'); 
  1240. $tt_prefix = 'ns' . rand(1000, 9999); 
  1241. $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 
  1242. // force this to be added to usedNamespaces 
  1243. $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 
  1244. $contents = ''; 
  1245. foreach($value as $k => $v) { 
  1246. $this->debug("serializing map element: key $k, value $v"); 
  1247. $contents .= '<item>'; 
  1248. $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use); 
  1249. $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use); 
  1250. $contents .= '</item>'; 
  1251. if ($use == 'literal') { 
  1252. if ($forceType) { 
  1253. $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 
  1254. } else { 
  1255. $xml = "<$name>$contents</$name>"; 
  1256. } else { 
  1257. $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 
  1258. $this->debug("in serializeType: returning: $xml"); 
  1259. return $xml; 
  1260. $this->debug('in serializeType: Apache SOAP type, but only support Map'); 
  1261. } else { 
  1262. // TODO: should the type be compared to types in XSD, and the namespace 
  1263. // set to XSD if the type matches? 
  1264. $this->debug("in serializeType: No namespace for type $type"); 
  1265. $ns = ''; 
  1266. $uqType = $type; 
  1267. if(!$typeDef = $this->getTypeDef($uqType, $ns)) { 
  1268. $this->setError("$type ($uqType) is not a supported type."); 
  1269. $this->debug("in serializeType: $type ($uqType) is not a supported type."); 
  1270. return false; 
  1271. } else { 
  1272. $this->debug("in serializeType: found typeDef"); 
  1273. $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 
  1274. if (substr($uqType, -1) == '^') { 
  1275. $uqType = substr($uqType, 0, -1); 
  1276. if (!isset($typeDef['phpType'])) { 
  1277. $this->setError("$type ($uqType) has no phpType."); 
  1278. $this->debug("in serializeType: $type ($uqType) has no phpType."); 
  1279. return false; 
  1280. $phpType = $typeDef['phpType']; 
  1281. $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );  
  1282. // if php type == struct, map value to the <all> element names 
  1283. if ($phpType == 'struct') { 
  1284. if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 
  1285. $elementName = $uqType; 
  1286. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1287. $elementNS = " xmlns=\"$ns\""; 
  1288. } else { 
  1289. $elementNS = " xmlns=\"\""; 
  1290. } else { 
  1291. $elementName = $name; 
  1292. if ($unqualified) { 
  1293. $elementNS = " xmlns=\"\""; 
  1294. } else { 
  1295. $elementNS = ''; 
  1296. if (is_null($value)) { 
  1297. if ($use == 'literal') { 
  1298. // TODO: depends on minOccurs and nillable 
  1299. $xml = "<$elementName$elementNS/>"; 
  1300. } else { 
  1301. $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 
  1302. $this->debug("in serializeType: returning: $xml"); 
  1303. return $xml; 
  1304. if (is_object($value)) { 
  1305. $value = get_object_vars($value); 
  1306. if (is_array($value)) { 
  1307. $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 
  1308. if ($use == 'literal') { 
  1309. if ($forceType) { 
  1310. $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 
  1311. } else { 
  1312. $xml = "<$elementName$elementNS$elementAttrs>"; 
  1313. } else { 
  1314. $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 
  1315.  
  1316. if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { 
  1317. if (isset($value['!'])) { 
  1318. $xml .= $value['!']; 
  1319. $this->debug("in serializeType: serialized simpleContent for type $type"); 
  1320. } else { 
  1321. $this->debug("in serializeType: no simpleContent to serialize for type $type"); 
  1322. } else { 
  1323. // complexContent 
  1324. $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 
  1325. $xml .= "</$elementName>"; 
  1326. } else { 
  1327. $this->debug("in serializeType: phpType is struct, but value is not an array"); 
  1328. $this->setError("phpType is struct, but value is not an array: see debug output for details"); 
  1329. $xml = ''; 
  1330. } elseif ($phpType == 'array') { 
  1331. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1332. $elementNS = " xmlns=\"$ns\""; 
  1333. } else { 
  1334. if ($unqualified) { 
  1335. $elementNS = " xmlns=\"\""; 
  1336. } else { 
  1337. $elementNS = ''; 
  1338. if (is_null($value)) { 
  1339. if ($use == 'literal') { 
  1340. // TODO: depends on minOccurs 
  1341. $xml = "<$name$elementNS/>"; 
  1342. } else { 
  1343. $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 
  1344. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 
  1345. ":Array\" " . 
  1346. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 
  1347. ':arrayType="' . 
  1348. $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 
  1349. ':' . 
  1350. $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 
  1351. $this->debug("in serializeType: returning: $xml"); 
  1352. return $xml; 
  1353. if (isset($typeDef['multidimensional'])) { 
  1354. $nv = array(); 
  1355. foreach($value as $v) { 
  1356. $cols = ', ' . sizeof($v); 
  1357. $nv = array_merge($nv, $v); 
  1358. }  
  1359. $value = $nv; 
  1360. } else { 
  1361. $cols = ''; 
  1362. }  
  1363. if (is_array($value) && sizeof($value) >= 1) { 
  1364. $rows = sizeof($value); 
  1365. $contents = ''; 
  1366. foreach($value as $k => $v) { 
  1367. $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 
  1368. //if (strpos($typeDef['arrayType'], ':') ) { 
  1369. if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) { 
  1370. $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 
  1371. } else { 
  1372. $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 
  1373. }  
  1374. } else { 
  1375. $rows = 0; 
  1376. $contents = null; 
  1377. // TODO: for now, an empty value will be serialized as a zero element 
  1378. // array. Revisit this when coding the handling of null/nil values. 
  1379. if ($use == 'literal') { 
  1380. $xml = "<$name$elementNS>" 
  1381. .$contents 
  1382. ."</$name>"; 
  1383. } else { 
  1384. $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 
  1385. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 
  1386. .':arrayType="' 
  1387. .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 
  1388. .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 
  1389. .$contents 
  1390. ."</$name>"; 
  1391. } elseif ($phpType == 'scalar') { 
  1392. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1393. $elementNS = " xmlns=\"$ns\""; 
  1394. } else { 
  1395. if ($unqualified) { 
  1396. $elementNS = " xmlns=\"\""; 
  1397. } else { 
  1398. $elementNS = ''; 
  1399. if ($use == 'literal') { 
  1400. if ($forceType) { 
  1401. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 
  1402. } else { 
  1403. $xml = "<$name$elementNS>$value</$name>"; 
  1404. } else { 
  1405. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 
  1406. $this->debug("in serializeType: returning: $xml"); 
  1407. return $xml; 
  1408.  
  1409. /** 
  1410. * serializes the attributes for a complexType 
  1411. * @param array $typeDef our internal representation of an XML schema type (or element) 
  1412. * @param mixed $value a native PHP value (parameter value) 
  1413. * @param string $ns the namespace of the type 
  1414. * @param string $uqType the local part of the type 
  1415. * @return string value serialized as an XML string 
  1416. * @access private 
  1417. */ 
  1418. function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 
  1419. $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); 
  1420. $xml = ''; 
  1421. if (isset($typeDef['extensionBase'])) { 
  1422. $nsx = $this->getPrefix($typeDef['extensionBase']); 
  1423. $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 
  1424. if ($this->getNamespaceFromPrefix($nsx)) { 
  1425. $nsx = $this->getNamespaceFromPrefix($nsx); 
  1426. if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 
  1427. $this->debug("serialize attributes for extension base $nsx:$uqTypex"); 
  1428. $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); 
  1429. } else { 
  1430. $this->debug("extension base $nsx:$uqTypex is not a supported type"); 
  1431. if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 
  1432. $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 
  1433. if (is_array($value)) { 
  1434. $xvalue = $value; 
  1435. } elseif (is_object($value)) { 
  1436. $xvalue = get_object_vars($value); 
  1437. } else { 
  1438. $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 
  1439. $xvalue = array(); 
  1440. foreach ($typeDef['attrs'] as $aName => $attrs) { 
  1441. if (isset($xvalue['!' . $aName])) { 
  1442. $xname = '!' . $aName; 
  1443. $this->debug("value provided for attribute $aName with key $xname"); 
  1444. } elseif (isset($xvalue[$aName])) { 
  1445. $xname = $aName; 
  1446. $this->debug("value provided for attribute $aName with key $xname"); 
  1447. } elseif (isset($attrs['default'])) { 
  1448. $xname = '!' . $aName; 
  1449. $xvalue[$xname] = $attrs['default']; 
  1450. $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 
  1451. } else { 
  1452. $xname = ''; 
  1453. $this->debug("no value provided for attribute $aName"); 
  1454. if ($xname) { 
  1455. $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 
  1456. }  
  1457. } else { 
  1458. $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 
  1459. return $xml; 
  1460.  
  1461. /** 
  1462. * serializes the elements for a complexType 
  1463. * @param array $typeDef our internal representation of an XML schema type (or element) 
  1464. * @param mixed $value a native PHP value (parameter value) 
  1465. * @param string $ns the namespace of the type 
  1466. * @param string $uqType the local part of the type 
  1467. * @param string $use use for part (encoded|literal) 
  1468. * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 
  1469. * @return string value serialized as an XML string 
  1470. * @access private 
  1471. */ 
  1472. function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 
  1473. $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); 
  1474. $xml = ''; 
  1475. if (isset($typeDef['extensionBase'])) { 
  1476. $nsx = $this->getPrefix($typeDef['extensionBase']); 
  1477. $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 
  1478. if ($this->getNamespaceFromPrefix($nsx)) { 
  1479. $nsx = $this->getNamespaceFromPrefix($nsx); 
  1480. if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 
  1481. $this->debug("serialize elements for extension base $nsx:$uqTypex"); 
  1482. $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); 
  1483. } else { 
  1484. $this->debug("extension base $nsx:$uqTypex is not a supported type"); 
  1485. if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 
  1486. $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 
  1487. if (is_array($value)) { 
  1488. $xvalue = $value; 
  1489. } elseif (is_object($value)) { 
  1490. $xvalue = get_object_vars($value); 
  1491. } else { 
  1492. $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 
  1493. $xvalue = array(); 
  1494. // toggle whether all elements are present - ideally should validate against schema 
  1495. if (count($typeDef['elements']) != count($xvalue)) { 
  1496. $optionals = true; 
  1497. foreach ($typeDef['elements'] as $eName => $attrs) { 
  1498. if (!isset($xvalue[$eName])) { 
  1499. if (isset($attrs['default'])) { 
  1500. $xvalue[$eName] = $attrs['default']; 
  1501. $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 
  1502. // if user took advantage of a minOccurs=0, then only serialize named parameters 
  1503. if (isset($optionals) 
  1504. && (!isset($xvalue[$eName]))  
  1505. && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 
  1506. ) { 
  1507. if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 
  1508. $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 
  1509. // do nothing 
  1510. $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 
  1511. } else { 
  1512. // get value 
  1513. if (isset($xvalue[$eName])) { 
  1514. $v = $xvalue[$eName]; 
  1515. } else { 
  1516. $v = null; 
  1517. if (isset($attrs['form'])) { 
  1518. $unqualified = ($attrs['form'] == 'unqualified'); 
  1519. } else { 
  1520. $unqualified = false; 
  1521. if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 
  1522. $vv = $v; 
  1523. foreach ($vv as $k => $v) { 
  1524. if (isset($attrs['type']) || isset($attrs['ref'])) { 
  1525. // serialize schema-defined type 
  1526. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1527. } else { 
  1528. // serialize generic type (can this ever really happen?) 
  1529. $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 
  1530. $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 
  1531. } else { 
  1532. if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { 
  1533. // do nothing 
  1534. } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { 
  1535. // TODO: serialize a nil correctly, but for now serialize schema-defined type 
  1536. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1537. } elseif (isset($attrs['type']) || isset($attrs['ref'])) { 
  1538. // serialize schema-defined type 
  1539. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1540. } else { 
  1541. // serialize generic type (can this ever really happen?) 
  1542. $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 
  1543. $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 
  1544. }  
  1545. } else { 
  1546. $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 
  1547. return $xml; 
  1548.  
  1549. /** 
  1550. * adds an XML Schema complex type to the WSDL types 
  1551. * @param string $name 
  1552. * @param string $typeClass (complexType|simpleType|attribute) 
  1553. * @param string $phpType currently supported are array and struct (php assoc array) 
  1554. * @param string $compositor (all|sequence|choice) 
  1555. * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 
  1556. * @param array $elements e.g. array ( name => array(name=>'', type=>'') ) 
  1557. * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType', 'wsdl:arrayType'=>'xsd:string[]')) 
  1558. * @param string $arrayType as namespace:name (xsd:string) 
  1559. * @see nusoap_xmlschema 
  1560. * @access public 
  1561. */ 
  1562. function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=array(), $attrs=array(), $arrayType='') { 
  1563. if (count($elements) > 0) { 
  1564. $eElements = array(); 
  1565. foreach($elements as $n => $e) { 
  1566. // expand each element 
  1567. $ee = array(); 
  1568. foreach ($e as $k => $v) { 
  1569. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  1570. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  1571. $ee[$k] = $v; 
  1572. $eElements[$n] = $ee; 
  1573. $elements = $eElements; 
  1574.  
  1575. if (count($attrs) > 0) { 
  1576. foreach($attrs as $n => $a) { 
  1577. // expand each attribute 
  1578. foreach ($a as $k => $v) { 
  1579. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  1580. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  1581. $aa[$k] = $v; 
  1582. $eAttrs[$n] = $aa; 
  1583. $attrs = $eAttrs; 
  1584.  
  1585. $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; 
  1586. $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType; 
  1587.  
  1588. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1589. $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType); 
  1590.  
  1591. /** 
  1592. * adds an XML Schema simple type to the WSDL types 
  1593. * @param string $name 
  1594. * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 
  1595. * @param string $typeClass (should always be simpleType) 
  1596. * @param string $phpType (should always be scalar) 
  1597. * @param array $enumeration array of values 
  1598. * @see nusoap_xmlschema 
  1599. * @access public 
  1600. */ 
  1601. function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 
  1602. $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; 
  1603.  
  1604. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1605. $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 
  1606.  
  1607. /** 
  1608. * adds an element to the WSDL types 
  1609. * @param array $attrs attributes that must include name and type 
  1610. * @see nusoap_xmlschema 
  1611. * @access public 
  1612. */ 
  1613. function addElement($attrs) { 
  1614. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1615. $this->schemas[$typens][0]->addElement($attrs); 
  1616.  
  1617. /** 
  1618. * register an operation with the server 
  1619. *  
  1620. * @param string $name operation (method) name 
  1621. * @param array $in assoc array of input values: key = param name, value = param type 
  1622. * @param array $out assoc array of output values: key = param name, value = param type 
  1623. * @param string $namespace optional The namespace for the operation 
  1624. * @param string $soapaction optional The soapaction for the operation 
  1625. * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically 
  1626. * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) 
  1627. * @param string $documentation optional The description to include in the WSDL 
  1628. * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 
  1629. * @access public  
  1630. */ 
  1631. function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '') { 
  1632. if ($use == 'encoded' && $encodingStyle == '') { 
  1633. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1634.  
  1635. if ($style == 'document') { 
  1636. $elements = array(); 
  1637. foreach ($in as $n => $t) { 
  1638. $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 
  1639. $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 
  1640. $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 
  1641. $in = array('parameters' => 'tns:' . $name . '^'); 
  1642.  
  1643. $elements = array(); 
  1644. foreach ($out as $n => $t) { 
  1645. $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 
  1646. $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 
  1647. $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); 
  1648. $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); 
  1649.  
  1650. // get binding 
  1651. $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 
  1652. array( 
  1653. 'name' => $name,  
  1654. 'binding' => $this->serviceName . 'Binding',  
  1655. 'endpoint' => $this->endpoint,  
  1656. 'soapAction' => $soapaction,  
  1657. 'style' => $style,  
  1658. 'input' => array( 
  1659. 'use' => $use,  
  1660. 'namespace' => $namespace,  
  1661. 'encodingStyle' => $encodingStyle,  
  1662. 'message' => $name . 'Request',  
  1663. 'parts' => $in),  
  1664. 'output' => array( 
  1665. 'use' => $use,  
  1666. 'namespace' => $namespace,  
  1667. 'encodingStyle' => $encodingStyle,  
  1668. 'message' => $name . 'Response',  
  1669. 'parts' => $out),  
  1670. 'namespace' => $namespace,  
  1671. 'transport' => 'http://schemas.xmlsoap.org/soap/http',  
  1672. 'documentation' => $documentation);  
  1673. // add portTypes 
  1674. // add messages 
  1675. if($in) 
  1676. foreach($in as $pName => $pType) 
  1677. if(strpos($pType, ':')) { 
  1678. $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 
  1679. $this->messages[$name.'Request'][$pName] = $pType; 
  1680. } else { 
  1681. $this->messages[$name.'Request']= '0'; 
  1682. if($out) 
  1683. foreach($out as $pName => $pType) 
  1684. if(strpos($pType, ':')) { 
  1685. $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 
  1686. $this->messages[$name.'Response'][$pName] = $pType; 
  1687. } else { 
  1688. $this->messages[$name.'Response']= '0'; 
  1689. return true; 
  1690. }  
/lib/nusoap.php  
  1. class wsdl extends nusoap_base { 
  2. // URL or filename of the root of this WSDL 
  3. var $wsdl;  
  4. // define internal arrays of bindings, ports, operations, messages, etc. 
  5. var $schemas = array(); 
  6. var $currentSchema; 
  7. var $message = array(); 
  8. var $complexTypes = array(); 
  9. var $messages = array(); 
  10. var $currentMessage; 
  11. var $currentOperation; 
  12. var $portTypes = array(); 
  13. var $currentPortType; 
  14. var $bindings = array(); 
  15. var $currentBinding; 
  16. var $ports = array(); 
  17. var $currentPort; 
  18. var $opData = array(); 
  19. var $status = ''; 
  20. var $documentation = false; 
  21. var $endpoint = '';  
  22. // array of wsdl docs to import 
  23. var $import = array();  
  24. // parser vars 
  25. var $parser; 
  26. var $position = 0; 
  27. var $depth = 0; 
  28. var $depth_array = array(); 
  29. // for getting wsdl 
  30. var $proxyhost = ''; 
  31. var $proxyport = ''; 
  32. var $proxyusername = ''; 
  33. var $proxypassword = ''; 
  34. var $timeout = 0; 
  35. var $response_timeout = 30; 
  36. var $curl_options = array(); // User-specified cURL options 
  37. var $use_curl = false; // whether to always try to use cURL 
  38. // for HTTP authentication 
  39. var $username = ''; // Username for HTTP authentication 
  40. var $password = ''; // Password for HTTP authentication 
  41. var $authtype = ''; // Type of HTTP authentication 
  42. var $certRequest = array(); // Certificate for HTTP SSL authentication 
  43.  
  44. /** 
  45. * constructor 
  46. *  
  47. * @param string $wsdl WSDL document URL 
  48. * @param string $proxyhost 
  49. * @param string $proxyport 
  50. * @param string $proxyusername 
  51. * @param string $proxypassword 
  52. * @param integer $timeout set the connection timeout 
  53. * @param integer $response_timeout set the response timeout 
  54. * @param array $curl_options user-specified cURL options 
  55. * @param boolean $use_curl try to use cURL 
  56. * @access public  
  57. */ 
  58. function wsdl($wsdl = '', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $curl_options=null, $use_curl=false) { 
  59. parent::nusoap_base(); 
  60. $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 
  61. $this->proxyhost = $proxyhost; 
  62. $this->proxyport = $proxyport; 
  63. $this->proxyusername = $proxyusername; 
  64. $this->proxypassword = $proxypassword; 
  65. $this->timeout = $timeout; 
  66. $this->response_timeout = $response_timeout; 
  67. if (is_array($curl_options)) 
  68. $this->curl_options = $curl_options; 
  69. $this->use_curl = $use_curl; 
  70. $this->fetchWSDL($wsdl); 
  71.  
  72. /** 
  73. * fetches the WSDL document and parses it 
  74. * @access public 
  75. */ 
  76. function fetchWSDL($wsdl) { 
  77. $this->debug("parse and process WSDL path=$wsdl"); 
  78. $this->wsdl = $wsdl; 
  79. // parse wsdl file 
  80. if ($this->wsdl != "") { 
  81. $this->parseWSDL($this->wsdl); 
  82. // imports 
  83. // TODO: handle imports more properly, grabbing them in-line and nesting them 
  84. $imported_urls = array(); 
  85. $imported = 1; 
  86. while ($imported > 0) { 
  87. $imported = 0; 
  88. // Schema imports 
  89. foreach ($this->schemas as $ns => $list) { 
  90. foreach ($list as $xs) { 
  91. $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 
  92. foreach ($xs->imports as $ns2 => $list2) { 
  93. for ($ii = 0; $ii < count($list2); $ii++) { 
  94. if (! $list2[$ii]['loaded']) { 
  95. $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 
  96. $url = $list2[$ii]['location']; 
  97. if ($url != '') { 
  98. $urlparts = parse_url($url); 
  99. if (!isset($urlparts['host'])) { 
  100. $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 
  101. substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path']; 
  102. if (! in_array($url, $imported_urls)) { 
  103. $this->parseWSDL($url); 
  104. $imported++; 
  105. $imported_urls[] = $url; 
  106. } else { 
  107. $this->debug("Unexpected scenario: empty URL for unloaded import"); 
  108. }  
  109. // WSDL imports 
  110. $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 
  111. foreach ($this->import as $ns => $list) { 
  112. for ($ii = 0; $ii < count($list); $ii++) { 
  113. if (! $list[$ii]['loaded']) { 
  114. $this->import[$ns][$ii]['loaded'] = true; 
  115. $url = $list[$ii]['location']; 
  116. if ($url != '') { 
  117. $urlparts = parse_url($url); 
  118. if (!isset($urlparts['host'])) { 
  119. $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 
  120. substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path']; 
  121. if (! in_array($url, $imported_urls)) { 
  122. $this->parseWSDL($url); 
  123. $imported++; 
  124. $imported_urls[] = $url; 
  125. } else { 
  126. $this->debug("Unexpected scenario: empty URL for unloaded import"); 
  127. }  
  128. // add new data to operation data 
  129. foreach($this->bindings as $binding => $bindingData) { 
  130. if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 
  131. foreach($bindingData['operations'] as $operation => $data) { 
  132. $this->debug('post-parse data gathering for ' . $operation); 
  133. $this->bindings[$binding]['operations'][$operation]['input'] =  
  134. isset($this->bindings[$binding]['operations'][$operation]['input']) ?  
  135. array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 
  136. $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 
  137. $this->bindings[$binding]['operations'][$operation]['output'] =  
  138. isset($this->bindings[$binding]['operations'][$operation]['output']) ? 
  139. array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 
  140. $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 
  141. if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])) { 
  142. $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 
  143. if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])) { 
  144. $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 
  145. // Set operation style if necessary, but do not override one already provided 
  146. if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { 
  147. $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 
  148. $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 
  149. $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 
  150. $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 
  151. }  
  152. }  
  153.  
  154. /** 
  155. * parses the wsdl document 
  156. *  
  157. * @param string $wsdl path or URL 
  158. * @access private  
  159. */ 
  160. function parseWSDL($wsdl = '') { 
  161. $this->debug("parse WSDL at path=$wsdl"); 
  162.  
  163. if ($wsdl == '') { 
  164. $this->debug('no wsdl passed to parseWSDL()!!'); 
  165. $this->setError('no wsdl passed to parseWSDL()!!'); 
  166. return false; 
  167.  
  168. // parse $wsdl for url format 
  169. $wsdl_props = parse_url($wsdl); 
  170.  
  171. if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 
  172. $this->debug('getting WSDL http(s) URL ' . $wsdl); 
  173. // get wsdl 
  174. $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); 
  175. $tr->request_method = 'GET'; 
  176. $tr->useSOAPAction = false; 
  177. if($this->proxyhost && $this->proxyport) { 
  178. $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword); 
  179. if ($this->authtype != '') { 
  180. $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 
  181. $tr->setEncoding('gzip, deflate'); 
  182. $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 
  183. //$this->debug("WSDL request\n" . $tr->outgoing_payload); 
  184. //$this->debug("WSDL response\n" . $tr->incoming_payload); 
  185. $this->appendDebug($tr->getDebug()); 
  186. // catch errors 
  187. if($err = $tr->getError() ) { 
  188. $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; 
  189. $this->debug($errstr); 
  190. $this->setError($errstr); 
  191. unset($tr); 
  192. return false; 
  193. unset($tr); 
  194. $this->debug("got WSDL URL"); 
  195. } else { 
  196. // $wsdl is not http(s), so treat it as a file URL or plain file path 
  197. if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 
  198. $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 
  199. } else { 
  200. $path = $wsdl; 
  201. $this->debug('getting WSDL file ' . $path); 
  202. if ($fp = @fopen($path, 'r')) { 
  203. $wsdl_string = ''; 
  204. while ($data = fread($fp, 32768)) { 
  205. $wsdl_string .= $data; 
  206. }  
  207. fclose($fp); 
  208. } else { 
  209. $errstr = "Bad path to WSDL file $path"; 
  210. $this->debug($errstr); 
  211. $this->setError($errstr); 
  212. return false; 
  213. }  
  214. $this->debug('Parse WSDL'); 
  215. // end new code added 
  216. // Create an XML parser. 
  217. $this->parser = xml_parser_create();  
  218. // Set the options for parsing the XML data. 
  219. // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
  220. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);  
  221. // Set the object for the parser. 
  222. xml_set_object($this->parser, $this);  
  223. // Set the element handlers for the parser. 
  224. xml_set_element_handler($this->parser, 'start_element', 'end_element'); 
  225. xml_set_character_data_handler($this->parser, 'character_data'); 
  226. // Parse the XML file. 
  227. if (!xml_parse($this->parser, $wsdl_string, true)) { 
  228. // Display an error message. 
  229. $errstr = sprintf( 
  230. 'XML error parsing WSDL from %s on line %d: %s',  
  231. $wsdl,  
  232. xml_get_current_line_number($this->parser),  
  233. xml_error_string(xml_get_error_code($this->parser)) 
  234. ); 
  235. $this->debug($errstr); 
  236. $this->debug("XML payload:\n" . $wsdl_string); 
  237. $this->setError($errstr); 
  238. return false; 
  239. }  
  240. // free the parser 
  241. xml_parser_free($this->parser); 
  242. $this->debug('Parsing WSDL done'); 
  243. // catch wsdl parse errors 
  244. if($this->getError()) { 
  245. return false; 
  246. return true; 
  247. }  
  248.  
  249. /** 
  250. * start-element handler 
  251. *  
  252. * @param string $parser XML parser object 
  253. * @param string $name element name 
  254. * @param string $attrs associative array of attributes 
  255. * @access private  
  256. */ 
  257. function start_element($parser, $name, $attrs) 
  258. if ($this->status == 'schema') { 
  259. $this->currentSchema->schemaStartElement($parser, $name, $attrs); 
  260. $this->appendDebug($this->currentSchema->getDebug()); 
  261. $this->currentSchema->clearDebug(); 
  262. } elseif (preg_match('/schema$/', $name)) { 
  263. $this->debug('Parsing WSDL schema'); 
  264. // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 
  265. $this->status = 'schema'; 
  266. $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); 
  267. $this->currentSchema->schemaStartElement($parser, $name, $attrs); 
  268. $this->appendDebug($this->currentSchema->getDebug()); 
  269. $this->currentSchema->clearDebug(); 
  270. } else { 
  271. // position in the total number of elements, starting from 0 
  272. $pos = $this->position++; 
  273. $depth = $this->depth++;  
  274. // set self as current value for this depth 
  275. $this->depth_array[$depth] = $pos; 
  276. $this->message[$pos] = array('cdata' => '');  
  277. // process attributes 
  278. if (count($attrs) > 0) { 
  279. // register namespace declarations 
  280. foreach($attrs as $k => $v) { 
  281. if (preg_match('/^xmlns/', $k)) { 
  282. if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 
  283. $this->namespaces[$ns_prefix] = $v; 
  284. } else { 
  285. $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 
  286. }  
  287. if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 
  288. $this->XMLSchemaVersion = $v; 
  289. $this->namespaces['xsi'] = $v . '-instance'; 
  290. }  
  291. // expand each attribute prefix to its namespace 
  292. foreach($attrs as $k => $v) { 
  293. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  294. if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 
  295. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  296. }  
  297. $eAttrs[$k] = $v; 
  298. }  
  299. $attrs = $eAttrs; 
  300. } else { 
  301. $attrs = array(); 
  302. }  
  303. // get element prefix, namespace and name 
  304. if (preg_match('/:/', $name)) { 
  305. // get ns prefix 
  306. $prefix = substr($name, 0, strpos($name, ':'));  
  307. // get ns 
  308. $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';  
  309. // get unqualified name 
  310. $name = substr(strstr($name, ':'), 1); 
  311. }  
  312. // process attributes, expanding any prefixes to namespaces 
  313. // find status, register data 
  314. switch ($this->status) { 
  315. case 'message': 
  316. if ($name == 'part') { 
  317. if (isset($attrs['type'])) { 
  318. $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(', ', $attrs)); 
  319. $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 
  320. }  
  321. if (isset($attrs['element'])) { 
  322. $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(', ', $attrs)); 
  323. $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; 
  324. }  
  325. }  
  326. break; 
  327. case 'portType': 
  328. switch ($name) { 
  329. case 'operation': 
  330. $this->currentPortOperation = $attrs['name']; 
  331. $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 
  332. if (isset($attrs['parameterOrder'])) { 
  333. $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 
  334. }  
  335. break; 
  336. case 'documentation': 
  337. $this->documentation = true; 
  338. break;  
  339. // merge input/output data 
  340. default: 
  341. $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 
  342. $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 
  343. break; 
  344. }  
  345. break; 
  346. case 'binding': 
  347. switch ($name) { 
  348. case 'binding':  
  349. // get ns prefix 
  350. if (isset($attrs['style'])) { 
  351. $this->bindings[$this->currentBinding]['prefix'] = $prefix; 
  352. }  
  353. $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 
  354. break; 
  355. case 'header': 
  356. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 
  357. break; 
  358. case 'operation': 
  359. if (isset($attrs['soapAction'])) { 
  360. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 
  361. }  
  362. if (isset($attrs['style'])) { 
  363. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 
  364. }  
  365. if (isset($attrs['name'])) { 
  366. $this->currentOperation = $attrs['name']; 
  367. $this->debug("current binding operation: $this->currentOperation"); 
  368. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 
  369. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 
  370. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 
  371. }  
  372. break; 
  373. case 'input': 
  374. $this->opStatus = 'input'; 
  375. break; 
  376. case 'output': 
  377. $this->opStatus = 'output'; 
  378. break; 
  379. case 'body': 
  380. if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 
  381. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 
  382. } else { 
  383. $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 
  384. }  
  385. break; 
  386. }  
  387. break; 
  388. case 'service': 
  389. switch ($name) { 
  390. case 'port': 
  391. $this->currentPort = $attrs['name']; 
  392. $this->debug('current port: ' . $this->currentPort); 
  393. $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 
  394.  
  395. break; 
  396. case 'address': 
  397. $this->ports[$this->currentPort]['location'] = $attrs['location']; 
  398. $this->ports[$this->currentPort]['bindingType'] = $namespace; 
  399. $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 
  400. $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 
  401. break; 
  402. }  
  403. break; 
  404. }  
  405. // set status 
  406. switch ($name) { 
  407. case 'import': 
  408. if (isset($attrs['location'])) { 
  409. $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 
  410. $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 
  411. } else { 
  412. $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 
  413. if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 
  414. $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 
  415. $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 
  416. break; 
  417. //wait for schema 
  418. //case 'types': 
  419. // $this->status = 'schema'; 
  420. // break; 
  421. case 'message': 
  422. $this->status = 'message'; 
  423. $this->messages[$attrs['name']] = array(); 
  424. $this->currentMessage = $attrs['name']; 
  425. break; 
  426. case 'portType': 
  427. $this->status = 'portType'; 
  428. $this->portTypes[$attrs['name']] = array(); 
  429. $this->currentPortType = $attrs['name']; 
  430. break; 
  431. case "binding": 
  432. if (isset($attrs['name'])) { 
  433. // get binding name 
  434. if (strpos($attrs['name'], ':')) { 
  435. $this->currentBinding = $this->getLocalPart($attrs['name']); 
  436. } else { 
  437. $this->currentBinding = $attrs['name']; 
  438. }  
  439. $this->status = 'binding'; 
  440. $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 
  441. $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 
  442. }  
  443. break; 
  444. case 'service': 
  445. $this->serviceName = $attrs['name']; 
  446. $this->status = 'service'; 
  447. $this->debug('current service: ' . $this->serviceName); 
  448. break; 
  449. case 'definitions': 
  450. foreach ($attrs as $name => $value) { 
  451. $this->wsdl_info[$name] = $value; 
  452. }  
  453. break; 
  454. }  
  455. }  
  456. }  
  457.  
  458. /** 
  459. * end-element handler 
  460. *  
  461. * @param string $parser XML parser object 
  462. * @param string $name element name 
  463. * @access private  
  464. */ 
  465. function end_element($parser, $name) {  
  466. // unset schema status 
  467. if (/**preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { 
  468. $this->status = ""; 
  469. $this->appendDebug($this->currentSchema->getDebug()); 
  470. $this->currentSchema->clearDebug(); 
  471. $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 
  472. $this->debug('Parsing WSDL schema done'); 
  473. }  
  474. if ($this->status == 'schema') { 
  475. $this->currentSchema->schemaEndElement($parser, $name); 
  476. } else { 
  477. // bring depth down a notch 
  478. $this->depth--; 
  479. }  
  480. // end documentation 
  481. if ($this->documentation) { 
  482. //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 
  483. //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 
  484. $this->documentation = false; 
  485. }  
  486. }  
  487.  
  488. /** 
  489. * element content handler 
  490. *  
  491. * @param string $parser XML parser object 
  492. * @param string $data element content 
  493. * @access private  
  494. */ 
  495. function character_data($parser, $data) 
  496. $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 
  497. if (isset($this->message[$pos]['cdata'])) { 
  498. $this->message[$pos]['cdata'] .= $data; 
  499. }  
  500. if ($this->documentation) { 
  501. $this->documentation .= $data; 
  502. }  
  503. }  
  504.  
  505. /** 
  506. * if authenticating, set user credentials here 
  507. * @param string $username 
  508. * @param string $password 
  509. * @param string $authtype (basic|digest|certificate|ntlm) 
  510. * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 
  511. * @access public 
  512. */ 
  513. function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 
  514. $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 
  515. $this->appendDebug($this->varDump($certRequest)); 
  516. $this->username = $username; 
  517. $this->password = $password; 
  518. $this->authtype = $authtype; 
  519. $this->certRequest = $certRequest; 
  520.  
  521. function getBindingData($binding) 
  522. if (is_array($this->bindings[$binding])) { 
  523. return $this->bindings[$binding]; 
  524. }  
  525.  
  526. /** 
  527. * returns an assoc array of operation names => operation data 
  528. *  
  529. * @param string $portName WSDL port name 
  530. * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) 
  531. * @return array  
  532. * @access public  
  533. */ 
  534. function getOperations($portName = '', $bindingType = 'soap') { 
  535. $ops = array(); 
  536. if ($bindingType == 'soap') { 
  537. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  538. } elseif ($bindingType == 'soap12') { 
  539. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  540. } else { 
  541. $this->debug("getOperations bindingType $bindingType may not be supported"); 
  542. $this->debug("getOperations for port '$portName' bindingType $bindingType"); 
  543. // loop thru ports 
  544. foreach($this->ports as $port => $portData) { 
  545. $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); 
  546. if ($portName == '' || $port == $portName) { 
  547. // binding type of port matches parameter 
  548. if ($portData['bindingType'] == $bindingType) { 
  549. $this->debug("getOperations found port $port bindingType $bindingType"); 
  550. //$this->debug("port data: " . $this->varDump($portData)); 
  551. //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 
  552. // merge bindings 
  553. if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 
  554. $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 
  555. if (count($ops) == 0) { 
  556. $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); 
  557. return $ops; 
  558. }  
  559.  
  560. /** 
  561. * returns an associative array of data necessary for calling an operation 
  562. *  
  563. * @param string $operation name of operation 
  564. * @param string $bindingType type of binding eg: soap, soap12 
  565. * @return array  
  566. * @access public  
  567. */ 
  568. function getOperationData($operation, $bindingType = 'soap') 
  569. if ($bindingType == 'soap') { 
  570. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  571. } elseif ($bindingType == 'soap12') { 
  572. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  573. // loop thru ports 
  574. foreach($this->ports as $port => $portData) { 
  575. // binding type of port matches parameter 
  576. if ($portData['bindingType'] == $bindingType) { 
  577. // get binding 
  578. //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 
  579. foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 
  580. // note that we could/should also check the namespace here 
  581. if ($operation == $bOperation) { 
  582. $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 
  583. return $opData; 
  584. }  
  585. }  
  586. }  
  587.  
  588. /** 
  589. * returns an associative array of data necessary for calling an operation 
  590. *  
  591. * @param string $soapAction soapAction for operation 
  592. * @param string $bindingType type of binding eg: soap, soap12 
  593. * @return array  
  594. * @access public  
  595. */ 
  596. function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 
  597. if ($bindingType == 'soap') { 
  598. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 
  599. } elseif ($bindingType == 'soap12') { 
  600. $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 
  601. // loop thru ports 
  602. foreach($this->ports as $port => $portData) { 
  603. // binding type of port matches parameter 
  604. if ($portData['bindingType'] == $bindingType) { 
  605. // loop through operations for the binding 
  606. foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 
  607. if ($opData['soapAction'] == $soapAction) { 
  608. return $opData; 
  609. }  
  610. }  
  611. }  
  612.  
  613. /** 
  614. * returns an array of information about a given type 
  615. * returns false if no type exists by the given name 
  616. * typeDef = array( 
  617. * 'elements' => array(), // refs to elements array 
  618. * 'restrictionBase' => '',  
  619. * 'phpType' => '',  
  620. * 'order' => '(sequence|all)',  
  621. * 'attrs' => array() // refs to attributes array 
  622. * ) 
  623. * @param string $type the type 
  624. * @param string $ns namespace (not prefix) of the type 
  625. * @return mixed 
  626. * @access public 
  627. * @see nusoap_xmlschema 
  628. */ 
  629. function getTypeDef($type, $ns) { 
  630. $this->debug("in getTypeDef: type=$type, ns=$ns"); 
  631. if ((! $ns) && isset($this->namespaces['tns'])) { 
  632. $ns = $this->namespaces['tns']; 
  633. $this->debug("in getTypeDef: type namespace forced to $ns"); 
  634. if (!isset($this->schemas[$ns])) { 
  635. foreach ($this->schemas as $ns0 => $schema0) { 
  636. if (strcasecmp($ns, $ns0) == 0) { 
  637. $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); 
  638. $ns = $ns0; 
  639. break; 
  640. if (isset($this->schemas[$ns])) { 
  641. $this->debug("in getTypeDef: have schema for namespace $ns"); 
  642. for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 
  643. $xs = &$this->schemas[$ns][$i]; 
  644. $t = $xs->getTypeDef($type); 
  645. $this->appendDebug($xs->getDebug()); 
  646. $xs->clearDebug(); 
  647. if ($t) { 
  648. $this->debug("in getTypeDef: found type $type"); 
  649. if (!isset($t['phpType'])) { 
  650. // get info for type to tack onto the element 
  651. $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 
  652. $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 
  653. $etype = $this->getTypeDef($uqType, $ns); 
  654. if ($etype) { 
  655. $this->debug("found type for [element] $type:"); 
  656. $this->debug($this->varDump($etype)); 
  657. if (isset($etype['phpType'])) { 
  658. $t['phpType'] = $etype['phpType']; 
  659. if (isset($etype['elements'])) { 
  660. $t['elements'] = $etype['elements']; 
  661. if (isset($etype['attrs'])) { 
  662. $t['attrs'] = $etype['attrs']; 
  663. } else { 
  664. $this->debug("did not find type for [element] $type"); 
  665. return $t; 
  666. $this->debug("in getTypeDef: did not find type $type"); 
  667. } else { 
  668. $this->debug("in getTypeDef: do not have schema for namespace $ns"); 
  669. return false; 
  670.  
  671. /** 
  672. * prints html description of services 
  673. * @access private 
  674. */ 
  675. function webDescription() { 
  676. global $HTTP_SERVER_VARS; 
  677.  
  678. if (isset($_SERVER)) { 
  679. $PHP_SELF = $_SERVER['PHP_SELF']; 
  680. } elseif (isset($HTTP_SERVER_VARS)) { 
  681. $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 
  682. } else { 
  683. $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 
  684.  
  685. $b = ' 
  686. <html><head><title>NuSOAP: '.$this->serviceName.'</title> 
  687. <style type="text/css"> 
  688. body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 
  689. p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 
  690. pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 
  691. ul { margin-top: 10px; margin-left: 20px; } 
  692. li { list-style-type: none; margin-top: 10px; color: #000000; } 
  693. .content{ 
  694. margin-left: 0px; padding-bottom: 2em; } 
  695. .nav { 
  696. padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 
  697. margin-top: 10px; margin-left: 0px; color: #000000; 
  698. background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 
  699. .title { 
  700. font-family: arial; font-size: 26px; color: #ffffff; 
  701. background-color: #999999; width: 100%; 
  702. margin-left: 0px; margin-right: 0px; 
  703. padding-top: 10px; padding-bottom: 10px;} 
  704. .hidden { 
  705. position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 
  706. font-family: arial; overflow: hidden; width: 600; 
  707. padding: 20px; font-size: 10px; background-color: #999999; 
  708. layer-background-color:#FFFFFF; } 
  709. a, a:active { color: charcoal; font-weight: bold; } 
  710. a:visited { color: #666666; font-weight: bold; } 
  711. a:hover { color: cc3300; font-weight: bold; } 
  712. </style> 
  713. <script language="JavaScript" type="text/javascript"> 
  714. <!-- 
  715. // POP-UP CAPTIONS... 
  716. function lib_bwcheck() { //Browsercheck (needed) 
  717. this.ver=navigator.appVersion 
  718. this.agent=navigator.userAgent 
  719. this.dom=document.getElementById?1:0 
  720. this.opera5=this.agent.indexOf("Opera 5")>-1 
  721. this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 
  722. this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 
  723. this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 
  724. this.ie=this.ie4||this.ie5||this.ie6 
  725. this.mac=this.agent.indexOf("Mac")>-1 
  726. this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 
  727. this.ns4=(document.layers && !this.dom)?1:0; 
  728. this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 
  729. return this 
  730. var bw = new lib_bwcheck() 
  731. //Makes crossbrowser object. 
  732. function makeObj(obj) { 
  733. this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 
  734. if(!this.evnt) return false 
  735. this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 
  736. this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 
  737. this.writeIt=b_writeIt; 
  738. return this 
  739. // A unit of measure that will be added when setting the position of a layer. 
  740. //var px = bw.ns4||window.opera?"":"px"; 
  741. function b_writeIt(text) { 
  742. if (bw.ns4) {this.wref.write(text);this.wref.close()} 
  743. else this.wref.innerHTML = text 
  744. //Shows the messages 
  745. var oDesc; 
  746. function popup(divid) { 
  747. if(oDesc = new makeObj(divid)) { 
  748. oDesc.css.visibility = "visible" 
  749. function popout() { // Hides message 
  750. if(oDesc) oDesc.css.visibility = "hidden" 
  751. //--> 
  752. </script> 
  753. </head> 
  754. <body> 
  755. <div class=content> 
  756. <br><br> 
  757. <div class=title>'.$this->serviceName.'</div> 
  758. <div class=nav> 
  759. <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 
  760. Click on an operation name to view it's details.</p> 
  761. <ul>'; 
  762. foreach($this->getOperations() as $op => $data) { 
  763. $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 
  764. // create hidden div 
  765. $b .= "<div id='$op' class='hidden'> 
  766. <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 
  767. foreach($data as $donnie => $marie) { // loop through opdata 
  768. if($donnie == 'input' || $donnie == 'output') { // show input/output data 
  769. $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 
  770. foreach($marie as $captain => $tenille) { // loop through data 
  771. if($captain == 'parts') { // loop thru parts 
  772. $b .= "  $captain:<br>"; 
  773. //if(is_array($tenille)) { 
  774. foreach($tenille as $joanie => $chachi) { 
  775. $b .= "    $joanie: $chachi<br>"; 
  776. //} 
  777. } else { 
  778. $b .= "  $captain: $tenille<br>"; 
  779. } else { 
  780. $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 
  781. $b .= '</div>'; 
  782. $b .= ' 
  783. <ul> 
  784. </div> 
  785. </div></body></html>'; 
  786. return $b; 
  787.  
  788. /** 
  789. * serialize the parsed wsdl 
  790. * @param mixed $debug whether to put debug=1 in endpoint URL 
  791. * @return string serialization of WSDL 
  792. * @access public  
  793. */ 
  794. function serialize($debug = 0) 
  795. $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 
  796. $xml .= "\n<definitions"; 
  797. foreach($this->namespaces as $k => $v) { 
  798. $xml .= " xmlns:$k=\"$v\""; 
  799. }  
  800. // 10.9.02 - add poulter fix for wsdl and tns declarations 
  801. if (isset($this->namespaces['wsdl'])) { 
  802. $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 
  803. }  
  804. if (isset($this->namespaces['tns'])) { 
  805. $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 
  806. }  
  807. $xml .= '>';  
  808. // imports 
  809. if (sizeof($this->import) > 0) { 
  810. foreach($this->import as $ns => $list) { 
  811. foreach ($list as $ii) { 
  812. if ($ii['location'] != '') { 
  813. $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 
  814. } else { 
  815. $xml .= '<import namespace="' . $ns . '" />'; 
  816. }  
  817. }  
  818. // types 
  819. if (count($this->schemas)>=1) { 
  820. $xml .= "\n<types>\n"; 
  821. foreach ($this->schemas as $ns => $list) { 
  822. foreach ($list as $xs) { 
  823. $xml .= $xs->serializeSchema(); 
  824. $xml .= '</types>'; 
  825. }  
  826. // messages 
  827. if (count($this->messages) >= 1) { 
  828. foreach($this->messages as $msgName => $msgParts) { 
  829. $xml .= "\n<message name=\"" . $msgName . '">'; 
  830. if(is_array($msgParts)) { 
  831. foreach($msgParts as $partName => $partType) { 
  832. // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 
  833. if (strpos($partType, ':')) { 
  834. $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 
  835. } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 
  836. // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 
  837. $typePrefix = 'xsd'; 
  838. } else { 
  839. foreach($this->typemap as $ns => $types) { 
  840. if (isset($types[$partType])) { 
  841. $typePrefix = $this->getPrefixFromNamespace($ns); 
  842. }  
  843. }  
  844. if (!isset($typePrefix)) { 
  845. die("$partType has no namespace!"); 
  846. }  
  847. $ns = $this->getNamespaceFromPrefix($typePrefix); 
  848. $localPart = $this->getLocalPart($partType); 
  849. $typeDef = $this->getTypeDef($localPart, $ns); 
  850. if ($typeDef['typeClass'] == 'element') { 
  851. $elementortype = 'element'; 
  852. if (substr($localPart, -1) == '^') { 
  853. $localPart = substr($localPart, 0, -1); 
  854. } else { 
  855. $elementortype = 'type'; 
  856. $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; 
  857. $xml .= '</message>'; 
  858. }  
  859. }  
  860. // bindings & porttypes 
  861. if (count($this->bindings) >= 1) { 
  862. $binding_xml = ''; 
  863. $portType_xml = ''; 
  864. foreach($this->bindings as $bindingName => $attrs) { 
  865. $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 
  866. $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 
  867. $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 
  868. foreach($attrs['operations'] as $opName => $opParts) { 
  869. $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; 
  870. $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 
  871. if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 
  872. $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 
  873. } else { 
  874. $enc_style = ''; 
  875. $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 
  876. if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 
  877. $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 
  878. } else { 
  879. $enc_style = ''; 
  880. $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 
  881. $binding_xml .= "\n" . ' </operation>'; 
  882. $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; 
  883. if (isset($opParts['parameterOrder'])) { 
  884. $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 
  885. }  
  886. $portType_xml .= '>'; 
  887. if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 
  888. $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 
  889. $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; 
  890. $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; 
  891. $portType_xml .= "\n" . ' </operation>'; 
  892. }  
  893. $portType_xml .= "\n" . '</portType>'; 
  894. $binding_xml .= "\n" . '</binding>'; 
  895. }  
  896. $xml .= $portType_xml . $binding_xml; 
  897. }  
  898. // services 
  899. $xml .= "\n<service name=\"" . $this->serviceName . '">'; 
  900. if (count($this->ports) >= 1) { 
  901. foreach($this->ports as $pName => $attrs) { 
  902. $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 
  903. $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 
  904. $xml .= "\n" . ' </port>'; 
  905. }  
  906. }  
  907. $xml .= "\n" . '</service>'; 
  908. return $xml . "\n</definitions>"; 
  909. }  
  910.  
  911. /** 
  912. * determine whether a set of parameters are unwrapped 
  913. * when they are expect to be wrapped, Microsoft-style. 
  914. * @param string $type the type (element name) of the wrapper 
  915. * @param array $parameters the parameter values for the SOAP call 
  916. * @return boolean whether they parameters are unwrapped (and should be wrapped) 
  917. * @access private 
  918. */ 
  919. function parametersMatchWrapped($type, &$parameters) { 
  920. $this->debug("in parametersMatchWrapped type=$type, parameters="); 
  921. $this->appendDebug($this->varDump($parameters)); 
  922.  
  923. // split type into namespace:unqualified-type 
  924. if (strpos($type, ':')) { 
  925. $uqType = substr($type, strrpos($type, ':') + 1); 
  926. $ns = substr($type, 0, strrpos($type, ':')); 
  927. $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); 
  928. if ($this->getNamespaceFromPrefix($ns)) { 
  929. $ns = $this->getNamespaceFromPrefix($ns); 
  930. $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); 
  931. } else { 
  932. // TODO: should the type be compared to types in XSD, and the namespace 
  933. // set to XSD if the type matches? 
  934. $this->debug("in parametersMatchWrapped: No namespace for type $type"); 
  935. $ns = ''; 
  936. $uqType = $type; 
  937.  
  938. // get the type information 
  939. if (!$typeDef = $this->getTypeDef($uqType, $ns)) { 
  940. $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); 
  941. return false; 
  942. $this->debug("in parametersMatchWrapped: found typeDef="); 
  943. $this->appendDebug($this->varDump($typeDef)); 
  944. if (substr($uqType, -1) == '^') { 
  945. $uqType = substr($uqType, 0, -1); 
  946. $phpType = $typeDef['phpType']; 
  947. $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); 
  948. $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); 
  949.  
  950. // we expect a complexType or element of complexType 
  951. if ($phpType != 'struct') { 
  952. $this->debug("in parametersMatchWrapped: not a struct"); 
  953. return false; 
  954.  
  955. // see whether the parameter names match the elements 
  956. if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 
  957. $elements = 0; 
  958. $matches = 0; 
  959. foreach ($typeDef['elements'] as $name => $attrs) { 
  960. if (isset($parameters[$name])) { 
  961. $this->debug("in parametersMatchWrapped: have parameter named $name"); 
  962. $matches++; 
  963. } else { 
  964. $this->debug("in parametersMatchWrapped: do not have parameter named $name"); 
  965. $elements++; 
  966.  
  967. $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); 
  968. if ($matches == 0) { 
  969. return false; 
  970. return true; 
  971.  
  972. // since there are no elements for the type, if the user passed no 
  973. // parameters, the parameters match wrapped. 
  974. $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); 
  975. return count($parameters) == 0; 
  976.  
  977. /** 
  978. * serialize PHP values according to a WSDL message definition 
  979. * contrary to the method name, this is not limited to RPC 
  980. * TODO 
  981. * - multi-ref serialization 
  982. * - validate PHP values against type definitions, return errors if invalid 
  983. *  
  984. * @param string $operation operation name 
  985. * @param string $direction (input|output) 
  986. * @param mixed $parameters parameter value(s) 
  987. * @param string $bindingType (soap|soap12) 
  988. * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 
  989. * @access public 
  990. */ 
  991. function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { 
  992. $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); 
  993. $this->appendDebug('parameters=' . $this->varDump($parameters)); 
  994.  
  995. if ($direction != 'input' && $direction != 'output') { 
  996. $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 
  997. $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 
  998. return false; 
  999. }  
  1000. if (!$opData = $this->getOperationData($operation, $bindingType)) { 
  1001. $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 
  1002. $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 
  1003. return false; 
  1004. $this->debug('in serializeRPCParameters: opData:'); 
  1005. $this->appendDebug($this->varDump($opData)); 
  1006.  
  1007. // Get encoding style for output and set to current 
  1008. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1009. if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 
  1010. $encodingStyle = $opData['output']['encodingStyle']; 
  1011. $enc_style = $encodingStyle; 
  1012.  
  1013. // set input params 
  1014. $xml = ''; 
  1015. if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 
  1016. $parts = &$opData[$direction]['parts']; 
  1017. $part_count = sizeof($parts); 
  1018. $style = $opData['style']; 
  1019. $use = $opData[$direction]['use']; 
  1020. $this->debug("have $part_count part(s) to serialize using $style/$use"); 
  1021. if (is_array($parameters)) { 
  1022. $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 
  1023. $parameter_count = count($parameters); 
  1024. $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); 
  1025. // check for Microsoft-style wrapped parameters 
  1026. if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { 
  1027. $this->debug('check whether the caller has wrapped the parameters'); 
  1028. if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { 
  1029. // TODO: consider checking here for double-wrapping, when 
  1030. // service function wraps, then NuSOAP wraps again 
  1031. $this->debug("change simple array to associative with 'parameters' element"); 
  1032. $parameters['parameters'] = $parameters[0]; 
  1033. unset($parameters[0]); 
  1034. if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { 
  1035. $this->debug('check whether caller\'s parameters match the wrapped ones'); 
  1036. if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { 
  1037. $this->debug('wrap the parameters for the caller'); 
  1038. $parameters = array('parameters' => $parameters); 
  1039. $parameter_count = 1; 
  1040. foreach ($parts as $name => $type) { 
  1041. $this->debug("serializing part $name of type $type"); 
  1042. // Track encoding style 
  1043. if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 
  1044. $encodingStyle = $opData[$direction]['encodingStyle'];  
  1045. $enc_style = $encodingStyle; 
  1046. } else { 
  1047. $enc_style = false; 
  1048. // NOTE: add error handling here 
  1049. // if serializeType returns false, then catch global error and fault 
  1050. if ($parametersArrayType == 'arraySimple') { 
  1051. $p = array_shift($parameters); 
  1052. $this->debug('calling serializeType w/indexed param'); 
  1053. $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 
  1054. } elseif (isset($parameters[$name])) { 
  1055. $this->debug('calling serializeType w/named param'); 
  1056. $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 
  1057. } else { 
  1058. // TODO: only send nillable 
  1059. $this->debug('calling serializeType w/null param'); 
  1060. $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 
  1061. } else { 
  1062. $this->debug('no parameters passed.'); 
  1063. $this->debug("serializeRPCParameters returning: $xml"); 
  1064. return $xml; 
  1065. }  
  1066.  
  1067. /** 
  1068. * serialize a PHP value according to a WSDL message definition 
  1069. *  
  1070. * TODO 
  1071. * - multi-ref serialization 
  1072. * - validate PHP values against type definitions, return errors if invalid 
  1073. *  
  1074. * @param string $operation operation name 
  1075. * @param string $direction (input|output) 
  1076. * @param mixed $parameters parameter value(s) 
  1077. * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 
  1078. * @access public 
  1079. * @deprecated 
  1080. */ 
  1081. function serializeParameters($operation, $direction, $parameters) 
  1082. $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");  
  1083. $this->appendDebug('parameters=' . $this->varDump($parameters)); 
  1084.  
  1085. if ($direction != 'input' && $direction != 'output') { 
  1086. $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 
  1087. $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 
  1088. return false; 
  1089. }  
  1090. if (!$opData = $this->getOperationData($operation)) { 
  1091. $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 
  1092. $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 
  1093. return false; 
  1094. $this->debug('opData:'); 
  1095. $this->appendDebug($this->varDump($opData)); 
  1096.  
  1097. // Get encoding style for output and set to current 
  1098. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1099. if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 
  1100. $encodingStyle = $opData['output']['encodingStyle']; 
  1101. $enc_style = $encodingStyle; 
  1102.  
  1103. // set input params 
  1104. $xml = ''; 
  1105. if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 
  1106.  
  1107. $use = $opData[$direction]['use']; 
  1108. $this->debug("use=$use"); 
  1109. $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 
  1110. if (is_array($parameters)) { 
  1111. $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 
  1112. $this->debug('have ' . $parametersArrayType . ' parameters'); 
  1113. foreach($opData[$direction]['parts'] as $name => $type) { 
  1114. $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 
  1115. // Track encoding style 
  1116. if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 
  1117. $encodingStyle = $opData[$direction]['encodingStyle'];  
  1118. $enc_style = $encodingStyle; 
  1119. } else { 
  1120. $enc_style = false; 
  1121. // NOTE: add error handling here 
  1122. // if serializeType returns false, then catch global error and fault 
  1123. if ($parametersArrayType == 'arraySimple') { 
  1124. $p = array_shift($parameters); 
  1125. $this->debug('calling serializeType w/indexed param'); 
  1126. $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 
  1127. } elseif (isset($parameters[$name])) { 
  1128. $this->debug('calling serializeType w/named param'); 
  1129. $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 
  1130. } else { 
  1131. // TODO: only send nillable 
  1132. $this->debug('calling serializeType w/null param'); 
  1133. $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 
  1134. } else { 
  1135. $this->debug('no parameters passed.'); 
  1136. $this->debug("serializeParameters returning: $xml"); 
  1137. return $xml; 
  1138. }  
  1139.  
  1140. /** 
  1141. * serializes a PHP value according a given type definition 
  1142. *  
  1143. * @param string $name name of value (part or element) 
  1144. * @param string $type XML schema type of value (type or element) 
  1145. * @param mixed $value a native PHP value (parameter value) 
  1146. * @param string $use use for part (encoded|literal) 
  1147. * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 
  1148. * @param boolean $unqualified a kludge for what should be XML namespace form handling 
  1149. * @return string value serialized as an XML string 
  1150. * @access private 
  1151. */ 
  1152. function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 
  1153. $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 
  1154. $this->appendDebug("value=" . $this->varDump($value)); 
  1155. if($use == 'encoded' && $encodingStyle) { 
  1156. $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 
  1157.  
  1158. // if a soapval has been supplied, let its type override the WSDL 
  1159. if (is_object($value) && get_class($value) == 'soapval') { 
  1160. if ($value->type_ns) { 
  1161. $type = $value->type_ns . ':' . $value->type; 
  1162. $forceType = true; 
  1163. $this->debug("in serializeType: soapval overrides type to $type"); 
  1164. } elseif ($value->type) { 
  1165. $type = $value->type; 
  1166. $forceType = true; 
  1167. $this->debug("in serializeType: soapval overrides type to $type"); 
  1168. } else { 
  1169. $forceType = false; 
  1170. $this->debug("in serializeType: soapval does not override type"); 
  1171. $attrs = $value->attributes; 
  1172. $value = $value->value; 
  1173. $this->debug("in serializeType: soapval overrides value to $value"); 
  1174. if ($attrs) { 
  1175. if (!is_array($value)) { 
  1176. $value['!'] = $value; 
  1177. foreach ($attrs as $n => $v) { 
  1178. $value['!' . $n] = $v; 
  1179. $this->debug("in serializeType: soapval provides attributes"); 
  1180. } else { 
  1181. $forceType = false; 
  1182.  
  1183. $xml = ''; 
  1184. if (strpos($type, ':')) { 
  1185. $uqType = substr($type, strrpos($type, ':') + 1); 
  1186. $ns = substr($type, 0, strrpos($type, ':')); 
  1187. $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 
  1188. if ($this->getNamespaceFromPrefix($ns)) { 
  1189. $ns = $this->getNamespaceFromPrefix($ns); 
  1190. $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 
  1191.  
  1192. if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') { 
  1193. $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 
  1194. if ($unqualified && $use == 'literal') { 
  1195. $elementNS = " xmlns=\"\""; 
  1196. } else { 
  1197. $elementNS = ''; 
  1198. if (is_null($value)) { 
  1199. if ($use == 'literal') { 
  1200. // TODO: depends on minOccurs 
  1201. $xml = "<$name$elementNS/>"; 
  1202. } else { 
  1203. // TODO: depends on nillable, which should be checked before calling this method 
  1204. $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 
  1205. $this->debug("in serializeType: returning: $xml"); 
  1206. return $xml; 
  1207. if ($uqType == 'Array') { 
  1208. // JBoss/Axis does this sometimes 
  1209. return $this->serialize_val($value, $name, false, false, false, false, $use); 
  1210. if ($uqType == 'boolean') { 
  1211. if ((is_string($value) && $value == 'false') || (! $value)) { 
  1212. $value = 'false'; 
  1213. } else { 
  1214. $value = 'true'; 
  1215. }  
  1216. if ($uqType == 'string' && gettype($value) == 'string') { 
  1217. $value = $this->expandEntities($value); 
  1218. if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 
  1219. $value = sprintf("%.0lf", $value); 
  1220. // it's a scalar 
  1221. // TODO: what about null/nil values? 
  1222. // check type isn't a custom type extending xmlschema namespace 
  1223. if (!$this->getTypeDef($uqType, $ns)) { 
  1224. if ($use == 'literal') { 
  1225. if ($forceType) { 
  1226. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 
  1227. } else { 
  1228. $xml = "<$name$elementNS>$value</$name>"; 
  1229. } else { 
  1230. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 
  1231. $this->debug("in serializeType: returning: $xml"); 
  1232. return $xml; 
  1233. $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 
  1234. } else if ($ns == 'http://xml.apache.org/xml-soap') { 
  1235. $this->debug('in serializeType: appears to be Apache SOAP type'); 
  1236. if ($uqType == 'Map') { 
  1237. $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 
  1238. if (! $tt_prefix) { 
  1239. $this->debug('in serializeType: Add namespace for Apache SOAP type'); 
  1240. $tt_prefix = 'ns' . rand(1000, 9999); 
  1241. $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 
  1242. // force this to be added to usedNamespaces 
  1243. $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 
  1244. $contents = ''; 
  1245. foreach($value as $k => $v) { 
  1246. $this->debug("serializing map element: key $k, value $v"); 
  1247. $contents .= '<item>'; 
  1248. $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use); 
  1249. $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use); 
  1250. $contents .= '</item>'; 
  1251. if ($use == 'literal') { 
  1252. if ($forceType) { 
  1253. $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 
  1254. } else { 
  1255. $xml = "<$name>$contents</$name>"; 
  1256. } else { 
  1257. $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 
  1258. $this->debug("in serializeType: returning: $xml"); 
  1259. return $xml; 
  1260. $this->debug('in serializeType: Apache SOAP type, but only support Map'); 
  1261. } else { 
  1262. // TODO: should the type be compared to types in XSD, and the namespace 
  1263. // set to XSD if the type matches? 
  1264. $this->debug("in serializeType: No namespace for type $type"); 
  1265. $ns = ''; 
  1266. $uqType = $type; 
  1267. if(!$typeDef = $this->getTypeDef($uqType, $ns)) { 
  1268. $this->setError("$type ($uqType) is not a supported type."); 
  1269. $this->debug("in serializeType: $type ($uqType) is not a supported type."); 
  1270. return false; 
  1271. } else { 
  1272. $this->debug("in serializeType: found typeDef"); 
  1273. $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 
  1274. if (substr($uqType, -1) == '^') { 
  1275. $uqType = substr($uqType, 0, -1); 
  1276. if (!isset($typeDef['phpType'])) { 
  1277. $this->setError("$type ($uqType) has no phpType."); 
  1278. $this->debug("in serializeType: $type ($uqType) has no phpType."); 
  1279. return false; 
  1280. $phpType = $typeDef['phpType']; 
  1281. $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );  
  1282. // if php type == struct, map value to the <all> element names 
  1283. if ($phpType == 'struct') { 
  1284. if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 
  1285. $elementName = $uqType; 
  1286. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1287. $elementNS = " xmlns=\"$ns\""; 
  1288. } else { 
  1289. $elementNS = " xmlns=\"\""; 
  1290. } else { 
  1291. $elementName = $name; 
  1292. if ($unqualified) { 
  1293. $elementNS = " xmlns=\"\""; 
  1294. } else { 
  1295. $elementNS = ''; 
  1296. if (is_null($value)) { 
  1297. if ($use == 'literal') { 
  1298. // TODO: depends on minOccurs and nillable 
  1299. $xml = "<$elementName$elementNS/>"; 
  1300. } else { 
  1301. $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 
  1302. $this->debug("in serializeType: returning: $xml"); 
  1303. return $xml; 
  1304. if (is_object($value)) { 
  1305. $value = get_object_vars($value); 
  1306. if (is_array($value)) { 
  1307. $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 
  1308. if ($use == 'literal') { 
  1309. if ($forceType) { 
  1310. $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 
  1311. } else { 
  1312. $xml = "<$elementName$elementNS$elementAttrs>"; 
  1313. } else { 
  1314. $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 
  1315.  
  1316. if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { 
  1317. if (isset($value['!'])) { 
  1318. $xml .= $value['!']; 
  1319. $this->debug("in serializeType: serialized simpleContent for type $type"); 
  1320. } else { 
  1321. $this->debug("in serializeType: no simpleContent to serialize for type $type"); 
  1322. } else { 
  1323. // complexContent 
  1324. $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 
  1325. $xml .= "</$elementName>"; 
  1326. } else { 
  1327. $this->debug("in serializeType: phpType is struct, but value is not an array"); 
  1328. $this->setError("phpType is struct, but value is not an array: see debug output for details"); 
  1329. $xml = ''; 
  1330. } elseif ($phpType == 'array') { 
  1331. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1332. $elementNS = " xmlns=\"$ns\""; 
  1333. } else { 
  1334. if ($unqualified) { 
  1335. $elementNS = " xmlns=\"\""; 
  1336. } else { 
  1337. $elementNS = ''; 
  1338. if (is_null($value)) { 
  1339. if ($use == 'literal') { 
  1340. // TODO: depends on minOccurs 
  1341. $xml = "<$name$elementNS/>"; 
  1342. } else { 
  1343. $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 
  1344. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 
  1345. ":Array\" " . 
  1346. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 
  1347. ':arrayType="' . 
  1348. $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 
  1349. ':' . 
  1350. $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 
  1351. $this->debug("in serializeType: returning: $xml"); 
  1352. return $xml; 
  1353. if (isset($typeDef['multidimensional'])) { 
  1354. $nv = array(); 
  1355. foreach($value as $v) { 
  1356. $cols = ', ' . sizeof($v); 
  1357. $nv = array_merge($nv, $v); 
  1358. }  
  1359. $value = $nv; 
  1360. } else { 
  1361. $cols = ''; 
  1362. }  
  1363. if (is_array($value) && sizeof($value) >= 1) { 
  1364. $rows = sizeof($value); 
  1365. $contents = ''; 
  1366. foreach($value as $k => $v) { 
  1367. $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 
  1368. //if (strpos($typeDef['arrayType'], ':') ) { 
  1369. if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) { 
  1370. $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 
  1371. } else { 
  1372. $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 
  1373. }  
  1374. } else { 
  1375. $rows = 0; 
  1376. $contents = null; 
  1377. // TODO: for now, an empty value will be serialized as a zero element 
  1378. // array. Revisit this when coding the handling of null/nil values. 
  1379. if ($use == 'literal') { 
  1380. $xml = "<$name$elementNS>" 
  1381. .$contents 
  1382. ."</$name>"; 
  1383. } else { 
  1384. $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 
  1385. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 
  1386. .':arrayType="' 
  1387. .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 
  1388. .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 
  1389. .$contents 
  1390. ."</$name>"; 
  1391. } elseif ($phpType == 'scalar') { 
  1392. if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 
  1393. $elementNS = " xmlns=\"$ns\""; 
  1394. } else { 
  1395. if ($unqualified) { 
  1396. $elementNS = " xmlns=\"\""; 
  1397. } else { 
  1398. $elementNS = ''; 
  1399. if ($use == 'literal') { 
  1400. if ($forceType) { 
  1401. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 
  1402. } else { 
  1403. $xml = "<$name$elementNS>$value</$name>"; 
  1404. } else { 
  1405. $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 
  1406. $this->debug("in serializeType: returning: $xml"); 
  1407. return $xml; 
  1408.  
  1409. /** 
  1410. * serializes the attributes for a complexType 
  1411. * @param array $typeDef our internal representation of an XML schema type (or element) 
  1412. * @param mixed $value a native PHP value (parameter value) 
  1413. * @param string $ns the namespace of the type 
  1414. * @param string $uqType the local part of the type 
  1415. * @return string value serialized as an XML string 
  1416. * @access private 
  1417. */ 
  1418. function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 
  1419. $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); 
  1420. $xml = ''; 
  1421. if (isset($typeDef['extensionBase'])) { 
  1422. $nsx = $this->getPrefix($typeDef['extensionBase']); 
  1423. $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 
  1424. if ($this->getNamespaceFromPrefix($nsx)) { 
  1425. $nsx = $this->getNamespaceFromPrefix($nsx); 
  1426. if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 
  1427. $this->debug("serialize attributes for extension base $nsx:$uqTypex"); 
  1428. $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); 
  1429. } else { 
  1430. $this->debug("extension base $nsx:$uqTypex is not a supported type"); 
  1431. if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 
  1432. $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 
  1433. if (is_array($value)) { 
  1434. $xvalue = $value; 
  1435. } elseif (is_object($value)) { 
  1436. $xvalue = get_object_vars($value); 
  1437. } else { 
  1438. $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 
  1439. $xvalue = array(); 
  1440. foreach ($typeDef['attrs'] as $aName => $attrs) { 
  1441. if (isset($xvalue['!' . $aName])) { 
  1442. $xname = '!' . $aName; 
  1443. $this->debug("value provided for attribute $aName with key $xname"); 
  1444. } elseif (isset($xvalue[$aName])) { 
  1445. $xname = $aName; 
  1446. $this->debug("value provided for attribute $aName with key $xname"); 
  1447. } elseif (isset($attrs['default'])) { 
  1448. $xname = '!' . $aName; 
  1449. $xvalue[$xname] = $attrs['default']; 
  1450. $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 
  1451. } else { 
  1452. $xname = ''; 
  1453. $this->debug("no value provided for attribute $aName"); 
  1454. if ($xname) { 
  1455. $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 
  1456. }  
  1457. } else { 
  1458. $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 
  1459. return $xml; 
  1460.  
  1461. /** 
  1462. * serializes the elements for a complexType 
  1463. * @param array $typeDef our internal representation of an XML schema type (or element) 
  1464. * @param mixed $value a native PHP value (parameter value) 
  1465. * @param string $ns the namespace of the type 
  1466. * @param string $uqType the local part of the type 
  1467. * @param string $use use for part (encoded|literal) 
  1468. * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 
  1469. * @return string value serialized as an XML string 
  1470. * @access private 
  1471. */ 
  1472. function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 
  1473. $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); 
  1474. $xml = ''; 
  1475. if (isset($typeDef['extensionBase'])) { 
  1476. $nsx = $this->getPrefix($typeDef['extensionBase']); 
  1477. $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 
  1478. if ($this->getNamespaceFromPrefix($nsx)) { 
  1479. $nsx = $this->getNamespaceFromPrefix($nsx); 
  1480. if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 
  1481. $this->debug("serialize elements for extension base $nsx:$uqTypex"); 
  1482. $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); 
  1483. } else { 
  1484. $this->debug("extension base $nsx:$uqTypex is not a supported type"); 
  1485. if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 
  1486. $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 
  1487. if (is_array($value)) { 
  1488. $xvalue = $value; 
  1489. } elseif (is_object($value)) { 
  1490. $xvalue = get_object_vars($value); 
  1491. } else { 
  1492. $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 
  1493. $xvalue = array(); 
  1494. // toggle whether all elements are present - ideally should validate against schema 
  1495. if (count($typeDef['elements']) != count($xvalue)) { 
  1496. $optionals = true; 
  1497. foreach ($typeDef['elements'] as $eName => $attrs) { 
  1498. if (!isset($xvalue[$eName])) { 
  1499. if (isset($attrs['default'])) { 
  1500. $xvalue[$eName] = $attrs['default']; 
  1501. $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 
  1502. // if user took advantage of a minOccurs=0, then only serialize named parameters 
  1503. if (isset($optionals) 
  1504. && (!isset($xvalue[$eName]))  
  1505. && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 
  1506. ) { 
  1507. if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 
  1508. $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 
  1509. // do nothing 
  1510. $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 
  1511. } else { 
  1512. // get value 
  1513. if (isset($xvalue[$eName])) { 
  1514. $v = $xvalue[$eName]; 
  1515. } else { 
  1516. $v = null; 
  1517. if (isset($attrs['form'])) { 
  1518. $unqualified = ($attrs['form'] == 'unqualified'); 
  1519. } else { 
  1520. $unqualified = false; 
  1521. if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 
  1522. $vv = $v; 
  1523. foreach ($vv as $k => $v) { 
  1524. if (isset($attrs['type']) || isset($attrs['ref'])) { 
  1525. // serialize schema-defined type 
  1526. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1527. } else { 
  1528. // serialize generic type (can this ever really happen?) 
  1529. $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 
  1530. $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 
  1531. } else { 
  1532. if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { 
  1533. // do nothing 
  1534. } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { 
  1535. // TODO: serialize a nil correctly, but for now serialize schema-defined type 
  1536. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1537. } elseif (isset($attrs['type']) || isset($attrs['ref'])) { 
  1538. // serialize schema-defined type 
  1539. $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 
  1540. } else { 
  1541. // serialize generic type (can this ever really happen?) 
  1542. $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 
  1543. $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 
  1544. }  
  1545. } else { 
  1546. $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 
  1547. return $xml; 
  1548.  
  1549. /** 
  1550. * adds an XML Schema complex type to the WSDL types 
  1551. * @param string $name 
  1552. * @param string $typeClass (complexType|simpleType|attribute) 
  1553. * @param string $phpType currently supported are array and struct (php assoc array) 
  1554. * @param string $compositor (all|sequence|choice) 
  1555. * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 
  1556. * @param array $elements e.g. array ( name => array(name=>'', type=>'') ) 
  1557. * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType', 'wsdl:arrayType'=>'xsd:string[]')) 
  1558. * @param string $arrayType as namespace:name (xsd:string) 
  1559. * @see nusoap_xmlschema 
  1560. * @access public 
  1561. */ 
  1562. function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=array(), $attrs=array(), $arrayType='') { 
  1563. if (count($elements) > 0) { 
  1564. $eElements = array(); 
  1565. foreach($elements as $n => $e) { 
  1566. // expand each element 
  1567. $ee = array(); 
  1568. foreach ($e as $k => $v) { 
  1569. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  1570. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  1571. $ee[$k] = $v; 
  1572. $eElements[$n] = $ee; 
  1573. $elements = $eElements; 
  1574.  
  1575. if (count($attrs) > 0) { 
  1576. foreach($attrs as $n => $a) { 
  1577. // expand each attribute 
  1578. foreach ($a as $k => $v) { 
  1579. $k = strpos($k, ':') ? $this->expandQname($k) : $k; 
  1580. $v = strpos($v, ':') ? $this->expandQname($v) : $v; 
  1581. $aa[$k] = $v; 
  1582. $eAttrs[$n] = $aa; 
  1583. $attrs = $eAttrs; 
  1584.  
  1585. $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; 
  1586. $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType; 
  1587.  
  1588. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1589. $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType); 
  1590.  
  1591. /** 
  1592. * adds an XML Schema simple type to the WSDL types 
  1593. * @param string $name 
  1594. * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 
  1595. * @param string $typeClass (should always be simpleType) 
  1596. * @param string $phpType (should always be scalar) 
  1597. * @param array $enumeration array of values 
  1598. * @see nusoap_xmlschema 
  1599. * @access public 
  1600. */ 
  1601. function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 
  1602. $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; 
  1603.  
  1604. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1605. $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 
  1606.  
  1607. /** 
  1608. * adds an element to the WSDL types 
  1609. * @param array $attrs attributes that must include name and type 
  1610. * @see nusoap_xmlschema 
  1611. * @access public 
  1612. */ 
  1613. function addElement($attrs) { 
  1614. $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 
  1615. $this->schemas[$typens][0]->addElement($attrs); 
  1616.  
  1617. /** 
  1618. * register an operation with the server 
  1619. *  
  1620. * @param string $name operation (method) name 
  1621. * @param array $in assoc array of input values: key = param name, value = param type 
  1622. * @param array $out assoc array of output values: key = param name, value = param type 
  1623. * @param string $namespace optional The namespace for the operation 
  1624. * @param string $soapaction optional The soapaction for the operation 
  1625. * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically 
  1626. * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) 
  1627. * @param string $documentation optional The description to include in the WSDL 
  1628. * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 
  1629. * @access public  
  1630. */ 
  1631. function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '') { 
  1632. if ($use == 'encoded' && $encodingStyle == '') { 
  1633. $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 
  1634.  
  1635. if ($style == 'document') { 
  1636. $elements = array(); 
  1637. foreach ($in as $n => $t) { 
  1638. $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 
  1639. $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 
  1640. $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 
  1641. $in = array('parameters' => 'tns:' . $name . '^'); 
  1642.  
  1643. $elements = array(); 
  1644. foreach ($out as $n => $t) { 
  1645. $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 
  1646. $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 
  1647. $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); 
  1648. $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); 
  1649.  
  1650. // get binding 
  1651. $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 
  1652. array( 
  1653. 'name' => $name,  
  1654. 'binding' => $this->serviceName . 'Binding',  
  1655. 'endpoint' => $this->endpoint,  
  1656. 'soapAction' => $soapaction,  
  1657. 'style' => $style,  
  1658. 'input' => array( 
  1659. 'use' => $use,  
  1660. 'namespace' => $namespace,  
  1661. 'encodingStyle' => $encodingStyle,  
  1662. 'message' => $name . 'Request',  
  1663. 'parts' => $in),  
  1664. 'output' => array( 
  1665. 'use' => $use,  
  1666. 'namespace' => $namespace,  
  1667. 'encodingStyle' => $encodingStyle,  
  1668. 'message' => $name . 'Response',  
  1669. 'parts' => $out),  
  1670. 'namespace' => $namespace,  
  1671. 'transport' => 'http://schemas.xmlsoap.org/soap/http',  
  1672. 'documentation' => $documentation);  
  1673. // add portTypes 
  1674. // add messages 
  1675. if($in) 
  1676. foreach($in as $pName => $pType) 
  1677. if(strpos($pType, ':')) { 
  1678. $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 
  1679. $this->messages[$name.'Request'][$pName] = $pType; 
  1680. } else { 
  1681. $this->messages[$name.'Request']= '0'; 
  1682. if($out) 
  1683. foreach($out as $pName => $pType) 
  1684. if(strpos($pType, ':')) { 
  1685. $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 
  1686. $this->messages[$name.'Response'][$pName] = $pType; 
  1687. } else { 
  1688. $this->messages[$name.'Response']= '0'; 
  1689. return true; 
  1690. }