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