1<?php 2 3/* 4$Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 5 6NuSOAP - Web Services Toolkit for PHP 7 8Copyright (c) 2002 NuSphere Corporation 9 10This library is free software; you can redistribute it and/or 11modify it under the terms of the GNU Lesser General Public 12License as published by the Free Software Foundation; either 13version 2.1 of the License, or (at your option) any later version. 14 15This library is distributed in the hope that it will be useful, 16but WITHOUT ANY WARRANTY; without even the implied warranty of 17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18Lesser General Public License for more details. 19 20You should have received a copy of the GNU Lesser General Public 21License along with this library; if not, write to the Free Software 22Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 24The NuSOAP project home is: 25http://sourceforge.net/projects/nusoap/ 26 27The primary support for NuSOAP is the mailing list: 28nusoap-general@lists.sourceforge.net 29 30If you have any questions or comments, please email: 31 32Dietrich Ayala 33dietrich@ganx4.com 34http://dietrich.ganx4.com/nusoap 35 36NuSphere Corporation 37http://www.nusphere.com 38 39*/ 40 41/* 42 * Some of the standards implmented in whole or part by NuSOAP: 43 * 44 * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) 45 * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) 46 * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) 47 * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) 48 * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) 49 * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) 50 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies 51 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 52 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication 53 */ 54 55/* load classes 56 57// necessary classes 58require_once('class.soapclient.php'); 59require_once('class.soap_val.php'); 60require_once('class.soap_parser.php'); 61require_once('class.soap_fault.php'); 62 63// transport classes 64require_once('class.soap_transport_http.php'); 65 66// optional add-on classes 67require_once('class.xmlschema.php'); 68require_once('class.wsdl.php'); 69 70// server class 71require_once('class.soap_server.php');*/ 72 73// class variable emulation 74// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html 75$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9; 76 77/** 78* 79* nusoap_base 80* 81* @author Dietrich Ayala <dietrich@ganx4.com> 82* @author Scott Nichol <snichol@users.sourceforge.net> 83* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 84* @access public 85*/ 86class nusoap_base { 87 /** 88 * Identification for HTTP headers. 89 * 90 * @var string 91 * @access private 92 */ 93 var $title = 'NuSOAP'; 94 /** 95 * Version for HTTP headers. 96 * 97 * @var string 98 * @access private 99 */ 100 var $version = '0.7.3'; 101 /** 102 * CVS revision for HTTP headers. 103 * 104 * @var string 105 * @access private 106 */ 107 var $revision = '$Revision: 1.114 $'; 108 /** 109 * Current error string (manipulated by getError/setError) 110 * 111 * @var string 112 * @access private 113 */ 114 var $error_str = ''; 115 /** 116 * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) 117 * 118 * @var string 119 * @access private 120 */ 121 var $debug_str = ''; 122 /** 123 * toggles automatic encoding of special characters as entities 124 * (should always be true, I think) 125 * 126 * @var boolean 127 * @access private 128 */ 129 var $charencoding = true; 130 /** 131 * the debug level for this instance 132 * 133 * @var integer 134 * @access private 135 */ 136 var $debugLevel; 137 138 /** 139 * set schema version 140 * 141 * @var string 142 * @access public 143 */ 144 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 145 146 /** 147 * charset encoding for outgoing messages 148 * 149 * @var string 150 * @access public 151 */ 152 var $soap_defencoding = 'ISO-8859-1'; 153 //var $soap_defencoding = 'UTF-8'; 154 155 /** 156 * namespaces in an array of prefix => uri 157 * 158 * this is "seeded" by a set of constants, but it may be altered by code 159 * 160 * @var array 161 * @access public 162 */ 163 var $namespaces = array( 164 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 165 'xsd' => 'http://www.w3.org/2001/XMLSchema', 166 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 167 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 168 ); 169 170 /** 171 * namespaces used in the current context, e.g. during serialization 172 * 173 * @var array 174 * @access private 175 */ 176 var $usedNamespaces = array(); 177 178 /** 179 * XML Schema types in an array of uri => (array of xml type => php type) 180 * is this legacy yet? 181 * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. 182 * @var array 183 * @access public 184 */ 185 var $typemap = array( 186 'http://www.w3.org/2001/XMLSchema' => array( 187 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 188 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 189 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 190 // abstract "any" types 191 'anyType'=>'string','anySimpleType'=>'string', 192 // derived datatypes 193 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 194 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 195 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 196 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 197 'http://www.w3.org/2000/10/XMLSchema' => array( 198 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 199 'float'=>'double','dateTime'=>'string', 200 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 201 'http://www.w3.org/1999/XMLSchema' => array( 202 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 203 'float'=>'double','dateTime'=>'string', 204 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 205 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 206 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 207 'http://xml.apache.org/xml-soap' => array('Map') 208 ); 209 210 /** 211 * XML entities to convert 212 * 213 * @var array 214 * @access public 215 * @deprecated 216 * @see expandEntities 217 */ 218 var $xmlEntities = array('quot' => '"','amp' => '&', 219 'lt' => '<','gt' => '>','apos' => "'"); 220 221 /** 222 * constructor 223 * 224 * @access public 225 */ 226 function nusoap_base() { 227 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 228 } 229 230 /** 231 * gets the global debug level, which applies to future instances 232 * 233 * @return integer Debug level 0-9, where 0 turns off 234 * @access public 235 */ 236 function getGlobalDebugLevel() { 237 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 238 } 239 240 /** 241 * sets the global debug level, which applies to future instances 242 * 243 * @param int $level Debug level 0-9, where 0 turns off 244 * @access public 245 */ 246 function setGlobalDebugLevel($level) { 247 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; 248 } 249 250 /** 251 * gets the debug level for this instance 252 * 253 * @return int Debug level 0-9, where 0 turns off 254 * @access public 255 */ 256 function getDebugLevel() { 257 return $this->debugLevel; 258 } 259 260 /** 261 * sets the debug level for this instance 262 * 263 * @param int $level Debug level 0-9, where 0 turns off 264 * @access public 265 */ 266 function setDebugLevel($level) { 267 $this->debugLevel = $level; 268 } 269 270 /** 271 * adds debug data to the instance debug string with formatting 272 * 273 * @param string $string debug data 274 * @access private 275 */ 276 function debug($string){ 277 if ($this->debugLevel > 0) { 278 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 279 } 280 } 281 282 /** 283 * adds debug data to the instance debug string without formatting 284 * 285 * @param string $string debug data 286 * @access public 287 */ 288 function appendDebug($string){ 289 if ($this->debugLevel > 0) { 290 // it would be nice to use a memory stream here to use 291 // memory more efficiently 292 $this->debug_str .= $string; 293 } 294 } 295 296 /** 297 * clears the current debug data for this instance 298 * 299 * @access public 300 */ 301 function clearDebug() { 302 // it would be nice to use a memory stream here to use 303 // memory more efficiently 304 $this->debug_str = ''; 305 } 306 307 /** 308 * gets the current debug data for this instance 309 * 310 * @return debug data 311 * @access public 312 */ 313 function &getDebug() { 314 // it would be nice to use a memory stream here to use 315 // memory more efficiently 316 return $this->debug_str; 317 } 318 319 /** 320 * gets the current debug data for this instance as an XML comment 321 * this may change the contents of the debug data 322 * 323 * @return debug data as an XML comment 324 * @access public 325 */ 326 function &getDebugAsXMLComment() { 327 // it would be nice to use a memory stream here to use 328 // memory more efficiently 329 while (strpos($this->debug_str, '--')) { 330 $this->debug_str = str_replace('--', '- -', $this->debug_str); 331 } 332 $ret = "<!--\n" . $this->debug_str . "\n-->"; 333 return $ret; 334 } 335 336 /** 337 * expands entities, e.g. changes '<' to '<'. 338 * 339 * @param string $val The string in which to expand entities. 340 * @access private 341 */ 342 function expandEntities($val) { 343 if ($this->charencoding) { 344 $val = str_replace('&', '&', $val); 345 $val = str_replace("'", ''', $val); 346 $val = str_replace('"', '"', $val); 347 $val = str_replace('<', '<', $val); 348 $val = str_replace('>', '>', $val); 349 } 350 return $val; 351 } 352 353 /** 354 * returns error string if present 355 * 356 * @return mixed error string or false 357 * @access public 358 */ 359 function getError(){ 360 if($this->error_str != ''){ 361 return $this->error_str; 362 } 363 return false; 364 } 365 366 /** 367 * sets error string 368 * 369 * @return boolean $string error string 370 * @access private 371 */ 372 function setError($str){ 373 $this->error_str = $str; 374 } 375 376 /** 377 * detect if array is a simple array or a struct (associative array) 378 * 379 * @param mixed $val The PHP array 380 * @return string (arraySimple|arrayStruct) 381 * @access private 382 */ 383 function isArraySimpleOrStruct($val) { 384 $keyList = array_keys($val); 385 foreach ($keyList as $keyListValue) { 386 if (!is_int($keyListValue)) { 387 return 'arrayStruct'; 388 } 389 } 390 return 'arraySimple'; 391 } 392 393 /** 394 * serializes PHP values in accordance w/ section 5. Type information is 395 * not serialized if $use == 'literal'. 396 * 397 * @param mixed $val The value to serialize 398 * @param string $name The name (local part) of the XML element 399 * @param string $type The XML schema type (local part) for the element 400 * @param string $name_ns The namespace for the name of the XML element 401 * @param string $type_ns The namespace for the type of the element 402 * @param array $attributes The attributes to serialize as name=>value pairs 403 * @param string $use The WSDL "use" (encoded|literal) 404 * @param boolean $soapval Whether this is called from soapval. 405 * @return string The serialized element, possibly with child elements 406 * @access public 407 */ 408 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { 409 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); 410 $this->appendDebug('value=' . $this->varDump($val)); 411 $this->appendDebug('attributes=' . $this->varDump($attributes)); 412 413 if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { 414 $this->debug("serialize_val: serialize soapval"); 415 $xml = $val->serialize($use); 416 $this->appendDebug($val->getDebug()); 417 $val->clearDebug(); 418 $this->debug("serialize_val of soapval returning $xml"); 419 return $xml; 420 } 421 // force valid name if necessary 422 if (is_numeric($name)) { 423 $name = '__numeric_' . $name; 424 } elseif (! $name) { 425 $name = 'noname'; 426 } 427 // if name has ns, add ns prefix to name 428 $xmlns = ''; 429 if($name_ns){ 430 $prefix = 'nu'.rand(1000,9999); 431 $name = $prefix.':'.$name; 432 $xmlns .= " xmlns:$prefix=\"$name_ns\""; 433 } 434 // if type is prefixed, create type prefix 435 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 436 // need to fix this. shouldn't default to xsd if no ns specified 437 // w/o checking against typemap 438 $type_prefix = 'xsd'; 439 } elseif($type_ns){ 440 $type_prefix = 'ns'.rand(1000,9999); 441 $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 442 } 443 // serialize attributes if present 444 $atts = ''; 445 if($attributes){ 446 foreach($attributes as $k => $v){ 447 $atts .= " $k=\"".$this->expandEntities($v).'"'; 448 } 449 } 450 // serialize null value 451 if (is_null($val)) { 452 $this->debug("serialize_val: serialize null"); 453 if ($use == 'literal') { 454 // TODO: depends on minOccurs 455 $xml = "<$name$xmlns$atts/>"; 456 $this->debug("serialize_val returning $xml"); 457 return $xml; 458 } else { 459 if (isset($type) && isset($type_prefix)) { 460 $type_str = " xsi:type=\"$type_prefix:$type\""; 461 } else { 462 $type_str = ''; 463 } 464 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; 465 $this->debug("serialize_val returning $xml"); 466 return $xml; 467 } 468 } 469 // serialize if an xsd built-in primitive type 470 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 471 $this->debug("serialize_val: serialize xsd built-in primitive type"); 472 if (is_bool($val)) { 473 if ($type == 'boolean') { 474 $val = $val ? 'true' : 'false'; 475 } elseif (! $val) { 476 $val = 0; 477 } 478 } else if (is_string($val)) { 479 $val = $this->expandEntities($val); 480 } 481 if ($use == 'literal') { 482 $xml = "<$name$xmlns$atts>$val</$name>"; 483 $this->debug("serialize_val returning $xml"); 484 return $xml; 485 } else { 486 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>"; 487 $this->debug("serialize_val returning $xml"); 488 return $xml; 489 } 490 } 491 // detect type and serialize 492 $xml = ''; 493 switch(true) { 494 case (is_bool($val) || $type == 'boolean'): 495 $this->debug("serialize_val: serialize boolean"); 496 if ($type == 'boolean') { 497 $val = $val ? 'true' : 'false'; 498 } elseif (! $val) { 499 $val = 0; 500 } 501 if ($use == 'literal') { 502 $xml .= "<$name$xmlns$atts>$val</$name>"; 503 } else { 504 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; 505 } 506 break; 507 case (is_int($val) || is_long($val) || $type == 'int'): 508 $this->debug("serialize_val: serialize int"); 509 if ($use == 'literal') { 510 $xml .= "<$name$xmlns$atts>$val</$name>"; 511 } else { 512 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; 513 } 514 break; 515 case (is_float($val)|| is_double($val) || $type == 'float'): 516 $this->debug("serialize_val: serialize float"); 517 if ($use == 'literal') { 518 $xml .= "<$name$xmlns$atts>$val</$name>"; 519 } else { 520 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; 521 } 522 break; 523 case (is_string($val) || $type == 'string'): 524 $this->debug("serialize_val: serialize string"); 525 $val = $this->expandEntities($val); 526 if ($use == 'literal') { 527 $xml .= "<$name$xmlns$atts>$val</$name>"; 528 } else { 529 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; 530 } 531 break; 532 case is_object($val): 533 $this->debug("serialize_val: serialize object"); 534 if (get_class($val) == 'soapval') { 535 $this->debug("serialize_val: serialize soapval object"); 536 $pXml = $val->serialize($use); 537 $this->appendDebug($val->getDebug()); 538 $val->clearDebug(); 539 } else { 540 if (! $name) { 541 $name = get_class($val); 542 $this->debug("In serialize_val, used class name $name as element name"); 543 } else { 544 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 545 } 546 foreach(get_object_vars($val) as $k => $v){ 547 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 548 } 549 } 550 if(isset($type) && isset($type_prefix)){ 551 $type_str = " xsi:type=\"$type_prefix:$type\""; 552 } else { 553 $type_str = ''; 554 } 555 if ($use == 'literal') { 556 $xml .= "<$name$xmlns$atts>$pXml</$name>"; 557 } else { 558 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>"; 559 } 560 break; 561 break; 562 case (is_array($val) || $type): 563 // detect if struct or array 564 $valueType = $this->isArraySimpleOrStruct($val); 565 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ 566 $this->debug("serialize_val: serialize array"); 567 $i = 0; 568 if(is_array($val) && count($val)> 0){ 569 foreach($val as $v){ 570 if(is_object($v) && get_class($v) == 'soapval'){ 571 $tt_ns = $v->type_ns; 572 $tt = $v->type; 573 } elseif (is_array($v)) { 574 $tt = $this->isArraySimpleOrStruct($v); 575 } else { 576 $tt = gettype($v); 577 } 578 $array_types[$tt] = 1; 579 // TODO: for literal, the name should be $name 580 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 581 ++$i; 582 } 583 if(count($array_types) > 1){ 584 $array_typename = 'xsd:anyType'; 585 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 586 if ($tt == 'integer') { 587 $tt = 'int'; 588 } 589 $array_typename = 'xsd:'.$tt; 590 } elseif(isset($tt) && $tt == 'arraySimple'){ 591 $array_typename = 'SOAP-ENC:Array'; 592 } elseif(isset($tt) && $tt == 'arrayStruct'){ 593 $array_typename = 'unnamed_struct_use_soapval'; 594 } else { 595 // if type is prefixed, create type prefix 596 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 597 $array_typename = 'xsd:' . $tt; 598 } elseif ($tt_ns) { 599 $tt_prefix = 'ns' . rand(1000, 9999); 600 $array_typename = "$tt_prefix:$tt"; 601 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 602 } else { 603 $array_typename = $tt; 604 } 605 } 606 $array_type = $i; 607 if ($use == 'literal') { 608 $type_str = ''; 609 } else if (isset($type) && isset($type_prefix)) { 610 $type_str = " xsi:type=\"$type_prefix:$type\""; 611 } else { 612 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 613 } 614 // empty array 615 } else { 616 if ($use == 'literal') { 617 $type_str = ''; 618 } else if (isset($type) && isset($type_prefix)) { 619 $type_str = " xsi:type=\"$type_prefix:$type\""; 620 } else { 621 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 622 } 623 } 624 // TODO: for array in literal, there is no wrapper here 625 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; 626 } else { 627 // got a struct 628 $this->debug("serialize_val: serialize struct"); 629 if(isset($type) && isset($type_prefix)){ 630 $type_str = " xsi:type=\"$type_prefix:$type\""; 631 } else { 632 $type_str = ''; 633 } 634 if ($use == 'literal') { 635 $xml .= "<$name$xmlns$atts>"; 636 } else { 637 $xml .= "<$name$xmlns$type_str$atts>"; 638 } 639 foreach($val as $k => $v){ 640 // Apache Map 641 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 642 $xml .= '<item>'; 643 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 644 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 645 $xml .= '</item>'; 646 } else { 647 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 648 } 649 } 650 $xml .= "</$name>"; 651 } 652 break; 653 default: 654 $this->debug("serialize_val: serialize unknown"); 655 $xml .= 'not detected, got '.gettype($val).' for '.$val; 656 break; 657 } 658 $this->debug("serialize_val returning $xml"); 659 return $xml; 660 } 661 662 /** 663 * serializes a message 664 * 665 * @param string $body the XML of the SOAP body 666 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array 667 * @param array $namespaces optional the namespaces used in generating the body and headers 668 * @param string $style optional (rpc|document) 669 * @param string $use optional (encoded|literal) 670 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 671 * @return string the message 672 * @access public 673 */ 674 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 675 // TODO: add an option to automatically run utf8_encode on $body and $headers 676 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 677 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 678 679 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 680 $this->debug("headers:"); 681 $this->appendDebug($this->varDump($headers)); 682 $this->debug("namespaces:"); 683 $this->appendDebug($this->varDump($namespaces)); 684 685 // serialize namespaces 686 $ns_string = ''; 687 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 688 $ns_string .= " xmlns:$k=\"$v\""; 689 } 690 if($encodingStyle) { 691 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 692 } 693 694 // serialize headers 695 if($headers){ 696 if (is_array($headers)) { 697 $xml = ''; 698 foreach ($headers as $k => $v) { 699 if (is_object($v) && get_class($v) == 'soapval') { 700 $xml .= $this->serialize_val($v, false, false, false, false, false, $use); 701 } else { 702 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); 703 } 704 } 705 $headers = $xml; 706 $this->debug("In serializeEnvelope, serialized array of headers to $headers"); 707 } 708 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; 709 } 710 // serialize envelope 711 return 712 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". 713 '<SOAP-ENV:Envelope'.$ns_string.">". 714 $headers. 715 "<SOAP-ENV:Body>". 716 $body. 717 "</SOAP-ENV:Body>". 718 "</SOAP-ENV:Envelope>"; 719 } 720 721 /** 722 * formats a string to be inserted into an HTML stream 723 * 724 * @param string $str The string to format 725 * @return string The formatted string 726 * @access public 727 * @deprecated 728 */ 729 function formatDump($str){ 730 $str = htmlspecialchars($str); 731 return nl2br($str); 732 } 733 734 /** 735 * contracts (changes namespace to prefix) a qualified name 736 * 737 * @param string $qname qname 738 * @return string contracted qname 739 * @access private 740 */ 741 function contractQname($qname){ 742 // get element namespace 743 //$this->xdebug("Contract $qname"); 744 if (strrpos($qname, ':')) { 745 // get unqualified name 746 $name = substr($qname, strrpos($qname, ':') + 1); 747 // get ns 748 $ns = substr($qname, 0, strrpos($qname, ':')); 749 $p = $this->getPrefixFromNamespace($ns); 750 if ($p) { 751 return $p . ':' . $name; 752 } 753 return $qname; 754 } else { 755 return $qname; 756 } 757 } 758 759 /** 760 * expands (changes prefix to namespace) a qualified name 761 * 762 * @param string $qname qname 763 * @return string expanded qname 764 * @access private 765 */ 766 function expandQname($qname){ 767 // get element prefix 768 if(strpos($qname,':') && !ereg('^http://',$qname)){ 769 // get unqualified name 770 $name = substr(strstr($qname,':'),1); 771 // get ns prefix 772 $prefix = substr($qname,0,strpos($qname,':')); 773 if(isset($this->namespaces[$prefix])){ 774 return $this->namespaces[$prefix].':'.$name; 775 } else { 776 return $qname; 777 } 778 } else { 779 return $qname; 780 } 781 } 782 783 /** 784 * returns the local part of a prefixed string 785 * returns the original string, if not prefixed 786 * 787 * @param string $str The prefixed string 788 * @return string The local part 789 * @access public 790 */ 791 function getLocalPart($str){ 792 if($sstr = strrchr($str,':')){ 793 // get unqualified name 794 return substr( $sstr, 1 ); 795 } else { 796 return $str; 797 } 798 } 799 800 /** 801 * returns the prefix part of a prefixed string 802 * returns false, if not prefixed 803 * 804 * @param string $str The prefixed string 805 * @return mixed The prefix or false if there is no prefix 806 * @access public 807 */ 808 function getPrefix($str){ 809 if($pos = strrpos($str,':')){ 810 // get prefix 811 return substr($str,0,$pos); 812 } 813 return false; 814 } 815 816 /** 817 * pass it a prefix, it returns a namespace 818 * 819 * @param string $prefix The prefix 820 * @return mixed The namespace, false if no namespace has the specified prefix 821 * @access public 822 */ 823 function getNamespaceFromPrefix($prefix){ 824 if (isset($this->namespaces[$prefix])) { 825 return $this->namespaces[$prefix]; 826 } 827 //$this->setError("No namespace registered for prefix '$prefix'"); 828 return false; 829 } 830 831 /** 832 * returns the prefix for a given namespace (or prefix) 833 * or false if no prefixes registered for the given namespace 834 * 835 * @param string $ns The namespace 836 * @return mixed The prefix, false if the namespace has no prefixes 837 * @access public 838 */ 839 function getPrefixFromNamespace($ns) { 840 foreach ($this->namespaces as $p => $n) { 841 if ($ns == $n || $ns == $p) { 842 $this->usedNamespaces[$p] = $n; 843 return $p; 844 } 845 } 846 return false; 847 } 848 849 /** 850 * returns the time in ODBC canonical form with microseconds 851 * 852 * @return string The time in ODBC canonical form with microseconds 853 * @access public 854 */ 855 function getmicrotime() { 856 if (function_exists('gettimeofday')) { 857 $tod = gettimeofday(); 858 $sec = $tod['sec']; 859 $usec = $tod['usec']; 860 } else { 861 $sec = time(); 862 $usec = 0; 863 } 864 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 865 } 866 867 /** 868 * Returns a string with the output of var_dump 869 * 870 * @param mixed $data The variable to var_dump 871 * @return string The output of var_dump 872 * @access public 873 */ 874 function varDump($data) { 875 ob_start(); 876 var_dump($data); 877 $ret_val = ob_get_contents(); 878 ob_end_clean(); 879 return $ret_val; 880 } 881 882 /** 883 * represents the object as a string 884 * 885 * @return string 886 * @access public 887 */ 888 function __toString() { 889 return $this->varDump($this); 890 } 891} 892 893// XML Schema Datatype Helper Functions 894 895//xsd:dateTime helpers 896 897/** 898* convert unix timestamp to ISO 8601 compliant date string 899* 900* @param string $timestamp Unix time stamp 901* @param boolean $utc Whether the time stamp is UTC or local 902* @access public 903*/ 904function timestamp_to_iso8601($timestamp,$utc=true){ 905 $datestr = date('Y-m-d\TH:i:sO',$timestamp); 906 if($utc){ 907 $eregStr = 908 '([0-9]{4})-'. // centuries & years CCYY- 909 '([0-9]{2})-'. // months MM- 910 '([0-9]{2})'. // days DD 911 'T'. // separator T 912 '([0-9]{2}):'. // hours hh: 913 '([0-9]{2}):'. // minutes mm: 914 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 915 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 916 917 if(ereg($eregStr,$datestr,$regs)){ 918 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 919 } 920 return false; 921 } else { 922 return $datestr; 923 } 924} 925 926/** 927* convert ISO 8601 compliant date string to unix timestamp 928* 929* @param string $datestr ISO 8601 compliant date string 930* @access public 931*/ 932function iso8601_to_timestamp($datestr){ 933 $eregStr = 934 '([0-9]{4})-'. // centuries & years CCYY- 935 '([0-9]{2})-'. // months MM- 936 '([0-9]{2})'. // days DD 937 'T'. // separator T 938 '([0-9]{2}):'. // hours hh: 939 '([0-9]{2}):'. // minutes mm: 940 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 941 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 942 if(ereg($eregStr,$datestr,$regs)){ 943 // not utc 944 if($regs[8] != 'Z'){ 945 $op = substr($regs[8],0,1); 946 $h = substr($regs[8],1,2); 947 $m = substr($regs[8],strlen($regs[8])-2,2); 948 if($op == '-'){ 949 $regs[4] = $regs[4] + $h; 950 $regs[5] = $regs[5] + $m; 951 } elseif($op == '+'){ 952 $regs[4] = $regs[4] - $h; 953 $regs[5] = $regs[5] - $m; 954 } 955 } 956 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 957// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 958 } else { 959 return false; 960 } 961} 962 963/** 964* sleeps some number of microseconds 965* 966* @param string $usec the number of microseconds to sleep 967* @access public 968* @deprecated 969*/ 970function usleepWindows($usec) 971{ 972 $start = gettimeofday(); 973 974 do 975 { 976 $stop = gettimeofday(); 977 $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 978 + $stop['usec'] - $start['usec']; 979 } 980 while ($timePassed < $usec); 981} 982 983?><?php 984 985 986 987/** 988* Contains information for a SOAP fault. 989* Mainly used for returning faults from deployed functions 990* in a server instance. 991* @author Dietrich Ayala <dietrich@ganx4.com> 992* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 993* @access public 994*/ 995class nusoap_fault extends nusoap_base { 996 /** 997 * The fault code (client|server) 998 * @var string 999 * @access private 1000 */ 1001 var $faultcode; 1002 /** 1003 * The fault actor 1004 * @var string 1005 * @access private 1006 */ 1007 var $faultactor; 1008 /** 1009 * The fault string, a description of the fault 1010 * @var string 1011 * @access private 1012 */ 1013 var $faultstring; 1014 /** 1015 * The fault detail, typically a string or array of string 1016 * @var mixed 1017 * @access private 1018 */ 1019 var $faultdetail; 1020 1021 /** 1022 * constructor 1023 * 1024 * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) 1025 * @param string $faultactor only used when msg routed between multiple actors 1026 * @param string $faultstring human readable error message 1027 * @param mixed $faultdetail detail, typically a string or array of string 1028 */ 1029 function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ 1030 parent::nusoap_base(); 1031 $this->faultcode = $faultcode; 1032 $this->faultactor = $faultactor; 1033 $this->faultstring = $faultstring; 1034 $this->faultdetail = $faultdetail; 1035 } 1036 1037 /** 1038 * serialize a fault 1039 * 1040 * @return string The serialization of the fault instance. 1041 * @access public 1042 */ 1043 function serialize(){ 1044 $ns_string = ''; 1045 foreach($this->namespaces as $k => $v){ 1046 $ns_string .= "\n xmlns:$k=\"$v\""; 1047 } 1048 $return_msg = 1049 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. 1050 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". 1051 '<SOAP-ENV:Body>'. 1052 '<SOAP-ENV:Fault>'. 1053 $this->serialize_val($this->faultcode, 'faultcode'). 1054 $this->serialize_val($this->faultactor, 'faultactor'). 1055 $this->serialize_val($this->faultstring, 'faultstring'). 1056 $this->serialize_val($this->faultdetail, 'detail'). 1057 '</SOAP-ENV:Fault>'. 1058 '</SOAP-ENV:Body>'. 1059 '</SOAP-ENV:Envelope>'; 1060 return $return_msg; 1061 } 1062} 1063 1064/** 1065 * Backward compatibility 1066 */ 1067class soap_fault extends nusoap_fault { 1068} 1069 1070?><?php 1071 1072 1073 1074/** 1075* parses an XML Schema, allows access to it's data, other utility methods. 1076* imperfect, no validation... yet, but quite functional. 1077* 1078* @author Dietrich Ayala <dietrich@ganx4.com> 1079* @author Scott Nichol <snichol@users.sourceforge.net> 1080* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 1081* @access public 1082*/ 1083class nusoap_xmlschema extends nusoap_base { 1084 1085 // files 1086 var $schema = ''; 1087 var $xml = ''; 1088 // namespaces 1089 var $enclosingNamespaces; 1090 // schema info 1091 var $schemaInfo = array(); 1092 var $schemaTargetNamespace = ''; 1093 // types, elements, attributes defined by the schema 1094 var $attributes = array(); 1095 var $complexTypes = array(); 1096 var $complexTypeStack = array(); 1097 var $currentComplexType = null; 1098 var $elements = array(); 1099 var $elementStack = array(); 1100 var $currentElement = null; 1101 var $simpleTypes = array(); 1102 var $simpleTypeStack = array(); 1103 var $currentSimpleType = null; 1104 // imports 1105 var $imports = array(); 1106 // parser vars 1107 var $parser; 1108 var $position = 0; 1109 var $depth = 0; 1110 var $depth_array = array(); 1111 var $message = array(); 1112 var $defaultNamespace = array(); 1113 1114 /** 1115 * constructor 1116 * 1117 * @param string $schema schema document URI 1118 * @param string $xml xml document URI 1119 * @param string $namespaces namespaces defined in enclosing XML 1120 * @access public 1121 */ 1122 function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ 1123 parent::nusoap_base(); 1124 $this->debug('nusoap_xmlschema class instantiated, inside constructor'); 1125 // files 1126 $this->schema = $schema; 1127 $this->xml = $xml; 1128 1129 // namespaces 1130 $this->enclosingNamespaces = $namespaces; 1131 $this->namespaces = array_merge($this->namespaces, $namespaces); 1132 1133 // parse schema file 1134 if($schema != ''){ 1135 $this->debug('initial schema file: '.$schema); 1136 $this->parseFile($schema, 'schema'); 1137 } 1138 1139 // parse xml file 1140 if($xml != ''){ 1141 $this->debug('initial xml file: '.$xml); 1142 $this->parseFile($xml, 'xml'); 1143 } 1144 1145 } 1146 1147 /** 1148 * parse an XML file 1149 * 1150 * @param string $xml path/URL to XML file 1151 * @param string $type (schema | xml) 1152 * @return boolean 1153 * @access public 1154 */ 1155 function parseFile($xml,$type){ 1156 // parse xml file 1157 if($xml != ""){ 1158 $xmlStr = @join("",@file($xml)); 1159 if($xmlStr == ""){ 1160 $msg = 'Error reading XML from '.$xml; 1161 $this->setError($msg); 1162 $this->debug($msg); 1163 return false; 1164 } else { 1165 $this->debug("parsing $xml"); 1166 $this->parseString($xmlStr,$type); 1167 $this->debug("done parsing $xml"); 1168 return true; 1169 } 1170 } 1171 return false; 1172 } 1173 1174 /** 1175 * parse an XML string 1176 * 1177 * @param string $xml path or URL 1178 * @param string $type (schema|xml) 1179 * @access private 1180 */ 1181 function parseString($xml,$type){ 1182 // parse xml string 1183 if($xml != ""){ 1184 1185 // Create an XML parser. 1186 $this->parser = xml_parser_create(); 1187 // Set the options for parsing the XML data. 1188 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 1189 1190 // Set the object for the parser. 1191 xml_set_object($this->parser, $this); 1192 1193 // Set the element handlers for the parser. 1194 if($type == "schema"){ 1195 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); 1196 xml_set_character_data_handler($this->parser,'schemaCharacterData'); 1197 } elseif($type == "xml"){ 1198 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); 1199 xml_set_character_data_handler($this->parser,'xmlCharacterData'); 1200 } 1201 1202 // Parse the XML file. 1203 if(!xml_parse($this->parser,$xml,true)){ 1204 // Display an error message. 1205 $errstr = sprintf('XML error parsing XML schema on line %d: %s', 1206 xml_get_current_line_number($this->parser), 1207 xml_error_string(xml_get_error_code($this->parser)) 1208 ); 1209 $this->debug($errstr); 1210 $this->debug("XML payload:\n" . $xml); 1211 $this->setError($errstr); 1212 } 1213 1214 xml_parser_free($this->parser); 1215 } else{ 1216 $this->debug('no xml passed to parseString()!!'); 1217 $this->setError('no xml passed to parseString()!!'); 1218 } 1219 } 1220 1221 /** 1222 * gets a type name for an unnamed type 1223 * 1224 * @param string Element name 1225 * @return string A type name for an unnamed type 1226 * @access private 1227 */ 1228 function CreateTypeName($ename) { 1229 $scope = ''; 1230 for ($i = 0; $i < count($this->complexTypeStack); $i++) { 1231 $scope .= $this->complexTypeStack[$i] . '_'; 1232 } 1233 return $scope . $ename . '_ContainedType'; 1234 } 1235 1236 /** 1237 * start-element handler 1238 * 1239 * @param string $parser XML parser object 1240 * @param string $name element name 1241 * @param string $attrs associative array of attributes 1242 * @access private 1243 */ 1244 function schemaStartElement($parser, $name, $attrs) { 1245 1246 // position in the total number of elements, starting from 0 1247 $pos = $this->position++; 1248 $depth = $this->depth++; 1249 // set self as current value for this depth 1250 $this->depth_array[$depth] = $pos; 1251 $this->message[$pos] = array('cdata' => ''); 1252 if ($depth > 0) { 1253 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; 1254 } else { 1255 $this->defaultNamespace[$pos] = false; 1256 } 1257 1258 // get element prefix 1259 if($prefix = $this->getPrefix($name)){ 1260 // get unqualified name 1261 $name = $this->getLocalPart($name); 1262 } else { 1263 $prefix = ''; 1264 } 1265 1266 // loop thru attributes, expanding, and registering namespace declarations 1267 if(count($attrs) > 0){ 1268 foreach($attrs as $k => $v){ 1269 // if ns declarations, add to class level array of valid namespaces 1270 if(ereg("^xmlns",$k)){ 1271 //$this->xdebug("$k: $v"); 1272 //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); 1273 if($ns_prefix = substr(strrchr($k,':'),1)){ 1274 //$this->xdebug("Add namespace[$ns_prefix] = $v"); 1275 $this->namespaces[$ns_prefix] = $v; 1276 } else { 1277 $this->defaultNamespace[$pos] = $v; 1278 if (! $this->getPrefixFromNamespace($v)) { 1279 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; 1280 } 1281 } 1282 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ 1283 $this->XMLSchemaVersion = $v; 1284 $this->namespaces['xsi'] = $v.'-instance'; 1285 } 1286 } 1287 } 1288 foreach($attrs as $k => $v){ 1289 // expand each attribute 1290 $k = strpos($k,':') ? $this->expandQname($k) : $k; 1291 $v = strpos($v,':') ? $this->expandQname($v) : $v; 1292 $eAttrs[$k] = $v; 1293 } 1294 $attrs = $eAttrs; 1295 } else { 1296 $attrs = array(); 1297 } 1298 // find status, register data 1299 switch($name){ 1300 case 'all': // (optional) compositor content for a complexType 1301 case 'choice': 1302 case 'group': 1303 case 'sequence': 1304 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); 1305 $this->complexTypes[$this->currentComplexType]['compositor'] = $name; 1306 //if($name == 'all' || $name == 'sequence'){ 1307 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 1308 //} 1309 break; 1310 case 'attribute': // complexType attribute 1311 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); 1312 $this->xdebug("parsing attribute:"); 1313 $this->appendDebug($this->varDump($attrs)); 1314 if (!isset($attrs['form'])) { 1315 $attrs['form'] = $this->schemaInfo['attributeFormDefault']; 1316 } 1317 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 1318 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 1319 if (!strpos($v, ':')) { 1320 // no namespace in arrayType attribute value... 1321 if ($this->defaultNamespace[$pos]) { 1322 // ...so use the default 1323 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 1324 } 1325 } 1326 } 1327 if(isset($attrs['name'])){ 1328 $this->attributes[$attrs['name']] = $attrs; 1329 $aname = $attrs['name']; 1330 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ 1331 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 1332 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 1333 } else { 1334 $aname = ''; 1335 } 1336 } elseif(isset($attrs['ref'])){ 1337 $aname = $attrs['ref']; 1338 $this->attributes[$attrs['ref']] = $attrs; 1339 } 1340 1341 if($this->currentComplexType){ // This should *always* be 1342 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; 1343 } 1344 // arrayType attribute 1345 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ 1346 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 1347 $prefix = $this->getPrefix($aname); 1348 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ 1349 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 1350 } else { 1351 $v = ''; 1352 } 1353 if(strpos($v,'[,]')){ 1354 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; 1355 } 1356 $v = substr($v,0,strpos($v,'[')); // clip the [] 1357 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ 1358 $v = $this->XMLSchemaVersion.':'.$v; 1359 } 1360 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; 1361 } 1362 break; 1363 case 'complexContent': // (optional) content for a complexType 1364 break; 1365 case 'complexType': 1366 array_push($this->complexTypeStack, $this->currentComplexType); 1367 if(isset($attrs['name'])){ 1368 // TODO: what is the scope of named complexTypes that appear 1369 // nested within other c complexTypes? 1370 $this->xdebug('processing named complexType '.$attrs['name']); 1371 //$this->currentElement = false; 1372 $this->currentComplexType = $attrs['name']; 1373 $this->complexTypes[$this->currentComplexType] = $attrs; 1374 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 1375 // This is for constructs like 1376 // <complexType name="ListOfString" base="soap:Array"> 1377 // <sequence> 1378 // <element name="string" type="xsd:string" 1379 // minOccurs="0" maxOccurs="unbounded" /> 1380 // </sequence> 1381 // </complexType> 1382 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 1383 $this->xdebug('complexType is unusual array'); 1384 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 1385 } else { 1386 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 1387 } 1388 } else { 1389 $name = $this->CreateTypeName($this->currentElement); 1390 $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); 1391 $this->currentComplexType = $name; 1392 //$this->currentElement = false; 1393 $this->complexTypes[$this->currentComplexType] = $attrs; 1394 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 1395 // This is for constructs like 1396 // <complexType name="ListOfString" base="soap:Array"> 1397 // <sequence> 1398 // <element name="string" type="xsd:string" 1399 // minOccurs="0" maxOccurs="unbounded" /> 1400 // </sequence> 1401 // </complexType> 1402 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 1403 $this->xdebug('complexType is unusual array'); 1404 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 1405 } else { 1406 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 1407 } 1408 } 1409 break; 1410 case 'element': 1411 array_push($this->elementStack, $this->currentElement); 1412 if (!isset($attrs['form'])) { 1413 $attrs['form'] = $this->schemaInfo['elementFormDefault']; 1414 } 1415 if(isset($attrs['type'])){ 1416 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); 1417 if (! $this->getPrefix($attrs['type'])) { 1418 if ($this->defaultNamespace[$pos]) { 1419 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; 1420 $this->xdebug('used default namespace to make type ' . $attrs['type']); 1421 } 1422 } 1423 // This is for constructs like 1424 // <complexType name="ListOfString" base="soap:Array"> 1425 // <sequence> 1426 // <element name="string" type="xsd:string" 1427 // minOccurs="0" maxOccurs="unbounded" /> 1428 // </sequence> 1429 // </complexType> 1430 if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { 1431 $this->xdebug('arrayType for unusual array is ' . $attrs['type']); 1432 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; 1433 } 1434 $this->currentElement = $attrs['name']; 1435 $ename = $attrs['name']; 1436 } elseif(isset($attrs['ref'])){ 1437 $this->xdebug("processing element as ref to ".$attrs['ref']); 1438 $this->currentElement = "ref to ".$attrs['ref']; 1439 $ename = $this->getLocalPart($attrs['ref']); 1440 } else { 1441 $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); 1442 $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); 1443 $this->currentElement = $attrs['name']; 1444 $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; 1445 $ename = $attrs['name']; 1446 } 1447 if (isset($ename) && $this->currentComplexType) { 1448 $this->xdebug("add element $ename to complexType $this->currentComplexType"); 1449 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; 1450 } elseif (!isset($attrs['ref'])) { 1451 $this->xdebug("add element $ename to elements array"); 1452 $this->elements[ $attrs['name'] ] = $attrs; 1453 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 1454 } 1455 break; 1456 case 'enumeration': // restriction value list member 1457 $this->xdebug('enumeration ' . $attrs['value']); 1458 if ($this->currentSimpleType) { 1459 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; 1460 } elseif ($this->currentComplexType) { 1461 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; 1462 } 1463 break; 1464 case 'extension': // simpleContent or complexContent type extension 1465 $this->xdebug('extension ' . $attrs['base']); 1466 if ($this->currentComplexType) { 1467 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; 1468 } 1469 break; 1470 case 'import': 1471 if (isset($attrs['schemaLocation'])) { 1472 //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); 1473 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 1474 } else { 1475 //$this->xdebug('import namespace ' . $attrs['namespace']); 1476 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 1477 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 1478 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 1479 } 1480 } 1481 break; 1482 case 'list': // simpleType value list 1483 break; 1484 case 'restriction': // simpleType, simpleContent or complexContent value restriction 1485 $this->xdebug('restriction ' . $attrs['base']); 1486 if($this->currentSimpleType){ 1487 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; 1488 } elseif($this->currentComplexType){ 1489 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; 1490 if(strstr($attrs['base'],':') == ':Array'){ 1491 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 1492 } 1493 } 1494 break; 1495 case 'schema': 1496 $this->schemaInfo = $attrs; 1497 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); 1498 if (isset($attrs['targetNamespace'])) { 1499 $this->schemaTargetNamespace = $attrs['targetNamespace']; 1500 } 1501 if (!isset($attrs['elementFormDefault'])) { 1502 $this->schemaInfo['elementFormDefault'] = 'unqualified'; 1503 } 1504 if (!isset($attrs['attributeFormDefault'])) { 1505 $this->schemaInfo['attributeFormDefault'] = 'unqualified'; 1506 } 1507 break; 1508 case 'simpleContent': // (optional) content for a complexType 1509 break; 1510 case 'simpleType': 1511 array_push($this->simpleTypeStack, $this->currentSimpleType); 1512 if(isset($attrs['name'])){ 1513 $this->xdebug("processing simpleType for name " . $attrs['name']); 1514 $this->currentSimpleType = $attrs['name']; 1515 $this->simpleTypes[ $attrs['name'] ] = $attrs; 1516 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; 1517 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; 1518 } else { 1519 $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); 1520 $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); 1521 $this->currentSimpleType = $name; 1522 //$this->currentElement = false; 1523 $this->simpleTypes[$this->currentSimpleType] = $attrs; 1524 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; 1525 } 1526 break; 1527 case 'union': // simpleType type list 1528 break; 1529 default: 1530 //$this->xdebug("do not have anything to do for element $name"); 1531 } 1532 } 1533 1534 /** 1535 * end-element handler 1536 * 1537 * @param string $parser XML parser object 1538 * @param string $name element name 1539 * @access private 1540 */ 1541 function schemaEndElement($parser, $name) { 1542 // bring depth down a notch 1543 $this->depth--; 1544 // position of current element is equal to the last value left in depth_array for my depth 1545 if(isset($this->depth_array[$this->depth])){ 1546 $pos = $this->depth_array[$this->depth]; 1547 } 1548 // get element prefix 1549 if ($prefix = $this->getPrefix($name)){ 1550 // get unqualified name 1551 $name = $this->getLocalPart($name); 1552 } else { 1553 $prefix = ''; 1554 } 1555 // move on... 1556 if($name == 'complexType'){ 1557 $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); 1558 $this->currentComplexType = array_pop($this->complexTypeStack); 1559 //$this->currentElement = false; 1560 } 1561 if($name == 'element'){ 1562 $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); 1563 $this->currentElement = array_pop($this->elementStack); 1564 } 1565 if($name == 'simpleType'){ 1566 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); 1567 $this->currentSimpleType = array_pop($this->simpleTypeStack); 1568 } 1569 } 1570 1571 /** 1572 * element content handler 1573 * 1574 * @param string $parser XML parser object 1575 * @param string $data element content 1576 * @access private 1577 */ 1578 function schemaCharacterData($parser, $data){ 1579 $pos = $this->depth_array[$this->depth - 1]; 1580 $this->message[$pos]['cdata'] .= $data; 1581 } 1582 1583 /** 1584 * serialize the schema 1585 * 1586 * @access public 1587 */ 1588 function serializeSchema(){ 1589 1590 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); 1591 $xml = ''; 1592 // imports 1593 if (sizeof($this->imports) > 0) { 1594 foreach($this->imports as $ns => $list) { 1595 foreach ($list as $ii) { 1596 if ($ii['location'] != '') { 1597 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; 1598 } else { 1599 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; 1600 } 1601 } 1602 } 1603 } 1604 // complex types 1605 foreach($this->complexTypes as $typeName => $attrs){ 1606 $contentStr = ''; 1607 // serialize child elements 1608 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ 1609 foreach($attrs['elements'] as $element => $eParts){ 1610 if(isset($eParts['ref'])){ 1611 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; 1612 } else { 1613 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; 1614 foreach ($eParts as $aName => $aValue) { 1615 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable 1616 if ($aName != 'name' && $aName != 'type') { 1617 $contentStr .= " $aName=\"$aValue\""; 1618 } 1619 } 1620 $contentStr .= "/>\n"; 1621 } 1622 } 1623 // compositor wraps elements 1624 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { 1625 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; 1626 } 1627 } 1628 // attributes 1629 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ 1630 foreach($attrs['attrs'] as $attr => $aParts){ 1631 $contentStr .= " <$schemaPrefix:attribute"; 1632 foreach ($aParts as $a => $v) { 1633 if ($a == 'ref' || $a == 'type') { 1634 $contentStr .= " $a=\"".$this->contractQName($v).'"'; 1635 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { 1636 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; 1637 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; 1638 } else { 1639 $contentStr .= " $a=\"$v\""; 1640 } 1641 } 1642 $contentStr .= "/>\n"; 1643 } 1644 } 1645 // if restriction 1646 if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ 1647 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; 1648 // complex or simple content 1649 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ 1650 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; 1651 } 1652 } 1653 // finalize complex type 1654 if($contentStr != ''){ 1655 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; 1656 } else { 1657 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; 1658 } 1659 $xml .= $contentStr; 1660 } 1661 // simple types 1662 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ 1663 foreach($this->simpleTypes as $typeName => $eParts){ 1664 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; 1665 if (isset($eParts['enumeration'])) { 1666 foreach ($eParts['enumeration'] as $e) { 1667 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; 1668 } 1669 } 1670 $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>"; 1671 } 1672 } 1673 // elements 1674 if(isset($this->elements) && count($this->elements) > 0){ 1675 foreach($this->elements as $element => $eParts){ 1676 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; 1677 } 1678 } 1679 // attributes 1680 if(isset($this->attributes) && count($this->attributes) > 0){ 1681 foreach($this->attributes as $attr => $aParts){ 1682 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; 1683 } 1684 } 1685 // finish 'er up 1686 $attr = ''; 1687 foreach ($this->schemaInfo as $k => $v) { 1688 if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { 1689 $attr .= " $k=\"$v\""; 1690 } 1691 } 1692 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; 1693 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { 1694 $el .= " xmlns:$nsp=\"$ns\""; 1695 } 1696 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; 1697 return $xml; 1698 } 1699 1700 /** 1701 * adds debug data to the clas level debug string 1702 * 1703 * @param string $string debug data 1704 * @access private 1705 */ 1706 function xdebug($string){ 1707 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); 1708 } 1709 1710 /** 1711 * get the PHP type of a user defined type in the schema 1712 * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays 1713 * returns false if no type exists, or not w/ the given namespace 1714 * else returns a string that is either a native php type, or 'struct' 1715 * 1716 * @param string $type name of defined type 1717 * @param string $ns namespace of type 1718 * @return mixed 1719 * @access public 1720 * @deprecated 1721 */ 1722 function getPHPType($type,$ns){ 1723 if(isset($this->typemap[$ns][$type])){ 1724 //print "found type '$type' and ns $ns in typemap<br>"; 1725 return $this->typemap[$ns][$type]; 1726 } elseif(isset($this->complexTypes[$type])){ 1727 //print "getting type '$type' and ns $ns from complexTypes array<br>"; 1728 return $this->complexTypes[$type]['phpType']; 1729 } 1730 return false; 1731 } 1732 1733 /** 1734 * returns an associative array of information about a given type 1735 * returns false if no type exists by the given name 1736 * 1737 * For a complexType typeDef = array( 1738 * 'restrictionBase' => '', 1739 * 'phpType' => '', 1740 * 'compositor' => '(sequence|all)', 1741 * 'elements' => array(), // refs to elements array 1742 * 'attrs' => array() // refs to attributes array 1743 * ... and so on (see addComplexType) 1744 * ) 1745 * 1746 * For simpleType or element, the array has different keys. 1747 * 1748 * @param string $type 1749 * @return mixed 1750 * @access public 1751 * @see addComplexType 1752 * @see addSimpleType 1753 * @see addElement 1754 */ 1755 function getTypeDef($type){ 1756 //$this->debug("in getTypeDef for type $type"); 1757 if (substr($type, -1) == '^') { 1758 $is_element = 1; 1759 $type = substr($type, 0, -1); 1760 } else { 1761 $is_element = 0; 1762 } 1763 1764 if((! $is_element) && isset($this->complexTypes[$type])){ 1765 $this->xdebug("in getTypeDef, found complexType $type"); 1766 return $this->complexTypes[$type]; 1767 } elseif((! $is_element) && isset($this->simpleTypes[$type])){ 1768 $this->xdebug("in getTypeDef, found simpleType $type"); 1769 if (!isset($this->simpleTypes[$type]['phpType'])) { 1770 // get info for type to tack onto the simple type 1771 // TODO: can this ever really apply (i.e. what is a simpleType really?) 1772 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); 1773 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); 1774 $etype = $this->getTypeDef($uqType); 1775 if ($etype) { 1776 $this->xdebug("in getTypeDef, found type for simpleType $type:"); 1777 $this->xdebug($this->varDump($etype)); 1778 if (isset($etype['phpType'])) { 1779 $this->simpleTypes[$type]['phpType'] = $etype['phpType']; 1780 } 1781 if (isset($etype['elements'])) { 1782 $this->simpleTypes[$type]['elements'] = $etype['elements']; 1783 } 1784 } 1785 } 1786 return $this->simpleTypes[$type]; 1787 } elseif(isset($this->elements[$type])){ 1788 $this->xdebug("in getTypeDef, found element $type"); 1789 if (!isset($this->elements[$type]['phpType'])) { 1790 // get info for type to tack onto the element 1791 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); 1792 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); 1793 $etype = $this->getTypeDef($uqType); 1794 if ($etype) { 1795 $this->xdebug("in getTypeDef, found type for element $type:"); 1796 $this->xdebug($this->varDump($etype)); 1797 if (isset($etype['phpType'])) { 1798 $this->elements[$type]['phpType'] = $etype['phpType']; 1799 } 1800 if (isset($etype['elements'])) { 1801 $this->elements[$type]['elements'] = $etype['elements']; 1802 } 1803 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { 1804 $this->xdebug("in getTypeDef, element $type is an XSD type"); 1805 $this->elements[$type]['phpType'] = 'scalar'; 1806 } 1807 } 1808 return $this->elements[$type]; 1809 } elseif(isset($this->attributes[$type])){ 1810 $this->xdebug("in getTypeDef, found attribute $type"); 1811 return $this->attributes[$type]; 1812 } elseif (ereg('_ContainedType$', $type)) { 1813 $this->xdebug("in getTypeDef, have an untyped element $type"); 1814 $typeDef['typeClass'] = 'simpleType'; 1815 $typeDef['phpType'] = 'scalar'; 1816 $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; 1817 return $typeDef; 1818 } 1819 $this->xdebug("in getTypeDef, did not find $type"); 1820 return false; 1821 } 1822 1823 /** 1824 * returns a sample serialization of a given type, or false if no type by the given name 1825 * 1826 * @param string $type name of type 1827 * @return mixed 1828 * @access public 1829 * @deprecated 1830 */ 1831 function serializeTypeDef($type){ 1832 //print "in sTD() for type $type<br>"; 1833 if($typeDef = $this->getTypeDef($type)){ 1834 $str .= '<'.$type; 1835 if(is_array($typeDef['attrs'])){ 1836 foreach($typeDef['attrs'] as $attName => $data){ 1837 $str .= " $attName=\"{type = ".$data['type']."}\""; 1838 } 1839 } 1840 $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; 1841 if(count($typeDef['elements']) > 0){ 1842 $str .= ">"; 1843 foreach($typeDef['elements'] as $element => $eData){ 1844 $str .= $this->serializeTypeDef($element); 1845 } 1846 $str .= "</$type>"; 1847 } elseif($typeDef['typeClass'] == 'element') { 1848 $str .= "></$type>"; 1849 } else { 1850 $str .= "/>"; 1851 } 1852 return $str; 1853 } 1854 return false; 1855 } 1856 1857 /** 1858 * returns HTML form elements that allow a user 1859 * to enter values for creating an instance of the given type. 1860 * 1861 * @param string $name name for type instance 1862 * @param string $type name of type 1863 * @return string 1864 * @access public 1865 * @deprecated 1866 */ 1867 function typeToForm($name,$type){ 1868 // get typedef 1869 if($typeDef = $this->getTypeDef($type)){ 1870 // if struct 1871 if($typeDef['phpType'] == 'struct'){ 1872 $buffer .= '<table>'; 1873 foreach($typeDef['elements'] as $child => $childDef){ 1874 $buffer .= " 1875 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> 1876 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; 1877 } 1878 $buffer .= '</table>'; 1879 // if array 1880 } elseif($typeDef['phpType'] == 'array'){ 1881 $buffer .= '<table>'; 1882 for($i=0;$i < 3; $i++){ 1883 $buffer .= " 1884 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> 1885 <td><input type='text' name='parameters[".$name."][]'></td></tr>"; 1886 } 1887 $buffer .= '</table>'; 1888 // if scalar 1889 } else { 1890 $buffer .= "<input type='text' name='parameters[$name]'>"; 1891 } 1892 } else { 1893 $buffer .= "<input type='text' name='parameters[$name]'>"; 1894 } 1895 return $buffer; 1896 } 1897 1898 /** 1899 * adds a complex type to the schema 1900 * 1901 * example: array 1902 * 1903 * addType( 1904 * 'ArrayOfstring', 1905 * 'complexType', 1906 * 'array', 1907 * '', 1908 * 'SOAP-ENC:Array', 1909 * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), 1910 * 'xsd:string' 1911 * ); 1912 * 1913 * example: PHP associative array ( SOAP Struct ) 1914 * 1915 * addType( 1916 * 'SOAPStruct', 1917 * 'complexType', 1918 * 'struct', 1919 * 'all', 1920 * array('myVar'=> array('name'=>'myVar','type'=>'string') 1921 * ); 1922 * 1923 * @param name 1924 * @param typeClass (complexType|simpleType|attribute) 1925 * @param phpType: currently supported are array and struct (php assoc array) 1926 * @param compositor (all|sequence|choice) 1927 * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 1928 * @param elements = array ( name = array(name=>'',type=>'') ) 1929 * @param attrs = array( 1930 * array( 1931 * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", 1932 * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" 1933 * ) 1934 * ) 1935 * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) 1936 * @access public 1937 * @see getTypeDef 1938 */ 1939 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ 1940 $this->complexTypes[$name] = array( 1941 'name' => $name, 1942 'typeClass' => $typeClass, 1943 'phpType' => $phpType, 1944 'compositor'=> $compositor, 1945 'restrictionBase' => $restrictionBase, 1946 'elements' => $elements, 1947 'attrs' => $attrs, 1948 'arrayType' => $arrayType 1949 ); 1950 1951 $this->xdebug("addComplexType $name:"); 1952 $this->appendDebug($this->varDump($this->complexTypes[$name])); 1953 } 1954 1955 /** 1956 * adds a simple type to the schema 1957 * 1958 * @param string $name 1959 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 1960 * @param string $typeClass (should always be simpleType) 1961 * @param string $phpType (should always be scalar) 1962 * @param array $enumeration array of values 1963 * @access public 1964 * @see nusoap_xmlschema 1965 * @see getTypeDef 1966 */ 1967 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 1968 $this->simpleTypes[$name] = array( 1969 'name' => $name, 1970 'typeClass' => $typeClass, 1971 'phpType' => $phpType, 1972 'type' => $restrictionBase, 1973 'enumeration' => $enumeration 1974 ); 1975 1976 $this->xdebug("addSimpleType $name:"); 1977 $this->appendDebug($this->varDump($this->simpleTypes[$name])); 1978 } 1979 1980 /** 1981 * adds an element to the schema 1982 * 1983 * @param array $attrs attributes that must include name and type 1984 * @see nusoap_xmlschema 1985 * @access public 1986 */ 1987 function addElement($attrs) { 1988 if (! $this->getPrefix($attrs['type'])) { 1989 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; 1990 } 1991 $this->elements[ $attrs['name'] ] = $attrs; 1992 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 1993 1994 $this->xdebug("addElement " . $attrs['name']); 1995 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); 1996 } 1997} 1998 1999/** 2000 * Backward compatibility 2001 */ 2002class XMLSchema extends nusoap_xmlschema { 2003} 2004 2005?><?php 2006 2007 2008 2009/** 2010* For creating serializable abstractions of native PHP types. This class 2011* allows element name/namespace, XSD type, and XML attributes to be 2012* associated with a value. This is extremely useful when WSDL is not 2013* used, but is also useful when WSDL is used with polymorphic types, including 2014* xsd:anyType and user-defined types. 2015* 2016* @author Dietrich Ayala <dietrich@ganx4.com> 2017* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 2018* @access public 2019*/ 2020class soapval extends nusoap_base { 2021 /** 2022 * The XML element name 2023 * 2024 * @var string 2025 * @access private 2026 */ 2027 var $name; 2028 /** 2029 * The XML type name (string or false) 2030 * 2031 * @var mixed 2032 * @access private 2033 */ 2034 var $type; 2035 /** 2036 * The PHP value 2037 * 2038 * @var mixed 2039 * @access private 2040 */ 2041 var $value; 2042 /** 2043 * The XML element namespace (string or false) 2044 * 2045 * @var mixed 2046 * @access private 2047 */ 2048 var $element_ns; 2049 /** 2050 * The XML type namespace (string or false) 2051 * 2052 * @var mixed 2053 * @access private 2054 */ 2055 var $type_ns; 2056 /** 2057 * The XML element attributes (array or false) 2058 * 2059 * @var mixed 2060 * @access private 2061 */ 2062 var $attributes; 2063 2064 /** 2065 * constructor 2066 * 2067 * @param string $name optional name 2068 * @param mixed $type optional type name 2069 * @param mixed $value optional value 2070 * @param mixed $element_ns optional namespace of value 2071 * @param mixed $type_ns optional namespace of type 2072 * @param mixed $attributes associative array of attributes to add to element serialization 2073 * @access public 2074 */ 2075 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { 2076 parent::nusoap_base(); 2077 $this->name = $name; 2078 $this->type = $type; 2079 $this->value = $value; 2080 $this->element_ns = $element_ns; 2081 $this->type_ns = $type_ns; 2082 $this->attributes = $attributes; 2083 } 2084 2085 /** 2086 * return serialized value 2087 * 2088 * @param string $use The WSDL use value (encoded|literal) 2089 * @return string XML data 2090 * @access public 2091 */ 2092 function serialize($use='encoded') { 2093 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); 2094 } 2095 2096 /** 2097 * decodes a soapval object into a PHP native type 2098 * 2099 * @return mixed 2100 * @access public 2101 */ 2102 function decode(){ 2103 return $this->value; 2104 } 2105} 2106 2107 2108 2109?><?php 2110 2111 2112 2113/** 2114* transport class for sending/receiving data via HTTP and HTTPS 2115* NOTE: PHP must be compiled with the CURL extension for HTTPS support 2116* 2117* @author Dietrich Ayala <dietrich@ganx4.com> 2118* @author Scott Nichol <snichol@users.sourceforge.net> 2119* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 2120* @access public 2121*/ 2122class soap_transport_http extends nusoap_base { 2123 2124 var $url = ''; 2125 var $uri = ''; 2126 var $digest_uri = ''; 2127 var $scheme = ''; 2128 var $host = ''; 2129 var $port = ''; 2130 var $path = ''; 2131 var $request_method = 'POST'; 2132 var $protocol_version = '1.0'; 2133 var $encoding = ''; 2134 var $outgoing_headers = array(); 2135 var $incoming_headers = array(); 2136 var $incoming_cookies = array(); 2137 var $outgoing_payload = ''; 2138 var $incoming_payload = ''; 2139 var $response_status_line; // HTTP response status line 2140 var $useSOAPAction = true; 2141 var $persistentConnection = false; 2142 var $ch = false; // cURL handle 2143 var $ch_options = array(); // cURL custom options 2144 var $use_curl = false; // force cURL use 2145 var $proxy = null; // proxy information (associative array) 2146 var $username = ''; 2147 var $password = ''; 2148 var $authtype = ''; 2149 var $digestRequest = array(); 2150 var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) 2151 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' 2152 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' 2153 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' 2154 // passphrase: SSL key password/passphrase 2155 // certpassword: SSL certificate password 2156 // verifypeer: default is 1 2157 // verifyhost: default is 1 2158 2159 /** 2160 * constructor 2161 * 2162 * @param string $url The URL to which to connect 2163 * @param array $curl_options User-specified cURL options 2164 * @param boolean $use_curl Whether to try to force cURL use 2165 * @access public 2166 */ 2167 function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ 2168 parent::nusoap_base(); 2169 $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); 2170 $this->appendDebug($this->varDump($curl_options)); 2171 $this->setURL($url); 2172 if (is_array($curl_options)) { 2173 $this->ch_options = $curl_options; 2174 } 2175 $this->use_curl = $use_curl; 2176 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 2177 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); 2178 } 2179 2180 /** 2181 * sets a cURL option 2182 * 2183 * @param mixed $option The cURL option (always integer?) 2184 * @param mixed $value The cURL option value 2185 * @access private 2186 */ 2187 function setCurlOption($option, $value) { 2188 $this->debug("setCurlOption option=$option, value="); 2189 $this->appendDebug($this->varDump($value)); 2190 curl_setopt($this->ch, $option, $value); 2191 } 2192 2193 /** 2194 * sets an HTTP header 2195 * 2196 * @param string $name The name of the header 2197 * @param string $value The value of the header 2198 * @access private 2199 */ 2200 function setHeader($name, $value) { 2201 $this->outgoing_headers[$name] = $value; 2202 $this->debug("set header $name: $value"); 2203 } 2204 2205 /** 2206 * unsets an HTTP header 2207 * 2208 * @param string $name The name of the header 2209 * @access private 2210 */ 2211 function unsetHeader($name) { 2212 if (isset($this->outgoing_headers[$name])) { 2213 $this->debug("unset header $name"); 2214 unset($this->outgoing_headers[$name]); 2215 } 2216 } 2217 2218 /** 2219 * sets the URL to which to connect 2220 * 2221 * @param string $url The URL to which to connect 2222 * @access private 2223 */ 2224 function setURL($url) { 2225 $this->url = $url; 2226 2227 $u = parse_url($url); 2228 foreach($u as $k => $v){ 2229 $this->debug("parsed URL $k = $v"); 2230 $this->$k = $v; 2231 } 2232 2233 // add any GET params to path 2234 if(isset($u['query']) && $u['query'] != ''){ 2235 $this->path .= '?' . $u['query']; 2236 } 2237 2238 // set default port 2239 if(!isset($u['port'])){ 2240 if($u['scheme'] == 'https'){ 2241 $this->port = 443; 2242 } else { 2243 $this->port = 80; 2244 } 2245 } 2246 2247 $this->uri = $this->path; 2248 $this->digest_uri = $this->uri; 2249 2250 // build headers 2251 if (!isset($u['port'])) { 2252 $this->setHeader('Host', $this->host); 2253 } else { 2254 $this->setHeader('Host', $this->host.':'.$this->port); 2255 } 2256 2257 if (isset($u['user']) && $u['user'] != '') { 2258 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); 2259 } 2260 } 2261 2262 /** 2263 * gets the I/O method to use 2264 * 2265 * @return string I/O method to use (socket|curl|unknown) 2266 * @access private 2267 */ 2268 function io_method() { 2269 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) 2270 return 'curl'; 2271 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) 2272 return 'socket'; 2273 return 'unknown'; 2274 } 2275 2276 /** 2277 * establish an HTTP connection 2278 * 2279 * @param integer $timeout set connection timeout in seconds 2280 * @param integer $response_timeout set response timeout in seconds 2281 * @return boolean true if connected, false if not 2282 * @access private 2283 */ 2284 function connect($connection_timeout=0,$response_timeout=30){ 2285 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like 2286 // "regular" socket. 2287 // TODO: disabled for now because OpenSSL must be *compiled* in (not just 2288 // loaded), and until PHP5 stream_get_wrappers is not available. 2289// if ($this->scheme == 'https') { 2290// if (version_compare(phpversion(), '4.3.0') >= 0) { 2291// if (extension_loaded('openssl')) { 2292// $this->scheme = 'ssl'; 2293// $this->debug('Using SSL over OpenSSL'); 2294// } 2295// } 2296// } 2297 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); 2298 if ($this->io_method() == 'socket') { 2299 if (!is_array($this->proxy)) { 2300 $host = $this->host; 2301 $port = $this->port; 2302 } else { 2303 $host = $this->proxy['host']; 2304 $port = $this->proxy['port']; 2305 } 2306 2307 // use persistent connection 2308 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ 2309 if (!feof($this->fp)) { 2310 $this->debug('Re-use persistent connection'); 2311 return true; 2312 } 2313 fclose($this->fp); 2314 $this->debug('Closed persistent connection at EOF'); 2315 } 2316 2317 // munge host if using OpenSSL 2318 if ($this->scheme == 'ssl') { 2319 $host = 'ssl://' . $host; 2320 } 2321 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); 2322 2323 // open socket 2324 if($connection_timeout > 0){ 2325 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); 2326 } else { 2327 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); 2328 } 2329 2330 // test pointer 2331 if(!$this->fp) { 2332 $msg = 'Couldn\'t open socket connection to server ' . $this->url; 2333 if ($this->errno) { 2334 $msg .= ', Error ('.$this->errno.'): '.$this->error_str; 2335 } else { 2336 $msg .= ' prior to connect(). This is often a problem looking up the host name.'; 2337 } 2338 $this->debug($msg); 2339 $this->setError($msg); 2340 return false; 2341 } 2342 2343 // set response timeout 2344 $this->debug('set response timeout to ' . $response_timeout); 2345 socket_set_timeout( $this->fp, $response_timeout); 2346 2347 $this->debug('socket connected'); 2348 return true; 2349 } else if ($this->io_method() == 'curl') { 2350 if (!extension_loaded('curl')) { 2351// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); 2352 $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.'); 2353 return false; 2354 } 2355 // Avoid warnings when PHP does not have these options 2356 if (defined('CURLOPT_CONNECTIONTIMEOUT')) 2357 $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; 2358 else 2359 $CURLOPT_CONNECTIONTIMEOUT = 78; 2360 if (defined('CURLOPT_HTTPAUTH')) 2361 $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; 2362 else 2363 $CURLOPT_HTTPAUTH = 107; 2364 if (defined('CURLOPT_PROXYAUTH')) 2365 $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; 2366 else 2367 $CURLOPT_PROXYAUTH = 111; 2368 if (defined('CURLAUTH_BASIC')) 2369 $CURLAUTH_BASIC = CURLAUTH_BASIC; 2370 else 2371 $CURLAUTH_BASIC = 1; 2372 if (defined('CURLAUTH_DIGEST')) 2373 $CURLAUTH_DIGEST = CURLAUTH_DIGEST; 2374 else 2375 $CURLAUTH_DIGEST = 2; 2376 if (defined('CURLAUTH_NTLM')) 2377 $CURLAUTH_NTLM = CURLAUTH_NTLM; 2378 else 2379 $CURLAUTH_NTLM = 8; 2380 2381 $this->debug('connect using cURL'); 2382 // init CURL 2383 $this->ch = curl_init(); 2384 // set url 2385 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; 2386 // add path 2387 $hostURL .= $this->path; 2388 $this->setCurlOption(CURLOPT_URL, $hostURL); 2389 // follow location headers (re-directs) 2390 if (ini_get('safe_mode') || ini_get('open_basedir')) { 2391 $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); 2392 $this->debug('safe_mode = '); 2393 $this->appendDebug($this->varDump(ini_get('safe_mode'))); 2394 $this->debug('open_basedir = '); 2395 $this->appendDebug($this->varDump(ini_get('open_basedir'))); 2396 } else { 2397 $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); 2398 } 2399 // ask for headers in the response output 2400 $this->setCurlOption(CURLOPT_HEADER, 1); 2401 // ask for the response output as the return value 2402 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); 2403 // encode 2404 // We manage this ourselves through headers and encoding 2405// if(function_exists('gzuncompress')){ 2406// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); 2407// } 2408 // persistent connection 2409 if ($this->persistentConnection) { 2410 // I believe the following comment is now bogus, having applied to 2411 // the code when it used CURLOPT_CUSTOMREQUEST to send the request. 2412 // The way we send data, we cannot use persistent connections, since 2413 // there will be some "junk" at the end of our request. 2414 //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); 2415 $this->persistentConnection = false; 2416 $this->setHeader('Connection', 'close'); 2417 } 2418 // set timeouts 2419 if ($connection_timeout != 0) { 2420 $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); 2421 } 2422 if ($response_timeout != 0) { 2423 $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); 2424 } 2425 2426 if ($this->scheme == 'https') { 2427 $this->debug('set cURL SSL verify options'); 2428 // recent versions of cURL turn on peer/host checking by default, 2429 // while PHP binaries are not compiled with a default location for the 2430 // CA cert bundle, so disable peer/host checking. 2431 //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); 2432 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); 2433 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); 2434 2435 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) 2436 if ($this->authtype == 'certificate') { 2437 $this->debug('set cURL certificate options'); 2438 if (isset($this->certRequest['cainfofile'])) { 2439 $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); 2440 } 2441 if (isset($this->certRequest['verifypeer'])) { 2442 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); 2443 } else { 2444 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); 2445 } 2446 if (isset($this->certRequest['verifyhost'])) { 2447 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); 2448 } else { 2449 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); 2450 } 2451 if (isset($this->certRequest['sslcertfile'])) { 2452 $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); 2453 } 2454 if (isset($this->certRequest['sslkeyfile'])) { 2455 $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); 2456 } 2457 if (isset($this->certRequest['passphrase'])) { 2458 $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); 2459 } 2460 if (isset($this->certRequest['certpassword'])) { 2461 $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); 2462 } 2463 } 2464 } 2465 if ($this->authtype && ($this->authtype != 'certificate')) { 2466 if ($this->username) { 2467 $this->debug('set cURL username/password'); 2468 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); 2469 } 2470 if ($this->authtype == 'basic') { 2471 $this->debug('set cURL for Basic authentication'); 2472 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); 2473 } 2474 if ($this->authtype == 'digest') { 2475 $this->debug('set cURL for digest authentication'); 2476 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); 2477 } 2478 if ($this->authtype == 'ntlm') { 2479 $this->debug('set cURL for NTLM authentication'); 2480 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); 2481 } 2482 } 2483 if (is_array($this->proxy)) { 2484 $this->debug('set cURL proxy options'); 2485 if ($this->proxy['port'] != '') { 2486 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); 2487 } else { 2488 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); 2489 } 2490 if ($this->proxy['username'] || $this->proxy['password']) { 2491 $this->debug('set cURL proxy authentication options'); 2492 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); 2493 if ($this->proxy['authtype'] == 'basic') { 2494 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); 2495 } 2496 if ($this->proxy['authtype'] == 'ntlm') { 2497 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); 2498 } 2499 } 2500 } 2501 $this->debug('cURL connection set up'); 2502 return true; 2503 } else { 2504 $this->setError('Unknown scheme ' . $this->scheme); 2505 $this->debug('Unknown scheme ' . $this->scheme); 2506 return false; 2507 } 2508 } 2509 2510 /** 2511 * sends the SOAP request and gets the SOAP response via HTTP[S] 2512 * 2513 * @param string $data message data 2514 * @param integer $timeout set connection timeout in seconds 2515 * @param integer $response_timeout set response timeout in seconds 2516 * @param array $cookies cookies to send 2517 * @return string data 2518 * @access public 2519 */ 2520 function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { 2521 2522 $this->debug('entered send() with data of length: '.strlen($data)); 2523 2524 $this->tryagain = true; 2525 $tries = 0; 2526 while ($this->tryagain) { 2527 $this->tryagain = false; 2528 if ($tries++ < 2) { 2529 // make connnection 2530 if (!$this->connect($timeout, $response_timeout)){ 2531 return false; 2532 } 2533 2534 // send request 2535 if (!$this->sendRequest($data, $cookies)){ 2536 return false; 2537 } 2538 2539 // get response 2540 $respdata = $this->getResponse(); 2541 } else { 2542 $this->setError("Too many tries to get an OK response ($this->response_status_line)"); 2543 } 2544 } 2545 $this->debug('end of send()'); 2546 return $respdata; 2547 } 2548 2549 2550 /** 2551 * sends the SOAP request and gets the SOAP response via HTTPS using CURL 2552 * 2553 * @param string $data message data 2554 * @param integer $timeout set connection timeout in seconds 2555 * @param integer $response_timeout set response timeout in seconds 2556 * @param array $cookies cookies to send 2557 * @return string data 2558 * @access public 2559 * @deprecated 2560 */ 2561 function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { 2562 return $this->send($data, $timeout, $response_timeout, $cookies); 2563 } 2564 2565 /** 2566 * if authenticating, set user credentials here 2567 * 2568 * @param string $username 2569 * @param string $password 2570 * @param string $authtype (basic|digest|certificate|ntlm) 2571 * @param array $digestRequest (keys must be nonce, nc, realm, qop) 2572 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 2573 * @access public 2574 */ 2575 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { 2576 $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); 2577 $this->appendDebug($this->varDump($digestRequest)); 2578 $this->debug("certRequest="); 2579 $this->appendDebug($this->varDump($certRequest)); 2580 // cf. RFC 2617 2581 if ($authtype == 'basic') { 2582 $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); 2583 } elseif ($authtype == 'digest') { 2584 if (isset($digestRequest['nonce'])) { 2585 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; 2586 2587 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) 2588 2589 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd 2590 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; 2591 2592 // H(A1) = MD5(A1) 2593 $HA1 = md5($A1); 2594 2595 // A2 = Method ":" digest-uri-value 2596 $A2 = $this->request_method . ':' . $this->digest_uri; 2597 2598 // H(A2) 2599 $HA2 = md5($A2); 2600 2601 // KD(secret, data) = H(concat(secret, ":", data)) 2602 // if qop == auth: 2603 // request-digest = <"> < KD ( H(A1), unq(nonce-value) 2604 // ":" nc-value 2605 // ":" unq(cnonce-value) 2606 // ":" unq(qop-value) 2607 // ":" H(A2) 2608 // ) <"> 2609 // if qop is missing, 2610 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> 2611 2612 $unhashedDigest = ''; 2613 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; 2614 $cnonce = $nonce; 2615 if ($digestRequest['qop'] != '') { 2616 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; 2617 } else { 2618 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; 2619 } 2620 2621 $hashedDigest = md5($unhashedDigest); 2622 2623 $opaque = ''; 2624 if (isset($digestRequest['opaque'])) { 2625 $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; 2626 } 2627 2628 $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 . '"'); 2629 } 2630 } elseif ($authtype == 'certificate') { 2631 $this->certRequest = $certRequest; 2632 $this->debug('Authorization header not set for certificate'); 2633 } elseif ($authtype == 'ntlm') { 2634 // do nothing 2635 $this->debug('Authorization header not set for ntlm'); 2636 } 2637 $this->username = $username; 2638 $this->password = $password; 2639 $this->authtype = $authtype; 2640 $this->digestRequest = $digestRequest; 2641 } 2642 2643 /** 2644 * set the soapaction value 2645 * 2646 * @param string $soapaction 2647 * @access public 2648 */ 2649 function setSOAPAction($soapaction) { 2650 $this->setHeader('SOAPAction', '"' . $soapaction . '"'); 2651 } 2652 2653 /** 2654 * use http encoding 2655 * 2656 * @param string $enc encoding style. supported values: gzip, deflate, or both 2657 * @access public 2658 */ 2659 function setEncoding($enc='gzip, deflate') { 2660 if (function_exists('gzdeflate')) { 2661 $this->protocol_version = '1.1'; 2662 $this->setHeader('Accept-Encoding', $enc); 2663 if (!isset($this->outgoing_headers['Connection'])) { 2664 $this->setHeader('Connection', 'close'); 2665 $this->persistentConnection = false; 2666 } 2667 set_magic_quotes_runtime(0); 2668 // deprecated 2669 $this->encoding = $enc; 2670 } 2671 } 2672 2673 /** 2674 * set proxy info here 2675 * 2676 * @param string $proxyhost use an empty string to remove proxy 2677 * @param string $proxyport 2678 * @param string $proxyusername 2679 * @param string $proxypassword 2680 * @param string $proxyauthtype (basic|ntlm) 2681 * @access public 2682 */ 2683 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { 2684 if ($proxyhost) { 2685 $this->proxy = array( 2686 'host' => $proxyhost, 2687 'port' => $proxyport, 2688 'username' => $proxyusername, 2689 'password' => $proxypassword, 2690 'authtype' => $proxyauthtype 2691 ); 2692 if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { 2693 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); 2694 } 2695 } else { 2696 $this->debug('remove proxy'); 2697 $proxy = null; 2698 unsetHeader('Proxy-Authorization'); 2699 } 2700 } 2701 2702 2703 /** 2704 * Test if the given string starts with a header that is to be skipped. 2705 * Skippable headers result from chunked transfer and proxy requests. 2706 * 2707 * @param string $data The string to check. 2708 * @returns boolean Whether a skippable header was found. 2709 * @access private 2710 */ 2711 function isSkippableCurlHeader(&$data) { 2712 $skipHeaders = array( 'HTTP/1.1 100', 2713 'HTTP/1.0 301', 2714 'HTTP/1.1 301', 2715 'HTTP/1.0 302', 2716 'HTTP/1.1 302', 2717 'HTTP/1.0 401', 2718 'HTTP/1.1 401', 2719 'HTTP/1.0 200 Connection established'); 2720 foreach ($skipHeaders as $hd) { 2721 $prefix = substr($data, 0, strlen($hd)); 2722 if ($prefix == $hd) return true; 2723 } 2724 2725 return false; 2726 } 2727 2728 /** 2729 * decode a string that is encoded w/ "chunked' transfer encoding 2730 * as defined in RFC2068 19.4.6 2731 * 2732 * @param string $buffer 2733 * @param string $lb 2734 * @returns string 2735 * @access public 2736 * @deprecated 2737 */ 2738 function decodeChunked($buffer, $lb){ 2739 // length := 0 2740 $length = 0; 2741 $new = ''; 2742 2743 // read chunk-size, chunk-extension (if any) and CRLF 2744 // get the position of the linebreak 2745 $chunkend = strpos($buffer, $lb); 2746 if ($chunkend == FALSE) { 2747 $this->debug('no linebreak found in decodeChunked'); 2748 return $new; 2749 } 2750 $temp = substr($buffer,0,$chunkend); 2751 $chunk_size = hexdec( trim($temp) ); 2752 $chunkstart = $chunkend + strlen($lb); 2753 // while (chunk-size > 0) { 2754 while ($chunk_size > 0) { 2755 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); 2756 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); 2757 2758 // Just in case we got a broken connection 2759 if ($chunkend == FALSE) { 2760 $chunk = substr($buffer,$chunkstart); 2761 // append chunk-data to entity-body 2762 $new .= $chunk; 2763 $length += strlen($chunk); 2764 break; 2765 } 2766 2767 // read chunk-data and CRLF 2768 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); 2769 // append chunk-data to entity-body 2770 $new .= $chunk; 2771 // length := length + chunk-size 2772 $length += strlen($chunk); 2773 // read chunk-size and CRLF 2774 $chunkstart = $chunkend + strlen($lb); 2775 2776 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); 2777 if ($chunkend == FALSE) { 2778 break; //Just in case we got a broken connection 2779 } 2780 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); 2781 $chunk_size = hexdec( trim($temp) ); 2782 $chunkstart = $chunkend; 2783 } 2784 return $new; 2785 } 2786 2787 /** 2788 * Writes the payload, including HTTP headers, to $this->outgoing_payload. 2789 * 2790 * @param string $data HTTP body 2791 * @param string $cookie_str data for HTTP Cookie header 2792 * @return void 2793 * @access private 2794 */ 2795 function buildPayload($data, $cookie_str = '') { 2796 // Note: for cURL connections, $this->outgoing_payload is ignored, 2797 // as is the Content-Length header, but these are still created as 2798 // debugging guides. 2799 2800 // add content-length header 2801 $this->setHeader('Content-Length', strlen($data)); 2802 2803 // start building outgoing payload: 2804 if ($this->proxy) { 2805 $uri = $this->url; 2806 } else { 2807 $uri = $this->uri; 2808 } 2809 $req = "$this->request_method $uri HTTP/$this->protocol_version"; 2810 $this->debug("HTTP request: $req"); 2811 $this->outgoing_payload = "$req\r\n"; 2812 2813 // loop thru headers, serializing 2814 foreach($this->outgoing_headers as $k => $v){ 2815 $hdr = $k.': '.$v; 2816 $this->debug("HTTP header: $hdr"); 2817 $this->outgoing_payload .= "$hdr\r\n"; 2818 } 2819 2820 // add any cookies 2821 if ($cookie_str != '') { 2822 $hdr = 'Cookie: '.$cookie_str; 2823 $this->debug("HTTP header: $hdr"); 2824 $this->outgoing_payload .= "$hdr\r\n"; 2825 } 2826 2827 // header/body separator 2828 $this->outgoing_payload .= "\r\n"; 2829 2830 // add data 2831 $this->outgoing_payload .= $data; 2832 } 2833 2834 /** 2835 * sends the SOAP request via HTTP[S] 2836 * 2837 * @param string $data message data 2838 * @param array $cookies cookies to send 2839 * @return boolean true if OK, false if problem 2840 * @access private 2841 */ 2842 function sendRequest($data, $cookies = NULL) { 2843 // build cookie string 2844 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); 2845 2846 // build payload 2847 $this->buildPayload($data, $cookie_str); 2848 2849 if ($this->io_method() == 'socket') { 2850 // send payload 2851 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { 2852 $this->setError('couldn\'t write message data to socket'); 2853 $this->debug('couldn\'t write message data to socket'); 2854 return false; 2855 } 2856 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); 2857 return true; 2858 } else if ($this->io_method() == 'curl') { 2859 // set payload 2860 // cURL does say this should only be the verb, and in fact it 2861 // turns out that the URI and HTTP version are appended to this, which 2862 // some servers refuse to work with (so we no longer use this method!) 2863 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); 2864 $curl_headers = array(); 2865 foreach($this->outgoing_headers as $k => $v){ 2866 if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { 2867 $this->debug("Skip cURL header $k: $v"); 2868 } else { 2869 $curl_headers[] = "$k: $v"; 2870 } 2871 } 2872 if ($cookie_str != '') { 2873 $curl_headers[] = 'Cookie: ' . $cookie_str; 2874 } 2875 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); 2876 $this->debug('set cURL HTTP headers'); 2877 if ($this->request_method == "POST") { 2878 $this->setCurlOption(CURLOPT_POST, 1); 2879 $this->setCurlOption(CURLOPT_POSTFIELDS, $data); 2880 $this->debug('set cURL POST data'); 2881 } else { 2882 } 2883 // insert custom user-set cURL options 2884 foreach ($this->ch_options as $key => $val) { 2885 $this->setCurlOption($key, $val); 2886 } 2887 2888 $this->debug('set cURL payload'); 2889 return true; 2890 } 2891 } 2892 2893 /** 2894 * gets the SOAP response via HTTP[S] 2895 * 2896 * @return string the response (also sets member variables like incoming_payload) 2897 * @access private 2898 */ 2899 function getResponse(){ 2900 $this->incoming_payload = ''; 2901 2902 if ($this->io_method() == 'socket') { 2903 // loop until headers have been retrieved 2904 $data = ''; 2905 while (!isset($lb)){ 2906 2907 // We might EOF during header read. 2908 if(feof($this->fp)) { 2909 $this->incoming_payload = $data; 2910 $this->debug('found no headers before EOF after length ' . strlen($data)); 2911 $this->debug("received before EOF:\n" . $data); 2912 $this->setError('server failed to send headers'); 2913 return false; 2914 } 2915 2916 $tmp = fgets($this->fp, 256); 2917 $tmplen = strlen($tmp); 2918 $this->debug("read line of $tmplen bytes: " . trim($tmp)); 2919 2920 if ($tmplen == 0) { 2921 $this->incoming_payload = $data; 2922 $this->debug('socket read of headers timed out after length ' . strlen($data)); 2923 $this->debug("read before timeout: " . $data); 2924 $this->setError('socket read of headers timed out'); 2925 return false; 2926 } 2927 2928 $data .= $tmp; 2929 $pos = strpos($data,"\r\n\r\n"); 2930 if($pos > 1){ 2931 $lb = "\r\n"; 2932 } else { 2933 $pos = strpos($data,"\n\n"); 2934 if($pos > 1){ 2935 $lb = "\n"; 2936 } 2937 } 2938 // remove 100 headers 2939 if (isset($lb) && ereg('^HTTP/1.1 100',$data)) { 2940 unset($lb); 2941 $data = ''; 2942 }// 2943 } 2944 // store header data 2945 $this->incoming_payload .= $data; 2946 $this->debug('found end of headers after length ' . strlen($data)); 2947 // process headers 2948 $header_data = trim(substr($data,0,$pos)); 2949 $header_array = explode($lb,$header_data); 2950 $this->incoming_headers = array(); 2951 $this->incoming_cookies = array(); 2952 foreach($header_array as $header_line){ 2953 $arr = explode(':',$header_line, 2); 2954 if(count($arr) > 1){ 2955 $header_name = strtolower(trim($arr[0])); 2956 $this->incoming_headers[$header_name] = trim($arr[1]); 2957 if ($header_name == 'set-cookie') { 2958 // TODO: allow multiple cookies from parseCookie 2959 $cookie = $this->parseCookie(trim($arr[1])); 2960 if ($cookie) { 2961 $this->incoming_cookies[] = $cookie; 2962 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 2963 } else { 2964 $this->debug('did not find cookie in ' . trim($arr[1])); 2965 } 2966 } 2967 } else if (isset($header_name)) { 2968 // append continuation line to previous header 2969 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 2970 } 2971 } 2972 2973 // loop until msg has been received 2974 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { 2975 $content_length = 2147483647; // ignore any content-length header 2976 $chunked = true; 2977 $this->debug("want to read chunked content"); 2978 } elseif (isset($this->incoming_headers['content-length'])) { 2979 $content_length = $this->incoming_headers['content-length']; 2980 $chunked = false; 2981 $this->debug("want to read content of length $content_length"); 2982 } else { 2983 $content_length = 2147483647; 2984 $chunked = false; 2985 $this->debug("want to read content to EOF"); 2986 } 2987 $data = ''; 2988 do { 2989 if ($chunked) { 2990 $tmp = fgets($this->fp, 256); 2991 $tmplen = strlen($tmp); 2992 $this->debug("read chunk line of $tmplen bytes"); 2993 if ($tmplen == 0) { 2994 $this->incoming_payload = $data; 2995 $this->debug('socket read of chunk length timed out after length ' . strlen($data)); 2996 $this->debug("read before timeout:\n" . $data); 2997 $this->setError('socket read of chunk length timed out'); 2998 return false; 2999 } 3000 $content_length = hexdec(trim($tmp)); 3001 $this->debug("chunk length $content_length"); 3002 } 3003 $strlen = 0; 3004 while (($strlen < $content_length) && (!feof($this->fp))) { 3005 $readlen = min(8192, $content_length - $strlen); 3006 $tmp = fread($this->fp, $readlen); 3007 $tmplen = strlen($tmp); 3008 $this->debug("read buffer of $tmplen bytes"); 3009 if (($tmplen == 0) && (!feof($this->fp))) { 3010 $this->incoming_payload = $data; 3011 $this->debug('socket read of body timed out after length ' . strlen($data)); 3012 $this->debug("read before timeout:\n" . $data); 3013 $this->setError('socket read of body timed out'); 3014 return false; 3015 } 3016 $strlen += $tmplen; 3017 $data .= $tmp; 3018 } 3019 if ($chunked && ($content_length > 0)) { 3020 $tmp = fgets($this->fp, 256); 3021 $tmplen = strlen($tmp); 3022 $this->debug("read chunk terminator of $tmplen bytes"); 3023 if ($tmplen == 0) { 3024 $this->incoming_payload = $data; 3025 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); 3026 $this->debug("read before timeout:\n" . $data); 3027 $this->setError('socket read of chunk terminator timed out'); 3028 return false; 3029 } 3030 } 3031 } while ($chunked && ($content_length > 0) && (!feof($this->fp))); 3032 if (feof($this->fp)) { 3033 $this->debug('read to EOF'); 3034 } 3035 $this->debug('read body of length ' . strlen($data)); 3036 $this->incoming_payload .= $data; 3037 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); 3038 3039 // close filepointer 3040 if( 3041 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 3042 (! $this->persistentConnection) || feof($this->fp)){ 3043 fclose($this->fp); 3044 $this->fp = false; 3045 $this->debug('closed socket'); 3046 } 3047 3048 // connection was closed unexpectedly 3049 if($this->incoming_payload == ''){ 3050 $this->setError('no response from server'); 3051 return false; 3052 } 3053 3054 // decode transfer-encoding 3055// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ 3056// if(!$data = $this->decodeChunked($data, $lb)){ 3057// $this->setError('Decoding of chunked data failed'); 3058// return false; 3059// } 3060 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; 3061 // set decoded payload 3062// $this->incoming_payload = $header_data.$lb.$lb.$data; 3063// } 3064 3065 } else if ($this->io_method() == 'curl') { 3066 // send and receive 3067 $this->debug('send and receive with cURL'); 3068 $this->incoming_payload = curl_exec($this->ch); 3069 $data = $this->incoming_payload; 3070 3071 $cErr = curl_error($this->ch); 3072 if ($cErr != '') { 3073 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>'; 3074 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE 3075 foreach(curl_getinfo($this->ch) as $k => $v){ 3076 $err .= "$k: $v<br>"; 3077 } 3078 $this->debug($err); 3079 $this->setError($err); 3080 curl_close($this->ch); 3081 return false; 3082 } else { 3083 //echo '<pre>'; 3084 //var_dump(curl_getinfo($this->ch)); 3085 //echo '</pre>'; 3086 } 3087 // close curl 3088 $this->debug('No cURL error, closing cURL'); 3089 curl_close($this->ch); 3090 3091 // try removing skippable headers 3092 $savedata = $data; 3093 while ($this->isSkippableCurlHeader($data)) { 3094 $this->debug("Found HTTP header to skip"); 3095 if ($pos = strpos($data,"\r\n\r\n")) { 3096 $data = ltrim(substr($data,$pos)); 3097 } elseif($pos = strpos($data,"\n\n") ) { 3098 $data = ltrim(substr($data,$pos)); 3099 } 3100 } 3101 3102 if ($data == '') { 3103 // have nothing left; just remove 100 header(s) 3104 $data = $savedata; 3105 while (ereg('^HTTP/1.1 100',$data)) { 3106 if ($pos = strpos($data,"\r\n\r\n")) { 3107 $data = ltrim(substr($data,$pos)); 3108 } elseif($pos = strpos($data,"\n\n") ) { 3109 $data = ltrim(substr($data,$pos)); 3110 } 3111 } 3112 } 3113 3114 // separate content from HTTP headers 3115 if ($pos = strpos($data,"\r\n\r\n")) { 3116 $lb = "\r\n"; 3117 } elseif( $pos = strpos($data,"\n\n")) { 3118 $lb = "\n"; 3119 } else { 3120 $this->debug('no proper separation of headers and document'); 3121 $this->setError('no proper separation of headers and document'); 3122 return false; 3123 } 3124 $header_data = trim(substr($data,0,$pos)); 3125 $header_array = explode($lb,$header_data); 3126 $data = ltrim(substr($data,$pos)); 3127 $this->debug('found proper separation of headers and document'); 3128 $this->debug('cleaned data, stringlen: '.strlen($data)); 3129 // clean headers 3130 foreach ($header_array as $header_line) { 3131 $arr = explode(':',$header_line,2); 3132 if(count($arr) > 1){ 3133 $header_name = strtolower(trim($arr[0])); 3134 $this->incoming_headers[$header_name] = trim($arr[1]); 3135 if ($header_name == 'set-cookie') { 3136 // TODO: allow multiple cookies from parseCookie 3137 $cookie = $this->parseCookie(trim($arr[1])); 3138 if ($cookie) { 3139 $this->incoming_cookies[] = $cookie; 3140 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 3141 } else { 3142 $this->debug('did not find cookie in ' . trim($arr[1])); 3143 } 3144 } 3145 } else if (isset($header_name)) { 3146 // append continuation line to previous header 3147 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 3148 } 3149 } 3150 } 3151 3152 $this->response_status_line = $header_array[0]; 3153 $arr = explode(' ', $this->response_status_line, 3); 3154 $http_version = $arr[0]; 3155 $http_status = intval($arr[1]); 3156 $http_reason = count($arr) > 2 ? $arr[2] : ''; 3157 3158 // see if we need to resend the request with http digest authentication 3159 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { 3160 $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); 3161 $this->setURL($this->incoming_headers['location']); 3162 $this->tryagain = true; 3163 return false; 3164 } 3165 3166 // see if we need to resend the request with http digest authentication 3167 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { 3168 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); 3169 if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { 3170 $this->debug('Server wants digest authentication'); 3171 // remove "Digest " from our elements 3172 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); 3173 3174 // parse elements into array 3175 $digestElements = explode(',', $digestString); 3176 foreach ($digestElements as $val) { 3177 $tempElement = explode('=', trim($val), 2); 3178 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); 3179 } 3180 3181 // should have (at least) qop, realm, nonce 3182 if (isset($digestRequest['nonce'])) { 3183 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); 3184 $this->tryagain = true; 3185 return false; 3186 } 3187 } 3188 $this->debug('HTTP authentication failed'); 3189 $this->setError('HTTP authentication failed'); 3190 return false; 3191 } 3192 3193 if ( 3194 ($http_status >= 300 && $http_status <= 307) || 3195 ($http_status >= 400 && $http_status <= 417) || 3196 ($http_status >= 501 && $http_status <= 505) 3197 ) { 3198 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); 3199 return false; 3200 } 3201 3202 // decode content-encoding 3203 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ 3204 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ 3205 // if decoding works, use it. else assume data wasn't gzencoded 3206 if(function_exists('gzinflate')){ 3207 //$timer->setMarker('starting decoding of gzip/deflated content'); 3208 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) 3209 // this means there are no Zlib headers, although there should be 3210 $this->debug('The gzinflate function exists'); 3211 $datalen = strlen($data); 3212 if ($this->incoming_headers['content-encoding'] == 'deflate') { 3213 if ($degzdata = @gzinflate($data)) { 3214 $data = $degzdata; 3215 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); 3216 if (strlen($data) < $datalen) { 3217 // test for the case that the payload has been compressed twice 3218 $this->debug('The inflated payload is smaller than the gzipped one; try again'); 3219 if ($degzdata = @gzinflate($data)) { 3220 $data = $degzdata; 3221 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); 3222 } 3223 } 3224 } else { 3225 $this->debug('Error using gzinflate to inflate the payload'); 3226 $this->setError('Error using gzinflate to inflate the payload'); 3227 } 3228 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { 3229 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best 3230 $data = $degzdata; 3231 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); 3232 if (strlen($data) < $datalen) { 3233 // test for the case that the payload has been compressed twice 3234 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); 3235 if ($degzdata = @gzinflate(substr($data, 10))) { 3236 $data = $degzdata; 3237 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); 3238 } 3239 } 3240 } else { 3241 $this->debug('Error using gzinflate to un-gzip the payload'); 3242 $this->setError('Error using gzinflate to un-gzip the payload'); 3243 } 3244 } 3245 //$timer->setMarker('finished decoding of gzip/deflated content'); 3246 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; 3247 // set decoded payload 3248 $this->incoming_payload = $header_data.$lb.$lb.$data; 3249 } else { 3250 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 3251 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 3252 } 3253 } else { 3254 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 3255 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 3256 } 3257 } else { 3258 $this->debug('No Content-Encoding header'); 3259 } 3260 3261 if(strlen($data) == 0){ 3262 $this->debug('no data after headers!'); 3263 $this->setError('no data present after HTTP headers'); 3264 return false; 3265 } 3266 3267 return $data; 3268 } 3269 3270 /** 3271 * sets the content-type for the SOAP message to be sent 3272 * 3273 * @param string $type the content type, MIME style 3274 * @param mixed $charset character set used for encoding (or false) 3275 * @access public 3276 */ 3277 function setContentType($type, $charset = false) { 3278 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); 3279 } 3280 3281 /** 3282 * specifies that an HTTP persistent connection should be used 3283 * 3284 * @return boolean whether the request was honored by this method. 3285 * @access public 3286 */ 3287 function usePersistentConnection(){ 3288 if (isset($this->outgoing_headers['Accept-Encoding'])) { 3289 return false; 3290 } 3291 $this->protocol_version = '1.1'; 3292 $this->persistentConnection = true; 3293 $this->setHeader('Connection', 'Keep-Alive'); 3294 return true; 3295 } 3296 3297 /** 3298 * parse an incoming Cookie into it's parts 3299 * 3300 * @param string $cookie_str content of cookie 3301 * @return array with data of that cookie 3302 * @access private 3303 */ 3304 /* 3305 * TODO: allow a Set-Cookie string to be parsed into multiple cookies 3306 */ 3307 function parseCookie($cookie_str) { 3308 $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; 3309 $data = split(';', $cookie_str); 3310 $value_str = $data[0]; 3311 3312 $cookie_param = 'domain='; 3313 $start = strpos($cookie_str, $cookie_param); 3314 if ($start > 0) { 3315 $domain = substr($cookie_str, $start + strlen($cookie_param)); 3316 $domain = substr($domain, 0, strpos($domain, ';')); 3317 } else { 3318 $domain = ''; 3319 } 3320 3321 $cookie_param = 'expires='; 3322 $start = strpos($cookie_str, $cookie_param); 3323 if ($start > 0) { 3324 $expires = substr($cookie_str, $start + strlen($cookie_param)); 3325 $expires = substr($expires, 0, strpos($expires, ';')); 3326 } else { 3327 $expires = ''; 3328 } 3329 3330 $cookie_param = 'path='; 3331 $start = strpos($cookie_str, $cookie_param); 3332 if ( $start > 0 ) { 3333 $path = substr($cookie_str, $start + strlen($cookie_param)); 3334 $path = substr($path, 0, strpos($path, ';')); 3335 } else { 3336 $path = '/'; 3337 } 3338 3339 $cookie_param = ';secure;'; 3340 if (strpos($cookie_str, $cookie_param) !== FALSE) { 3341 $secure = true; 3342 } else { 3343 $secure = false; 3344 } 3345 3346 $sep_pos = strpos($value_str, '='); 3347 3348 if ($sep_pos) { 3349 $name = substr($value_str, 0, $sep_pos); 3350 $value = substr($value_str, $sep_pos + 1); 3351 $cookie= array( 'name' => $name, 3352 'value' => $value, 3353 'domain' => $domain, 3354 'path' => $path, 3355 'expires' => $expires, 3356 'secure' => $secure 3357 ); 3358 return $cookie; 3359 } 3360 return false; 3361 } 3362 3363 /** 3364 * sort out cookies for the current request 3365 * 3366 * @param array $cookies array with all cookies 3367 * @param boolean $secure is the send-content secure or not? 3368 * @return string for Cookie-HTTP-Header 3369 * @access private 3370 */ 3371 function getCookiesForRequest($cookies, $secure=false) { 3372 $cookie_str = ''; 3373 if ((! is_null($cookies)) && (is_array($cookies))) { 3374 foreach ($cookies as $cookie) { 3375 if (! is_array($cookie)) { 3376 continue; 3377 } 3378 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); 3379 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 3380 if (strtotime($cookie['expires']) <= time()) { 3381 $this->debug('cookie has expired'); 3382 continue; 3383 } 3384 } 3385 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { 3386 $domain = preg_quote($cookie['domain']); 3387 if (! preg_match("'.*$domain$'i", $this->host)) { 3388 $this->debug('cookie has different domain'); 3389 continue; 3390 } 3391 } 3392 if ((isset($cookie['path'])) && (! empty($cookie['path']))) { 3393 $path = preg_quote($cookie['path']); 3394 if (! preg_match("'^$path.*'i", $this->path)) { 3395 $this->debug('cookie is for a different path'); 3396 continue; 3397 } 3398 } 3399 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { 3400 $this->debug('cookie is secure, transport is not'); 3401 continue; 3402 } 3403 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; 3404 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); 3405 } 3406 } 3407 return $cookie_str; 3408 } 3409} 3410 3411?><?php 3412 3413 3414 3415/** 3416* 3417* nusoap_server allows the user to create a SOAP server 3418* that is capable of receiving messages and returning responses 3419* 3420* @author Dietrich Ayala <dietrich@ganx4.com> 3421* @author Scott Nichol <snichol@users.sourceforge.net> 3422* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 3423* @access public 3424*/ 3425class nusoap_server extends nusoap_base { 3426 /** 3427 * HTTP headers of request 3428 * @var array 3429 * @access private 3430 */ 3431 var $headers = array(); 3432 /** 3433 * HTTP request 3434 * @var string 3435 * @access private 3436 */ 3437 var $request = ''; 3438 /** 3439 * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) 3440 * @var string 3441 * @access public 3442 */ 3443 var $requestHeaders = ''; 3444 /** 3445 * SOAP Headers from request (parsed) 3446 * @var mixed 3447 * @access public 3448 */ 3449 var $requestHeader = NULL; 3450 /** 3451 * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) 3452 * @var string 3453 * @access public 3454 */ 3455 var $document = ''; 3456 /** 3457 * SOAP payload for request (text) 3458 * @var string 3459 * @access public 3460 */ 3461 var $requestSOAP = ''; 3462 /** 3463 * requested method namespace URI 3464 * @var string 3465 * @access private 3466 */ 3467 var $methodURI = ''; 3468 /** 3469 * name of method requested 3470 * @var string 3471 * @access private 3472 */ 3473 var $methodname = ''; 3474 /** 3475 * method parameters from request 3476 * @var array 3477 * @access private 3478 */ 3479 var $methodparams = array(); 3480 /** 3481 * SOAP Action from request 3482 * @var string 3483 * @access private 3484 */ 3485 var $SOAPAction = ''; 3486 /** 3487 * character set encoding of incoming (request) messages 3488 * @var string 3489 * @access public 3490 */ 3491 var $xml_encoding = ''; 3492 /** 3493 * toggles whether the parser decodes element content w/ utf8_decode() 3494 * @var boolean 3495 * @access public 3496 */ 3497 var $decode_utf8 = true; 3498 3499 /** 3500 * HTTP headers of response 3501 * @var array 3502 * @access public 3503 */ 3504 var $outgoing_headers = array(); 3505 /** 3506 * HTTP response 3507 * @var string 3508 * @access private 3509 */ 3510 var $response = ''; 3511 /** 3512 * SOAP headers for response (text or array of soapval or associative array) 3513 * @var mixed 3514 * @access public 3515 */ 3516 var $responseHeaders = ''; 3517 /** 3518 * SOAP payload for response (text) 3519 * @var string 3520 * @access private 3521 */ 3522 var $responseSOAP = ''; 3523 /** 3524 * method return value to place in response 3525 * @var mixed 3526 * @access private 3527 */ 3528 var $methodreturn = false; 3529 /** 3530 * whether $methodreturn is a string of literal XML 3531 * @var boolean 3532 * @access public 3533 */ 3534 var $methodreturnisliteralxml = false; 3535 /** 3536 * SOAP fault for response (or false) 3537 * @var mixed 3538 * @access private 3539 */ 3540 var $fault = false; 3541 /** 3542 * text indication of result (for debugging) 3543 * @var string 3544 * @access private 3545 */ 3546 var $result = 'successful'; 3547 3548 /** 3549 * assoc array of operations => opData; operations are added by the register() 3550 * method or by parsing an external WSDL definition 3551 * @var array 3552 * @access private 3553 */ 3554 var $operations = array(); 3555 /** 3556 * wsdl instance (if one) 3557 * @var mixed 3558 * @access private 3559 */ 3560 var $wsdl = false; 3561 /** 3562 * URL for WSDL (if one) 3563 * @var mixed 3564 * @access private 3565 */ 3566 var $externalWSDLURL = false; 3567 /** 3568 * whether to append debug to response as XML comment 3569 * @var boolean 3570 * @access public 3571 */ 3572 var $debug_flag = false; 3573 3574 3575 /** 3576 * constructor 3577 * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. 3578 * 3579 * @param mixed $wsdl file path or URL (string), or wsdl instance (object) 3580 * @access public 3581 */ 3582 function nusoap_server($wsdl=false){ 3583 parent::nusoap_base(); 3584 // turn on debugging? 3585 global $debug; 3586 global $HTTP_SERVER_VARS; 3587 3588 if (isset($_SERVER)) { 3589 $this->debug("_SERVER is defined:"); 3590 $this->appendDebug($this->varDump($_SERVER)); 3591 } elseif (isset($HTTP_SERVER_VARS)) { 3592 $this->debug("HTTP_SERVER_VARS is defined:"); 3593 $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); 3594 } else { 3595 $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); 3596 } 3597 3598 if (isset($debug)) { 3599 $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); 3600 $this->debug_flag = $debug; 3601 } elseif (isset($_SERVER['QUERY_STRING'])) { 3602 $qs = explode('&', $_SERVER['QUERY_STRING']); 3603 foreach ($qs as $v) { 3604 if (substr($v, 0, 6) == 'debug=') { 3605 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); 3606 $this->debug_flag = substr($v, 6); 3607 } 3608 } 3609 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 3610 $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); 3611 foreach ($qs as $v) { 3612 if (substr($v, 0, 6) == 'debug=') { 3613 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); 3614 $this->debug_flag = substr($v, 6); 3615 } 3616 } 3617 } 3618 3619 // wsdl 3620 if($wsdl){ 3621 $this->debug("In nusoap_server, WSDL is specified"); 3622 if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { 3623 $this->wsdl = $wsdl; 3624 $this->externalWSDLURL = $this->wsdl->wsdl; 3625 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); 3626 } else { 3627 $this->debug('Create wsdl from ' . $wsdl); 3628 $this->wsdl = new wsdl($wsdl); 3629 $this->externalWSDLURL = $wsdl; 3630 } 3631 $this->appendDebug($this->wsdl->getDebug()); 3632 $this->wsdl->clearDebug(); 3633 if($err = $this->wsdl->getError()){ 3634 die('WSDL ERROR: '.$err); 3635 } 3636 } 3637 } 3638 3639 /** 3640 * processes request and returns response 3641 * 3642 * @param string $data usually is the value of $HTTP_RAW_POST_DATA 3643 * @access public 3644 */ 3645 function service($data){ 3646 global $HTTP_SERVER_VARS; 3647 3648 if (isset($_SERVER['QUERY_STRING'])) { 3649 $qs = $_SERVER['QUERY_STRING']; 3650 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 3651 $qs = $HTTP_SERVER_VARS['QUERY_STRING']; 3652 } else { 3653 $qs = ''; 3654 } 3655 $this->debug("In service, query string=$qs"); 3656 3657 if (ereg('wsdl', $qs) ){ 3658 $this->debug("In service, this is a request for WSDL"); 3659 if($this->externalWSDLURL){ 3660 if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL 3661 header('Location: '.$this->externalWSDLURL); 3662 } else { // assume file 3663 header("Content-Type: text/xml\r\n"); 3664 $fp = fopen($this->externalWSDLURL, 'r'); 3665 fpassthru($fp); 3666 } 3667 } elseif ($this->wsdl) { 3668 header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); 3669 print $this->wsdl->serialize($this->debug_flag); 3670 if ($this->debug_flag) { 3671 $this->debug('wsdl:'); 3672 $this->appendDebug($this->varDump($this->wsdl)); 3673 print $this->getDebugAsXMLComment(); 3674 } 3675 } else { 3676 header("Content-Type: text/html; charset=ISO-8859-1\r\n"); 3677 print "This service does not provide WSDL"; 3678 } 3679 } elseif ($data == '' && $this->wsdl) { 3680 $this->debug("In service, there is no data, so return Web description"); 3681 print $this->wsdl->webDescription(); 3682 } else { 3683 $this->debug("In service, invoke the request"); 3684 $this->parse_request($data); 3685 if (! $this->fault) { 3686 $this->invoke_method(); 3687 } 3688 if (! $this->fault) { 3689 $this->serialize_return(); 3690 } 3691 $this->send_response(); 3692 } 3693 } 3694 3695 /** 3696 * parses HTTP request headers. 3697 * 3698 * The following fields are set by this function (when successful) 3699 * 3700 * headers 3701 * request 3702 * xml_encoding 3703 * SOAPAction 3704 * 3705 * @access private 3706 */ 3707 function parse_http_headers() { 3708 global $HTTP_SERVER_VARS; 3709 3710 $this->request = ''; 3711 $this->SOAPAction = ''; 3712 if(function_exists('getallheaders')){ 3713 $this->debug("In parse_http_headers, use getallheaders"); 3714 $headers = getallheaders(); 3715 foreach($headers as $k=>$v){ 3716 $k = strtolower($k); 3717 $this->headers[$k] = $v; 3718 $this->request .= "$k: $v\r\n"; 3719 $this->debug("$k: $v"); 3720 } 3721 // get SOAPAction header 3722 if(isset($this->headers['soapaction'])){ 3723 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); 3724 } 3725 // get the character encoding of the incoming request 3726 if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ 3727 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); 3728 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 3729 $this->xml_encoding = strtoupper($enc); 3730 } else { 3731 $this->xml_encoding = 'US-ASCII'; 3732 } 3733 } else { 3734 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 3735 $this->xml_encoding = 'ISO-8859-1'; 3736 } 3737 } elseif(isset($_SERVER) && is_array($_SERVER)){ 3738 $this->debug("In parse_http_headers, use _SERVER"); 3739 foreach ($_SERVER as $k => $v) { 3740 if (substr($k, 0, 5) == 'HTTP_') { 3741 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); 3742 } else { 3743 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); 3744 } 3745 if ($k == 'soapaction') { 3746 // get SOAPAction header 3747 $k = 'SOAPAction'; 3748 $v = str_replace('"', '', $v); 3749 $v = str_replace('\\', '', $v); 3750 $this->SOAPAction = $v; 3751 } else if ($k == 'content-type') { 3752 // get the character encoding of the incoming request 3753 if (strpos($v, '=')) { 3754 $enc = substr(strstr($v, '='), 1); 3755 $enc = str_replace('"', '', $enc); 3756 $enc = str_replace('\\', '', $enc); 3757 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 3758 $this->xml_encoding = strtoupper($enc); 3759 } else { 3760 $this->xml_encoding = 'US-ASCII'; 3761 } 3762 } else { 3763 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 3764 $this->xml_encoding = 'ISO-8859-1'; 3765 } 3766 } 3767 $this->headers[$k] = $v; 3768 $this->request .= "$k: $v\r\n"; 3769 $this->debug("$k: $v"); 3770 } 3771 } elseif (is_array($HTTP_SERVER_VARS)) { 3772 $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); 3773 foreach ($HTTP_SERVER_VARS as $k => $v) { 3774 if (substr($k, 0, 5) == 'HTTP_') { 3775 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); 3776 } else { 3777 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); 3778 } 3779 if ($k == 'soapaction') { 3780 // get SOAPAction header 3781 $k = 'SOAPAction'; 3782 $v = str_replace('"', '', $v); 3783 $v = str_replace('\\', '', $v); 3784 $this->SOAPAction = $v; 3785 } else if ($k == 'content-type') { 3786 // get the character encoding of the incoming request 3787 if (strpos($v, '=')) { 3788 $enc = substr(strstr($v, '='), 1); 3789 $enc = str_replace('"', '', $enc); 3790 $enc = str_replace('\\', '', $enc); 3791 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 3792 $this->xml_encoding = strtoupper($enc); 3793 } else { 3794 $this->xml_encoding = 'US-ASCII'; 3795 } 3796 } else { 3797 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 3798 $this->xml_encoding = 'ISO-8859-1'; 3799 } 3800 } 3801 $this->headers[$k] = $v; 3802 $this->request .= "$k: $v\r\n"; 3803 $this->debug("$k: $v"); 3804 } 3805 } else { 3806 $this->debug("In parse_http_headers, HTTP headers not accessible"); 3807 $this->setError("HTTP headers not accessible"); 3808 } 3809 } 3810 3811 /** 3812 * parses a request 3813 * 3814 * The following fields are set by this function (when successful) 3815 * 3816 * headers 3817 * request 3818 * xml_encoding 3819 * SOAPAction 3820 * request 3821 * requestSOAP 3822 * methodURI 3823 * methodname 3824 * methodparams 3825 * requestHeaders 3826 * document 3827 * 3828 * This sets the fault field on error 3829 * 3830 * @param string $data XML string 3831 * @access private 3832 */ 3833 function parse_request($data='') { 3834 $this->debug('entering parse_request()'); 3835 $this->parse_http_headers(); 3836 $this->debug('got character encoding: '.$this->xml_encoding); 3837 // uncompress if necessary 3838 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { 3839 $this->debug('got content encoding: ' . $this->headers['content-encoding']); 3840 if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { 3841 // if decoding works, use it. else assume data wasn't gzencoded 3842 if (function_exists('gzuncompress')) { 3843 if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { 3844 $data = $degzdata; 3845 } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { 3846 $data = $degzdata; 3847 } else { 3848 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); 3849 return; 3850 } 3851 } else { 3852 $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); 3853 return; 3854 } 3855 } 3856 } 3857 $this->request .= "\r\n".$data; 3858 $data = $this->parseRequest($this->headers, $data); 3859 $this->requestSOAP = $data; 3860 $this->debug('leaving parse_request'); 3861 } 3862 3863 /** 3864 * invokes a PHP function for the requested SOAP method 3865 * 3866 * The following fields are set by this function (when successful) 3867 * 3868 * methodreturn 3869 * 3870 * Note that the PHP function that is called may also set the following 3871 * fields to affect the response sent to the client 3872 * 3873 * responseHeaders 3874 * outgoing_headers 3875 * 3876 * This sets the fault field on error 3877 * 3878 * @access private 3879 */ 3880 function invoke_method() { 3881 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); 3882 3883 3884 // NEW - BSP 3885 $data = split("_", $this->methodname); 3886 if(sizeof($data) == 2) 3887 { 3888 $class = $data[0]; 3889 $method = $data[1]; 3890 } 3891 else 3892 { 3893 $class = ''; 3894 $method = ''; 3895 } 3896 // END OF NEW 3897 3898 3899 if ($this->wsdl) { 3900 if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { 3901 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); 3902 $this->appendDebug('opData=' . $this->varDump($this->opData)); 3903 } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { 3904 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element 3905 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); 3906 $this->appendDebug('opData=' . $this->varDump($this->opData)); 3907 $this->methodname = $this->opData['name']; 3908 } else { 3909 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); 3910 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); 3911 return; 3912 } 3913 } else { 3914 $this->debug('in invoke_method, no WSDL to validate method'); 3915 } 3916 3917 // if a . is present in $this->methodname, we see if there is a class in scope, 3918 // which could be referred to. We will also distinguish between two deliminators, 3919 // to allow methods to be called a the class or an instance 3920 //$class = ''; 3921 //$method = ''; 3922 if (strpos($this->methodname, '..') > 0) { 3923 $delim = '..'; 3924 } else if (strpos($this->methodname, '.') > 0) { 3925 $delim = '.'; 3926 } else if (strpos($this->methodname, '_') > 0) { 3927 $delim = '_'; 3928 } else { 3929 $delim = ''; 3930 } 3931 3932 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && 3933 class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { 3934 // get the class and method name 3935 $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); 3936 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); 3937 $this->debug("in invoke_method, class=$class method=$method delim=$delim"); 3938 } 3939 3940 // does method exist? 3941 if ($class == '') { 3942 if (!function_exists($this->methodname)) { 3943 $this->debug("in invoke_method, function '$this->methodname' not found!"); 3944 $this->result = 'fault: method not found'; 3945// $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 3946 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction"); 3947 return; 3948 } 3949 } else { 3950 $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; 3951 if (!in_array($method_to_compare, get_class_methods($class))) { 3952 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); 3953 $this->result = 'fault: method not found'; 3954 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 3955 return; 3956 } 3957 } 3958 3959 // evaluate message, getting back parameters 3960 // verify that request parameters match the method's signature 3961 if(! $this->verify_method($this->methodname,$this->methodparams)){ 3962 // debug 3963 $this->debug('ERROR: request not verified against method signature'); 3964 $this->result = 'fault: request failed validation against method signature'; 3965 // return fault 3966 $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); 3967 return; 3968 } 3969 3970 // if there are parameters to pass 3971 $this->debug('in invoke_method, params:'); 3972 $this->appendDebug($this->varDump($this->methodparams)); 3973 $this->debug("in invoke_method, calling '$this->methodname'"); 3974 if (!function_exists('call_user_func_array')) { 3975 if ($class == '') { 3976 $this->debug('in invoke_method, calling function using eval()'); 3977 $funcCall = "\$this->methodreturn = $this->methodname("; 3978 } else { 3979 if ($delim == '..') { 3980 $this->debug('in invoke_method, calling class method using eval()'); 3981 $funcCall = "\$this->methodreturn = ".$class."::".$method."("; 3982 } else { 3983 $this->debug('in invoke_method, calling instance method using eval()'); 3984 // generate unique instance name 3985 $instname = "\$inst_".time(); 3986 $funcCall = $instname." = new ".$class."(); "; 3987 $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; 3988 } 3989 } 3990 if ($this->methodparams) { 3991 foreach ($this->methodparams as $param) { 3992 if (is_array($param) || is_object($param)) { 3993 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); 3994 return; 3995 } 3996 $funcCall .= "\"$param\","; 3997 } 3998 $funcCall = substr($funcCall, 0, -1); 3999 } 4000 $funcCall .= ');'; 4001 $this->debug('in invoke_method, function call: '.$funcCall); 4002 @eval($funcCall); 4003 } else { 4004 if ($class == '') { 4005 $this->debug('in invoke_method, calling function using call_user_func_array()'); 4006 $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() 4007 } elseif ($delim == '..') { 4008 $this->debug('in invoke_method, calling class method using call_user_func_array()'); 4009 $call_arg = array ($class, $method); 4010 } else { 4011 $this->debug('in invoke_method, calling instance method using call_user_func_array()'); 4012 $instance = new $class (); 4013 $call_arg = array(&$instance, $method); 4014 } 4015 4016 /* NEU BSP */ 4017 $bsp_call_arg = array(&$instance, "addServer"); 4018 call_user_func_array($bsp_call_arg, array($this)); 4019 /* END NEU */ 4020 4021 if (is_array($this->methodparams)) { 4022 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); 4023 } else { 4024 $this->methodreturn = call_user_func_array($call_arg, array()); 4025 } 4026 } 4027 $this->debug('in invoke_method, methodreturn:'); 4028 $this->appendDebug($this->varDump($this->methodreturn)); 4029 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); 4030 } 4031 4032 /** 4033 * serializes the return value from a PHP function into a full SOAP Envelope 4034 * 4035 * The following fields are set by this function (when successful) 4036 * 4037 * responseSOAP 4038 * 4039 * This sets the fault field on error 4040 * 4041 * @access private 4042 */ 4043 function serialize_return() { 4044 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); 4045 // if fault 4046 if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { 4047 $this->debug('got a fault object from method'); 4048 $this->fault = $this->methodreturn; 4049 return; 4050 } elseif ($this->methodreturnisliteralxml) { 4051 $return_val = $this->methodreturn; 4052 // returned value(s) 4053 } else { 4054 $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); 4055 $this->debug('serializing return value'); 4056 if($this->wsdl){ 4057 if (sizeof($this->opData['output']['parts']) > 1) { 4058 $this->debug('more than one output part, so use the method return unchanged'); 4059 $opParams = $this->methodreturn; 4060 } elseif (sizeof($this->opData['output']['parts']) == 1) { 4061 $this->debug('exactly one output part, so wrap the method return in a simple array'); 4062 // TODO: verify that it is not already wrapped! 4063 //foreach ($this->opData['output']['parts'] as $name => $type) { 4064 // $this->debug('wrap in element named ' . $name); 4065 //} 4066 $opParams = array($this->methodreturn); 4067 } 4068 $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); 4069 $this->appendDebug($this->wsdl->getDebug()); 4070 $this->wsdl->clearDebug(); 4071 if($errstr = $this->wsdl->getError()){ 4072 $this->debug('got wsdl error: '.$errstr); 4073 $this->fault('SOAP-ENV:Server', 'unable to serialize result'); 4074 return; 4075 } 4076 } else { 4077 if (isset($this->methodreturn)) { 4078 $return_val = $this->serialize_val($this->methodreturn, 'return'); 4079 } else { 4080 $return_val = ''; 4081 $this->debug('in absence of WSDL, assume void return for backward compatibility'); 4082 } 4083 } 4084 } 4085 $this->debug('return value:'); 4086 $this->appendDebug($this->varDump($return_val)); 4087 4088 $this->debug('serializing response'); 4089 if ($this->wsdl) { 4090 $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); 4091 if ($this->opData['style'] == 'rpc') { 4092 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); 4093 if ($this->opData['output']['use'] == 'literal') { 4094 // 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 4095 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 4096 } else { 4097 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 4098 } 4099 } else { 4100 $this->debug('style is not rpc for serialization: assume document'); 4101 $payload = $return_val; 4102 } 4103 } else { 4104 $this->debug('do not have WSDL for serialization: assume rpc/encoded'); 4105 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 4106 } 4107 $this->result = 'successful'; 4108 if($this->wsdl){ 4109 //if($this->debug_flag){ 4110 $this->appendDebug($this->wsdl->getDebug()); 4111 // } 4112 if (isset($opData['output']['encodingStyle'])) { 4113 $encodingStyle = $opData['output']['encodingStyle']; 4114 } else { 4115 $encodingStyle = ''; 4116 } 4117 4118 /* CHANGED 2009-04-08 BY Björn Spichal ---------------------------------*/ 4119 $payload = str_replace("<![CDATA[", "<![CDATA[", $payload); 4120 $payload = str_replace("]]>", "]]>", $payload); 4121 /*----------------------------------------------------------------------*/ 4122 4123 // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. 4124 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); 4125 } else { 4126 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); 4127 } 4128 4129 $this->debug("Leaving serialize_return"); 4130 } 4131 4132 /** 4133 * sends an HTTP response 4134 * 4135 * The following fields are set by this function (when successful) 4136 * 4137 * outgoing_headers 4138 * response 4139 * 4140 * @access private 4141 */ 4142 function send_response() { 4143 $this->debug('Enter send_response'); 4144 if ($this->fault) { 4145 $payload = $this->fault->serialize(); 4146 $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; 4147 $this->outgoing_headers[] = "Status: 500 Internal Server Error"; 4148 } else { 4149 $payload = $this->responseSOAP; 4150 // Some combinations of PHP+Web server allow the Status 4151 // to come through as a header. Since OK is the default 4152 // just do nothing. 4153 // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; 4154 // $this->outgoing_headers[] = "Status: 200 OK"; 4155 } 4156 // add debug data if in debug mode 4157 if(isset($this->debug_flag) && $this->debug_flag){ 4158 $payload .= $this->getDebugAsXMLComment(); 4159 } 4160 $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; 4161 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 4162 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; 4163 // Let the Web server decide about this 4164 //$this->outgoing_headers[] = "Connection: Close\r\n"; 4165 $payload = $this->getHTTPBody($payload); 4166 $type = $this->getHTTPContentType(); 4167 $charset = $this->getHTTPContentTypeCharset(); 4168 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); 4169 //begin code to compress payload - by John 4170 // NOTE: there is no way to know whether the Web server will also compress 4171 // this data. 4172 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { 4173 if (strstr($this->headers['accept-encoding'], 'gzip')) { 4174 if (function_exists('gzencode')) { 4175 if (isset($this->debug_flag) && $this->debug_flag) { 4176 $payload .= "<!-- Content being gzipped -->"; 4177 } 4178 $this->outgoing_headers[] = "Content-Encoding: gzip"; 4179 $payload = gzencode($payload); 4180 } else { 4181 if (isset($this->debug_flag) && $this->debug_flag) { 4182 $payload .= "<!-- Content will not be gzipped: no gzencode -->"; 4183 } 4184 } 4185 } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { 4186 // Note: MSIE requires gzdeflate output (no Zlib header and checksum), 4187 // instead of gzcompress output, 4188 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) 4189 if (function_exists('gzdeflate')) { 4190 if (isset($this->debug_flag) && $this->debug_flag) { 4191 $payload .= "<!-- Content being deflated -->"; 4192 } 4193 $this->outgoing_headers[] = "Content-Encoding: deflate"; 4194 $payload = gzdeflate($payload); 4195 } else { 4196 if (isset($this->debug_flag) && $this->debug_flag) { 4197 $payload .= "<!-- Content will not be deflated: no gzcompress -->"; 4198 } 4199 } 4200 } 4201 } 4202 //end code 4203 $this->outgoing_headers[] = "Content-Length: ".strlen($payload); 4204 reset($this->outgoing_headers); 4205 foreach($this->outgoing_headers as $hdr){ 4206 header($hdr, false); 4207 } 4208 4209 print $payload; 4210 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; 4211 } 4212 4213 /** 4214 * takes the value that was created by parsing the request 4215 * and compares to the method's signature, if available. 4216 * 4217 * @param string $operation The operation to be invoked 4218 * @param array $request The array of parameter values 4219 * @return boolean Whether the operation was found 4220 * @access private 4221 */ 4222 function verify_method($operation,$request){ 4223 if(isset($this->wsdl) && is_object($this->wsdl)){ 4224 if($this->wsdl->getOperationData($operation)){ 4225 return true; 4226 } 4227 } elseif(isset($this->operations[$operation])){ 4228 return true; 4229 } 4230 return false; 4231 } 4232 4233 /** 4234 * processes SOAP message received from client 4235 * 4236 * @param array $headers The HTTP headers 4237 * @param string $data unprocessed request data from client 4238 * @return mixed value of the message, decoded into a PHP type 4239 * @access private 4240 */ 4241 function parseRequest($headers, $data) { 4242 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); 4243 if (!strstr($headers['content-type'], 'text/xml')) { 4244 $this->setError('Request not of type text/xml'); 4245 return false; 4246 } 4247 if (strpos($headers['content-type'], '=')) { 4248 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 4249 $this->debug('Got response encoding: ' . $enc); 4250 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 4251 $this->xml_encoding = strtoupper($enc); 4252 } else { 4253 $this->xml_encoding = 'US-ASCII'; 4254 } 4255 } else { 4256 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 4257 $this->xml_encoding = 'ISO-8859-1'; 4258 } 4259 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 4260 // parse response, get soap parser obj 4261 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); 4262 // parser debug 4263 $this->debug("parser debug: \n".$parser->getDebug()); 4264 // if fault occurred during message parsing 4265 if($err = $parser->getError()){ 4266 $this->result = 'fault: error in msg parsing: '.$err; 4267 $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); 4268 // else successfully parsed request into soapval object 4269 } else { 4270 // get/set methodname 4271 $this->methodURI = $parser->root_struct_namespace; 4272 $this->methodname = $parser->root_struct_name; 4273 $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); 4274 $this->debug('calling parser->get_soapbody()'); 4275 $this->methodparams = $parser->get_soapbody(); 4276 // get SOAP headers 4277 $this->requestHeaders = $parser->getHeaders(); 4278 // get SOAP Header 4279 $this->requestHeader = $parser->get_soapheader(); 4280 // add document for doclit support 4281 $this->document = $parser->document; 4282 } 4283 } 4284 4285 /** 4286 * gets the HTTP body for the current response. 4287 * 4288 * @param string $soapmsg The SOAP payload 4289 * @return string The HTTP body, which includes the SOAP payload 4290 * @access private 4291 */ 4292 function getHTTPBody($soapmsg) { 4293 return $soapmsg; 4294 } 4295 4296 /** 4297 * gets the HTTP content type for the current response. 4298 * 4299 * Note: getHTTPBody must be called before this. 4300 * 4301 * @return string the HTTP content type for the current response. 4302 * @access private 4303 */ 4304 function getHTTPContentType() { 4305 return 'text/xml'; 4306 } 4307 4308 /** 4309 * gets the HTTP content type charset for the current response. 4310 * returns false for non-text content types. 4311 * 4312 * Note: getHTTPBody must be called before this. 4313 * 4314 * @return string the HTTP content type charset for the current response. 4315 * @access private 4316 */ 4317 function getHTTPContentTypeCharset() { 4318 return $this->soap_defencoding; 4319 } 4320 4321 /** 4322 * add a method to the dispatch map (this has been replaced by the register method) 4323 * 4324 * @param string $methodname 4325 * @param string $in array of input values 4326 * @param string $out array of output values 4327 * @access public 4328 * @deprecated 4329 */ 4330 function add_to_map($methodname,$in,$out){ 4331 $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); 4332 } 4333 4334 /** 4335 * register a service function with the server 4336 * 4337 * @param string $name the name of the PHP function, class.method or class..method 4338 * @param array $in assoc array of input values: key = param name, value = param type 4339 * @param array $out assoc array of output values: key = param name, value = param type 4340 * @param mixed $namespace the element namespace for the method or false 4341 * @param mixed $soapaction the soapaction for the method or false 4342 * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically 4343 * @param mixed $use optional (encoded|literal) or false 4344 * @param string $documentation optional Description to include in WSDL 4345 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 4346 * @access public 4347 */ 4348 function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ 4349 global $HTTP_SERVER_VARS; 4350 4351 if($this->externalWSDLURL){ 4352 die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); 4353 } 4354 if (! $name) { 4355 die('You must specify a name when you register an operation'); 4356 } 4357 if (!is_array($in)) { 4358 die('You must provide an array for operation inputs'); 4359 } 4360 if (!is_array($out)) { 4361 die('You must provide an array for operation outputs'); 4362 } 4363 if(false == $namespace) { 4364 } 4365 if(false == $soapaction) { 4366 if (isset($_SERVER)) { 4367 $SERVER_NAME = $_SERVER['SERVER_NAME']; 4368 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 4369 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 4370 } elseif (isset($HTTP_SERVER_VARS)) { 4371 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 4372 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 4373 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 4374 } else { 4375 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 4376 } 4377 if ($HTTPS == '1' || $HTTPS == 'on') { 4378 $SCHEME = 'https'; 4379 } else { 4380 $SCHEME = 'http'; 4381 } 4382 $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; 4383 } 4384 if(false == $style) { 4385 $style = "rpc"; 4386 } 4387 if(false == $use) { 4388 $use = "encoded"; 4389 } 4390 if ($use == 'encoded' && $encodingStyle = '') { 4391 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 4392 } 4393 4394 $this->operations[$name] = array( 4395 'name' => $name, 4396 'in' => $in, 4397 'out' => $out, 4398 'namespace' => $namespace, 4399 'soapaction' => $soapaction, 4400 'style' => $style); 4401 if($this->wsdl){ 4402 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); 4403 } 4404 return true; 4405 } 4406 4407 /** 4408 * Specify a fault to be returned to the client. 4409 * This also acts as a flag to the server that a fault has occured. 4410 * 4411 * @param string $faultcode 4412 * @param string $faultstring 4413 * @param string $faultactor 4414 * @param string $faultdetail 4415 * @access public 4416 */ 4417 function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ 4418 if ($faultdetail == '' && $this->debug_flag) { 4419 $faultdetail = $this->getDebug(); 4420 } 4421 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); 4422 $this->fault->soap_defencoding = $this->soap_defencoding; 4423 } 4424 4425 /** 4426 * Sets up wsdl object. 4427 * Acts as a flag to enable internal WSDL generation 4428 * 4429 * @param string $serviceName, name of the service 4430 * @param mixed $namespace optional 'tns' service namespace or false 4431 * @param mixed $endpoint optional URL of service endpoint or false 4432 * @param string $style optional (rpc|document) WSDL style (also specified by operation) 4433 * @param string $transport optional SOAP transport 4434 * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false 4435 */ 4436 function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) 4437 { 4438 global $HTTP_SERVER_VARS; 4439 4440 if (isset($_SERVER)) { 4441 $SERVER_NAME = $_SERVER['SERVER_NAME']; 4442 $SERVER_PORT = $_SERVER['SERVER_PORT']; 4443 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 4444 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 4445 } elseif (isset($HTTP_SERVER_VARS)) { 4446 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 4447 $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; 4448 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 4449 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 4450 } else { 4451 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 4452 } 4453 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) 4454 $colon = strpos($SERVER_NAME,":"); 4455 if ($colon) { 4456 $SERVER_NAME = substr($SERVER_NAME, 0, $colon); 4457 } 4458 if ($SERVER_PORT == 80) { 4459 $SERVER_PORT = ''; 4460 } else { 4461 $SERVER_PORT = ':' . $SERVER_PORT; 4462 } 4463 if(false == $namespace) { 4464 $namespace = "http://$SERVER_NAME/soap/$serviceName"; 4465 } 4466 4467 if(false == $endpoint) { 4468 if ($HTTPS == '1' || $HTTPS == 'on') { 4469 $SCHEME = 'https'; 4470 } else { 4471 $SCHEME = 'http'; 4472 } 4473 $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; 4474 } 4475 4476 if(false == $schemaTargetNamespace) { 4477 $schemaTargetNamespace = $namespace; 4478 } 4479 4480 $this->wsdl = new wsdl; 4481 $this->wsdl->serviceName = $serviceName; 4482 $this->wsdl->endpoint = $endpoint; 4483 $this->wsdl->namespaces['tns'] = $namespace; 4484 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; 4485 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; 4486 if ($schemaTargetNamespace != $namespace) { 4487 $this->wsdl->namespaces['types'] = $schemaTargetNamespace; 4488 } 4489 $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); 4490 if ($style == 'document') { 4491 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; 4492 } 4493 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; 4494 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); 4495 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); 4496 $this->wsdl->bindings[$serviceName.'Binding'] = array( 4497 'name'=>$serviceName.'Binding', 4498 'style'=>$style, 4499 'transport'=>$transport, 4500 'portType'=>$serviceName.'PortType'); 4501 $this->wsdl->ports[$serviceName.'Port'] = array( 4502 'binding'=>$serviceName.'Binding', 4503 'location'=>$endpoint, 4504 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); 4505 } 4506} 4507 4508/** 4509 * Backward compatibility 4510 */ 4511class soap_server extends nusoap_server { 4512} 4513 4514?><?php 4515 4516 4517 4518/** 4519* parses a WSDL file, allows access to it's data, other utility methods. 4520* also builds WSDL structures programmatically. 4521* 4522* @author Dietrich Ayala <dietrich@ganx4.com> 4523* @author Scott Nichol <snichol@users.sourceforge.net> 4524* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 4525* @access public 4526*/ 4527class wsdl extends nusoap_base { 4528 // URL or filename of the root of this WSDL 4529 var $wsdl; 4530 // define internal arrays of bindings, ports, operations, messages, etc. 4531 var $schemas = array(); 4532 var $currentSchema; 4533 var $message = array(); 4534 var $complexTypes = array(); 4535 var $messages = array(); 4536 var $currentMessage; 4537 var $currentOperation; 4538 var $portTypes = array(); 4539 var $currentPortType; 4540 var $bindings = array(); 4541 var $currentBinding; 4542 var $ports = array(); 4543 var $currentPort; 4544 var $opData = array(); 4545 var $status = ''; 4546 var $documentation = false; 4547 var $endpoint = ''; 4548 // array of wsdl docs to import 4549 var $import = array(); 4550 // parser vars 4551 var $parser; 4552 var $position = 0; 4553 var $depth = 0; 4554 var $depth_array = array(); 4555 // for getting wsdl 4556 var $proxyhost = ''; 4557 var $proxyport = ''; 4558 var $proxyusername = ''; 4559 var $proxypassword = ''; 4560 var $timeout = 0; 4561 var $response_timeout = 30; 4562 var $curl_options = array(); // User-specified cURL options 4563 var $use_curl = false; // whether to always try to use cURL 4564 // for HTTP authentication 4565 var $username = ''; // Username for HTTP authentication 4566 var $password = ''; // Password for HTTP authentication 4567 var $authtype = ''; // Type of HTTP authentication 4568 var $certRequest = array(); // Certificate for HTTP SSL authentication 4569 4570 /** 4571 * constructor 4572 * 4573 * @param string $wsdl WSDL document URL 4574 * @param string $proxyhost 4575 * @param string $proxyport 4576 * @param string $proxyusername 4577 * @param string $proxypassword 4578 * @param integer $timeout set the connection timeout 4579 * @param integer $response_timeout set the response timeout 4580 * @param array $curl_options user-specified cURL options 4581 * @param boolean $use_curl try to use cURL 4582 * @access public 4583 */ 4584 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ 4585 parent::nusoap_base(); 4586 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 4587 $this->proxyhost = $proxyhost; 4588 $this->proxyport = $proxyport; 4589 $this->proxyusername = $proxyusername; 4590 $this->proxypassword = $proxypassword; 4591 $this->timeout = $timeout; 4592 $this->response_timeout = $response_timeout; 4593 if (is_array($curl_options)) 4594 $this->curl_options = $curl_options; 4595 $this->use_curl = $use_curl; 4596 $this->fetchWSDL($wsdl); 4597 } 4598 4599 /** 4600 * fetches the WSDL document and parses it 4601 * 4602 * @access public 4603 */ 4604 function fetchWSDL($wsdl) { 4605 $this->debug("parse and process WSDL path=$wsdl"); 4606 $this->wsdl = $wsdl; 4607 // parse wsdl file 4608 if ($this->wsdl != "") { 4609 $this->parseWSDL($this->wsdl); 4610 } 4611 // imports 4612 // TODO: handle imports more properly, grabbing them in-line and nesting them 4613 $imported_urls = array(); 4614 $imported = 1; 4615 while ($imported > 0) { 4616 $imported = 0; 4617 // Schema imports 4618 foreach ($this->schemas as $ns => $list) { 4619 foreach ($list as $xs) { 4620 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 4621 foreach ($xs->imports as $ns2 => $list2) { 4622 for ($ii = 0; $ii < count($list2); $ii++) { 4623 if (! $list2[$ii]['loaded']) { 4624 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 4625 $url = $list2[$ii]['location']; 4626 if ($url != '') { 4627 $urlparts = parse_url($url); 4628 if (!isset($urlparts['host'])) { 4629 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 4630 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 4631 } 4632 if (! in_array($url, $imported_urls)) { 4633 $this->parseWSDL($url); 4634 $imported++; 4635 $imported_urls[] = $url; 4636 } 4637 } else { 4638 $this->debug("Unexpected scenario: empty URL for unloaded import"); 4639 } 4640 } 4641 } 4642 } 4643 } 4644 } 4645 // WSDL imports 4646 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 4647 foreach ($this->import as $ns => $list) { 4648 for ($ii = 0; $ii < count($list); $ii++) { 4649 if (! $list[$ii]['loaded']) { 4650 $this->import[$ns][$ii]['loaded'] = true; 4651 $url = $list[$ii]['location']; 4652 if ($url != '') { 4653 $urlparts = parse_url($url); 4654 if (!isset($urlparts['host'])) { 4655 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 4656 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 4657 } 4658 if (! in_array($url, $imported_urls)) { 4659 $this->parseWSDL($url); 4660 $imported++; 4661 $imported_urls[] = $url; 4662 } 4663 } else { 4664 $this->debug("Unexpected scenario: empty URL for unloaded import"); 4665 } 4666 } 4667 } 4668 } 4669 } 4670 // add new data to operation data 4671 foreach($this->bindings as $binding => $bindingData) { 4672 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 4673 foreach($bindingData['operations'] as $operation => $data) { 4674 $this->debug('post-parse data gathering for ' . $operation); 4675 $this->bindings[$binding]['operations'][$operation]['input'] = 4676 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 4677 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 4678 $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 4679 $this->bindings[$binding]['operations'][$operation]['output'] = 4680 isset($this->bindings[$binding]['operations'][$operation]['output']) ? 4681 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 4682 $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 4683 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ 4684 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 4685 } 4686 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ 4687 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 4688 } 4689 // Set operation style if necessary, but do not override one already provided 4690 if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { 4691 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 4692 } 4693 $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 4694 $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 4695 $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 4696 } 4697 } 4698 } 4699 } 4700 4701 /** 4702 * parses the wsdl document 4703 * 4704 * @param string $wsdl path or URL 4705 * @access private 4706 */ 4707 function parseWSDL($wsdl = '') { 4708 $this->debug("parse WSDL at path=$wsdl"); 4709 4710 if ($wsdl == '') { 4711 $this->debug('no wsdl passed to parseWSDL()!!'); 4712 $this->setError('no wsdl passed to parseWSDL()!!'); 4713 return false; 4714 } 4715 4716 // parse $wsdl for url format 4717 $wsdl_props = parse_url($wsdl); 4718 4719 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 4720 $this->debug('getting WSDL http(s) URL ' . $wsdl); 4721 // get wsdl 4722 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); 4723 $tr->request_method = 'GET'; 4724 $tr->useSOAPAction = false; 4725 if($this->proxyhost && $this->proxyport){ 4726 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 4727 } 4728 if ($this->authtype != '') { 4729 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 4730 } 4731 $tr->setEncoding('gzip, deflate'); 4732 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 4733 //$this->debug("WSDL request\n" . $tr->outgoing_payload); 4734 //$this->debug("WSDL response\n" . $tr->incoming_payload); 4735 $this->appendDebug($tr->getDebug()); 4736 // catch errors 4737 if($err = $tr->getError() ){ 4738 $errstr = 'HTTP ERROR: '.$err; 4739 $this->debug($errstr); 4740 $this->setError($errstr); 4741 unset($tr); 4742 return false; 4743 } 4744 unset($tr); 4745 $this->debug("got WSDL URL"); 4746 } else { 4747 // $wsdl is not http(s), so treat it as a file URL or plain file path 4748 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 4749 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 4750 } else { 4751 $path = $wsdl; 4752 } 4753 $this->debug('getting WSDL file ' . $path); 4754 if ($fp = @fopen($path, 'r')) { 4755 $wsdl_string = ''; 4756 while ($data = fread($fp, 32768)) { 4757 $wsdl_string .= $data; 4758 } 4759 fclose($fp); 4760 } else { 4761 $errstr = "Bad path to WSDL file $path"; 4762 $this->debug($errstr); 4763 $this->setError($errstr); 4764 return false; 4765 } 4766 } 4767 $this->debug('Parse WSDL'); 4768 // end new code added 4769 // Create an XML parser. 4770 $this->parser = xml_parser_create(); 4771 // Set the options for parsing the XML data. 4772 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 4773 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 4774 // Set the object for the parser. 4775 xml_set_object($this->parser, $this); 4776 // Set the element handlers for the parser. 4777 xml_set_element_handler($this->parser, 'start_element', 'end_element'); 4778 xml_set_character_data_handler($this->parser, 'character_data'); 4779 // Parse the XML file. 4780 if (!xml_parse($this->parser, $wsdl_string, true)) { 4781 // Display an error message. 4782 $errstr = sprintf( 4783 'XML error parsing WSDL from %s on line %d: %s', 4784 $wsdl, 4785 xml_get_current_line_number($this->parser), 4786 xml_error_string(xml_get_error_code($this->parser)) 4787 ); 4788 $this->debug($errstr); 4789 $this->debug("XML payload:\n" . $wsdl_string); 4790 $this->setError($errstr); 4791 return false; 4792 } 4793 // free the parser 4794 xml_parser_free($this->parser); 4795 $this->debug('Parsing WSDL done'); 4796 // catch wsdl parse errors 4797 if($this->getError()){ 4798 return false; 4799 } 4800 return true; 4801 } 4802 4803 /** 4804 * start-element handler 4805 * 4806 * @param string $parser XML parser object 4807 * @param string $name element name 4808 * @param string $attrs associative array of attributes 4809 * @access private 4810 */ 4811 function start_element($parser, $name, $attrs) 4812 { 4813 if ($this->status == 'schema') { 4814 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 4815 $this->appendDebug($this->currentSchema->getDebug()); 4816 $this->currentSchema->clearDebug(); 4817 } elseif (ereg('schema$', $name)) { 4818 $this->debug('Parsing WSDL schema'); 4819 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 4820 $this->status = 'schema'; 4821 $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); 4822 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 4823 $this->appendDebug($this->currentSchema->getDebug()); 4824 $this->currentSchema->clearDebug(); 4825 } else { 4826 // position in the total number of elements, starting from 0 4827 $pos = $this->position++; 4828 $depth = $this->depth++; 4829 // set self as current value for this depth 4830 $this->depth_array[$depth] = $pos; 4831 $this->message[$pos] = array('cdata' => ''); 4832 // process attributes 4833 if (count($attrs) > 0) { 4834 // register namespace declarations 4835 foreach($attrs as $k => $v) { 4836 if (ereg("^xmlns", $k)) { 4837 if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 4838 $this->namespaces[$ns_prefix] = $v; 4839 } else { 4840 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 4841 } 4842 if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 4843 $this->XMLSchemaVersion = $v; 4844 $this->namespaces['xsi'] = $v . '-instance'; 4845 } 4846 } 4847 } 4848 // expand each attribute prefix to its namespace 4849 foreach($attrs as $k => $v) { 4850 $k = strpos($k, ':') ? $this->expandQname($k) : $k; 4851 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 4852 $v = strpos($v, ':') ? $this->expandQname($v) : $v; 4853 } 4854 $eAttrs[$k] = $v; 4855 } 4856 $attrs = $eAttrs; 4857 } else { 4858 $attrs = array(); 4859 } 4860 // get element prefix, namespace and name 4861 if (ereg(':', $name)) { 4862 // get ns prefix 4863 $prefix = substr($name, 0, strpos($name, ':')); 4864 // get ns 4865 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 4866 // get unqualified name 4867 $name = substr(strstr($name, ':'), 1); 4868 } 4869 // process attributes, expanding any prefixes to namespaces 4870 // find status, register data 4871 switch ($this->status) { 4872 case 'message': 4873 if ($name == 'part') { 4874 if (isset($attrs['type'])) { 4875 $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); 4876 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 4877 } 4878 if (isset($attrs['element'])) { 4879 $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); 4880 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; 4881 } 4882 } 4883 break; 4884 case 'portType': 4885 switch ($name) { 4886 case 'operation': 4887 $this->currentPortOperation = $attrs['name']; 4888 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 4889 if (isset($attrs['parameterOrder'])) { 4890 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 4891 } 4892 break; 4893 case 'documentation': 4894 $this->documentation = true; 4895 break; 4896 // merge input/output data 4897 default: 4898 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 4899 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 4900 break; 4901 } 4902 break; 4903 case 'binding': 4904 switch ($name) { 4905 case 'binding': 4906 // get ns prefix 4907 if (isset($attrs['style'])) { 4908 $this->bindings[$this->currentBinding]['prefix'] = $prefix; 4909 } 4910 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 4911 break; 4912 case 'header': 4913 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 4914 break; 4915 case 'operation': 4916 if (isset($attrs['soapAction'])) { 4917 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 4918 } 4919 if (isset($attrs['style'])) { 4920 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 4921 } 4922 if (isset($attrs['name'])) { 4923 $this->currentOperation = $attrs['name']; 4924 $this->debug("current binding operation: $this->currentOperation"); 4925 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 4926 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 4927 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 4928 } 4929 break; 4930 case 'input': 4931 $this->opStatus = 'input'; 4932 break; 4933 case 'output': 4934 $this->opStatus = 'output'; 4935 break; 4936 case 'body': 4937 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 4938 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 4939 } else { 4940 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 4941 } 4942 break; 4943 } 4944 break; 4945 case 'service': 4946 switch ($name) { 4947 case 'port': 4948 $this->currentPort = $attrs['name']; 4949 $this->debug('current port: ' . $this->currentPort); 4950 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 4951 4952 break; 4953 case 'address': 4954 $this->ports[$this->currentPort]['location'] = $attrs['location']; 4955 $this->ports[$this->currentPort]['bindingType'] = $namespace; 4956 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 4957 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 4958 break; 4959 } 4960 break; 4961 } 4962 // set status 4963 switch ($name) { 4964 case 'import': 4965 if (isset($attrs['location'])) { 4966 $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 4967 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 4968 } else { 4969 $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 4970 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 4971 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 4972 } 4973 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 4974 } 4975 break; 4976 //wait for schema 4977 //case 'types': 4978 // $this->status = 'schema'; 4979 // break; 4980 case 'message': 4981 $this->status = 'message'; 4982 $this->messages[$attrs['name']] = array(); 4983 $this->currentMessage = $attrs['name']; 4984 break; 4985 case 'portType': 4986 $this->status = 'portType'; 4987 $this->portTypes[$attrs['name']] = array(); 4988 $this->currentPortType = $attrs['name']; 4989 break; 4990 case "binding": 4991 if (isset($attrs['name'])) { 4992 // get binding name 4993 if (strpos($attrs['name'], ':')) { 4994 $this->currentBinding = $this->getLocalPart($attrs['name']); 4995 } else { 4996 $this->currentBinding = $attrs['name']; 4997 } 4998 $this->status = 'binding'; 4999 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 5000 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 5001 } 5002 break; 5003 case 'service': 5004 $this->serviceName = $attrs['name']; 5005 $this->status = 'service'; 5006 $this->debug('current service: ' . $this->serviceName); 5007 break; 5008 case 'definitions': 5009 foreach ($attrs as $name => $value) { 5010 $this->wsdl_info[$name] = $value; 5011 } 5012 break; 5013 } 5014 } 5015 } 5016 5017 /** 5018 * end-element handler 5019 * 5020 * @param string $parser XML parser object 5021 * @param string $name element name 5022 * @access private 5023 */ 5024 function end_element($parser, $name){ 5025 // unset schema status 5026 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) { 5027 $this->status = ""; 5028 $this->appendDebug($this->currentSchema->getDebug()); 5029 $this->currentSchema->clearDebug(); 5030 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 5031 $this->debug('Parsing WSDL schema done'); 5032 } 5033 if ($this->status == 'schema') { 5034 $this->currentSchema->schemaEndElement($parser, $name); 5035 } else { 5036 // bring depth down a notch 5037 $this->depth--; 5038 } 5039 // end documentation 5040 if ($this->documentation) { 5041 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 5042 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 5043 $this->documentation = false; 5044 } 5045 } 5046 5047 /** 5048 * element content handler 5049 * 5050 * @param string $parser XML parser object 5051 * @param string $data element content 5052 * @access private 5053 */ 5054 function character_data($parser, $data) 5055 { 5056 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 5057 if (isset($this->message[$pos]['cdata'])) { 5058 $this->message[$pos]['cdata'] .= $data; 5059 } 5060 if ($this->documentation) { 5061 $this->documentation .= $data; 5062 } 5063 } 5064 5065 /** 5066 * if authenticating, set user credentials here 5067 * 5068 * @param string $username 5069 * @param string $password 5070 * @param string $authtype (basic|digest|certificate|ntlm) 5071 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 5072 * @access public 5073 */ 5074 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 5075 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 5076 $this->appendDebug($this->varDump($certRequest)); 5077 $this->username = $username; 5078 $this->password = $password; 5079 $this->authtype = $authtype; 5080 $this->certRequest = $certRequest; 5081 } 5082 5083 function getBindingData($binding) 5084 { 5085 if (is_array($this->bindings[$binding])) { 5086 return $this->bindings[$binding]; 5087 } 5088 } 5089 5090 /** 5091 * returns an assoc array of operation names => operation data 5092 * 5093 * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) 5094 * @return array 5095 * @access public 5096 */ 5097 function getOperations($bindingType = 'soap') { 5098 $ops = array(); 5099 if ($bindingType == 'soap') { 5100 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 5101 } elseif ($bindingType == 'soap12') { 5102 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 5103 } 5104 // loop thru ports 5105 foreach($this->ports as $port => $portData) { 5106 // binding type of port matches parameter 5107 if ($portData['bindingType'] == $bindingType) { 5108 //$this->debug("getOperations for port $port"); 5109 //$this->debug("port data: " . $this->varDump($portData)); 5110 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 5111 // merge bindings 5112 if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 5113 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 5114 } 5115 } 5116 } 5117 return $ops; 5118 } 5119 5120 /** 5121 * returns an associative array of data necessary for calling an operation 5122 * 5123 * @param string $operation name of operation 5124 * @param string $bindingType type of binding eg: soap, soap12 5125 * @return array 5126 * @access public 5127 */ 5128 function getOperationData($operation, $bindingType = 'soap') 5129 { 5130 if ($bindingType == 'soap') { 5131 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 5132 } elseif ($bindingType == 'soap12') { 5133 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 5134 } 5135 // loop thru ports 5136 foreach($this->ports as $port => $portData) { 5137 // binding type of port matches parameter 5138 if ($portData['bindingType'] == $bindingType) { 5139 // get binding 5140 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 5141 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 5142 // note that we could/should also check the namespace here 5143 if ($operation == $bOperation) { 5144 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 5145 return $opData; 5146 } 5147 } 5148 } 5149 } 5150 } 5151 5152 /** 5153 * returns an associative array of data necessary for calling an operation 5154 * 5155 * @param string $soapAction soapAction for operation 5156 * @param string $bindingType type of binding eg: soap, soap12 5157 * @return array 5158 * @access public 5159 */ 5160 function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 5161 if ($bindingType == 'soap') { 5162 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 5163 } elseif ($bindingType == 'soap12') { 5164 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 5165 } 5166 // loop thru ports 5167 foreach($this->ports as $port => $portData) { 5168 // binding type of port matches parameter 5169 if ($portData['bindingType'] == $bindingType) { 5170 // loop through operations for the binding 5171 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 5172 if ($opData['soapAction'] == $soapAction) { 5173 return $opData; 5174 } 5175 } 5176 } 5177 } 5178 } 5179 5180 /** 5181 * returns an array of information about a given type 5182 * returns false if no type exists by the given name 5183 * 5184 * typeDef = array( 5185 * 'elements' => array(), // refs to elements array 5186 * 'restrictionBase' => '', 5187 * 'phpType' => '', 5188 * 'order' => '(sequence|all)', 5189 * 'attrs' => array() // refs to attributes array 5190 * ) 5191 * 5192 * @param string $type the type 5193 * @param string $ns namespace (not prefix) of the type 5194 * @return mixed 5195 * @access public 5196 * @see nusoap_xmlschema 5197 */ 5198 function getTypeDef($type, $ns) { 5199 $this->debug("in getTypeDef: type=$type, ns=$ns"); 5200 if ((! $ns) && isset($this->namespaces['tns'])) { 5201 $ns = $this->namespaces['tns']; 5202 $this->debug("in getTypeDef: type namespace forced to $ns"); 5203 } 5204 if (!isset($this->schemas[$ns])) { 5205 foreach ($this->schemas as $ns0 => $schema0) { 5206 if (strcasecmp($ns, $ns0) == 0) { 5207 $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); 5208 $ns = $ns0; 5209 break; 5210 } 5211 } 5212 } 5213 if (isset($this->schemas[$ns])) { 5214 $this->debug("in getTypeDef: have schema for namespace $ns"); 5215 for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 5216 $xs = &$this->schemas[$ns][$i]; 5217 $t = $xs->getTypeDef($type); 5218 //$this->appendDebug($xs->getDebug()); 5219 //$xs->clearDebug(); 5220 if ($t) { 5221 if (!isset($t['phpType'])) { 5222 // get info for type to tack onto the element 5223 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 5224 $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 5225 $etype = $this->getTypeDef($uqType, $ns); 5226 if ($etype) { 5227 $this->debug("found type for [element] $type:"); 5228 $this->debug($this->varDump($etype)); 5229 if (isset($etype['phpType'])) { 5230 $t['phpType'] = $etype['phpType']; 5231 } 5232 if (isset($etype['elements'])) { 5233 $t['elements'] = $etype['elements']; 5234 } 5235 if (isset($etype['attrs'])) { 5236 $t['attrs'] = $etype['attrs']; 5237 } 5238 } 5239 } 5240 return $t; 5241 } 5242 } 5243 } else { 5244 $this->debug("in getTypeDef: do not have schema for namespace $ns"); 5245 } 5246 return false; 5247 } 5248 5249 /** 5250 * prints html description of services 5251 * 5252 * @access private 5253 */ 5254 function webDescription(){ 5255 global $HTTP_SERVER_VARS; 5256 5257 if (isset($_SERVER)) { 5258 $PHP_SELF = $_SERVER['PHP_SELF']; 5259 } elseif (isset($HTTP_SERVER_VARS)) { 5260 $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 5261 } else { 5262 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 5263 } 5264 5265 $b = ' 5266 <html><head><title>NuSOAP: '.$this->serviceName.'</title> 5267 <style type="text/css"> 5268 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 5269 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 5270 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 5271 ul { margin-top: 10px; margin-left: 20px; } 5272 li { list-style-type: none; margin-top: 10px; color: #000000; } 5273 .content{ 5274 margin-left: 0px; padding-bottom: 2em; } 5275 .nav { 5276 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 5277 margin-top: 10px; margin-left: 0px; color: #000000; 5278 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 5279 .title { 5280 font-family: arial; font-size: 26px; color: #ffffff; 5281 background-color: #999999; width: 105%; margin-left: 0px; 5282 padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} 5283 .hidden { 5284 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 5285 font-family: arial; overflow: hidden; width: 600; 5286 padding: 20px; font-size: 10px; background-color: #999999; 5287 layer-background-color:#FFFFFF; } 5288 a,a:active { color: charcoal; font-weight: bold; } 5289 a:visited { color: #666666; font-weight: bold; } 5290 a:hover { color: cc3300; font-weight: bold; } 5291 </style> 5292 <script language="JavaScript" type="text/javascript"> 5293 <!-- 5294 // POP-UP CAPTIONS... 5295 function lib_bwcheck(){ //Browsercheck (needed) 5296 this.ver=navigator.appVersion 5297 this.agent=navigator.userAgent 5298 this.dom=document.getElementById?1:0 5299 this.opera5=this.agent.indexOf("Opera 5")>-1 5300 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 5301 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 5302 this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 5303 this.ie=this.ie4||this.ie5||this.ie6 5304 this.mac=this.agent.indexOf("Mac")>-1 5305 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 5306 this.ns4=(document.layers && !this.dom)?1:0; 5307 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 5308 return this 5309 } 5310 var bw = new lib_bwcheck() 5311 //Makes crossbrowser object. 5312 function makeObj(obj){ 5313 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 5314 if(!this.evnt) return false 5315 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 5316 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 5317 this.writeIt=b_writeIt; 5318 return this 5319 } 5320 // A unit of measure that will be added when setting the position of a layer. 5321 //var px = bw.ns4||window.opera?"":"px"; 5322 function b_writeIt(text){ 5323 if (bw.ns4){this.wref.write(text);this.wref.close()} 5324 else this.wref.innerHTML = text 5325 } 5326 //Shows the messages 5327 var oDesc; 5328 function popup(divid){ 5329 if(oDesc = new makeObj(divid)){ 5330 oDesc.css.visibility = "visible" 5331 } 5332 } 5333 function popout(){ // Hides message 5334 if(oDesc) oDesc.css.visibility = "hidden" 5335 } 5336 //--> 5337 </script> 5338 </head> 5339 <body> 5340 <div class=content> 5341 <br><br> 5342 <div class=title>'.$this->serviceName.'</div> 5343 <div class=nav> 5344 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 5345 Click on an operation name to view it's details.</p> 5346 <ul>'; 5347 foreach($this->getOperations() as $op => $data){ 5348 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 5349 // create hidden div 5350 $b .= "<div id='$op' class='hidden'> 5351 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 5352 foreach($data as $donnie => $marie){ // loop through opdata 5353 if($donnie == 'input' || $donnie == 'output'){ // show input/output data 5354 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 5355 foreach($marie as $captain => $tenille){ // loop through data 5356 if($captain == 'parts'){ // loop thru parts 5357 $b .= " $captain:<br>"; 5358 //if(is_array($tenille)){ 5359 foreach($tenille as $joanie => $chachi){ 5360 $b .= " $joanie: $chachi<br>"; 5361 } 5362 //} 5363 } else { 5364 $b .= " $captain: $tenille<br>"; 5365 } 5366 } 5367 } else { 5368 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 5369 } 5370 } 5371 $b .= '</div>'; 5372 } 5373 $b .= ' 5374 <ul> 5375 </div> 5376 </div></body></html>'; 5377 return $b; 5378 } 5379 5380 /** 5381 * serialize the parsed wsdl 5382 * 5383 * @param mixed $debug whether to put debug=1 in endpoint URL 5384 * @return string serialization of WSDL 5385 * @access public 5386 */ 5387 function serialize($debug = 0) 5388 { 5389 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 5390 $xml .= "\n<definitions"; 5391 foreach($this->namespaces as $k => $v) { 5392 $xml .= " xmlns:$k=\"$v\""; 5393 } 5394 // 10.9.02 - add poulter fix for wsdl and tns declarations 5395 if (isset($this->namespaces['wsdl'])) { 5396 $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 5397 } 5398 if (isset($this->namespaces['tns'])) { 5399 $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 5400 } 5401 $xml .= '>'; 5402 // imports 5403 if (sizeof($this->import) > 0) { 5404 foreach($this->import as $ns => $list) { 5405 foreach ($list as $ii) { 5406 if ($ii['location'] != '') { 5407 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 5408 } else { 5409 $xml .= '<import namespace="' . $ns . '" />'; 5410 } 5411 } 5412 } 5413 } 5414 // types 5415 if (count($this->schemas)>=1) { 5416 $xml .= "\n<types>\n"; 5417 foreach ($this->schemas as $ns => $list) { 5418 foreach ($list as $xs) { 5419 $xml .= $xs->serializeSchema(); 5420 } 5421 } 5422 $xml .= '</types>'; 5423 } 5424 // messages 5425 if (count($this->messages) >= 1) { 5426 foreach($this->messages as $msgName => $msgParts) { 5427 $xml .= "\n<message name=\"" . $msgName . '">'; 5428 if(is_array($msgParts)){ 5429 foreach($msgParts as $partName => $partType) { 5430 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 5431 if (strpos($partType, ':')) { 5432 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 5433 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 5434 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 5435 $typePrefix = 'xsd'; 5436 } else { 5437 foreach($this->typemap as $ns => $types) { 5438 if (isset($types[$partType])) { 5439 $typePrefix = $this->getPrefixFromNamespace($ns); 5440 } 5441 } 5442 if (!isset($typePrefix)) { 5443 die("$partType has no namespace!"); 5444 } 5445 } 5446 $ns = $this->getNamespaceFromPrefix($typePrefix); 5447 $localPart = $this->getLocalPart($partType); 5448 $typeDef = $this->getTypeDef($localPart, $ns); 5449 if ($typeDef['typeClass'] == 'element') { 5450 $elementortype = 'element'; 5451 if (substr($localPart, -1) == '^') { 5452 $localPart = substr($localPart, 0, -1); 5453 } 5454 } else { 5455 $elementortype = 'type'; 5456 } 5457 $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; 5458 } 5459 } 5460 $xml .= '</message>'; 5461 } 5462 } 5463 // bindings & porttypes 5464 if (count($this->bindings) >= 1) { 5465 $binding_xml = ''; 5466 $portType_xml = ''; 5467 foreach($this->bindings as $bindingName => $attrs) { 5468 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 5469 $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 5470 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 5471 foreach($attrs['operations'] as $opName => $opParts) { 5472 $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; 5473 $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 5474 if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 5475 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 5476 } else { 5477 $enc_style = ''; 5478 } 5479 $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 5480 if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 5481 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 5482 } else { 5483 $enc_style = ''; 5484 } 5485 $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 5486 $binding_xml .= "\n" . ' </operation>'; 5487 $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; 5488 if (isset($opParts['parameterOrder'])) { 5489 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 5490 } 5491 $portType_xml .= '>'; 5492 if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 5493 $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 5494 } 5495 $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; 5496 $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; 5497 $portType_xml .= "\n" . ' </operation>'; 5498 } 5499 $portType_xml .= "\n" . '</portType>'; 5500 $binding_xml .= "\n" . '</binding>'; 5501 } 5502 $xml .= $portType_xml . $binding_xml; 5503 } 5504 // services 5505 $xml .= "\n<service name=\"" . $this->serviceName . '">'; 5506 if (count($this->ports) >= 1) { 5507 foreach($this->ports as $pName => $attrs) { 5508 $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 5509 $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 5510 $xml .= "\n" . ' </port>'; 5511 } 5512 } 5513 $xml .= "\n" . '</service>'; 5514 return $xml . "\n</definitions>"; 5515 } 5516 5517 /** 5518 * determine whether a set of parameters are unwrapped 5519 * when they are expect to be wrapped, Microsoft-style. 5520 * 5521 * @param string $type the type (element name) of the wrapper 5522 * @param array $parameters the parameter values for the SOAP call 5523 * @return boolean whether they parameters are unwrapped (and should be wrapped) 5524 * @access private 5525 */ 5526 function parametersMatchWrapped($type, &$parameters) { 5527 $this->debug("in parametersMatchWrapped type=$type, parameters="); 5528 $this->appendDebug($this->varDump($parameters)); 5529 5530 // split type into namespace:unqualified-type 5531 if (strpos($type, ':')) { 5532 $uqType = substr($type, strrpos($type, ':') + 1); 5533 $ns = substr($type, 0, strrpos($type, ':')); 5534 $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); 5535 if ($this->getNamespaceFromPrefix($ns)) { 5536 $ns = $this->getNamespaceFromPrefix($ns); 5537 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); 5538 } 5539 } else { 5540 // TODO: should the type be compared to types in XSD, and the namespace 5541 // set to XSD if the type matches? 5542 $this->debug("in parametersMatchWrapped: No namespace for type $type"); 5543 $ns = ''; 5544 $uqType = $type; 5545 } 5546 5547 // get the type information 5548 if (!$typeDef = $this->getTypeDef($uqType, $ns)) { 5549 $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); 5550 return false; 5551 } 5552 $this->debug("in parametersMatchWrapped: found typeDef="); 5553 $this->appendDebug($this->varDump($typeDef)); 5554 if (substr($uqType, -1) == '^') { 5555 $uqType = substr($uqType, 0, -1); 5556 } 5557 $phpType = $typeDef['phpType']; 5558 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); 5559 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); 5560 5561 // we expect a complexType or element of complexType 5562 if ($phpType != 'struct') { 5563 $this->debug("in parametersMatchWrapped: not a struct"); 5564 return false; 5565 } 5566 5567 // see whether the parameter names match the elements 5568 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 5569 $elements = 0; 5570 $matches = 0; 5571 $change = false; 5572 if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) { 5573 $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap"); 5574 $change = true; 5575 } 5576 foreach ($typeDef['elements'] as $name => $attrs) { 5577 if ($change) { 5578 $this->debug("in parametersMatchWrapped: change parameter $element to name $name"); 5579 $parameters[$name] = $parameters[$elements]; 5580 unset($parameters[$elements]); 5581 $matches++; 5582 } elseif (isset($parameters[$name])) { 5583 $this->debug("in parametersMatchWrapped: have parameter named $name"); 5584 $matches++; 5585 } else { 5586 $this->debug("in parametersMatchWrapped: do not have parameter named $name"); 5587 } 5588 $elements++; 5589 } 5590 5591 $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); 5592 if ($matches == 0) { 5593 return false; 5594 } 5595 return true; 5596 } 5597 5598 // since there are no elements for the type, if the user passed no 5599 // parameters, the parameters match wrapped. 5600 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); 5601 return count($parameters) == 0; 5602 } 5603 5604 /** 5605 * serialize PHP values according to a WSDL message definition 5606 * contrary to the method name, this is not limited to RPC 5607 * 5608 * TODO 5609 * - multi-ref serialization 5610 * - validate PHP values against type definitions, return errors if invalid 5611 * 5612 * @param string $operation operation name 5613 * @param string $direction (input|output) 5614 * @param mixed $parameters parameter value(s) 5615 * @param string $bindingType (soap|soap12) 5616 * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 5617 * @access public 5618 */ 5619 function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { 5620 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); 5621 $this->appendDebug('parameters=' . $this->varDump($parameters)); 5622 5623 if ($direction != 'input' && $direction != 'output') { 5624 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 5625 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 5626 return false; 5627 } 5628 if (!$opData = $this->getOperationData($operation, $bindingType)) { 5629 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 5630 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 5631 return false; 5632 } 5633 $this->debug('in serializeRPCParameters: opData:'); 5634 $this->appendDebug($this->varDump($opData)); 5635 5636 // Get encoding style for output and set to current 5637 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 5638 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 5639 $encodingStyle = $opData['output']['encodingStyle']; 5640 $enc_style = $encodingStyle; 5641 } 5642 5643 // set input params 5644 $xml = ''; 5645 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 5646 $parts = &$opData[$direction]['parts']; 5647 $part_count = sizeof($parts); 5648 $style = $opData['style']; 5649 $use = $opData[$direction]['use']; 5650 $this->debug("have $part_count part(s) to serialize using $style/$use"); 5651 if (is_array($parameters)) { 5652 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 5653 $parameter_count = count($parameters); 5654 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); 5655 // check for Microsoft-style wrapped parameters 5656 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { 5657 $this->debug('check whether the caller has wrapped the parameters'); 5658 if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) { 5659 $this->debug('check whether caller\'s parameters match the wrapped ones'); 5660 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { 5661 $this->debug('wrap the parameters for the caller'); 5662 $parameters = array('parameters' => $parameters); 5663 $parameter_count = 1; 5664 } 5665 } 5666 } 5667 foreach ($parts as $name => $type) { 5668 $this->debug("serializing part $name of type $type"); 5669 // Track encoding style 5670 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 5671 $encodingStyle = $opData[$direction]['encodingStyle']; 5672 $enc_style = $encodingStyle; 5673 } else { 5674 $enc_style = false; 5675 } 5676 // NOTE: add error handling here 5677 // if serializeType returns false, then catch global error and fault 5678 if ($parametersArrayType == 'arraySimple') { 5679 $p = array_shift($parameters); 5680 $this->debug('calling serializeType w/indexed param'); 5681 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 5682 } elseif (isset($parameters[$name])) { 5683 $this->debug('calling serializeType w/named param'); 5684 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 5685 } else { 5686 // TODO: only send nillable 5687 $this->debug('calling serializeType w/null param'); 5688 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 5689 } 5690 } 5691 } else { 5692 $this->debug('no parameters passed.'); 5693 } 5694 } 5695 $this->debug("serializeRPCParameters returning: $xml"); 5696 return $xml; 5697 } 5698 5699 /** 5700 * serialize a PHP value according to a WSDL message definition 5701 * 5702 * TODO 5703 * - multi-ref serialization 5704 * - validate PHP values against type definitions, return errors if invalid 5705 * 5706 * @param string $operation operation name 5707 * @param string $direction (input|output) 5708 * @param mixed $parameters parameter value(s) 5709 * @return mixed parameters serialized as XML or false on error (e.g. operation not found) 5710 * @access public 5711 * @deprecated 5712 */ 5713 function serializeParameters($operation, $direction, $parameters) 5714 { 5715 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 5716 $this->appendDebug('parameters=' . $this->varDump($parameters)); 5717 5718 if ($direction != 'input' && $direction != 'output') { 5719 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 5720 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 5721 return false; 5722 } 5723 if (!$opData = $this->getOperationData($operation)) { 5724 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 5725 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 5726 return false; 5727 } 5728 $this->debug('opData:'); 5729 $this->appendDebug($this->varDump($opData)); 5730 5731 // Get encoding style for output and set to current 5732 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 5733 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 5734 $encodingStyle = $opData['output']['encodingStyle']; 5735 $enc_style = $encodingStyle; 5736 } 5737 5738 // set input params 5739 $xml = ''; 5740 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 5741 5742 $use = $opData[$direction]['use']; 5743 $this->debug("use=$use"); 5744 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 5745 if (is_array($parameters)) { 5746 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 5747 $this->debug('have ' . $parametersArrayType . ' parameters'); 5748 foreach($opData[$direction]['parts'] as $name => $type) { 5749 $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 5750 // Track encoding style 5751 if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 5752 $encodingStyle = $opData[$direction]['encodingStyle']; 5753 $enc_style = $encodingStyle; 5754 } else { 5755 $enc_style = false; 5756 } 5757 // NOTE: add error handling here 5758 // if serializeType returns false, then catch global error and fault 5759 if ($parametersArrayType == 'arraySimple') { 5760 $p = array_shift($parameters); 5761 $this->debug('calling serializeType w/indexed param'); 5762 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 5763 } elseif (isset($parameters[$name])) { 5764 $this->debug('calling serializeType w/named param'); 5765 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 5766 } else { 5767 // TODO: only send nillable 5768 $this->debug('calling serializeType w/null param'); 5769 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 5770 } 5771 } 5772 } else { 5773 $this->debug('no parameters passed.'); 5774 } 5775 } 5776 $this->debug("serializeParameters returning: $xml"); 5777 return $xml; 5778 } 5779 5780 /** 5781 * serializes a PHP value according a given type definition 5782 * 5783 * @param string $name name of value (part or element) 5784 * @param string $type XML schema type of value (type or element) 5785 * @param mixed $value a native PHP value (parameter value) 5786 * @param string $use use for part (encoded|literal) 5787 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 5788 * @param boolean $unqualified a kludge for what should be XML namespace form handling 5789 * @return string value serialized as an XML string 5790 * @access private 5791 */ 5792 function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 5793 { 5794 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 5795 $this->appendDebug("value=" . $this->varDump($value)); 5796 if($use == 'encoded' && $encodingStyle) { 5797 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 5798 } 5799 5800 // if a soapval has been supplied, let its type override the WSDL 5801 if (is_object($value) && get_class($value) == 'soapval') { 5802 if ($value->type_ns) { 5803 $type = $value->type_ns . ':' . $value->type; 5804 $forceType = true; 5805 $this->debug("in serializeType: soapval overrides type to $type"); 5806 } elseif ($value->type) { 5807 $type = $value->type; 5808 $forceType = true; 5809 $this->debug("in serializeType: soapval overrides type to $type"); 5810 } else { 5811 $forceType = false; 5812 $this->debug("in serializeType: soapval does not override type"); 5813 } 5814 $attrs = $value->attributes; 5815 $value = $value->value; 5816 $this->debug("in serializeType: soapval overrides value to $value"); 5817 if ($attrs) { 5818 if (!is_array($value)) { 5819 $value['!'] = $value; 5820 } 5821 foreach ($attrs as $n => $v) { 5822 $value['!' . $n] = $v; 5823 } 5824 $this->debug("in serializeType: soapval provides attributes"); 5825 } 5826 } else { 5827 $forceType = false; 5828 } 5829 5830 $xml = ''; 5831 if (strpos($type, ':')) { 5832 $uqType = substr($type, strrpos($type, ':') + 1); 5833 $ns = substr($type, 0, strrpos($type, ':')); 5834 $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 5835 if ($this->getNamespaceFromPrefix($ns)) { 5836 $ns = $this->getNamespaceFromPrefix($ns); 5837 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 5838 } 5839 5840 if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ 5841 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 5842 if ($unqualified && $use == 'literal') { 5843 $elementNS = " xmlns=\"\""; 5844 } else { 5845 $elementNS = ''; 5846 } 5847 if (is_null($value)) { 5848 if ($use == 'literal') { 5849 // TODO: depends on minOccurs 5850 $xml = "<$name$elementNS/>"; 5851 } else { 5852 // TODO: depends on nillable, which should be checked before calling this method 5853 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 5854 } 5855 $this->debug("in serializeType: returning: $xml"); 5856 return $xml; 5857 } 5858 if ($uqType == 'Array') { 5859 // JBoss/Axis does this sometimes 5860 return $this->serialize_val($value, $name, false, false, false, false, $use); 5861 } 5862 if ($uqType == 'boolean') { 5863 if ((is_string($value) && $value == 'false') || (! $value)) { 5864 $value = 'false'; 5865 } else { 5866 $value = 'true'; 5867 } 5868 } 5869 if ($uqType == 'string' && gettype($value) == 'string') { 5870 // NEW BSP - Preventing to escape if string has a CDATA-Block 5871 if(strpos($value, "<![CDATA[") > -1) 5872 { 5873 // nothing todo 5874 } 5875 else 5876 { 5877 $value = $this->expandEntities($value); 5878 } 5879 } 5880 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 5881 $value = sprintf("%.0lf", $value); 5882 } 5883 // it's a scalar 5884 // TODO: what about null/nil values? 5885 // check type isn't a custom type extending xmlschema namespace 5886 if (!$this->getTypeDef($uqType, $ns)) { 5887 if ($use == 'literal') { 5888 if ($forceType) { 5889 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 5890 } else { 5891 $xml = "<$name$elementNS>$value</$name>"; 5892 } 5893 } else { 5894 // CHANGES: BSP 5895 /* 5896 * if($this->getPrefixFromNamespace($ns) . ":" . $uqType == "xsd:string") 5897 * { 5898 * $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle><![CDATA[$value]]></$name>"; 5899 * } 5900 * else 5901 * { 5902 * $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 5903 * } 5904 */ 5905 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 5906 } 5907 $this->debug("in serializeType: returning: $xml"); 5908 return $xml; 5909 } 5910 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 5911 } else if ($ns == 'http://xml.apache.org/xml-soap') { 5912 $this->debug('in serializeType: appears to be Apache SOAP type'); 5913 if ($uqType == 'Map') { 5914 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 5915 if (! $tt_prefix) { 5916 $this->debug('in serializeType: Add namespace for Apache SOAP type'); 5917 $tt_prefix = 'ns' . rand(1000, 9999); 5918 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 5919 // force this to be added to usedNamespaces 5920 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 5921 } 5922 $contents = ''; 5923 foreach($value as $k => $v) { 5924 $this->debug("serializing map element: key $k, value $v"); 5925 $contents .= '<item>'; 5926 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); 5927 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); 5928 $contents .= '</item>'; 5929 } 5930 if ($use == 'literal') { 5931 if ($forceType) { 5932 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 5933 } else { 5934 $xml = "<$name>$contents</$name>"; 5935 } 5936 } else { 5937 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 5938 } 5939 $this->debug("in serializeType: returning: $xml"); 5940 return $xml; 5941 } 5942 $this->debug('in serializeType: Apache SOAP type, but only support Map'); 5943 } 5944 } else { 5945 // TODO: should the type be compared to types in XSD, and the namespace 5946 // set to XSD if the type matches? 5947 $this->debug("in serializeType: No namespace for type $type"); 5948 $ns = ''; 5949 $uqType = $type; 5950 } 5951 if(!$typeDef = $this->getTypeDef($uqType, $ns)){ 5952 $this->setError("$type ($uqType) is not a supported type."); 5953 $this->debug("in serializeType: $type ($uqType) is not a supported type."); 5954 return false; 5955 } else { 5956 $this->debug("in serializeType: found typeDef"); 5957 $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 5958 if (substr($uqType, -1) == '^') { 5959 $uqType = substr($uqType, 0, -1); 5960 } 5961 } 5962 $phpType = $typeDef['phpType']; 5963 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 5964 // if php type == struct, map value to the <all> element names 5965 if ($phpType == 'struct') { 5966 if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 5967 $elementName = $uqType; 5968 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 5969 $elementNS = " xmlns=\"$ns\""; 5970 } else { 5971 $elementNS = " xmlns=\"\""; 5972 } 5973 } else { 5974 $elementName = $name; 5975 if ($unqualified) { 5976 $elementNS = " xmlns=\"\""; 5977 } else { 5978 $elementNS = ''; 5979 } 5980 } 5981 if (is_null($value)) { 5982 if ($use == 'literal') { 5983 // TODO: depends on minOccurs 5984 $xml = "<$elementName$elementNS/>"; 5985 } else { 5986 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 5987 } 5988 $this->debug("in serializeType: returning: $xml"); 5989 return $xml; 5990 } 5991 if (is_object($value)) { 5992 $value = get_object_vars($value); 5993 } 5994 if (is_array($value)) { 5995 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 5996 if ($use == 'literal') { 5997 if ($forceType) { 5998 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 5999 } else { 6000 $xml = "<$elementName$elementNS$elementAttrs>"; 6001 } 6002 } else { 6003 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 6004 } 6005 6006 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 6007 $xml .= "</$elementName>"; 6008 } else { 6009 $this->debug("in serializeType: phpType is struct, but value is not an array"); 6010 $this->setError("phpType is struct, but value is not an array: see debug output for details"); 6011 $xml = ''; 6012 } 6013 } elseif ($phpType == 'array') { 6014 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 6015 $elementNS = " xmlns=\"$ns\""; 6016 } else { 6017 if ($unqualified) { 6018 $elementNS = " xmlns=\"\""; 6019 } else { 6020 $elementNS = ''; 6021 } 6022 } 6023 if (is_null($value)) { 6024 if ($use == 'literal') { 6025 // TODO: depends on minOccurs 6026 $xml = "<$name$elementNS/>"; 6027 } else { 6028 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 6029 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 6030 ":Array\" " . 6031 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 6032 ':arrayType="' . 6033 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 6034 ':' . 6035 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 6036 } 6037 $this->debug("in serializeType: returning: $xml"); 6038 return $xml; 6039 } 6040 if (isset($typeDef['multidimensional'])) { 6041 $nv = array(); 6042 foreach($value as $v) { 6043 $cols = ',' . sizeof($v); 6044 $nv = array_merge($nv, $v); 6045 } 6046 $value = $nv; 6047 } else { 6048 $cols = ''; 6049 } 6050 if (is_array($value) && sizeof($value) >= 1) { 6051 $rows = sizeof($value); 6052 $contents = ''; 6053 foreach($value as $k => $v) { 6054 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 6055 //if (strpos($typeDef['arrayType'], ':') ) { 6056 if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { 6057 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 6058 } else { 6059 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 6060 } 6061 } 6062 } else { 6063 $rows = 0; 6064 $contents = null; 6065 } 6066 // TODO: for now, an empty value will be serialized as a zero element 6067 // array. Revisit this when coding the handling of null/nil values. 6068 if ($use == 'literal') { 6069 $xml = "<$name$elementNS>" 6070 .$contents 6071 ."</$name>"; 6072 } else { 6073 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 6074 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 6075 .':arrayType="' 6076 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 6077 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 6078 .$contents 6079 ."</$name>"; 6080 } 6081 } elseif ($phpType == 'scalar') { 6082 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 6083 $elementNS = " xmlns=\"$ns\""; 6084 } else { 6085 if ($unqualified) { 6086 $elementNS = " xmlns=\"\""; 6087 } else { 6088 $elementNS = ''; 6089 } 6090 } 6091 if ($use == 'literal') { 6092 if ($forceType) { 6093 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 6094 } else { 6095 $xml = "<$name$elementNS>$value</$name>"; 6096 } 6097 } else { 6098 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 6099 } 6100 } 6101 $this->debug("in serializeType: returning: $xml"); 6102 return $xml; 6103 } 6104 6105 /** 6106 * serializes the attributes for a complexType 6107 * 6108 * @param array $typeDef our internal representation of an XML schema type (or element) 6109 * @param mixed $value a native PHP value (parameter value) 6110 * @param string $ns the namespace of the type 6111 * @param string $uqType the local part of the type 6112 * @return string value serialized as an XML string 6113 * @access private 6114 */ 6115 function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 6116 $xml = ''; 6117 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 6118 $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 6119 if (is_array($value)) { 6120 $xvalue = $value; 6121 } elseif (is_object($value)) { 6122 $xvalue = get_object_vars($value); 6123 } else { 6124 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 6125 $xvalue = array(); 6126 } 6127 foreach ($typeDef['attrs'] as $aName => $attrs) { 6128 if (isset($xvalue['!' . $aName])) { 6129 $xname = '!' . $aName; 6130 $this->debug("value provided for attribute $aName with key $xname"); 6131 } elseif (isset($xvalue[$aName])) { 6132 $xname = $aName; 6133 $this->debug("value provided for attribute $aName with key $xname"); 6134 } elseif (isset($attrs['default'])) { 6135 $xname = '!' . $aName; 6136 $xvalue[$xname] = $attrs['default']; 6137 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 6138 } else { 6139 $xname = ''; 6140 $this->debug("no value provided for attribute $aName"); 6141 } 6142 if ($xname) { 6143 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 6144 } 6145 } 6146 } else { 6147 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 6148 } 6149 if (isset($typeDef['extensionBase'])) { 6150 $ns = $this->getPrefix($typeDef['extensionBase']); 6151 $uqType = $this->getLocalPart($typeDef['extensionBase']); 6152 if ($this->getNamespaceFromPrefix($ns)) { 6153 $ns = $this->getNamespaceFromPrefix($ns); 6154 } 6155 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 6156 $this->debug("serialize attributes for extension base $ns:$uqType"); 6157 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 6158 } else { 6159 $this->debug("extension base $ns:$uqType is not a supported type"); 6160 } 6161 } 6162 return $xml; 6163 } 6164 6165 /** 6166 * serializes the elements for a complexType 6167 * 6168 * @param array $typeDef our internal representation of an XML schema type (or element) 6169 * @param mixed $value a native PHP value (parameter value) 6170 * @param string $ns the namespace of the type 6171 * @param string $uqType the local part of the type 6172 * @param string $use use for part (encoded|literal) 6173 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) 6174 * @return string value serialized as an XML string 6175 * @access private 6176 */ 6177 function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 6178 $xml = ''; 6179 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 6180 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 6181 if (is_array($value)) { 6182 $xvalue = $value; 6183 } elseif (is_object($value)) { 6184 $xvalue = get_object_vars($value); 6185 } else { 6186 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 6187 $xvalue = array(); 6188 } 6189 // toggle whether all elements are present - ideally should validate against schema 6190 if (count($typeDef['elements']) != count($xvalue)){ 6191 $optionals = true; 6192 } 6193 foreach ($typeDef['elements'] as $eName => $attrs) { 6194 if (!isset($xvalue[$eName])) { 6195 if (isset($attrs['default'])) { 6196 $xvalue[$eName] = $attrs['default']; 6197 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 6198 } 6199 } 6200 // if user took advantage of a minOccurs=0, then only serialize named parameters 6201 if (isset($optionals) 6202 && (!isset($xvalue[$eName])) 6203 && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 6204 ){ 6205 if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 6206 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 6207 } 6208 // do nothing 6209 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 6210 } else { 6211 // get value 6212 if (isset($xvalue[$eName])) { 6213 $v = $xvalue[$eName]; 6214 } else { 6215 $v = null; 6216 } 6217 if (isset($attrs['form'])) { 6218 $unqualified = ($attrs['form'] == 'unqualified'); 6219 } else { 6220 $unqualified = false; 6221 } 6222 if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 6223 $vv = $v; 6224 foreach ($vv as $k => $v) { 6225 if (isset($attrs['type']) || isset($attrs['ref'])) { 6226 // serialize schema-defined type 6227 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 6228 } else { 6229 // serialize generic type (can this ever really happen?) 6230 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 6231 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 6232 } 6233 } 6234 } else { 6235 if (isset($attrs['type']) || isset($attrs['ref'])) { 6236 // serialize schema-defined type 6237 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 6238 } else { 6239 // serialize generic type (can this ever really happen?) 6240 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 6241 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 6242 } 6243 } 6244 } 6245 } 6246 } else { 6247 $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 6248 } 6249 if (isset($typeDef['extensionBase'])) { 6250 $ns = $this->getPrefix($typeDef['extensionBase']); 6251 $uqType = $this->getLocalPart($typeDef['extensionBase']); 6252 if ($this->getNamespaceFromPrefix($ns)) { 6253 $ns = $this->getNamespaceFromPrefix($ns); 6254 } 6255 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 6256 $this->debug("serialize elements for extension base $ns:$uqType"); 6257 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 6258 } else { 6259 $this->debug("extension base $ns:$uqType is not a supported type"); 6260 } 6261 } 6262 return $xml; 6263 } 6264 6265 /** 6266 * adds an XML Schema complex type to the WSDL types 6267 * 6268 * @param string $name 6269 * @param string $typeClass (complexType|simpleType|attribute) 6270 * @param string $phpType currently supported are array and struct (php assoc array) 6271 * @param string $compositor (all|sequence|choice) 6272 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 6273 * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) 6274 * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) 6275 * @param string $arrayType as namespace:name (xsd:string) 6276 * @see nusoap_xmlschema 6277 * @access public 6278 */ 6279 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { 6280 if (count($elements) > 0) { 6281 $eElements = array(); 6282 foreach($elements as $n => $e){ 6283 // expand each element 6284 $ee = array(); 6285 foreach ($e as $k => $v) { 6286 $k = strpos($k,':') ? $this->expandQname($k) : $k; 6287 $v = strpos($v,':') ? $this->expandQname($v) : $v; 6288 $ee[$k] = $v; 6289 } 6290 $eElements[$n] = $ee; 6291 } 6292 $elements = $eElements; 6293 } 6294 6295 if (count($attrs) > 0) { 6296 foreach($attrs as $n => $a){ 6297 // expand each attribute 6298 foreach ($a as $k => $v) { 6299 $k = strpos($k,':') ? $this->expandQname($k) : $k; 6300 $v = strpos($v,':') ? $this->expandQname($v) : $v; 6301 $aa[$k] = $v; 6302 } 6303 $eAttrs[$n] = $aa; 6304 } 6305 $attrs = $eAttrs; 6306 } 6307 6308 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 6309 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; 6310 6311 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 6312 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); 6313 } 6314 6315 /** 6316 * adds an XML Schema simple type to the WSDL types 6317 * 6318 * @param string $name 6319 * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 6320 * @param string $typeClass (should always be simpleType) 6321 * @param string $phpType (should always be scalar) 6322 * @param array $enumeration array of values 6323 * @see nusoap_xmlschema 6324 * @access public 6325 */ 6326 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 6327 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 6328 6329 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 6330 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 6331 } 6332 6333 /** 6334 * adds an element to the WSDL types 6335 * 6336 * @param array $attrs attributes that must include name and type 6337 * @see nusoap_xmlschema 6338 * @access public 6339 */ 6340 function addElement($attrs) { 6341 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 6342 $this->schemas[$typens][0]->addElement($attrs); 6343 } 6344 6345 /** 6346 * register an operation with the server 6347 * 6348 * @param string $name operation (method) name 6349 * @param array $in assoc array of input values: key = param name, value = param type 6350 * @param array $out assoc array of output values: key = param name, value = param type 6351 * @param string $namespace optional The namespace for the operation 6352 * @param string $soapaction optional The soapaction for the operation 6353 * @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 6354 * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) 6355 * @param string $documentation optional The description to include in the WSDL 6356 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 6357 * @access public 6358 */ 6359 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ 6360 if ($use == 'encoded' && $encodingStyle == '') { 6361 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 6362 } 6363 6364 if ($style == 'document') { 6365 $elements = array(); 6366 foreach ($in as $n => $t) { 6367 $elements[$n] = array('name' => $n, 'type' => $t); 6368 } 6369 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 6370 $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 6371 $in = array('parameters' => 'tns:' . $name . '^'); 6372 6373 $elements = array(); 6374 foreach ($out as $n => $t) { 6375 $elements[$n] = array('name' => $n, 'type' => $t); 6376 } 6377 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 6378 $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); 6379 $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); 6380 } 6381 6382 // get binding 6383 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 6384 array( 6385 'name' => $name, 6386 'binding' => $this->serviceName . 'Binding', 6387 'endpoint' => $this->endpoint, 6388 'soapAction' => $soapaction, 6389 'style' => $style, 6390 'input' => array( 6391 'use' => $use, 6392 'namespace' => $namespace, 6393 'encodingStyle' => $encodingStyle, 6394 'message' => $name . 'Request', 6395 'parts' => $in), 6396 'output' => array( 6397 'use' => $use, 6398 'namespace' => $namespace, 6399 'encodingStyle' => $encodingStyle, 6400 'message' => $name . 'Response', 6401 'parts' => $out), 6402 'namespace' => $namespace, 6403 'transport' => 'http://schemas.xmlsoap.org/soap/http', 6404 'documentation' => $documentation); 6405 // add portTypes 6406 // add messages 6407 if($in) 6408 { 6409 foreach($in as $pName => $pType) 6410 { 6411 if(strpos($pType,':')) { 6412 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 6413 } 6414 $this->messages[$name.'Request'][$pName] = $pType; 6415 } 6416 } else { 6417 $this->messages[$name.'Request']= '0'; 6418 } 6419 if($out) 6420 { 6421 foreach($out as $pName => $pType) 6422 { 6423 if(strpos($pType,':')) { 6424 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 6425 } 6426 $this->messages[$name.'Response'][$pName] = $pType; 6427 } 6428 } else { 6429 $this->messages[$name.'Response']= '0'; 6430 } 6431 return true; 6432 } 6433} 6434?><?php 6435 6436 6437 6438/** 6439* 6440* nusoap_parser class parses SOAP XML messages into native PHP values 6441* 6442* @author Dietrich Ayala <dietrich@ganx4.com> 6443* @author Scott Nichol <snichol@users.sourceforge.net> 6444* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 6445* @access public 6446*/ 6447class nusoap_parser extends nusoap_base { 6448 6449 var $xml = ''; 6450 var $xml_encoding = ''; 6451 var $method = ''; 6452 var $root_struct = ''; 6453 var $root_struct_name = ''; 6454 var $root_struct_namespace = ''; 6455 var $root_header = ''; 6456 var $document = ''; // incoming SOAP body (text) 6457 // determines where in the message we are (envelope,header,body,method) 6458 var $status = ''; 6459 var $position = 0; 6460 var $depth = 0; 6461 var $default_namespace = ''; 6462 var $namespaces = array(); 6463 var $message = array(); 6464 var $parent = ''; 6465 var $fault = false; 6466 var $fault_code = ''; 6467 var $fault_str = ''; 6468 var $fault_detail = ''; 6469 var $depth_array = array(); 6470 var $debug_flag = true; 6471 var $soapresponse = NULL; // parsed SOAP Body 6472 var $soapheader = NULL; // parsed SOAP Header 6473 var $responseHeaders = ''; // incoming SOAP headers (text) 6474 var $body_position = 0; 6475 // for multiref parsing: 6476 // array of id => pos 6477 var $ids = array(); 6478 // array of id => hrefs => pos 6479 var $multirefs = array(); 6480 // toggle for auto-decoding element content 6481 var $decode_utf8 = true; 6482 6483 /** 6484 * constructor that actually does the parsing 6485 * 6486 * @param string $xml SOAP message 6487 * @param string $encoding character encoding scheme of message 6488 * @param string $method method for which XML is parsed (unused?) 6489 * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 6490 * @access public 6491 */ 6492 function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ 6493 parent::nusoap_base(); 6494 $this->xml = $xml; 6495 $this->xml_encoding = $encoding; 6496 $this->method = $method; 6497 $this->decode_utf8 = $decode_utf8; 6498 6499 // Check whether content has been read. 6500 if(!empty($xml)){ 6501 // Check XML encoding 6502 $pos_xml = strpos($xml, '<?xml'); 6503 if ($pos_xml !== FALSE) { 6504 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); 6505 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { 6506 $xml_encoding = $res[1]; 6507 if (strtoupper($xml_encoding) != $encoding) { 6508 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; 6509 $this->debug($err); 6510 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { 6511 $this->setError($err); 6512 return; 6513 } 6514 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed 6515 } else { 6516 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); 6517 } 6518 } else { 6519 $this->debug('No encoding specified in XML declaration'); 6520 } 6521 } else { 6522 $this->debug('No XML declaration'); 6523 } 6524 $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); 6525 // Create an XML parser - why not xml_parser_create_ns? 6526 $this->parser = xml_parser_create($this->xml_encoding); 6527 // Set the options for parsing the XML data. 6528 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 6529 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 6530 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); 6531 // Set the object for the parser. 6532 xml_set_object($this->parser, $this); 6533 // Set the element handlers for the parser. 6534 xml_set_element_handler($this->parser, 'start_element','end_element'); 6535 xml_set_character_data_handler($this->parser,'character_data'); 6536 6537 // Parse the XML file. 6538 if(!xml_parse($this->parser,$xml,true)){ 6539 // Display an error message. 6540 $err = sprintf('XML error parsing SOAP payload on line %d: %s', 6541 xml_get_current_line_number($this->parser), 6542 xml_error_string(xml_get_error_code($this->parser))); 6543 $this->debug($err); 6544 $this->debug("XML payload:\n" . $xml); 6545 $this->setError($err); 6546 } else { 6547 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); 6548 // get final value 6549 $this->soapresponse = $this->message[$this->root_struct]['result']; 6550 // get header value 6551 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ 6552 $this->soapheader = $this->message[$this->root_header]['result']; 6553 } 6554 // resolve hrefs/ids 6555 if(sizeof($this->multirefs) > 0){ 6556 foreach($this->multirefs as $id => $hrefs){ 6557 $this->debug('resolving multirefs for id: '.$id); 6558 $idVal = $this->buildVal($this->ids[$id]); 6559 if (is_array($idVal) && isset($idVal['!id'])) { 6560 unset($idVal['!id']); 6561 } 6562 foreach($hrefs as $refPos => $ref){ 6563 $this->debug('resolving href at pos '.$refPos); 6564 $this->multirefs[$id][$refPos] = $idVal; 6565 } 6566 } 6567 } 6568 } 6569 xml_parser_free($this->parser); 6570 } else { 6571 $this->debug('xml was empty, didn\'t parse!'); 6572 $this->setError('xml was empty, didn\'t parse!'); 6573 } 6574 } 6575 6576 /** 6577 * start-element handler 6578 * 6579 * @param resource $parser XML parser object 6580 * @param string $name element name 6581 * @param array $attrs associative array of attributes 6582 * @access private 6583 */ 6584 function start_element($parser, $name, $attrs) { 6585 // position in a total number of elements, starting from 0 6586 // update class level pos 6587 $pos = $this->position++; 6588 // and set mine 6589 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); 6590 // depth = how many levels removed from root? 6591 // set mine as current global depth and increment global depth value 6592 $this->message[$pos]['depth'] = $this->depth++; 6593 6594 // else add self as child to whoever the current parent is 6595 if($pos != 0){ 6596 $this->message[$this->parent]['children'] .= '|'.$pos; 6597 } 6598 // set my parent 6599 $this->message[$pos]['parent'] = $this->parent; 6600 // set self as current parent 6601 $this->parent = $pos; 6602 // set self as current value for this depth 6603 $this->depth_array[$this->depth] = $pos; 6604 // get element prefix 6605 if(strpos($name,':')){ 6606 // get ns prefix 6607 $prefix = substr($name,0,strpos($name,':')); 6608 // get unqualified name 6609 $name = substr(strstr($name,':'),1); 6610 } 6611 // set status 6612 if($name == 'Envelope'){ 6613 $this->status = 'envelope'; 6614 } elseif($name == 'Header' && $this->status = 'envelope'){ 6615 $this->root_header = $pos; 6616 $this->status = 'header'; 6617 } elseif($name == 'Body' && $this->status = 'envelope'){ 6618 $this->status = 'body'; 6619 $this->body_position = $pos; 6620 // set method 6621 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){ 6622 $this->status = 'method'; 6623 $this->root_struct_name = $name; 6624 $this->root_struct = $pos; 6625 $this->message[$pos]['type'] = 'struct'; 6626 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); 6627 } 6628 // set my status 6629 $this->message[$pos]['status'] = $this->status; 6630 // set name 6631 $this->message[$pos]['name'] = htmlspecialchars($name); 6632 // set attrs 6633 $this->message[$pos]['attrs'] = $attrs; 6634 6635 // loop through atts, logging ns and type declarations 6636 $attstr = ''; 6637 foreach($attrs as $key => $value){ 6638 $key_prefix = $this->getPrefix($key); 6639 $key_localpart = $this->getLocalPart($key); 6640 // if ns declarations, add to class level array of valid namespaces 6641 if($key_prefix == 'xmlns'){ 6642 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ 6643 $this->XMLSchemaVersion = $value; 6644 $this->namespaces['xsd'] = $this->XMLSchemaVersion; 6645 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; 6646 } 6647 $this->namespaces[$key_localpart] = $value; 6648 // set method namespace 6649 if($name == $this->root_struct_name){ 6650 $this->methodNamespace = $value; 6651 } 6652 // if it's a type declaration, set type 6653 } elseif($key_localpart == 'type'){ 6654 if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { 6655 // do nothing: already processed arrayType 6656 } else { 6657 $value_prefix = $this->getPrefix($value); 6658 $value_localpart = $this->getLocalPart($value); 6659 $this->message[$pos]['type'] = $value_localpart; 6660 $this->message[$pos]['typePrefix'] = $value_prefix; 6661 if(isset($this->namespaces[$value_prefix])){ 6662 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; 6663 } else if(isset($attrs['xmlns:'.$value_prefix])) { 6664 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; 6665 } 6666 // should do something here with the namespace of specified type? 6667 } 6668 } elseif($key_localpart == 'arrayType'){ 6669 $this->message[$pos]['type'] = 'array'; 6670 /* do arrayType ereg here 6671 [1] arrayTypeValue ::= atype asize 6672 [2] atype ::= QName rank* 6673 [3] rank ::= '[' (',')* ']' 6674 [4] asize ::= '[' length~ ']' 6675 [5] length ::= nextDimension* Digit+ 6676 [6] nextDimension ::= Digit+ ',' 6677 */ 6678 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; 6679 if(ereg($expr,$value,$regs)){ 6680 $this->message[$pos]['typePrefix'] = $regs[1]; 6681 $this->message[$pos]['arrayTypePrefix'] = $regs[1]; 6682 if (isset($this->namespaces[$regs[1]])) { 6683 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; 6684 } else if (isset($attrs['xmlns:'.$regs[1]])) { 6685 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; 6686 } 6687 $this->message[$pos]['arrayType'] = $regs[2]; 6688 $this->message[$pos]['arraySize'] = $regs[3]; 6689 $this->message[$pos]['arrayCols'] = $regs[4]; 6690 } 6691 // specifies nil value (or not) 6692 } elseif ($key_localpart == 'nil'){ 6693 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); 6694 // some other attribute 6695 } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { 6696 $this->message[$pos]['xattrs']['!' . $key] = $value; 6697 } 6698 6699 if ($key == 'xmlns') { 6700 $this->default_namespace = $value; 6701 } 6702 // log id 6703 if($key == 'id'){ 6704 $this->ids[$value] = $pos; 6705 } 6706 // root 6707 if($key_localpart == 'root' && $value == 1){ 6708 $this->status = 'method'; 6709 $this->root_struct_name = $name; 6710 $this->root_struct = $pos; 6711 $this->debug("found root struct $this->root_struct_name, pos $pos"); 6712 } 6713 // for doclit 6714 $attstr .= " $key=\"$value\""; 6715 } 6716 // get namespace - must be done after namespace atts are processed 6717 if(isset($prefix)){ 6718 $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; 6719 $this->default_namespace = $this->namespaces[$prefix]; 6720 } else { 6721 $this->message[$pos]['namespace'] = $this->default_namespace; 6722 } 6723 if($this->status == 'header'){ 6724 if ($this->root_header != $pos) { 6725 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 6726 } 6727 } elseif($this->root_struct_name != ''){ 6728 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 6729 } 6730 } 6731 6732 /** 6733 * end-element handler 6734 * 6735 * @param resource $parser XML parser object 6736 * @param string $name element name 6737 * @access private 6738 */ 6739 function end_element($parser, $name) { 6740 // position of current element is equal to the last value left in depth_array for my depth 6741 $pos = $this->depth_array[$this->depth--]; 6742 6743 // get element prefix 6744 if(strpos($name,':')){ 6745 // get ns prefix 6746 $prefix = substr($name,0,strpos($name,':')); 6747 // get unqualified name 6748 $name = substr(strstr($name,':'),1); 6749 } 6750 6751 // build to native type 6752 if(isset($this->body_position) && $pos > $this->body_position){ 6753 // deal w/ multirefs 6754 if(isset($this->message[$pos]['attrs']['href'])){ 6755 // get id 6756 $id = substr($this->message[$pos]['attrs']['href'],1); 6757 // add placeholder to href array 6758 $this->multirefs[$id][$pos] = 'placeholder'; 6759 // add set a reference to it as the result value 6760 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; 6761 // build complexType values 6762 } elseif($this->message[$pos]['children'] != ''){ 6763 // if result has already been generated (struct/array) 6764 if(!isset($this->message[$pos]['result'])){ 6765 $this->message[$pos]['result'] = $this->buildVal($pos); 6766 } 6767 // build complexType values of attributes and possibly simpleContent 6768 } elseif (isset($this->message[$pos]['xattrs'])) { 6769 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 6770 $this->message[$pos]['xattrs']['!'] = null; 6771 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 6772 if (isset($this->message[$pos]['type'])) { 6773 $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'] : ''); 6774 } else { 6775 $parent = $this->message[$pos]['parent']; 6776 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 6777 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 6778 } else { 6779 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; 6780 } 6781 } 6782 } 6783 $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; 6784 // set value of simpleType (or nil complexType) 6785 } else { 6786 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); 6787 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 6788 $this->message[$pos]['xattrs']['!'] = null; 6789 } elseif (isset($this->message[$pos]['type'])) { 6790 $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'] : ''); 6791 } else { 6792 $parent = $this->message[$pos]['parent']; 6793 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 6794 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 6795 } else { 6796 $this->message[$pos]['result'] = $this->message[$pos]['cdata']; 6797 } 6798 } 6799 6800 /* add value to parent's result, if parent is struct/array 6801 $parent = $this->message[$pos]['parent']; 6802 if($this->message[$parent]['type'] != 'map'){ 6803 if(strtolower($this->message[$parent]['type']) == 'array'){ 6804 $this->message[$parent]['result'][] = $this->message[$pos]['result']; 6805 } else { 6806 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; 6807 } 6808 } 6809 */ 6810 } 6811 } 6812 6813 // for doclit 6814 if($this->status == 'header'){ 6815 if ($this->root_header != $pos) { 6816 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 6817 } 6818 } elseif($pos >= $this->root_struct){ 6819 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 6820 } 6821 // switch status 6822 if($pos == $this->root_struct){ 6823 $this->status = 'body'; 6824 $this->root_struct_namespace = $this->message[$pos]['namespace']; 6825 } elseif($name == 'Body'){ 6826 $this->status = 'envelope'; 6827 } elseif($name == 'Header'){ 6828 $this->status = 'envelope'; 6829 } elseif($name == 'Envelope'){ 6830 // 6831 } 6832 // set parent back to my parent 6833 $this->parent = $this->message[$pos]['parent']; 6834 } 6835 6836 /** 6837 * element content handler 6838 * 6839 * @param resource $parser XML parser object 6840 * @param string $data element content 6841 * @access private 6842 */ 6843 function character_data($parser, $data){ 6844 $pos = $this->depth_array[$this->depth]; 6845 if ($this->xml_encoding=='UTF-8'){ 6846 // TODO: add an option to disable this for folks who want 6847 // raw UTF-8 that, e.g., might not map to iso-8859-1 6848 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); 6849 if($this->decode_utf8){ 6850 $data = utf8_decode($data); 6851 } 6852 } 6853 $this->message[$pos]['cdata'] .= $data; 6854 // for doclit 6855 if($this->status == 'header'){ 6856 $this->responseHeaders .= $data; 6857 } else { 6858 $this->document .= $data; 6859 } 6860 } 6861 6862 /** 6863 * get the parsed message (SOAP Body) 6864 * 6865 * @return mixed 6866 * @access public 6867 * @deprecated use get_soapbody instead 6868 */ 6869 function get_response(){ 6870 return $this->soapresponse; 6871 } 6872 6873 /** 6874 * get the parsed SOAP Body (NULL if there was none) 6875 * 6876 * @return mixed 6877 * @access public 6878 */ 6879 function get_soapbody(){ 6880 return $this->soapresponse; 6881 } 6882 6883 /** 6884 * get the parsed SOAP Header (NULL if there was none) 6885 * 6886 * @return mixed 6887 * @access public 6888 */ 6889 function get_soapheader(){ 6890 return $this->soapheader; 6891 } 6892 6893 /** 6894 * get the unparsed SOAP Header 6895 * 6896 * @return string XML or empty if no Header 6897 * @access public 6898 */ 6899 function getHeaders(){ 6900 return $this->responseHeaders; 6901 } 6902 6903 /** 6904 * decodes simple types into PHP variables 6905 * 6906 * @param string $value value to decode 6907 * @param string $type XML type to decode 6908 * @param string $typens XML type namespace to decode 6909 * @return mixed PHP value 6910 * @access private 6911 */ 6912 function decodeSimple($value, $type, $typens) { 6913 // TODO: use the namespace! 6914 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { 6915 return (string) $value; 6916 } 6917 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { 6918 return (int) $value; 6919 } 6920 if ($type == 'float' || $type == 'double' || $type == 'decimal') { 6921 return (double) $value; 6922 } 6923 if ($type == 'boolean') { 6924 if (strtolower($value) == 'false' || strtolower($value) == 'f') { 6925 return false; 6926 } 6927 return (boolean) $value; 6928 } 6929 if ($type == 'base64' || $type == 'base64Binary') { 6930 $this->debug('Decode base64 value'); 6931 return base64_decode($value); 6932 } 6933 // obscure numeric types 6934 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' 6935 || $type == 'nonNegativeInteger' || $type == 'positiveInteger' 6936 || $type == 'unsignedInt' 6937 || $type == 'unsignedShort' || $type == 'unsignedByte') { 6938 return (int) $value; 6939 } 6940 // bogus: parser treats array with no elements as a simple type 6941 if ($type == 'array') { 6942 return array(); 6943 } 6944 // everything else 6945 return (string) $value; 6946 } 6947 6948 /** 6949 * builds response structures for compound values (arrays/structs) 6950 * and scalars 6951 * 6952 * @param integer $pos position in node tree 6953 * @return mixed PHP value 6954 * @access private 6955 */ 6956 function buildVal($pos){ 6957 if(!isset($this->message[$pos]['type'])){ 6958 $this->message[$pos]['type'] = ''; 6959 } 6960 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); 6961 // if there are children... 6962 if($this->message[$pos]['children'] != ''){ 6963 $this->debug('in buildVal, there are children'); 6964 $children = explode('|',$this->message[$pos]['children']); 6965 array_shift($children); // knock off empty 6966 // md array 6967 if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ 6968 $r=0; // rowcount 6969 $c=0; // colcount 6970 foreach($children as $child_pos){ 6971 $this->debug("in buildVal, got an MD array element: $r, $c"); 6972 $params[$r][] = $this->message[$child_pos]['result']; 6973 $c++; 6974 if($c == $this->message[$pos]['arrayCols']){ 6975 $c = 0; 6976 $r++; 6977 } 6978 } 6979 // array 6980 } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ 6981 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); 6982 foreach($children as $child_pos){ 6983 $params[] = &$this->message[$child_pos]['result']; 6984 } 6985 // apache Map type: java hashtable 6986 } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ 6987 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); 6988 foreach($children as $child_pos){ 6989 $kv = explode("|",$this->message[$child_pos]['children']); 6990 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; 6991 } 6992 // generic compound type 6993 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { 6994 } else { 6995 // Apache Vector type: treat as an array 6996 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); 6997 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { 6998 $notstruct = 1; 6999 } else { 7000 $notstruct = 0; 7001 } 7002 // 7003 foreach($children as $child_pos){ 7004 if($notstruct){ 7005 $params[] = &$this->message[$child_pos]['result']; 7006 } else { 7007 if (isset($params[$this->message[$child_pos]['name']])) { 7008 // de-serialize repeated element name into an array 7009 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { 7010 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); 7011 } 7012 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; 7013 } else { 7014 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; 7015 } 7016 } 7017 } 7018 } 7019 if (isset($this->message[$pos]['xattrs'])) { 7020 $this->debug('in buildVal, handling attributes'); 7021 foreach ($this->message[$pos]['xattrs'] as $n => $v) { 7022 $params[$n] = $v; 7023 } 7024 } 7025 // handle simpleContent 7026 if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 7027 $this->debug('in buildVal, handling simpleContent'); 7028 if (isset($this->message[$pos]['type'])) { 7029 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 7030 } else { 7031 $parent = $this->message[$pos]['parent']; 7032 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 7033 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 7034 } else { 7035 $params['!'] = $this->message[$pos]['cdata']; 7036 } 7037 } 7038 } 7039 $ret = is_array($params) ? $params : array(); 7040 $this->debug('in buildVal, return:'); 7041 $this->appendDebug($this->varDump($ret)); 7042 return $ret; 7043 } else { 7044 $this->debug('in buildVal, no children, building scalar'); 7045 $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; 7046 if (isset($this->message[$pos]['type'])) { 7047 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 7048 $this->debug("in buildVal, return: $ret"); 7049 return $ret; 7050 } 7051 $parent = $this->message[$pos]['parent']; 7052 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 7053 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 7054 $this->debug("in buildVal, return: $ret"); 7055 return $ret; 7056 } 7057 $ret = $this->message[$pos]['cdata']; 7058 $this->debug("in buildVal, return: $ret"); 7059 return $ret; 7060 } 7061 } 7062} 7063 7064/** 7065 * Backward compatibility 7066 */ 7067class soap_parser extends nusoap_parser { 7068} 7069 7070?><?php 7071 7072 7073 7074/** 7075* 7076* [nu]soapclient higher level class for easy usage. 7077* 7078* usage: 7079* 7080* // instantiate client with server info 7081* $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); 7082* 7083* // call method, get results 7084* echo $soapclient->call( string methodname [ ,array parameters] ); 7085* 7086* // bye bye client 7087* unset($soapclient); 7088* 7089* @author Dietrich Ayala <dietrich@ganx4.com> 7090* @author Scott Nichol <snichol@users.sourceforge.net> 7091* @version $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 7092* @access public 7093*/ 7094class nusoap_client extends nusoap_base { 7095 7096 var $username = ''; // Username for HTTP authentication 7097 var $password = ''; // Password for HTTP authentication 7098 var $authtype = ''; // Type of HTTP authentication 7099 var $certRequest = array(); // Certificate for HTTP SSL authentication 7100 var $requestHeaders = false; // SOAP headers in request (text) 7101 var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) 7102 var $responseHeader = NULL; // SOAP Header from response (parsed) 7103 var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) 7104 var $endpoint; 7105 var $forceEndpoint = ''; // overrides WSDL endpoint 7106 var $proxyhost = ''; 7107 var $proxyport = ''; 7108 var $proxyusername = ''; 7109 var $proxypassword = ''; 7110 var $xml_encoding = ''; // character set encoding of incoming (response) messages 7111 var $http_encoding = false; 7112 var $timeout = 0; // HTTP connection timeout 7113 var $response_timeout = 30; // HTTP response timeout 7114 var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error 7115 var $persistentConnection = false; 7116 var $defaultRpcParams = false; // This is no longer used 7117 var $request = ''; // HTTP request 7118 var $response = ''; // HTTP response 7119 var $responseData = ''; // SOAP payload of response 7120 var $cookies = array(); // Cookies from response or for request 7121 var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() 7122 var $operations = array(); // WSDL operations, empty for WSDL initialization error 7123 var $curl_options = array(); // User-specified cURL options 7124 var $bindingType = ''; // WSDL operation binding type 7125 var $use_curl = false; // whether to always try to use cURL 7126 7127 /* 7128 * fault related variables 7129 */ 7130 /** 7131 * @var fault 7132 * @access public 7133 */ 7134 var $fault; 7135 /** 7136 * @var faultcode 7137 * @access public 7138 */ 7139 var $faultcode; 7140 /** 7141 * @var faultstring 7142 * @access public 7143 */ 7144 var $faultstring; 7145 /** 7146 * @var faultdetail 7147 * @access public 7148 */ 7149 var $faultdetail; 7150 7151 /** 7152 * constructor 7153 * 7154 * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) 7155 * @param bool $wsdl optional, set to true if using WSDL 7156 * @param int $portName optional portName in WSDL document 7157 * @param string $proxyhost 7158 * @param string $proxyport 7159 * @param string $proxyusername 7160 * @param string $proxypassword 7161 * @param integer $timeout set the connection timeout 7162 * @param integer $response_timeout set the response timeout 7163 * @access public 7164 */ 7165 function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ 7166 parent::nusoap_base(); 7167 $this->endpoint = $endpoint; 7168 $this->proxyhost = $proxyhost; 7169 $this->proxyport = $proxyport; 7170 $this->proxyusername = $proxyusername; 7171 $this->proxypassword = $proxypassword; 7172 $this->timeout = $timeout; 7173 $this->response_timeout = $response_timeout; 7174 7175 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 7176 $this->appendDebug('endpoint=' . $this->varDump($endpoint)); 7177 7178 // make values 7179 if($wsdl){ 7180 if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { 7181 $this->wsdl = $endpoint; 7182 $this->endpoint = $this->wsdl->wsdl; 7183 $this->wsdlFile = $this->endpoint; 7184 $this->debug('existing wsdl instance created from ' . $this->endpoint); 7185 $this->checkWSDL(); 7186 } else { 7187 $this->wsdlFile = $this->endpoint; 7188 $this->wsdl = null; 7189 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); 7190 } 7191 $this->endpointType = 'wsdl'; 7192 } else { 7193 $this->debug("instantiate SOAP with endpoint at $endpoint"); 7194 $this->endpointType = 'soap'; 7195 } 7196 } 7197 7198 /** 7199 * calls method, returns PHP native type 7200 * 7201 * @param string $operation SOAP server URL or path 7202 * @param mixed $params An array, associative or simple, of the parameters 7203 * for the method call, or a string that is the XML 7204 * for the call. For rpc style, this call will 7205 * wrap the XML in a tag named after the method, as 7206 * well as the SOAP Envelope and Body. For document 7207 * style, this will only wrap with the Envelope and Body. 7208 * IMPORTANT: when using an array with document style, 7209 * in which case there 7210 * is really one parameter, the root of the fragment 7211 * used in the call, which encloses what programmers 7212 * normally think of parameters. A parameter array 7213 * *must* include the wrapper. 7214 * @param string $namespace optional method namespace (WSDL can override) 7215 * @param string $soapAction optional SOAPAction value (WSDL can override) 7216 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array 7217 * @param boolean $rpcParams optional (no longer used) 7218 * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) 7219 * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) 7220 * @return mixed response from SOAP call 7221 * @access public 7222 */ 7223 function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ 7224 $this->operation = $operation; 7225 $this->fault = false; 7226 $this->setError(''); 7227 $this->request = ''; 7228 $this->response = ''; 7229 $this->responseData = ''; 7230 $this->faultstring = ''; 7231 $this->faultcode = ''; 7232 $this->opData = array(); 7233 7234 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); 7235 $this->appendDebug('params=' . $this->varDump($params)); 7236 $this->appendDebug('headers=' . $this->varDump($headers)); 7237 if ($headers) { 7238 $this->requestHeaders = $headers; 7239 } 7240 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 7241 $this->loadWSDL(); 7242 if ($this->getError()) 7243 return false; 7244 } 7245 // serialize parameters 7246 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ 7247 // use WSDL for operation 7248 $this->opData = $opData; 7249 $this->debug("found operation"); 7250 $this->appendDebug('opData=' . $this->varDump($opData)); 7251 if (isset($opData['soapAction'])) { 7252 $soapAction = $opData['soapAction']; 7253 } 7254 if (! $this->forceEndpoint) { 7255 $this->endpoint = $opData['endpoint']; 7256 } else { 7257 $this->endpoint = $this->forceEndpoint; 7258 } 7259 $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; 7260 $style = $opData['style']; 7261 $use = $opData['input']['use']; 7262 // add ns to ns array 7263 if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ 7264 $nsPrefix = 'ns' . rand(1000, 9999); 7265 $this->wsdl->namespaces[$nsPrefix] = $namespace; 7266 } 7267 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); 7268 // serialize payload 7269 if (is_string($params)) { 7270 $this->debug("serializing param string for WSDL operation $operation"); 7271 $payload = $params; 7272 } elseif (is_array($params)) { 7273 $this->debug("serializing param array for WSDL operation $operation"); 7274 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); 7275 } else { 7276 $this->debug('params must be array or string'); 7277 $this->setError('params must be array or string'); 7278 return false; 7279 } 7280 $usedNamespaces = $this->wsdl->usedNamespaces; 7281 if (isset($opData['input']['encodingStyle'])) { 7282 $encodingStyle = $opData['input']['encodingStyle']; 7283 } else { 7284 $encodingStyle = ''; 7285 } 7286 $this->appendDebug($this->wsdl->getDebug()); 7287 $this->wsdl->clearDebug(); 7288 if ($errstr = $this->wsdl->getError()) { 7289 $this->debug('got wsdl error: '.$errstr); 7290 $this->setError('wsdl error: '.$errstr); 7291 return false; 7292 } 7293 } elseif($this->endpointType == 'wsdl') { 7294 // operation not in WSDL 7295 $this->appendDebug($this->wsdl->getDebug()); 7296 $this->wsdl->clearDebug(); 7297 $this->setError( 'operation '.$operation.' not present.'); 7298 $this->debug("operation '$operation' not present."); 7299 return false; 7300 } else { 7301 // no WSDL 7302 //$this->namespaces['ns1'] = $namespace; 7303 $nsPrefix = 'ns' . rand(1000, 9999); 7304 // serialize 7305 $payload = ''; 7306 if (is_string($params)) { 7307 $this->debug("serializing param string for operation $operation"); 7308 $payload = $params; 7309 } elseif (is_array($params)) { 7310 $this->debug("serializing param array for operation $operation"); 7311 foreach($params as $k => $v){ 7312 $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); 7313 } 7314 } else { 7315 $this->debug('params must be array or string'); 7316 $this->setError('params must be array or string'); 7317 return false; 7318 } 7319 $usedNamespaces = array(); 7320 if ($use == 'encoded') { 7321 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 7322 } else { 7323 $encodingStyle = ''; 7324 } 7325 } 7326 // wrap RPC calls with method element 7327 if ($style == 'rpc') { 7328 if ($use == 'literal') { 7329 $this->debug("wrapping RPC request with literal method element"); 7330 if ($namespace) { 7331 // 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 7332 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 7333 $payload . 7334 "</$nsPrefix:$operation>"; 7335 } else { 7336 $payload = "<$operation>" . $payload . "</$operation>"; 7337 } 7338 } else { 7339 $this->debug("wrapping RPC request with encoded method element"); 7340 if ($namespace) { 7341 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 7342 $payload . 7343 "</$nsPrefix:$operation>"; 7344 } else { 7345 $payload = "<$operation>" . 7346 $payload . 7347 "</$operation>"; 7348 } 7349 } 7350 } 7351 // serialize envelope 7352 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); 7353 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); 7354 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); 7355 // send 7356 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); 7357 if($errstr = $this->getError()){ 7358 $this->debug('Error: '.$errstr); 7359 return false; 7360 } else { 7361 $this->return = $return; 7362 $this->debug('sent message successfully and got a(n) '.gettype($return)); 7363 $this->appendDebug('return=' . $this->varDump($return)); 7364 7365 // fault? 7366 if(is_array($return) && isset($return['faultcode'])){ 7367 $this->debug('got fault'); 7368 $this->setError($return['faultcode'].': '.$return['faultstring']); 7369 $this->fault = true; 7370 foreach($return as $k => $v){ 7371 $this->$k = $v; 7372 $this->debug("$k = $v<br>"); 7373 } 7374 return $return; 7375 } elseif ($style == 'document') { 7376 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), 7377 // we are only going to return the first part here...sorry about that 7378 return $return; 7379 } else { 7380 // array of return values 7381 if(is_array($return)){ 7382 // multiple 'out' parameters, which we return wrapped up 7383 // in the array 7384 if(sizeof($return) > 1){ 7385 return $return; 7386 } 7387 // single 'out' parameter (normally the return value) 7388 $return = array_shift($return); 7389 $this->debug('return shifted value: '); 7390 $this->appendDebug($this->varDump($return)); 7391 return $return; 7392 // nothing returned (ie, echoVoid) 7393 } else { 7394 return ""; 7395 } 7396 } 7397 } 7398 } 7399 7400 /** 7401 * check WSDL passed as an instance or pulled from an endpoint 7402 * 7403 * @access private 7404 */ 7405 function checkWSDL() { 7406 $this->appendDebug($this->wsdl->getDebug()); 7407 $this->wsdl->clearDebug(); 7408 $this->debug('checkWSDL'); 7409 // catch errors 7410 if ($errstr = $this->wsdl->getError()) { 7411 $this->debug('got wsdl error: '.$errstr); 7412 $this->setError('wsdl error: '.$errstr); 7413 } elseif ($this->operations = $this->wsdl->getOperations('soap')) { 7414 $this->bindingType = 'soap'; 7415 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 7416 } elseif ($this->operations = $this->wsdl->getOperations('soap12')) { 7417 $this->bindingType = 'soap12'; 7418 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 7419 $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); 7420 } else { 7421 $this->debug('getOperations returned false'); 7422 $this->setError('no operations defined in the WSDL document!'); 7423 } 7424 } 7425 7426 /** 7427 * instantiate wsdl object and parse wsdl file 7428 * 7429 * @access public 7430 */ 7431 function loadWSDL() { 7432 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); 7433 $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); 7434 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); 7435 $this->wsdl->fetchWSDL($this->wsdlFile); 7436 $this->checkWSDL(); 7437 } 7438 7439 /** 7440 * get available data pertaining to an operation 7441 * 7442 * @param string $operation operation name 7443 * @return array array of data pertaining to the operation 7444 * @access public 7445 */ 7446 function getOperationData($operation){ 7447 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 7448 $this->loadWSDL(); 7449 if ($this->getError()) 7450 return false; 7451 } 7452 if(isset($this->operations[$operation])){ 7453 return $this->operations[$operation]; 7454 } 7455 $this->debug("No data for operation: $operation"); 7456 } 7457 7458 /** 7459 * send the SOAP message 7460 * 7461 * Note: if the operation has multiple return values 7462 * the return value of this method will be an array 7463 * of those values. 7464 * 7465 * @param string $msg a SOAPx4 soapmsg object 7466 * @param string $soapaction SOAPAction value 7467 * @param integer $timeout set connection timeout in seconds 7468 * @param integer $response_timeout set response timeout in seconds 7469 * @return mixed native PHP types. 7470 * @access private 7471 */ 7472 function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { 7473 $this->checkCookies(); 7474 // detect transport 7475 switch(true){ 7476 // http(s) 7477 case ereg('^http',$this->endpoint): 7478 $this->debug('transporting via HTTP'); 7479 if($this->persistentConnection == true && is_object($this->persistentConnection)){ 7480 $http =& $this->persistentConnection; 7481 } else { 7482 $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); 7483 if ($this->persistentConnection) { 7484 $http->usePersistentConnection(); 7485 } 7486 } 7487 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); 7488 $http->setSOAPAction($soapaction); 7489 if($this->proxyhost && $this->proxyport){ 7490 $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 7491 } 7492 if($this->authtype != '') { 7493 $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 7494 } 7495 if($this->http_encoding != ''){ 7496 $http->setEncoding($this->http_encoding); 7497 } 7498 $this->debug('sending message, length='.strlen($msg)); 7499 if(ereg('^http:',$this->endpoint)){ 7500 //if(strpos($this->endpoint,'http:')){ 7501 $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); 7502 } elseif(ereg('^https',$this->endpoint)){ 7503 //} elseif(strpos($this->endpoint,'https:')){ 7504 //if(phpversion() == '4.3.0-dev'){ 7505 //$response = $http->send($msg,$timeout,$response_timeout); 7506 //$this->request = $http->outgoing_payload; 7507 //$this->response = $http->incoming_payload; 7508 //} else 7509 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); 7510 } else { 7511 $this->setError('no http/s in endpoint url'); 7512 } 7513 $this->request = $http->outgoing_payload; 7514 $this->response = $http->incoming_payload; 7515 $this->appendDebug($http->getDebug()); 7516 $this->UpdateCookies($http->incoming_cookies); 7517 7518 // save transport object if using persistent connections 7519 if ($this->persistentConnection) { 7520 $http->clearDebug(); 7521 if (!is_object($this->persistentConnection)) { 7522 $this->persistentConnection = $http; 7523 } 7524 } 7525 7526 if($err = $http->getError()){ 7527 $this->setError('HTTP Error: '.$err); 7528 return false; 7529 } elseif($this->getError()){ 7530 return false; 7531 } else { 7532 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); 7533 return $this->parseResponse($http->incoming_headers, $this->responseData); 7534 } 7535 break; 7536 default: 7537 $this->setError('no transport found, or selected transport is not yet supported!'); 7538 return false; 7539 break; 7540 } 7541 } 7542 7543 /** 7544 * processes SOAP message returned from server 7545 * 7546 * @param array $headers The HTTP headers 7547 * @param string $data unprocessed response data from server 7548 * @return mixed value of the message, decoded into a PHP type 7549 * @access private 7550 */ 7551 function parseResponse($headers, $data) { 7552 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); 7553 $this->appendDebug($this->varDump($headers)); 7554 if (!strstr($headers['content-type'], 'text/xml')) { 7555 $this->setError('Response not of type text/xml: ' . $headers['content-type']); 7556 return false; 7557 } 7558 if (strpos($headers['content-type'], '=')) { 7559 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 7560 $this->debug('Got response encoding: ' . $enc); 7561 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 7562 $this->xml_encoding = strtoupper($enc); 7563 } else { 7564 $this->xml_encoding = 'US-ASCII'; 7565 } 7566 } else { 7567 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 7568 $this->xml_encoding = 'ISO-8859-1'; 7569 } 7570 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 7571 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); 7572 // add parser debug data to our debug 7573 $this->appendDebug($parser->getDebug()); 7574 // if parse errors 7575 if($errstr = $parser->getError()){ 7576 $this->setError( $errstr); 7577 // destroy the parser object 7578 unset($parser); 7579 return false; 7580 } else { 7581 // get SOAP headers 7582 $this->responseHeaders = $parser->getHeaders(); 7583 // get SOAP headers 7584 $this->responseHeader = $parser->get_soapheader(); 7585 // get decoded message 7586 $return = $parser->get_soapbody(); 7587 // add document for doclit support 7588 $this->document = $parser->document; 7589 // destroy the parser object 7590 unset($parser); 7591 // return decode message 7592 return $return; 7593 } 7594 } 7595 7596 /** 7597 * sets user-specified cURL options 7598 * 7599 * @param mixed $option The cURL option (always integer?) 7600 * @param mixed $value The cURL option value 7601 * @access public 7602 */ 7603 function setCurlOption($option, $value) { 7604 $this->debug("setCurlOption option=$option, value="); 7605 $this->appendDebug($this->varDump($value)); 7606 $this->curl_options[$option] = $value; 7607 } 7608 7609 /** 7610 * sets the SOAP endpoint, which can override WSDL 7611 * 7612 * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override 7613 * @access public 7614 */ 7615 function setEndpoint($endpoint) { 7616 $this->debug("setEndpoint(\"$endpoint\")"); 7617 $this->forceEndpoint = $endpoint; 7618 } 7619 7620 /** 7621 * set the SOAP headers 7622 * 7623 * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers 7624 * @access public 7625 */ 7626 function setHeaders($headers){ 7627 $this->debug("setHeaders headers="); 7628 $this->appendDebug($this->varDump($headers)); 7629 $this->requestHeaders = $headers; 7630 } 7631 7632 /** 7633 * get the SOAP response headers (namespace resolution incomplete) 7634 * 7635 * @return string 7636 * @access public 7637 */ 7638 function getHeaders(){ 7639 return $this->responseHeaders; 7640 } 7641 7642 /** 7643 * get the SOAP response Header (parsed) 7644 * 7645 * @return mixed 7646 * @access public 7647 */ 7648 function getHeader(){ 7649 return $this->responseHeader; 7650 } 7651 7652 /** 7653 * set proxy info here 7654 * 7655 * @param string $proxyhost 7656 * @param string $proxyport 7657 * @param string $proxyusername 7658 * @param string $proxypassword 7659 * @access public 7660 */ 7661 function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 7662 $this->proxyhost = $proxyhost; 7663 $this->proxyport = $proxyport; 7664 $this->proxyusername = $proxyusername; 7665 $this->proxypassword = $proxypassword; 7666 } 7667 7668 /** 7669 * if authenticating, set user credentials here 7670 * 7671 * @param string $username 7672 * @param string $password 7673 * @param string $authtype (basic|digest|certificate|ntlm) 7674 * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 7675 * @access public 7676 */ 7677 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 7678 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 7679 $this->appendDebug($this->varDump($certRequest)); 7680 $this->username = $username; 7681 $this->password = $password; 7682 $this->authtype = $authtype; 7683 $this->certRequest = $certRequest; 7684 } 7685 7686 /** 7687 * use HTTP encoding 7688 * 7689 * @param string $enc HTTP encoding 7690 * @access public 7691 */ 7692 function setHTTPEncoding($enc='gzip, deflate'){ 7693 $this->debug("setHTTPEncoding(\"$enc\")"); 7694 $this->http_encoding = $enc; 7695 } 7696 7697 /** 7698 * Set whether to try to use cURL connections if possible 7699 * 7700 * @param boolean $use Whether to try to use cURL 7701 * @access public 7702 */ 7703 function setUseCURL($use) { 7704 $this->debug("setUseCURL($use)"); 7705 $this->use_curl = $use; 7706 } 7707 7708 /** 7709 * use HTTP persistent connections if possible 7710 * 7711 * @access public 7712 */ 7713 function useHTTPPersistentConnection(){ 7714 $this->debug("useHTTPPersistentConnection"); 7715 $this->persistentConnection = true; 7716 } 7717 7718 /** 7719 * gets the default RPC parameter setting. 7720 * If true, default is that call params are like RPC even for document style. 7721 * Each call() can override this value. 7722 * 7723 * This is no longer used. 7724 * 7725 * @return boolean 7726 * @access public 7727 * @deprecated 7728 */ 7729 function getDefaultRpcParams() { 7730 return $this->defaultRpcParams; 7731 } 7732 7733 /** 7734 * sets the default RPC parameter setting. 7735 * If true, default is that call params are like RPC even for document style 7736 * Each call() can override this value. 7737 * 7738 * This is no longer used. 7739 * 7740 * @param boolean $rpcParams 7741 * @access public 7742 * @deprecated 7743 */ 7744 function setDefaultRpcParams($rpcParams) { 7745 $this->defaultRpcParams = $rpcParams; 7746 } 7747 7748 /** 7749 * dynamically creates an instance of a proxy class, 7750 * allowing user to directly call methods from wsdl 7751 * 7752 * @return object soap_proxy object 7753 * @access public 7754 */ 7755 function getProxy() { 7756 $r = rand(); 7757 $evalStr = $this->_getProxyClassCode($r); 7758 //$this->debug("proxy class: $evalStr"); 7759 if ($this->getError()) { 7760 $this->debug("Error from _getProxyClassCode, so return NULL"); 7761 return null; 7762 } 7763 // eval the class 7764 eval($evalStr); 7765 // instantiate proxy object 7766 eval("\$proxy = new nusoap_proxy_$r('');"); 7767 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice 7768 $proxy->endpointType = 'wsdl'; 7769 $proxy->wsdlFile = $this->wsdlFile; 7770 $proxy->wsdl = $this->wsdl; 7771 $proxy->operations = $this->operations; 7772 $proxy->defaultRpcParams = $this->defaultRpcParams; 7773 // transfer other state 7774 $proxy->soap_defencoding = $this->soap_defencoding; 7775 $proxy->username = $this->username; 7776 $proxy->password = $this->password; 7777 $proxy->authtype = $this->authtype; 7778 $proxy->certRequest = $this->certRequest; 7779 $proxy->requestHeaders = $this->requestHeaders; 7780 $proxy->endpoint = $this->endpoint; 7781 $proxy->forceEndpoint = $this->forceEndpoint; 7782 $proxy->proxyhost = $this->proxyhost; 7783 $proxy->proxyport = $this->proxyport; 7784 $proxy->proxyusername = $this->proxyusername; 7785 $proxy->proxypassword = $this->proxypassword; 7786 $proxy->http_encoding = $this->http_encoding; 7787 $proxy->timeout = $this->timeout; 7788 $proxy->response_timeout = $this->response_timeout; 7789 $proxy->persistentConnection = &$this->persistentConnection; 7790 $proxy->decode_utf8 = $this->decode_utf8; 7791 $proxy->curl_options = $this->curl_options; 7792 $proxy->bindingType = $this->bindingType; 7793 $proxy->use_curl = $this->use_curl; 7794 return $proxy; 7795 } 7796 7797 /** 7798 * dynamically creates proxy class code 7799 * 7800 * @return string PHP/NuSOAP code for the proxy class 7801 * @access private 7802 */ 7803 function _getProxyClassCode($r) { 7804 $this->debug("in getProxy endpointType=$this->endpointType"); 7805 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); 7806 if ($this->endpointType != 'wsdl') { 7807 $evalStr = 'A proxy can only be created for a WSDL client'; 7808 $this->setError($evalStr); 7809 $evalStr = "echo \"$evalStr\";"; 7810 return $evalStr; 7811 } 7812 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 7813 $this->loadWSDL(); 7814 if ($this->getError()) { 7815 return "echo \"" . $this->getError() . "\";"; 7816 } 7817 } 7818 $evalStr = ''; 7819 foreach ($this->operations as $operation => $opData) { 7820 if ($operation != '') { 7821 // create param string and param comment string 7822 if (sizeof($opData['input']['parts']) > 0) { 7823 $paramStr = ''; 7824 $paramArrayStr = ''; 7825 $paramCommentStr = ''; 7826 foreach ($opData['input']['parts'] as $name => $type) { 7827 $paramStr .= "\$$name, "; 7828 $paramArrayStr .= "'$name' => \$$name, "; 7829 $paramCommentStr .= "$type \$$name, "; 7830 } 7831 $paramStr = substr($paramStr, 0, strlen($paramStr)-2); 7832 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); 7833 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); 7834 } else { 7835 $paramStr = ''; 7836 $paramArrayStr = ''; 7837 $paramCommentStr = 'void'; 7838 } 7839 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; 7840 $evalStr .= "// $paramCommentStr 7841 function " . str_replace('.', '__', $operation) . "($paramStr) { 7842 \$params = array($paramArrayStr); 7843 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); 7844 } 7845 "; 7846 unset($paramStr); 7847 unset($paramCommentStr); 7848 } 7849 } 7850 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { 7851 '.$evalStr.' 7852}'; 7853 return $evalStr; 7854 } 7855 7856 /** 7857 * dynamically creates proxy class code 7858 * 7859 * @return string PHP/NuSOAP code for the proxy class 7860 * @access public 7861 */ 7862 function getProxyClassCode() { 7863 $r = rand(); 7864 return $this->_getProxyClassCode($r); 7865 } 7866 7867 /** 7868 * gets the HTTP body for the current request. 7869 * 7870 * @param string $soapmsg The SOAP payload 7871 * @return string The HTTP body, which includes the SOAP payload 7872 * @access private 7873 */ 7874 function getHTTPBody($soapmsg) { 7875 return $soapmsg; 7876 } 7877 7878 /** 7879 * gets the HTTP content type for the current request. 7880 * 7881 * Note: getHTTPBody must be called before this. 7882 * 7883 * @return string the HTTP content type for the current request. 7884 * @access private 7885 */ 7886 function getHTTPContentType() { 7887 return 'text/xml'; 7888 } 7889 7890 /** 7891 * gets the HTTP content type charset for the current request. 7892 * returns false for non-text content types. 7893 * 7894 * Note: getHTTPBody must be called before this. 7895 * 7896 * @return string the HTTP content type charset for the current request. 7897 * @access private 7898 */ 7899 function getHTTPContentTypeCharset() { 7900 return $this->soap_defencoding; 7901 } 7902 7903 /* 7904 * whether or not parser should decode utf8 element content 7905 * 7906 * @return always returns true 7907 * @access public 7908 */ 7909 function decodeUTF8($bool){ 7910 $this->decode_utf8 = $bool; 7911 return true; 7912 } 7913 7914 /** 7915 * adds a new Cookie into $this->cookies array 7916 * 7917 * @param string $name Cookie Name 7918 * @param string $value Cookie Value 7919 * @return boolean if cookie-set was successful returns true, else false 7920 * @access public 7921 */ 7922 function setCookie($name, $value) { 7923 if (strlen($name) == 0) { 7924 return false; 7925 } 7926 $this->cookies[] = array('name' => $name, 'value' => $value); 7927 return true; 7928 } 7929 7930 /** 7931 * gets all Cookies 7932 * 7933 * @return array with all internal cookies 7934 * @access public 7935 */ 7936 function getCookies() { 7937 return $this->cookies; 7938 } 7939 7940 /** 7941 * checks all Cookies and delete those which are expired 7942 * 7943 * @return boolean always return true 7944 * @access private 7945 */ 7946 function checkCookies() { 7947 if (sizeof($this->cookies) == 0) { 7948 return true; 7949 } 7950 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); 7951 $curr_cookies = $this->cookies; 7952 $this->cookies = array(); 7953 foreach ($curr_cookies as $cookie) { 7954 if (! is_array($cookie)) { 7955 $this->debug('Remove cookie that is not an array'); 7956 continue; 7957 } 7958 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 7959 if (strtotime($cookie['expires']) > time()) { 7960 $this->cookies[] = $cookie; 7961 } else { 7962 $this->debug('Remove expired cookie ' . $cookie['name']); 7963 } 7964 } else { 7965 $this->cookies[] = $cookie; 7966 } 7967 } 7968 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); 7969 return true; 7970 } 7971 7972 /** 7973 * updates the current cookies with a new set 7974 * 7975 * @param array $cookies new cookies with which to update current ones 7976 * @return boolean always return true 7977 * @access private 7978 */ 7979 function UpdateCookies($cookies) { 7980 if (sizeof($this->cookies) == 0) { 7981 // no existing cookies: take whatever is new 7982 if (sizeof($cookies) > 0) { 7983 $this->debug('Setting new cookie(s)'); 7984 $this->cookies = $cookies; 7985 } 7986 return true; 7987 } 7988 if (sizeof($cookies) == 0) { 7989 // no new cookies: keep what we've got 7990 return true; 7991 } 7992 // merge 7993 foreach ($cookies as $newCookie) { 7994 if (!is_array($newCookie)) { 7995 continue; 7996 } 7997 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { 7998 continue; 7999 } 8000 $newName = $newCookie['name']; 8001 8002 $found = false; 8003 for ($i = 0; $i < count($this->cookies); $i++) { 8004 $cookie = $this->cookies[$i]; 8005 if (!is_array($cookie)) { 8006 continue; 8007 } 8008 if (!isset($cookie['name'])) { 8009 continue; 8010 } 8011 if ($newName != $cookie['name']) { 8012 continue; 8013 } 8014 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; 8015 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; 8016 if ($newDomain != $domain) { 8017 continue; 8018 } 8019 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; 8020 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; 8021 if ($newPath != $path) { 8022 continue; 8023 } 8024 $this->cookies[$i] = $newCookie; 8025 $found = true; 8026 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); 8027 break; 8028 } 8029 if (! $found) { 8030 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); 8031 $this->cookies[] = $newCookie; 8032 } 8033 } 8034 return true; 8035 } 8036} 8037 8038if (!extension_loaded('soap')) { 8039 /** 8040 * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. 8041 */ 8042 class soapclient extends nusoap_client { 8043 } 8044} 8045?> 8046