source: pro-violet-viettel/www/deploy/20150304/application/libraries/nusoap/class.wsdl.php @ 780

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