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