4 $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
6 NuSOAP - Web Services Toolkit for PHP
\r
8 Copyright (c) 2002 NuSphere Corporation
\r
10 This library is free software; you can redistribute it and/or
\r
11 modify it under the terms of the GNU Lesser General Public
\r
12 License as published by the Free Software Foundation; either
\r
13 version 2.1 of the License, or (at your option) any later version.
\r
15 This library is distributed in the hope that it will be useful,
\r
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
18 Lesser General Public License for more details.
\r
20 You should have received a copy of the GNU Lesser General Public
\r
21 License along with this library; if not, write to the Free Software
\r
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
24 The NuSOAP project home is:
\r
25 http://sourceforge.net/projects/nusoap/
\r
27 The primary support for NuSOAP is the mailing list:
\r
28 nusoap-general@lists.sourceforge.net
\r
30 If you have any questions or comments, please email:
\r
34 http://dietrich.ganx4.com/nusoap
\r
36 NuSphere Corporation
\r
37 http://www.nusphere.com
\r
42 * Some of the standards implmented in whole or part by NuSOAP:
\r
44 * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
\r
45 * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
\r
46 * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
\r
47 * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
\r
48 * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
\r
49 * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
\r
50 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
\r
51 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
\r
52 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
\r
57 * This is a modified version of nusoap for usage of Axis2
\r
58 * for some reason it does not marshall the SOAP Body correct for Axis2 on Linux Platforms
\r
64 // necessary classes
\r
65 require_once('class.soapclient.php');
\r
66 require_once('class.soap_val.php');
\r
67 require_once('class.soap_parser.php');
\r
68 require_once('class.soap_fault.php');
\r
70 // transport classes
\r
71 require_once('class.soap_transport_http.php');
\r
73 // optional add-on classes
\r
74 require_once('class.xmlschema.php');
\r
75 require_once('class.wsdl.php');
\r
78 require_once('class.soap_server.php');*/
\r
80 // class variable emulation
\r
81 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
\r
82 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
\r
88 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
89 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
90 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
95 * Identification for HTTP headers.
\r
100 var $title = 'NuSOAP';
\r
102 * Version for HTTP headers.
\r
107 var $version = '0.7.3';
\r
109 * CVS revision for HTTP headers.
\r
114 var $revision = '$Revision: 1.114 $';
\r
116 * Current error string (manipulated by getError/setError)
\r
121 var $error_str = '';
\r
123 * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
\r
128 var $debug_str = '';
\r
130 * toggles automatic encoding of special characters as entities
\r
131 * (should always be true, I think)
\r
136 var $charencoding = true;
\r
138 * the debug level for this instance
\r
146 * set schema version
\r
151 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
\r
154 * charset encoding for outgoing messages
\r
159 var $soap_defencoding = 'ISO-8859-1';
\r
160 //var $soap_defencoding = 'UTF-8';
\r
163 * namespaces in an array of prefix => uri
\r
165 * this is "seeded" by a set of constants, but it may be altered by code
\r
170 var $namespaces = array(
\r
171 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
\r
172 'xsd' => 'http://www.w3.org/2001/XMLSchema',
\r
173 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
\r
174 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
\r
178 * namespaces used in the current context, e.g. during serialization
\r
183 var $usedNamespaces = array();
\r
186 * XML Schema types in an array of uri => (array of xml type => php type)
\r
187 * is this legacy yet?
\r
188 * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
\r
192 var $typemap = array(
\r
193 'http://www.w3.org/2001/XMLSchema' => array(
\r
194 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
\r
195 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
\r
196 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
\r
197 // abstract "any" types
\r
198 'anyType'=>'string','anySimpleType'=>'string',
\r
199 // derived datatypes
\r
200 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
\r
201 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
\r
202 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
\r
203 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
\r
204 'http://www.w3.org/2000/10/XMLSchema' => array(
\r
205 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
\r
206 'float'=>'double','dateTime'=>'string',
\r
207 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
\r
208 'http://www.w3.org/1999/XMLSchema' => array(
\r
209 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
\r
210 'float'=>'double','dateTime'=>'string',
\r
211 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
\r
212 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
\r
213 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
\r
214 'http://xml.apache.org/xml-soap' => array('Map')
\r
218 * XML entities to convert
\r
223 * @see expandEntities
\r
225 var $xmlEntities = array('quot' => '"','amp' => '&',
\r
226 'lt' => '<','gt' => '>','apos' => "'");
\r
233 function nusoap_base() {
\r
234 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
\r
238 * gets the global debug level, which applies to future instances
\r
240 * @return integer Debug level 0-9, where 0 turns off
\r
243 function getGlobalDebugLevel() {
\r
244 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
\r
248 * sets the global debug level, which applies to future instances
\r
250 * @param int $level Debug level 0-9, where 0 turns off
\r
253 function setGlobalDebugLevel($level) {
\r
254 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
\r
258 * gets the debug level for this instance
\r
260 * @return int Debug level 0-9, where 0 turns off
\r
263 function getDebugLevel() {
\r
264 return $this->debugLevel;
\r
268 * sets the debug level for this instance
\r
270 * @param int $level Debug level 0-9, where 0 turns off
\r
273 function setDebugLevel($level) {
\r
274 $this->debugLevel = $level;
\r
278 * adds debug data to the instance debug string with formatting
\r
280 * @param string $string debug data
\r
283 function debug($string){
\r
284 if ($this->debugLevel > 0) {
\r
285 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
\r
290 * adds debug data to the instance debug string without formatting
\r
292 * @param string $string debug data
\r
295 function appendDebug($string){
\r
296 //echo "## appendDebug: ".$string."<br/>";
\r
297 if ($this->debugLevel > 0) {
\r
298 // it would be nice to use a memory stream here to use
\r
299 // memory more efficiently
\r
300 $this->debug_str .= $string;
\r
305 * clears the current debug data for this instance
\r
309 function clearDebug() {
\r
310 // it would be nice to use a memory stream here to use
\r
311 // memory more efficiently
\r
312 $this->debug_str = '';
\r
316 * gets the current debug data for this instance
\r
318 * @return debug data
\r
321 function &getDebug() {
\r
322 // it would be nice to use a memory stream here to use
\r
323 // memory more efficiently
\r
324 return $this->debug_str;
\r
328 * gets the current debug data for this instance as an XML comment
\r
329 * this may change the contents of the debug data
\r
331 * @return debug data as an XML comment
\r
334 function &getDebugAsXMLComment() {
\r
335 // it would be nice to use a memory stream here to use
\r
336 // memory more efficiently
\r
337 while (strpos($this->debug_str, '--')) {
\r
338 $this->debug_str = str_replace('--', '- -', $this->debug_str);
\r
340 $ret = "<!--\n" . $this->debug_str . "\n-->";
\r
345 * expands entities, e.g. changes '<' to '<'.
\r
347 * @param string $val The string in which to expand entities.
\r
350 function expandEntities($val) {
\r
351 if ($this->charencoding) {
\r
352 $val = str_replace('&', '&', $val);
\r
353 $val = str_replace("'", ''', $val);
\r
354 $val = str_replace('"', '"', $val);
\r
355 $val = str_replace('<', '<', $val);
\r
356 $val = str_replace('>', '>', $val);
\r
362 * returns error string if present
\r
364 * @return mixed error string or false
\r
367 function getError(){
\r
368 if($this->error_str != ''){
\r
369 return $this->error_str;
\r
375 * sets error string
\r
377 * @return boolean $string error string
\r
380 function setError($str){
\r
381 $this->error_str = $str;
\r
385 * detect if array is a simple array or a struct (associative array)
\r
387 * @param mixed $val The PHP array
\r
388 * @return string (arraySimple|arrayStruct)
\r
391 function isArraySimpleOrStruct($val) {
\r
392 $keyList = array_keys($val);
\r
393 foreach ($keyList as $keyListValue) {
\r
394 if (!is_int($keyListValue)) {
\r
395 return 'arrayStruct';
\r
398 return 'arraySimple';
\r
402 * serializes PHP values in accordance w/ section 5. Type information is
\r
403 * not serialized if $use == 'literal'.
\r
405 * @param mixed $val The value to serialize
\r
406 * @param string $name The name (local part) of the XML element
\r
407 * @param string $type The XML schema type (local part) for the element
\r
408 * @param string $name_ns The namespace for the name of the XML element
\r
409 * @param string $type_ns The namespace for the type of the element
\r
410 * @param array $attributes The attributes to serialize as name=>value pairs
\r
411 * @param string $use The WSDL "use" (encoded|literal)
\r
412 * @param boolean $soapval Whether this is called from soapval.
\r
413 * @return string The serialized element, possibly with child elements
\r
416 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
\r
417 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
\r
418 $this->appendDebug('value=' . $this->varDump($val));
\r
419 $this->appendDebug('attributes=' . $this->varDump($attributes));
\r
421 if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
\r
422 $this->debug("serialize_val: serialize soapval");
\r
423 $xml = $val->serialize($use);
\r
424 $this->appendDebug($val->getDebug());
\r
425 $val->clearDebug();
\r
426 $this->debug("serialize_val of soapval returning $xml");
\r
429 // force valid name if necessary
\r
430 if (is_numeric($name)) {
\r
431 $name = '__numeric_' . $name;
\r
432 } elseif (! $name) {
\r
435 // if name has ns, add ns prefix to name
\r
438 $prefix = 'nu'.rand(1000,9999);
\r
439 $name = $prefix.':'.$name;
\r
440 $xmlns .= " xmlns:$prefix=\"$name_ns\"";
\r
442 // if type is prefixed, create type prefix
\r
443 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
\r
444 // need to fix this. shouldn't default to xsd if no ns specified
\r
445 // w/o checking against typemap
\r
446 $type_prefix = 'xsd';
\r
447 } elseif($type_ns){
\r
448 $type_prefix = 'ns'.rand(1000,9999);
\r
449 $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
\r
451 // serialize attributes if present
\r
454 foreach($attributes as $k => $v){
\r
455 $atts .= " $k=\"".$this->expandEntities($v).'"';
\r
458 // serialize null value
\r
459 if (is_null($val)) {
\r
460 $this->debug("serialize_val: serialize null");
\r
461 if ($use == 'literal') {
\r
462 // TODO: depends on minOccurs
\r
463 $xml = "<$name$xmlns$atts/>";
\r
464 $this->debug("serialize_val returning $xml");
\r
467 if (isset($type) && isset($type_prefix)) {
\r
468 $type_str = " xsi:type=\"$type_prefix:$type\"";
\r
472 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
\r
473 $this->debug("serialize_val returning $xml");
\r
477 // serialize if an xsd built-in primitive type
\r
478 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
\r
479 $this->debug("serialize_val: serialize xsd built-in primitive type");
\r
480 if (is_bool($val)) {
\r
481 if ($type == 'boolean') {
\r
482 $val = $val ? 'true' : 'false';
\r
483 } elseif (! $val) {
\r
486 } else if (is_string($val)) {
\r
487 $val = $this->expandEntities($val);
\r
489 if ($use == 'literal') {
\r
490 $xml = "<$name$xmlns$atts>$val</$name>";
\r
491 $this->debug("serialize_val returning $xml");
\r
494 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
\r
495 $this->debug("serialize_val returning $xml");
\r
499 // detect type and serialize
\r
502 case (is_bool($val) || $type == 'boolean'):
\r
503 $this->debug("serialize_val: serialize boolean");
\r
504 if ($type == 'boolean') {
\r
505 $val = $val ? 'true' : 'false';
\r
506 } elseif (! $val) {
\r
509 if ($use == 'literal') {
\r
510 $xml .= "<$name$xmlns$atts>$val</$name>";
\r
512 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
\r
515 case (is_int($val) || is_long($val) || $type == 'int'):
\r
516 $this->debug("serialize_val: serialize int");
\r
517 if ($use == 'literal') {
\r
518 $xml .= "<$name$xmlns$atts>$val</$name>";
\r
520 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
\r
523 case (is_float($val)|| is_double($val) || $type == 'float'):
\r
524 $this->debug("serialize_val: serialize float");
\r
525 if ($use == 'literal') {
\r
526 $xml .= "<$name$xmlns$atts>$val</$name>";
\r
528 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
\r
531 case (is_string($val) || $type == 'string'):
\r
532 $this->debug("serialize_val: serialize string");
\r
533 $val = $this->expandEntities($val);
\r
534 if ($use == 'literal') {
\r
535 $xml .= "<$name$xmlns$atts>$val</$name>";
\r
537 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
\r
540 case is_object($val):
\r
541 $this->debug("serialize_val: serialize object");
\r
542 if (get_class($val) == 'soapval') {
\r
543 $this->debug("serialize_val: serialize soapval object");
\r
544 $pXml = $val->serialize($use);
\r
545 $this->appendDebug($val->getDebug());
\r
546 $val->clearDebug();
\r
549 $name = get_class($val);
\r
550 $this->debug("In serialize_val, used class name $name as element name");
\r
552 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
\r
554 foreach(get_object_vars($val) as $k => $v){
\r
555 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
\r
558 if(isset($type) && isset($type_prefix)){
\r
559 $type_str = " xsi:type=\"$type_prefix:$type\"";
\r
563 if ($use == 'literal') {
\r
564 $xml .= "<$name$xmlns$atts>$pXml</$name>";
\r
566 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
\r
570 case (is_array($val) || $type):
\r
571 // detect if struct or array
\r
572 $valueType = $this->isArraySimpleOrStruct($val);
\r
573 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
\r
574 $this->debug("serialize_val: serialize array");
\r
576 if(is_array($val) && count($val)> 0){
\r
577 foreach($val as $v){
\r
578 if(is_object($v) && get_class($v) == 'soapval'){
\r
579 $tt_ns = $v->type_ns;
\r
581 } elseif (is_array($v)) {
\r
582 $tt = $this->isArraySimpleOrStruct($v);
\r
586 $array_types[$tt] = 1;
\r
587 // TODO: for literal, the name should be $name
\r
588 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
\r
591 if(count($array_types) > 1){
\r
592 $array_typename = 'xsd:anyType';
\r
593 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
\r
594 if ($tt == 'integer') {
\r
597 $array_typename = 'xsd:'.$tt;
\r
598 } elseif(isset($tt) && $tt == 'arraySimple'){
\r
599 $array_typename = 'SOAP-ENC:Array';
\r
600 } elseif(isset($tt) && $tt == 'arrayStruct'){
\r
601 $array_typename = 'unnamed_struct_use_soapval';
\r
603 // if type is prefixed, create type prefix
\r
604 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
\r
605 $array_typename = 'xsd:' . $tt;
\r
606 } elseif ($tt_ns) {
\r
607 $tt_prefix = 'ns' . rand(1000, 9999);
\r
608 $array_typename = "$tt_prefix:$tt";
\r
609 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
\r
611 $array_typename = $tt;
\r
615 if ($use == 'literal') {
\r
617 } else if (isset($type) && isset($type_prefix)) {
\r
618 $type_str = " xsi:type=\"$type_prefix:$type\"";
\r
620 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
\r
624 if ($use == 'literal') {
\r
626 } else if (isset($type) && isset($type_prefix)) {
\r
627 $type_str = " xsi:type=\"$type_prefix:$type\"";
\r
629 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
\r
632 // TODO: for array in literal, there is no wrapper here
\r
633 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
\r
636 $this->debug("serialize_val: serialize struct");
\r
637 if(isset($type) && isset($type_prefix)){
\r
638 $type_str = " xsi:type=\"$type_prefix:$type\"";
\r
642 if ($use == 'literal') {
\r
643 $xml .= "<$name$xmlns$atts>";
\r
645 $xml .= "<$name$xmlns$type_str$atts>";
\r
647 foreach($val as $k => $v){
\r
649 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
\r
651 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
\r
652 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
\r
655 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
\r
658 $xml .= "</$name>";
\r
662 $this->debug("serialize_val: serialize unknown");
\r
663 $xml .= 'not detected, got '.gettype($val).' for '.$val;
\r
666 $this->debug("serialize_val returning $xml");
\r
671 * serializes a message
\r
673 * @param string $body the XML of the SOAP body
\r
674 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
\r
675 * @param array $namespaces optional the namespaces used in generating the body and headers
\r
676 * @param string $style optional (rpc|document)
\r
677 * @param string $use optional (encoded|literal)
\r
678 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
\r
679 * @return string the message
\r
682 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
\r
683 // TODO: add an option to automatically run utf8_encode on $body and $headers
\r
684 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
\r
685 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
\r
687 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
\r
688 $this->debug("headers:");
\r
689 $this->appendDebug($this->varDump($headers));
\r
690 $this->debug("namespaces:");
\r
691 $this->appendDebug($this->varDump($namespaces));
\r
693 // serialize namespaces
\r
695 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
\r
696 $ns_string .= " xmlns:$k=\"$v\"";
\r
698 if($encodingStyle) {
\r
699 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
\r
702 // serialize headers
\r
704 if (is_array($headers)) {
\r
706 foreach ($headers as $k => $v) {
\r
707 if (is_object($v) && get_class($v) == 'soapval') {
\r
708 $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
\r
710 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
\r
714 $this->debug("In serializeEnvelope, serialized array of headers to $headers");
\r
716 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
\r
718 //echo "####<br/>";
\r
720 //echo "<br/>####<br/>";
\r
721 // serialize envelope
\r
723 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
\r
724 '<SOAP-ENV:Envelope'.$ns_string.">".
\r
728 "</SOAP-ENV:Body>".
\r
729 "</SOAP-ENV:Envelope>";
\r
733 * formats a string to be inserted into an HTML stream
\r
735 * @param string $str The string to format
\r
736 * @return string The formatted string
\r
740 function formatDump($str){
\r
741 $str = htmlspecialchars($str);
\r
742 return nl2br($str);
\r
746 * contracts (changes namespace to prefix) a qualified name
\r
748 * @param string $qname qname
\r
749 * @return string contracted qname
\r
752 function contractQname($qname){
\r
753 // get element namespace
\r
754 //$this->xdebug("Contract $qname");
\r
755 if (strrpos($qname, ':')) {
\r
756 // get unqualified name
\r
757 $name = substr($qname, strrpos($qname, ':') + 1);
\r
759 $ns = substr($qname, 0, strrpos($qname, ':'));
\r
760 $p = $this->getPrefixFromNamespace($ns);
\r
762 return $p . ':' . $name;
\r
771 * expands (changes prefix to namespace) a qualified name
\r
773 * @param string $qname qname
\r
774 * @return string expanded qname
\r
777 function expandQname($qname){
\r
778 // get element prefix
\r
779 if(strpos($qname,':') && !ereg('^http://',$qname)){
\r
780 // get unqualified name
\r
781 $name = substr(strstr($qname,':'),1);
\r
783 $prefix = substr($qname,0,strpos($qname,':'));
\r
784 if(isset($this->namespaces[$prefix])){
\r
785 return $this->namespaces[$prefix].':'.$name;
\r
795 * returns the local part of a prefixed string
\r
796 * returns the original string, if not prefixed
\r
798 * @param string $str The prefixed string
\r
799 * @return string The local part
\r
802 function getLocalPart($str){
\r
803 if($sstr = strrchr($str,':')){
\r
804 // get unqualified name
\r
805 return substr( $sstr, 1 );
\r
812 * returns the prefix part of a prefixed string
\r
813 * returns false, if not prefixed
\r
815 * @param string $str The prefixed string
\r
816 * @return mixed The prefix or false if there is no prefix
\r
819 function getPrefix($str){
\r
820 if($pos = strrpos($str,':')){
\r
822 return substr($str,0,$pos);
\r
828 * pass it a prefix, it returns a namespace
\r
830 * @param string $prefix The prefix
\r
831 * @return mixed The namespace, false if no namespace has the specified prefix
\r
834 function getNamespaceFromPrefix($prefix){
\r
835 if (isset($this->namespaces[$prefix])) {
\r
836 return $this->namespaces[$prefix];
\r
838 //$this->setError("No namespace registered for prefix '$prefix'");
\r
843 * returns the prefix for a given namespace (or prefix)
\r
844 * or false if no prefixes registered for the given namespace
\r
846 * @param string $ns The namespace
\r
847 * @return mixed The prefix, false if the namespace has no prefixes
\r
850 function getPrefixFromNamespace($ns) {
\r
851 foreach ($this->namespaces as $p => $n) {
\r
852 if ($ns == $n || $ns == $p) {
\r
853 $this->usedNamespaces[$p] = $n;
\r
861 * returns the time in ODBC canonical form with microseconds
\r
863 * @return string The time in ODBC canonical form with microseconds
\r
866 function getmicrotime() {
\r
867 if (function_exists('gettimeofday')) {
\r
868 $tod = gettimeofday();
\r
869 $sec = $tod['sec'];
\r
870 $usec = $tod['usec'];
\r
875 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
\r
879 * Returns a string with the output of var_dump
\r
881 * @param mixed $data The variable to var_dump
\r
882 * @return string The output of var_dump
\r
885 function varDump($data) {
\r
888 $ret_val = ob_get_contents();
\r
894 * represents the object as a string
\r
899 function __toString() {
\r
900 return $this->varDump($this);
\r
904 // XML Schema Datatype Helper Functions
\r
906 //xsd:dateTime helpers
\r
909 * convert unix timestamp to ISO 8601 compliant date string
\r
911 * @param string $timestamp Unix time stamp
\r
912 * @param boolean $utc Whether the time stamp is UTC or local
\r
915 function timestamp_to_iso8601($timestamp,$utc=true){
\r
916 $datestr = date('Y-m-d\TH:i:sO',$timestamp);
\r
919 '([0-9]{4})-'. // centuries & years CCYY-
\r
920 '([0-9]{2})-'. // months MM-
\r
921 '([0-9]{2})'. // days DD
\r
922 'T'. // separator T
\r
923 '([0-9]{2}):'. // hours hh:
\r
924 '([0-9]{2}):'. // minutes mm:
\r
925 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
\r
926 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
\r
928 if(ereg($eregStr,$datestr,$regs)){
\r
929 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
\r
938 * convert ISO 8601 compliant date string to unix timestamp
\r
940 * @param string $datestr ISO 8601 compliant date string
\r
943 function iso8601_to_timestamp($datestr){
\r
945 '([0-9]{4})-'. // centuries & years CCYY-
\r
946 '([0-9]{2})-'. // months MM-
\r
947 '([0-9]{2})'. // days DD
\r
948 'T'. // separator T
\r
949 '([0-9]{2}):'. // hours hh:
\r
950 '([0-9]{2}):'. // minutes mm:
\r
951 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
\r
952 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
\r
953 if(ereg($eregStr,$datestr,$regs)){
\r
955 if($regs[8] != 'Z'){
\r
956 $op = substr($regs[8],0,1);
\r
957 $h = substr($regs[8],1,2);
\r
958 $m = substr($regs[8],strlen($regs[8])-2,2);
\r
960 $regs[4] = $regs[4] + $h;
\r
961 $regs[5] = $regs[5] + $m;
\r
962 } elseif($op == '+'){
\r
963 $regs[4] = $regs[4] - $h;
\r
964 $regs[5] = $regs[5] - $m;
\r
967 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
\r
968 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
\r
975 * sleeps some number of microseconds
\r
977 * @param string $usec the number of microseconds to sleep
\r
981 function usleepWindows($usec)
\r
983 $start = gettimeofday();
\r
987 $stop = gettimeofday();
\r
988 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
\r
989 + $stop['usec'] - $start['usec'];
\r
991 while ($timePassed < $usec);
\r
999 * Contains information for a SOAP fault.
\r
1000 * Mainly used for returning faults from deployed functions
\r
1001 * in a server instance.
\r
1002 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
1003 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
1006 class nusoap_fault extends nusoap_base {
\r
1008 * The fault code (client|server)
\r
1020 * The fault string, a description of the fault
\r
1026 * The fault detail, typically a string or array of string
\r
1035 * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
\r
1036 * @param string $faultactor only used when msg routed between multiple actors
\r
1037 * @param string $faultstring human readable error message
\r
1038 * @param mixed $faultdetail detail, typically a string or array of string
\r
1040 function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
\r
1041 parent::nusoap_base();
\r
1042 $this->faultcode = $faultcode;
\r
1043 $this->faultactor = $faultactor;
\r
1044 $this->faultstring = $faultstring;
\r
1045 $this->faultdetail = $faultdetail;
\r
1049 * serialize a fault
\r
1051 * @return string The serialization of the fault instance.
\r
1054 function serialize(){
\r
1056 foreach($this->namespaces as $k => $v){
\r
1057 $ns_string .= "\n xmlns:$k=\"$v\"";
\r
1060 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
\r
1061 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
\r
1062 '<SOAP-ENV:Body>'.
\r
1063 '<SOAP-ENV:Fault>'.
\r
1064 $this->serialize_val($this->faultcode, 'faultcode').
\r
1065 $this->serialize_val($this->faultactor, 'faultactor').
\r
1066 $this->serialize_val($this->faultstring, 'faultstring').
\r
1067 $this->serialize_val($this->faultdetail, 'detail').
\r
1068 '</SOAP-ENV:Fault>'.
\r
1069 '</SOAP-ENV:Body>'.
\r
1070 '</SOAP-ENV:Envelope>';
\r
1071 return $return_msg;
\r
1076 * Backward compatibility
\r
1078 class soap_fault extends nusoap_fault {
\r
1086 * parses an XML Schema, allows access to it's data, other utility methods.
\r
1087 * imperfect, no validation... yet, but quite functional.
\r
1089 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
1090 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
1091 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
1094 class nusoap_xmlschema extends nusoap_base {
\r
1100 var $enclosingNamespaces;
\r
1102 var $schemaInfo = array();
\r
1103 var $schemaTargetNamespace = '';
\r
1104 // types, elements, attributes defined by the schema
\r
1105 var $attributes = array();
\r
1106 var $complexTypes = array();
\r
1107 var $complexTypeStack = array();
\r
1108 var $currentComplexType = null;
\r
1109 var $elements = array();
\r
1110 var $elementStack = array();
\r
1111 var $currentElement = null;
\r
1112 var $simpleTypes = array();
\r
1113 var $simpleTypeStack = array();
\r
1114 var $currentSimpleType = null;
\r
1116 var $imports = array();
\r
1119 var $position = 0;
\r
1121 var $depth_array = array();
\r
1122 var $message = array();
\r
1123 var $defaultNamespace = array();
\r
1128 * @param string $schema schema document URI
\r
1129 * @param string $xml xml document URI
\r
1130 * @param string $namespaces namespaces defined in enclosing XML
\r
1133 function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
\r
1134 parent::nusoap_base();
\r
1135 $this->debug('nusoap_xmlschema class instantiated, inside constructor');
\r
1137 $this->schema = $schema;
\r
1138 $this->xml = $xml;
\r
1141 $this->enclosingNamespaces = $namespaces;
\r
1142 $this->namespaces = array_merge($this->namespaces, $namespaces);
\r
1144 // parse schema file
\r
1145 if($schema != ''){
\r
1146 $this->debug('initial schema file: '.$schema);
\r
1147 $this->parseFile($schema, 'schema');
\r
1152 $this->debug('initial xml file: '.$xml);
\r
1153 $this->parseFile($xml, 'xml');
\r
1159 * parse an XML file
\r
1161 * @param string $xml path/URL to XML file
\r
1162 * @param string $type (schema | xml)
\r
1166 function parseFile($xml,$type){
\r
1169 $xmlStr = @join("",@file($xml));
\r
1170 if($xmlStr == ""){
\r
1171 $msg = 'Error reading XML from '.$xml;
\r
1172 $this->setError($msg);
\r
1173 $this->debug($msg);
\r
1176 $this->debug("parsing $xml");
\r
1177 $this->parseString($xmlStr,$type);
\r
1178 $this->debug("done parsing $xml");
\r
1186 * parse an XML string
\r
1188 * @param string $xml path or URL
\r
1189 * @param string $type (schema|xml)
\r
1192 function parseString($xml,$type){
\r
1193 // parse xml string
\r
1196 // Create an XML parser.
\r
1197 $this->parser = xml_parser_create();
\r
1198 // Set the options for parsing the XML data.
\r
1199 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
\r
1201 // Set the object for the parser.
\r
1202 xml_set_object($this->parser, $this);
\r
1204 // Set the element handlers for the parser.
\r
1205 if($type == "schema"){
\r
1206 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
\r
1207 xml_set_character_data_handler($this->parser,'schemaCharacterData');
\r
1208 } elseif($type == "xml"){
\r
1209 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
\r
1210 xml_set_character_data_handler($this->parser,'xmlCharacterData');
\r
1213 // Parse the XML file.
\r
1214 if(!xml_parse($this->parser,$xml,true)){
\r
1215 // Display an error message.
\r
1216 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
\r
1217 xml_get_current_line_number($this->parser),
\r
1218 xml_error_string(xml_get_error_code($this->parser))
\r
1220 $this->debug($errstr);
\r
1221 $this->debug("XML payload:\n" . $xml);
\r
1222 $this->setError($errstr);
\r
1225 xml_parser_free($this->parser);
\r
1227 $this->debug('no xml passed to parseString()!!');
\r
1228 $this->setError('no xml passed to parseString()!!');
\r
1233 * gets a type name for an unnamed type
\r
1235 * @param string Element name
\r
1236 * @return string A type name for an unnamed type
\r
1239 function CreateTypeName($ename) {
\r
1241 for ($i = 0; $i < count($this->complexTypeStack); $i++) {
\r
1242 $scope .= $this->complexTypeStack[$i] . '_';
\r
1244 return $scope . $ename . '_ContainedType';
\r
1248 * start-element handler
\r
1250 * @param string $parser XML parser object
\r
1251 * @param string $name element name
\r
1252 * @param string $attrs associative array of attributes
\r
1255 function schemaStartElement($parser, $name, $attrs) {
\r
1257 // position in the total number of elements, starting from 0
\r
1258 $pos = $this->position++;
\r
1259 $depth = $this->depth++;
\r
1260 // set self as current value for this depth
\r
1261 $this->depth_array[$depth] = $pos;
\r
1262 $this->message[$pos] = array('cdata' => '');
\r
1264 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
\r
1266 $this->defaultNamespace[$pos] = false;
\r
1269 // get element prefix
\r
1270 if($prefix = $this->getPrefix($name)){
\r
1271 // get unqualified name
\r
1272 $name = $this->getLocalPart($name);
\r
1277 // loop thru attributes, expanding, and registering namespace declarations
\r
1278 if(count($attrs) > 0){
\r
1279 foreach($attrs as $k => $v){
\r
1280 // if ns declarations, add to class level array of valid namespaces
\r
1281 if(ereg("^xmlns",$k)){
\r
1282 //$this->xdebug("$k: $v");
\r
1283 //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
\r
1284 if($ns_prefix = substr(strrchr($k,':'),1)){
\r
1285 //$this->xdebug("Add namespace[$ns_prefix] = $v");
\r
1286 $this->namespaces[$ns_prefix] = $v;
\r
1288 $this->defaultNamespace[$pos] = $v;
\r
1289 if (! $this->getPrefixFromNamespace($v)) {
\r
1290 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
\r
1293 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
\r
1294 $this->XMLSchemaVersion = $v;
\r
1295 $this->namespaces['xsi'] = $v.'-instance';
\r
1299 foreach($attrs as $k => $v){
\r
1300 // expand each attribute
\r
1301 $k = strpos($k,':') ? $this->expandQname($k) : $k;
\r
1302 $v = strpos($v,':') ? $this->expandQname($v) : $v;
\r
1309 // find status, register data
\r
1311 case 'all': // (optional) compositor content for a complexType
\r
1315 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
\r
1316 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
\r
1317 //if($name == 'all' || $name == 'sequence'){
\r
1318 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
\r
1321 case 'attribute': // complexType attribute
\r
1322 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
\r
1323 $this->xdebug("parsing attribute:");
\r
1324 $this->appendDebug($this->varDump($attrs));
\r
1325 if (!isset($attrs['form'])) {
\r
1326 $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
\r
1328 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
\r
1329 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
\r
1330 if (!strpos($v, ':')) {
\r
1331 // no namespace in arrayType attribute value...
\r
1332 if ($this->defaultNamespace[$pos]) {
\r
1333 // ...so use the default
\r
1334 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
\r
1338 if(isset($attrs['name'])){
\r
1339 $this->attributes[$attrs['name']] = $attrs;
\r
1340 $aname = $attrs['name'];
\r
1341 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
\r
1342 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
\r
1343 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
\r
1347 } elseif(isset($attrs['ref'])){
\r
1348 $aname = $attrs['ref'];
\r
1349 $this->attributes[$attrs['ref']] = $attrs;
\r
1352 if($this->currentComplexType){ // This should *always* be
\r
1353 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
\r
1355 // arrayType attribute
\r
1356 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
\r
1357 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
\r
1358 $prefix = $this->getPrefix($aname);
\r
1359 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
\r
1360 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
\r
1364 if(strpos($v,'[,]')){
\r
1365 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
\r
1367 $v = substr($v,0,strpos($v,'[')); // clip the []
\r
1368 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
\r
1369 $v = $this->XMLSchemaVersion.':'.$v;
\r
1371 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
\r
1374 case 'complexContent': // (optional) content for a complexType
\r
1376 case 'complexType':
\r
1377 array_push($this->complexTypeStack, $this->currentComplexType);
\r
1378 if(isset($attrs['name'])){
\r
1379 // TODO: what is the scope of named complexTypes that appear
\r
1380 // nested within other c complexTypes?
\r
1381 $this->xdebug('processing named complexType '.$attrs['name']);
\r
1382 //$this->currentElement = false;
\r
1383 $this->currentComplexType = $attrs['name'];
\r
1384 $this->complexTypes[$this->currentComplexType] = $attrs;
\r
1385 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
\r
1386 // This is for constructs like
\r
1387 // <complexType name="ListOfString" base="soap:Array">
\r
1389 // <element name="string" type="xsd:string"
\r
1390 // minOccurs="0" maxOccurs="unbounded" />
\r
1393 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
\r
1394 $this->xdebug('complexType is unusual array');
\r
1395 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
\r
1397 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
\r
1400 $name = $this->CreateTypeName($this->currentElement);
\r
1401 $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
\r
1402 $this->currentComplexType = $name;
\r
1403 //$this->currentElement = false;
\r
1404 $this->complexTypes[$this->currentComplexType] = $attrs;
\r
1405 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
\r
1406 // This is for constructs like
\r
1407 // <complexType name="ListOfString" base="soap:Array">
\r
1409 // <element name="string" type="xsd:string"
\r
1410 // minOccurs="0" maxOccurs="unbounded" />
\r
1413 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
\r
1414 $this->xdebug('complexType is unusual array');
\r
1415 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
\r
1417 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
\r
1422 array_push($this->elementStack, $this->currentElement);
\r
1423 if (!isset($attrs['form'])) {
\r
1424 $attrs['form'] = $this->schemaInfo['elementFormDefault'];
\r
1426 if(isset($attrs['type'])){
\r
1427 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
\r
1428 if (! $this->getPrefix($attrs['type'])) {
\r
1429 if ($this->defaultNamespace[$pos]) {
\r
1430 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
\r
1431 $this->xdebug('used default namespace to make type ' . $attrs['type']);
\r
1434 // This is for constructs like
\r
1435 // <complexType name="ListOfString" base="soap:Array">
\r
1437 // <element name="string" type="xsd:string"
\r
1438 // minOccurs="0" maxOccurs="unbounded" />
\r
1441 if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
\r
1442 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
\r
1443 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
\r
1445 $this->currentElement = $attrs['name'];
\r
1446 $ename = $attrs['name'];
\r
1447 } elseif(isset($attrs['ref'])){
\r
1448 $this->xdebug("processing element as ref to ".$attrs['ref']);
\r
1449 $this->currentElement = "ref to ".$attrs['ref'];
\r
1450 $ename = $this->getLocalPart($attrs['ref']);
\r
1452 $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
\r
1453 $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
\r
1454 $this->currentElement = $attrs['name'];
\r
1455 $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
\r
1456 $ename = $attrs['name'];
\r
1458 if (isset($ename) && $this->currentComplexType) {
\r
1459 $this->xdebug("add element $ename to complexType $this->currentComplexType");
\r
1460 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
\r
1461 } elseif (!isset($attrs['ref'])) {
\r
1462 $this->xdebug("add element $ename to elements array");
\r
1463 $this->elements[ $attrs['name'] ] = $attrs;
\r
1464 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
\r
1467 case 'enumeration': // restriction value list member
\r
1468 $this->xdebug('enumeration ' . $attrs['value']);
\r
1469 if ($this->currentSimpleType) {
\r
1470 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
\r
1471 } elseif ($this->currentComplexType) {
\r
1472 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
\r
1475 case 'extension': // simpleContent or complexContent type extension
\r
1476 $this->xdebug('extension ' . $attrs['base']);
\r
1477 if ($this->currentComplexType) {
\r
1478 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
\r
1482 if (isset($attrs['schemaLocation'])) {
\r
1483 //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
\r
1484 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
\r
1486 //$this->xdebug('import namespace ' . $attrs['namespace']);
\r
1487 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
\r
1488 if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
\r
1489 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
\r
1493 case 'list': // simpleType value list
\r
1495 case 'restriction': // simpleType, simpleContent or complexContent value restriction
\r
1496 $this->xdebug('restriction ' . $attrs['base']);
\r
1497 if($this->currentSimpleType){
\r
1498 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
\r
1499 } elseif($this->currentComplexType){
\r
1500 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
\r
1501 if(strstr($attrs['base'],':') == ':Array'){
\r
1502 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
\r
1507 $this->schemaInfo = $attrs;
\r
1508 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
\r
1509 if (isset($attrs['targetNamespace'])) {
\r
1510 $this->schemaTargetNamespace = $attrs['targetNamespace'];
\r
1512 if (!isset($attrs['elementFormDefault'])) {
\r
1513 $this->schemaInfo['elementFormDefault'] = 'unqualified';
\r
1515 if (!isset($attrs['attributeFormDefault'])) {
\r
1516 $this->schemaInfo['attributeFormDefault'] = 'unqualified';
\r
1519 case 'simpleContent': // (optional) content for a complexType
\r
1521 case 'simpleType':
\r
1522 array_push($this->simpleTypeStack, $this->currentSimpleType);
\r
1523 if(isset($attrs['name'])){
\r
1524 $this->xdebug("processing simpleType for name " . $attrs['name']);
\r
1525 $this->currentSimpleType = $attrs['name'];
\r
1526 $this->simpleTypes[ $attrs['name'] ] = $attrs;
\r
1527 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
\r
1528 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
\r
1530 $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
\r
1531 $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
\r
1532 $this->currentSimpleType = $name;
\r
1533 //$this->currentElement = false;
\r
1534 $this->simpleTypes[$this->currentSimpleType] = $attrs;
\r
1535 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
\r
1538 case 'union': // simpleType type list
\r
1541 //$this->xdebug("do not have anything to do for element $name");
\r
1546 * end-element handler
\r
1548 * @param string $parser XML parser object
\r
1549 * @param string $name element name
\r
1552 function schemaEndElement($parser, $name) {
\r
1553 // bring depth down a notch
\r
1555 // position of current element is equal to the last value left in depth_array for my depth
\r
1556 if(isset($this->depth_array[$this->depth])){
\r
1557 $pos = $this->depth_array[$this->depth];
\r
1559 // get element prefix
\r
1560 if ($prefix = $this->getPrefix($name)){
\r
1561 // get unqualified name
\r
1562 $name = $this->getLocalPart($name);
\r
1567 if($name == 'complexType'){
\r
1568 $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
\r
1569 $this->currentComplexType = array_pop($this->complexTypeStack);
\r
1570 //$this->currentElement = false;
\r
1572 if($name == 'element'){
\r
1573 $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
\r
1574 $this->currentElement = array_pop($this->elementStack);
\r
1576 if($name == 'simpleType'){
\r
1577 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
\r
1578 $this->currentSimpleType = array_pop($this->simpleTypeStack);
\r
1583 * element content handler
\r
1585 * @param string $parser XML parser object
\r
1586 * @param string $data element content
\r
1589 function schemaCharacterData($parser, $data){
\r
1590 $pos = $this->depth_array[$this->depth - 1];
\r
1591 $this->message[$pos]['cdata'] .= $data;
\r
1595 * serialize the schema
\r
1599 function serializeSchema(){
\r
1601 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
\r
1604 if (sizeof($this->imports) > 0) {
\r
1605 foreach($this->imports as $ns => $list) {
\r
1606 foreach ($list as $ii) {
\r
1607 if ($ii['location'] != '') {
\r
1608 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
\r
1610 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
\r
1616 foreach($this->complexTypes as $typeName => $attrs){
\r
1618 // serialize child elements
\r
1619 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
\r
1620 foreach($attrs['elements'] as $element => $eParts){
\r
1621 if(isset($eParts['ref'])){
\r
1622 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
\r
1624 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
\r
1625 foreach ($eParts as $aName => $aValue) {
\r
1626 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
\r
1627 if ($aName != 'name' && $aName != 'type') {
\r
1628 $contentStr .= " $aName=\"$aValue\"";
\r
1631 $contentStr .= "/>\n";
\r
1634 // compositor wraps elements
\r
1635 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
\r
1636 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
\r
1640 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
\r
1641 foreach($attrs['attrs'] as $attr => $aParts){
\r
1642 $contentStr .= " <$schemaPrefix:attribute";
\r
1643 foreach ($aParts as $a => $v) {
\r
1644 if ($a == 'ref' || $a == 'type') {
\r
1645 $contentStr .= " $a=\"".$this->contractQName($v).'"';
\r
1646 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
\r
1647 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
\r
1648 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
\r
1650 $contentStr .= " $a=\"$v\"";
\r
1653 $contentStr .= "/>\n";
\r
1657 if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
\r
1658 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
\r
1659 // complex or simple content
\r
1660 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
\r
1661 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
\r
1664 // finalize complex type
\r
1665 if($contentStr != ''){
\r
1666 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
\r
1668 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
\r
1670 $xml .= $contentStr;
\r
1673 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
\r
1674 foreach($this->simpleTypes as $typeName => $eParts){
\r
1675 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
\r
1676 if (isset($eParts['enumeration'])) {
\r
1677 foreach ($eParts['enumeration'] as $e) {
\r
1678 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
\r
1681 $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
\r
1685 if(isset($this->elements) && count($this->elements) > 0){
\r
1686 foreach($this->elements as $element => $eParts){
\r
1687 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
\r
1691 if(isset($this->attributes) && count($this->attributes) > 0){
\r
1692 foreach($this->attributes as $attr => $aParts){
\r
1693 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
\r
1698 foreach ($this->schemaInfo as $k => $v) {
\r
1699 if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
\r
1700 $attr .= " $k=\"$v\"";
\r
1703 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
\r
1704 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
\r
1705 $el .= " xmlns:$nsp=\"$ns\"";
\r
1707 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
\r
1712 * adds debug data to the clas level debug string
\r
1714 * @param string $string debug data
\r
1717 function xdebug($string){
\r
1718 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
\r
1722 * get the PHP type of a user defined type in the schema
\r
1723 * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
\r
1724 * returns false if no type exists, or not w/ the given namespace
\r
1725 * else returns a string that is either a native php type, or 'struct'
\r
1727 * @param string $type name of defined type
\r
1728 * @param string $ns namespace of type
\r
1733 function getPHPType($type,$ns){
\r
1734 if(isset($this->typemap[$ns][$type])){
\r
1735 //print "found type '$type' and ns $ns in typemap<br>";
\r
1736 return $this->typemap[$ns][$type];
\r
1737 } elseif(isset($this->complexTypes[$type])){
\r
1738 //print "getting type '$type' and ns $ns from complexTypes array<br>";
\r
1739 return $this->complexTypes[$type]['phpType'];
\r
1745 * returns an associative array of information about a given type
\r
1746 * returns false if no type exists by the given name
\r
1748 * For a complexType typeDef = array(
\r
1749 * 'restrictionBase' => '',
\r
1750 * 'phpType' => '',
\r
1751 * 'compositor' => '(sequence|all)',
\r
1752 * 'elements' => array(), // refs to elements array
\r
1753 * 'attrs' => array() // refs to attributes array
\r
1754 * ... and so on (see addComplexType)
\r
1757 * For simpleType or element, the array has different keys.
\r
1759 * @param string $type
\r
1762 * @see addComplexType
\r
1763 * @see addSimpleType
\r
1766 function getTypeDef($type){
\r
1767 //$this->debug("in getTypeDef for type $type");
\r
1768 if (substr($type, -1) == '^') {
\r
1770 $type = substr($type, 0, -1);
\r
1775 if((! $is_element) && isset($this->complexTypes[$type])){
\r
1776 $this->xdebug("in getTypeDef, found complexType $type");
\r
1777 return $this->complexTypes[$type];
\r
1778 } elseif((! $is_element) && isset($this->simpleTypes[$type])){
\r
1779 $this->xdebug("in getTypeDef, found simpleType $type");
\r
1780 if (!isset($this->simpleTypes[$type]['phpType'])) {
\r
1781 // get info for type to tack onto the simple type
\r
1782 // TODO: can this ever really apply (i.e. what is a simpleType really?)
\r
1783 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
\r
1784 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
\r
1785 $etype = $this->getTypeDef($uqType);
\r
1787 $this->xdebug("in getTypeDef, found type for simpleType $type:");
\r
1788 $this->xdebug($this->varDump($etype));
\r
1789 if (isset($etype['phpType'])) {
\r
1790 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
\r
1792 if (isset($etype['elements'])) {
\r
1793 $this->simpleTypes[$type]['elements'] = $etype['elements'];
\r
1797 return $this->simpleTypes[$type];
\r
1798 } elseif(isset($this->elements[$type])){
\r
1799 $this->xdebug("in getTypeDef, found element $type");
\r
1800 if (!isset($this->elements[$type]['phpType'])) {
\r
1801 // get info for type to tack onto the element
\r
1802 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
\r
1803 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
\r
1804 $etype = $this->getTypeDef($uqType);
\r
1806 $this->xdebug("in getTypeDef, found type for element $type:");
\r
1807 $this->xdebug($this->varDump($etype));
\r
1808 if (isset($etype['phpType'])) {
\r
1809 $this->elements[$type]['phpType'] = $etype['phpType'];
\r
1811 if (isset($etype['elements'])) {
\r
1812 $this->elements[$type]['elements'] = $etype['elements'];
\r
1814 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
\r
1815 $this->xdebug("in getTypeDef, element $type is an XSD type");
\r
1816 $this->elements[$type]['phpType'] = 'scalar';
\r
1819 return $this->elements[$type];
\r
1820 } elseif(isset($this->attributes[$type])){
\r
1821 $this->xdebug("in getTypeDef, found attribute $type");
\r
1822 return $this->attributes[$type];
\r
1823 } elseif (ereg('_ContainedType$', $type)) {
\r
1824 $this->xdebug("in getTypeDef, have an untyped element $type");
\r
1825 $typeDef['typeClass'] = 'simpleType';
\r
1826 $typeDef['phpType'] = 'scalar';
\r
1827 $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
\r
1830 $this->xdebug("in getTypeDef, did not find $type");
\r
1835 * returns a sample serialization of a given type, or false if no type by the given name
\r
1837 * @param string $type name of type
\r
1842 function serializeTypeDef($type){
\r
1843 //print "in sTD() for type $type<br>";
\r
1844 if($typeDef = $this->getTypeDef($type)){
\r
1845 $str .= '<'.$type;
\r
1846 if(is_array($typeDef['attrs'])){
\r
1847 foreach($typeDef['attrs'] as $attName => $data){
\r
1848 $str .= " $attName=\"{type = ".$data['type']."}\"";
\r
1851 $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
\r
1852 if(count($typeDef['elements']) > 0){
\r
1854 foreach($typeDef['elements'] as $element => $eData){
\r
1855 $str .= $this->serializeTypeDef($element);
\r
1857 $str .= "</$type>";
\r
1858 } elseif($typeDef['typeClass'] == 'element') {
\r
1859 $str .= "></$type>";
\r
1869 * returns HTML form elements that allow a user
\r
1870 * to enter values for creating an instance of the given type.
\r
1872 * @param string $name name for type instance
\r
1873 * @param string $type name of type
\r
1878 function typeToForm($name,$type){
\r
1880 if($typeDef = $this->getTypeDef($type)){
\r
1882 if($typeDef['phpType'] == 'struct'){
\r
1883 $buffer .= '<table>';
\r
1884 foreach($typeDef['elements'] as $child => $childDef){
\r
1886 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
\r
1887 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
\r
1889 $buffer .= '</table>';
\r
1891 } elseif($typeDef['phpType'] == 'array'){
\r
1892 $buffer .= '<table>';
\r
1893 for($i=0;$i < 3; $i++){
\r
1895 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
\r
1896 <td><input type='text' name='parameters[".$name."][]'></td></tr>";
\r
1898 $buffer .= '</table>';
\r
1901 $buffer .= "<input type='text' name='parameters[$name]'>";
\r
1904 $buffer .= "<input type='text' name='parameters[$name]'>";
\r
1910 * adds a complex type to the schema
\r
1915 * 'ArrayOfstring',
\r
1919 * 'SOAP-ENC:Array',
\r
1920 * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
\r
1924 * example: PHP associative array ( SOAP Struct )
\r
1931 * array('myVar'=> array('name'=>'myVar','type'=>'string')
\r
1935 * @param typeClass (complexType|simpleType|attribute)
\r
1936 * @param phpType: currently supported are array and struct (php assoc array)
\r
1937 * @param compositor (all|sequence|choice)
\r
1938 * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
\r
1939 * @param elements = array ( name = array(name=>'',type=>'') )
\r
1940 * @param attrs = array(
\r
1942 * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
\r
1943 * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
\r
1946 * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
\r
1950 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
\r
1951 $this->complexTypes[$name] = array(
\r
1953 'typeClass' => $typeClass,
\r
1954 'phpType' => $phpType,
\r
1955 'compositor'=> $compositor,
\r
1956 'restrictionBase' => $restrictionBase,
\r
1957 'elements' => $elements,
\r
1958 'attrs' => $attrs,
\r
1959 'arrayType' => $arrayType
\r
1962 $this->xdebug("addComplexType $name:");
\r
1963 $this->appendDebug($this->varDump($this->complexTypes[$name]));
\r
1967 * adds a simple type to the schema
\r
1969 * @param string $name
\r
1970 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
\r
1971 * @param string $typeClass (should always be simpleType)
\r
1972 * @param string $phpType (should always be scalar)
\r
1973 * @param array $enumeration array of values
\r
1975 * @see nusoap_xmlschema
\r
1978 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
\r
1979 $this->simpleTypes[$name] = array(
\r
1981 'typeClass' => $typeClass,
\r
1982 'phpType' => $phpType,
\r
1983 'type' => $restrictionBase,
\r
1984 'enumeration' => $enumeration
\r
1987 $this->xdebug("addSimpleType $name:");
\r
1988 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
\r
1992 * adds an element to the schema
\r
1994 * @param array $attrs attributes that must include name and type
\r
1995 * @see nusoap_xmlschema
\r
1998 function addElement($attrs) {
\r
1999 if (! $this->getPrefix($attrs['type'])) {
\r
2000 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
\r
2002 $this->elements[ $attrs['name'] ] = $attrs;
\r
2003 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
\r
2005 $this->xdebug("addElement " . $attrs['name']);
\r
2006 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
\r
2011 * Backward compatibility
\r
2013 class XMLSchema extends nusoap_xmlschema {
\r
2021 * For creating serializable abstractions of native PHP types. This class
\r
2022 * allows element name/namespace, XSD type, and XML attributes to be
\r
2023 * associated with a value. This is extremely useful when WSDL is not
\r
2024 * used, but is also useful when WSDL is used with polymorphic types, including
\r
2025 * xsd:anyType and user-defined types.
\r
2027 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
2028 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
2031 class soapval extends nusoap_base {
\r
2033 * The XML element name
\r
2040 * The XML type name (string or false)
\r
2054 * The XML element namespace (string or false)
\r
2061 * The XML type namespace (string or false)
\r
2068 * The XML element attributes (array or false)
\r
2078 * @param string $name optional name
\r
2079 * @param mixed $type optional type name
\r
2080 * @param mixed $value optional value
\r
2081 * @param mixed $element_ns optional namespace of value
\r
2082 * @param mixed $type_ns optional namespace of type
\r
2083 * @param mixed $attributes associative array of attributes to add to element serialization
\r
2086 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
\r
2087 parent::nusoap_base();
\r
2088 $this->name = $name;
\r
2089 $this->type = $type;
\r
2090 $this->value = $value;
\r
2091 $this->element_ns = $element_ns;
\r
2092 $this->type_ns = $type_ns;
\r
2093 $this->attributes = $attributes;
\r
2097 * return serialized value
\r
2099 * @param string $use The WSDL use value (encoded|literal)
\r
2100 * @return string XML data
\r
2103 function serialize($use='encoded') {
\r
2104 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
\r
2108 * decodes a soapval object into a PHP native type
\r
2113 function decode(){
\r
2114 return $this->value;
\r
2125 * transport class for sending/receiving data via HTTP and HTTPS
\r
2126 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
\r
2128 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
2129 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
2130 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
2133 class soap_transport_http extends nusoap_base {
\r
2137 var $digest_uri = '';
\r
2142 var $request_method = 'POST';
\r
2143 var $protocol_version = '1.0';
\r
2144 var $encoding = '';
\r
2145 var $outgoing_headers = array();
\r
2146 var $incoming_headers = array();
\r
2147 var $incoming_cookies = array();
\r
2148 var $outgoing_payload = '';
\r
2149 var $incoming_payload = '';
\r
2150 var $response_status_line; // HTTP response status line
\r
2151 var $useSOAPAction = true;
\r
2152 var $persistentConnection = false;
\r
2153 var $ch = false; // cURL handle
\r
2154 var $ch_options = array(); // cURL custom options
\r
2155 var $use_curl = false; // force cURL use
\r
2156 var $proxy = null; // proxy information (associative array)
\r
2157 var $username = '';
\r
2158 var $password = '';
\r
2159 var $authtype = '';
\r
2160 var $digestRequest = array();
\r
2161 var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
\r
2162 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
\r
2163 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
\r
2164 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
\r
2165 // passphrase: SSL key password/passphrase
\r
2166 // certpassword: SSL certificate password
\r
2167 // verifypeer: default is 1
\r
2168 // verifyhost: default is 1
\r
2173 * @param string $url The URL to which to connect
\r
2174 * @param array $curl_options User-specified cURL options
\r
2175 * @param boolean $use_curl Whether to try to force cURL use
\r
2178 function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
\r
2179 parent::nusoap_base();
\r
2180 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
\r
2181 $this->appendDebug($this->varDump($curl_options));
\r
2182 $this->setURL($url);
\r
2183 if (is_array($curl_options)) {
\r
2184 $this->ch_options = $curl_options;
\r
2186 $this->use_curl = $use_curl;
\r
2187 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
\r
2188 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
\r
2192 * sets a cURL option
\r
2194 * @param mixed $option The cURL option (always integer?)
\r
2195 * @param mixed $value The cURL option value
\r
2198 function setCurlOption($option, $value) {
\r
2199 $this->debug("setCurlOption option=$option, value=");
\r
2200 $this->appendDebug($this->varDump($value));
\r
2201 curl_setopt($this->ch, $option, $value);
\r
2205 * sets an HTTP header
\r
2207 * @param string $name The name of the header
\r
2208 * @param string $value The value of the header
\r
2211 function setHeader($name, $value) {
\r
2212 $this->outgoing_headers[$name] = $value;
\r
2213 $this->debug("set header $name: $value");
\r
2217 * unsets an HTTP header
\r
2219 * @param string $name The name of the header
\r
2222 function unsetHeader($name) {
\r
2223 if (isset($this->outgoing_headers[$name])) {
\r
2224 $this->debug("unset header $name");
\r
2225 unset($this->outgoing_headers[$name]);
\r
2230 * sets the URL to which to connect
\r
2232 * @param string $url The URL to which to connect
\r
2235 function setURL($url) {
\r
2236 $this->url = $url;
\r
2238 $u = parse_url($url);
\r
2239 foreach($u as $k => $v){
\r
2240 $this->debug("parsed URL $k = $v");
\r
2244 // add any GET params to path
\r
2245 if(isset($u['query']) && $u['query'] != ''){
\r
2246 $this->path .= '?' . $u['query'];
\r
2249 // set default port
\r
2250 if(!isset($u['port'])){
\r
2251 if($u['scheme'] == 'https'){
\r
2252 $this->port = 443;
\r
2258 $this->uri = $this->path;
\r
2259 $this->digest_uri = $this->uri;
\r
2262 if (!isset($u['port'])) {
\r
2263 $this->setHeader('Host', $this->host);
\r
2265 $this->setHeader('Host', $this->host.':'.$this->port);
\r
2268 if (isset($u['user']) && $u['user'] != '') {
\r
2269 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
\r
2274 * gets the I/O method to use
\r
2276 * @return string I/O method to use (socket|curl|unknown)
\r
2279 function io_method() {
\r
2280 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
\r
2282 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
\r
2288 * establish an HTTP connection
\r
2290 * @param integer $timeout set connection timeout in seconds
\r
2291 * @param integer $response_timeout set response timeout in seconds
\r
2292 * @return boolean true if connected, false if not
\r
2295 function connect($connection_timeout=0,$response_timeout=30){
\r
2296 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
\r
2297 // "regular" socket.
\r
2298 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
\r
2299 // loaded), and until PHP5 stream_get_wrappers is not available.
\r
2300 // if ($this->scheme == 'https') {
\r
2301 // if (version_compare(phpversion(), '4.3.0') >= 0) {
\r
2302 // if (extension_loaded('openssl')) {
\r
2303 // $this->scheme = 'ssl';
\r
2304 // $this->debug('Using SSL over OpenSSL');
\r
2308 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
\r
2309 if ($this->io_method() == 'socket') {
\r
2310 if (!is_array($this->proxy)) {
\r
2311 $host = $this->host;
\r
2312 $port = $this->port;
\r
2314 $host = $this->proxy['host'];
\r
2315 $port = $this->proxy['port'];
\r
2318 // use persistent connection
\r
2319 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
\r
2320 if (!feof($this->fp)) {
\r
2321 $this->debug('Re-use persistent connection');
\r
2324 fclose($this->fp);
\r
2325 $this->debug('Closed persistent connection at EOF');
\r
2328 // munge host if using OpenSSL
\r
2329 if ($this->scheme == 'ssl') {
\r
2330 $host = 'ssl://' . $host;
\r
2332 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
\r
2335 if($connection_timeout > 0){
\r
2336 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
\r
2338 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
\r
2343 $msg = 'Couldn\'t open socket connection to server ' . $this->url;
\r
2344 if ($this->errno) {
\r
2345 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
\r
2347 $msg .= ' prior to connect(). This is often a problem looking up the host name.';
\r
2349 $this->debug($msg);
\r
2350 $this->setError($msg);
\r
2354 // set response timeout
\r
2355 $this->debug('set response timeout to ' . $response_timeout);
\r
2356 socket_set_timeout( $this->fp, $response_timeout);
\r
2358 $this->debug('socket connected');
\r
2360 } else if ($this->io_method() == 'curl') {
\r
2361 if (!extension_loaded('curl')) {
\r
2362 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
\r
2363 $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to included cURL.');
\r
2366 // Avoid warnings when PHP does not have these options
\r
2367 if (defined('CURLOPT_CONNECTIONTIMEOUT'))
\r
2368 $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
\r
2370 $CURLOPT_CONNECTIONTIMEOUT = 78;
\r
2371 if (defined('CURLOPT_HTTPAUTH'))
\r
2372 $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
\r
2374 $CURLOPT_HTTPAUTH = 107;
\r
2375 if (defined('CURLOPT_PROXYAUTH'))
\r
2376 $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
\r
2378 $CURLOPT_PROXYAUTH = 111;
\r
2379 if (defined('CURLAUTH_BASIC'))
\r
2380 $CURLAUTH_BASIC = CURLAUTH_BASIC;
\r
2382 $CURLAUTH_BASIC = 1;
\r
2383 if (defined('CURLAUTH_DIGEST'))
\r
2384 $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
\r
2386 $CURLAUTH_DIGEST = 2;
\r
2387 if (defined('CURLAUTH_NTLM'))
\r
2388 $CURLAUTH_NTLM = CURLAUTH_NTLM;
\r
2390 $CURLAUTH_NTLM = 8;
\r
2392 $this->debug('connect using cURL');
\r
2394 $this->ch = curl_init();
\r
2396 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
\r
2398 $hostURL .= $this->path;
\r
2399 $this->setCurlOption(CURLOPT_URL, $hostURL);
\r
2400 // follow location headers (re-directs)
\r
2401 if (ini_get('safe_mode') || ini_get('open_basedir')) {
\r
2402 $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
\r
2403 $this->debug('safe_mode = ');
\r
2404 $this->appendDebug($this->varDump(ini_get('safe_mode')));
\r
2405 $this->debug('open_basedir = ');
\r
2406 $this->appendDebug($this->varDump(ini_get('open_basedir')));
\r
2408 $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
\r
2410 // ask for headers in the response output
\r
2411 $this->setCurlOption(CURLOPT_HEADER, 1);
\r
2412 // ask for the response output as the return value
\r
2413 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
\r
2415 // We manage this ourselves through headers and encoding
\r
2416 // if(function_exists('gzuncompress')){
\r
2417 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
\r
2419 // persistent connection
\r
2420 if ($this->persistentConnection) {
\r
2421 // I believe the following comment is now bogus, having applied to
\r
2422 // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
\r
2423 // The way we send data, we cannot use persistent connections, since
\r
2424 // there will be some "junk" at the end of our request.
\r
2425 //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
\r
2426 $this->persistentConnection = false;
\r
2427 $this->setHeader('Connection', 'close');
\r
2430 if ($connection_timeout != 0) {
\r
2431 $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
\r
2433 if ($response_timeout != 0) {
\r
2434 $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
\r
2437 if ($this->scheme == 'https') {
\r
2438 $this->debug('set cURL SSL verify options');
\r
2439 // recent versions of cURL turn on peer/host checking by default,
\r
2440 // while PHP binaries are not compiled with a default location for the
\r
2441 // CA cert bundle, so disable peer/host checking.
\r
2442 //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
\r
2443 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
\r
2444 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
\r
2446 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
\r
2447 if ($this->authtype == 'certificate') {
\r
2448 $this->debug('set cURL certificate options');
\r
2449 if (isset($this->certRequest['cainfofile'])) {
\r
2450 $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
\r
2452 if (isset($this->certRequest['verifypeer'])) {
\r
2453 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
\r
2455 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
\r
2457 if (isset($this->certRequest['verifyhost'])) {
\r
2458 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
\r
2460 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
\r
2462 if (isset($this->certRequest['sslcertfile'])) {
\r
2463 $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
\r
2465 if (isset($this->certRequest['sslkeyfile'])) {
\r
2466 $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
\r
2468 if (isset($this->certRequest['passphrase'])) {
\r
2469 $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
\r
2471 if (isset($this->certRequest['certpassword'])) {
\r
2472 $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
\r
2476 if ($this->authtype && ($this->authtype != 'certificate')) {
\r
2477 if ($this->username) {
\r
2478 $this->debug('set cURL username/password');
\r
2479 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
\r
2481 if ($this->authtype == 'basic') {
\r
2482 $this->debug('set cURL for Basic authentication');
\r
2483 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
\r
2485 if ($this->authtype == 'digest') {
\r
2486 $this->debug('set cURL for digest authentication');
\r
2487 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
\r
2489 if ($this->authtype == 'ntlm') {
\r
2490 $this->debug('set cURL for NTLM authentication');
\r
2491 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
\r
2494 if (is_array($this->proxy)) {
\r
2495 $this->debug('set cURL proxy options');
\r
2496 if ($this->proxy['port'] != '') {
\r
2497 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
\r
2499 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
\r
2501 if ($this->proxy['username'] || $this->proxy['password']) {
\r
2502 $this->debug('set cURL proxy authentication options');
\r
2503 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
\r
2504 if ($this->proxy['authtype'] == 'basic') {
\r
2505 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
\r
2507 if ($this->proxy['authtype'] == 'ntlm') {
\r
2508 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
\r
2512 $this->debug('cURL connection set up');
\r
2515 $this->setError('Unknown scheme ' . $this->scheme);
\r
2516 $this->debug('Unknown scheme ' . $this->scheme);
\r
2522 * sends the SOAP request and gets the SOAP response via HTTP[S]
\r
2524 * @param string $data message data
\r
2525 * @param integer $timeout set connection timeout in seconds
\r
2526 * @param integer $response_timeout set response timeout in seconds
\r
2527 * @param array $cookies cookies to send
\r
2528 * @return string data
\r
2531 function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
\r
2533 $this->debug('entered send() with data of length: '.strlen($data));
\r
2535 $this->tryagain = true;
\r
2537 while ($this->tryagain) {
\r
2538 $this->tryagain = false;
\r
2539 if ($tries++ < 2) {
\r
2540 // make connnection
\r
2541 if (!$this->connect($timeout, $response_timeout)){
\r
2546 if (!$this->sendRequest($data, $cookies)){
\r
2551 $respdata = $this->getResponse();
\r
2553 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
\r
2556 $this->debug('end of send()');
\r
2562 * sends the SOAP request and gets the SOAP response via HTTPS using CURL
\r
2564 * @param string $data message data
\r
2565 * @param integer $timeout set connection timeout in seconds
\r
2566 * @param integer $response_timeout set response timeout in seconds
\r
2567 * @param array $cookies cookies to send
\r
2568 * @return string data
\r
2572 function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
\r
2573 return $this->send($data, $timeout, $response_timeout, $cookies);
\r
2577 * if authenticating, set user credentials here
\r
2579 * @param string $username
\r
2580 * @param string $password
\r
2581 * @param string $authtype (basic|digest|certificate|ntlm)
\r
2582 * @param array $digestRequest (keys must be nonce, nc, realm, qop)
\r
2583 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
\r
2586 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
\r
2587 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
\r
2588 $this->appendDebug($this->varDump($digestRequest));
\r
2589 $this->debug("certRequest=");
\r
2590 $this->appendDebug($this->varDump($certRequest));
\r
2592 if ($authtype == 'basic') {
\r
2593 $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
\r
2594 } elseif ($authtype == 'digest') {
\r
2595 if (isset($digestRequest['nonce'])) {
\r
2596 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
\r
2598 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
\r
2600 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
\r
2601 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
\r
2603 // H(A1) = MD5(A1)
\r
2606 // A2 = Method ":" digest-uri-value
\r
2607 $A2 = $this->request_method . ':' . $this->digest_uri;
\r
2612 // KD(secret, data) = H(concat(secret, ":", data))
\r
2613 // if qop == auth:
\r
2614 // request-digest = <"> < KD ( H(A1), unq(nonce-value)
\r
2616 // ":" unq(cnonce-value)
\r
2617 // ":" unq(qop-value)
\r
2620 // if qop is missing,
\r
2621 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
\r
2623 $unhashedDigest = '';
\r
2624 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
\r
2626 if ($digestRequest['qop'] != '') {
\r
2627 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
\r
2629 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
\r
2632 $hashedDigest = md5($unhashedDigest);
\r
2635 if (isset($digestRequest['opaque'])) {
\r
2636 $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
\r
2639 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
\r
2641 } elseif ($authtype == 'certificate') {
\r
2642 $this->certRequest = $certRequest;
\r
2643 $this->debug('Authorization header not set for certificate');
\r
2644 } elseif ($authtype == 'ntlm') {
\r
2646 $this->debug('Authorization header not set for ntlm');
\r
2648 $this->username = $username;
\r
2649 $this->password = $password;
\r
2650 $this->authtype = $authtype;
\r
2651 $this->digestRequest = $digestRequest;
\r
2655 * set the soapaction value
\r
2657 * @param string $soapaction
\r
2660 function setSOAPAction($soapaction) {
\r
2661 $this->setHeader('SOAPAction', '"' . $soapaction . '"');
\r
2665 * use http encoding
\r
2667 * @param string $enc encoding style. supported values: gzip, deflate, or both
\r
2670 function setEncoding($enc='gzip, deflate') {
\r
2671 if (function_exists('gzdeflate')) {
\r
2672 $this->protocol_version = '1.1';
\r
2673 $this->setHeader('Accept-Encoding', $enc);
\r
2674 if (!isset($this->outgoing_headers['Connection'])) {
\r
2675 $this->setHeader('Connection', 'close');
\r
2676 $this->persistentConnection = false;
\r
2678 set_magic_quotes_runtime(0);
\r
2680 $this->encoding = $enc;
\r
2685 * set proxy info here
\r
2687 * @param string $proxyhost use an empty string to remove proxy
\r
2688 * @param string $proxyport
\r
2689 * @param string $proxyusername
\r
2690 * @param string $proxypassword
\r
2691 * @param string $proxyauthtype (basic|ntlm)
\r
2694 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
\r
2696 $this->proxy = array(
\r
2697 'host' => $proxyhost,
\r
2698 'port' => $proxyport,
\r
2699 'username' => $proxyusername,
\r
2700 'password' => $proxypassword,
\r
2701 'authtype' => $proxyauthtype
\r
2703 if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
\r
2704 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
\r
2707 $this->debug('remove proxy');
\r
2709 unsetHeader('Proxy-Authorization');
\r
2715 * Test if the given string starts with a header that is to be skipped.
\r
2716 * Skippable headers result from chunked transfer and proxy requests.
\r
2718 * @param string $data The string to check.
\r
2719 * @returns boolean Whether a skippable header was found.
\r
2722 function isSkippableCurlHeader(&$data) {
\r
2723 $skipHeaders = array( 'HTTP/1.1 100',
\r
2730 'HTTP/1.0 200 Connection established');
\r
2731 foreach ($skipHeaders as $hd) {
\r
2732 $prefix = substr($data, 0, strlen($hd));
\r
2733 if ($prefix == $hd) return true;
\r
2740 * decode a string that is encoded w/ "chunked' transfer encoding
\r
2741 * as defined in RFC2068 19.4.6
\r
2743 * @param string $buffer
\r
2744 * @param string $lb
\r
2749 function decodeChunked($buffer, $lb){
\r
2754 // read chunk-size, chunk-extension (if any) and CRLF
\r
2755 // get the position of the linebreak
\r
2756 $chunkend = strpos($buffer, $lb);
\r
2757 if ($chunkend == FALSE) {
\r
2758 $this->debug('no linebreak found in decodeChunked');
\r
2761 $temp = substr($buffer,0,$chunkend);
\r
2762 $chunk_size = hexdec( trim($temp) );
\r
2763 $chunkstart = $chunkend + strlen($lb);
\r
2764 // while (chunk-size > 0) {
\r
2765 while ($chunk_size > 0) {
\r
2766 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
\r
2767 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
\r
2769 // Just in case we got a broken connection
\r
2770 if ($chunkend == FALSE) {
\r
2771 $chunk = substr($buffer,$chunkstart);
\r
2772 // append chunk-data to entity-body
\r
2774 $length += strlen($chunk);
\r
2778 // read chunk-data and CRLF
\r
2779 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
\r
2780 // append chunk-data to entity-body
\r
2782 // length := length + chunk-size
\r
2783 $length += strlen($chunk);
\r
2784 // read chunk-size and CRLF
\r
2785 $chunkstart = $chunkend + strlen($lb);
\r
2787 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
\r
2788 if ($chunkend == FALSE) {
\r
2789 break; //Just in case we got a broken connection
\r
2791 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
\r
2792 $chunk_size = hexdec( trim($temp) );
\r
2793 $chunkstart = $chunkend;
\r
2799 * Writes the payload, including HTTP headers, to $this->outgoing_payload.
\r
2801 * @param string $data HTTP body
\r
2802 * @param string $cookie_str data for HTTP Cookie header
\r
2806 function buildPayload($data, $cookie_str = '') {
\r
2807 // Note: for cURL connections, $this->outgoing_payload is ignored,
\r
2808 // as is the Content-Length header, but these are still created as
\r
2809 // debugging guides.
\r
2811 // add content-length header
\r
2812 $this->setHeader('Content-Length', strlen($data));
\r
2814 // start building outgoing payload:
\r
2815 if ($this->proxy) {
\r
2816 $uri = $this->url;
\r
2818 $uri = $this->uri;
\r
2820 $req = "$this->request_method $uri HTTP/$this->protocol_version";
\r
2821 $this->debug("HTTP request: $req");
\r
2822 $this->outgoing_payload = "$req\r\n";
\r
2824 // loop thru headers, serializing
\r
2825 foreach($this->outgoing_headers as $k => $v){
\r
2826 $hdr = $k.': '.$v;
\r
2827 $this->debug("HTTP header: $hdr");
\r
2828 $this->outgoing_payload .= "$hdr\r\n";
\r
2831 // add any cookies
\r
2832 if ($cookie_str != '') {
\r
2833 $hdr = 'Cookie: '.$cookie_str;
\r
2834 $this->debug("HTTP header: $hdr");
\r
2835 $this->outgoing_payload .= "$hdr\r\n";
\r
2838 // header/body separator
\r
2839 $this->outgoing_payload .= "\r\n";
\r
2842 $this->outgoing_payload .= $data;
\r
2846 * sends the SOAP request via HTTP[S]
\r
2848 * @param string $data message data
\r
2849 * @param array $cookies cookies to send
\r
2850 * @return boolean true if OK, false if problem
\r
2853 function sendRequest($data, $cookies = NULL) {
\r
2854 // build cookie string
\r
2855 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
\r
2858 $this->buildPayload($data, $cookie_str);
\r
2860 if ($this->io_method() == 'socket') {
\r
2862 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
\r
2863 $this->setError('couldn\'t write message data to socket');
\r
2864 $this->debug('couldn\'t write message data to socket');
\r
2867 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
\r
2869 } else if ($this->io_method() == 'curl') {
\r
2871 // cURL does say this should only be the verb, and in fact it
\r
2872 // turns out that the URI and HTTP version are appended to this, which
\r
2873 // some servers refuse to work with (so we no longer use this method!)
\r
2874 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
\r
2875 $curl_headers = array();
\r
2876 foreach($this->outgoing_headers as $k => $v){
\r
2877 if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
\r
2878 $this->debug("Skip cURL header $k: $v");
\r
2880 $curl_headers[] = "$k: $v";
\r
2883 if ($cookie_str != '') {
\r
2884 $curl_headers[] = 'Cookie: ' . $cookie_str;
\r
2886 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
\r
2887 $this->debug('set cURL HTTP headers');
\r
2888 if ($this->request_method == "POST") {
\r
2889 $this->setCurlOption(CURLOPT_POST, 1);
\r
2890 $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
\r
2891 $this->debug('set cURL POST data');
\r
2894 // insert custom user-set cURL options
\r
2895 foreach ($this->ch_options as $key => $val) {
\r
2896 $this->setCurlOption($key, $val);
\r
2899 $this->debug('set cURL payload');
\r
2905 * gets the SOAP response via HTTP[S]
\r
2907 * @return string the response (also sets member variables like incoming_payload)
\r
2910 function getResponse(){
\r
2911 $this->incoming_payload = '';
\r
2913 if ($this->io_method() == 'socket') {
\r
2914 // loop until headers have been retrieved
\r
2916 while (!isset($lb)){
\r
2918 // We might EOF during header read.
\r
2919 if(feof($this->fp)) {
\r
2920 $this->incoming_payload = $data;
\r
2921 $this->debug('found no headers before EOF after length ' . strlen($data));
\r
2922 $this->debug("received before EOF:\n" . $data);
\r
2923 $this->setError('server failed to send headers');
\r
2927 $tmp = fgets($this->fp, 256);
\r
2928 $tmplen = strlen($tmp);
\r
2929 $this->debug("read line of $tmplen bytes: " . trim($tmp));
\r
2931 if ($tmplen == 0) {
\r
2932 $this->incoming_payload = $data;
\r
2933 $this->debug('socket read of headers timed out after length ' . strlen($data));
\r
2934 $this->debug("read before timeout: " . $data);
\r
2935 $this->setError('socket read of headers timed out');
\r
2940 $pos = strpos($data,"\r\n\r\n");
\r
2944 $pos = strpos($data,"\n\n");
\r
2949 // remove 100 headers
\r
2950 if (isset($lb) && ereg('^HTTP/1.1 100',$data)) {
\r
2955 // store header data
\r
2956 $this->incoming_payload .= $data;
\r
2957 $this->debug('found end of headers after length ' . strlen($data));
\r
2958 // process headers
\r
2959 $header_data = trim(substr($data,0,$pos));
\r
2960 $header_array = explode($lb,$header_data);
\r
2961 $this->incoming_headers = array();
\r
2962 $this->incoming_cookies = array();
\r
2963 foreach($header_array as $header_line){
\r
2964 $arr = explode(':',$header_line, 2);
\r
2965 if(count($arr) > 1){
\r
2966 $header_name = strtolower(trim($arr[0]));
\r
2967 $this->incoming_headers[$header_name] = trim($arr[1]);
\r
2968 if ($header_name == 'set-cookie') {
\r
2969 // TODO: allow multiple cookies from parseCookie
\r
2970 $cookie = $this->parseCookie(trim($arr[1]));
\r
2972 $this->incoming_cookies[] = $cookie;
\r
2973 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
\r
2975 $this->debug('did not find cookie in ' . trim($arr[1]));
\r
2978 } else if (isset($header_name)) {
\r
2979 // append continuation line to previous header
\r
2980 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
\r
2984 // loop until msg has been received
\r
2985 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
\r
2986 $content_length = 2147483647; // ignore any content-length header
\r
2988 $this->debug("want to read chunked content");
\r
2989 } elseif (isset($this->incoming_headers['content-length'])) {
\r
2990 $content_length = $this->incoming_headers['content-length'];
\r
2992 $this->debug("want to read content of length $content_length");
\r
2994 $content_length = 2147483647;
\r
2996 $this->debug("want to read content to EOF");
\r
3001 $tmp = fgets($this->fp, 256);
\r
3002 $tmplen = strlen($tmp);
\r
3003 $this->debug("read chunk line of $tmplen bytes");
\r
3004 if ($tmplen == 0) {
\r
3005 $this->incoming_payload = $data;
\r
3006 $this->debug('socket read of chunk length timed out after length ' . strlen($data));
\r
3007 $this->debug("read before timeout:\n" . $data);
\r
3008 $this->setError('socket read of chunk length timed out');
\r
3011 $content_length = hexdec(trim($tmp));
\r
3012 $this->debug("chunk length $content_length");
\r
3015 while (($strlen < $content_length) && (!feof($this->fp))) {
\r
3016 $readlen = min(8192, $content_length - $strlen);
\r
3017 $tmp = fread($this->fp, $readlen);
\r
3018 $tmplen = strlen($tmp);
\r
3019 $this->debug("read buffer of $tmplen bytes");
\r
3020 if (($tmplen == 0) && (!feof($this->fp))) {
\r
3021 $this->incoming_payload = $data;
\r
3022 $this->debug('socket read of body timed out after length ' . strlen($data));
\r
3023 $this->debug("read before timeout:\n" . $data);
\r
3024 $this->setError('socket read of body timed out');
\r
3027 $strlen += $tmplen;
\r
3030 if ($chunked && ($content_length > 0)) {
\r
3031 $tmp = fgets($this->fp, 256);
\r
3032 $tmplen = strlen($tmp);
\r
3033 $this->debug("read chunk terminator of $tmplen bytes");
\r
3034 if ($tmplen == 0) {
\r
3035 $this->incoming_payload = $data;
\r
3036 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
\r
3037 $this->debug("read before timeout:\n" . $data);
\r
3038 $this->setError('socket read of chunk terminator timed out');
\r
3042 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
\r
3043 if (feof($this->fp)) {
\r
3044 $this->debug('read to EOF');
\r
3046 $this->debug('read body of length ' . strlen($data));
\r
3047 $this->incoming_payload .= $data;
\r
3048 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
\r
3050 // close filepointer
\r
3052 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
\r
3053 (! $this->persistentConnection) || feof($this->fp)){
\r
3054 fclose($this->fp);
\r
3055 $this->fp = false;
\r
3056 $this->debug('closed socket');
\r
3059 // connection was closed unexpectedly
\r
3060 if($this->incoming_payload == ''){
\r
3061 $this->setError('no response from server');
\r
3065 // decode transfer-encoding
\r
3066 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
\r
3067 // if(!$data = $this->decodeChunked($data, $lb)){
\r
3068 // $this->setError('Decoding of chunked data failed');
\r
3071 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
\r
3072 // set decoded payload
\r
3073 // $this->incoming_payload = $header_data.$lb.$lb.$data;
\r
3076 } else if ($this->io_method() == 'curl') {
\r
3077 // send and receive
\r
3078 $this->debug('send and receive with cURL');
\r
3079 $this->incoming_payload = curl_exec($this->ch);
\r
3080 $data = $this->incoming_payload;
\r
3082 $cErr = curl_error($this->ch);
\r
3083 if ($cErr != '') {
\r
3084 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
\r
3085 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
\r
3086 foreach(curl_getinfo($this->ch) as $k => $v){
\r
3087 $err .= "$k: $v<br>";
\r
3089 $this->debug($err);
\r
3090 $this->setError($err);
\r
3091 curl_close($this->ch);
\r
3095 //var_dump(curl_getinfo($this->ch));
\r
3096 ////echo '</pre>';
\r
3099 $this->debug('No cURL error, closing cURL');
\r
3100 curl_close($this->ch);
\r
3102 // try removing skippable headers
\r
3103 $savedata = $data;
\r
3104 while ($this->isSkippableCurlHeader($data)) {
\r
3105 $this->debug("Found HTTP header to skip");
\r
3106 if ($pos = strpos($data,"\r\n\r\n")) {
\r
3107 $data = ltrim(substr($data,$pos));
\r
3108 } elseif($pos = strpos($data,"\n\n") ) {
\r
3109 $data = ltrim(substr($data,$pos));
\r
3113 if ($data == '') {
\r
3114 // have nothing left; just remove 100 header(s)
\r
3115 $data = $savedata;
\r
3116 while (ereg('^HTTP/1.1 100',$data)) {
\r
3117 if ($pos = strpos($data,"\r\n\r\n")) {
\r
3118 $data = ltrim(substr($data,$pos));
\r
3119 } elseif($pos = strpos($data,"\n\n") ) {
\r
3120 $data = ltrim(substr($data,$pos));
\r
3125 // separate content from HTTP headers
\r
3126 if ($pos = strpos($data,"\r\n\r\n")) {
\r
3128 } elseif( $pos = strpos($data,"\n\n")) {
\r
3131 $this->debug('no proper separation of headers and document');
\r
3132 $this->setError('no proper separation of headers and document');
\r
3135 $header_data = trim(substr($data,0,$pos));
\r
3136 $header_array = explode($lb,$header_data);
\r
3137 $data = ltrim(substr($data,$pos));
\r
3138 $this->debug('found proper separation of headers and document');
\r
3139 $this->debug('cleaned data, stringlen: '.strlen($data));
\r
3141 foreach ($header_array as $header_line) {
\r
3142 $arr = explode(':',$header_line,2);
\r
3143 if(count($arr) > 1){
\r
3144 $header_name = strtolower(trim($arr[0]));
\r
3145 $this->incoming_headers[$header_name] = trim($arr[1]);
\r
3146 if ($header_name == 'set-cookie') {
\r
3147 // TODO: allow multiple cookies from parseCookie
\r
3148 $cookie = $this->parseCookie(trim($arr[1]));
\r
3150 $this->incoming_cookies[] = $cookie;
\r
3151 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
\r
3153 $this->debug('did not find cookie in ' . trim($arr[1]));
\r
3156 } else if (isset($header_name)) {
\r
3157 // append continuation line to previous header
\r
3158 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
\r
3163 $this->response_status_line = $header_array[0];
\r
3164 $arr = explode(' ', $this->response_status_line, 3);
\r
3165 $http_version = $arr[0];
\r
3166 $http_status = intval($arr[1]);
\r
3167 $http_reason = count($arr) > 2 ? $arr[2] : '';
\r
3169 // see if we need to resend the request with http digest authentication
\r
3170 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
\r
3171 $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
\r
3172 $this->setURL($this->incoming_headers['location']);
\r
3173 $this->tryagain = true;
\r
3177 // see if we need to resend the request with http digest authentication
\r
3178 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
\r
3179 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
\r
3180 if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
\r
3181 $this->debug('Server wants digest authentication');
\r
3182 // remove "Digest " from our elements
\r
3183 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
\r
3185 // parse elements into array
\r
3186 $digestElements = explode(',', $digestString);
\r
3187 foreach ($digestElements as $val) {
\r
3188 $tempElement = explode('=', trim($val), 2);
\r
3189 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
\r
3192 // should have (at least) qop, realm, nonce
\r
3193 if (isset($digestRequest['nonce'])) {
\r
3194 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
\r
3195 $this->tryagain = true;
\r
3199 $this->debug('HTTP authentication failed');
\r
3200 $this->setError('HTTP authentication failed');
\r
3205 ($http_status >= 300 && $http_status <= 307) ||
\r
3206 ($http_status >= 400 && $http_status <= 417) ||
\r
3207 ($http_status >= 501 && $http_status <= 505)
\r
3209 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
\r
3213 // decode content-encoding
\r
3214 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
\r
3215 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
\r
3216 // if decoding works, use it. else assume data wasn't gzencoded
\r
3217 if(function_exists('gzinflate')){
\r
3218 //$timer->setMarker('starting decoding of gzip/deflated content');
\r
3219 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
\r
3220 // this means there are no Zlib headers, although there should be
\r
3221 $this->debug('The gzinflate function exists');
\r
3222 $datalen = strlen($data);
\r
3223 if ($this->incoming_headers['content-encoding'] == 'deflate') {
\r
3224 if ($degzdata = @gzinflate($data)) {
\r
3225 $data = $degzdata;
\r
3226 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
\r
3227 if (strlen($data) < $datalen) {
\r
3228 // test for the case that the payload has been compressed twice
\r
3229 $this->debug('The inflated payload is smaller than the gzipped one; try again');
\r
3230 if ($degzdata = @gzinflate($data)) {
\r
3231 $data = $degzdata;
\r
3232 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
\r
3236 $this->debug('Error using gzinflate to inflate the payload');
\r
3237 $this->setError('Error using gzinflate to inflate the payload');
\r
3239 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
\r
3240 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
\r
3241 $data = $degzdata;
\r
3242 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
\r
3243 if (strlen($data) < $datalen) {
\r
3244 // test for the case that the payload has been compressed twice
\r
3245 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
\r
3246 if ($degzdata = @gzinflate(substr($data, 10))) {
\r
3247 $data = $degzdata;
\r
3248 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
\r
3252 $this->debug('Error using gzinflate to un-gzip the payload');
\r
3253 $this->setError('Error using gzinflate to un-gzip the payload');
\r
3256 //$timer->setMarker('finished decoding of gzip/deflated content');
\r
3257 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
\r
3258 // set decoded payload
\r
3259 $this->incoming_payload = $header_data.$lb.$lb.$data;
\r
3261 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
\r
3262 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
\r
3265 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
\r
3266 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
\r
3269 $this->debug('No Content-Encoding header');
\r
3272 if(strlen($data) == 0){
\r
3273 $this->debug('no data after headers!');
\r
3274 $this->setError('no data present after HTTP headers');
\r
3282 * sets the content-type for the SOAP message to be sent
\r
3284 * @param string $type the content type, MIME style
\r
3285 * @param mixed $charset character set used for encoding (or false)
\r
3288 function setContentType($type, $charset = false) {
\r
3289 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
\r
3293 * specifies that an HTTP persistent connection should be used
\r
3295 * @return boolean whether the request was honored by this method.
\r
3298 function usePersistentConnection(){
\r
3299 if (isset($this->outgoing_headers['Accept-Encoding'])) {
\r
3302 $this->protocol_version = '1.1';
\r
3303 $this->persistentConnection = true;
\r
3304 $this->setHeader('Connection', 'Keep-Alive');
\r
3309 * parse an incoming Cookie into it's parts
\r
3311 * @param string $cookie_str content of cookie
\r
3312 * @return array with data of that cookie
\r
3316 * TODO: allow a Set-Cookie string to be parsed into multiple cookies
\r
3318 function parseCookie($cookie_str) {
\r
3319 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
\r
3320 $data = split(';', $cookie_str);
\r
3321 $value_str = $data[0];
\r
3323 $cookie_param = 'domain=';
\r
3324 $start = strpos($cookie_str, $cookie_param);
\r
3326 $domain = substr($cookie_str, $start + strlen($cookie_param));
\r
3327 $domain = substr($domain, 0, strpos($domain, ';'));
\r
3332 $cookie_param = 'expires=';
\r
3333 $start = strpos($cookie_str, $cookie_param);
\r
3335 $expires = substr($cookie_str, $start + strlen($cookie_param));
\r
3336 $expires = substr($expires, 0, strpos($expires, ';'));
\r
3341 $cookie_param = 'path=';
\r
3342 $start = strpos($cookie_str, $cookie_param);
\r
3343 if ( $start > 0 ) {
\r
3344 $path = substr($cookie_str, $start + strlen($cookie_param));
\r
3345 $path = substr($path, 0, strpos($path, ';'));
\r
3350 $cookie_param = ';secure;';
\r
3351 if (strpos($cookie_str, $cookie_param) !== FALSE) {
\r
3357 $sep_pos = strpos($value_str, '=');
\r
3360 $name = substr($value_str, 0, $sep_pos);
\r
3361 $value = substr($value_str, $sep_pos + 1);
\r
3362 $cookie= array( 'name' => $name,
\r
3363 'value' => $value,
\r
3364 'domain' => $domain,
\r
3366 'expires' => $expires,
\r
3367 'secure' => $secure
\r
3375 * sort out cookies for the current request
\r
3377 * @param array $cookies array with all cookies
\r
3378 * @param boolean $secure is the send-content secure or not?
\r
3379 * @return string for Cookie-HTTP-Header
\r
3382 function getCookiesForRequest($cookies, $secure=false) {
\r
3384 if ((! is_null($cookies)) && (is_array($cookies))) {
\r
3385 foreach ($cookies as $cookie) {
\r
3386 if (! is_array($cookie)) {
\r
3389 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
\r
3390 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
\r
3391 if (strtotime($cookie['expires']) <= time()) {
\r
3392 $this->debug('cookie has expired');
\r
3396 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
\r
3397 $domain = preg_quote($cookie['domain']);
\r
3398 if (! preg_match("'.*$domain$'i", $this->host)) {
\r
3399 $this->debug('cookie has different domain');
\r
3403 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
\r
3404 $path = preg_quote($cookie['path']);
\r
3405 if (! preg_match("'^$path.*'i", $this->path)) {
\r
3406 $this->debug('cookie is for a different path');
\r
3410 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
\r
3411 $this->debug('cookie is secure, transport is not');
\r
3414 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
\r
3415 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
\r
3418 return $cookie_str;
\r
3427 * parses a WSDL file, allows access to it's data, other utility methods.
\r
3428 * also builds WSDL structures programmatically.
\r
3430 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
3431 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
3432 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
3435 class wsdl extends nusoap_base {
\r
3436 // URL or filename of the root of this WSDL
\r
3438 // define internal arrays of bindings, ports, operations, messages, etc.
\r
3439 var $schemas = array();
\r
3440 var $currentSchema;
\r
3441 var $message = array();
\r
3442 var $complexTypes = array();
\r
3443 var $messages = array();
\r
3444 var $currentMessage;
\r
3445 var $currentOperation;
\r
3446 var $portTypes = array();
\r
3447 var $currentPortType;
\r
3448 var $bindings = array();
\r
3449 var $currentBinding;
\r
3450 var $ports = array();
\r
3452 var $opData = array();
\r
3454 var $documentation = false;
\r
3455 var $endpoint = '';
\r
3456 // array of wsdl docs to import
\r
3457 var $import = array();
\r
3460 var $position = 0;
\r
3462 var $depth_array = array();
\r
3463 // for getting wsdl
\r
3464 var $proxyhost = '';
\r
3465 var $proxyport = '';
\r
3466 var $proxyusername = '';
\r
3467 var $proxypassword = '';
\r
3469 var $response_timeout = 30;
\r
3470 var $curl_options = array(); // User-specified cURL options
\r
3471 var $use_curl = false; // whether to always try to use cURL
\r
3472 // for HTTP authentication
\r
3473 var $username = ''; // Username for HTTP authentication
\r
3474 var $password = ''; // Password for HTTP authentication
\r
3475 var $authtype = ''; // Type of HTTP authentication
\r
3476 var $certRequest = array(); // Certificate for HTTP SSL authentication
\r
3481 * @param string $wsdl WSDL document URL
\r
3482 * @param string $proxyhost
\r
3483 * @param string $proxyport
\r
3484 * @param string $proxyusername
\r
3485 * @param string $proxypassword
\r
3486 * @param integer $timeout set the connection timeout
\r
3487 * @param integer $response_timeout set the response timeout
\r
3488 * @param array $curl_options user-specified cURL options
\r
3489 * @param boolean $use_curl try to use cURL
\r
3492 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
\r
3493 parent::nusoap_base();
\r
3494 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
\r
3495 $this->proxyhost = $proxyhost;
\r
3496 $this->proxyport = $proxyport;
\r
3497 $this->proxyusername = $proxyusername;
\r
3498 $this->proxypassword = $proxypassword;
\r
3499 $this->timeout = $timeout;
\r
3500 $this->response_timeout = $response_timeout;
\r
3501 if (is_array($curl_options))
\r
3502 $this->curl_options = $curl_options;
\r
3503 $this->use_curl = $use_curl;
\r
3504 $this->fetchWSDL($wsdl);
\r
3508 * fetches the WSDL document and parses it
\r
3512 function fetchWSDL($wsdl) {
\r
3513 $this->debug("parse and process WSDL path=$wsdl");
\r
3514 $this->wsdl = $wsdl;
\r
3515 // parse wsdl file
\r
3516 if ($this->wsdl != "") {
\r
3517 $this->parseWSDL($this->wsdl);
\r
3520 // TODO: handle imports more properly, grabbing them in-line and nesting them
\r
3521 $imported_urls = array();
\r
3523 while ($imported > 0) {
\r
3526 foreach ($this->schemas as $ns => $list) {
\r
3527 foreach ($list as $xs) {
\r
3528 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
\r
3529 foreach ($xs->imports as $ns2 => $list2) {
\r
3530 for ($ii = 0; $ii < count($list2); $ii++) {
\r
3531 if (! $list2[$ii]['loaded']) {
\r
3532 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
\r
3533 $url = $list2[$ii]['location'];
\r
3535 $urlparts = parse_url($url);
\r
3536 if (!isset($urlparts['host'])) {
\r
3537 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
\r
3538 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
\r
3540 if (! in_array($url, $imported_urls)) {
\r
3541 $this->parseWSDL($url);
\r
3543 $imported_urls[] = $url;
\r
3546 $this->debug("Unexpected scenario: empty URL for unloaded import");
\r
3554 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
\r
3555 foreach ($this->import as $ns => $list) {
\r
3556 for ($ii = 0; $ii < count($list); $ii++) {
\r
3557 if (! $list[$ii]['loaded']) {
\r
3558 $this->import[$ns][$ii]['loaded'] = true;
\r
3559 $url = $list[$ii]['location'];
\r
3561 $urlparts = parse_url($url);
\r
3562 if (!isset($urlparts['host'])) {
\r
3563 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
\r
3564 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
\r
3566 if (! in_array($url, $imported_urls)) {
\r
3567 $this->parseWSDL($url);
\r
3569 $imported_urls[] = $url;
\r
3572 $this->debug("Unexpected scenario: empty URL for unloaded import");
\r
3578 // add new data to operation data
\r
3579 foreach($this->bindings as $binding => $bindingData) {
\r
3580 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
\r
3581 foreach($bindingData['operations'] as $operation => $data) {
\r
3582 $this->debug('post-parse data gathering for ' . $operation);
\r
3583 $this->bindings[$binding]['operations'][$operation]['input'] =
\r
3584 isset($this->bindings[$binding]['operations'][$operation]['input']) ?
\r
3585 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
\r
3586 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
\r
3587 $this->bindings[$binding]['operations'][$operation]['output'] =
\r
3588 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
\r
3589 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
\r
3590 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
\r
3591 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
\r
3592 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
\r
3594 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
\r
3595 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
\r
3597 // Set operation style if necessary, but do not override one already provided
\r
3598 if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
\r
3599 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
\r
3601 $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
\r
3602 $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
\r
3603 $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
\r
3610 * parses the wsdl document
\r
3612 * @param string $wsdl path or URL
\r
3613 * @access private
\r
3615 function parseWSDL($wsdl = '') {
\r
3616 $this->debug("parse WSDL at path=$wsdl");
\r
3618 if ($wsdl == '') {
\r
3619 $this->debug('no wsdl passed to parseWSDL()!!');
\r
3620 $this->setError('no wsdl passed to parseWSDL()!!');
\r
3624 // parse $wsdl for url format
\r
3625 $wsdl_props = parse_url($wsdl);
\r
3627 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
\r
3628 $this->debug('getting WSDL http(s) URL ' . $wsdl);
\r
3630 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
\r
3631 $tr->request_method = 'GET';
\r
3632 $tr->useSOAPAction = false;
\r
3633 if($this->proxyhost && $this->proxyport){
\r
3634 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
\r
3636 if ($this->authtype != '') {
\r
3637 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
\r
3639 $tr->setEncoding('gzip, deflate');
\r
3640 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
\r
3641 //$this->debug("WSDL request\n" . $tr->outgoing_payload);
\r
3642 //$this->debug("WSDL response\n" . $tr->incoming_payload);
\r
3643 $this->appendDebug($tr->getDebug());
\r
3645 if($err = $tr->getError() ){
\r
3646 $errstr = 'HTTP ERROR: '.$err;
\r
3647 $this->debug($errstr);
\r
3648 $this->setError($errstr);
\r
3653 $this->debug("got WSDL URL");
\r
3655 // $wsdl is not http(s), so treat it as a file URL or plain file path
\r
3656 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
\r
3657 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
\r
3661 $this->debug('getting WSDL file ' . $path);
\r
3662 if ($fp = @fopen($path, 'r')) {
\r
3663 $wsdl_string = '';
\r
3664 while ($data = fread($fp, 32768)) {
\r
3665 $wsdl_string .= $data;
\r
3669 $errstr = "Bad path to WSDL file $path";
\r
3670 $this->debug($errstr);
\r
3671 $this->setError($errstr);
\r
3675 $this->debug('Parse WSDL');
\r
3676 // end new code added
\r
3677 // Create an XML parser.
\r
3678 $this->parser = xml_parser_create();
\r
3679 // Set the options for parsing the XML data.
\r
3680 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
\r
3681 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
\r
3682 // Set the object for the parser.
\r
3683 xml_set_object($this->parser, $this);
\r
3684 // Set the element handlers for the parser.
\r
3685 xml_set_element_handler($this->parser, 'start_element', 'end_element');
\r
3686 xml_set_character_data_handler($this->parser, 'character_data');
\r
3687 // Parse the XML file.
\r
3688 if (!xml_parse($this->parser, $wsdl_string, true)) {
\r
3689 // Display an error message.
\r
3690 $errstr = sprintf(
\r
3691 'XML error parsing WSDL from %s on line %d: %s',
\r
3693 xml_get_current_line_number($this->parser),
\r
3694 xml_error_string(xml_get_error_code($this->parser))
\r
3696 $this->debug($errstr);
\r
3697 $this->debug("XML payload:\n" . $wsdl_string);
\r
3698 $this->setError($errstr);
\r
3701 // free the parser
\r
3702 xml_parser_free($this->parser);
\r
3703 $this->debug('Parsing WSDL done');
\r
3704 // catch wsdl parse errors
\r
3705 if($this->getError()){
\r
3712 * start-element handler
\r
3714 * @param string $parser XML parser object
\r
3715 * @param string $name element name
\r
3716 * @param string $attrs associative array of attributes
\r
3717 * @access private
\r
3719 function start_element($parser, $name, $attrs)
\r
3721 if ($this->status == 'schema') {
\r
3722 $this->currentSchema->schemaStartElement($parser, $name, $attrs);
\r
3723 $this->appendDebug($this->currentSchema->getDebug());
\r
3724 $this->currentSchema->clearDebug();
\r
3725 } elseif (ereg('schema$', $name)) {
\r
3726 $this->debug('Parsing WSDL schema');
\r
3727 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
\r
3728 $this->status = 'schema';
\r
3729 $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
\r
3730 $this->currentSchema->schemaStartElement($parser, $name, $attrs);
\r
3731 $this->appendDebug($this->currentSchema->getDebug());
\r
3732 $this->currentSchema->clearDebug();
\r
3734 // position in the total number of elements, starting from 0
\r
3735 $pos = $this->position++;
\r
3736 $depth = $this->depth++;
\r
3737 // set self as current value for this depth
\r
3738 $this->depth_array[$depth] = $pos;
\r
3739 $this->message[$pos] = array('cdata' => '');
\r
3740 // process attributes
\r
3741 if (count($attrs) > 0) {
\r
3742 // register namespace declarations
\r
3743 foreach($attrs as $k => $v) {
\r
3744 if (ereg("^xmlns", $k)) {
\r
3745 if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
\r
3746 $this->namespaces[$ns_prefix] = $v;
\r
3748 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
\r
3750 if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
\r
3751 $this->XMLSchemaVersion = $v;
\r
3752 $this->namespaces['xsi'] = $v . '-instance';
\r
3756 // expand each attribute prefix to its namespace
\r
3757 foreach($attrs as $k => $v) {
\r
3758 $k = strpos($k, ':') ? $this->expandQname($k) : $k;
\r
3759 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
\r
3760 $v = strpos($v, ':') ? $this->expandQname($v) : $v;
\r
3768 // get element prefix, namespace and name
\r
3769 if (ereg(':', $name)) {
\r
3771 $prefix = substr($name, 0, strpos($name, ':'));
\r
3773 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
\r
3774 // get unqualified name
\r
3775 $name = substr(strstr($name, ':'), 1);
\r
3777 // process attributes, expanding any prefixes to namespaces
\r
3778 // find status, register data
\r
3779 switch ($this->status) {
\r
3781 if ($name == 'part') {
\r
3782 if (isset($attrs['type'])) {
\r
3783 $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
\r
3784 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
\r
3786 if (isset($attrs['element'])) {
\r
3787 $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
\r
3788 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
\r
3795 $this->currentPortOperation = $attrs['name'];
\r
3796 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
\r
3797 if (isset($attrs['parameterOrder'])) {
\r
3798 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
\r
3801 case 'documentation':
\r
3802 $this->documentation = true;
\r
3804 // merge input/output data
\r
3806 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
\r
3807 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
\r
3815 if (isset($attrs['style'])) {
\r
3816 $this->bindings[$this->currentBinding]['prefix'] = $prefix;
\r
3818 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
\r
3821 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
\r
3824 if (isset($attrs['soapAction'])) {
\r
3825 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
\r
3827 if (isset($attrs['style'])) {
\r
3828 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
\r
3830 if (isset($attrs['name'])) {
\r
3831 $this->currentOperation = $attrs['name'];
\r
3832 $this->debug("current binding operation: $this->currentOperation");
\r
3833 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
\r
3834 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
\r
3835 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
\r
3839 $this->opStatus = 'input';
\r
3842 $this->opStatus = 'output';
\r
3845 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
\r
3846 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
\r
3848 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
\r
3856 $this->currentPort = $attrs['name'];
\r
3857 $this->debug('current port: ' . $this->currentPort);
\r
3858 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
\r
3862 $this->ports[$this->currentPort]['location'] = $attrs['location'];
\r
3863 $this->ports[$this->currentPort]['bindingType'] = $namespace;
\r
3864 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
\r
3865 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
\r
3873 if (isset($attrs['location'])) {
\r
3874 $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
\r
3875 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
\r
3877 $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
\r
3878 if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
\r
3879 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
\r
3881 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
\r
3886 // $this->status = 'schema';
\r
3889 $this->status = 'message';
\r
3890 $this->messages[$attrs['name']] = array();
\r
3891 $this->currentMessage = $attrs['name'];
\r
3894 $this->status = 'portType';
\r
3895 $this->portTypes[$attrs['name']] = array();
\r
3896 $this->currentPortType = $attrs['name'];
\r
3899 if (isset($attrs['name'])) {
\r
3900 // get binding name
\r
3901 if (strpos($attrs['name'], ':')) {
\r
3902 $this->currentBinding = $this->getLocalPart($attrs['name']);
\r
3904 $this->currentBinding = $attrs['name'];
\r
3906 $this->status = 'binding';
\r
3907 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
\r
3908 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
\r
3912 $this->serviceName = $attrs['name'];
\r
3913 $this->status = 'service';
\r
3914 $this->debug('current service: ' . $this->serviceName);
\r
3916 case 'definitions':
\r
3917 foreach ($attrs as $name => $value) {
\r
3918 $this->wsdl_info[$name] = $value;
\r
3926 * end-element handler
\r
3928 * @param string $parser XML parser object
\r
3929 * @param string $name element name
\r
3930 * @access private
\r
3932 function end_element($parser, $name){
\r
3933 // unset schema status
\r
3934 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
\r
3935 $this->status = "";
\r
3936 $this->appendDebug($this->currentSchema->getDebug());
\r
3937 $this->currentSchema->clearDebug();
\r
3938 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
\r
3939 $this->debug('Parsing WSDL schema done');
\r
3941 if ($this->status == 'schema') {
\r
3942 $this->currentSchema->schemaEndElement($parser, $name);
\r
3944 // bring depth down a notch
\r
3947 // end documentation
\r
3948 if ($this->documentation) {
\r
3949 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
\r
3950 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
\r
3951 $this->documentation = false;
\r
3956 * element content handler
\r
3958 * @param string $parser XML parser object
\r
3959 * @param string $data element content
\r
3960 * @access private
\r
3962 function character_data($parser, $data)
\r
3964 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
\r
3965 if (isset($this->message[$pos]['cdata'])) {
\r
3966 $this->message[$pos]['cdata'] .= $data;
\r
3968 if ($this->documentation) {
\r
3969 $this->documentation .= $data;
\r
3974 * if authenticating, set user credentials here
\r
3976 * @param string $username
\r
3977 * @param string $password
\r
3978 * @param string $authtype (basic|digest|certificate|ntlm)
\r
3979 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
\r
3982 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
\r
3983 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
\r
3984 $this->appendDebug($this->varDump($certRequest));
\r
3985 $this->username = $username;
\r
3986 $this->password = $password;
\r
3987 $this->authtype = $authtype;
\r
3988 $this->certRequest = $certRequest;
\r
3991 function getBindingData($binding)
\r
3993 if (is_array($this->bindings[$binding])) {
\r
3994 return $this->bindings[$binding];
\r
3999 * returns an assoc array of operation names => operation data
\r
4001 * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
\r
4005 function getOperations($bindingType = 'soap') {
\r
4007 if ($bindingType == 'soap') {
\r
4008 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
\r
4009 } elseif ($bindingType == 'soap12') {
\r
4010 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
\r
4012 // loop thru ports
\r
4013 foreach($this->ports as $port => $portData) {
\r
4014 // binding type of port matches parameter
\r
4015 if ($portData['bindingType'] == $bindingType) {
\r
4016 //$this->debug("getOperations for port $port");
\r
4017 //$this->debug("port data: " . $this->varDump($portData));
\r
4018 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
\r
4020 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
\r
4021 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
\r
4029 * returns an associative array of data necessary for calling an operation
\r
4031 * @param string $operation name of operation
\r
4032 * @param string $bindingType type of binding eg: soap, soap12
\r
4036 function getOperationData($operation, $bindingType = 'soap')
\r
4038 if ($bindingType == 'soap') {
\r
4039 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
\r
4040 } elseif ($bindingType == 'soap12') {
\r
4041 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
\r
4043 // loop thru ports
\r
4044 foreach($this->ports as $port => $portData) {
\r
4045 // binding type of port matches parameter
\r
4046 if ($portData['bindingType'] == $bindingType) {
\r
4048 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
\r
4049 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
\r
4050 // note that we could/should also check the namespace here
\r
4051 if ($operation == $bOperation) {
\r
4052 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
\r
4061 * returns an associative array of data necessary for calling an operation
\r
4063 * @param string $soapAction soapAction for operation
\r
4064 * @param string $bindingType type of binding eg: soap, soap12
\r
4068 function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
\r
4069 if ($bindingType == 'soap') {
\r
4070 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
\r
4071 } elseif ($bindingType == 'soap12') {
\r
4072 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
\r
4074 // loop thru ports
\r
4075 foreach($this->ports as $port => $portData) {
\r
4076 // binding type of port matches parameter
\r
4077 if ($portData['bindingType'] == $bindingType) {
\r
4078 // loop through operations for the binding
\r
4079 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
\r
4080 if ($opData['soapAction'] == $soapAction) {
\r
4089 * returns an array of information about a given type
\r
4090 * returns false if no type exists by the given name
\r
4092 * typeDef = array(
\r
4093 * 'elements' => array(), // refs to elements array
\r
4094 * 'restrictionBase' => '',
\r
4095 * 'phpType' => '',
\r
4096 * 'order' => '(sequence|all)',
\r
4097 * 'attrs' => array() // refs to attributes array
\r
4100 * @param string $type the type
\r
4101 * @param string $ns namespace (not prefix) of the type
\r
4104 * @see nusoap_xmlschema
\r
4106 function getTypeDef($type, $ns) {
\r
4107 $this->debug("in getTypeDef: type=$type, ns=$ns");
\r
4108 if ((! $ns) && isset($this->namespaces['tns'])) {
\r
4109 $ns = $this->namespaces['tns'];
\r
4110 $this->debug("in getTypeDef: type namespace forced to $ns");
\r
4112 if (!isset($this->schemas[$ns])) {
\r
4113 foreach ($this->schemas as $ns0 => $schema0) {
\r
4114 if (strcasecmp($ns, $ns0) == 0) {
\r
4115 $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
\r
4121 if (isset($this->schemas[$ns])) {
\r
4122 $this->debug("in getTypeDef: have schema for namespace $ns");
\r
4123 for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
\r
4124 $xs = &$this->schemas[$ns][$i];
\r
4125 $t = $xs->getTypeDef($type);
\r
4126 //$this->appendDebug($xs->getDebug());
\r
4127 //$xs->clearDebug();
\r
4129 if (!isset($t['phpType'])) {
\r
4130 // get info for type to tack onto the element
\r
4131 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
\r
4132 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
\r
4133 $etype = $this->getTypeDef($uqType, $ns);
\r
4135 $this->debug("found type for [element] $type:");
\r
4136 $this->debug($this->varDump($etype));
\r
4137 if (isset($etype['phpType'])) {
\r
4138 $t['phpType'] = $etype['phpType'];
\r
4140 if (isset($etype['elements'])) {
\r
4141 $t['elements'] = $etype['elements'];
\r
4143 if (isset($etype['attrs'])) {
\r
4144 $t['attrs'] = $etype['attrs'];
\r
4152 $this->debug("in getTypeDef: do not have schema for namespace $ns");
\r
4158 * prints html description of services
\r
4162 function webDescription(){
\r
4163 global $HTTP_SERVER_VARS;
\r
4165 if (isset($_SERVER)) {
\r
4166 $PHP_SELF = $_SERVER['PHP_SELF'];
\r
4167 } elseif (isset($HTTP_SERVER_VARS)) {
\r
4168 $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
\r
4170 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
\r
4174 <html><head><title>NuSOAP: '.$this->serviceName.'</title>
\r
4175 <style type="text/css">
\r
4176 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
\r
4177 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
\r
4178 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
\r
4179 ul { margin-top: 10px; margin-left: 20px; }
\r
4180 li { list-style-type: none; margin-top: 10px; color: #000000; }
\r
4182 margin-left: 0px; padding-bottom: 2em; }
\r
4184 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
\r
4185 margin-top: 10px; margin-left: 0px; color: #000000;
\r
4186 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
\r
4188 font-family: arial; font-size: 26px; color: #ffffff;
\r
4189 background-color: #999999; width: 105%; margin-left: 0px;
\r
4190 padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
\r
4192 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
\r
4193 font-family: arial; overflow: hidden; width: 600;
\r
4194 padding: 20px; font-size: 10px; background-color: #999999;
\r
4195 layer-background-color:#FFFFFF; }
\r
4196 a,a:active { color: charcoal; font-weight: bold; }
\r
4197 a:visited { color: #666666; font-weight: bold; }
\r
4198 a:hover { color: cc3300; font-weight: bold; }
\r
4200 <script language="JavaScript" type="text/javascript">
\r
4202 // POP-UP CAPTIONS...
\r
4203 function lib_bwcheck(){ //Browsercheck (needed)
\r
4204 this.ver=navigator.appVersion
\r
4205 this.agent=navigator.userAgent
\r
4206 this.dom=document.getElementById?1:0
\r
4207 this.opera5=this.agent.indexOf("Opera 5")>-1
\r
4208 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
\r
4209 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
\r
4210 this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
\r
4211 this.ie=this.ie4||this.ie5||this.ie6
\r
4212 this.mac=this.agent.indexOf("Mac")>-1
\r
4213 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
\r
4214 this.ns4=(document.layers && !this.dom)?1:0;
\r
4215 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
\r
4218 var bw = new lib_bwcheck()
\r
4219 //Makes crossbrowser object.
\r
4220 function makeObj(obj){
\r
4221 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
\r
4222 if(!this.evnt) return false
\r
4223 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
\r
4224 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
\r
4225 this.writeIt=b_writeIt;
\r
4228 // A unit of measure that will be added when setting the position of a layer.
\r
4229 //var px = bw.ns4||window.opera?"":"px";
\r
4230 function b_writeIt(text){
\r
4231 if (bw.ns4){this.wref.write(text);this.wref.close()}
\r
4232 else this.wref.innerHTML = text
\r
4234 //Shows the messages
\r
4236 function popup(divid){
\r
4237 if(oDesc = new makeObj(divid)){
\r
4238 oDesc.css.visibility = "visible"
\r
4241 function popout(){ // Hides message
\r
4242 if(oDesc) oDesc.css.visibility = "hidden"
\r
4248 <div class=content>
\r
4250 <div class=title>'.$this->serviceName.'</div>
\r
4252 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
\r
4253 Click on an operation name to view it's details.</p>
\r
4255 foreach($this->getOperations() as $op => $data){
\r
4256 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
\r
4257 // create hidden div
\r
4258 $b .= "<div id='$op' class='hidden'>
\r
4259 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
\r
4260 foreach($data as $donnie => $marie){ // loop through opdata
\r
4261 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
\r
4262 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
\r
4263 foreach($marie as $captain => $tenille){ // loop through data
\r
4264 if($captain == 'parts'){ // loop thru parts
\r
4265 $b .= " $captain:<br>";
\r
4266 //if(is_array($tenille)){
\r
4267 foreach($tenille as $joanie => $chachi){
\r
4268 $b .= " $joanie: $chachi<br>";
\r
4272 $b .= " $captain: $tenille<br>";
\r
4276 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
\r
4284 </div></body></html>';
\r
4289 * serialize the parsed wsdl
\r
4291 * @param mixed $debug whether to put debug=1 in endpoint URL
\r
4292 * @return string serialization of WSDL
\r
4295 function serialize($debug = 0)
\r
4297 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
\r
4298 $xml .= "\n<definitions";
\r
4299 foreach($this->namespaces as $k => $v) {
\r
4300 $xml .= " xmlns:$k=\"$v\"";
\r
4302 // 10.9.02 - add poulter fix for wsdl and tns declarations
\r
4303 if (isset($this->namespaces['wsdl'])) {
\r
4304 $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
\r
4306 if (isset($this->namespaces['tns'])) {
\r
4307 $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
\r
4311 if (sizeof($this->import) > 0) {
\r
4312 foreach($this->import as $ns => $list) {
\r
4313 foreach ($list as $ii) {
\r
4314 if ($ii['location'] != '') {
\r
4315 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
\r
4317 $xml .= '<import namespace="' . $ns . '" />';
\r
4323 if (count($this->schemas)>=1) {
\r
4324 $xml .= "\n<types>\n";
\r
4325 foreach ($this->schemas as $ns => $list) {
\r
4326 foreach ($list as $xs) {
\r
4327 $xml .= $xs->serializeSchema();
\r
4330 $xml .= '</types>';
\r
4333 if (count($this->messages) >= 1) {
\r
4334 foreach($this->messages as $msgName => $msgParts) {
\r
4335 $xml .= "\n<message name=\"" . $msgName . '">';
\r
4336 if(is_array($msgParts)){
\r
4337 foreach($msgParts as $partName => $partType) {
\r
4338 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
\r
4339 if (strpos($partType, ':')) {
\r
4340 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
\r
4341 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
\r
4342 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
\r
4343 $typePrefix = 'xsd';
\r
4345 foreach($this->typemap as $ns => $types) {
\r
4346 if (isset($types[$partType])) {
\r
4347 $typePrefix = $this->getPrefixFromNamespace($ns);
\r
4350 if (!isset($typePrefix)) {
\r
4351 die("$partType has no namespace!");
\r
4354 $ns = $this->getNamespaceFromPrefix($typePrefix);
\r
4355 $localPart = $this->getLocalPart($partType);
\r
4356 $typeDef = $this->getTypeDef($localPart, $ns);
\r
4357 if ($typeDef['typeClass'] == 'element') {
\r
4358 $elementortype = 'element';
\r
4359 if (substr($localPart, -1) == '^') {
\r
4360 $localPart = substr($localPart, 0, -1);
\r
4363 $elementortype = 'type';
\r
4365 $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
\r
4368 $xml .= '</message>';
\r
4371 // bindings & porttypes
\r
4372 if (count($this->bindings) >= 1) {
\r
4373 $binding_xml = '';
\r
4374 $portType_xml = '';
\r
4375 foreach($this->bindings as $bindingName => $attrs) {
\r
4376 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
\r
4377 $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
\r
4378 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
\r
4379 foreach($attrs['operations'] as $opName => $opParts) {
\r
4380 $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
\r
4381 $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
\r
4382 if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
\r
4383 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
\r
4387 $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
\r
4388 if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
\r
4389 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
\r
4393 $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
\r
4394 $binding_xml .= "\n" . ' </operation>';
\r
4395 $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
\r
4396 if (isset($opParts['parameterOrder'])) {
\r
4397 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
\r
4399 $portType_xml .= '>';
\r
4400 if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
\r
4401 $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
\r
4403 $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
\r
4404 $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
\r
4405 $portType_xml .= "\n" . ' </operation>';
\r
4407 $portType_xml .= "\n" . '</portType>';
\r
4408 $binding_xml .= "\n" . '</binding>';
\r
4410 $xml .= $portType_xml . $binding_xml;
\r
4413 $xml .= "\n<service name=\"" . $this->serviceName . '">';
\r
4414 if (count($this->ports) >= 1) {
\r
4415 foreach($this->ports as $pName => $attrs) {
\r
4416 $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
\r
4417 $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
\r
4418 $xml .= "\n" . ' </port>';
\r
4421 $xml .= "\n" . '</service>';
\r
4422 return $xml . "\n</definitions>";
\r
4426 * determine whether a set of parameters are unwrapped
\r
4427 * when they are expect to be wrapped, Microsoft-style.
\r
4429 * @param string $type the type (element name) of the wrapper
\r
4430 * @param array $parameters the parameter values for the SOAP call
\r
4431 * @return boolean whether they parameters are unwrapped (and should be wrapped)
\r
4434 function parametersMatchWrapped($type, &$parameters) {
\r
4435 $this->debug("in parametersMatchWrapped type=$type, parameters=");
\r
4436 $this->appendDebug($this->varDump($parameters));
\r
4438 // split type into namespace:unqualified-type
\r
4439 if (strpos($type, ':')) {
\r
4440 $uqType = substr($type, strrpos($type, ':') + 1);
\r
4441 $ns = substr($type, 0, strrpos($type, ':'));
\r
4442 $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
\r
4443 if ($this->getNamespaceFromPrefix($ns)) {
\r
4444 $ns = $this->getNamespaceFromPrefix($ns);
\r
4445 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
\r
4448 // TODO: should the type be compared to types in XSD, and the namespace
\r
4449 // set to XSD if the type matches?
\r
4450 $this->debug("in parametersMatchWrapped: No namespace for type $type");
\r
4455 // get the type information
\r
4456 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
\r
4457 $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
\r
4460 $this->debug("in parametersMatchWrapped: found typeDef=");
\r
4461 $this->appendDebug($this->varDump($typeDef));
\r
4462 if (substr($uqType, -1) == '^') {
\r
4463 $uqType = substr($uqType, 0, -1);
\r
4465 $phpType = $typeDef['phpType'];
\r
4466 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
\r
4467 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
\r
4469 // we expect a complexType or element of complexType
\r
4470 if ($phpType != 'struct') {
\r
4471 $this->debug("in parametersMatchWrapped: not a struct");
\r
4475 // see whether the parameter names match the elements
\r
4476 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
\r
4480 if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
\r
4481 $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
\r
4484 foreach ($typeDef['elements'] as $name => $attrs) {
\r
4486 $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
\r
4487 $parameters[$name] = $parameters[$elements];
\r
4488 unset($parameters[$elements]);
\r
4490 } elseif (isset($parameters[$name])) {
\r
4491 $this->debug("in parametersMatchWrapped: have parameter named $name");
\r
4494 $this->debug("in parametersMatchWrapped: do not have parameter named $name");
\r
4499 $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
\r
4500 if ($matches == 0) {
\r
4506 // since there are no elements for the type, if the user passed no
\r
4507 // parameters, the parameters match wrapped.
\r
4508 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
\r
4509 return count($parameters) == 0;
\r
4513 * serialize PHP values according to a WSDL message definition
\r
4514 * contrary to the method name, this is not limited to RPC
\r
4517 * - multi-ref serialization
\r
4518 * - validate PHP values against type definitions, return errors if invalid
\r
4520 * @param string $operation operation name
\r
4521 * @param string $direction (input|output)
\r
4522 * @param mixed $parameters parameter value(s)
\r
4523 * @param string $bindingType (soap|soap12)
\r
4524 * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
\r
4527 function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
\r
4528 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
\r
4530 //echo "in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"."<br/>";
\r
4531 //print_r($parameters);
\r
4534 $this->appendDebug('parameters=' . $this->varDump($parameters));
\r
4536 if ($direction != 'input' && $direction != 'output') {
\r
4537 $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
\r
4538 $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
\r
4541 if (!$opData = $this->getOperationData($operation, $bindingType)) {
\r
4542 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
\r
4543 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
\r
4546 $this->debug('in serializeRPCParameters: opData:');
\r
4547 $this->appendDebug($this->varDump($opData));
\r
4549 // Get encoding style for output and set to current
\r
4550 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
\r
4551 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
\r
4552 $encodingStyle = $opData['output']['encodingStyle'];
\r
4553 $enc_style = $encodingStyle;
\r
4556 // set input params
\r
4558 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
\r
4559 $parts = &$opData[$direction]['parts'];
\r
4560 $part_count = sizeof($parts);
\r
4561 $style = $opData['style'];
\r
4562 $use = $opData[$direction]['use'];
\r
4563 $this->debug("have $part_count part(s) to serialize using $style/$use");
\r
4564 if (is_array($parameters)) {
\r
4565 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
\r
4566 $parameter_count = count($parameters);
\r
4567 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
\r
4568 // check for Microsoft-style wrapped parameters
\r
4569 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
\r
4570 $this->debug('check whether the caller has wrapped the parameters');
\r
4571 if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
\r
4572 $this->debug('check whether caller\'s parameters match the wrapped ones');
\r
4573 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
\r
4574 $this->debug('wrap the parameters for the caller');
\r
4575 $parameters = array('parameters' => $parameters);
\r
4576 $parameter_count = 1;
\r
4580 foreach ($parts as $name => $type) {
\r
4581 //echo "serializing part $name of type $type"."<br/>";
\r
4582 $this->debug("serializing part $name of type $type");
\r
4583 // Track encoding style
\r
4584 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
\r
4585 $encodingStyle = $opData[$direction]['encodingStyle'];
\r
4586 $enc_style = $encodingStyle;
\r
4588 $enc_style = false;
\r
4590 // NOTE: add error handling here
\r
4591 // if serializeType returns false, then catch global error and fault
\r
4592 if ($parametersArrayType == 'arraySimple') {
\r
4593 //echo "arraySimple<br/>";
\r
4594 $p = array_shift($parameters);
\r
4595 $this->debug('calling serializeType w/indexed param');
\r
4596 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
\r
4597 } elseif (isset($parameters[$name])) {
\r
4598 //echo "array SECOND<br/>";
\r
4599 $this->debug('calling serializeType w/named param');
\r
4600 //echo "PARAMS: ";
\r
4601 //print_r ($parameters[$name]);
\r
4603 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
\r
4605 //echo "array THIRD<br/>";
\r
4606 // TODO: only send nillable
\r
4607 $this->debug('calling serializeType w/null param');
\r
4608 //echo "PARAMS: ";
\r
4609 //print_r ($parameters);
\r
4611 //For some reason this does not work!! I am heavily (!) thinking about WHY the params here
\r
4612 //are passed as NULL?! What should be the resulting XML if you pass NULL as paramlist?!?!?
\r
4613 //seba.wagner at gmail dot com 2008/05/12
\r
4614 //$xml .= $this->serializeType($name, $type, null, $use, $enc_style);
\r
4615 $xml .= $this->serializeLinuxAxis2Type($name, $type, $parameters, $use, $enc_style);
\r
4617 //echo "PART XML: ".htmlentities($xml)."<br/>";
\r
4620 $this->debug('no parameters passed.');
\r
4623 $this->debug("serializeRPCParameters returning: $xml");
\r
4624 //echo "<br/>"."serializeRPCParameters returning: ".htmlentities($xml)."<BR/>";
\r
4629 * serialize a PHP value according to a WSDL message definition
\r
4632 * - multi-ref serialization
\r
4633 * - validate PHP values against type definitions, return errors if invalid
\r
4635 * @param string $operation operation name
\r
4636 * @param string $direction (input|output)
\r
4637 * @param mixed $parameters parameter value(s)
\r
4638 * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
\r
4642 function serializeParameters($operation, $direction, $parameters)
\r
4644 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
\r
4645 $this->appendDebug('parameters=' . $this->varDump($parameters));
\r
4647 if ($direction != 'input' && $direction != 'output') {
\r
4648 $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
\r
4649 $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
\r
4652 if (!$opData = $this->getOperationData($operation)) {
\r
4653 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
\r
4654 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
\r
4657 $this->debug('opData:');
\r
4658 $this->appendDebug($this->varDump($opData));
\r
4660 // Get encoding style for output and set to current
\r
4661 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
\r
4662 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
\r
4663 $encodingStyle = $opData['output']['encodingStyle'];
\r
4664 $enc_style = $encodingStyle;
\r
4667 // set input params
\r
4669 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
\r
4671 $use = $opData[$direction]['use'];
\r
4672 $this->debug("use=$use");
\r
4673 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
\r
4674 if (is_array($parameters)) {
\r
4675 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
\r
4676 $this->debug('have ' . $parametersArrayType . ' parameters');
\r
4677 foreach($opData[$direction]['parts'] as $name => $type) {
\r
4678 $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
\r
4679 // Track encoding style
\r
4680 if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
\r
4681 $encodingStyle = $opData[$direction]['encodingStyle'];
\r
4682 $enc_style = $encodingStyle;
\r
4684 $enc_style = false;
\r
4686 // NOTE: add error handling here
\r
4687 // if serializeType returns false, then catch global error and fault
\r
4688 if ($parametersArrayType == 'arraySimple') {
\r
4689 $p = array_shift($parameters);
\r
4690 $this->debug('calling serializeType w/indexed param');
\r
4691 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
\r
4692 } elseif (isset($parameters[$name])) {
\r
4693 $this->debug('calling serializeType w/named param');
\r
4694 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
\r
4696 // TODO: only send nillable
\r
4697 $this->debug('calling serializeType w/null param');
\r
4698 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
\r
4702 $this->debug('no parameters passed.');
\r
4705 $this->debug("serializeParameters returning: $xml");
\r
4709 function serializeLinuxAxis2Type($name, $type, $params, $use='encoded', $encodingStyle=false, $unqualified=false)
\r
4712 if (strpos($type, ':')) {
\r
4713 $uqType = substr($type, strrpos($type, ':') + 1);
\r
4714 $ns = substr($type, 0, strrpos($type, ':'));
\r
4715 $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
\r
4716 if ($this->getNamespaceFromPrefix($ns)) {
\r
4717 $ns = $this->getNamespaceFromPrefix($ns);
\r
4718 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
\r
4721 //echo "NameSpace: ".$ns."<br/>";
\r
4722 //echo "Method: ".$uqType."<br/>";
\r
4723 $methodName = substr($uqType,0,strlen($uqType)-1);
\r
4725 //echo "Method: ".$methodName."<br/>";
\r
4727 $xml .= '<'.$methodName.' xmlns="'.$ns.'">';
\r
4729 foreach ($params as $key => $val){
\r
4730 //echo "Key".$key." Value".$val."<br/>";
\r
4732 $insertVal = $val;
\r
4734 //If Boolean rewrite the Value
\r
4735 if (is_bool($val)){
\r
4737 $insertVal = "true";
\r
4739 $insertVal = "false";
\r
4742 $xml .= '<'.$key.'>'.$insertVal.'</'.$key.'>';
\r
4745 $xml .= '</'.$methodName.'>';
\r
4747 //echo htmlentities($xml)."<br/>";
\r
4749 //<loginUser xmlns="http://services.axis.openmeetings.org">
\r
4754 * serializes a PHP value according a given type definition
\r
4756 * @param string $name name of value (part or element)
\r
4757 * @param string $type XML schema type of value (type or element)
\r
4758 * @param mixed $value a native PHP value (parameter value)
\r
4759 * @param string $use use for part (encoded|literal)
\r
4760 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
\r
4761 * @param boolean $unqualified a kludge for what should be XML namespace form handling
\r
4762 * @return string value serialized as an XML string
\r
4765 function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
\r
4767 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
\r
4768 //echo "in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")."<br/>";
\r
4770 //echo "SerialieType: ".$type."<br/>";
\r
4772 $this->appendDebug("value=" . $this->varDump($value));
\r
4773 if($use == 'encoded' && $encodingStyle) {
\r
4774 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
\r
4777 // if a soapval has been supplied, let its type override the WSDL
\r
4778 if (is_object($value) && get_class($value) == 'soapval') {
\r
4779 ////echo "IS OBJECT "."<br/>";
\r
4780 if ($value->type_ns) {
\r
4781 $type = $value->type_ns . ':' . $value->type;
\r
4782 $forceType = true;
\r
4783 $this->debug("in serializeType: soapval overrides type to $type");
\r
4784 } elseif ($value->type) {
\r
4785 $type = $value->type;
\r
4786 $forceType = true;
\r
4787 $this->debug("in serializeType: soapval overrides type to $type");
\r
4789 $forceType = false;
\r
4790 $this->debug("in serializeType: soapval does not override type");
\r
4792 $attrs = $value->attributes;
\r
4793 $value = $value->value;
\r
4794 $this->debug("in serializeType: soapval overrides value to $value");
\r
4796 if (!is_array($value)) {
\r
4797 $value['!'] = $value;
\r
4799 foreach ($attrs as $n => $v) {
\r
4800 $value['!' . $n] = $v;
\r
4802 $this->debug("in serializeType: soapval provides attributes");
\r
4805 $forceType = false;
\r
4809 if (strpos($type, ':')) {
\r
4810 $uqType = substr($type, strrpos($type, ':') + 1);
\r
4812 //echo "FIRST ### uqType: ".$uqType."<br/>";
\r
4814 $ns = substr($type, 0, strrpos($type, ':'));
\r
4815 $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
\r
4816 if ($this->getNamespaceFromPrefix($ns)) {
\r
4817 $ns = $this->getNamespaceFromPrefix($ns);
\r
4818 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
\r
4821 //echo "NameSpace: ".$ns."<br/>";
\r
4822 if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
\r
4823 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
\r
4824 if ($unqualified && $use == 'literal') {
\r
4825 $elementNS = " xmlns=\"\"";
\r
4829 if (is_null($value)) {
\r
4830 if ($use == 'literal') {
\r
4831 // TODO: depends on minOccurs
\r
4832 $xml = "<$name$elementNS/>";
\r
4834 // TODO: depends on nillable, which should be checked before calling this method
\r
4835 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
\r
4837 $this->debug("in serializeType: returning: $xml");
\r
4840 //echo "uqType: ".$uqType."<br/>";
\r
4841 if ($uqType == 'Array') {
\r
4842 // JBoss/Axis does this sometimes
\r
4843 return $this->serialize_val($value, $name, false, false, false, false, $use);
\r
4845 if ($uqType == 'boolean') {
\r
4846 if ((is_string($value) && $value == 'false') || (! $value)) {
\r
4852 if ($uqType == 'string' && gettype($value) == 'string') {
\r
4853 $value = $this->expandEntities($value);
\r
4855 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
\r
4856 $value = sprintf("%.0lf", $value);
\r
4859 // TODO: what about null/nil values?
\r
4860 // check type isn't a custom type extending xmlschema namespace
\r
4861 if (!$this->getTypeDef($uqType, $ns)) {
\r
4862 if ($use == 'literal') {
\r
4864 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
\r
4866 $xml = "<$name$elementNS>$value</$name>";
\r
4869 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
\r
4871 $this->debug("in serializeType: returning: $xml");
\r
4874 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
\r
4875 } else if ($ns == 'http://xml.apache.org/xml-soap') {
\r
4876 $this->debug('in serializeType: appears to be Apache SOAP type');
\r
4877 if ($uqType == 'Map') {
\r
4878 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
\r
4879 if (! $tt_prefix) {
\r
4880 $this->debug('in serializeType: Add namespace for Apache SOAP type');
\r
4881 $tt_prefix = 'ns' . rand(1000, 9999);
\r
4882 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
\r
4883 // force this to be added to usedNamespaces
\r
4884 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
\r
4887 foreach($value as $k => $v) {
\r
4888 $this->debug("serializing map element: key $k, value $v");
\r
4889 $contents .= '<item>';
\r
4890 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
\r
4891 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
\r
4892 $contents .= '</item>';
\r
4894 if ($use == 'literal') {
\r
4896 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
\r
4898 $xml = "<$name>$contents</$name>";
\r
4901 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
\r
4903 $this->debug("in serializeType: returning: $xml");
\r
4906 $this->debug('in serializeType: Apache SOAP type, but only support Map');
\r
4909 // TODO: should the type be compared to types in XSD, and the namespace
\r
4910 // set to XSD if the type matches?
\r
4911 $this->debug("in serializeType: No namespace for type $type");
\r
4915 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
\r
4916 $this->setError("$type ($uqType) is not a supported type.");
\r
4917 $this->debug("in serializeType: $type ($uqType) is not a supported type.");
\r
4920 $this->debug("in serializeType: found typeDef");
\r
4921 $this->appendDebug('typeDef=' . $this->varDump($typeDef));
\r
4922 if (substr($uqType, -1) == '^') {
\r
4923 $uqType = substr($uqType, 0, -1);
\r
4926 $phpType = $typeDef['phpType'];
\r
4927 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
\r
4928 // if php type == struct, map value to the <all> element names
\r
4929 if ($phpType == 'struct') {
\r
4930 if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
\r
4931 $elementName = $uqType;
\r
4932 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
\r
4933 $elementNS = " xmlns=\"$ns\"";
\r
4935 $elementNS = " xmlns=\"\"";
\r
4938 $elementName = $name;
\r
4939 if ($unqualified) {
\r
4940 $elementNS = " xmlns=\"\"";
\r
4945 if (is_null($value)) {
\r
4946 if ($use == 'literal') {
\r
4947 // TODO: depends on minOccurs
\r
4948 $xml = "<$elementName$elementNS/>";
\r
4950 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
\r
4952 $this->debug("in serializeType: returning: $xml");
\r
4955 if (is_object($value)) {
\r
4956 $value = get_object_vars($value);
\r
4958 if (is_array($value)) {
\r
4959 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
\r
4960 if ($use == 'literal') {
\r
4962 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
\r
4964 $xml = "<$elementName$elementNS$elementAttrs>";
\r
4967 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
\r
4970 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
\r
4971 $xml .= "</$elementName>";
\r
4973 $this->debug("in serializeType: phpType is struct, but value is not an array");
\r
4974 $this->setError("phpType is struct, but value is not an array: see debug output for details");
\r
4977 } elseif ($phpType == 'array') {
\r
4978 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
\r
4979 $elementNS = " xmlns=\"$ns\"";
\r
4981 if ($unqualified) {
\r
4982 $elementNS = " xmlns=\"\"";
\r
4987 if (is_null($value)) {
\r
4988 if ($use == 'literal') {
\r
4989 // TODO: depends on minOccurs
\r
4990 $xml = "<$name$elementNS/>";
\r
4992 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
\r
4993 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
\r
4995 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
\r
4997 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
\r
4999 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
\r
5001 $this->debug("in serializeType: returning: $xml");
\r
5004 if (isset($typeDef['multidimensional'])) {
\r
5006 foreach($value as $v) {
\r
5007 $cols = ',' . sizeof($v);
\r
5008 $nv = array_merge($nv, $v);
\r
5014 if (is_array($value) && sizeof($value) >= 1) {
\r
5015 ////echo "IS ARRAY !! ".sizeof($value)."<br/>";
\r
5016 $rows = sizeof($value);
\r
5018 foreach($value as $k => $v) {
\r
5020 ////echo $k." => ".$v."<br/>";
\r
5022 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
\r
5023 //if (strpos($typeDef['arrayType'], ':') ) {
\r
5024 if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
\r
5025 //echo "CALL AGAIN HEHRERERERER ########### <br/>";
\r
5026 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
\r
5028 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
\r
5035 // TODO: for now, an empty value will be serialized as a zero element
\r
5036 // array. Revisit this when coding the handling of null/nil values.
\r
5037 if ($use == 'literal') {
\r
5038 $xml = "<$name$elementNS>"
\r
5042 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
\r
5043 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
\r
5045 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
\r
5046 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
\r
5050 } elseif ($phpType == 'scalar') {
\r
5051 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
\r
5052 $elementNS = " xmlns=\"$ns\"";
\r
5054 if ($unqualified) {
\r
5055 $elementNS = " xmlns=\"\"";
\r
5060 if ($use == 'literal') {
\r
5062 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
\r
5064 $xml = "<$name$elementNS>$value</$name>";
\r
5067 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
\r
5070 $this->debug("in serializeType: returning: $xml");
\r
5075 * serializes the attributes for a complexType
\r
5077 * @param array $typeDef our internal representation of an XML schema type (or element)
\r
5078 * @param mixed $value a native PHP value (parameter value)
\r
5079 * @param string $ns the namespace of the type
\r
5080 * @param string $uqType the local part of the type
\r
5081 * @return string value serialized as an XML string
\r
5084 function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
\r
5086 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
\r
5087 $this->debug("serialize attributes for XML Schema type $ns:$uqType");
\r
5088 if (is_array($value)) {
\r
5090 } elseif (is_object($value)) {
\r
5091 $xvalue = get_object_vars($value);
\r
5093 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
\r
5094 $xvalue = array();
\r
5096 foreach ($typeDef['attrs'] as $aName => $attrs) {
\r
5097 if (isset($xvalue['!' . $aName])) {
\r
5098 $xname = '!' . $aName;
\r
5099 $this->debug("value provided for attribute $aName with key $xname");
\r
5100 } elseif (isset($xvalue[$aName])) {
\r
5102 $this->debug("value provided for attribute $aName with key $xname");
\r
5103 } elseif (isset($attrs['default'])) {
\r
5104 $xname = '!' . $aName;
\r
5105 $xvalue[$xname] = $attrs['default'];
\r
5106 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
\r
5109 $this->debug("no value provided for attribute $aName");
\r
5112 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
\r
5116 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
\r
5118 if (isset($typeDef['extensionBase'])) {
\r
5119 $ns = $this->getPrefix($typeDef['extensionBase']);
\r
5120 $uqType = $this->getLocalPart($typeDef['extensionBase']);
\r
5121 if ($this->getNamespaceFromPrefix($ns)) {
\r
5122 $ns = $this->getNamespaceFromPrefix($ns);
\r
5124 if ($typeDef = $this->getTypeDef($uqType, $ns)) {
\r
5125 $this->debug("serialize attributes for extension base $ns:$uqType");
\r
5126 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
\r
5128 $this->debug("extension base $ns:$uqType is not a supported type");
\r
5135 * serializes the elements for a complexType
\r
5137 * @param array $typeDef our internal representation of an XML schema type (or element)
\r
5138 * @param mixed $value a native PHP value (parameter value)
\r
5139 * @param string $ns the namespace of the type
\r
5140 * @param string $uqType the local part of the type
\r
5141 * @param string $use use for part (encoded|literal)
\r
5142 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
\r
5143 * @return string value serialized as an XML string
\r
5146 function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
\r
5148 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
\r
5149 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
\r
5150 if (is_array($value)) {
\r
5152 } elseif (is_object($value)) {
\r
5153 $xvalue = get_object_vars($value);
\r
5155 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
\r
5156 $xvalue = array();
\r
5158 // toggle whether all elements are present - ideally should validate against schema
\r
5159 if (count($typeDef['elements']) != count($xvalue)){
\r
5160 $optionals = true;
\r
5162 foreach ($typeDef['elements'] as $eName => $attrs) {
\r
5163 if (!isset($xvalue[$eName])) {
\r
5164 if (isset($attrs['default'])) {
\r
5165 $xvalue[$eName] = $attrs['default'];
\r
5166 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
\r
5169 // if user took advantage of a minOccurs=0, then only serialize named parameters
\r
5170 if (isset($optionals)
\r
5171 && (!isset($xvalue[$eName]))
\r
5172 && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
\r
5174 if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
\r
5175 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
\r
5178 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
\r
5181 if (isset($xvalue[$eName])) {
\r
5182 $v = $xvalue[$eName];
\r
5186 if (isset($attrs['form'])) {
\r
5187 $unqualified = ($attrs['form'] == 'unqualified');
\r
5189 $unqualified = false;
\r
5191 if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
\r
5193 foreach ($vv as $k => $v) {
\r
5194 if (isset($attrs['type']) || isset($attrs['ref'])) {
\r
5195 // serialize schema-defined type
\r
5196 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
\r
5198 // serialize generic type (can this ever really happen?)
\r
5199 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
\r
5200 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
\r
5204 if (isset($attrs['type']) || isset($attrs['ref'])) {
\r
5205 // serialize schema-defined type
\r
5206 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
\r
5208 // serialize generic type (can this ever really happen?)
\r
5209 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
\r
5210 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
\r
5216 $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
\r
5218 if (isset($typeDef['extensionBase'])) {
\r
5219 $ns = $this->getPrefix($typeDef['extensionBase']);
\r
5220 $uqType = $this->getLocalPart($typeDef['extensionBase']);
\r
5221 if ($this->getNamespaceFromPrefix($ns)) {
\r
5222 $ns = $this->getNamespaceFromPrefix($ns);
\r
5224 if ($typeDef = $this->getTypeDef($uqType, $ns)) {
\r
5225 $this->debug("serialize elements for extension base $ns:$uqType");
\r
5226 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
\r
5228 $this->debug("extension base $ns:$uqType is not a supported type");
\r
5235 * adds an XML Schema complex type to the WSDL types
\r
5237 * @param string $name
\r
5238 * @param string $typeClass (complexType|simpleType|attribute)
\r
5239 * @param string $phpType currently supported are array and struct (php assoc array)
\r
5240 * @param string $compositor (all|sequence|choice)
\r
5241 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
\r
5242 * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
\r
5243 * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
\r
5244 * @param string $arrayType as namespace:name (xsd:string)
\r
5245 * @see nusoap_xmlschema
\r
5248 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
\r
5249 if (count($elements) > 0) {
\r
5250 $eElements = array();
\r
5251 foreach($elements as $n => $e){
\r
5252 // expand each element
\r
5254 foreach ($e as $k => $v) {
\r
5255 $k = strpos($k,':') ? $this->expandQname($k) : $k;
\r
5256 $v = strpos($v,':') ? $this->expandQname($v) : $v;
\r
5259 $eElements[$n] = $ee;
\r
5261 $elements = $eElements;
\r
5264 if (count($attrs) > 0) {
\r
5265 foreach($attrs as $n => $a){
\r
5266 // expand each attribute
\r
5267 foreach ($a as $k => $v) {
\r
5268 $k = strpos($k,':') ? $this->expandQname($k) : $k;
\r
5269 $v = strpos($v,':') ? $this->expandQname($v) : $v;
\r
5272 $eAttrs[$n] = $aa;
\r
5277 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
\r
5278 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
\r
5280 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
\r
5281 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
\r
5285 * adds an XML Schema simple type to the WSDL types
\r
5287 * @param string $name
\r
5288 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
\r
5289 * @param string $typeClass (should always be simpleType)
\r
5290 * @param string $phpType (should always be scalar)
\r
5291 * @param array $enumeration array of values
\r
5292 * @see nusoap_xmlschema
\r
5295 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
\r
5296 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
\r
5298 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
\r
5299 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
\r
5303 * adds an element to the WSDL types
\r
5305 * @param array $attrs attributes that must include name and type
\r
5306 * @see nusoap_xmlschema
\r
5309 function addElement($attrs) {
\r
5310 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
\r
5311 $this->schemas[$typens][0]->addElement($attrs);
\r
5315 * register an operation with the server
\r
5317 * @param string $name operation (method) name
\r
5318 * @param array $in assoc array of input values: key = param name, value = param type
\r
5319 * @param array $out assoc array of output values: key = param name, value = param type
\r
5320 * @param string $namespace optional The namespace for the operation
\r
5321 * @param string $soapaction optional The soapaction for the operation
\r
5322 * @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
\r
5323 * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
\r
5324 * @param string $documentation optional The description to include in the WSDL
\r
5325 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
\r
5328 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
\r
5329 if ($use == 'encoded' && $encodingStyle == '') {
\r
5330 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
\r
5333 if ($style == 'document') {
\r
5334 $elements = array();
\r
5335 foreach ($in as $n => $t) {
\r
5336 $elements[$n] = array('name' => $n, 'type' => $t);
\r
5338 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
\r
5339 $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
\r
5340 $in = array('parameters' => 'tns:' . $name . '^');
\r
5342 $elements = array();
\r
5343 foreach ($out as $n => $t) {
\r
5344 $elements[$n] = array('name' => $n, 'type' => $t);
\r
5346 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
\r
5347 $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
\r
5348 $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
\r
5352 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
\r
5355 'binding' => $this->serviceName . 'Binding',
\r
5356 'endpoint' => $this->endpoint,
\r
5357 'soapAction' => $soapaction,
\r
5358 'style' => $style,
\r
5361 'namespace' => $namespace,
\r
5362 'encodingStyle' => $encodingStyle,
\r
5363 'message' => $name . 'Request',
\r
5365 'output' => array(
\r
5367 'namespace' => $namespace,
\r
5368 'encodingStyle' => $encodingStyle,
\r
5369 'message' => $name . 'Response',
\r
5371 'namespace' => $namespace,
\r
5372 'transport' => 'http://schemas.xmlsoap.org/soap/http',
\r
5373 'documentation' => $documentation);
\r
5378 foreach($in as $pName => $pType)
\r
5380 if(strpos($pType,':')) {
\r
5381 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
\r
5383 $this->messages[$name.'Request'][$pName] = $pType;
\r
5386 $this->messages[$name.'Request']= '0';
\r
5390 foreach($out as $pName => $pType)
\r
5392 if(strpos($pType,':')) {
\r
5393 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
\r
5395 $this->messages[$name.'Response'][$pName] = $pType;
\r
5398 $this->messages[$name.'Response']= '0';
\r
5409 * nusoap_parser class parses SOAP XML messages into native PHP values
\r
5411 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
5412 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
5413 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
5416 class nusoap_parser extends nusoap_base {
\r
5419 var $xml_encoding = '';
\r
5421 var $root_struct = '';
\r
5422 var $root_struct_name = '';
\r
5423 var $root_struct_namespace = '';
\r
5424 var $root_header = '';
\r
5425 var $document = ''; // incoming SOAP body (text)
\r
5426 // determines where in the message we are (envelope,header,body,method)
\r
5428 var $position = 0;
\r
5430 var $default_namespace = '';
\r
5431 var $namespaces = array();
\r
5432 var $message = array();
\r
5434 var $fault = false;
\r
5435 var $fault_code = '';
\r
5436 var $fault_str = '';
\r
5437 var $fault_detail = '';
\r
5438 var $depth_array = array();
\r
5439 var $debug_flag = true;
\r
5440 var $soapresponse = NULL; // parsed SOAP Body
\r
5441 var $soapheader = NULL; // parsed SOAP Header
\r
5442 var $responseHeaders = ''; // incoming SOAP headers (text)
\r
5443 var $body_position = 0;
\r
5444 // for multiref parsing:
\r
5445 // array of id => pos
\r
5446 var $ids = array();
\r
5447 // array of id => hrefs => pos
\r
5448 var $multirefs = array();
\r
5449 // toggle for auto-decoding element content
\r
5450 var $decode_utf8 = true;
\r
5453 * constructor that actually does the parsing
\r
5455 * @param string $xml SOAP message
\r
5456 * @param string $encoding character encoding scheme of message
\r
5457 * @param string $method method for which XML is parsed (unused?)
\r
5458 * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
\r
5461 function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
\r
5462 parent::nusoap_base();
\r
5463 $this->xml = $xml;
\r
5464 $this->xml_encoding = $encoding;
\r
5465 $this->method = $method;
\r
5466 $this->decode_utf8 = $decode_utf8;
\r
5468 // Check whether content has been read.
\r
5470 // Check XML encoding
\r
5471 $pos_xml = strpos($xml, '<?xml');
\r
5472 if ($pos_xml !== FALSE) {
\r
5473 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
\r
5474 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
\r
5475 $xml_encoding = $res[1];
\r
5476 if (strtoupper($xml_encoding) != $encoding) {
\r
5477 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
\r
5478 $this->debug($err);
\r
5479 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
\r
5480 $this->setError($err);
\r
5483 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
\r
5485 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
\r
5488 $this->debug('No encoding specified in XML declaration');
\r
5491 $this->debug('No XML declaration');
\r
5493 $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
\r
5494 // Create an XML parser - why not xml_parser_create_ns?
\r
5495 $this->parser = xml_parser_create($this->xml_encoding);
\r
5496 // Set the options for parsing the XML data.
\r
5497 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
\r
5498 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
\r
5499 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
\r
5500 // Set the object for the parser.
\r
5501 xml_set_object($this->parser, $this);
\r
5502 // Set the element handlers for the parser.
\r
5503 xml_set_element_handler($this->parser, 'start_element','end_element');
\r
5504 xml_set_character_data_handler($this->parser,'character_data');
\r
5506 // Parse the XML file.
\r
5507 if(!xml_parse($this->parser,$xml,true)){
\r
5508 // Display an error message.
\r
5509 $err = sprintf('XML error parsing SOAP payload on line %d: %s',
\r
5510 xml_get_current_line_number($this->parser),
\r
5511 xml_error_string(xml_get_error_code($this->parser)));
\r
5512 $this->debug($err);
\r
5513 $this->debug("XML payload:\n" . $xml);
\r
5514 $this->setError($err);
\r
5516 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
\r
5517 // get final value
\r
5518 $this->soapresponse = $this->message[$this->root_struct]['result'];
\r
5519 // get header value
\r
5520 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
\r
5521 $this->soapheader = $this->message[$this->root_header]['result'];
\r
5523 // resolve hrefs/ids
\r
5524 if(sizeof($this->multirefs) > 0){
\r
5525 foreach($this->multirefs as $id => $hrefs){
\r
5526 $this->debug('resolving multirefs for id: '.$id);
\r
5527 $idVal = $this->buildVal($this->ids[$id]);
\r
5528 if (is_array($idVal) && isset($idVal['!id'])) {
\r
5529 unset($idVal['!id']);
\r
5531 foreach($hrefs as $refPos => $ref){
\r
5532 $this->debug('resolving href at pos '.$refPos);
\r
5533 $this->multirefs[$id][$refPos] = $idVal;
\r
5538 xml_parser_free($this->parser);
\r
5540 $this->debug('xml was empty, didn\'t parse!');
\r
5541 $this->setError('xml was empty, didn\'t parse!');
\r
5546 * start-element handler
\r
5548 * @param resource $parser XML parser object
\r
5549 * @param string $name element name
\r
5550 * @param array $attrs associative array of attributes
\r
5553 function start_element($parser, $name, $attrs) {
\r
5554 // position in a total number of elements, starting from 0
\r
5555 // update class level pos
\r
5556 $pos = $this->position++;
\r
5558 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
\r
5559 // depth = how many levels removed from root?
\r
5560 // set mine as current global depth and increment global depth value
\r
5561 $this->message[$pos]['depth'] = $this->depth++;
\r
5563 // else add self as child to whoever the current parent is
\r
5565 $this->message[$this->parent]['children'] .= '|'.$pos;
\r
5568 $this->message[$pos]['parent'] = $this->parent;
\r
5569 // set self as current parent
\r
5570 $this->parent = $pos;
\r
5571 // set self as current value for this depth
\r
5572 $this->depth_array[$this->depth] = $pos;
\r
5573 // get element prefix
\r
5574 if(strpos($name,':')){
\r
5576 $prefix = substr($name,0,strpos($name,':'));
\r
5577 // get unqualified name
\r
5578 $name = substr(strstr($name,':'),1);
\r
5581 if($name == 'Envelope'){
\r
5582 $this->status = 'envelope';
\r
5583 } elseif($name == 'Header' && $this->status = 'envelope'){
\r
5584 $this->root_header = $pos;
\r
5585 $this->status = 'header';
\r
5586 } elseif($name == 'Body' && $this->status = 'envelope'){
\r
5587 $this->status = 'body';
\r
5588 $this->body_position = $pos;
\r
5590 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
\r
5591 $this->status = 'method';
\r
5592 $this->root_struct_name = $name;
\r
5593 $this->root_struct = $pos;
\r
5594 $this->message[$pos]['type'] = 'struct';
\r
5595 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
\r
5598 $this->message[$pos]['status'] = $this->status;
\r
5600 $this->message[$pos]['name'] = htmlspecialchars($name);
\r
5602 $this->message[$pos]['attrs'] = $attrs;
\r
5604 // loop through atts, logging ns and type declarations
\r
5606 foreach($attrs as $key => $value){
\r
5607 $key_prefix = $this->getPrefix($key);
\r
5608 $key_localpart = $this->getLocalPart($key);
\r
5609 // if ns declarations, add to class level array of valid namespaces
\r
5610 if($key_prefix == 'xmlns'){
\r
5611 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
\r
5612 $this->XMLSchemaVersion = $value;
\r
5613 $this->namespaces['xsd'] = $this->XMLSchemaVersion;
\r
5614 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
\r
5616 $this->namespaces[$key_localpart] = $value;
\r
5617 // set method namespace
\r
5618 if($name == $this->root_struct_name){
\r
5619 $this->methodNamespace = $value;
\r
5621 // if it's a type declaration, set type
\r
5622 } elseif($key_localpart == 'type'){
\r
5623 if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
\r
5624 // do nothing: already processed arrayType
\r
5626 $value_prefix = $this->getPrefix($value);
\r
5627 $value_localpart = $this->getLocalPart($value);
\r
5628 $this->message[$pos]['type'] = $value_localpart;
\r
5629 $this->message[$pos]['typePrefix'] = $value_prefix;
\r
5630 if(isset($this->namespaces[$value_prefix])){
\r
5631 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
\r
5632 } else if(isset($attrs['xmlns:'.$value_prefix])) {
\r
5633 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
\r
5635 // should do something here with the namespace of specified type?
\r
5637 } elseif($key_localpart == 'arrayType'){
\r
5638 $this->message[$pos]['type'] = 'array';
\r
5639 /* do arrayType ereg here
\r
5640 [1] arrayTypeValue ::= atype asize
\r
5641 [2] atype ::= QName rank*
\r
5642 [3] rank ::= '[' (',')* ']'
\r
5643 [4] asize ::= '[' length~ ']'
\r
5644 [5] length ::= nextDimension* Digit+
\r
5645 [6] nextDimension ::= Digit+ ','
\r
5647 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
\r
5648 if(ereg($expr,$value,$regs)){
\r
5649 $this->message[$pos]['typePrefix'] = $regs[1];
\r
5650 $this->message[$pos]['arrayTypePrefix'] = $regs[1];
\r
5651 if (isset($this->namespaces[$regs[1]])) {
\r
5652 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
\r
5653 } else if (isset($attrs['xmlns:'.$regs[1]])) {
\r
5654 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
\r
5656 $this->message[$pos]['arrayType'] = $regs[2];
\r
5657 $this->message[$pos]['arraySize'] = $regs[3];
\r
5658 $this->message[$pos]['arrayCols'] = $regs[4];
\r
5660 // specifies nil value (or not)
\r
5661 } elseif ($key_localpart == 'nil'){
\r
5662 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
\r
5663 // some other attribute
\r
5664 } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
\r
5665 $this->message[$pos]['xattrs']['!' . $key] = $value;
\r
5668 if ($key == 'xmlns') {
\r
5669 $this->default_namespace = $value;
\r
5673 $this->ids[$value] = $pos;
\r
5676 if($key_localpart == 'root' && $value == 1){
\r
5677 $this->status = 'method';
\r
5678 $this->root_struct_name = $name;
\r
5679 $this->root_struct = $pos;
\r
5680 $this->debug("found root struct $this->root_struct_name, pos $pos");
\r
5683 $attstr .= " $key=\"$value\"";
\r
5685 // get namespace - must be done after namespace atts are processed
\r
5686 if(isset($prefix)){
\r
5687 $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
\r
5688 $this->default_namespace = $this->namespaces[$prefix];
\r
5690 $this->message[$pos]['namespace'] = $this->default_namespace;
\r
5692 if($this->status == 'header'){
\r
5693 if ($this->root_header != $pos) {
\r
5694 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
\r
5696 } elseif($this->root_struct_name != ''){
\r
5697 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
\r
5702 * end-element handler
\r
5704 * @param resource $parser XML parser object
\r
5705 * @param string $name element name
\r
5708 function end_element($parser, $name) {
\r
5709 // position of current element is equal to the last value left in depth_array for my depth
\r
5710 $pos = $this->depth_array[$this->depth--];
\r
5712 // get element prefix
\r
5713 if(strpos($name,':')){
\r
5715 $prefix = substr($name,0,strpos($name,':'));
\r
5716 // get unqualified name
\r
5717 $name = substr(strstr($name,':'),1);
\r
5720 // build to native type
\r
5721 if(isset($this->body_position) && $pos > $this->body_position){
\r
5722 // deal w/ multirefs
\r
5723 if(isset($this->message[$pos]['attrs']['href'])){
\r
5725 $id = substr($this->message[$pos]['attrs']['href'],1);
\r
5726 // add placeholder to href array
\r
5727 $this->multirefs[$id][$pos] = 'placeholder';
\r
5728 // add set a reference to it as the result value
\r
5729 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
\r
5730 // build complexType values
\r
5731 } elseif($this->message[$pos]['children'] != ''){
\r
5732 // if result has already been generated (struct/array)
\r
5733 if(!isset($this->message[$pos]['result'])){
\r
5734 $this->message[$pos]['result'] = $this->buildVal($pos);
\r
5736 // build complexType values of attributes and possibly simpleContent
\r
5737 } elseif (isset($this->message[$pos]['xattrs'])) {
\r
5738 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
\r
5739 $this->message[$pos]['xattrs']['!'] = null;
\r
5740 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
\r
5741 if (isset($this->message[$pos]['type'])) {
\r
5742 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
\r
5744 $parent = $this->message[$pos]['parent'];
\r
5745 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
\r
5746 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
\r
5748 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
\r
5752 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
\r
5753 // set value of simpleType (or nil complexType)
\r
5755 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
\r
5756 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
\r
5757 $this->message[$pos]['xattrs']['!'] = null;
\r
5758 } elseif (isset($this->message[$pos]['type'])) {
\r
5759 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
\r
5761 $parent = $this->message[$pos]['parent'];
\r
5762 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
\r
5763 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
\r
5765 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
\r
5769 /* add value to parent's result, if parent is struct/array
\r
5770 $parent = $this->message[$pos]['parent'];
\r
5771 if($this->message[$parent]['type'] != 'map'){
\r
5772 if(strtolower($this->message[$parent]['type']) == 'array'){
\r
5773 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
\r
5775 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
\r
5783 if($this->status == 'header'){
\r
5784 if ($this->root_header != $pos) {
\r
5785 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
\r
5787 } elseif($pos >= $this->root_struct){
\r
5788 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
\r
5791 if($pos == $this->root_struct){
\r
5792 $this->status = 'body';
\r
5793 $this->root_struct_namespace = $this->message[$pos]['namespace'];
\r
5794 } elseif($name == 'Body'){
\r
5795 $this->status = 'envelope';
\r
5796 } elseif($name == 'Header'){
\r
5797 $this->status = 'envelope';
\r
5798 } elseif($name == 'Envelope'){
\r
5801 // set parent back to my parent
\r
5802 $this->parent = $this->message[$pos]['parent'];
\r
5806 * element content handler
\r
5808 * @param resource $parser XML parser object
\r
5809 * @param string $data element content
\r
5812 function character_data($parser, $data){
\r
5813 $pos = $this->depth_array[$this->depth];
\r
5814 if ($this->xml_encoding=='UTF-8'){
\r
5815 // TODO: add an option to disable this for folks who want
\r
5816 // raw UTF-8 that, e.g., might not map to iso-8859-1
\r
5817 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
\r
5818 if($this->decode_utf8){
\r
5819 $data = utf8_decode($data);
\r
5822 $this->message[$pos]['cdata'] .= $data;
\r
5824 if($this->status == 'header'){
\r
5825 $this->responseHeaders .= $data;
\r
5827 $this->document .= $data;
\r
5832 * get the parsed message (SOAP Body)
\r
5836 * @deprecated use get_soapbody instead
\r
5838 function get_response(){
\r
5839 return $this->soapresponse;
\r
5843 * get the parsed SOAP Body (NULL if there was none)
\r
5848 function get_soapbody(){
\r
5849 return $this->soapresponse;
\r
5853 * get the parsed SOAP Header (NULL if there was none)
\r
5858 function get_soapheader(){
\r
5859 return $this->soapheader;
\r
5863 * get the unparsed SOAP Header
\r
5865 * @return string XML or empty if no Header
\r
5868 function getHeaders(){
\r
5869 return $this->responseHeaders;
\r
5873 * decodes simple types into PHP variables
\r
5875 * @param string $value value to decode
\r
5876 * @param string $type XML type to decode
\r
5877 * @param string $typens XML type namespace to decode
\r
5878 * @return mixed PHP value
\r
5881 function decodeSimple($value, $type, $typens) {
\r
5882 // TODO: use the namespace!
\r
5883 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
\r
5884 return (string) $value;
\r
5886 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
\r
5887 return (int) $value;
\r
5889 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
\r
5890 return (double) $value;
\r
5892 if ($type == 'boolean') {
\r
5893 if (strtolower($value) == 'false' || strtolower($value) == 'f') {
\r
5896 return (boolean) $value;
\r
5898 if ($type == 'base64' || $type == 'base64Binary') {
\r
5899 $this->debug('Decode base64 value');
\r
5900 return base64_decode($value);
\r
5902 // obscure numeric types
\r
5903 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
\r
5904 || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
\r
5905 || $type == 'unsignedInt'
\r
5906 || $type == 'unsignedShort' || $type == 'unsignedByte') {
\r
5907 return (int) $value;
\r
5909 // bogus: parser treats array with no elements as a simple type
\r
5910 if ($type == 'array') {
\r
5913 // everything else
\r
5914 return (string) $value;
\r
5918 * builds response structures for compound values (arrays/structs)
\r
5921 * @param integer $pos position in node tree
\r
5922 * @return mixed PHP value
\r
5925 function buildVal($pos){
\r
5926 if(!isset($this->message[$pos]['type'])){
\r
5927 $this->message[$pos]['type'] = '';
\r
5929 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
\r
5930 // if there are children...
\r
5931 if($this->message[$pos]['children'] != ''){
\r
5932 $this->debug('in buildVal, there are children');
\r
5933 $children = explode('|',$this->message[$pos]['children']);
\r
5934 array_shift($children); // knock off empty
\r
5936 if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
\r
5939 foreach($children as $child_pos){
\r
5940 $this->debug("in buildVal, got an MD array element: $r, $c");
\r
5941 $params[$r][] = $this->message[$child_pos]['result'];
\r
5943 if($c == $this->message[$pos]['arrayCols']){
\r
5949 } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
\r
5950 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
\r
5951 foreach($children as $child_pos){
\r
5952 $params[] = &$this->message[$child_pos]['result'];
\r
5954 // apache Map type: java hashtable
\r
5955 } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
\r
5956 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
\r
5957 foreach($children as $child_pos){
\r
5958 $kv = explode("|",$this->message[$child_pos]['children']);
\r
5959 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
\r
5961 // generic compound type
\r
5962 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
\r
5964 // Apache Vector type: treat as an array
\r
5965 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
\r
5966 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
\r
5972 foreach($children as $child_pos){
\r
5974 $params[] = &$this->message[$child_pos]['result'];
\r
5976 if (isset($params[$this->message[$child_pos]['name']])) {
\r
5977 // de-serialize repeated element name into an array
\r
5978 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
\r
5979 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
\r
5981 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
\r
5983 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
\r
5988 if (isset($this->message[$pos]['xattrs'])) {
\r
5989 $this->debug('in buildVal, handling attributes');
\r
5990 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
\r
5994 // handle simpleContent
\r
5995 if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
\r
5996 $this->debug('in buildVal, handling simpleContent');
\r
5997 if (isset($this->message[$pos]['type'])) {
\r
5998 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
\r
6000 $parent = $this->message[$pos]['parent'];
\r
6001 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
\r
6002 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
\r
6004 $params['!'] = $this->message[$pos]['cdata'];
\r
6008 $ret = is_array($params) ? $params : array();
\r
6009 $this->debug('in buildVal, return:');
\r
6010 $this->appendDebug($this->varDump($ret));
\r
6013 $this->debug('in buildVal, no children, building scalar');
\r
6014 $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
\r
6015 if (isset($this->message[$pos]['type'])) {
\r
6016 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
\r
6017 $this->debug("in buildVal, return: $ret");
\r
6020 $parent = $this->message[$pos]['parent'];
\r
6021 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
\r
6022 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
\r
6023 $this->debug("in buildVal, return: $ret");
\r
6026 $ret = $this->message[$pos]['cdata'];
\r
6027 $this->debug("in buildVal, return: $ret");
\r
6034 * Backward compatibility
\r
6036 class soap_parser extends nusoap_parser {
\r
6045 * [nu]soapclient higher level class for easy usage.
\r
6049 * // instantiate client with server info
\r
6050 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
\r
6052 * // call method, get results
\r
6053 * //echo $soapclient->call( string methodname [ ,array parameters] );
\r
6055 * // bye bye client
\r
6056 * unset($soapclient);
\r
6058 * @author Dietrich Ayala <dietrich@ganx4.com>
\r
6059 * @author Scott Nichol <snichol@users.sourceforge.net>
\r
6060 * @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $
\r
6063 class nusoap_client extends nusoap_base {
\r
6065 var $username = ''; // Username for HTTP authentication
\r
6066 var $password = ''; // Password for HTTP authentication
\r
6067 var $authtype = ''; // Type of HTTP authentication
\r
6068 var $certRequest = array(); // Certificate for HTTP SSL authentication
\r
6069 var $requestHeaders = false; // SOAP headers in request (text)
\r
6070 var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
\r
6071 var $responseHeader = NULL; // SOAP Header from response (parsed)
\r
6072 var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
\r
6074 var $forceEndpoint = ''; // overrides WSDL endpoint
\r
6075 var $proxyhost = '';
\r
6076 var $proxyport = '';
\r
6077 var $proxyusername = '';
\r
6078 var $proxypassword = '';
\r
6079 var $xml_encoding = ''; // character set encoding of incoming (response) messages
\r
6080 var $http_encoding = false;
\r
6081 var $timeout = 0; // HTTP connection timeout
\r
6082 var $response_timeout = 30; // HTTP response timeout
\r
6083 var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
\r
6084 var $persistentConnection = false;
\r
6085 var $defaultRpcParams = false; // This is no longer used
\r
6086 var $request = ''; // HTTP request
\r
6087 var $response = ''; // HTTP response
\r
6088 var $responseData = ''; // SOAP payload of response
\r
6089 var $cookies = array(); // Cookies from response or for request
\r
6090 var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
\r
6091 var $operations = array(); // WSDL operations, empty for WSDL initialization error
\r
6092 var $curl_options = array(); // User-specified cURL options
\r
6093 var $bindingType = ''; // WSDL operation binding type
\r
6094 var $use_curl = false; // whether to always try to use cURL
\r
6097 * fault related variables
\r
6110 * @var faultstring
\r
6115 * @var faultdetail
\r
6123 * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
\r
6124 * @param bool $wsdl optional, set to true if using WSDL
\r
6125 * @param int $portName optional portName in WSDL document
\r
6126 * @param string $proxyhost
\r
6127 * @param string $proxyport
\r
6128 * @param string $proxyusername
\r
6129 * @param string $proxypassword
\r
6130 * @param integer $timeout set the connection timeout
\r
6131 * @param integer $response_timeout set the response timeout
\r
6134 function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
\r
6135 parent::nusoap_base();
\r
6136 $this->endpoint = $endpoint;
\r
6137 $this->proxyhost = $proxyhost;
\r
6138 $this->proxyport = $proxyport;
\r
6139 $this->proxyusername = $proxyusername;
\r
6140 $this->proxypassword = $proxypassword;
\r
6141 $this->timeout = $timeout;
\r
6142 $this->response_timeout = $response_timeout;
\r
6144 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
\r
6145 $this->appendDebug('endpoint=' . $this->varDump($endpoint));
\r
6149 if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
\r
6150 $this->wsdl = $endpoint;
\r
6151 $this->endpoint = $this->wsdl->wsdl;
\r
6152 $this->wsdlFile = $this->endpoint;
\r
6153 $this->debug('existing wsdl instance created from ' . $this->endpoint);
\r
6154 $this->checkWSDL();
\r
6156 $this->wsdlFile = $this->endpoint;
\r
6157 $this->wsdl = null;
\r
6158 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
\r
6160 $this->endpointType = 'wsdl';
\r
6162 $this->debug("instantiate SOAP with endpoint at $endpoint");
\r
6163 $this->endpointType = 'soap';
\r
6168 * calls method, returns PHP native type
\r
6170 * @param string $operation SOAP server URL or path
\r
6171 * @param mixed $params An array, associative or simple, of the parameters
\r
6172 * for the method call, or a string that is the XML
\r
6173 * for the call. For rpc style, this call will
\r
6174 * wrap the XML in a tag named after the method, as
\r
6175 * well as the SOAP Envelope and Body. For document
\r
6176 * style, this will only wrap with the Envelope and Body.
\r
6177 * IMPORTANT: when using an array with document style,
\r
6178 * in which case there
\r
6179 * is really one parameter, the root of the fragment
\r
6180 * used in the call, which encloses what programmers
\r
6181 * normally think of parameters. A parameter array
\r
6182 * *must* include the wrapper.
\r
6183 * @param string $namespace optional method namespace (WSDL can override)
\r
6184 * @param string $soapAction optional SOAPAction value (WSDL can override)
\r
6185 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
\r
6186 * @param boolean $rpcParams optional (no longer used)
\r
6187 * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
\r
6188 * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
\r
6189 * @return mixed response from SOAP call
\r
6192 function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
\r
6193 $this->operation = $operation;
\r
6194 $this->fault = false;
\r
6195 $this->setError('');
\r
6196 $this->request = '';
\r
6197 $this->response = '';
\r
6198 $this->responseData = '';
\r
6199 $this->faultstring = '';
\r
6200 $this->faultcode = '';
\r
6201 $this->opData = array();
\r
6203 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
\r
6204 $this->appendDebug('params=' . $this->varDump($params));
\r
6205 $this->appendDebug('headers=' . $this->varDump($headers));
\r
6207 $this->requestHeaders = $headers;
\r
6209 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
\r
6210 $this->loadWSDL();
\r
6211 if ($this->getError())
\r
6214 // serialize parameters
\r
6215 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
\r
6216 // use WSDL for operation
\r
6217 //echo "use WSDL for operation<br/>";
\r
6218 $this->opData = $opData;
\r
6219 $this->debug("found operation");
\r
6220 $this->appendDebug('opData=' . $this->varDump($opData));
\r
6221 if (isset($opData['soapAction'])) {
\r
6222 $soapAction = $opData['soapAction'];
\r
6224 if (! $this->forceEndpoint) {
\r
6225 $this->endpoint = $opData['endpoint'];
\r
6227 $this->endpoint = $this->forceEndpoint;
\r
6229 $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
\r
6230 $style = $opData['style'];
\r
6231 $use = $opData['input']['use'];
\r
6232 // add ns to ns array
\r
6233 if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
\r
6234 $nsPrefix = 'ns' . rand(1000, 9999);
\r
6235 $this->wsdl->namespaces[$nsPrefix] = $namespace;
\r
6237 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
\r
6238 // serialize payload
\r
6239 if (is_string($params)) {
\r
6240 $this->debug("serializing param string for WSDL operation $operation");
\r
6241 $payload = $params;
\r
6242 } elseif (is_array($params)) {
\r
6243 $this->debug("serializing param array for WSDL operation $operation");
\r
6244 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
\r
6245 //echo "#####PAYLOAD 2 ####<br/>";
\r
6246 //echo htmlentities($payload)."<br/>";
\r
6247 //echo "#####PAYLOAD 2 ####<br/>";
\r
6249 $this->debug('params must be array or string');
\r
6250 $this->setError('params must be array or string');
\r
6253 $usedNamespaces = $this->wsdl->usedNamespaces;
\r
6254 if (isset($opData['input']['encodingStyle'])) {
\r
6255 $encodingStyle = $opData['input']['encodingStyle'];
\r
6257 $encodingStyle = '';
\r
6259 $this->appendDebug($this->wsdl->getDebug());
\r
6260 $this->wsdl->clearDebug();
\r
6261 if ($errstr = $this->wsdl->getError()) {
\r
6262 $this->debug('got wsdl error: '.$errstr);
\r
6263 $this->setError('wsdl error: '.$errstr);
\r
6266 } elseif($this->endpointType == 'wsdl') {
\r
6267 // operation not in WSDL
\r
6268 $this->appendDebug($this->wsdl->getDebug());
\r
6269 $this->wsdl->clearDebug();
\r
6270 $this->setError( 'operation '.$operation.' not present.');
\r
6271 $this->debug("operation '$operation' not present.");
\r
6275 //$this->namespaces['ns1'] = $namespace;
\r
6276 $nsPrefix = 'ns' . rand(1000, 9999);
\r
6279 if (is_string($params)) {
\r
6280 $this->debug("serializing param string for operation $operation");
\r
6281 $payload = $params;
\r
6282 } elseif (is_array($params)) {
\r
6283 $this->debug("serializing param array for operation $operation");
\r
6284 foreach($params as $k => $v){
\r
6285 $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
\r
6288 $this->debug('params must be array or string');
\r
6289 $this->setError('params must be array or string');
\r
6292 $usedNamespaces = array();
\r
6293 if ($use == 'encoded') {
\r
6294 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
\r
6296 $encodingStyle = '';
\r
6299 //echo "#####PAYLOAD 1 ####<br/>";
\r
6300 //echo htmlentities($payload)."<br/>";
\r
6301 //echo "#####PAYLOAD 1 ####<br/>";
\r
6302 // wrap RPC calls with method element
\r
6303 if ($style == 'rpc') {
\r
6304 if ($use == 'literal') {
\r
6305 $this->debug("wrapping RPC request with literal method element");
\r
6307 // 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
\r
6308 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
\r
6310 "</$nsPrefix:$operation>";
\r
6312 $payload = "<$operation>" . $payload . "</$operation>";
\r
6315 $this->debug("wrapping RPC request with encoded method element");
\r
6317 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
\r
6319 "</$nsPrefix:$operation>";
\r
6321 $payload = "<$operation>" .
\r
6327 //echo "#####PAYLOAD####<br/>";
\r
6328 //echo htmlentities($payload)."<br/>";
\r
6329 //echo "#####PAYLOAD####<br/>";
\r
6330 // serialize envelope
\r
6331 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
\r
6332 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
\r
6333 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
\r
6335 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
\r
6336 if($errstr = $this->getError()){
\r
6337 $this->debug('Error: '.$errstr);
\r
6340 $this->return = $return;
\r
6341 $this->debug('sent message successfully and got a(n) '.gettype($return));
\r
6342 $this->appendDebug('return=' . $this->varDump($return));
\r
6345 if(is_array($return) && isset($return['faultcode'])){
\r
6346 $this->debug('got fault');
\r
6347 $this->setError($return['faultcode'].': '.$return['faultstring']);
\r
6348 $this->fault = true;
\r
6349 foreach($return as $k => $v){
\r
6351 $this->debug("$k = $v<br>");
\r
6354 } elseif ($style == 'document') {
\r
6355 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
\r
6356 // we are only going to return the first part here...sorry about that
\r
6359 // array of return values
\r
6360 if(is_array($return)){
\r
6361 // multiple 'out' parameters, which we return wrapped up
\r
6363 if(sizeof($return) > 1){
\r
6366 // single 'out' parameter (normally the return value)
\r
6367 $return = array_shift($return);
\r
6368 $this->debug('return shifted value: ');
\r
6369 $this->appendDebug($this->varDump($return));
\r
6371 // nothing returned (ie, echoVoid)
\r
6380 * check WSDL passed as an instance or pulled from an endpoint
\r
6384 function checkWSDL() {
\r
6385 $this->appendDebug($this->wsdl->getDebug());
\r
6386 $this->wsdl->clearDebug();
\r
6387 $this->debug('checkWSDL');
\r
6389 if ($errstr = $this->wsdl->getError()) {
\r
6390 $this->debug('got wsdl error: '.$errstr);
\r
6391 $this->setError('wsdl error: '.$errstr);
\r
6392 } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
\r
6393 $this->bindingType = 'soap';
\r
6394 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
\r
6395 } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
\r
6396 $this->bindingType = 'soap12';
\r
6397 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
\r
6398 $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
\r
6400 $this->debug('getOperations returned false');
\r
6401 $this->setError('no operations defined in the WSDL document!');
\r
6406 * instantiate wsdl object and parse wsdl file
\r
6410 function loadWSDL() {
\r
6411 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
\r
6412 $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
\r
6413 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
\r
6414 $this->wsdl->fetchWSDL($this->wsdlFile);
\r
6415 $this->checkWSDL();
\r
6419 * get available data pertaining to an operation
\r
6421 * @param string $operation operation name
\r
6422 * @return array array of data pertaining to the operation
\r
6425 function getOperationData($operation){
\r
6426 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
\r
6427 $this->loadWSDL();
\r
6428 if ($this->getError())
\r
6431 if(isset($this->operations[$operation])){
\r
6432 return $this->operations[$operation];
\r
6434 $this->debug("No data for operation: $operation");
\r
6438 * send the SOAP message
\r
6440 * Note: if the operation has multiple return values
\r
6441 * the return value of this method will be an array
\r
6442 * of those values.
\r
6444 * @param string $msg a SOAPx4 soapmsg object
\r
6445 * @param string $soapaction SOAPAction value
\r
6446 * @param integer $timeout set connection timeout in seconds
\r
6447 * @param integer $response_timeout set response timeout in seconds
\r
6448 * @return mixed native PHP types.
\r
6451 function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
\r
6452 $this->checkCookies();
\r
6453 // detect transport
\r
6456 case ereg('^http',$this->endpoint):
\r
6457 $this->debug('transporting via HTTP');
\r
6458 if($this->persistentConnection == true && is_object($this->persistentConnection)){
\r
6459 $http =& $this->persistentConnection;
\r
6461 $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
\r
6462 if ($this->persistentConnection) {
\r
6463 $http->usePersistentConnection();
\r
6466 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
\r
6467 $http->setSOAPAction($soapaction);
\r
6468 if($this->proxyhost && $this->proxyport){
\r
6469 $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
\r
6471 if($this->authtype != '') {
\r
6472 $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
\r
6474 if($this->http_encoding != ''){
\r
6475 $http->setEncoding($this->http_encoding);
\r
6477 $this->debug('sending message, length='.strlen($msg));
\r
6478 if(ereg('^http:',$this->endpoint)){
\r
6479 //if(strpos($this->endpoint,'http:')){
\r
6480 $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
\r
6481 } elseif(ereg('^https',$this->endpoint)){
\r
6482 //} elseif(strpos($this->endpoint,'https:')){
\r
6483 //if(phpversion() == '4.3.0-dev'){
\r
6484 //$response = $http->send($msg,$timeout,$response_timeout);
\r
6485 //$this->request = $http->outgoing_payload;
\r
6486 //$this->response = $http->incoming_payload;
\r
6488 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
\r
6490 $this->setError('no http/s in endpoint url');
\r
6492 $this->request = $http->outgoing_payload;
\r
6493 $this->response = $http->incoming_payload;
\r
6494 $this->appendDebug($http->getDebug());
\r
6495 $this->UpdateCookies($http->incoming_cookies);
\r
6497 // save transport object if using persistent connections
\r
6498 if ($this->persistentConnection) {
\r
6499 $http->clearDebug();
\r
6500 if (!is_object($this->persistentConnection)) {
\r
6501 $this->persistentConnection = $http;
\r
6505 if($err = $http->getError()){
\r
6506 $this->setError('HTTP Error: '.$err);
\r
6508 } elseif($this->getError()){
\r
6511 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
\r
6512 return $this->parseResponse($http->incoming_headers, $this->responseData);
\r
6516 $this->setError('no transport found, or selected transport is not yet supported!');
\r
6523 * processes SOAP message returned from server
\r
6525 * @param array $headers The HTTP headers
\r
6526 * @param string $data unprocessed response data from server
\r
6527 * @return mixed value of the message, decoded into a PHP type
\r
6530 function parseResponse($headers, $data) {
\r
6531 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
\r
6532 $this->appendDebug($this->varDump($headers));
\r
6533 if (!strstr($headers['content-type'], 'text/xml')) {
\r
6534 $this->setError('Response not of type text/xml: ' . $headers['content-type']);
\r
6537 if (strpos($headers['content-type'], '=')) {
\r
6538 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
\r
6539 $this->debug('Got response encoding: ' . $enc);
\r
6540 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
\r
6541 $this->xml_encoding = strtoupper($enc);
\r
6543 $this->xml_encoding = 'US-ASCII';
\r
6546 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
\r
6547 $this->xml_encoding = 'ISO-8859-1';
\r
6549 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
\r
6550 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
\r
6551 // add parser debug data to our debug
\r
6552 $this->appendDebug($parser->getDebug());
\r
6553 // if parse errors
\r
6554 if($errstr = $parser->getError()){
\r
6555 $this->setError( $errstr);
\r
6556 // destroy the parser object
\r
6560 // get SOAP headers
\r
6561 $this->responseHeaders = $parser->getHeaders();
\r
6562 // get SOAP headers
\r
6563 $this->responseHeader = $parser->get_soapheader();
\r
6564 // get decoded message
\r
6565 $return = $parser->get_soapbody();
\r
6566 // add document for doclit support
\r
6567 $this->document = $parser->document;
\r
6568 // destroy the parser object
\r
6570 // return decode message
\r
6576 * sets user-specified cURL options
\r
6578 * @param mixed $option The cURL option (always integer?)
\r
6579 * @param mixed $value The cURL option value
\r
6582 function setCurlOption($option, $value) {
\r
6583 $this->debug("setCurlOption option=$option, value=");
\r
6584 $this->appendDebug($this->varDump($value));
\r
6585 $this->curl_options[$option] = $value;
\r
6589 * sets the SOAP endpoint, which can override WSDL
\r
6591 * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
\r
6594 function setEndpoint($endpoint) {
\r
6595 $this->debug("setEndpoint(\"$endpoint\")");
\r
6596 $this->forceEndpoint = $endpoint;
\r
6600 * set the SOAP headers
\r
6602 * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
\r
6605 function setHeaders($headers){
\r
6606 $this->debug("setHeaders headers=");
\r
6607 $this->appendDebug($this->varDump($headers));
\r
6608 $this->requestHeaders = $headers;
\r
6612 * get the SOAP response headers (namespace resolution incomplete)
\r
6617 function getHeaders(){
\r
6618 return $this->responseHeaders;
\r
6622 * get the SOAP response Header (parsed)
\r
6627 function getHeader(){
\r
6628 return $this->responseHeader;
\r
6632 * set proxy info here
\r
6634 * @param string $proxyhost
\r
6635 * @param string $proxyport
\r
6636 * @param string $proxyusername
\r
6637 * @param string $proxypassword
\r
6640 function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
\r
6641 $this->proxyhost = $proxyhost;
\r
6642 $this->proxyport = $proxyport;
\r
6643 $this->proxyusername = $proxyusername;
\r
6644 $this->proxypassword = $proxypassword;
\r
6648 * if authenticating, set user credentials here
\r
6650 * @param string $username
\r
6651 * @param string $password
\r
6652 * @param string $authtype (basic|digest|certificate|ntlm)
\r
6653 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
\r
6656 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
\r
6657 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
\r
6658 $this->appendDebug($this->varDump($certRequest));
\r
6659 $this->username = $username;
\r
6660 $this->password = $password;
\r
6661 $this->authtype = $authtype;
\r
6662 $this->certRequest = $certRequest;
\r
6666 * use HTTP encoding
\r
6668 * @param string $enc HTTP encoding
\r
6671 function setHTTPEncoding($enc='gzip, deflate'){
\r
6672 $this->debug("setHTTPEncoding(\"$enc\")");
\r
6673 $this->http_encoding = $enc;
\r
6677 * Set whether to try to use cURL connections if possible
\r
6679 * @param boolean $use Whether to try to use cURL
\r
6682 function setUseCURL($use) {
\r
6683 $this->debug("setUseCURL($use)");
\r
6684 $this->use_curl = $use;
\r
6688 * use HTTP persistent connections if possible
\r
6692 function useHTTPPersistentConnection(){
\r
6693 $this->debug("useHTTPPersistentConnection");
\r
6694 $this->persistentConnection = true;
\r
6698 * gets the default RPC parameter setting.
\r
6699 * If true, default is that call params are like RPC even for document style.
\r
6700 * Each call() can override this value.
\r
6702 * This is no longer used.
\r
6708 function getDefaultRpcParams() {
\r
6709 return $this->defaultRpcParams;
\r
6713 * sets the default RPC parameter setting.
\r
6714 * If true, default is that call params are like RPC even for document style
\r
6715 * Each call() can override this value.
\r
6717 * This is no longer used.
\r
6719 * @param boolean $rpcParams
\r
6723 function setDefaultRpcParams($rpcParams) {
\r
6724 $this->defaultRpcParams = $rpcParams;
\r
6728 * dynamically creates an instance of a proxy class,
\r
6729 * allowing user to directly call methods from wsdl
\r
6731 * @return object soap_proxy object
\r
6734 function getProxy() {
\r
6736 $evalStr = $this->_getProxyClassCode($r);
\r
6737 //$this->debug("proxy class: $evalStr");
\r
6738 if ($this->getError()) {
\r
6739 $this->debug("Error from _getProxyClassCode, so return NULL");
\r
6744 // instantiate proxy object
\r
6745 eval("\$proxy = new nusoap_proxy_$r('');");
\r
6746 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
\r
6747 $proxy->endpointType = 'wsdl';
\r
6748 $proxy->wsdlFile = $this->wsdlFile;
\r
6749 $proxy->wsdl = $this->wsdl;
\r
6750 $proxy->operations = $this->operations;
\r
6751 $proxy->defaultRpcParams = $this->defaultRpcParams;
\r
6752 // transfer other state
\r
6753 $proxy->soap_defencoding = $this->soap_defencoding;
\r
6754 $proxy->username = $this->username;
\r
6755 $proxy->password = $this->password;
\r
6756 $proxy->authtype = $this->authtype;
\r
6757 $proxy->certRequest = $this->certRequest;
\r
6758 $proxy->requestHeaders = $this->requestHeaders;
\r
6759 $proxy->endpoint = $this->endpoint;
\r
6760 $proxy->forceEndpoint = $this->forceEndpoint;
\r
6761 $proxy->proxyhost = $this->proxyhost;
\r
6762 $proxy->proxyport = $this->proxyport;
\r
6763 $proxy->proxyusername = $this->proxyusername;
\r
6764 $proxy->proxypassword = $this->proxypassword;
\r
6765 $proxy->http_encoding = $this->http_encoding;
\r
6766 $proxy->timeout = $this->timeout;
\r
6767 $proxy->response_timeout = $this->response_timeout;
\r
6768 $proxy->persistentConnection = &$this->persistentConnection;
\r
6769 $proxy->decode_utf8 = $this->decode_utf8;
\r
6770 $proxy->curl_options = $this->curl_options;
\r
6771 $proxy->bindingType = $this->bindingType;
\r
6772 $proxy->use_curl = $this->use_curl;
\r
6777 * dynamically creates proxy class code
\r
6779 * @return string PHP/NuSOAP code for the proxy class
\r
6782 function _getProxyClassCode($r) {
\r
6783 $this->debug("in getProxy endpointType=$this->endpointType");
\r
6784 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
\r
6785 if ($this->endpointType != 'wsdl') {
\r
6786 $evalStr = 'A proxy can only be created for a WSDL client';
\r
6787 $this->setError($evalStr);
\r
6788 $evalStr = "echo \"$evalStr\";";
\r
6791 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
\r
6792 $this->loadWSDL();
\r
6793 if ($this->getError()) {
\r
6794 return "echo \"" . $this->getError() . "\";";
\r
6798 foreach ($this->operations as $operation => $opData) {
\r
6799 if ($operation != '') {
\r
6800 // create param string and param comment string
\r
6801 if (sizeof($opData['input']['parts']) > 0) {
\r
6803 $paramArrayStr = '';
\r
6804 $paramCommentStr = '';
\r
6805 foreach ($opData['input']['parts'] as $name => $type) {
\r
6806 $paramStr .= "\$$name, ";
\r
6807 $paramArrayStr .= "'$name' => \$$name, ";
\r
6808 $paramCommentStr .= "$type \$$name, ";
\r
6810 $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
\r
6811 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
\r
6812 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
\r
6815 $paramArrayStr = '';
\r
6816 $paramCommentStr = 'void';
\r
6818 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
\r
6819 $evalStr .= "// $paramCommentStr
\r
6820 function " . str_replace('.', '__', $operation) . "($paramStr) {
\r
6821 \$params = array($paramArrayStr);
\r
6822 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
\r
6826 unset($paramCommentStr);
\r
6829 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
\r
6836 * dynamically creates proxy class code
\r
6838 * @return string PHP/NuSOAP code for the proxy class
\r
6841 function getProxyClassCode() {
\r
6843 return $this->_getProxyClassCode($r);
\r
6847 * gets the HTTP body for the current request.
\r
6849 * @param string $soapmsg The SOAP payload
\r
6850 * @return string The HTTP body, which includes the SOAP payload
\r
6853 function getHTTPBody($soapmsg) {
\r
6858 * gets the HTTP content type for the current request.
\r
6860 * Note: getHTTPBody must be called before this.
\r
6862 * @return string the HTTP content type for the current request.
\r
6865 function getHTTPContentType() {
\r
6866 return 'text/xml';
\r
6870 * gets the HTTP content type charset for the current request.
\r
6871 * returns false for non-text content types.
\r
6873 * Note: getHTTPBody must be called before this.
\r
6875 * @return string the HTTP content type charset for the current request.
\r
6878 function getHTTPContentTypeCharset() {
\r
6879 return $this->soap_defencoding;
\r
6883 * whether or not parser should decode utf8 element content
\r
6885 * @return always returns true
\r
6888 function decodeUTF8($bool){
\r
6889 $this->decode_utf8 = $bool;
\r
6894 * adds a new Cookie into $this->cookies array
\r
6896 * @param string $name Cookie Name
\r
6897 * @param string $value Cookie Value
\r
6898 * @return boolean if cookie-set was successful returns true, else false
\r
6901 function setCookie($name, $value) {
\r
6902 if (strlen($name) == 0) {
\r
6905 $this->cookies[] = array('name' => $name, 'value' => $value);
\r
6910 * gets all Cookies
\r
6912 * @return array with all internal cookies
\r
6915 function getCookies() {
\r
6916 return $this->cookies;
\r
6920 * checks all Cookies and delete those which are expired
\r
6922 * @return boolean always return true
\r
6925 function checkCookies() {
\r
6926 if (sizeof($this->cookies) == 0) {
\r
6929 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
\r
6930 $curr_cookies = $this->cookies;
\r
6931 $this->cookies = array();
\r
6932 foreach ($curr_cookies as $cookie) {
\r
6933 if (! is_array($cookie)) {
\r
6934 $this->debug('Remove cookie that is not an array');
\r
6937 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
\r
6938 if (strtotime($cookie['expires']) > time()) {
\r
6939 $this->cookies[] = $cookie;
\r
6941 $this->debug('Remove expired cookie ' . $cookie['name']);
\r
6944 $this->cookies[] = $cookie;
\r
6947 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
\r
6952 * updates the current cookies with a new set
\r
6954 * @param array $cookies new cookies with which to update current ones
\r
6955 * @return boolean always return true
\r
6958 function UpdateCookies($cookies) {
\r
6959 if (sizeof($this->cookies) == 0) {
\r
6960 // no existing cookies: take whatever is new
\r
6961 if (sizeof($cookies) > 0) {
\r
6962 $this->debug('Setting new cookie(s)');
\r
6963 $this->cookies = $cookies;
\r
6967 if (sizeof($cookies) == 0) {
\r
6968 // no new cookies: keep what we've got
\r
6972 foreach ($cookies as $newCookie) {
\r
6973 if (!is_array($newCookie)) {
\r
6976 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
\r
6979 $newName = $newCookie['name'];
\r
6982 for ($i = 0; $i < count($this->cookies); $i++) {
\r
6983 $cookie = $this->cookies[$i];
\r
6984 if (!is_array($cookie)) {
\r
6987 if (!isset($cookie['name'])) {
\r
6990 if ($newName != $cookie['name']) {
\r
6993 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
\r
6994 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
\r
6995 if ($newDomain != $domain) {
\r
6998 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
\r
6999 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
\r
7000 if ($newPath != $path) {
\r
7003 $this->cookies[$i] = $newCookie;
\r
7005 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
\r
7009 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
\r
7010 $this->cookies[] = $newCookie;
\r
7017 if (!extension_loaded('soap')) {
\r
7019 * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
\r
7021 class soapclient extends nusoap_client {
\r