root/trunk/lib/class.wsdl.php

Revision 61, 68.7 kB (checked in by yann, 5 years ago)

use nusoap library for SOAP access (can be included in plugin package)

Line 
1 <?php
2
3
4
5
6 /**
7 * parses a WSDL file, allows access to it's data, other utility methods
8 *
9 * @author   Dietrich Ayala <dietrich@ganx4.com>
10 * @version  $Id: class.wsdl.php,v 1.56 2005/08/04 01:27:42 snichol Exp $
11 * @access public
12 */
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;
23     var $currentOperation;
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
49     /**
50      * constructor
51      *
52      * @param string $wsdl WSDL document URL
53      * @param string $proxyhost
54      * @param string $proxyport
55      * @param string $proxyusername
56      * @param string $proxypassword
57      * @param integer $timeout set the connection timeout
58      * @param integer $response_timeout set the response timeout
59      * @access public
60      */
61     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
62         parent::nusoap_base();
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
165     /**
166      * parses the wsdl document
167      *
168      * @param string $wsdl path or URL
169      * @access private
170      */
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
263     /**
264      * start-element handler
265      *
266      * @param string $parser XML parser object
267      * @param string $name element name
268      * @param string $attrs associative array of attributes
269      * @access private
270      */
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
477     /**
478     * end-element handler
479     *
480     * @param string $parser XML parser object
481     * @param string $name element name
482     * @access private
483     */
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
507     /**
508      * element content handler
509      *
510      * @param string $parser XML parser object
511      * @param string $data element content
512      * @access private
513      */
514     function character_data($parser, $data)
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     
532     /**
533      * returns an assoc array of operation names => operation data
534      *
535      * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported)
536      * @return array
537      * @access public
538      */
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     
561     /**
562      * returns an associative array of data necessary for calling an operation
563      *
564      * @param string $operation , name of operation
565      * @param string $bindingType , type of binding eg: soap
566      * @return array
567      * @access public
568      */
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     
591     /**
592      * returns an associative array of data necessary for calling an operation
593      *
594      * @param string $soapAction soapAction for operation
595      * @param string $bindingType type of binding eg: soap
596      * @return array
597      * @access public
598      */
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     
617     /**
618     * returns an array of information about a given type
619     * returns false if no type exists by the given name
620     *
621     *     typeDef = array(
622     *     'elements' => array(), // refs to elements array
623     *    'restrictionBase' => '',
624     *    'phpType' => '',
625     *    'order' => '(sequence|all)',
626     *    'attrs' => array() // refs to attributes array
627     *    )
628     *
629     * @param $type string the type
630     * @param $ns string namespace (not prefix) of the type
631     * @return mixed
632     * @access public
633     * @see xmlschema
634     */
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
677     /**
678     * prints html description of services
679     *
680     * @access private
681     */
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
808     /**
809     * serialize the parsed wsdl
810     *
811     * @param mixed $debug whether to put debug=1 in endpoint URL
812     * @return string serialization of WSDL
813     * @access public
814     */
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     
941     /**
942      * serialize PHP values according to a WSDL message definition
943      *
944      * TODO
945      * - multi-ref serialization
946      * - validate PHP values against type definitions, return errors if invalid
947      *
948      * @param string $operation operation name
949      * @param string $direction (input|output)
950      * @param mixed $parameters parameter value(s)
951      * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
952      * @access public
953      */
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     
1020     /**
1021      * serialize a PHP value according to a WSDL message definition
1022      *
1023      * TODO
1024      * - multi-ref serialization
1025      * - validate PHP values against type definitions, return errors if invalid
1026      *
1027      * @param string $ type name
1028      * @param mixed $ param value
1029      * @return mixed new param or false if initial value didn't validate
1030      * @access public
1031      * @deprecated
1032      */
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     
1100     /**
1101      * serializes a PHP value according a given type definition
1102      *
1103      * @param string $name name of value (part or element)
1104      * @param string $type XML schema type of value (type or element)
1105      * @param mixed $value a native PHP value (parameter value)
1106      * @param string $use use for part (encoded|literal)
1107      * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
1108      * @param boolean $unqualified a kludge for what should be XML namespace form handling
1109      * @return string value serialized as an XML string
1110      * @access private
1111      */
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     
1399     /**
1400      * serializes the attributes for a complexType
1401      *
1402      * @param array $typeDef our internal representation of an XML schema type (or element)
1403      * @param mixed $value a native PHP value (parameter value)
1404      * @param string $ns the namespace of the type
1405      * @param string $uqType the local part of the type
1406      * @return string value serialized as an XML string
1407      * @access private
1408      */
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
1459     /**
1460      * serializes the elements for a complexType
1461      *
1462      * @param array $typeDef our internal representation of an XML schema type (or element)
1463      * @param mixed $value a native PHP value (parameter value)
1464      * @param string $ns the namespace of the type
1465      * @param string $uqType the local part of the type
1466      * @param string $use use for part (encoded|literal)
1467      * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
1468      * @return string value serialized as an XML string
1469      * @access private
1470      */
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
1559     /**
1560     * adds an XML Schema complex type to the WSDL types
1561     *
1562     * @param string    name
1563     * @param string typeClass (complexType|simpleType|attribute)
1564     * @param string phpType: currently supported are array and struct (php assoc array)
1565     * @param string compositor (all|sequence|choice)
1566     * @param string restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1567     * @param array elements = array ( name => array(name=>'',type=>'') )
1568     * @param array attrs =     array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
1569     * @param string arrayType: namespace:name (xsd:string)
1570     * @see xmlschema
1571     * @access public
1572     */
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
1607     /**
1608     * adds an XML Schema simple type to the WSDL types
1609     *
1610     * @param string $name
1611     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1612     * @param string $typeClass (should always be simpleType)
1613     * @param string $phpType (should always be scalar)
1614     * @param array $enumeration array of values
1615     * @see xmlschema
1616     * @access public
1617     */
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
1625     /**
1626     * adds an element to the WSDL types
1627     *
1628     * @param array $attrs attributes that must include name and type
1629     * @see xmlschema
1630     * @access public
1631     */
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
1637     /**
1638     * register an operation with the server
1639     *
1640     * @param string $name operation (method) name
1641     * @param array $in assoc array of input values: key = param name, value = param type
1642     * @param array $out assoc array of output values: key = param name, value = param type
1643     * @param string $namespace optional The namespace for the operation
1644     * @param string $soapaction optional The soapaction for the operation
1645     * @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
1646     * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
1647     * @param string $documentation optional The description to include in the WSDL
1648     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
1649     * @access public
1650     */
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 ?>
Note: See TracBrowser for help on using the browser.