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

Last change on this file since 780 was 780, checked in by dungnv, 10 years ago
File size: 40.1 KB
Line 
1<?php
2
3
4
5
6/**
7*
8* nusoap_server allows the user to create a SOAP server
9* that is capable of receiving messages and returning responses
10*
11* @author   Dietrich Ayala <dietrich@ganx4.com>
12* @author   Scott Nichol <snichol@users.sourceforge.net>
13* @version  $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $
14* @access   public
15*/
16class nusoap_server extends nusoap_base {
17        /**
18         * HTTP headers of request
19         * @var array
20         * @access private
21         */
22        var $headers = array();
23        /**
24         * HTTP request
25         * @var string
26         * @access private
27         */
28        var $request = '';
29        /**
30         * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
31         * @var string
32         * @access public
33         */
34        var $requestHeaders = '';
35        /**
36         * SOAP Headers from request (parsed)
37         * @var mixed
38         * @access public
39         */
40        var $requestHeader = NULL;
41        /**
42         * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
43         * @var string
44         * @access public
45         */
46        var $document = '';
47        /**
48         * SOAP payload for request (text)
49         * @var string
50         * @access public
51         */
52        var $requestSOAP = '';
53        /**
54         * requested method namespace URI
55         * @var string
56         * @access private
57         */
58        var $methodURI = '';
59        /**
60         * name of method requested
61         * @var string
62         * @access private
63         */
64        var $methodname = '';
65        /**
66         * method parameters from request
67         * @var array
68         * @access private
69         */
70        var $methodparams = array();
71        /**
72         * SOAP Action from request
73         * @var string
74         * @access private
75         */
76        var $SOAPAction = '';
77        /**
78         * character set encoding of incoming (request) messages
79         * @var string
80         * @access public
81         */
82        var $xml_encoding = '';
83        /**
84         * toggles whether the parser decodes element content w/ utf8_decode()
85         * @var boolean
86         * @access public
87         */
88    var $decode_utf8 = true;
89
90        /**
91         * HTTP headers of response
92         * @var array
93         * @access public
94         */
95        var $outgoing_headers = array();
96        /**
97         * HTTP response
98         * @var string
99         * @access private
100         */
101        var $response = '';
102        /**
103         * SOAP headers for response (text or array of soapval or associative array)
104         * @var mixed
105         * @access public
106         */
107        var $responseHeaders = '';
108        /**
109         * SOAP payload for response (text)
110         * @var string
111         * @access private
112         */
113        var $responseSOAP = '';
114        /**
115         * method return value to place in response
116         * @var mixed
117         * @access private
118         */
119        var $methodreturn = false;
120        /**
121         * whether $methodreturn is a string of literal XML
122         * @var boolean
123         * @access public
124         */
125        var $methodreturnisliteralxml = false;
126        /**
127         * SOAP fault for response (or false)
128         * @var mixed
129         * @access private
130         */
131        var $fault = false;
132        /**
133         * text indication of result (for debugging)
134         * @var string
135         * @access private
136         */
137        var $result = 'successful';
138
139        /**
140         * assoc array of operations => opData; operations are added by the register()
141         * method or by parsing an external WSDL definition
142         * @var array
143         * @access private
144         */
145        var $operations = array();
146        /**
147         * wsdl instance (if one)
148         * @var mixed
149         * @access private
150         */
151        var $wsdl = false;
152        /**
153         * URL for WSDL (if one)
154         * @var mixed
155         * @access private
156         */
157        var $externalWSDLURL = false;
158        /**
159         * whether to append debug to response as XML comment
160         * @var boolean
161         * @access public
162         */
163        var $debug_flag = false;
164
165
166        /**
167        * constructor
168    * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
169        *
170    * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
171        * @access   public
172        */
173        function nusoap_server($wsdl=false){
174                parent::nusoap_base();
175                // turn on debugging?
176                global $debug;
177                global $HTTP_SERVER_VARS;
178
179                if (isset($_SERVER)) {
180                        $this->debug("_SERVER is defined:");
181                        $this->appendDebug($this->varDump($_SERVER));
182                } elseif (isset($HTTP_SERVER_VARS)) {
183                        $this->debug("HTTP_SERVER_VARS is defined:");
184                        $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
185                } else {
186                        $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
187                }
188
189                if (isset($debug)) {
190                        $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
191                        $this->debug_flag = $debug;
192                } elseif (isset($_SERVER['QUERY_STRING'])) {
193                        $qs = explode('&', $_SERVER['QUERY_STRING']);
194                        foreach ($qs as $v) {
195                                if (substr($v, 0, 6) == 'debug=') {
196                                        $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
197                                        $this->debug_flag = substr($v, 6);
198                                }
199                        }
200                } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
201                        $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
202                        foreach ($qs as $v) {
203                                if (substr($v, 0, 6) == 'debug=') {
204                                        $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
205                                        $this->debug_flag = substr($v, 6);
206                                }
207                        }
208                }
209
210                // wsdl
211                if($wsdl){
212                        $this->debug("In nusoap_server, WSDL is specified");
213                        if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
214                                $this->wsdl = $wsdl;
215                                $this->externalWSDLURL = $this->wsdl->wsdl;
216                                $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
217                        } else {
218                                $this->debug('Create wsdl from ' . $wsdl);
219                                $this->wsdl = new wsdl($wsdl);
220                                $this->externalWSDLURL = $wsdl;
221                        }
222                        $this->appendDebug($this->wsdl->getDebug());
223                        $this->wsdl->clearDebug();
224                        if($err = $this->wsdl->getError()){
225                                die('WSDL ERROR: '.$err);
226                        }
227                }
228        }
229
230        /**
231        * processes request and returns response
232        *
233        * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
234        * @access   public
235        */
236        function service($data){
237                global $HTTP_SERVER_VARS;
238
239                if (isset($_SERVER['REQUEST_METHOD'])) {
240                        $rm = $_SERVER['REQUEST_METHOD'];
241                } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
242                        $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
243                } else {
244                        $rm = '';
245                }
246
247                if (isset($_SERVER['QUERY_STRING'])) {
248                        $qs = $_SERVER['QUERY_STRING'];
249                } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
250                        $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
251                } else {
252                        $qs = '';
253                }
254                $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
255
256                if ($rm == 'POST') {
257                        $this->debug("In service, invoke the request");
258                        $this->parse_request($data);
259                        if (! $this->fault) {
260                                $this->invoke_method();
261                        }
262                        if (! $this->fault) {
263                                $this->serialize_return();
264                        }
265                        $this->send_response();
266                } elseif (preg_match('/wsdl/', $qs) ){
267                        $this->debug("In service, this is a request for WSDL");
268                        if ($this->externalWSDLURL){
269              if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
270                                $this->debug("In service, re-direct for WSDL");
271                                header('Location: '.$this->externalWSDLURL);
272              } else { // assume file
273                                $this->debug("In service, use file passthru for WSDL");
274                header("Content-Type: text/xml\r\n");
275                                $pos = strpos($this->externalWSDLURL, "file://");
276                                if ($pos === false) {
277                                        $filename = $this->externalWSDLURL;
278                                } else {
279                                        $filename = substr($this->externalWSDLURL, $pos + 7);
280                                }
281                $fp = fopen($this->externalWSDLURL, 'r');
282                fpassthru($fp);
283              }
284                        } elseif ($this->wsdl) {
285                                $this->debug("In service, serialize WSDL");
286                                header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
287                                print $this->wsdl->serialize($this->debug_flag);
288                                if ($this->debug_flag) {
289                                        $this->debug('wsdl:');
290                                        $this->appendDebug($this->varDump($this->wsdl));
291                                        print $this->getDebugAsXMLComment();
292                                }
293                        } else {
294                                $this->debug("In service, there is no WSDL");
295                                header("Content-Type: text/html; charset=ISO-8859-1\r\n");
296                                print "This service does not provide WSDL";
297                        }
298                } elseif ($this->wsdl) {
299                        $this->debug("In service, return Web description");
300                        print $this->wsdl->webDescription();
301                } else {
302                        $this->debug("In service, no Web description");
303                        header("Content-Type: text/html; charset=ISO-8859-1\r\n");
304                        print "This service does not provide a Web description";
305                }
306        }
307
308        /**
309        * parses HTTP request headers.
310        *
311        * The following fields are set by this function (when successful)
312        *
313        * headers
314        * request
315        * xml_encoding
316        * SOAPAction
317        *
318        * @access   private
319        */
320        function parse_http_headers() {
321                global $HTTP_SERVER_VARS;
322
323                $this->request = '';
324                $this->SOAPAction = '';
325                if(function_exists('getallheaders')){
326                        $this->debug("In parse_http_headers, use getallheaders");
327                        $headers = getallheaders();
328                        foreach($headers as $k=>$v){
329                                $k = strtolower($k);
330                                $this->headers[$k] = $v;
331                                $this->request .= "$k: $v\r\n";
332                                $this->debug("$k: $v");
333                        }
334                        // get SOAPAction header
335                        if(isset($this->headers['soapaction'])){
336                                $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
337                        }
338                        // get the character encoding of the incoming request
339                        if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
340                                $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
341                                if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
342                                        $this->xml_encoding = strtoupper($enc);
343                                } else {
344                                        $this->xml_encoding = 'US-ASCII';
345                                }
346                        } else {
347                                // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
348                                $this->xml_encoding = 'ISO-8859-1';
349                        }
350                } elseif(isset($_SERVER) && is_array($_SERVER)){
351                        $this->debug("In parse_http_headers, use _SERVER");
352                        foreach ($_SERVER as $k => $v) {
353                                if (substr($k, 0, 5) == 'HTTP_') {
354                                        $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
355                                } else {
356                                        $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
357                                }
358                                if ($k == 'soapaction') {
359                                        // get SOAPAction header
360                                        $k = 'SOAPAction';
361                                        $v = str_replace('"', '', $v);
362                                        $v = str_replace('\\', '', $v);
363                                        $this->SOAPAction = $v;
364                                } else if ($k == 'content-type') {
365                                        // get the character encoding of the incoming request
366                                        if (strpos($v, '=')) {
367                                                $enc = substr(strstr($v, '='), 1);
368                                                $enc = str_replace('"', '', $enc);
369                                                $enc = str_replace('\\', '', $enc);
370                                                if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
371                                                        $this->xml_encoding = strtoupper($enc);
372                                                } else {
373                                                        $this->xml_encoding = 'US-ASCII';
374                                                }
375                                        } else {
376                                                // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
377                                                $this->xml_encoding = 'ISO-8859-1';
378                                        }
379                                }
380                                $this->headers[$k] = $v;
381                                $this->request .= "$k: $v\r\n";
382                                $this->debug("$k: $v");
383                        }
384                } elseif (is_array($HTTP_SERVER_VARS)) {
385                        $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
386                        foreach ($HTTP_SERVER_VARS as $k => $v) {
387                                if (substr($k, 0, 5) == 'HTTP_') {
388                                        $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                            $k = strtolower(substr($k, 5));
389                                } else {
390                                        $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                               $k = strtolower($k);
391                                }
392                                if ($k == 'soapaction') {
393                                        // get SOAPAction header
394                                        $k = 'SOAPAction';
395                                        $v = str_replace('"', '', $v);
396                                        $v = str_replace('\\', '', $v);
397                                        $this->SOAPAction = $v;
398                                } else if ($k == 'content-type') {
399                                        // get the character encoding of the incoming request
400                                        if (strpos($v, '=')) {
401                                                $enc = substr(strstr($v, '='), 1);
402                                                $enc = str_replace('"', '', $enc);
403                                                $enc = str_replace('\\', '', $enc);
404                                                if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
405                                                        $this->xml_encoding = strtoupper($enc);
406                                                } else {
407                                                        $this->xml_encoding = 'US-ASCII';
408                                                }
409                                        } else {
410                                                // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
411                                                $this->xml_encoding = 'ISO-8859-1';
412                                        }
413                                }
414                                $this->headers[$k] = $v;
415                                $this->request .= "$k: $v\r\n";
416                                $this->debug("$k: $v");
417                        }
418                } else {
419                        $this->debug("In parse_http_headers, HTTP headers not accessible");
420                        $this->setError("HTTP headers not accessible");
421                }
422        }
423
424        /**
425        * parses a request
426        *
427        * The following fields are set by this function (when successful)
428        *
429        * headers
430        * request
431        * xml_encoding
432        * SOAPAction
433        * request
434        * requestSOAP
435        * methodURI
436        * methodname
437        * methodparams
438        * requestHeaders
439        * document
440        *
441        * This sets the fault field on error
442        *
443        * @param    string $data XML string
444        * @access   private
445        */
446        function parse_request($data='') {
447                $this->debug('entering parse_request()');
448                $this->parse_http_headers();
449                $this->debug('got character encoding: '.$this->xml_encoding);
450                // uncompress if necessary
451                if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
452                        $this->debug('got content encoding: ' . $this->headers['content-encoding']);
453                        if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
454                        // if decoding works, use it. else assume data wasn't gzencoded
455                                if (function_exists('gzuncompress')) {
456                                        if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
457                                                $data = $degzdata;
458                                        } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
459                                                $data = $degzdata;
460                                        } else {
461                                                $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
462                                                return;
463                                        }
464                                } else {
465                                        $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
466                                        return;
467                                }
468                        }
469                }
470                $this->request .= "\r\n".$data;
471                $data = $this->parseRequest($this->headers, $data);
472                $this->requestSOAP = $data;
473                $this->debug('leaving parse_request');
474        }
475
476        /**
477        * invokes a PHP function for the requested SOAP method
478        *
479        * The following fields are set by this function (when successful)
480        *
481        * methodreturn
482        *
483        * Note that the PHP function that is called may also set the following
484        * fields to affect the response sent to the client
485        *
486        * responseHeaders
487        * outgoing_headers
488        *
489        * This sets the fault field on error
490        *
491        * @access   private
492        */
493        function invoke_method() {
494                $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
495
496                //
497                // if you are debugging in this area of the code, your service uses a class to implement methods,
498                // you use SOAP RPC, and the client is .NET, please be aware of the following...
499                // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
500                // method name.  that is fine for naming the .NET methods.  it is not fine for properly constructing
501                // the XML request and reading the XML response.  you need to add the RequestElementName and
502                // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
503                // generates for the method.  these parameters are used to specify the correct XML element names
504                // for .NET to use, i.e. the names with the '.' in them.
505                //
506                $orig_methodname = $this->methodname;
507                if ($this->wsdl) {
508                        if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
509                                $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
510                                $this->appendDebug('opData=' . $this->varDump($this->opData));
511                        } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
512                                // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
513                                $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
514                                $this->appendDebug('opData=' . $this->varDump($this->opData));
515                                $this->methodname = $this->opData['name'];
516                        } else {
517                                $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
518                                $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
519                                return;
520                        }
521                } else {
522                        $this->debug('in invoke_method, no WSDL to validate method');
523                }
524
525                // if a . is present in $this->methodname, we see if there is a class in scope,
526                // which could be referred to. We will also distinguish between two deliminators,
527                // to allow methods to be called a the class or an instance
528                if (strpos($this->methodname, '..') > 0) {
529                        $delim = '..';
530                } else if (strpos($this->methodname, '.') > 0) {
531                        $delim = '.';
532                } else {
533                        $delim = '';
534                }
535                $this->debug("in invoke_method, delim=$delim");
536
537                $class = '';
538                $method = '';
539                if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
540                        $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
541                        if (class_exists($try_class)) {
542                                // get the class and method name
543                                $class = $try_class;
544                                $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
545                                $this->debug("in invoke_method, class=$class method=$method delim=$delim");
546                        } else {
547                                $this->debug("in invoke_method, class=$try_class not found");
548                        }
549                } else {
550                        $try_class = '';
551                        $this->debug("in invoke_method, no class to try");
552                }
553
554                // does method exist?
555                if ($class == '') {
556                        if (!function_exists($this->methodname)) {
557                                $this->debug("in invoke_method, function '$this->methodname' not found!");
558                                $this->result = 'fault: method not found';
559                                $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
560                                return;
561                        }
562                } else {
563                        $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
564                        if (!in_array($method_to_compare, get_class_methods($class))) {
565                                $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
566                                $this->result = 'fault: method not found';
567                                $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
568                                return;
569                        }
570                }
571
572                // evaluate message, getting back parameters
573                // verify that request parameters match the method's signature
574                if(! $this->verify_method($this->methodname,$this->methodparams)){
575                        // debug
576                        $this->debug('ERROR: request not verified against method signature');
577                        $this->result = 'fault: request failed validation against method signature';
578                        // return fault
579                        $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
580                        return;
581                }
582
583                // if there are parameters to pass
584                $this->debug('in invoke_method, params:');
585                $this->appendDebug($this->varDump($this->methodparams));
586                $this->debug("in invoke_method, calling '$this->methodname'");
587                if (!function_exists('call_user_func_array')) {
588                        if ($class == '') {
589                                $this->debug('in invoke_method, calling function using eval()');
590                                $funcCall = "\$this->methodreturn = $this->methodname(";
591                        } else {
592                                if ($delim == '..') {
593                                        $this->debug('in invoke_method, calling class method using eval()');
594                                        $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
595                                } else {
596                                        $this->debug('in invoke_method, calling instance method using eval()');
597                                        // generate unique instance name
598                                        $instname = "\$inst_".time();
599                                        $funcCall = $instname." = new ".$class."(); ";
600                                        $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
601                                }
602                        }
603                        if ($this->methodparams) {
604                                foreach ($this->methodparams as $param) {
605                                        if (is_array($param) || is_object($param)) {
606                                                $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
607                                                return;
608                                        }
609                                        $funcCall .= "\"$param\",";
610                                }
611                                $funcCall = substr($funcCall, 0, -1);
612                        }
613                        $funcCall .= ');';
614                        $this->debug('in invoke_method, function call: '.$funcCall);
615                        @eval($funcCall);
616                } else {
617                        if ($class == '') {
618                                $this->debug('in invoke_method, calling function using call_user_func_array()');
619                                $call_arg = "$this->methodname";        // straight assignment changes $this->methodname to lower case after call_user_func_array()
620                        } elseif ($delim == '..') {
621                                $this->debug('in invoke_method, calling class method using call_user_func_array()');
622                                $call_arg = array ($class, $method);
623                        } else {
624                                $this->debug('in invoke_method, calling instance method using call_user_func_array()');
625                                $instance = new $class ();
626                                $call_arg = array(&$instance, $method);
627                        }
628                        if (is_array($this->methodparams)) {
629                                $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
630                        } else {
631                                $this->methodreturn = call_user_func_array($call_arg, array());
632                        }
633                }
634        $this->debug('in invoke_method, methodreturn:');
635        $this->appendDebug($this->varDump($this->methodreturn));
636                $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
637        }
638
639        /**
640        * serializes the return value from a PHP function into a full SOAP Envelope
641        *
642        * The following fields are set by this function (when successful)
643        *
644        * responseSOAP
645        *
646        * This sets the fault field on error
647        *
648        * @access   private
649        */
650        function serialize_return() {
651                $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
652                // if fault
653                if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
654                        $this->debug('got a fault object from method');
655                        $this->fault = $this->methodreturn;
656                        return;
657                } elseif ($this->methodreturnisliteralxml) {
658                        $return_val = $this->methodreturn;
659                // returned value(s)
660                } else {
661                        $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
662                        $this->debug('serializing return value');
663                        if($this->wsdl){
664                                if (sizeof($this->opData['output']['parts']) > 1) {
665                                        $this->debug('more than one output part, so use the method return unchanged');
666                                $opParams = $this->methodreturn;
667                            } elseif (sizeof($this->opData['output']['parts']) == 1) {
668                                        $this->debug('exactly one output part, so wrap the method return in a simple array');
669                                        // TODO: verify that it is not already wrapped!
670                                //foreach ($this->opData['output']['parts'] as $name => $type) {
671                                        //      $this->debug('wrap in element named ' . $name);
672                                //}
673                                $opParams = array($this->methodreturn);
674                            }
675                            $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
676                            $this->appendDebug($this->wsdl->getDebug());
677                            $this->wsdl->clearDebug();
678                                if($errstr = $this->wsdl->getError()){
679                                        $this->debug('got wsdl error: '.$errstr);
680                                        $this->fault('SOAP-ENV:Server', 'unable to serialize result');
681                                        return;
682                                }
683                        } else {
684                                if (isset($this->methodreturn)) {
685                                        $return_val = $this->serialize_val($this->methodreturn, 'return');
686                                } else {
687                                        $return_val = '';
688                                        $this->debug('in absence of WSDL, assume void return for backward compatibility');
689                                }
690                        }
691                }
692                $this->debug('return value:');
693                $this->appendDebug($this->varDump($return_val));
694
695                $this->debug('serializing response');
696                if ($this->wsdl) {
697                        $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
698                        if ($this->opData['style'] == 'rpc') {
699                                $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
700                                if ($this->opData['output']['use'] == 'literal') {
701                                        // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
702                                        if ($this->methodURI) {
703                                                $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
704                                        } else {
705                                                $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
706                                        }
707                                } else {
708                                        if ($this->methodURI) {
709                                                $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
710                                        } else {
711                                                $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
712                                        }
713                                }
714                        } else {
715                                $this->debug('style is not rpc for serialization: assume document');
716                                $payload = $return_val;
717                        }
718                } else {
719                        $this->debug('do not have WSDL for serialization: assume rpc/encoded');
720                        $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
721                }
722                $this->result = 'successful';
723                if($this->wsdl){
724                        //if($this->debug_flag){
725                $this->appendDebug($this->wsdl->getDebug());
726            //  }
727                        if (isset($this->opData['output']['encodingStyle'])) {
728                                $encodingStyle = $this->opData['output']['encodingStyle'];
729                        } else {
730                                $encodingStyle = '';
731                        }
732                        // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
733                        $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
734                } else {
735                        $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
736                }
737                $this->debug("Leaving serialize_return");
738        }
739
740        /**
741        * sends an HTTP response
742        *
743        * The following fields are set by this function (when successful)
744        *
745        * outgoing_headers
746        * response
747        *
748        * @access   private
749        */
750        function send_response() {
751                $this->debug('Enter send_response');
752                if ($this->fault) {
753                        $payload = $this->fault->serialize();
754                        $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
755                        $this->outgoing_headers[] = "Status: 500 Internal Server Error";
756                } else {
757                        $payload = $this->responseSOAP;
758                        // Some combinations of PHP+Web server allow the Status
759                        // to come through as a header.  Since OK is the default
760                        // just do nothing.
761                        // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
762                        // $this->outgoing_headers[] = "Status: 200 OK";
763                }
764        // add debug data if in debug mode
765                if(isset($this->debug_flag) && $this->debug_flag){
766                $payload .= $this->getDebugAsXMLComment();
767        }
768                $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
769                preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
770                $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
771                // Let the Web server decide about this
772                //$this->outgoing_headers[] = "Connection: Close\r\n";
773                $payload = $this->getHTTPBody($payload);
774                $type = $this->getHTTPContentType();
775                $charset = $this->getHTTPContentTypeCharset();
776                $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
777                //begin code to compress payload - by John
778                // NOTE: there is no way to know whether the Web server will also compress
779                // this data.
780                if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {     
781                        if (strstr($this->headers['accept-encoding'], 'gzip')) {
782                                if (function_exists('gzencode')) {
783                                        if (isset($this->debug_flag) && $this->debug_flag) {
784                                                $payload .= "<!-- Content being gzipped -->";
785                                        }
786                                        $this->outgoing_headers[] = "Content-Encoding: gzip";
787                                        $payload = gzencode($payload);
788                                } else {
789                                        if (isset($this->debug_flag) && $this->debug_flag) {
790                                                $payload .= "<!-- Content will not be gzipped: no gzencode -->";
791                                        }
792                                }
793                        } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
794                                // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
795                                // instead of gzcompress output,
796                                // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
797                                if (function_exists('gzdeflate')) {
798                                        if (isset($this->debug_flag) && $this->debug_flag) {
799                                                $payload .= "<!-- Content being deflated -->";
800                                        }
801                                        $this->outgoing_headers[] = "Content-Encoding: deflate";
802                                        $payload = gzdeflate($payload);
803                                } else {
804                                        if (isset($this->debug_flag) && $this->debug_flag) {
805                                                $payload .= "<!-- Content will not be deflated: no gzcompress -->";
806                                        }
807                                }
808                        }
809                }
810                //end code
811                $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
812                reset($this->outgoing_headers);
813                foreach($this->outgoing_headers as $hdr){
814                        header($hdr, false);
815                }
816                print $payload;
817                $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
818        }
819
820        /**
821        * takes the value that was created by parsing the request
822        * and compares to the method's signature, if available.
823        *
824        * @param        string  $operation      The operation to be invoked
825        * @param        array   $request        The array of parameter values
826        * @return       boolean Whether the operation was found
827        * @access   private
828        */
829        function verify_method($operation,$request){
830                if(isset($this->wsdl) && is_object($this->wsdl)){
831                        if($this->wsdl->getOperationData($operation)){
832                                return true;
833                        }
834            } elseif(isset($this->operations[$operation])){
835                        return true;
836                }
837                return false;
838        }
839
840        /**
841        * processes SOAP message received from client
842        *
843        * @param        array   $headers        The HTTP headers
844        * @param        string  $data           unprocessed request data from client
845        * @return       mixed   value of the message, decoded into a PHP type
846        * @access   private
847        */
848    function parseRequest($headers, $data) {
849                $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
850                $this->appendDebug($this->varDump($headers));
851        if (!isset($headers['content-type'])) {
852                        $this->setError('Request not of type text/xml (no content-type header)');
853                        return false;
854        }
855                if (!strstr($headers['content-type'], 'text/xml')) {
856                        $this->setError('Request not of type text/xml');
857                        return false;
858                }
859                if (strpos($headers['content-type'], '=')) {
860                        $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
861                        $this->debug('Got response encoding: ' . $enc);
862                        if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
863                                $this->xml_encoding = strtoupper($enc);
864                        } else {
865                                $this->xml_encoding = 'US-ASCII';
866                        }
867                } else {
868                        // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
869                        $this->xml_encoding = 'ISO-8859-1';
870                }
871                $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
872                // parse response, get soap parser obj
873                $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
874                // parser debug
875                $this->debug("parser debug: \n".$parser->getDebug());
876                // if fault occurred during message parsing
877                if($err = $parser->getError()){
878                        $this->result = 'fault: error in msg parsing: '.$err;
879                        $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
880                // else successfully parsed request into soapval object
881                } else {
882                        // get/set methodname
883                        $this->methodURI = $parser->root_struct_namespace;
884                        $this->methodname = $parser->root_struct_name;
885                        $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
886                        $this->debug('calling parser->get_soapbody()');
887                        $this->methodparams = $parser->get_soapbody();
888                        // get SOAP headers
889                        $this->requestHeaders = $parser->getHeaders();
890                        // get SOAP Header
891                        $this->requestHeader = $parser->get_soapheader();
892            // add document for doclit support
893            $this->document = $parser->document;
894                }
895         }
896
897        /**
898        * gets the HTTP body for the current response.
899        *
900        * @param string $soapmsg The SOAP payload
901        * @return string The HTTP body, which includes the SOAP payload
902        * @access private
903        */
904        function getHTTPBody($soapmsg) {
905                return $soapmsg;
906        }
907       
908        /**
909        * gets the HTTP content type for the current response.
910        *
911        * Note: getHTTPBody must be called before this.
912        *
913        * @return string the HTTP content type for the current response.
914        * @access private
915        */
916        function getHTTPContentType() {
917                return 'text/xml';
918        }
919       
920        /**
921        * gets the HTTP content type charset for the current response.
922        * returns false for non-text content types.
923        *
924        * Note: getHTTPBody must be called before this.
925        *
926        * @return string the HTTP content type charset for the current response.
927        * @access private
928        */
929        function getHTTPContentTypeCharset() {
930                return $this->soap_defencoding;
931        }
932
933        /**
934        * add a method to the dispatch map (this has been replaced by the register method)
935        *
936        * @param    string $methodname
937        * @param    string $in array of input values
938        * @param    string $out array of output values
939        * @access   public
940        * @deprecated
941        */
942        function add_to_map($methodname,$in,$out){
943                        $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
944        }
945
946        /**
947        * register a service function with the server
948        *
949        * @param    string $name the name of the PHP function, class.method or class..method
950        * @param    array $in assoc array of input values: key = param name, value = param type
951        * @param    array $out assoc array of output values: key = param name, value = param type
952        * @param        mixed $namespace the element namespace for the method or false
953        * @param        mixed $soapaction the soapaction for the method or false
954        * @param        mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
955        * @param        mixed $use optional (encoded|literal) or false
956        * @param        string $documentation optional Description to include in WSDL
957        * @param        string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
958        * @access   public
959        */
960        function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
961                global $HTTP_SERVER_VARS;
962
963                if($this->externalWSDLURL){
964                        die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
965                }
966                if (! $name) {
967                        die('You must specify a name when you register an operation');
968                }
969                if (!is_array($in)) {
970                        die('You must provide an array for operation inputs');
971                }
972                if (!is_array($out)) {
973                        die('You must provide an array for operation outputs');
974                }
975                if(false == $namespace) {
976                }
977                if(false == $soapaction) {
978                        if (isset($_SERVER)) {
979                                $SERVER_NAME = $_SERVER['SERVER_NAME'];
980                                $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
981                                $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
982                        } elseif (isset($HTTP_SERVER_VARS)) {
983                                $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
984                                $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
985                                $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
986                        } else {
987                                $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
988                        }
989                if ($HTTPS == '1' || $HTTPS == 'on') {
990                        $SCHEME = 'https';
991                } else {
992                        $SCHEME = 'http';
993                }
994                        $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
995                }
996                if(false == $style) {
997                        $style = "rpc";
998                }
999                if(false == $use) {
1000                        $use = "encoded";
1001                }
1002                if ($use == 'encoded' && $encodingStyle == '') {
1003                        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
1004                }
1005
1006                $this->operations[$name] = array(
1007            'name' => $name,
1008            'in' => $in,
1009            'out' => $out,
1010            'namespace' => $namespace,
1011            'soapaction' => $soapaction,
1012            'style' => $style);
1013        if($this->wsdl){
1014                $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
1015            }
1016                return true;
1017        }
1018
1019        /**
1020        * Specify a fault to be returned to the client.
1021        * This also acts as a flag to the server that a fault has occured.
1022        *
1023        * @param        string $faultcode
1024        * @param        string $faultstring
1025        * @param        string $faultactor
1026        * @param        string $faultdetail
1027        * @access   public
1028        */
1029        function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
1030                if ($faultdetail == '' && $this->debug_flag) {
1031                        $faultdetail = $this->getDebug();
1032                }
1033                $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
1034                $this->fault->soap_defencoding = $this->soap_defencoding;
1035        }
1036
1037    /**
1038    * Sets up wsdl object.
1039    * Acts as a flag to enable internal WSDL generation
1040    *
1041    * @param string $serviceName, name of the service
1042    * @param mixed $namespace optional 'tns' service namespace or false
1043    * @param mixed $endpoint optional URL of service endpoint or false
1044    * @param string $style optional (rpc|document) WSDL style (also specified by operation)
1045    * @param string $transport optional SOAP transport
1046    * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
1047    */
1048    function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
1049    {
1050        global $HTTP_SERVER_VARS;
1051
1052                if (isset($_SERVER)) {
1053                        $SERVER_NAME = $_SERVER['SERVER_NAME'];
1054                        $SERVER_PORT = $_SERVER['SERVER_PORT'];
1055                        $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
1056                        $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
1057                } elseif (isset($HTTP_SERVER_VARS)) {
1058                        $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
1059                        $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
1060                        $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
1061                        $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
1062                } else {
1063                        $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
1064                }
1065                // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
1066                $colon = strpos($SERVER_NAME,":");
1067                if ($colon) {
1068                    $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
1069                }
1070                if ($SERVER_PORT == 80) {
1071                        $SERVER_PORT = '';
1072                } else {
1073                        $SERVER_PORT = ':' . $SERVER_PORT;
1074                }
1075        if(false == $namespace) {
1076            $namespace = "http://$SERVER_NAME/soap/$serviceName";
1077        }
1078       
1079        if(false == $endpoint) {
1080                if ($HTTPS == '1' || $HTTPS == 'on') {
1081                        $SCHEME = 'https';
1082                } else {
1083                        $SCHEME = 'http';
1084                }
1085            $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
1086        }
1087       
1088        if(false == $schemaTargetNamespace) {
1089            $schemaTargetNamespace = $namespace;
1090        }
1091       
1092                $this->wsdl = new wsdl;
1093                $this->wsdl->serviceName = $serviceName;
1094        $this->wsdl->endpoint = $endpoint;
1095                $this->wsdl->namespaces['tns'] = $namespace;
1096                $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
1097                $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
1098                if ($schemaTargetNamespace != $namespace) {
1099                        $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
1100                }
1101        $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
1102        if ($style == 'document') {
1103                $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
1104        }
1105        $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
1106        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
1107        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
1108        $this->wsdl->bindings[$serviceName.'Binding'] = array(
1109                'name'=>$serviceName.'Binding',
1110            'style'=>$style,
1111            'transport'=>$transport,
1112            'portType'=>$serviceName.'PortType');
1113        $this->wsdl->ports[$serviceName.'Port'] = array(
1114                'binding'=>$serviceName.'Binding',
1115            'location'=>$endpoint,
1116            'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
1117    }
1118}
1119
1120/**
1121 * Backward compatibility
1122 */
1123class soap_server extends nusoap_server {
1124}
1125
1126
1127?>
Note: See TracBrowser for help on using the repository browser.