|
Support Incident Tracker GIT4.x
|
00001 <?php 00002 00003 /* 00004 $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $ 00005 00006 NuSOAP - Web Services Toolkit for PHP 00007 00008 Copyright (c) 2002 NuSphere Corporation 00009 00010 This library is free software; you can redistribute it and/or 00011 modify it under the terms of the GNU Lesser General Public 00012 License as published by the Free Software Foundation; either 00013 version 2.1 of the License, or (at your option) any later version. 00014 00015 This library is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 Lesser General Public License for more details. 00019 00020 You should have received a copy of the GNU Lesser General Public 00021 License along with this library; if not, write to the Free Software 00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 00024 The NuSOAP project home is: 00025 http://sourceforge.net/projects/nusoap/ 00026 00027 The primary support for NuSOAP is the mailing list: 00028 nusoap-general@lists.sourceforge.net 00029 00030 If you have any questions or comments, please email: 00031 00032 Dietrich Ayala 00033 dietrich@ganx4.com 00034 http://dietrich.ganx4.com/nusoap 00035 00036 NuSphere Corporation 00037 http://www.nusphere.com 00038 00039 */ 00040 00041 /* 00042 * Some of the standards implmented in whole or part by NuSOAP: 00043 * 00044 * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) 00045 * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) 00046 * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) 00047 * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) 00048 * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) 00049 * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) 00050 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies 00051 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 00052 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication 00053 */ 00054 00055 /* load classes 00056 00057 // necessary classes 00058 require_once('class.soapclient.php'); 00059 require_once('class.soap_val.php'); 00060 require_once('class.soap_parser.php'); 00061 require_once('class.soap_fault.php'); 00062 00063 // transport classes 00064 require_once('class.soap_transport_http.php'); 00065 00066 // optional add-on classes 00067 require_once('class.xmlschema.php'); 00068 require_once('class.wsdl.php'); 00069 00070 // server class 00071 require_once('class.soap_server.php');*/ 00072 00073 // class variable emulation 00074 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html 00075 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9; 00076 00086 class nusoap_base { 00093 var $title = 'NuSOAP'; 00100 var $version = '0.7.3'; 00107 var $revision = '$Revision: 1.114 $'; 00114 var $error_str = ''; 00121 var $debug_str = ''; 00129 var $charencoding = true; 00136 var $debugLevel; 00137 00144 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 00145 00152 var $soap_defencoding = 'ISO-8859-1'; 00153 //var $soap_defencoding = 'UTF-8'; 00154 00163 var $namespaces = array( 00164 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 00165 'xsd' => 'http://www.w3.org/2001/XMLSchema', 00166 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 00167 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 00168 ); 00169 00176 var $usedNamespaces = array(); 00177 00185 var $typemap = array( 00186 'http://www.w3.org/2001/XMLSchema' => array( 00187 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 00188 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 00189 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 00190 // abstract "any" types 00191 'anyType'=>'string','anySimpleType'=>'string', 00192 // derived datatypes 00193 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 00194 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 00195 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 00196 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 00197 'http://www.w3.org/2000/10/XMLSchema' => array( 00198 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00199 'float'=>'double','dateTime'=>'string', 00200 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00201 'http://www.w3.org/1999/XMLSchema' => array( 00202 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00203 'float'=>'double','dateTime'=>'string', 00204 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00205 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 00206 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 00207 'http://xml.apache.org/xml-soap' => array('Map') 00208 ); 00209 00218 var $xmlEntities = array('quot' => '"','amp' => '&', 00219 'lt' => '<','gt' => '>','apos' => "'"); 00220 00226 function nusoap_base() { 00227 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 00228 } 00229 00236 function getGlobalDebugLevel() { 00237 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 00238 } 00239 00246 function setGlobalDebugLevel($level) { 00247 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; 00248 } 00249 00256 function getDebugLevel() { 00257 return $this->debugLevel; 00258 } 00259 00266 function setDebugLevel($level) { 00267 $this->debugLevel = $level; 00268 } 00269 00276 function debug($string){ 00277 if ($this->debugLevel > 0) { 00278 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 00279 } 00280 } 00281 00288 function appendDebug($string){ 00289 if ($this->debugLevel > 0) { 00290 // it would be nice to use a memory stream here to use 00291 // memory more efficiently 00292 $this->debug_str .= $string; 00293 } 00294 } 00295 00301 function clearDebug() { 00302 // it would be nice to use a memory stream here to use 00303 // memory more efficiently 00304 $this->debug_str = ''; 00305 } 00306 00313 function &getDebug() { 00314 // it would be nice to use a memory stream here to use 00315 // memory more efficiently 00316 return $this->debug_str; 00317 } 00318 00326 function &getDebugAsXMLComment() { 00327 // it would be nice to use a memory stream here to use 00328 // memory more efficiently 00329 while (strpos($this->debug_str, '--')) { 00330 $this->debug_str = str_replace('--', '- -', $this->debug_str); 00331 } 00332 $ret = "<!--\n" . $this->debug_str . "\n-->"; 00333 return $ret; 00334 } 00335 00342 function expandEntities($val) { 00343 if ($this->charencoding) { 00344 $val = str_replace('&', '&', $val); 00345 $val = str_replace("'", ''', $val); 00346 $val = str_replace('"', '"', $val); 00347 $val = str_replace('<', '<', $val); 00348 $val = str_replace('>', '>', $val); 00349 } 00350 return $val; 00351 } 00352 00359 function getError(){ 00360 if($this->error_str != ''){ 00361 return $this->error_str; 00362 } 00363 return false; 00364 } 00365 00372 function setError($str){ 00373 $this->error_str = $str; 00374 } 00375 00383 function isArraySimpleOrStruct($val) { 00384 $keyList = array_keys($val); 00385 foreach ($keyList as $keyListValue) { 00386 if (!is_int($keyListValue)) { 00387 return 'arrayStruct'; 00388 } 00389 } 00390 return 'arraySimple'; 00391 } 00392 00408 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { 00409 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); 00410 $this->appendDebug('value=' . $this->varDump($val)); 00411 $this->appendDebug('attributes=' . $this->varDump($attributes)); 00412 00413 if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { 00414 $this->debug("serialize_val: serialize soapval"); 00415 $xml = $val->serialize($use); 00416 $this->appendDebug($val->getDebug()); 00417 $val->clearDebug(); 00418 $this->debug("serialize_val of soapval returning $xml"); 00419 return $xml; 00420 } 00421 // force valid name if necessary 00422 if (is_numeric($name)) { 00423 $name = '__numeric_' . $name; 00424 } elseif (! $name) { 00425 $name = 'noname'; 00426 } 00427 // if name has ns, add ns prefix to name 00428 $xmlns = ''; 00429 if($name_ns){ 00430 $prefix = 'nu'.rand(1000,9999); 00431 $name = $prefix.':'.$name; 00432 $xmlns .= " xmlns:$prefix=\"$name_ns\""; 00433 } 00434 // if type is prefixed, create type prefix 00435 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 00436 // need to fix this. shouldn't default to xsd if no ns specified 00437 // w/o checking against typemap 00438 $type_prefix = 'xsd'; 00439 } elseif($type_ns){ 00440 $type_prefix = 'ns'.rand(1000,9999); 00441 $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 00442 } 00443 // serialize attributes if present 00444 $atts = ''; 00445 if($attributes){ 00446 foreach($attributes as $k => $v){ 00447 $atts .= " $k=\"".$this->expandEntities($v).'"'; 00448 } 00449 } 00450 // serialize null value 00451 if (is_null($val)) { 00452 $this->debug("serialize_val: serialize null"); 00453 if ($use == 'literal') { 00454 // TODO: depends on minOccurs 00455 $xml = "<$name$xmlns$atts/>"; 00456 $this->debug("serialize_val returning $xml"); 00457 return $xml; 00458 } else { 00459 if (isset($type) && isset($type_prefix)) { 00460 $type_str = " xsi:type=\"$type_prefix:$type\""; 00461 } else { 00462 $type_str = ''; 00463 } 00464 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; 00465 $this->debug("serialize_val returning $xml"); 00466 return $xml; 00467 } 00468 } 00469 // serialize if an xsd built-in primitive type 00470 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 00471 $this->debug("serialize_val: serialize xsd built-in primitive type"); 00472 if (is_bool($val)) { 00473 if ($type == 'boolean') { 00474 $val = $val ? 'true' : 'false'; 00475 } elseif (! $val) { 00476 $val = 0; 00477 } 00478 } else if (is_string($val)) { 00479 $val = $this->expandEntities($val); 00480 } 00481 if ($use == 'literal') { 00482 $xml = "<$name$xmlns$atts>$val</$name>"; 00483 $this->debug("serialize_val returning $xml"); 00484 return $xml; 00485 } else { 00486 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>"; 00487 $this->debug("serialize_val returning $xml"); 00488 return $xml; 00489 } 00490 } 00491 // detect type and serialize 00492 $xml = ''; 00493 switch(true) { 00494 case (is_bool($val) || $type == 'boolean'): 00495 $this->debug("serialize_val: serialize boolean"); 00496 if ($type == 'boolean') { 00497 $val = $val ? 'true' : 'false'; 00498 } elseif (! $val) { 00499 $val = 0; 00500 } 00501 if ($use == 'literal') { 00502 $xml .= "<$name$xmlns$atts>$val</$name>"; 00503 } else { 00504 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; 00505 } 00506 break; 00507 case (is_int($val) || is_long($val) || $type == 'int'): 00508 $this->debug("serialize_val: serialize int"); 00509 if ($use == 'literal') { 00510 $xml .= "<$name$xmlns$atts>$val</$name>"; 00511 } else { 00512 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; 00513 } 00514 break; 00515 case (is_float($val)|| is_double($val) || $type == 'float'): 00516 $this->debug("serialize_val: serialize float"); 00517 if ($use == 'literal') { 00518 $xml .= "<$name$xmlns$atts>$val</$name>"; 00519 } else { 00520 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; 00521 } 00522 break; 00523 case (is_string($val) || $type == 'string'): 00524 $this->debug("serialize_val: serialize string"); 00525 $val = $this->expandEntities($val); 00526 if ($use == 'literal') { 00527 $xml .= "<$name$xmlns$atts>$val</$name>"; 00528 } else { 00529 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; 00530 } 00531 break; 00532 case is_object($val): 00533 $this->debug("serialize_val: serialize object"); 00534 if (get_class($val) == 'soapval') { 00535 $this->debug("serialize_val: serialize soapval object"); 00536 $pXml = $val->serialize($use); 00537 $this->appendDebug($val->getDebug()); 00538 $val->clearDebug(); 00539 } else { 00540 if (! $name) { 00541 $name = get_class($val); 00542 $this->debug("In serialize_val, used class name $name as element name"); 00543 } else { 00544 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 00545 } 00546 foreach(get_object_vars($val) as $k => $v){ 00547 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 00548 } 00549 } 00550 if(isset($type) && isset($type_prefix)){ 00551 $type_str = " xsi:type=\"$type_prefix:$type\""; 00552 } else { 00553 $type_str = ''; 00554 } 00555 if ($use == 'literal') { 00556 $xml .= "<$name$xmlns$atts>$pXml</$name>"; 00557 } else { 00558 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>"; 00559 } 00560 break; 00561 break; 00562 case (is_array($val) || $type): 00563 // detect if struct or array 00564 $valueType = $this->isArraySimpleOrStruct($val); 00565 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ 00566 $this->debug("serialize_val: serialize array"); 00567 $i = 0; 00568 if(is_array($val) && count($val)> 0){ 00569 foreach($val as $v){ 00570 if(is_object($v) && get_class($v) == 'soapval'){ 00571 $tt_ns = $v->type_ns; 00572 $tt = $v->type; 00573 } elseif (is_array($v)) { 00574 $tt = $this->isArraySimpleOrStruct($v); 00575 } else { 00576 $tt = gettype($v); 00577 } 00578 $array_types[$tt] = 1; 00579 // TODO: for literal, the name should be $name 00580 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 00581 ++$i; 00582 } 00583 if(count($array_types) > 1){ 00584 $array_typename = 'xsd:anyType'; 00585 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 00586 if ($tt == 'integer') { 00587 $tt = 'int'; 00588 } 00589 $array_typename = 'xsd:'.$tt; 00590 } elseif(isset($tt) && $tt == 'arraySimple'){ 00591 $array_typename = 'SOAP-ENC:Array'; 00592 } elseif(isset($tt) && $tt == 'arrayStruct'){ 00593 $array_typename = 'unnamed_struct_use_soapval'; 00594 } else { 00595 // if type is prefixed, create type prefix 00596 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 00597 $array_typename = 'xsd:' . $tt; 00598 } elseif ($tt_ns) { 00599 $tt_prefix = 'ns' . rand(1000, 9999); 00600 $array_typename = "$tt_prefix:$tt"; 00601 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 00602 } else { 00603 $array_typename = $tt; 00604 } 00605 } 00606 $array_type = $i; 00607 if ($use == 'literal') { 00608 $type_str = ''; 00609 } else if (isset($type) && isset($type_prefix)) { 00610 $type_str = " xsi:type=\"$type_prefix:$type\""; 00611 } else { 00612 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 00613 } 00614 // empty array 00615 } else { 00616 if ($use == 'literal') { 00617 $type_str = ''; 00618 } else if (isset($type) && isset($type_prefix)) { 00619 $type_str = " xsi:type=\"$type_prefix:$type\""; 00620 } else { 00621 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 00622 } 00623 } 00624 // TODO: for array in literal, there is no wrapper here 00625 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; 00626 } else { 00627 // got a struct 00628 $this->debug("serialize_val: serialize struct"); 00629 if(isset($type) && isset($type_prefix)){ 00630 $type_str = " xsi:type=\"$type_prefix:$type\""; 00631 } else { 00632 $type_str = ''; 00633 } 00634 if ($use == 'literal') { 00635 $xml .= "<$name$xmlns$atts>"; 00636 } else { 00637 $xml .= "<$name$xmlns$type_str$atts>"; 00638 } 00639 foreach($val as $k => $v){ 00640 // Apache Map 00641 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 00642 $xml .= '<item>'; 00643 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 00644 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 00645 $xml .= '</item>'; 00646 } else { 00647 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 00648 } 00649 } 00650 $xml .= "</$name>"; 00651 } 00652 break; 00653 default: 00654 $this->debug("serialize_val: serialize unknown"); 00655 $xml .= 'not detected, got '.gettype($val).' for '.$val; 00656 break; 00657 } 00658 $this->debug("serialize_val returning $xml"); 00659 return $xml; 00660 } 00661 00674 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 00675 // TODO: add an option to automatically run utf8_encode on $body and $headers 00676 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 00677 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 00678 00679 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 00680 $this->debug("headers:"); 00681 $this->appendDebug($this->varDump($headers)); 00682 $this->debug("namespaces:"); 00683 $this->appendDebug($this->varDump($namespaces)); 00684 00685 // serialize namespaces 00686 $ns_string = ''; 00687 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 00688 $ns_string .= " xmlns:$k=\"$v\""; 00689 } 00690 if($encodingStyle) { 00691 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 00692 } 00693 00694 // serialize headers 00695 if($headers){ 00696 if (is_array($headers)) { 00697 $xml = ''; 00698 foreach ($headers as $k => $v) { 00699 if (is_object($v) && get_class($v) == 'soapval') { 00700 $xml .= $this->serialize_val($v, false, false, false, false, false, $use); 00701 } else { 00702 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); 00703 } 00704 } 00705 $headers = $xml; 00706 $this->debug("In serializeEnvelope, serialized array of headers to $headers"); 00707 } 00708 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; 00709 } 00710 // serialize envelope 00711 return 00712 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". 00713 '<SOAP-ENV:Envelope'.$ns_string.">". 00714 $headers. 00715 "<SOAP-ENV:Body>". 00716 $body. 00717 "</SOAP-ENV:Body>". 00718 "</SOAP-ENV:Envelope>"; 00719 } 00720 00729 function formatDump($str){ 00730 $str = htmlspecialchars($str); 00731 return nl2br($str); 00732 } 00733 00741 function contractQname($qname){ 00742 // get element namespace 00743 //$this->xdebug("Contract $qname"); 00744 if (strrpos($qname, ':')) { 00745 // get unqualified name 00746 $name = substr($qname, strrpos($qname, ':') + 1); 00747 // get ns 00748 $ns = substr($qname, 0, strrpos($qname, ':')); 00749 $p = $this->getPrefixFromNamespace($ns); 00750 if ($p) { 00751 return $p . ':' . $name; 00752 } 00753 return $qname; 00754 } else { 00755 return $qname; 00756 } 00757 } 00758 00766 function expandQname($qname){ 00767 // get element prefix 00768 if(strpos($qname,':') && !ereg('^http://',$qname)){ 00769 // get unqualified name 00770 $name = substr(strstr($qname,':'),1); 00771 // get ns prefix 00772 $prefix = substr($qname,0,strpos($qname,':')); 00773 if(isset($this->namespaces[$prefix])){ 00774 return $this->namespaces[$prefix].':'.$name; 00775 } else { 00776 return $qname; 00777 } 00778 } else { 00779 return $qname; 00780 } 00781 } 00782 00791 function getLocalPart($str){ 00792 if($sstr = strrchr($str,':')){ 00793 // get unqualified name 00794 return substr( $sstr, 1 ); 00795 } else { 00796 return $str; 00797 } 00798 } 00799 00808 function getPrefix($str){ 00809 if($pos = strrpos($str,':')){ 00810 // get prefix 00811 return substr($str,0,$pos); 00812 } 00813 return false; 00814 } 00815 00823 function getNamespaceFromPrefix($prefix){ 00824 if (isset($this->namespaces[$prefix])) { 00825 return $this->namespaces[$prefix]; 00826 } 00827 //$this->setError("No namespace registered for prefix '$prefix'"); 00828 return false; 00829 } 00830 00839 function getPrefixFromNamespace($ns) { 00840 foreach ($this->namespaces as $p => $n) { 00841 if ($ns == $n || $ns == $p) { 00842 $this->usedNamespaces[$p] = $n; 00843 return $p; 00844 } 00845 } 00846 return false; 00847 } 00848 00855 function getmicrotime() { 00856 if (function_exists('gettimeofday')) { 00857 $tod = gettimeofday(); 00858 $sec = $tod['sec']; 00859 $usec = $tod['usec']; 00860 } else { 00861 $sec = time(); 00862 $usec = 0; 00863 } 00864 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 00865 } 00866 00874 function varDump($data) { 00875 ob_start(); 00876 var_dump($data); 00877 $ret_val = ob_get_contents(); 00878 ob_end_clean(); 00879 return $ret_val; 00880 } 00881 00888 function __toString() { 00889 return $this->varDump($this); 00890 } 00891 } 00892 00893 // XML Schema Datatype Helper Functions 00894 00895 //xsd:dateTime helpers 00896 00904 function timestamp_to_iso8601($timestamp,$utc=true){ 00905 $datestr = date('Y-m-d\TH:i:sO',$timestamp); 00906 if($utc){ 00907 $eregStr = 00908 '([0-9]{4})-'. // centuries & years CCYY- 00909 '([0-9]{2})-'. // months MM- 00910 '([0-9]{2})'. // days DD 00911 'T'. // separator T 00912 '([0-9]{2}):'. // hours hh: 00913 '([0-9]{2}):'. // minutes mm: 00914 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 00915 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00916 00917 if(ereg($eregStr,$datestr,$regs)){ 00918 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 00919 } 00920 return false; 00921 } else { 00922 return $datestr; 00923 } 00924 } 00925 00932 function iso8601_to_timestamp($datestr){ 00933 $eregStr = 00934 '([0-9]{4})-'. // centuries & years CCYY- 00935 '([0-9]{2})-'. // months MM- 00936 '([0-9]{2})'. // days DD 00937 'T'. // separator T 00938 '([0-9]{2}):'. // hours hh: 00939 '([0-9]{2}):'. // minutes mm: 00940 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 00941 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00942 if(ereg($eregStr,$datestr,$regs)){ 00943 // not utc 00944 if($regs[8] != 'Z'){ 00945 $op = substr($regs[8],0,1); 00946 $h = substr($regs[8],1,2); 00947 $m = substr($regs[8],strlen($regs[8])-2,2); 00948 if($op == '-'){ 00949 $regs[4] = $regs[4] + $h; 00950 $regs[5] = $regs[5] + $m; 00951 } elseif($op == '+'){ 00952 $regs[4] = $regs[4] - $h; 00953 $regs[5] = $regs[5] - $m; 00954 } 00955 } 00956 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 00957 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 00958 } else { 00959 return false; 00960 } 00961 } 00962 00970 function usleepWindows($usec) 00971 { 00972 $start = gettimeofday(); 00973 00974 do 00975 { 00976 $stop = gettimeofday(); 00977 $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 00978 + $stop['usec'] - $start['usec']; 00979 } 00980 while ($timePassed < $usec); 00981 } 00982 00983 ?><?php 00984 00985 00986 00995 class nusoap_fault extends nusoap_base { 01001 var $faultcode; 01007 var $faultactor; 01013 var $faultstring; 01019 var $faultdetail; 01020 01029 function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ 01030 parent::nusoap_base(); 01031 $this->faultcode = $faultcode; 01032 $this->faultactor = $faultactor; 01033 $this->faultstring = $faultstring; 01034 $this->faultdetail = $faultdetail; 01035 } 01036 01043 function serialize(){ 01044 $ns_string = ''; 01045 foreach($this->namespaces as $k => $v){ 01046 $ns_string .= "\n xmlns:$k=\"$v\""; 01047 } 01048 $return_msg = 01049 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. 01050 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". 01051 '<SOAP-ENV:Body>'. 01052 '<SOAP-ENV:Fault>'. 01053 $this->serialize_val($this->faultcode, 'faultcode'). 01054 $this->serialize_val($this->faultactor, 'faultactor'). 01055 $this->serialize_val($this->faultstring, 'faultstring'). 01056 $this->serialize_val($this->faultdetail, 'detail'). 01057 '</SOAP-ENV:Fault>'. 01058 '</SOAP-ENV:Body>'. 01059 '</SOAP-ENV:Envelope>'; 01060 return $return_msg; 01061 } 01062 } 01063 01067 class soap_fault extends nusoap_fault { 01068 } 01069 01070 ?><?php 01071 01072 01073 01083 class nusoap_xmlschema extends nusoap_base { 01084 01085 // files 01086 var $schema = ''; 01087 var $xml = ''; 01088 // namespaces 01089 var $enclosingNamespaces; 01090 // schema info 01091 var $schemaInfo = array(); 01092 var $schemaTargetNamespace = ''; 01093 // types, elements, attributes defined by the schema 01094 var $attributes = array(); 01095 var $complexTypes = array(); 01096 var $complexTypeStack = array(); 01097 var $currentComplexType = null; 01098 var $elements = array(); 01099 var $elementStack = array(); 01100 var $currentElement = null; 01101 var $simpleTypes = array(); 01102 var $simpleTypeStack = array(); 01103 var $currentSimpleType = null; 01104 // imports 01105 var $imports = array(); 01106 // parser vars 01107 var $parser; 01108 var $position = 0; 01109 var $depth = 0; 01110 var $depth_array = array(); 01111 var $message = array(); 01112 var $defaultNamespace = array(); 01113 01122 function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ 01123 parent::nusoap_base(); 01124 $this->debug('nusoap_xmlschema class instantiated, inside constructor'); 01125 // files 01126 $this->schema = $schema; 01127 $this->xml = $xml; 01128 01129 // namespaces 01130 $this->enclosingNamespaces = $namespaces; 01131 $this->namespaces = array_merge($this->namespaces, $namespaces); 01132 01133 // parse schema file 01134 if($schema != ''){ 01135 $this->debug('initial schema file: '.$schema); 01136 $this->parseFile($schema, 'schema'); 01137 } 01138 01139 // parse xml file 01140 if($xml != ''){ 01141 $this->debug('initial xml file: '.$xml); 01142 $this->parseFile($xml, 'xml'); 01143 } 01144 01145 } 01146 01155 function parseFile($xml,$type){ 01156 // parse xml file 01157 if($xml != ""){ 01158 $xmlStr = @join("",@file($xml)); 01159 if($xmlStr == ""){ 01160 $msg = 'Error reading XML from '.$xml; 01161 $this->setError($msg); 01162 $this->debug($msg); 01163 return false; 01164 } else { 01165 $this->debug("parsing $xml"); 01166 $this->parseString($xmlStr,$type); 01167 $this->debug("done parsing $xml"); 01168 return true; 01169 } 01170 } 01171 return false; 01172 } 01173 01181 function parseString($xml,$type){ 01182 // parse xml string 01183 if($xml != ""){ 01184 01185 // Create an XML parser. 01186 $this->parser = xml_parser_create(); 01187 // Set the options for parsing the XML data. 01188 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 01189 01190 // Set the object for the parser. 01191 xml_set_object($this->parser, $this); 01192 01193 // Set the element handlers for the parser. 01194 if($type == "schema"){ 01195 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); 01196 xml_set_character_data_handler($this->parser,'schemaCharacterData'); 01197 } elseif($type == "xml"){ 01198 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); 01199 xml_set_character_data_handler($this->parser,'xmlCharacterData'); 01200 } 01201 01202 // Parse the XML file. 01203 if(!xml_parse($this->parser,$xml,true)){ 01204 // Display an error message. 01205 $errstr = sprintf('XML error parsing XML schema on line %d: %s', 01206 xml_get_current_line_number($this->parser), 01207 xml_error_string(xml_get_error_code($this->parser)) 01208 ); 01209 $this->debug($errstr); 01210 $this->debug("XML payload:\n" . $xml); 01211 $this->setError($errstr); 01212 } 01213 01214 xml_parser_free($this->parser); 01215 } else{ 01216 $this->debug('no xml passed to parseString()!!'); 01217 $this->setError('no xml passed to parseString()!!'); 01218 } 01219 } 01220 01228 function CreateTypeName($ename) { 01229 $scope = ''; 01230 for ($i = 0; $i < count($this->complexTypeStack); $i++) { 01231 $scope .= $this->complexTypeStack[$i] . '_'; 01232 } 01233 return $scope . $ename . '_ContainedType'; 01234 } 01235 01244 function schemaStartElement($parser, $name, $attrs) { 01245 01246 // position in the total number of elements, starting from 0 01247 $pos = $this->position++; 01248 $depth = $this->depth++; 01249 // set self as current value for this depth 01250 $this->depth_array[$depth] = $pos; 01251 $this->message[$pos] = array('cdata' => ''); 01252 if ($depth > 0) { 01253 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; 01254 } else { 01255 $this->defaultNamespace[$pos] = false; 01256 } 01257 01258 // get element prefix 01259 if($prefix = $this->getPrefix($name)){ 01260 // get unqualified name 01261 $name = $this->getLocalPart($name); 01262 } else { 01263 $prefix = ''; 01264 } 01265 01266 // loop thru attributes, expanding, and registering namespace declarations 01267 if(count($attrs) > 0){ 01268 foreach($attrs as $k => $v){ 01269 // if ns declarations, add to class level array of valid namespaces 01270 if(ereg("^xmlns",$k)){ 01271 //$this->xdebug("$k: $v"); 01272 //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); 01273 if($ns_prefix = substr(strrchr($k,':'),1)){ 01274 //$this->xdebug("Add namespace[$ns_prefix] = $v"); 01275 $this->namespaces[$ns_prefix] = $v; 01276 } else { 01277 $this->defaultNamespace[$pos] = $v; 01278 if (! $this->getPrefixFromNamespace($v)) { 01279 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; 01280 } 01281 } 01282 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ 01283 $this->XMLSchemaVersion = $v; 01284 $this->namespaces['xsi'] = $v.'-instance'; 01285 } 01286 } 01287 } 01288 foreach($attrs as $k => $v){ 01289 // expand each attribute 01290 $k = strpos($k,':') ? $this->expandQname($k) : $k; 01291 $v = strpos($v,':') ? $this->expandQname($v) : $v; 01292 $eAttrs[$k] = $v; 01293 } 01294 $attrs = $eAttrs; 01295 } else { 01296 $attrs = array(); 01297 } 01298 // find status, register data 01299 switch($name){ 01300 case 'all': // (optional) compositor content for a complexType 01301 case 'choice': 01302 case 'group': 01303 case 'sequence': 01304 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); 01305 $this->complexTypes[$this->currentComplexType]['compositor'] = $name; 01306 //if($name == 'all' || $name == 'sequence'){ 01307 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01308 //} 01309 break; 01310 case 'attribute': // complexType attribute 01311 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); 01312 $this->xdebug("parsing attribute:"); 01313 $this->appendDebug($this->varDump($attrs)); 01314 if (!isset($attrs['form'])) { 01315 $attrs['form'] = $this->schemaInfo['attributeFormDefault']; 01316 } 01317 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01318 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01319 if (!strpos($v, ':')) { 01320 // no namespace in arrayType attribute value... 01321 if ($this->defaultNamespace[$pos]) { 01322 // ...so use the default 01323 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01324 } 01325 } 01326 } 01327 if(isset($attrs['name'])){ 01328 $this->attributes[$attrs['name']] = $attrs; 01329 $aname = $attrs['name']; 01330 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ 01331 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01332 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01333 } else { 01334 $aname = ''; 01335 } 01336 } elseif(isset($attrs['ref'])){ 01337 $aname = $attrs['ref']; 01338 $this->attributes[$attrs['ref']] = $attrs; 01339 } 01340 01341 if($this->currentComplexType){ // This should *always* be 01342 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; 01343 } 01344 // arrayType attribute 01345 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ 01346 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01347 $prefix = $this->getPrefix($aname); 01348 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ 01349 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01350 } else { 01351 $v = ''; 01352 } 01353 if(strpos($v,'[,]')){ 01354 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; 01355 } 01356 $v = substr($v,0,strpos($v,'[')); // clip the [] 01357 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ 01358 $v = $this->XMLSchemaVersion.':'.$v; 01359 } 01360 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; 01361 } 01362 break; 01363 case 'complexContent': // (optional) content for a complexType 01364 break; 01365 case 'complexType': 01366 array_push($this->complexTypeStack, $this->currentComplexType); 01367 if(isset($attrs['name'])){ 01368 // TODO: what is the scope of named complexTypes that appear 01369 // nested within other c complexTypes? 01370 $this->xdebug('processing named complexType '.$attrs['name']); 01371 //$this->currentElement = false; 01372 $this->currentComplexType = $attrs['name']; 01373 $this->complexTypes[$this->currentComplexType] = $attrs; 01374 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01375 // This is for constructs like 01376 // <complexType name="ListOfString" base="soap:Array"> 01377 // <sequence> 01378 // <element name="string" type="xsd:string" 01379 // minOccurs="0" maxOccurs="unbounded" /> 01380 // </sequence> 01381 // </complexType> 01382 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01383 $this->xdebug('complexType is unusual array'); 01384 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01385 } else { 01386 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01387 } 01388 } else { 01389 $name = $this->CreateTypeName($this->currentElement); 01390 $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); 01391 $this->currentComplexType = $name; 01392 //$this->currentElement = false; 01393 $this->complexTypes[$this->currentComplexType] = $attrs; 01394 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01395 // This is for constructs like 01396 // <complexType name="ListOfString" base="soap:Array"> 01397 // <sequence> 01398 // <element name="string" type="xsd:string" 01399 // minOccurs="0" maxOccurs="unbounded" /> 01400 // </sequence> 01401 // </complexType> 01402 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01403 $this->xdebug('complexType is unusual array'); 01404 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01405 } else { 01406 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01407 } 01408 } 01409 break; 01410 case 'element': 01411 array_push($this->elementStack, $this->currentElement); 01412 if (!isset($attrs['form'])) { 01413 $attrs['form'] = $this->schemaInfo['elementFormDefault']; 01414 } 01415 if(isset($attrs['type'])){ 01416 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); 01417 if (! $this->getPrefix($attrs['type'])) { 01418 if ($this->defaultNamespace[$pos]) { 01419 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; 01420 $this->xdebug('used default namespace to make type ' . $attrs['type']); 01421 } 01422 } 01423 // This is for constructs like 01424 // <complexType name="ListOfString" base="soap:Array"> 01425 // <sequence> 01426 // <element name="string" type="xsd:string" 01427 // minOccurs="0" maxOccurs="unbounded" /> 01428 // </sequence> 01429 // </complexType> 01430 if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { 01431 $this->xdebug('arrayType for unusual array is ' . $attrs['type']); 01432 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; 01433 } 01434 $this->currentElement = $attrs['name']; 01435 $ename = $attrs['name']; 01436 } elseif(isset($attrs['ref'])){ 01437 $this->xdebug("processing element as ref to ".$attrs['ref']); 01438 $this->currentElement = "ref to ".$attrs['ref']; 01439 $ename = $this->getLocalPart($attrs['ref']); 01440 } else { 01441 $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); 01442 $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); 01443 $this->currentElement = $attrs['name']; 01444 $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; 01445 $ename = $attrs['name']; 01446 } 01447 if (isset($ename) && $this->currentComplexType) { 01448 $this->xdebug("add element $ename to complexType $this->currentComplexType"); 01449 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; 01450 } elseif (!isset($attrs['ref'])) { 01451 $this->xdebug("add element $ename to elements array"); 01452 $this->elements[ $attrs['name'] ] = $attrs; 01453 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01454 } 01455 break; 01456 case 'enumeration': // restriction value list member 01457 $this->xdebug('enumeration ' . $attrs['value']); 01458 if ($this->currentSimpleType) { 01459 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; 01460 } elseif ($this->currentComplexType) { 01461 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; 01462 } 01463 break; 01464 case 'extension': // simpleContent or complexContent type extension 01465 $this->xdebug('extension ' . $attrs['base']); 01466 if ($this->currentComplexType) { 01467 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; 01468 } 01469 break; 01470 case 'import': 01471 if (isset($attrs['schemaLocation'])) { 01472 //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); 01473 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 01474 } else { 01475 //$this->xdebug('import namespace ' . $attrs['namespace']); 01476 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 01477 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 01478 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 01479 } 01480 } 01481 break; 01482 case 'list': // simpleType value list 01483 break; 01484 case 'restriction': // simpleType, simpleContent or complexContent value restriction 01485 $this->xdebug('restriction ' . $attrs['base']); 01486 if($this->currentSimpleType){ 01487 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; 01488 } elseif($this->currentComplexType){ 01489 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; 01490 if(strstr($attrs['base'],':') == ':Array'){ 01491 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01492 } 01493 } 01494 break; 01495 case 'schema': 01496 $this->schemaInfo = $attrs; 01497 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); 01498 if (isset($attrs['targetNamespace'])) { 01499 $this->schemaTargetNamespace = $attrs['targetNamespace']; 01500 } 01501 if (!isset($attrs['elementFormDefault'])) { 01502 $this->schemaInfo['elementFormDefault'] = 'unqualified'; 01503 } 01504 if (!isset($attrs['attributeFormDefault'])) { 01505 $this->schemaInfo['attributeFormDefault'] = 'unqualified'; 01506 } 01507 break; 01508 case 'simpleContent': // (optional) content for a complexType 01509 break; 01510 case 'simpleType': 01511 array_push($this->simpleTypeStack, $this->currentSimpleType); 01512 if(isset($attrs['name'])){ 01513 $this->xdebug("processing simpleType for name " . $attrs['name']); 01514 $this->currentSimpleType = $attrs['name']; 01515 $this->simpleTypes[ $attrs['name'] ] = $attrs; 01516 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; 01517 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; 01518 } else { 01519 $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); 01520 $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); 01521 $this->currentSimpleType = $name; 01522 //$this->currentElement = false; 01523 $this->simpleTypes[$this->currentSimpleType] = $attrs; 01524 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; 01525 } 01526 break; 01527 case 'union': // simpleType type list 01528 break; 01529 default: 01530 //$this->xdebug("do not have anything to do for element $name"); 01531 } 01532 } 01533 01541 function schemaEndElement($parser, $name) { 01542 // bring depth down a notch 01543 $this->depth--; 01544 // position of current element is equal to the last value left in depth_array for my depth 01545 if(isset($this->depth_array[$this->depth])){ 01546 $pos = $this->depth_array[$this->depth]; 01547 } 01548 // get element prefix 01549 if ($prefix = $this->getPrefix($name)){ 01550 // get unqualified name 01551 $name = $this->getLocalPart($name); 01552 } else { 01553 $prefix = ''; 01554 } 01555 // move on... 01556 if($name == 'complexType'){ 01557 $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); 01558 $this->currentComplexType = array_pop($this->complexTypeStack); 01559 //$this->currentElement = false; 01560 } 01561 if($name == 'element'){ 01562 $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); 01563 $this->currentElement = array_pop($this->elementStack); 01564 } 01565 if($name == 'simpleType'){ 01566 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); 01567 $this->currentSimpleType = array_pop($this->simpleTypeStack); 01568 } 01569 } 01570 01578 function schemaCharacterData($parser, $data){ 01579 $pos = $this->depth_array[$this->depth - 1]; 01580 $this->message[$pos]['cdata'] .= $data; 01581 } 01582 01588 function serializeSchema(){ 01589 01590 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); 01591 $xml = ''; 01592 // imports 01593 if (sizeof($this->imports) > 0) { 01594 foreach($this->imports as $ns => $list) { 01595 foreach ($list as $ii) { 01596 if ($ii['location'] != '') { 01597 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; 01598 } else { 01599 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; 01600 } 01601 } 01602 } 01603 } 01604 // complex types 01605 foreach($this->complexTypes as $typeName => $attrs){ 01606 $contentStr = ''; 01607 // serialize child elements 01608 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ 01609 foreach($attrs['elements'] as $element => $eParts){ 01610 if(isset($eParts['ref'])){ 01611 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; 01612 } else { 01613 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; 01614 foreach ($eParts as $aName => $aValue) { 01615 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable 01616 if ($aName != 'name' && $aName != 'type') { 01617 $contentStr .= " $aName=\"$aValue\""; 01618 } 01619 } 01620 $contentStr .= "/>\n"; 01621 } 01622 } 01623 // compositor wraps elements 01624 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { 01625 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; 01626 } 01627 } 01628 // attributes 01629 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ 01630 foreach($attrs['attrs'] as $attr => $aParts){ 01631 $contentStr .= " <$schemaPrefix:attribute"; 01632 foreach ($aParts as $a => $v) { 01633 if ($a == 'ref' || $a == 'type') { 01634 $contentStr .= " $a=\"".$this->contractQName($v).'"'; 01635 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { 01636 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; 01637 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; 01638 } else { 01639 $contentStr .= " $a=\"$v\""; 01640 } 01641 } 01642 $contentStr .= "/>\n"; 01643 } 01644 } 01645 // if restriction 01646 if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ 01647 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; 01648 // complex or simple content 01649 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ 01650 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; 01651 } 01652 } 01653 // finalize complex type 01654 if($contentStr != ''){ 01655 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; 01656 } else { 01657 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; 01658 } 01659 $xml .= $contentStr; 01660 } 01661 // simple types 01662 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ 01663 foreach($this->simpleTypes as $typeName => $eParts){ 01664 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; 01665 if (isset($eParts['enumeration'])) { 01666 foreach ($eParts['enumeration'] as $e) { 01667 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; 01668 } 01669 } 01670 $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>"; 01671 } 01672 } 01673 // elements 01674 if(isset($this->elements) && count($this->elements) > 0){ 01675 foreach($this->elements as $element => $eParts){ 01676 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; 01677 } 01678 } 01679 // attributes 01680 if(isset($this->attributes) && count($this->attributes) > 0){ 01681 foreach($this->attributes as $attr => $aParts){ 01682 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; 01683 } 01684 } 01685 // finish 'er up 01686 $attr = ''; 01687 foreach ($this->schemaInfo as $k => $v) { 01688 if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { 01689 $attr .= " $k=\"$v\""; 01690 } 01691 } 01692 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; 01693 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { 01694 $el .= " xmlns:$nsp=\"$ns\""; 01695 } 01696 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; 01697 return $xml; 01698 } 01699 01706 function xdebug($string){ 01707 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); 01708 } 01709 01722 function getPHPType($type,$ns){ 01723 if(isset($this->typemap[$ns][$type])){ 01724 //print "found type '$type' and ns $ns in typemap<br>"; 01725 return $this->typemap[$ns][$type]; 01726 } elseif(isset($this->complexTypes[$type])){ 01727 //print "getting type '$type' and ns $ns from complexTypes array<br>"; 01728 return $this->complexTypes[$type]['phpType']; 01729 } 01730 return false; 01731 } 01732 01755 function getTypeDef($type){ 01756 //$this->debug("in getTypeDef for type $type"); 01757 if (substr($type, -1) == '^') { 01758 $is_element = 1; 01759 $type = substr($type, 0, -1); 01760 } else { 01761 $is_element = 0; 01762 } 01763 01764 if((! $is_element) && isset($this->complexTypes[$type])){ 01765 $this->xdebug("in getTypeDef, found complexType $type"); 01766 return $this->complexTypes[$type]; 01767 } elseif((! $is_element) && isset($this->simpleTypes[$type])){ 01768 $this->xdebug("in getTypeDef, found simpleType $type"); 01769 if (!isset($this->simpleTypes[$type]['phpType'])) { 01770 // get info for type to tack onto the simple type 01771 // TODO: can this ever really apply (i.e. what is a simpleType really?) 01772 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); 01773 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); 01774 $etype = $this->getTypeDef($uqType); 01775 if ($etype) { 01776 $this->xdebug("in getTypeDef, found type for simpleType $type:"); 01777 $this->xdebug($this->varDump($etype)); 01778 if (isset($etype['phpType'])) { 01779 $this->simpleTypes[$type]['phpType'] = $etype['phpType']; 01780 } 01781 if (isset($etype['elements'])) { 01782 $this->simpleTypes[$type]['elements'] = $etype['elements']; 01783 } 01784 } 01785 } 01786 return $this->simpleTypes[$type]; 01787 } elseif(isset($this->elements[$type])){ 01788 $this->xdebug("in getTypeDef, found element $type"); 01789 if (!isset($this->elements[$type]['phpType'])) { 01790 // get info for type to tack onto the element 01791 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); 01792 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); 01793 $etype = $this->getTypeDef($uqType); 01794 if ($etype) { 01795 $this->xdebug("in getTypeDef, found type for element $type:"); 01796 $this->xdebug($this->varDump($etype)); 01797 if (isset($etype['phpType'])) { 01798 $this->elements[$type]['phpType'] = $etype['phpType']; 01799 } 01800 if (isset($etype['elements'])) { 01801 $this->elements[$type]['elements'] = $etype['elements']; 01802 } 01803 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { 01804 $this->xdebug("in getTypeDef, element $type is an XSD type"); 01805 $this->elements[$type]['phpType'] = 'scalar'; 01806 } 01807 } 01808 return $this->elements[$type]; 01809 } elseif(isset($this->attributes[$type])){ 01810 $this->xdebug("in getTypeDef, found attribute $type"); 01811 return $this->attributes[$type]; 01812 } elseif (ereg('_ContainedType$', $type)) { 01813 $this->xdebug("in getTypeDef, have an untyped element $type"); 01814 $typeDef['typeClass'] = 'simpleType'; 01815 $typeDef['phpType'] = 'scalar'; 01816 $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; 01817 return $typeDef; 01818 } 01819 $this->xdebug("in getTypeDef, did not find $type"); 01820 return false; 01821 } 01822 01831 function serializeTypeDef($type){ 01832 //print "in sTD() for type $type<br>"; 01833 if($typeDef = $this->getTypeDef($type)){ 01834 $str .= '<'.$type; 01835 if(is_array($typeDef['attrs'])){ 01836 foreach($typeDef['attrs'] as $attName => $data){ 01837 $str .= " $attName=\"{type = ".$data['type']."}\""; 01838 } 01839 } 01840 $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; 01841 if(count($typeDef['elements']) > 0){ 01842 $str .= ">"; 01843 foreach($typeDef['elements'] as $element => $eData){ 01844 $str .= $this->serializeTypeDef($element); 01845 } 01846 $str .= "</$type>"; 01847 } elseif($typeDef['typeClass'] == 'element') { 01848 $str .= "></$type>"; 01849 } else { 01850 $str .= "/>"; 01851 } 01852 return $str; 01853 } 01854 return false; 01855 } 01856 01867 function typeToForm($name,$type){ 01868 // get typedef 01869 if($typeDef = $this->getTypeDef($type)){ 01870 // if struct 01871 if($typeDef['phpType'] == 'struct'){ 01872 $buffer .= '<table>'; 01873 foreach($typeDef['elements'] as $child => $childDef){ 01874 $buffer .= " 01875 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> 01876 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; 01877 } 01878 $buffer .= '</table>'; 01879 // if array 01880 } elseif($typeDef['phpType'] == 'array'){ 01881 $buffer .= '<table>'; 01882 for($i=0;$i < 3; $i++){ 01883 $buffer .= " 01884 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> 01885 <td><input type='text' name='parameters[".$name."][]'></td></tr>"; 01886 } 01887 $buffer .= '</table>'; 01888 // if scalar 01889 } else { 01890 $buffer .= "<input type='text' name='parameters[$name]'>"; 01891 } 01892 } else { 01893 $buffer .= "<input type='text' name='parameters[$name]'>"; 01894 } 01895 return $buffer; 01896 } 01897 01939 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ 01940 $this->complexTypes[$name] = array( 01941 'name' => $name, 01942 'typeClass' => $typeClass, 01943 'phpType' => $phpType, 01944 'compositor'=> $compositor, 01945 'restrictionBase' => $restrictionBase, 01946 'elements' => $elements, 01947 'attrs' => $attrs, 01948 'arrayType' => $arrayType 01949 ); 01950 01951 $this->xdebug("addComplexType $name:"); 01952 $this->appendDebug($this->varDump($this->complexTypes[$name])); 01953 } 01954 01967 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 01968 $this->simpleTypes[$name] = array( 01969 'name' => $name, 01970 'typeClass' => $typeClass, 01971 'phpType' => $phpType, 01972 'type' => $restrictionBase, 01973 'enumeration' => $enumeration 01974 ); 01975 01976 $this->xdebug("addSimpleType $name:"); 01977 $this->appendDebug($this->varDump($this->simpleTypes[$name])); 01978 } 01979 01987 function addElement($attrs) { 01988 if (! $this->getPrefix($attrs['type'])) { 01989 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; 01990 } 01991 $this->elements[ $attrs['name'] ] = $attrs; 01992 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01993 01994 $this->xdebug("addElement " . $attrs['name']); 01995 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); 01996 } 01997 } 01998 02002 class XMLSchema extends nusoap_xmlschema { 02003 } 02004 02005 ?><?php 02006 02007 02008 02020 class soapval extends nusoap_base { 02027 var $name; 02034 var $type; 02041 var $value; 02048 var $element_ns; 02055 var $type_ns; 02062 var $attributes; 02063 02075 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { 02076 parent::nusoap_base(); 02077 $this->name = $name; 02078 $this->type = $type; 02079 $this->value = $value; 02080 $this->element_ns = $element_ns; 02081 $this->type_ns = $type_ns; 02082 $this->attributes = $attributes; 02083 } 02084 02092 function serialize($use='encoded') { 02093 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); 02094 } 02095 02102 function decode(){ 02103 return $this->value; 02104 } 02105 } 02106 02107 02108 02109 ?><?php 02110 02111 02112 02122 class soap_transport_http extends nusoap_base { 02123 02124 var $url = ''; 02125 var $uri = ''; 02126 var $digest_uri = ''; 02127 var $scheme = ''; 02128 var $host = ''; 02129 var $port = ''; 02130 var $path = ''; 02131 var $request_method = 'POST'; 02132 var $protocol_version = '1.0'; 02133 var $encoding = ''; 02134 var $outgoing_headers = array(); 02135 var $incoming_headers = array(); 02136 var $incoming_cookies = array(); 02137 var $outgoing_payload = ''; 02138 var $incoming_payload = ''; 02139 var $response_status_line; // HTTP response status line 02140 var $useSOAPAction = true; 02141 var $persistentConnection = false; 02142 var $ch = false; // cURL handle 02143 var $ch_options = array(); // cURL custom options 02144 var $use_curl = false; // force cURL use 02145 var $proxy = null; // proxy information (associative array) 02146 var $username = ''; 02147 var $password = ''; 02148 var $authtype = ''; 02149 var $digestRequest = array(); 02150 var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) 02151 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' 02152 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' 02153 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' 02154 // passphrase: SSL key password/passphrase 02155 // certpassword: SSL certificate password 02156 // verifypeer: default is 1 02157 // verifyhost: default is 1 02158 02167 function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ 02168 parent::nusoap_base(); 02169 $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); 02170 $this->appendDebug($this->varDump($curl_options)); 02171 $this->setURL($url); 02172 if (is_array($curl_options)) { 02173 $this->ch_options = $curl_options; 02174 } 02175 $this->use_curl = $use_curl; 02176 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 02177 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); 02178 } 02179 02187 function setCurlOption($option, $value) { 02188 $this->debug("setCurlOption option=$option, value="); 02189 $this->appendDebug($this->varDump($value)); 02190 curl_setopt($this->ch, $option, $value); 02191 } 02192 02200 function setHeader($name, $value) { 02201 $this->outgoing_headers[$name] = $value; 02202 $this->debug("set header $name: $value"); 02203 } 02204 02211 function unsetHeader($name) { 02212 if (isset($this->outgoing_headers[$name])) { 02213 $this->debug("unset header $name"); 02214 unset($this->outgoing_headers[$name]); 02215 } 02216 } 02217 02224 function setURL($url) { 02225 $this->url = $url; 02226 02227 $u = parse_url($url); 02228 foreach($u as $k => $v){ 02229 $this->debug("parsed URL $k = $v"); 02230 $this->$k = $v; 02231 } 02232 02233 // add any GET params to path 02234 if(isset($u['query']) && $u['query'] != ''){ 02235 $this->path .= '?' . $u['query']; 02236 } 02237 02238 // set default port 02239 if(!isset($u['port'])){ 02240 if($u['scheme'] == 'https'){ 02241 $this->port = 443; 02242 } else { 02243 $this->port = 80; 02244 } 02245 } 02246 02247 $this->uri = $this->path; 02248 $this->digest_uri = $this->uri; 02249 02250 // build headers 02251 if (!isset($u['port'])) { 02252 $this->setHeader('Host', $this->host); 02253 } else { 02254 $this->setHeader('Host', $this->host.':'.$this->port); 02255 } 02256 02257 if (isset($u['user']) && $u['user'] != '') { 02258 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); 02259 } 02260 } 02261 02268 function io_method() { 02269 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) 02270 return 'curl'; 02271 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) 02272 return 'socket'; 02273 return 'unknown'; 02274 } 02275 02284 function connect($connection_timeout=0,$response_timeout=30){ 02285 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like 02286 // "regular" socket. 02287 // TODO: disabled for now because OpenSSL must be *compiled* in (not just 02288 // loaded), and until PHP5 stream_get_wrappers is not available. 02289 // if ($this->scheme == 'https') { 02290 // if (version_compare(phpversion(), '4.3.0') >= 0) { 02291 // if (extension_loaded('openssl')) { 02292 // $this->scheme = 'ssl'; 02293 // $this->debug('Using SSL over OpenSSL'); 02294 // } 02295 // } 02296 // } 02297 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); 02298 if ($this->io_method() == 'socket') { 02299 if (!is_array($this->proxy)) { 02300 $host = $this->host; 02301 $port = $this->port; 02302 } else { 02303 $host = $this->proxy['host']; 02304 $port = $this->proxy['port']; 02305 } 02306 02307 // use persistent connection 02308 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ 02309 if (!feof($this->fp)) { 02310 $this->debug('Re-use persistent connection'); 02311 return true; 02312 } 02313 fclose($this->fp); 02314 $this->debug('Closed persistent connection at EOF'); 02315 } 02316 02317 // munge host if using OpenSSL 02318 if ($this->scheme == 'ssl') { 02319 $host = 'ssl://' . $host; 02320 } 02321 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); 02322 02323 // open socket 02324 if($connection_timeout > 0){ 02325 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); 02326 } else { 02327 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); 02328 } 02329 02330 // test pointer 02331 if(!$this->fp) { 02332 $msg = 'Couldn\'t open socket connection to server ' . $this->url; 02333 if ($this->errno) { 02334 $msg .= ', Error ('.$this->errno.'): '.$this->error_str; 02335 } else { 02336 $msg .= ' prior to connect(). This is often a problem looking up the host name.'; 02337 } 02338 $this->debug($msg); 02339 $this->setError($msg); 02340 return false; 02341 } 02342 02343 // set response timeout 02344 $this->debug('set response timeout to ' . $response_timeout); 02345 socket_set_timeout( $this->fp, $response_timeout); 02346 02347 $this->debug('socket connected'); 02348 return true; 02349 } else if ($this->io_method() == 'curl') { 02350 if (!extension_loaded('curl')) { 02351 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); 02352 $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to included cURL.'); 02353 return false; 02354 } 02355 // Avoid warnings when PHP does not have these options 02356 if (defined('CURLOPT_CONNECTIONTIMEOUT')) 02357 $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; 02358 else 02359 $CURLOPT_CONNECTIONTIMEOUT = 78; 02360 if (defined('CURLOPT_HTTPAUTH')) 02361 $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; 02362 else 02363 $CURLOPT_HTTPAUTH = 107; 02364 if (defined('CURLOPT_PROXYAUTH')) 02365 $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; 02366 else 02367 $CURLOPT_PROXYAUTH = 111; 02368 if (defined('CURLAUTH_BASIC')) 02369 $CURLAUTH_BASIC = CURLAUTH_BASIC; 02370 else 02371 $CURLAUTH_BASIC = 1; 02372 if (defined('CURLAUTH_DIGEST')) 02373 $CURLAUTH_DIGEST = CURLAUTH_DIGEST; 02374 else 02375 $CURLAUTH_DIGEST = 2; 02376 if (defined('CURLAUTH_NTLM')) 02377 $CURLAUTH_NTLM = CURLAUTH_NTLM; 02378 else 02379 $CURLAUTH_NTLM = 8; 02380 02381 $this->debug('connect using cURL'); 02382 // init CURL 02383 $this->ch = curl_init(); 02384 // set url 02385 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; 02386 // add path 02387 $hostURL .= $this->path; 02388 $this->setCurlOption(CURLOPT_URL, $hostURL); 02389 // follow location headers (re-directs) 02390 if (ini_get('safe_mode') || ini_get('open_basedir')) { 02391 $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); 02392 $this->debug('safe_mode = '); 02393 $this->appendDebug($this->varDump(ini_get('safe_mode'))); 02394 $this->debug('open_basedir = '); 02395 $this->appendDebug($this->varDump(ini_get('open_basedir'))); 02396 } else { 02397 $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); 02398 } 02399 // ask for headers in the response output 02400 $this->setCurlOption(CURLOPT_HEADER, 1); 02401 // ask for the response output as the return value 02402 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); 02403 // encode 02404 // We manage this ourselves through headers and encoding 02405 // if(function_exists('gzuncompress')){ 02406 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); 02407 // } 02408 // persistent connection 02409 if ($this->persistentConnection) { 02410 // I believe the following comment is now bogus, having applied to 02411 // the code when it used CURLOPT_CUSTOMREQUEST to send the request. 02412 // The way we send data, we cannot use persistent connections, since 02413 // there will be some "junk" at the end of our request. 02414 //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); 02415 $this->persistentConnection = false; 02416 $this->setHeader('Connection', 'close'); 02417 } 02418 // set timeouts 02419 if ($connection_timeout != 0) { 02420 $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); 02421 } 02422 if ($response_timeout != 0) { 02423 $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); 02424 } 02425 02426 if ($this->scheme == 'https') { 02427 $this->debug('set cURL SSL verify options'); 02428 // recent versions of cURL turn on peer/host checking by default, 02429 // while PHP binaries are not compiled with a default location for the 02430 // CA cert bundle, so disable peer/host checking. 02431 //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); 02432 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); 02433 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); 02434 02435 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) 02436 if ($this->authtype == 'certificate') { 02437 $this->debug('set cURL certificate options'); 02438 if (isset($this->certRequest['cainfofile'])) { 02439 $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); 02440 } 02441 if (isset($this->certRequest['verifypeer'])) { 02442 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); 02443 } else { 02444 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); 02445 } 02446 if (isset($this->certRequest['verifyhost'])) { 02447 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); 02448 } else { 02449 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); 02450 } 02451 if (isset($this->certRequest['sslcertfile'])) { 02452 $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); 02453 } 02454 if (isset($this->certRequest['sslkeyfile'])) { 02455 $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); 02456 } 02457 if (isset($this->certRequest['passphrase'])) { 02458 $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); 02459 } 02460 if (isset($this->certRequest['certpassword'])) { 02461 $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); 02462 } 02463 } 02464 } 02465 if ($this->authtype && ($this->authtype != 'certificate')) { 02466 if ($this->username) { 02467 $this->debug('set cURL username/password'); 02468 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); 02469 } 02470 if ($this->authtype == 'basic') { 02471 $this->debug('set cURL for Basic authentication'); 02472 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); 02473 } 02474 if ($this->authtype == 'digest') { 02475 $this->debug('set cURL for digest authentication'); 02476 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); 02477 } 02478 if ($this->authtype == 'ntlm') { 02479 $this->debug('set cURL for NTLM authentication'); 02480 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); 02481 } 02482 } 02483 if (is_array($this->proxy)) { 02484 $this->debug('set cURL proxy options'); 02485 if ($this->proxy['port'] != '') { 02486 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); 02487 } else { 02488 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); 02489 } 02490 if ($this->proxy['username'] || $this->proxy['password']) { 02491 $this->debug('set cURL proxy authentication options'); 02492 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); 02493 if ($this->proxy['authtype'] == 'basic') { 02494 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); 02495 } 02496 if ($this->proxy['authtype'] == 'ntlm') { 02497 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); 02498 } 02499 } 02500 } 02501 $this->debug('cURL connection set up'); 02502 return true; 02503 } else { 02504 $this->setError('Unknown scheme ' . $this->scheme); 02505 $this->debug('Unknown scheme ' . $this->scheme); 02506 return false; 02507 } 02508 } 02509 02520 function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { 02521 02522 $this->debug('entered send() with data of length: '.strlen($data)); 02523 02524 $this->tryagain = true; 02525 $tries = 0; 02526 while ($this->tryagain) { 02527 $this->tryagain = false; 02528 if ($tries++ < 2) { 02529 // make connnection 02530 if (!$this->connect($timeout, $response_timeout)){ 02531 return false; 02532 } 02533 02534 // send request 02535 if (!$this->sendRequest($data, $cookies)){ 02536 return false; 02537 } 02538 02539 // get response 02540 $respdata = $this->getResponse(); 02541 } else { 02542 $this->setError("Too many tries to get an OK response ($this->response_status_line)"); 02543 } 02544 } 02545 $this->debug('end of send()'); 02546 return $respdata; 02547 } 02548 02549 02561 function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { 02562 return $this->send($data, $timeout, $response_timeout, $cookies); 02563 } 02564 02575 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { 02576 $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); 02577 $this->appendDebug($this->varDump($digestRequest)); 02578 $this->debug("certRequest="); 02579 $this->appendDebug($this->varDump($certRequest)); 02580 // cf. RFC 2617 02581 if ($authtype == 'basic') { 02582 $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); 02583 } elseif ($authtype == 'digest') { 02584 if (isset($digestRequest['nonce'])) { 02585 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; 02586 02587 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) 02588 02589 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd 02590 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; 02591 02592 // H(A1) = MD5(A1) 02593 $HA1 = md5($A1); 02594 02595 // A2 = Method ":" digest-uri-value 02596 $A2 = $this->request_method . ':' . $this->digest_uri; 02597 02598 // H(A2) 02599 $HA2 = md5($A2); 02600 02601 // KD(secret, data) = H(concat(secret, ":", data)) 02602 // if qop == auth: 02603 // request-digest = <"> < KD ( H(A1), unq(nonce-value) 02604 // ":" nc-value 02605 // ":" unq(cnonce-value) 02606 // ":" unq(qop-value) 02607 // ":" H(A2) 02608 // ) <"> 02609 // if qop is missing, 02610 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> 02611 02612 $unhashedDigest = ''; 02613 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; 02614 $cnonce = $nonce; 02615 if ($digestRequest['qop'] != '') { 02616 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; 02617 } else { 02618 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; 02619 } 02620 02621 $hashedDigest = md5($unhashedDigest); 02622 02623 $opaque = ''; 02624 if (isset($digestRequest['opaque'])) { 02625 $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; 02626 } 02627 02628 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); 02629 } 02630 } elseif ($authtype == 'certificate') { 02631 $this->certRequest = $certRequest; 02632 $this->debug('Authorization header not set for certificate'); 02633 } elseif ($authtype == 'ntlm') { 02634 // do nothing 02635 $this->debug('Authorization header not set for ntlm'); 02636 } 02637 $this->username = $username; 02638 $this->password = $password; 02639 $this->authtype = $authtype; 02640 $this->digestRequest = $digestRequest; 02641 } 02642 02649 function setSOAPAction($soapaction) { 02650 $this->setHeader('SOAPAction', '"' . $soapaction . '"'); 02651 } 02652 02659 function setEncoding($enc='gzip, deflate') { 02660 if (function_exists('gzdeflate')) { 02661 $this->protocol_version = '1.1'; 02662 $this->setHeader('Accept-Encoding', $enc); 02663 if (!isset($this->outgoing_headers['Connection'])) { 02664 $this->setHeader('Connection', 'close'); 02665 $this->persistentConnection = false; 02666 } 02667 set_magic_quotes_runtime(0); 02668 // deprecated 02669 $this->encoding = $enc; 02670 } 02671 } 02672 02683 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { 02684 if ($proxyhost) { 02685 $this->proxy = array( 02686 'host' => $proxyhost, 02687 'port' => $proxyport, 02688 'username' => $proxyusername, 02689 'password' => $proxypassword, 02690 'authtype' => $proxyauthtype 02691 ); 02692 if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { 02693 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); 02694 } 02695 } else { 02696 $this->debug('remove proxy'); 02697 $proxy = null; 02698 unsetHeader('Proxy-Authorization'); 02699 } 02700 } 02701 02702 02711 function isSkippableCurlHeader(&$data) { 02712 $skipHeaders = array( 'HTTP/1.1 100', 02713 'HTTP/1.0 301', 02714 'HTTP/1.1 301', 02715 'HTTP/1.0 302', 02716 'HTTP/1.1 302', 02717 'HTTP/1.0 401', 02718 'HTTP/1.1 401', 02719 'HTTP/1.0 200 Connection established'); 02720 foreach ($skipHeaders as $hd) { 02721 $prefix = substr($data, 0, strlen($hd)); 02722 if ($prefix == $hd) return true; 02723 } 02724 02725 return false; 02726 } 02727 02738 function decodeChunked($buffer, $lb){ 02739 // length := 0 02740 $length = 0; 02741 $new = ''; 02742 02743 // read chunk-size, chunk-extension (if any) and CRLF 02744 // get the position of the linebreak 02745 $chunkend = strpos($buffer, $lb); 02746 if ($chunkend == FALSE) { 02747 $this->debug('no linebreak found in decodeChunked'); 02748 return $new; 02749 } 02750 $temp = substr($buffer,0,$chunkend); 02751 $chunk_size = hexdec( trim($temp) ); 02752 $chunkstart = $chunkend + strlen($lb); 02753 // while (chunk-size > 0) { 02754 while ($chunk_size > 0) { 02755 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); 02756 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); 02757 02758 // Just in case we got a broken connection 02759 if ($chunkend == FALSE) { 02760 $chunk = substr($buffer,$chunkstart); 02761 // append chunk-data to entity-body 02762 $new .= $chunk; 02763 $length += strlen($chunk); 02764 break; 02765 } 02766 02767 // read chunk-data and CRLF 02768 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02769 // append chunk-data to entity-body 02770 $new .= $chunk; 02771 // length := length + chunk-size 02772 $length += strlen($chunk); 02773 // read chunk-size and CRLF 02774 $chunkstart = $chunkend + strlen($lb); 02775 02776 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); 02777 if ($chunkend == FALSE) { 02778 break; //Just in case we got a broken connection 02779 } 02780 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02781 $chunk_size = hexdec( trim($temp) ); 02782 $chunkstart = $chunkend; 02783 } 02784 return $new; 02785 } 02786 02795 function buildPayload($data, $cookie_str = '') { 02796 // Note: for cURL connections, $this->outgoing_payload is ignored, 02797 // as is the Content-Length header, but these are still created as 02798 // debugging guides. 02799 02800 // add content-length header 02801 $this->setHeader('Content-Length', strlen($data)); 02802 02803 // start building outgoing payload: 02804 if ($this->proxy) { 02805 $uri = $this->url; 02806 } else { 02807 $uri = $this->uri; 02808 } 02809 $req = "$this->request_method $uri HTTP/$this->protocol_version"; 02810 $this->debug("HTTP request: $req"); 02811 $this->outgoing_payload = "$req\r\n"; 02812 02813 // loop thru headers, serializing 02814 foreach($this->outgoing_headers as $k => $v){ 02815 $hdr = $k.': '.$v; 02816 $this->debug("HTTP header: $hdr"); 02817 $this->outgoing_payload .= "$hdr\r\n"; 02818 } 02819 02820 // add any cookies 02821 if ($cookie_str != '') { 02822 $hdr = 'Cookie: '.$cookie_str; 02823 $this->debug("HTTP header: $hdr"); 02824 $this->outgoing_payload .= "$hdr\r\n"; 02825 } 02826 02827 // header/body separator 02828 $this->outgoing_payload .= "\r\n"; 02829 02830 // add data 02831 $this->outgoing_payload .= $data; 02832 } 02833 02842 function sendRequest($data, $cookies = NULL) { 02843 // build cookie string 02844 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); 02845 02846 // build payload 02847 $this->buildPayload($data, $cookie_str); 02848 02849 if ($this->io_method() == 'socket') { 02850 // send payload 02851 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { 02852 $this->setError('couldn\'t write message data to socket'); 02853 $this->debug('couldn\'t write message data to socket'); 02854 return false; 02855 } 02856 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); 02857 return true; 02858 } else if ($this->io_method() == 'curl') { 02859 // set payload 02860 // cURL does say this should only be the verb, and in fact it 02861 // turns out that the URI and HTTP version are appended to this, which 02862 // some servers refuse to work with (so we no longer use this method!) 02863 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); 02864 $curl_headers = array(); 02865 foreach($this->outgoing_headers as $k => $v){ 02866 if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { 02867 $this->debug("Skip cURL header $k: $v"); 02868 } else { 02869 $curl_headers[] = "$k: $v"; 02870 } 02871 } 02872 if ($cookie_str != '') { 02873 $curl_headers[] = 'Cookie: ' . $cookie_str; 02874 } 02875 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); 02876 $this->debug('set cURL HTTP headers'); 02877 if ($this->request_method == "POST") { 02878 $this->setCurlOption(CURLOPT_POST, 1); 02879 $this->setCurlOption(CURLOPT_POSTFIELDS, $data); 02880 $this->debug('set cURL POST data'); 02881 } else { 02882 } 02883 // insert custom user-set cURL options 02884 foreach ($this->ch_options as $key => $val) { 02885 $this->setCurlOption($key, $val); 02886 } 02887 02888 $this->debug('set cURL payload'); 02889 return true; 02890 } 02891 } 02892 02899 function getResponse(){ 02900 $this->incoming_payload = ''; 02901 02902 if ($this->io_method() == 'socket') { 02903 // loop until headers have been retrieved 02904 $data = ''; 02905 while (!isset($lb)){ 02906 02907 // We might EOF during header read. 02908 if(feof($this->fp)) { 02909 $this->incoming_payload = $data; 02910 $this->debug('found no headers before EOF after length ' . strlen($data)); 02911 $this->debug("received before EOF:\n" . $data); 02912 $this->setError('server failed to send headers'); 02913 return false; 02914 } 02915 02916 $tmp = fgets($this->fp, 256); 02917 $tmplen = strlen($tmp); 02918 $this->debug("read line of $tmplen bytes: " . trim($tmp)); 02919 02920 if ($tmplen == 0) { 02921 $this->incoming_payload = $data; 02922 $this->debug('socket read of headers timed out after length ' . strlen($data)); 02923 $this->debug("read before timeout: " . $data); 02924 $this->setError('socket read of headers timed out'); 02925 return false; 02926 } 02927 02928 $data .= $tmp; 02929 $pos = strpos($data,"\r\n\r\n"); 02930 if($pos > 1){ 02931 $lb = "\r\n"; 02932 } else { 02933 $pos = strpos($data,"\n\n"); 02934 if($pos > 1){ 02935 $lb = "\n"; 02936 } 02937 } 02938 // remove 100 headers 02939 if (isset($lb) && ereg('^HTTP/1.1 100',$data)) { 02940 unset($lb); 02941 $data = ''; 02942 }// 02943 } 02944 // store header data 02945 $this->incoming_payload .= $data; 02946 $this->debug('found end of headers after length ' . strlen($data)); 02947 // process headers 02948 $header_data = trim(substr($data,0,$pos)); 02949 $header_array = explode($lb,$header_data); 02950 $this->incoming_headers = array(); 02951 $this->incoming_cookies = array(); 02952 foreach($header_array as $header_line){ 02953 $arr = explode(':',$header_line, 2); 02954 if(count($arr) > 1){ 02955 $header_name = strtolower(trim($arr[0])); 02956 $this->incoming_headers[$header_name] = trim($arr[1]); 02957 if ($header_name == 'set-cookie') { 02958 // TODO: allow multiple cookies from parseCookie 02959 $cookie = $this->parseCookie(trim($arr[1])); 02960 if ($cookie) { 02961 $this->incoming_cookies[] = $cookie; 02962 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 02963 } else { 02964 $this->debug('did not find cookie in ' . trim($arr[1])); 02965 } 02966 } 02967 } else if (isset($header_name)) { 02968 // append continuation line to previous header 02969 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 02970 } 02971 } 02972 02973 // loop until msg has been received 02974 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { 02975 $content_length = 2147483647; // ignore any content-length header 02976 $chunked = true; 02977 $this->debug("want to read chunked content"); 02978 } elseif (isset($this->incoming_headers['content-length'])) { 02979 $content_length = $this->incoming_headers['content-length']; 02980 $chunked = false; 02981 $this->debug("want to read content of length $content_length"); 02982 } else { 02983 $content_length = 2147483647; 02984 $chunked = false; 02985 $this->debug("want to read content to EOF"); 02986 } 02987 $data = ''; 02988 do { 02989 if ($chunked) { 02990 $tmp = fgets($this->fp, 256); 02991 $tmplen = strlen($tmp); 02992 $this->debug("read chunk line of $tmplen bytes"); 02993 if ($tmplen == 0) { 02994 $this->incoming_payload = $data; 02995 $this->debug('socket read of chunk length timed out after length ' . strlen($data)); 02996 $this->debug("read before timeout:\n" . $data); 02997 $this->setError('socket read of chunk length timed out'); 02998 return false; 02999 } 03000 $content_length = hexdec(trim($tmp)); 03001 $this->debug("chunk length $content_length"); 03002 } 03003 $strlen = 0; 03004 while (($strlen < $content_length) && (!feof($this->fp))) { 03005 $readlen = min(8192, $content_length - $strlen); 03006 $tmp = fread($this->fp, $readlen); 03007 $tmplen = strlen($tmp); 03008 $this->debug("read buffer of $tmplen bytes"); 03009 if (($tmplen == 0) && (!feof($this->fp))) { 03010 $this->incoming_payload = $data; 03011 $this->debug('socket read of body timed out after length ' . strlen($data)); 03012 $this->debug("read before timeout:\n" . $data); 03013 $this->setError('socket read of body timed out'); 03014 return false; 03015 } 03016 $strlen += $tmplen; 03017 $data .= $tmp; 03018 } 03019 if ($chunked && ($content_length > 0)) { 03020 $tmp = fgets($this->fp, 256); 03021 $tmplen = strlen($tmp); 03022 $this->debug("read chunk terminator of $tmplen bytes"); 03023 if ($tmplen == 0) { 03024 $this->incoming_payload = $data; 03025 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); 03026 $this->debug("read before timeout:\n" . $data); 03027 $this->setError('socket read of chunk terminator timed out'); 03028 return false; 03029 } 03030 } 03031 } while ($chunked && ($content_length > 0) && (!feof($this->fp))); 03032 if (feof($this->fp)) { 03033 $this->debug('read to EOF'); 03034 } 03035 $this->debug('read body of length ' . strlen($data)); 03036 $this->incoming_payload .= $data; 03037 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); 03038 03039 // close filepointer 03040 if( 03041 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 03042 (! $this->persistentConnection) || feof($this->fp)){ 03043 fclose($this->fp); 03044 $this->fp = false; 03045 $this->debug('closed socket'); 03046 } 03047 03048 // connection was closed unexpectedly 03049 if($this->incoming_payload == ''){ 03050 $this->setError('no response from server'); 03051 return false; 03052 } 03053 03054 // decode transfer-encoding 03055 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ 03056 // if(!$data = $this->decodeChunked($data, $lb)){ 03057 // $this->setError('Decoding of chunked data failed'); 03058 // return false; 03059 // } 03060 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; 03061 // set decoded payload 03062 // $this->incoming_payload = $header_data.$lb.$lb.$data; 03063 // } 03064 03065 } else if ($this->io_method() == 'curl') { 03066 // send and receive 03067 $this->debug('send and receive with cURL'); 03068 $this->incoming_payload = curl_exec($this->ch); 03069 $data = $this->incoming_payload; 03070 03071 $cErr = curl_error($this->ch); 03072 if ($cErr != '') { 03073 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>'; 03074 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE 03075 foreach(curl_getinfo($this->ch) as $k => $v){ 03076 $err .= "$k: $v<br>"; 03077 } 03078 $this->debug($err); 03079 $this->setError($err); 03080 curl_close($this->ch); 03081 return false; 03082 } else { 03083 //echo '<pre>'; 03084 //var_dump(curl_getinfo($this->ch)); 03085 //echo '</pre>'; 03086 } 03087 // close curl 03088 $this->debug('No cURL error, closing cURL'); 03089 curl_close($this->ch); 03090 03091 // try removing skippable headers 03092 $savedata = $data; 03093 while ($this->isSkippableCurlHeader($data)) { 03094 $this->debug("Found HTTP header to skip"); 03095 if ($pos = strpos($data,"\r\n\r\n")) { 03096 $data = ltrim(substr($data,$pos)); 03097 } elseif($pos = strpos($data,"\n\n") ) { 03098 $data = ltrim(substr($data,$pos)); 03099 } 03100 } 03101 03102 if ($data == '') { 03103 // have nothing left; just remove 100 header(s) 03104 $data = $savedata; 03105 while (ereg('^HTTP/1.1 100',$data)) { 03106 if ($pos = strpos($data,"\r\n\r\n")) { 03107 $data = ltrim(substr($data,$pos)); 03108 } elseif($pos = strpos($data,"\n\n") ) { 03109 $data = ltrim(substr($data,$pos)); 03110 } 03111 } 03112 } 03113 03114 // separate content from HTTP headers 03115 if ($pos = strpos($data,"\r\n\r\n")) { 03116 $lb = "\r\n"; 03117 } elseif( $pos = strpos($data,"\n\n")) { 03118 $lb = "\n"; 03119 } else { 03120 $this->debug('no proper separation of headers and document'); 03121 $this->setError('no proper separation of headers and document'); 03122 return false; 03123 } 03124 $header_data = trim(substr($data,0,$pos)); 03125 $header_array = explode($lb,$header_data); 03126 $data = ltrim(substr($data,$pos)); 03127 $this->debug('found proper separation of headers and document'); 03128 $this->debug('cleaned data, stringlen: '.strlen($data)); 03129 // clean headers 03130 foreach ($header_array as $header_line) { 03131 $arr = explode(':',$header_line,2); 03132 if(count($arr) > 1){ 03133 $header_name = strtolower(trim($arr[0])); 03134 $this->incoming_headers[$header_name] = trim($arr[1]); 03135 if ($header_name == 'set-cookie') { 03136 // TODO: allow multiple cookies from parseCookie 03137 $cookie = $this->parseCookie(trim($arr[1])); 03138 if ($cookie) { 03139 $this->incoming_cookies[] = $cookie; 03140 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 03141 } else { 03142 $this->debug('did not find cookie in ' . trim($arr[1])); 03143 } 03144 } 03145 } else if (isset($header_name)) { 03146 // append continuation line to previous header 03147 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 03148 } 03149 } 03150 } 03151 03152 $this->response_status_line = $header_array[0]; 03153 $arr = explode(' ', $this->response_status_line, 3); 03154 $http_version = $arr[0]; 03155 $http_status = intval($arr[1]); 03156 $http_reason = count($arr) > 2 ? $arr[2] : ''; 03157 03158 // see if we need to resend the request with http digest authentication 03159 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { 03160 $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); 03161 $this->setURL($this->incoming_headers['location']); 03162 $this->tryagain = true; 03163 return false; 03164 } 03165 03166 // see if we need to resend the request with http digest authentication 03167 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { 03168 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); 03169 if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { 03170 $this->debug('Server wants digest authentication'); 03171 // remove "Digest " from our elements 03172 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); 03173 03174 // parse elements into array 03175 $digestElements = explode(',', $digestString); 03176 foreach ($digestElements as $val) { 03177 $tempElement = explode('=', trim($val), 2); 03178 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); 03179 } 03180 03181 // should have (at least) qop, realm, nonce 03182 if (isset($digestRequest['nonce'])) { 03183 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); 03184 $this->tryagain = true; 03185 return false; 03186 } 03187 } 03188 $this->debug('HTTP authentication failed'); 03189 $this->setError('HTTP authentication failed'); 03190 return false; 03191 } 03192 03193 if ( 03194 ($http_status >= 300 && $http_status <= 307) || 03195 ($http_status >= 400 && $http_status <= 417) || 03196 ($http_status >= 501 && $http_status <= 505) 03197 ) { 03198 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); 03199 return false; 03200 } 03201 03202 // decode content-encoding 03203 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ 03204 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ 03205 // if decoding works, use it. else assume data wasn't gzencoded 03206 if(function_exists('gzinflate')){ 03207 //$timer->setMarker('starting decoding of gzip/deflated content'); 03208 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) 03209 // this means there are no Zlib headers, although there should be 03210 $this->debug('The gzinflate function exists'); 03211 $datalen = strlen($data); 03212 if ($this->incoming_headers['content-encoding'] == 'deflate') { 03213 if ($degzdata = @gzinflate($data)) { 03214 $data = $degzdata; 03215 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); 03216 if (strlen($data) < $datalen) { 03217 // test for the case that the payload has been compressed twice 03218 $this->debug('The inflated payload is smaller than the gzipped one; try again'); 03219 if ($degzdata = @gzinflate($data)) { 03220 $data = $degzdata; 03221 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); 03222 } 03223 } 03224 } else { 03225 $this->debug('Error using gzinflate to inflate the payload'); 03226 $this->setError('Error using gzinflate to inflate the payload'); 03227 } 03228 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { 03229 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best 03230 $data = $degzdata; 03231 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); 03232 if (strlen($data) < $datalen) { 03233 // test for the case that the payload has been compressed twice 03234 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); 03235 if ($degzdata = @gzinflate(substr($data, 10))) { 03236 $data = $degzdata; 03237 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); 03238 } 03239 } 03240 } else { 03241 $this->debug('Error using gzinflate to un-gzip the payload'); 03242 $this->setError('Error using gzinflate to un-gzip the payload'); 03243 } 03244 } 03245 //$timer->setMarker('finished decoding of gzip/deflated content'); 03246 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; 03247 // set decoded payload 03248 $this->incoming_payload = $header_data.$lb.$lb.$data; 03249 } else { 03250 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 03251 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 03252 } 03253 } else { 03254 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 03255 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 03256 } 03257 } else { 03258 $this->debug('No Content-Encoding header'); 03259 } 03260 03261 if(strlen($data) == 0){ 03262 $this->debug('no data after headers!'); 03263 $this->setError('no data present after HTTP headers'); 03264 return false; 03265 } 03266 03267 return $data; 03268 } 03269 03277 function setContentType($type, $charset = false) { 03278 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); 03279 } 03280 03287 function usePersistentConnection(){ 03288 if (isset($this->outgoing_headers['Accept-Encoding'])) { 03289 return false; 03290 } 03291 $this->protocol_version = '1.1'; 03292 $this->persistentConnection = true; 03293 $this->setHeader('Connection', 'Keep-Alive'); 03294 return true; 03295 } 03296 03304 /* 03305 * TODO: allow a Set-Cookie string to be parsed into multiple cookies 03306 */ 03307 function parseCookie($cookie_str) { 03308 $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; 03309 $data = split(';', $cookie_str); 03310 $value_str = $data[0]; 03311 03312 $cookie_param = 'domain='; 03313 $start = strpos($cookie_str, $cookie_param); 03314 if ($start > 0) { 03315 $domain = substr($cookie_str, $start + strlen($cookie_param)); 03316 $domain = substr($domain, 0, strpos($domain, ';')); 03317 } else { 03318 $domain = ''; 03319 } 03320 03321 $cookie_param = 'expires='; 03322 $start = strpos($cookie_str, $cookie_param); 03323 if ($start > 0) { 03324 $expires = substr($cookie_str, $start + strlen($cookie_param)); 03325 $expires = substr($expires, 0, strpos($expires, ';')); 03326 } else { 03327 $expires = ''; 03328 } 03329 03330 $cookie_param = 'path='; 03331 $start = strpos($cookie_str, $cookie_param); 03332 if ( $start > 0 ) { 03333 $path = substr($cookie_str, $start + strlen($cookie_param)); 03334 $path = substr($path, 0, strpos($path, ';')); 03335 } else { 03336 $path = '/'; 03337 } 03338 03339 $cookie_param = ';secure;'; 03340 if (strpos($cookie_str, $cookie_param) !== FALSE) { 03341 $secure = true; 03342 } else { 03343 $secure = false; 03344 } 03345 03346 $sep_pos = strpos($value_str, '='); 03347 03348 if ($sep_pos) { 03349 $name = substr($value_str, 0, $sep_pos); 03350 $value = substr($value_str, $sep_pos + 1); 03351 $cookie= array( 'name' => $name, 03352 'value' => $value, 03353 'domain' => $domain, 03354 'path' => $path, 03355 'expires' => $expires, 03356 'secure' => $secure 03357 ); 03358 return $cookie; 03359 } 03360 return false; 03361 } 03362 03371 function getCookiesForRequest($cookies, $secure=false) { 03372 $cookie_str = ''; 03373 if ((! is_null($cookies)) && (is_array($cookies))) { 03374 foreach ($cookies as $cookie) { 03375 if (! is_array($cookie)) { 03376 continue; 03377 } 03378 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); 03379 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 03380 if (strtotime($cookie['expires']) <= time()) { 03381 $this->debug('cookie has expired'); 03382 continue; 03383 } 03384 } 03385 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { 03386 $domain = preg_quote($cookie['domain']); 03387 if (! preg_match("'.*$domain$'i", $this->host)) { 03388 $this->debug('cookie has different domain'); 03389 continue; 03390 } 03391 } 03392 if ((isset($cookie['path'])) && (! empty($cookie['path']))) { 03393 $path = preg_quote($cookie['path']); 03394 if (! preg_match("'^$path.*'i", $this->path)) { 03395 $this->debug('cookie is for a different path'); 03396 continue; 03397 } 03398 } 03399 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { 03400 $this->debug('cookie is secure, transport is not'); 03401 continue; 03402 } 03403 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; 03404 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); 03405 } 03406 } 03407 return $cookie_str; 03408 } 03409 } 03410 03411 ?><?php 03412 03413 03414 03425 class nusoap_server extends nusoap_base { 03431 var $headers = array(); 03437 var $request = ''; 03443 var $requestHeaders = ''; 03449 var $requestHeader = NULL; 03455 var $document = ''; 03461 var $requestSOAP = ''; 03467 var $methodURI = ''; 03473 var $methodname = ''; 03479 var $methodparams = array(); 03485 var $SOAPAction = ''; 03491 var $xml_encoding = ''; 03497 var $decode_utf8 = true; 03498 03504 var $outgoing_headers = array(); 03510 var $response = ''; 03516 var $responseHeaders = ''; 03522 var $responseSOAP = ''; 03528 var $methodreturn = false; 03534 var $methodreturnisliteralxml = false; 03540 var $fault = false; 03546 var $result = 'successful'; 03547 03554 var $operations = array(); 03560 var $wsdl = false; 03566 var $externalWSDLURL = false; 03572 var $debug_flag = false; 03573 03574 03582 function nusoap_server($wsdl=false){ 03583 parent::nusoap_base(); 03584 // turn on debugging? 03585 global $debug; 03586 global $HTTP_SERVER_VARS; 03587 03588 if (isset($_SERVER)) { 03589 $this->debug("_SERVER is defined:"); 03590 $this->appendDebug($this->varDump($_SERVER)); 03591 } elseif (isset($HTTP_SERVER_VARS)) { 03592 $this->debug("HTTP_SERVER_VARS is defined:"); 03593 $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); 03594 } else { 03595 $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); 03596 } 03597 03598 if (isset($debug)) { 03599 $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); 03600 $this->debug_flag = $debug; 03601 } elseif (isset($_SERVER['QUERY_STRING'])) { 03602 $qs = explode('&', $_SERVER['QUERY_STRING']); 03603 foreach ($qs as $v) { 03604 if (substr($v, 0, 6) == 'debug=') { 03605 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); 03606 $this->debug_flag = substr($v, 6); 03607 } 03608 } 03609 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 03610 $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); 03611 foreach ($qs as $v) { 03612 if (substr($v, 0, 6) == 'debug=') { 03613 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); 03614 $this->debug_flag = substr($v, 6); 03615 } 03616 } 03617 } 03618 03619 // wsdl 03620 if($wsdl){ 03621 $this->debug("In nusoap_server, WSDL is specified"); 03622 if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { 03623 $this->wsdl = $wsdl; 03624 $this->externalWSDLURL = $this->wsdl->wsdl; 03625 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); 03626 } else { 03627 $this->debug('Create wsdl from ' . $wsdl); 03628 $this->wsdl = new wsdl($wsdl); 03629 $this->externalWSDLURL = $wsdl; 03630 } 03631 $this->appendDebug($this->wsdl->getDebug()); 03632 $this->wsdl->clearDebug(); 03633 if($err = $this->wsdl->getError()){ 03634 die('WSDL ERROR: '.$err); 03635 } 03636 } 03637 } 03638 03645 function service($data){ 03646 global $HTTP_SERVER_VARS; 03647 03648 if (isset($_SERVER['QUERY_STRING'])) { 03649 $qs = $_SERVER['QUERY_STRING']; 03650 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 03651 $qs = $HTTP_SERVER_VARS['QUERY_STRING']; 03652 } else { 03653 $qs = ''; 03654 } 03655 $this->debug("In service, query string=$qs"); 03656 03657 if (ereg('wsdl', $qs) ){ 03658 $this->debug("In service, this is a request for WSDL"); 03659 if($this->externalWSDLURL){ 03660 if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL 03661 header('Location: '.$this->externalWSDLURL); 03662 } else { // assume file 03663 header("Content-Type: text/xml\r\n"); 03664 $fp = fopen($this->externalWSDLURL, 'r'); 03665 fpassthru($fp); 03666 } 03667 } elseif ($this->wsdl) { 03668 header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); 03669 print $this->wsdl->serialize($this->debug_flag); 03670 if ($this->debug_flag) { 03671 $this->debug('wsdl:'); 03672 $this->appendDebug($this->varDump($this->wsdl)); 03673 print $this->getDebugAsXMLComment(); 03674 } 03675 } else { 03676 header("Content-Type: text/html; charset=ISO-8859-1\r\n"); 03677 print "This service does not provide WSDL"; 03678 } 03679 } elseif ($data == '' && $this->wsdl) { 03680 $this->debug("In service, there is no data, so return Web description"); 03681 print $this->wsdl->webDescription(); 03682 } else { 03683 $this->debug("In service, invoke the request"); 03684 $this->parse_request($data); 03685 if (! $this->fault) { 03686 $this->invoke_method(); 03687 } 03688 if (! $this->fault) { 03689 $this->serialize_return(); 03690 } 03691 $this->send_response(); 03692 } 03693 } 03694 03707 function parse_http_headers() { 03708 global $HTTP_SERVER_VARS; 03709 03710 $this->request = ''; 03711 $this->SOAPAction = ''; 03712 if(function_exists('getallheaders')){ 03713 $this->debug("In parse_http_headers, use getallheaders"); 03714 $headers = getallheaders(); 03715 foreach($headers as $k=>$v){ 03716 $k = strtolower($k); 03717 $this->headers[$k] = $v; 03718 $this->request .= "$k: $v\r\n"; 03719 $this->debug("$k: $v"); 03720 } 03721 // get SOAPAction header 03722 if(isset($this->headers['soapaction'])){ 03723 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); 03724 } 03725 // get the character encoding of the incoming request 03726 if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ 03727 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); 03728 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 03729 $this->xml_encoding = strtoupper($enc); 03730 } else { 03731 $this->xml_encoding = 'US-ASCII'; 03732 } 03733 } else { 03734 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03735 $this->xml_encoding = 'ISO-8859-1'; 03736 } 03737 } elseif(isset($_SERVER) && is_array($_SERVER)){ 03738 $this->debug("In parse_http_headers, use _SERVER"); 03739 foreach ($_SERVER as $k => $v) { 03740 if (substr($k, 0, 5) == 'HTTP_') { 03741 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); 03742 } else { 03743 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); 03744 } 03745 if ($k == 'soapaction') { 03746 // get SOAPAction header 03747 $k = 'SOAPAction'; 03748 $v = str_replace('"', '', $v); 03749 $v = str_replace('\\', '', $v); 03750 $this->SOAPAction = $v; 03751 } else if ($k == 'content-type') { 03752 // get the character encoding of the incoming request 03753 if (strpos($v, '=')) { 03754 $enc = substr(strstr($v, '='), 1); 03755 $enc = str_replace('"', '', $enc); 03756 $enc = str_replace('\\', '', $enc); 03757 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 03758 $this->xml_encoding = strtoupper($enc); 03759 } else { 03760 $this->xml_encoding = 'US-ASCII'; 03761 } 03762 } else { 03763 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03764 $this->xml_encoding = 'ISO-8859-1'; 03765 } 03766 } 03767 $this->headers[$k] = $v; 03768 $this->request .= "$k: $v\r\n"; 03769 $this->debug("$k: $v"); 03770 } 03771 } elseif (is_array($HTTP_SERVER_VARS)) { 03772 $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); 03773 foreach ($HTTP_SERVER_VARS as $k => $v) { 03774 if (substr($k, 0, 5) == 'HTTP_') { 03775 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); 03776 } else { 03777 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); 03778 } 03779 if ($k == 'soapaction') { 03780 // get SOAPAction header 03781 $k = 'SOAPAction'; 03782 $v = str_replace('"', '', $v); 03783 $v = str_replace('\\', '', $v); 03784 $this->SOAPAction = $v; 03785 } else if ($k == 'content-type') { 03786 // get the character encoding of the incoming request 03787 if (strpos($v, '=')) { 03788 $enc = substr(strstr($v, '='), 1); 03789 $enc = str_replace('"', '', $enc); 03790 $enc = str_replace('\\', '', $enc); 03791 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 03792 $this->xml_encoding = strtoupper($enc); 03793 } else { 03794 $this->xml_encoding = 'US-ASCII'; 03795 } 03796 } else { 03797 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03798 $this->xml_encoding = 'ISO-8859-1'; 03799 } 03800 } 03801 $this->headers[$k] = $v; 03802 $this->request .= "$k: $v\r\n"; 03803 $this->debug("$k: $v"); 03804 } 03805 } else { 03806 $this->debug("In parse_http_headers, HTTP headers not accessible"); 03807 $this->setError("HTTP headers not accessible"); 03808 } 03809 } 03810 03833 function parse_request($data='') { 03834 $this->debug('entering parse_request()'); 03835 $this->parse_http_headers(); 03836 $this->debug('got character encoding: '.$this->xml_encoding); 03837 // uncompress if necessary 03838 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { 03839 $this->debug('got content encoding: ' . $this->headers['content-encoding']); 03840 if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { 03841 // if decoding works, use it. else assume data wasn't gzencoded 03842 if (function_exists('gzuncompress')) { 03843 if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { 03844 $data = $degzdata; 03845 } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { 03846 $data = $degzdata; 03847 } else { 03848 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); 03849 return; 03850 } 03851 } else { 03852 $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); 03853 return; 03854 } 03855 } 03856 } 03857 $this->request .= "\r\n".$data; 03858 $data = $this->parseRequest($this->headers, $data); 03859 $this->requestSOAP = $data; 03860 $this->debug('leaving parse_request'); 03861 } 03862 03880 function invoke_method() { 03881 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); 03882 03883 if ($this->wsdl) { 03884 if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { 03885 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); 03886 $this->appendDebug('opData=' . $this->varDump($this->opData)); 03887 } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { 03888 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element 03889 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); 03890 $this->appendDebug('opData=' . $this->varDump($this->opData)); 03891 $this->methodname = $this->opData['name']; 03892 } else { 03893 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); 03894 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); 03895 return; 03896 } 03897 } else { 03898 $this->debug('in invoke_method, no WSDL to validate method'); 03899 } 03900 03901 // if a . is present in $this->methodname, we see if there is a class in scope, 03902 // which could be referred to. We will also distinguish between two deliminators, 03903 // to allow methods to be called a the class or an instance 03904 $class = ''; 03905 $method = ''; 03906 if (strpos($this->methodname, '..') > 0) { 03907 $delim = '..'; 03908 } else if (strpos($this->methodname, '.') > 0) { 03909 $delim = '.'; 03910 } else { 03911 $delim = ''; 03912 } 03913 03914 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && 03915 class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { 03916 // get the class and method name 03917 $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); 03918 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); 03919 $this->debug("in invoke_method, class=$class method=$method delim=$delim"); 03920 } 03921 03922 // does method exist? 03923 if ($class == '') { 03924 if (!function_exists($this->methodname)) { 03925 $this->debug("in invoke_method, function '$this->methodname' not found!"); 03926 $this->result = 'fault: method not found'; 03927 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 03928 return; 03929 } 03930 } else { 03931 $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; 03932 if (!in_array($method_to_compare, get_class_methods($class))) { 03933 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); 03934 $this->result = 'fault: method not found'; 03935 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 03936 return; 03937 } 03938 } 03939 03940 // evaluate message, getting back parameters 03941 // verify that request parameters match the method's signature 03942 if(! $this->verify_method($this->methodname,$this->methodparams)){ 03943 // debug 03944 $this->debug('ERROR: request not verified against method signature'); 03945 $this->result = 'fault: request failed validation against method signature'; 03946 // return fault 03947 $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); 03948 return; 03949 } 03950 03951 // if there are parameters to pass 03952 $this->debug('in invoke_method, params:'); 03953 $this->appendDebug($this->varDump($this->methodparams)); 03954 $this->debug("in invoke_method, calling '$this->methodname'"); 03955 if (!function_exists('call_user_func_array')) { 03956 if ($class == '') { 03957 $this->debug('in invoke_method, calling function using eval()'); 03958 $funcCall = "\$this->methodreturn = $this->methodname("; 03959 } else { 03960 if ($delim == '..') { 03961 $this->debug('in invoke_method, calling class method using eval()'); 03962 $funcCall = "\$this->methodreturn = ".$class."::".$method."("; 03963 } else { 03964 $this->debug('in invoke_method, calling instance method using eval()'); 03965 // generate unique instance name 03966 $instname = "\$inst_".time(); 03967 $funcCall = $instname." = new ".$class."(); "; 03968 $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; 03969 } 03970 } 03971 if ($this->methodparams) { 03972 foreach ($this->methodparams as $param) { 03973 if (is_array($param) || is_object($param)) { 03974 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); 03975 return; 03976 } 03977 $funcCall .= "\"$param\","; 03978 } 03979 $funcCall = substr($funcCall, 0, -1); 03980 } 03981 $funcCall .= ');'; 03982 $this->debug('in invoke_method, function call: '.$funcCall); 03983 @eval($funcCall); 03984 } else { 03985 if ($class == '') { 03986 $this->debug('in invoke_method, calling function using call_user_func_array()'); 03987 $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() 03988 } elseif ($delim == '..') { 03989 $this->debug('in invoke_method, calling class method using call_user_func_array()'); 03990 $call_arg = array ($class, $method); 03991 } else { 03992 $this->debug('in invoke_method, calling instance method using call_user_func_array()'); 03993 $instance = new $class (); 03994 $call_arg = array(&$instance, $method); 03995 } 03996 if (is_array($this->methodparams)) { 03997 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); 03998 } else { 03999 $this->methodreturn = call_user_func_array($call_arg, array()); 04000 } 04001 } 04002 $this->debug('in invoke_method, methodreturn:'); 04003 $this->appendDebug($this->varDump($this->methodreturn)); 04004 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); 04005 } 04006 04018 function serialize_return() { 04019 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); 04020 // if fault 04021 if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { 04022 $this->debug('got a fault object from method'); 04023 $this->fault = $this->methodreturn; 04024 return; 04025 } elseif ($this->methodreturnisliteralxml) { 04026 $return_val = $this->methodreturn; 04027 // returned value(s) 04028 } else { 04029 $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); 04030 $this->debug('serializing return value'); 04031 if($this->wsdl){ 04032 if (sizeof($this->opData['output']['parts']) > 1) { 04033 $this->debug('more than one output part, so use the method return unchanged'); 04034 $opParams = $this->methodreturn; 04035 } elseif (sizeof($this->opData['output']['parts']) == 1) { 04036 $this->debug('exactly one output part, so wrap the method return in a simple array'); 04037 // TODO: verify that it is not already wrapped! 04038 //foreach ($this->opData['output']['parts'] as $name => $type) { 04039 // $this->debug('wrap in element named ' . $name); 04040 //} 04041 $opParams = array($this->methodreturn); 04042 } 04043 $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); 04044 $this->appendDebug($this->wsdl->getDebug()); 04045 $this->wsdl->clearDebug(); 04046 if($errstr = $this->wsdl->getError()){ 04047 $this->debug('got wsdl error: '.$errstr); 04048 $this->fault('SOAP-ENV:Server', 'unable to serialize result'); 04049 return; 04050 } 04051 } else { 04052 if (isset($this->methodreturn)) { 04053 $return_val = $this->serialize_val($this->methodreturn, 'return'); 04054 } else { 04055 $return_val = ''; 04056 $this->debug('in absence of WSDL, assume void return for backward compatibility'); 04057 } 04058 } 04059 } 04060 $this->debug('return value:'); 04061 $this->appendDebug($this->varDump($return_val)); 04062 04063 $this->debug('serializing response'); 04064 if ($this->wsdl) { 04065 $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); 04066 if ($this->opData['style'] == 'rpc') { 04067 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); 04068 if ($this->opData['output']['use'] == 'literal') { 04069 // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 04070 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04071 } else { 04072 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04073 } 04074 } else { 04075 $this->debug('style is not rpc for serialization: assume document'); 04076 $payload = $return_val; 04077 } 04078 } else { 04079 $this->debug('do not have WSDL for serialization: assume rpc/encoded'); 04080 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04081 } 04082 $this->result = 'successful'; 04083 if($this->wsdl){ 04084 //if($this->debug_flag){ 04085 $this->appendDebug($this->wsdl->getDebug()); 04086 // } 04087 if (isset($opData['output']['encodingStyle'])) { 04088 $encodingStyle = $opData['output']['encodingStyle']; 04089 } else { 04090 $encodingStyle = ''; 04091 } 04092 // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. 04093 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); 04094 } else { 04095 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); 04096 } 04097 $this->debug("Leaving serialize_return"); 04098 } 04099 04110 function send_response() { 04111 $this->debug('Enter send_response'); 04112 if ($this->fault) { 04113 $payload = $this->fault->serialize(); 04114 $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; 04115 $this->outgoing_headers[] = "Status: 500 Internal Server Error"; 04116 } else { 04117 $payload = $this->responseSOAP; 04118 // Some combinations of PHP+Web server allow the Status 04119 // to come through as a header. Since OK is the default 04120 // just do nothing. 04121 // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; 04122 // $this->outgoing_headers[] = "Status: 200 OK"; 04123 } 04124 // add debug data if in debug mode 04125 if(isset($this->debug_flag) && $this->debug_flag){ 04126 $payload .= $this->getDebugAsXMLComment(); 04127 } 04128 $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; 04129 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 04130 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; 04131 // Let the Web server decide about this 04132 //$this->outgoing_headers[] = "Connection: Close\r\n"; 04133 $payload = $this->getHTTPBody($payload); 04134 $type = $this->getHTTPContentType(); 04135 $charset = $this->getHTTPContentTypeCharset(); 04136 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); 04137 //begin code to compress payload - by John 04138 // NOTE: there is no way to know whether the Web server will also compress 04139 // this data. 04140 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { 04141 if (strstr($this->headers['accept-encoding'], 'gzip')) { 04142 if (function_exists('gzencode')) { 04143 if (isset($this->debug_flag) && $this->debug_flag) { 04144 $payload .= "<!-- Content being gzipped -->"; 04145 } 04146 $this->outgoing_headers[] = "Content-Encoding: gzip"; 04147 $payload = gzencode($payload); 04148 } else { 04149 if (isset($this->debug_flag) && $this->debug_flag) { 04150 $payload .= "<!-- Content will not be gzipped: no gzencode -->"; 04151 } 04152 } 04153 } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { 04154 // Note: MSIE requires gzdeflate output (no Zlib header and checksum), 04155 // instead of gzcompress output, 04156 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) 04157 if (function_exists('gzdeflate')) { 04158 if (isset($this->debug_flag) && $this->debug_flag) { 04159 $payload .= "<!-- Content being deflated -->"; 04160 } 04161 $this->outgoing_headers[] = "Content-Encoding: deflate"; 04162 $payload = gzdeflate($payload); 04163 } else { 04164 if (isset($this->debug_flag) && $this->debug_flag) { 04165 $payload .= "<!-- Content will not be deflated: no gzcompress -->"; 04166 } 04167 } 04168 } 04169 } 04170 //end code 04171 $this->outgoing_headers[] = "Content-Length: ".strlen($payload); 04172 reset($this->outgoing_headers); 04173 foreach($this->outgoing_headers as $hdr){ 04174 header($hdr, false); 04175 } 04176 print $payload; 04177 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; 04178 } 04179 04189 function verify_method($operation,$request){ 04190 if(isset($this->wsdl) && is_object($this->wsdl)){ 04191 if($this->wsdl->getOperationData($operation)){ 04192 return true; 04193 } 04194 } elseif(isset($this->operations[$operation])){ 04195 return true; 04196 } 04197 return false; 04198 } 04199 04208 function parseRequest($headers, $data) { 04209 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); 04210 if (!strstr($headers['content-type'], 'text/xml')) { 04211 $this->setError('Request not of type text/xml'); 04212 return false; 04213 } 04214 if (strpos($headers['content-type'], '=')) { 04215 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 04216 $this->debug('Got response encoding: ' . $enc); 04217 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 04218 $this->xml_encoding = strtoupper($enc); 04219 } else { 04220 $this->xml_encoding = 'US-ASCII'; 04221 } 04222 } else { 04223 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 04224 $this->xml_encoding = 'ISO-8859-1'; 04225 } 04226 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 04227 // parse response, get soap parser obj 04228 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); 04229 // parser debug 04230 $this->debug("parser debug: \n".$parser->getDebug()); 04231 // if fault occurred during message parsing 04232 if($err = $parser->getError()){ 04233 $this->result = 'fault: error in msg parsing: '.$err; 04234 $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); 04235 // else successfully parsed request into soapval object 04236 } else { 04237 // get/set methodname 04238 $this->methodURI = $parser->root_struct_namespace; 04239 $this->methodname = $parser->root_struct_name; 04240 $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); 04241 $this->debug('calling parser->get_soapbody()'); 04242 $this->methodparams = $parser->get_soapbody(); 04243 // get SOAP headers 04244 $this->requestHeaders = $parser->getHeaders(); 04245 // get SOAP Header 04246 $this->requestHeader = $parser->get_soapheader(); 04247 // add document for doclit support 04248 $this->document = $parser->document; 04249 } 04250 } 04251 04259 function getHTTPBody($soapmsg) { 04260 return $soapmsg; 04261 } 04262 04271 function getHTTPContentType() { 04272 return 'text/xml'; 04273 } 04274 04284 function getHTTPContentTypeCharset() { 04285 return $this->soap_defencoding; 04286 } 04287 04297 function add_to_map($methodname,$in,$out){ 04298 $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); 04299 } 04300 04315 function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ 04316 global $HTTP_SERVER_VARS; 04317 04318 if($this->externalWSDLURL){ 04319 die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); 04320 } 04321 if (! $name) { 04322 die('You must specify a name when you register an operation'); 04323 } 04324 if (!is_array($in)) { 04325 die('You must provide an array for operation inputs'); 04326 } 04327 if (!is_array($out)) { 04328 die('You must provide an array for operation outputs'); 04329 } 04330 if(false == $namespace) { 04331 } 04332 if(false == $soapaction) { 04333 if (isset($_SERVER)) { 04334 $SERVER_NAME = $_SERVER['SERVER_NAME']; 04335 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 04336 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 04337 } elseif (isset($HTTP_SERVER_VARS)) { 04338 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 04339 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 04340 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 04341 } else { 04342 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 04343 } 04344 if ($HTTPS == '1' || $HTTPS == 'on') { 04345 $SCHEME = 'https'; 04346 } else { 04347 $SCHEME = 'http'; 04348 } 04349 $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; 04350 } 04351 if(false == $style) { 04352 $style = "rpc"; 04353 } 04354 if(false == $use) { 04355 $use = "encoded"; 04356 } 04357 if ($use == 'encoded' && $encodingStyle = '') { 04358 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 04359 } 04360 04361 $this->operations[$name] = array( 04362 'name' => $name, 04363 'in' => $in, 04364 'out' => $out, 04365 'namespace' => $namespace, 04366 'soapaction' => $soapaction, 04367 'style' => $style); 04368 if($this->wsdl){ 04369 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); 04370 } 04371 return true; 04372 } 04373 04384 function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ 04385 if ($faultdetail == '' && $this->debug_flag) { 04386 $faultdetail = $this->getDebug(); 04387 } 04388 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); 04389 $this->fault->soap_defencoding = $this->soap_defencoding; 04390 } 04391 04403 function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) 04404 { 04405 global $HTTP_SERVER_VARS; 04406 04407 if (isset($_SERVER)) { 04408 $SERVER_NAME = $_SERVER['SERVER_NAME']; 04409 $SERVER_PORT = $_SERVER['SERVER_PORT']; 04410 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 04411 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 04412 } elseif (isset($HTTP_SERVER_VARS)) { 04413 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 04414 $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; 04415 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 04416 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 04417 } else { 04418 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 04419 } 04420 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) 04421 $colon = strpos($SERVER_NAME,":"); 04422 if ($colon) { 04423 $SERVER_NAME = substr($SERVER_NAME, 0, $colon); 04424 } 04425 if ($SERVER_PORT == 80) { 04426 $SERVER_PORT = ''; 04427 } else { 04428 $SERVER_PORT = ':' . $SERVER_PORT; 04429 } 04430 if(false == $namespace) { 04431 $namespace = "http://$SERVER_NAME/soap/$serviceName"; 04432 } 04433 04434 if(false == $endpoint) { 04435 if ($HTTPS == '1' || $HTTPS == 'on') { 04436 $SCHEME = 'https'; 04437 } else { 04438 $SCHEME = 'http'; 04439 } 04440 $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; 04441 } 04442 04443 if(false == $schemaTargetNamespace) { 04444 $schemaTargetNamespace = $namespace; 04445 } 04446 04447 $this->wsdl = new wsdl; 04448 $this->wsdl->serviceName = $serviceName; 04449 $this->wsdl->endpoint = $endpoint; 04450 $this->wsdl->namespaces['tns'] = $namespace; 04451 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; 04452 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; 04453 if ($schemaTargetNamespace != $namespace) { 04454 $this->wsdl->namespaces['types'] = $schemaTargetNamespace; 04455 } 04456 $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); 04457 if ($style == 'document') { 04458 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; 04459 } 04460 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; 04461 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); 04462 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); 04463 $this->wsdl->bindings[$serviceName.'Binding'] = array( 04464 'name'=>$serviceName.'Binding', 04465 'style'=>$style, 04466 'transport'=>$transport, 04467 'portType'=>$serviceName.'PortType'); 04468 $this->wsdl->ports[$serviceName.'Port'] = array( 04469 'binding'=>$serviceName.'Binding', 04470 'location'=>$endpoint, 04471 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); 04472 } 04473 } 04474 04478 class soap_server extends nusoap_server { 04479 } 04480 04481 ?><?php 04482 04483 04484 04494 class wsdl extends nusoap_base { 04495 // URL or filename of the root of this WSDL 04496 var $wsdl; 04497 // define internal arrays of bindings, ports, operations, messages, etc. 04498 var $schemas = array(); 04499 var $currentSchema; 04500 var $message = array(); 04501 var $complexTypes = array(); 04502 var $messages = array(); 04503 var $currentMessage; 04504 var $currentOperation; 04505 var $portTypes = array(); 04506 var $currentPortType; 04507 var $bindings = array(); 04508 var $currentBinding; 04509 var $ports = array(); 04510 var $currentPort; 04511 var $opData = array(); 04512 var $status = ''; 04513 var $documentation = false; 04514 var $endpoint = ''; 04515 // array of wsdl docs to import 04516 var $import = array(); 04517 // parser vars 04518 var $parser; 04519 var $position = 0; 04520 var $depth = 0; 04521 var $depth_array = array(); 04522 // for getting wsdl 04523 var $proxyhost = ''; 04524 var $proxyport = ''; 04525 var $proxyusername = ''; 04526 var $proxypassword = ''; 04527 var $timeout = 0; 04528 var $response_timeout = 30; 04529 var $curl_options = array(); // User-specified cURL options 04530 var $use_curl = false; // whether to always try to use cURL 04531 // for HTTP authentication 04532 var $username = ''; // Username for HTTP authentication 04533 var $password = ''; // Password for HTTP authentication 04534 var $authtype = ''; // Type of HTTP authentication 04535 var $certRequest = array(); // Certificate for HTTP SSL authentication 04536 04551 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ 04552 parent::nusoap_base(); 04553 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 04554 $this->proxyhost = $proxyhost; 04555 $this->proxyport = $proxyport; 04556 $this->proxyusername = $proxyusername; 04557 $this->proxypassword = $proxypassword; 04558 $this->timeout = $timeout; 04559 $this->response_timeout = $response_timeout; 04560 if (is_array($curl_options)) 04561 $this->curl_options = $curl_options; 04562 $this->use_curl = $use_curl; 04563 $this->fetchWSDL($wsdl); 04564 } 04565 04571 function fetchWSDL($wsdl) { 04572 $this->debug("parse and process WSDL path=$wsdl"); 04573 $this->wsdl = $wsdl; 04574 // parse wsdl file 04575 if ($this->wsdl != "") { 04576 $this->parseWSDL($this->wsdl); 04577 } 04578 // imports 04579 // TODO: handle imports more properly, grabbing them in-line and nesting them 04580 $imported_urls = array(); 04581 $imported = 1; 04582 while ($imported > 0) { 04583 $imported = 0; 04584 // Schema imports 04585 foreach ($this->schemas as $ns => $list) { 04586 foreach ($list as $xs) { 04587 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 04588 foreach ($xs->imports as $ns2 => $list2) { 04589 for ($ii = 0; $ii < count($list2); $ii++) { 04590 if (! $list2[$ii]['loaded']) { 04591 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 04592 $url = $list2[$ii]['location']; 04593 if ($url != '') { 04594 $urlparts = parse_url($url); 04595 if (!isset($urlparts['host'])) { 04596 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 04597 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 04598 } 04599 if (! in_array($url, $imported_urls)) { 04600 $this->parseWSDL($url); 04601 $imported++; 04602 $imported_urls[] = $url; 04603 } 04604 } else { 04605 $this->debug("Unexpected scenario: empty URL for unloaded import"); 04606 } 04607 } 04608 } 04609 } 04610 } 04611 } 04612 // WSDL imports 04613 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 04614 foreach ($this->import as $ns => $list) { 04615 for ($ii = 0; $ii < count($list); $ii++) { 04616 if (! $list[$ii]['loaded']) { 04617 $this->import[$ns][$ii]['loaded'] = true; 04618 $url = $list[$ii]['location']; 04619 if ($url != '') { 04620 $urlparts = parse_url($url); 04621 if (!isset($urlparts['host'])) { 04622 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 04623 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 04624 } 04625 if (! in_array($url, $imported_urls)) { 04626 $this->parseWSDL($url); 04627 $imported++; 04628 $imported_urls[] = $url; 04629 } 04630 } else { 04631 $this->debug("Unexpected scenario: empty URL for unloaded import"); 04632 } 04633 } 04634 } 04635 } 04636 } 04637 // add new data to operation data 04638 foreach($this->bindings as $binding => $bindingData) { 04639 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 04640 foreach($bindingData['operations'] as $operation => $data) { 04641 $this->debug('post-parse data gathering for ' . $operation); 04642 $this->bindings[$binding]['operations'][$operation]['input'] = 04643 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 04644 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 04645 $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 04646 $this->bindings[$binding]['operations'][$operation]['output'] = 04647 isset($this->bindings[$binding]['operations'][$operation]['output']) ? 04648 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 04649 $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 04650 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ 04651 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 04652 } 04653 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ 04654 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 04655 } 04656 // Set operation style if necessary, but do not override one already provided 04657 if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { 04658 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 04659 } 04660 $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 04661 $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 04662 $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 04663 } 04664 } 04665 } 04666 } 04667 04674 function parseWSDL($wsdl = '') { 04675 $this->debug("parse WSDL at path=$wsdl"); 04676 04677 if ($wsdl == '') { 04678 $this->debug('no wsdl passed to parseWSDL()!!'); 04679 $this->setError('no wsdl passed to parseWSDL()!!'); 04680 return false; 04681 } 04682 04683 // parse $wsdl for url format 04684 $wsdl_props = parse_url($wsdl); 04685 04686 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 04687 $this->debug('getting WSDL http(s) URL ' . $wsdl); 04688 // get wsdl 04689 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); 04690 $tr->request_method = 'GET'; 04691 $tr->useSOAPAction = false; 04692 if($this->proxyhost && $this->proxyport){ 04693 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 04694 } 04695 if ($this->authtype != '') { 04696 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 04697 } 04698 $tr->setEncoding('gzip, deflate'); 04699 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 04700 //$this->debug("WSDL request\n" . $tr->outgoing_payload); 04701 //$this->debug("WSDL response\n" . $tr->incoming_payload); 04702 $this->appendDebug($tr->getDebug()); 04703 // catch errors 04704 if($err = $tr->getError() ){ 04705 $errstr = 'HTTP ERROR: '.$err; 04706 $this->debug($errstr); 04707 $this->setError($errstr); 04708 unset($tr); 04709 return false; 04710 } 04711 unset($tr); 04712 $this->debug("got WSDL URL"); 04713 } else { 04714 // $wsdl is not http(s), so treat it as a file URL or plain file path 04715 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 04716 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 04717 } else { 04718 $path = $wsdl; 04719 } 04720 $this->debug('getting WSDL file ' . $path); 04721 if ($fp = @fopen($path, 'r')) { 04722 $wsdl_string = ''; 04723 while ($data = fread($fp, 32768)) { 04724 $wsdl_string .= $data; 04725 } 04726 fclose($fp); 04727 } else { 04728 $errstr = "Bad path to WSDL file $path"; 04729 $this->debug($errstr); 04730 $this->setError($errstr); 04731 return false; 04732 } 04733 } 04734 $this->debug('Parse WSDL'); 04735 // end new code added 04736 // Create an XML parser. 04737 $this->parser = xml_parser_create(); 04738 // Set the options for parsing the XML data. 04739 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 04740 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 04741 // Set the object for the parser. 04742 xml_set_object($this->parser, $this); 04743 // Set the element handlers for the parser. 04744 xml_set_element_handler($this->parser, 'start_element', 'end_element'); 04745 xml_set_character_data_handler($this->parser, 'character_data'); 04746 // Parse the XML file. 04747 if (!xml_parse($this->parser, $wsdl_string, true)) { 04748 // Display an error message. 04749 $errstr = sprintf( 04750 'XML error parsing WSDL from %s on line %d: %s', 04751 $wsdl, 04752 xml_get_current_line_number($this->parser), 04753 xml_error_string(xml_get_error_code($this->parser)) 04754 ); 04755 $this->debug($errstr); 04756 $this->debug("XML payload:\n" . $wsdl_string); 04757 $this->setError($errstr); 04758 return false; 04759 } 04760 // free the parser 04761 xml_parser_free($this->parser); 04762 $this->debug('Parsing WSDL done'); 04763 // catch wsdl parse errors 04764 if($this->getError()){ 04765 return false; 04766 } 04767 return true; 04768 } 04769 04778 function start_element($parser, $name, $attrs) 04779 { 04780 if ($this->status == 'schema') { 04781 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 04782 $this->appendDebug($this->currentSchema->getDebug()); 04783 $this->currentSchema->clearDebug(); 04784 } elseif (ereg('schema$', $name)) { 04785 $this->debug('Parsing WSDL schema'); 04786 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 04787 $this->status = 'schema'; 04788 $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); 04789 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 04790 $this->appendDebug($this->currentSchema->getDebug()); 04791 $this->currentSchema->clearDebug(); 04792 } else { 04793 // position in the total number of elements, starting from 0 04794 $pos = $this->position++; 04795 $depth = $this->depth++; 04796 // set self as current value for this depth 04797 $this->depth_array[$depth] = $pos; 04798 $this->message[$pos] = array('cdata' => ''); 04799 // process attributes 04800 if (count($attrs) > 0) { 04801 // register namespace declarations 04802 foreach($attrs as $k => $v) { 04803 if (ereg("^xmlns", $k)) { 04804 if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 04805 $this->namespaces[$ns_prefix] = $v; 04806 } else { 04807 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 04808 } 04809 if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 04810 $this->XMLSchemaVersion = $v; 04811 $this->namespaces['xsi'] = $v . '-instance'; 04812 } 04813 } 04814 } 04815 // expand each attribute prefix to its namespace 04816 foreach($attrs as $k => $v) { 04817 $k = strpos($k, ':') ? $this->expandQname($k) : $k; 04818 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 04819 $v = strpos($v, ':') ? $this->expandQname($v) : $v; 04820 } 04821 $eAttrs[$k] = $v; 04822 } 04823 $attrs = $eAttrs; 04824 } else { 04825 $attrs = array(); 04826 } 04827 // get element prefix, namespace and name 04828 if (ereg(':', $name)) { 04829 // get ns prefix 04830 $prefix = substr($name, 0, strpos($name, ':')); 04831 // get ns 04832 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 04833 // get unqualified name 04834 $name = substr(strstr($name, ':'), 1); 04835 } 04836 // process attributes, expanding any prefixes to namespaces 04837 // find status, register data 04838 switch ($this->status) { 04839 case 'message': 04840 if ($name == 'part') { 04841 if (isset($attrs['type'])) { 04842 $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); 04843 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 04844 } 04845 if (isset($attrs['element'])) { 04846 $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); 04847 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; 04848 } 04849 } 04850 break; 04851 case 'portType': 04852 switch ($name) { 04853 case 'operation': 04854 $this->currentPortOperation = $attrs['name']; 04855 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 04856 if (isset($attrs['parameterOrder'])) { 04857 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 04858 } 04859 break; 04860 case 'documentation': 04861 $this->documentation = true; 04862 break; 04863 // merge input/output data 04864 default: 04865 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 04866 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 04867 break; 04868 } 04869 break; 04870 case 'binding': 04871 switch ($name) { 04872 case 'binding': 04873 // get ns prefix 04874 if (isset($attrs['style'])) { 04875 $this->bindings[$this->currentBinding]['prefix'] = $prefix; 04876 } 04877 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 04878 break; 04879 case 'header': 04880 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 04881 break; 04882 case 'operation': 04883 if (isset($attrs['soapAction'])) { 04884 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 04885 } 04886 if (isset($attrs['style'])) { 04887 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 04888 } 04889 if (isset($attrs['name'])) { 04890 $this->currentOperation = $attrs['name']; 04891 $this->debug("current binding operation: $this->currentOperation"); 04892 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 04893 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 04894 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 04895 } 04896 break; 04897 case 'input': 04898 $this->opStatus = 'input'; 04899 break; 04900 case 'output': 04901 $this->opStatus = 'output'; 04902 break; 04903 case 'body': 04904 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 04905 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 04906 } else { 04907 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 04908 } 04909 break; 04910 } 04911 break; 04912 case 'service': 04913 switch ($name) { 04914 case 'port': 04915 $this->currentPort = $attrs['name']; 04916 $this->debug('current port: ' . $this->currentPort); 04917 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 04918 04919 break; 04920 case 'address': 04921 $this->ports[$this->currentPort]['location'] = $attrs['location']; 04922 $this->ports[$this->currentPort]['bindingType'] = $namespace; 04923 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 04924 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 04925 break; 04926 } 04927 break; 04928 } 04929 // set status 04930 switch ($name) { 04931 case 'import': 04932 if (isset($attrs['location'])) { 04933 $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 04934 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 04935 } else { 04936 $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 04937 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 04938 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 04939 } 04940 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 04941 } 04942 break; 04943 //wait for schema 04944 //case 'types': 04945 // $this->status = 'schema'; 04946 // break; 04947 case 'message': 04948 $this->status = 'message'; 04949 $this->messages[$attrs['name']] = array(); 04950 $this->currentMessage = $attrs['name']; 04951 break; 04952 case 'portType': 04953 $this->status = 'portType'; 04954 $this->portTypes[$attrs['name']] = array(); 04955 $this->currentPortType = $attrs['name']; 04956 break; 04957 case "binding": 04958 if (isset($attrs['name'])) { 04959 // get binding name 04960 if (strpos($attrs['name'], ':')) { 04961 $this->currentBinding = $this->getLocalPart($attrs['name']); 04962 } else { 04963 $this->currentBinding = $attrs['name']; 04964 } 04965 $this->status = 'binding'; 04966 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 04967 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 04968 } 04969 break; 04970 case 'service': 04971 $this->serviceName = $attrs['name']; 04972 $this->status = 'service'; 04973 $this->debug('current service: ' . $this->serviceName); 04974 break; 04975 case 'definitions': 04976 foreach ($attrs as $name => $value) { 04977 $this->wsdl_info[$name] = $value; 04978 } 04979 break; 04980 } 04981 } 04982 } 04983 04991 function end_element($parser, $name){ 04992 // unset schema status 04993 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) { 04994 $this->status = ""; 04995 $this->appendDebug($this->currentSchema->getDebug()); 04996 $this->currentSchema->clearDebug(); 04997 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 04998 $this->debug('Parsing WSDL schema done'); 04999 } 05000 if ($this->status == 'schema') { 05001 $this->currentSchema->schemaEndElement($parser, $name); 05002 } else { 05003 // bring depth down a notch 05004 $this->depth--; 05005 } 05006 // end documentation 05007 if ($this->documentation) { 05008 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 05009 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 05010 $this->documentation = false; 05011 } 05012 } 05013 05021 function character_data($parser, $data) 05022 { 05023 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 05024 if (isset($this->message[$pos]['cdata'])) { 05025 $this->message[$pos]['cdata'] .= $data; 05026 } 05027 if ($this->documentation) { 05028 $this->documentation .= $data; 05029 } 05030 } 05031 05041 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 05042 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 05043 $this->appendDebug($this->varDump($certRequest)); 05044 $this->username = $username; 05045 $this->password = $password; 05046 $this->authtype = $authtype; 05047 $this->certRequest = $certRequest; 05048 } 05049 05050 function getBindingData($binding) 05051 { 05052 if (is_array($this->bindings[$binding])) { 05053 return $this->bindings[$binding]; 05054 } 05055 } 05056 05064 function getOperations($bindingType = 'soap') { 05065 $ops = array(); 05066 if ($bindingType == 'soap') { 05067 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05068 } elseif ($bindingType == 'soap12') { 05069 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05070 } 05071 // loop thru ports 05072 foreach($this->ports as $port => $portData) { 05073 // binding type of port matches parameter 05074 if ($portData['bindingType'] == $bindingType) { 05075 //$this->debug("getOperations for port $port"); 05076 //$this->debug("port data: " . $this->varDump($portData)); 05077 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 05078 // merge bindings 05079 if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 05080 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 05081 } 05082 } 05083 } 05084 return $ops; 05085 } 05086 05095 function getOperationData($operation, $bindingType = 'soap') 05096 { 05097 if ($bindingType == 'soap') { 05098 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05099 } elseif ($bindingType == 'soap12') { 05100 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05101 } 05102 // loop thru ports 05103 foreach($this->ports as $port => $portData) { 05104 // binding type of port matches parameter 05105 if ($portData['bindingType'] == $bindingType) { 05106 // get binding 05107 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 05108 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 05109 // note that we could/should also check the namespace here 05110 if ($operation == $bOperation) { 05111 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 05112 return $opData; 05113 } 05114 } 05115 } 05116 } 05117 } 05118 05127 function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 05128 if ($bindingType == 'soap') { 05129 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05130 } elseif ($bindingType == 'soap12') { 05131 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05132 } 05133 // loop thru ports 05134 foreach($this->ports as $port => $portData) { 05135 // binding type of port matches parameter 05136 if ($portData['bindingType'] == $bindingType) { 05137 // loop through operations for the binding 05138 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 05139 if ($opData['soapAction'] == $soapAction) { 05140 return $opData; 05141 } 05142 } 05143 } 05144 } 05145 } 05146 05165 function getTypeDef($type, $ns) { 05166 $this->debug("in getTypeDef: type=$type, ns=$ns"); 05167 if ((! $ns) && isset($this->namespaces['tns'])) { 05168 $ns = $this->namespaces['tns']; 05169 $this->debug("in getTypeDef: type namespace forced to $ns"); 05170 } 05171 if (!isset($this->schemas[$ns])) { 05172 foreach ($this->schemas as $ns0 => $schema0) { 05173 if (strcasecmp($ns, $ns0) == 0) { 05174 $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); 05175 $ns = $ns0; 05176 break; 05177 } 05178 } 05179 } 05180 if (isset($this->schemas[$ns])) { 05181 $this->debug("in getTypeDef: have schema for namespace $ns"); 05182 for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 05183 $xs = &$this->schemas[$ns][$i]; 05184 $t = $xs->getTypeDef($type); 05185 //$this->appendDebug($xs->getDebug()); 05186 //$xs->clearDebug(); 05187 if ($t) { 05188 if (!isset($t['phpType'])) { 05189 // get info for type to tack onto the element 05190 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 05191 $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 05192 $etype = $this->getTypeDef($uqType, $ns); 05193 if ($etype) { 05194 $this->debug("found type for [element] $type:"); 05195 $this->debug($this->varDump($etype)); 05196 if (isset($etype['phpType'])) { 05197 $t['phpType'] = $etype['phpType']; 05198 } 05199 if (isset($etype['elements'])) { 05200 $t['elements'] = $etype['elements']; 05201 } 05202 if (isset($etype['attrs'])) { 05203 $t['attrs'] = $etype['attrs']; 05204 } 05205 } 05206 } 05207 return $t; 05208 } 05209 } 05210 } else { 05211 $this->debug("in getTypeDef: do not have schema for namespace $ns"); 05212 } 05213 return false; 05214 } 05215 05221 function webDescription(){ 05222 global $HTTP_SERVER_VARS; 05223 05224 if (isset($_SERVER)) { 05225 $PHP_SELF = $_SERVER['PHP_SELF']; 05226 } elseif (isset($HTTP_SERVER_VARS)) { 05227 $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 05228 } else { 05229 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 05230 } 05231 05232 $b = ' 05233 <html><head><title>NuSOAP: '.$this->serviceName.'</title> 05234 <style type="text/css"> 05235 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 05236 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 05237 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 05238 ul { margin-top: 10px; margin-left: 20px; } 05239 li { list-style-type: none; margin-top: 10px; color: #000000; } 05240 .content{ 05241 margin-left: 0px; padding-bottom: 2em; } 05242 .nav { 05243 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 05244 margin-top: 10px; margin-left: 0px; color: #000000; 05245 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 05246 .title { 05247 font-family: arial; font-size: 26px; color: #ffffff; 05248 background-color: #999999; width: 105%; margin-left: 0px; 05249 padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} 05250 .hidden { 05251 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 05252 font-family: arial; overflow: hidden; width: 600; 05253 padding: 20px; font-size: 10px; background-color: #999999; 05254 layer-background-color:#FFFFFF; } 05255 a,a:active { color: charcoal; font-weight: bold; } 05256 a:visited { color: #666666; font-weight: bold; } 05257 a:hover { color: cc3300; font-weight: bold; } 05258 </style> 05259 <script language="JavaScript" type="text/javascript"> 05260 <!-- 05261 // POP-UP CAPTIONS... 05262 function lib_bwcheck(){ //Browsercheck (needed) 05263 this.ver=navigator.appVersion 05264 this.agent=navigator.userAgent 05265 this.dom=document.getElementById?1:0 05266 this.opera5=this.agent.indexOf("Opera 5")>-1 05267 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 05268 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 05269 this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 05270 this.ie=this.ie4||this.ie5||this.ie6 05271 this.mac=this.agent.indexOf("Mac")>-1 05272 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 05273 this.ns4=(document.layers && !this.dom)?1:0; 05274 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 05275 return this 05276 } 05277 var bw = new lib_bwcheck() 05278 //Makes crossbrowser object. 05279 function makeObj(obj){ 05280 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 05281 if(!this.evnt) return false 05282 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 05283 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 05284 this.writeIt=b_writeIt; 05285 return this 05286 } 05287 // A unit of measure that will be added when setting the position of a layer. 05288 //var px = bw.ns4||window.opera?"":"px"; 05289 function b_writeIt(text){ 05290 if (bw.ns4){this.wref.write(text);this.wref.close()} 05291 else this.wref.innerHTML = text 05292 } 05293 //Shows the messages 05294 var oDesc; 05295 function popup(divid){ 05296 if(oDesc = new makeObj(divid)){ 05297 oDesc.css.visibility = "visible" 05298 } 05299 } 05300 function popout(){ // Hides message 05301 if(oDesc) oDesc.css.visibility = "hidden" 05302 } 05303 //--> 05304 </script> 05305 </head> 05306 <body> 05307 <div class=content> 05308 <br><br> 05309 <div class=title>'.$this->serviceName.'</div> 05310 <div class=nav> 05311 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 05312 Click on an operation name to view it's details.</p> 05313 <ul>'; 05314 foreach($this->getOperations() as $op => $data){ 05315 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 05316 // create hidden div 05317 $b .= "<div id='$op' class='hidden'> 05318 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 05319 foreach($data as $donnie => $marie){ // loop through opdata 05320 if($donnie == 'input' || $donnie == 'output'){ // show input/output data 05321 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 05322 foreach($marie as $captain => $tenille){ // loop through data 05323 if($captain == 'parts'){ // loop thru parts 05324 $b .= " $captain:<br>"; 05325 //if(is_array($tenille)){ 05326 foreach($tenille as $joanie => $chachi){ 05327 $b .= " $joanie: $chachi<br>"; 05328 } 05329 //} 05330 } else { 05331 $b .= " $captain: $tenille<br>"; 05332 } 05333 } 05334 } else { 05335 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 05336 } 05337 } 05338 $b .= '</div>'; 05339 } 05340 $b .= ' 05341 <ul> 05342 </div> 05343 </div></body></html>'; 05344 return $b; 05345 } 05346 05354 function serialize($debug = 0) 05355 { 05356 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 05357 $xml .= "\n<definitions"; 05358 foreach($this->namespaces as $k => $v) { 05359 $xml .= " xmlns:$k=\"$v\""; 05360 } 05361 // 10.9.02 - add poulter fix for wsdl and tns declarations 05362 if (isset($this->namespaces['wsdl'])) { 05363 $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 05364 } 05365 if (isset($this->namespaces['tns'])) { 05366 $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 05367 } 05368 $xml .= '>'; 05369 // imports 05370 if (sizeof($this->import) > 0) { 05371 foreach($this->import as $ns => $list) { 05372 foreach ($list as $ii) { 05373 if ($ii['location'] != '') { 05374 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 05375 } else { 05376 $xml .= '<import namespace="' . $ns . '" />'; 05377 } 05378 } 05379 } 05380 } 05381 // types 05382 if (count($this->schemas)>=1) { 05383 $xml .= "\n<types>\n"; 05384 foreach ($this->schemas as $ns => $list) { 05385 foreach ($list as $xs) { 05386 $xml .= $xs->serializeSchema(); 05387 } 05388 } 05389 $xml .= '</types>'; 05390 } 05391 // messages 05392 if (count($this->messages) >= 1) { 05393 foreach($this->messages as $msgName => $msgParts) { 05394 $xml .= "\n<message name=\"" . $msgName . '">'; 05395 if(is_array($msgParts)){ 05396 foreach($msgParts as $partName => $partType) { 05397 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 05398 if (strpos($partType, ':')) { 05399 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 05400 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 05401 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 05402 $typePrefix = 'xsd'; 05403 } else { 05404 foreach($this->typemap as $ns => $types) { 05405 if (isset($types[$partType])) { 05406 $typePrefix = $this->getPrefixFromNamespace($ns); 05407 } 05408 } 05409 if (!isset($typePrefix)) { 05410 die("$partType has no namespace!"); 05411 } 05412 } 05413 $ns = $this->getNamespaceFromPrefix($typePrefix); 05414 $localPart = $this->getLocalPart($partType); 05415 $typeDef = $this->getTypeDef($localPart, $ns); 05416 if ($typeDef['typeClass'] == 'element') { 05417 $elementortype = 'element'; 05418 if (substr($localPart, -1) == '^') { 05419 $localPart = substr($localPart, 0, -1); 05420 } 05421 } else { 05422 $elementortype = 'type'; 05423 } 05424 $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; 05425 } 05426 } 05427 $xml .= '</message>'; 05428 } 05429 } 05430 // bindings & porttypes 05431 if (count($this->bindings) >= 1) { 05432 $binding_xml = ''; 05433 $portType_xml = ''; 05434 foreach($this->bindings as $bindingName => $attrs) { 05435 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 05436 $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 05437 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 05438 foreach($attrs['operations'] as $opName => $opParts) { 05439 $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; 05440 $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 05441 if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 05442 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 05443 } else { 05444 $enc_style = ''; 05445 } 05446 $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 05447 if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 05448 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 05449 } else { 05450 $enc_style = ''; 05451 } 05452 $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 05453 $binding_xml .= "\n" . ' </operation>'; 05454 $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; 05455 if (isset($opParts['parameterOrder'])) { 05456 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 05457 } 05458 $portType_xml .= '>'; 05459 if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 05460 $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 05461 } 05462 $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; 05463 $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; 05464 $portType_xml .= "\n" . ' </operation>'; 05465 } 05466 $portType_xml .= "\n" . '</portType>'; 05467 $binding_xml .= "\n" . '</binding>'; 05468 } 05469 $xml .= $portType_xml . $binding_xml; 05470 } 05471 // services 05472 $xml .= "\n<service name=\"" . $this->serviceName . '">'; 05473 if (count($this->ports) >= 1) { 05474 foreach($this->ports as $pName => $attrs) { 05475 $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 05476 $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 05477 $xml .= "\n" . ' </port>'; 05478 } 05479 } 05480 $xml .= "\n" . '</service>'; 05481 return $xml . "\n</definitions>"; 05482 } 05483 05493 function parametersMatchWrapped($type, &$parameters) { 05494 $this->debug("in parametersMatchWrapped type=$type, parameters="); 05495 $this->appendDebug($this->varDump($parameters)); 05496 05497 // split type into namespace:unqualified-type 05498 if (strpos($type, ':')) { 05499 $uqType = substr($type, strrpos($type, ':') + 1); 05500 $ns = substr($type, 0, strrpos($type, ':')); 05501 $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); 05502 if ($this->getNamespaceFromPrefix($ns)) { 05503 $ns = $this->getNamespaceFromPrefix($ns); 05504 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); 05505 } 05506 } else { 05507 // TODO: should the type be compared to types in XSD, and the namespace 05508 // set to XSD if the type matches? 05509 $this->debug("in parametersMatchWrapped: No namespace for type $type"); 05510 $ns = ''; 05511 $uqType = $type; 05512 } 05513 05514 // get the type information 05515 if (!$typeDef = $this->getTypeDef($uqType, $ns)) { 05516 $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); 05517 return false; 05518 } 05519 $this->debug("in parametersMatchWrapped: found typeDef="); 05520 $this->appendDebug($this->varDump($typeDef)); 05521 if (substr($uqType, -1) == '^') { 05522 $uqType = substr($uqType, 0, -1); 05523 } 05524 $phpType = $typeDef['phpType']; 05525 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); 05526 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); 05527 05528 // we expect a complexType or element of complexType 05529 if ($phpType != 'struct') { 05530 $this->debug("in parametersMatchWrapped: not a struct"); 05531 return false; 05532 } 05533 05534 // see whether the parameter names match the elements 05535 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 05536 $elements = 0; 05537 $matches = 0; 05538 $change = false; 05539 if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) { 05540 $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap"); 05541 $change = true; 05542 } 05543 foreach ($typeDef['elements'] as $name => $attrs) { 05544 if ($change) { 05545 $this->debug("in parametersMatchWrapped: change parameter $element to name $name"); 05546 $parameters[$name] = $parameters[$elements]; 05547 unset($parameters[$elements]); 05548 $matches++; 05549 } elseif (isset($parameters[$name])) { 05550 $this->debug("in parametersMatchWrapped: have parameter named $name"); 05551 $matches++; 05552 } else { 05553 $this->debug("in parametersMatchWrapped: do not have parameter named $name"); 05554 } 05555 $elements++; 05556 } 05557 05558 $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); 05559 if ($matches == 0) { 05560 return false; 05561 } 05562 return true; 05563 } 05564 05565 // since there are no elements for the type, if the user passed no 05566 // parameters, the parameters match wrapped. 05567 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); 05568 return count($parameters) == 0; 05569 } 05570 05586 function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { 05587 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); 05588 $this->appendDebug('parameters=' . $this->varDump($parameters)); 05589 05590 if ($direction != 'input' && $direction != 'output') { 05591 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 05592 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 05593 return false; 05594 } 05595 if (!$opData = $this->getOperationData($operation, $bindingType)) { 05596 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 05597 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 05598 return false; 05599 } 05600 $this->debug('in serializeRPCParameters: opData:'); 05601 $this->appendDebug($this->varDump($opData)); 05602 05603 // Get encoding style for output and set to current 05604 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 05605 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 05606 $encodingStyle = $opData['output']['encodingStyle']; 05607 $enc_style = $encodingStyle; 05608 } 05609 05610 // set input params 05611 $xml = ''; 05612 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 05613 $parts = &$opData[$direction]['parts']; 05614 $part_count = sizeof($parts); 05615 $style = $opData['style']; 05616 $use = $opData[$direction]['use']; 05617 $this->debug("have $part_count part(s) to serialize using $style/$use"); 05618 if (is_array($parameters)) { 05619 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 05620 $parameter_count = count($parameters); 05621 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); 05622 // check for Microsoft-style wrapped parameters 05623 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { 05624 $this->debug('check whether the caller has wrapped the parameters'); 05625 if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) { 05626 $this->debug('check whether caller\'s parameters match the wrapped ones'); 05627 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { 05628 $this->debug('wrap the parameters for the caller'); 05629 $parameters = array('parameters' => $parameters); 05630 $parameter_count = 1; 05631 } 05632 } 05633 } 05634 foreach ($parts as $name => $type) { 05635 $this->debug("serializing part $name of type $type"); 05636 // Track encoding style 05637 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 05638 $encodingStyle = $opData[$direction]['encodingStyle']; 05639 $enc_style = $encodingStyle; 05640 } else { 05641 $enc_style = false; 05642 } 05643 // NOTE: add error handling here 05644 // if serializeType returns false, then catch global error and fault 05645 if ($parametersArrayType == 'arraySimple') { 05646 $p = array_shift($parameters); 05647 $this->debug('calling serializeType w/indexed param'); 05648 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 05649 } elseif (isset($parameters[$name])) { 05650 $this->debug('calling serializeType w/named param'); 05651 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 05652 } else { 05653 // TODO: only send nillable 05654 $this->debug('calling serializeType w/null param'); 05655 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 05656 } 05657 } 05658 } else { 05659 $this->debug('no parameters passed.'); 05660 } 05661 } 05662 $this->debug("serializeRPCParameters returning: $xml"); 05663 return $xml; 05664 } 05665 05680 function serializeParameters($operation, $direction, $parameters) 05681 { 05682 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 05683 $this->appendDebug('parameters=' . $this->varDump($parameters)); 05684 05685 if ($direction != 'input' && $direction != 'output') { 05686 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 05687 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 05688 return false; 05689 } 05690 if (!$opData = $this->getOperationData($operation)) { 05691 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 05692 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 05693 return false; 05694 } 05695 $this->debug('opData:'); 05696 $this->appendDebug($this->varDump($opData)); 05697 05698 // Get encoding style for output and set to current 05699 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 05700 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 05701 $encodingStyle = $opData['output']['encodingStyle']; 05702 $enc_style = $encodingStyle; 05703 } 05704 05705 // set input params 05706 $xml = ''; 05707 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 05708 05709 $use = $opData[$direction]['use']; 05710 $this->debug("use=$use"); 05711 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 05712 if (is_array($parameters)) { 05713 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 05714 $this->debug('have ' . $parametersArrayType . ' parameters'); 05715 foreach($opData[$direction]['parts'] as $name => $type) { 05716 $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 05717 // Track encoding style 05718 if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 05719 $encodingStyle = $opData[$direction]['encodingStyle']; 05720 $enc_style = $encodingStyle; 05721 } else { 05722 $enc_style = false; 05723 } 05724 // NOTE: add error handling here 05725 // if serializeType returns false, then catch global error and fault 05726 if ($parametersArrayType == 'arraySimple') { 05727 $p = array_shift($parameters); 05728 $this->debug('calling serializeType w/indexed param'); 05729 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 05730 } elseif (isset($parameters[$name])) { 05731 $this->debug('calling serializeType w/named param'); 05732 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 05733 } else { 05734 // TODO: only send nillable 05735 $this->debug('calling serializeType w/null param'); 05736 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 05737 } 05738 } 05739 } else { 05740 $this->debug('no parameters passed.'); 05741 } 05742 } 05743 $this->debug("serializeParameters returning: $xml"); 05744 return $xml; 05745 } 05746 05759 function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 05760 { 05761 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 05762 $this->appendDebug("value=" . $this->varDump($value)); 05763 if($use == 'encoded' && $encodingStyle) { 05764 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 05765 } 05766 05767 // if a soapval has been supplied, let its type override the WSDL 05768 if (is_object($value) && get_class($value) == 'soapval') { 05769 if ($value->type_ns) { 05770 $type = $value->type_ns . ':' . $value->type; 05771 $forceType = true; 05772 $this->debug("in serializeType: soapval overrides type to $type"); 05773 } elseif ($value->type) { 05774 $type = $value->type; 05775 $forceType = true; 05776 $this->debug("in serializeType: soapval overrides type to $type"); 05777 } else { 05778 $forceType = false; 05779 $this->debug("in serializeType: soapval does not override type"); 05780 } 05781 $attrs = $value->attributes; 05782 $value = $value->value; 05783 $this->debug("in serializeType: soapval overrides value to $value"); 05784 if ($attrs) { 05785 if (!is_array($value)) { 05786 $value['!'] = $value; 05787 } 05788 foreach ($attrs as $n => $v) { 05789 $value['!' . $n] = $v; 05790 } 05791 $this->debug("in serializeType: soapval provides attributes"); 05792 } 05793 } else { 05794 $forceType = false; 05795 } 05796 05797 $xml = ''; 05798 if (strpos($type, ':')) { 05799 $uqType = substr($type, strrpos($type, ':') + 1); 05800 $ns = substr($type, 0, strrpos($type, ':')); 05801 $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 05802 if ($this->getNamespaceFromPrefix($ns)) { 05803 $ns = $this->getNamespaceFromPrefix($ns); 05804 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 05805 } 05806 05807 if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ 05808 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 05809 if ($unqualified && $use == 'literal') { 05810 $elementNS = " xmlns=\"\""; 05811 } else { 05812 $elementNS = ''; 05813 } 05814 if (is_null($value)) { 05815 if ($use == 'literal') { 05816 // TODO: depends on minOccurs 05817 $xml = "<$name$elementNS/>"; 05818 } else { 05819 // TODO: depends on nillable, which should be checked before calling this method 05820 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 05821 } 05822 $this->debug("in serializeType: returning: $xml"); 05823 return $xml; 05824 } 05825 if ($uqType == 'Array') { 05826 // JBoss/Axis does this sometimes 05827 return $this->serialize_val($value, $name, false, false, false, false, $use); 05828 } 05829 if ($uqType == 'boolean') { 05830 if ((is_string($value) && $value == 'false') || (! $value)) { 05831 $value = 'false'; 05832 } else { 05833 $value = 'true'; 05834 } 05835 } 05836 if ($uqType == 'string' && gettype($value) == 'string') { 05837 $value = $this->expandEntities($value); 05838 } 05839 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 05840 $value = sprintf("%.0lf", $value); 05841 } 05842 // it's a scalar 05843 // TODO: what about null/nil values? 05844 // check type isn't a custom type extending xmlschema namespace 05845 if (!$this->getTypeDef($uqType, $ns)) { 05846 if ($use == 'literal') { 05847 if ($forceType) { 05848 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 05849 } else { 05850 $xml = "<$name$elementNS>$value</$name>"; 05851 } 05852 } else { 05853 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 05854 } 05855 $this->debug("in serializeType: returning: $xml"); 05856 return $xml; 05857 } 05858 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 05859 } else if ($ns == 'http://xml.apache.org/xml-soap') { 05860 $this->debug('in serializeType: appears to be Apache SOAP type'); 05861 if ($uqType == 'Map') { 05862 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 05863 if (! $tt_prefix) { 05864 $this->debug('in serializeType: Add namespace for Apache SOAP type'); 05865 $tt_prefix = 'ns' . rand(1000, 9999); 05866 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 05867 // force this to be added to usedNamespaces 05868 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 05869 } 05870 $contents = ''; 05871 foreach($value as $k => $v) { 05872 $this->debug("serializing map element: key $k, value $v"); 05873 $contents .= '<item>'; 05874 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); 05875 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); 05876 $contents .= '</item>'; 05877 } 05878 if ($use == 'literal') { 05879 if ($forceType) { 05880 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 05881 } else { 05882 $xml = "<$name>$contents</$name>"; 05883 } 05884 } else { 05885 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 05886 } 05887 $this->debug("in serializeType: returning: $xml"); 05888 return $xml; 05889 } 05890 $this->debug('in serializeType: Apache SOAP type, but only support Map'); 05891 } 05892 } else { 05893 // TODO: should the type be compared to types in XSD, and the namespace 05894 // set to XSD if the type matches? 05895 $this->debug("in serializeType: No namespace for type $type"); 05896 $ns = ''; 05897 $uqType = $type; 05898 } 05899 if(!$typeDef = $this->getTypeDef($uqType, $ns)){ 05900 $this->setError("$type ($uqType) is not a supported type."); 05901 $this->debug("in serializeType: $type ($uqType) is not a supported type."); 05902 return false; 05903 } else { 05904 $this->debug("in serializeType: found typeDef"); 05905 $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 05906 if (substr($uqType, -1) == '^') { 05907 $uqType = substr($uqType, 0, -1); 05908 } 05909 } 05910 $phpType = $typeDef['phpType']; 05911 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 05912 // if php type == struct, map value to the <all> element names 05913 if ($phpType == 'struct') { 05914 if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 05915 $elementName = $uqType; 05916 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 05917 $elementNS = " xmlns=\"$ns\""; 05918 } else { 05919 $elementNS = " xmlns=\"\""; 05920 } 05921 } else { 05922 $elementName = $name; 05923 if ($unqualified) { 05924 $elementNS = " xmlns=\"\""; 05925 } else { 05926 $elementNS = ''; 05927 } 05928 } 05929 if (is_null($value)) { 05930 if ($use == 'literal') { 05931 // TODO: depends on minOccurs 05932 $xml = "<$elementName$elementNS/>"; 05933 } else { 05934 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 05935 } 05936 $this->debug("in serializeType: returning: $xml"); 05937 return $xml; 05938 } 05939 if (is_object($value)) { 05940 $value = get_object_vars($value); 05941 } 05942 if (is_array($value)) { 05943 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 05944 if ($use == 'literal') { 05945 if ($forceType) { 05946 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 05947 } else { 05948 $xml = "<$elementName$elementNS$elementAttrs>"; 05949 } 05950 } else { 05951 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 05952 } 05953 05954 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 05955 $xml .= "</$elementName>"; 05956 } else { 05957 $this->debug("in serializeType: phpType is struct, but value is not an array"); 05958 $this->setError("phpType is struct, but value is not an array: see debug output for details"); 05959 $xml = ''; 05960 } 05961 } elseif ($phpType == 'array') { 05962 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 05963 $elementNS = " xmlns=\"$ns\""; 05964 } else { 05965 if ($unqualified) { 05966 $elementNS = " xmlns=\"\""; 05967 } else { 05968 $elementNS = ''; 05969 } 05970 } 05971 if (is_null($value)) { 05972 if ($use == 'literal') { 05973 // TODO: depends on minOccurs 05974 $xml = "<$name$elementNS/>"; 05975 } else { 05976 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 05977 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 05978 ":Array\" " . 05979 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 05980 ':arrayType="' . 05981 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 05982 ':' . 05983 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 05984 } 05985 $this->debug("in serializeType: returning: $xml"); 05986 return $xml; 05987 } 05988 if (isset($typeDef['multidimensional'])) { 05989 $nv = array(); 05990 foreach($value as $v) { 05991 $cols = ',' . sizeof($v); 05992 $nv = array_merge($nv, $v); 05993 } 05994 $value = $nv; 05995 } else { 05996 $cols = ''; 05997 } 05998 if (is_array($value) && sizeof($value) >= 1) { 05999 $rows = sizeof($value); 06000 $contents = ''; 06001 foreach($value as $k => $v) { 06002 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 06003 //if (strpos($typeDef['arrayType'], ':') ) { 06004 if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { 06005 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 06006 } else { 06007 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 06008 } 06009 } 06010 } else { 06011 $rows = 0; 06012 $contents = null; 06013 } 06014 // TODO: for now, an empty value will be serialized as a zero element 06015 // array. Revisit this when coding the handling of null/nil values. 06016 if ($use == 'literal') { 06017 $xml = "<$name$elementNS>" 06018 .$contents 06019 ."</$name>"; 06020 } else { 06021 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 06022 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 06023 .':arrayType="' 06024 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 06025 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 06026 .$contents 06027 ."</$name>"; 06028 } 06029 } elseif ($phpType == 'scalar') { 06030 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 06031 $elementNS = " xmlns=\"$ns\""; 06032 } else { 06033 if ($unqualified) { 06034 $elementNS = " xmlns=\"\""; 06035 } else { 06036 $elementNS = ''; 06037 } 06038 } 06039 if ($use == 'literal') { 06040 if ($forceType) { 06041 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 06042 } else { 06043 $xml = "<$name$elementNS>$value</$name>"; 06044 } 06045 } else { 06046 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 06047 } 06048 } 06049 $this->debug("in serializeType: returning: $xml"); 06050 return $xml; 06051 } 06052 06063 function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 06064 $xml = ''; 06065 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 06066 $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 06067 if (is_array($value)) { 06068 $xvalue = $value; 06069 } elseif (is_object($value)) { 06070 $xvalue = get_object_vars($value); 06071 } else { 06072 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 06073 $xvalue = array(); 06074 } 06075 foreach ($typeDef['attrs'] as $aName => $attrs) { 06076 if (isset($xvalue['!' . $aName])) { 06077 $xname = '!' . $aName; 06078 $this->debug("value provided for attribute $aName with key $xname"); 06079 } elseif (isset($xvalue[$aName])) { 06080 $xname = $aName; 06081 $this->debug("value provided for attribute $aName with key $xname"); 06082 } elseif (isset($attrs['default'])) { 06083 $xname = '!' . $aName; 06084 $xvalue[$xname] = $attrs['default']; 06085 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 06086 } else { 06087 $xname = ''; 06088 $this->debug("no value provided for attribute $aName"); 06089 } 06090 if ($xname) { 06091 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 06092 } 06093 } 06094 } else { 06095 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 06096 } 06097 if (isset($typeDef['extensionBase'])) { 06098 $ns = $this->getPrefix($typeDef['extensionBase']); 06099 $uqType = $this->getLocalPart($typeDef['extensionBase']); 06100 if ($this->getNamespaceFromPrefix($ns)) { 06101 $ns = $this->getNamespaceFromPrefix($ns); 06102 } 06103 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 06104 $this->debug("serialize attributes for extension base $ns:$uqType"); 06105 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 06106 } else { 06107 $this->debug("extension base $ns:$uqType is not a supported type"); 06108 } 06109 } 06110 return $xml; 06111 } 06112 06125 function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 06126 $xml = ''; 06127 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 06128 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 06129 if (is_array($value)) { 06130 $xvalue = $value; 06131 } elseif (is_object($value)) { 06132 $xvalue = get_object_vars($value); 06133 } else { 06134 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 06135 $xvalue = array(); 06136 } 06137 // toggle whether all elements are present - ideally should validate against schema 06138 if (count($typeDef['elements']) != count($xvalue)){ 06139 $optionals = true; 06140 } 06141 foreach ($typeDef['elements'] as $eName => $attrs) { 06142 if (!isset($xvalue[$eName])) { 06143 if (isset($attrs['default'])) { 06144 $xvalue[$eName] = $attrs['default']; 06145 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 06146 } 06147 } 06148 // if user took advantage of a minOccurs=0, then only serialize named parameters 06149 if (isset($optionals) 06150 && (!isset($xvalue[$eName])) 06151 && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 06152 ){ 06153 if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 06154 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 06155 } 06156 // do nothing 06157 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 06158 } else { 06159 // get value 06160 if (isset($xvalue[$eName])) { 06161 $v = $xvalue[$eName]; 06162 } else { 06163 $v = null; 06164 } 06165 if (isset($attrs['form'])) { 06166 $unqualified = ($attrs['form'] == 'unqualified'); 06167 } else { 06168 $unqualified = false; 06169 } 06170 if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 06171 $vv = $v; 06172 foreach ($vv as $k => $v) { 06173 if (isset($attrs['type']) || isset($attrs['ref'])) { 06174 // serialize schema-defined type 06175 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 06176 } else { 06177 // serialize generic type (can this ever really happen?) 06178 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 06179 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 06180 } 06181 } 06182 } else { 06183 if (isset($attrs['type']) || isset($attrs['ref'])) { 06184 // serialize schema-defined type 06185 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 06186 } else { 06187 // serialize generic type (can this ever really happen?) 06188 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 06189 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 06190 } 06191 } 06192 } 06193 } 06194 } else { 06195 $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 06196 } 06197 if (isset($typeDef['extensionBase'])) { 06198 $ns = $this->getPrefix($typeDef['extensionBase']); 06199 $uqType = $this->getLocalPart($typeDef['extensionBase']); 06200 if ($this->getNamespaceFromPrefix($ns)) { 06201 $ns = $this->getNamespaceFromPrefix($ns); 06202 } 06203 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 06204 $this->debug("serialize elements for extension base $ns:$uqType"); 06205 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 06206 } else { 06207 $this->debug("extension base $ns:$uqType is not a supported type"); 06208 } 06209 } 06210 return $xml; 06211 } 06212 06227 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { 06228 if (count($elements) > 0) { 06229 $eElements = array(); 06230 foreach($elements as $n => $e){ 06231 // expand each element 06232 $ee = array(); 06233 foreach ($e as $k => $v) { 06234 $k = strpos($k,':') ? $this->expandQname($k) : $k; 06235 $v = strpos($v,':') ? $this->expandQname($v) : $v; 06236 $ee[$k] = $v; 06237 } 06238 $eElements[$n] = $ee; 06239 } 06240 $elements = $eElements; 06241 } 06242 06243 if (count($attrs) > 0) { 06244 foreach($attrs as $n => $a){ 06245 // expand each attribute 06246 foreach ($a as $k => $v) { 06247 $k = strpos($k,':') ? $this->expandQname($k) : $k; 06248 $v = strpos($v,':') ? $this->expandQname($v) : $v; 06249 $aa[$k] = $v; 06250 } 06251 $eAttrs[$n] = $aa; 06252 } 06253 $attrs = $eAttrs; 06254 } 06255 06256 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 06257 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; 06258 06259 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06260 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); 06261 } 06262 06274 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 06275 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 06276 06277 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06278 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 06279 } 06280 06288 function addElement($attrs) { 06289 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06290 $this->schemas[$typens][0]->addElement($attrs); 06291 } 06292 06307 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ 06308 if ($use == 'encoded' && $encodingStyle == '') { 06309 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 06310 } 06311 06312 if ($style == 'document') { 06313 $elements = array(); 06314 foreach ($in as $n => $t) { 06315 $elements[$n] = array('name' => $n, 'type' => $t); 06316 } 06317 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 06318 $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 06319 $in = array('parameters' => 'tns:' . $name . '^'); 06320 06321 $elements = array(); 06322 foreach ($out as $n => $t) { 06323 $elements[$n] = array('name' => $n, 'type' => $t); 06324 } 06325 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 06326 $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); 06327 $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); 06328 } 06329 06330 // get binding 06331 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 06332 array( 06333 'name' => $name, 06334 'binding' => $this->serviceName . 'Binding', 06335 'endpoint' => $this->endpoint, 06336 'soapAction' => $soapaction, 06337 'style' => $style, 06338 'input' => array( 06339 'use' => $use, 06340 'namespace' => $namespace, 06341 'encodingStyle' => $encodingStyle, 06342 'message' => $name . 'Request', 06343 'parts' => $in), 06344 'output' => array( 06345 'use' => $use, 06346 'namespace' => $namespace, 06347 'encodingStyle' => $encodingStyle, 06348 'message' => $name . 'Response', 06349 'parts' => $out), 06350 'namespace' => $namespace, 06351 'transport' => 'http://schemas.xmlsoap.org/soap/http', 06352 'documentation' => $documentation); 06353 // add portTypes 06354 // add messages 06355 if($in) 06356 { 06357 foreach($in as $pName => $pType) 06358 { 06359 if(strpos($pType,':')) { 06360 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 06361 } 06362 $this->messages[$name.'Request'][$pName] = $pType; 06363 } 06364 } else { 06365 $this->messages[$name.'Request']= '0'; 06366 } 06367 if($out) 06368 { 06369 foreach($out as $pName => $pType) 06370 { 06371 if(strpos($pType,':')) { 06372 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 06373 } 06374 $this->messages[$name.'Response'][$pName] = $pType; 06375 } 06376 } else { 06377 $this->messages[$name.'Response']= '0'; 06378 } 06379 return true; 06380 } 06381 } 06382 ?><?php 06383 06384 06385 06395 class nusoap_parser extends nusoap_base { 06396 06397 var $xml = ''; 06398 var $xml_encoding = ''; 06399 var $method = ''; 06400 var $root_struct = ''; 06401 var $root_struct_name = ''; 06402 var $root_struct_namespace = ''; 06403 var $root_header = ''; 06404 var $document = ''; // incoming SOAP body (text) 06405 // determines where in the message we are (envelope,header,body,method) 06406 var $status = ''; 06407 var $position = 0; 06408 var $depth = 0; 06409 var $default_namespace = ''; 06410 var $namespaces = array(); 06411 var $message = array(); 06412 var $parent = ''; 06413 var $fault = false; 06414 var $fault_code = ''; 06415 var $fault_str = ''; 06416 var $fault_detail = ''; 06417 var $depth_array = array(); 06418 var $debug_flag = true; 06419 var $soapresponse = NULL; // parsed SOAP Body 06420 var $soapheader = NULL; // parsed SOAP Header 06421 var $responseHeaders = ''; // incoming SOAP headers (text) 06422 var $body_position = 0; 06423 // for multiref parsing: 06424 // array of id => pos 06425 var $ids = array(); 06426 // array of id => hrefs => pos 06427 var $multirefs = array(); 06428 // toggle for auto-decoding element content 06429 var $decode_utf8 = true; 06430 06440 function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ 06441 parent::nusoap_base(); 06442 $this->xml = $xml; 06443 $this->xml_encoding = $encoding; 06444 $this->method = $method; 06445 $this->decode_utf8 = $decode_utf8; 06446 06447 // Check whether content has been read. 06448 if(!empty($xml)){ 06449 // Check XML encoding 06450 $pos_xml = strpos($xml, '<?xml'); 06451 if ($pos_xml !== FALSE) { 06452 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); 06453 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { 06454 $xml_encoding = $res[1]; 06455 if (strtoupper($xml_encoding) != $encoding) { 06456 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; 06457 $this->debug($err); 06458 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { 06459 $this->setError($err); 06460 return; 06461 } 06462 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed 06463 } else { 06464 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); 06465 } 06466 } else { 06467 $this->debug('No encoding specified in XML declaration'); 06468 } 06469 } else { 06470 $this->debug('No XML declaration'); 06471 } 06472 $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); 06473 // Create an XML parser - why not xml_parser_create_ns? 06474 $this->parser = xml_parser_create($this->xml_encoding); 06475 // Set the options for parsing the XML data. 06476 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 06477 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 06478 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); 06479 // Set the object for the parser. 06480 xml_set_object($this->parser, $this); 06481 // Set the element handlers for the parser. 06482 xml_set_element_handler($this->parser, 'start_element','end_element'); 06483 xml_set_character_data_handler($this->parser,'character_data'); 06484 06485 // Parse the XML file. 06486 if(!xml_parse($this->parser,$xml,true)){ 06487 // Display an error message. 06488 $err = sprintf('XML error parsing SOAP payload on line %d: %s', 06489 xml_get_current_line_number($this->parser), 06490 xml_error_string(xml_get_error_code($this->parser))); 06491 $this->debug($err); 06492 $this->debug("XML payload:\n" . $xml); 06493 $this->setError($err); 06494 } else { 06495 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); 06496 // get final value 06497 $this->soapresponse = $this->message[$this->root_struct]['result']; 06498 // get header value 06499 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ 06500 $this->soapheader = $this->message[$this->root_header]['result']; 06501 } 06502 // resolve hrefs/ids 06503 if(sizeof($this->multirefs) > 0){ 06504 foreach($this->multirefs as $id => $hrefs){ 06505 $this->debug('resolving multirefs for id: '.$id); 06506 $idVal = $this->buildVal($this->ids[$id]); 06507 if (is_array($idVal) && isset($idVal['!id'])) { 06508 unset($idVal['!id']); 06509 } 06510 foreach($hrefs as $refPos => $ref){ 06511 $this->debug('resolving href at pos '.$refPos); 06512 $this->multirefs[$id][$refPos] = $idVal; 06513 } 06514 } 06515 } 06516 } 06517 xml_parser_free($this->parser); 06518 } else { 06519 $this->debug('xml was empty, didn\'t parse!'); 06520 $this->setError('xml was empty, didn\'t parse!'); 06521 } 06522 } 06523 06532 function start_element($parser, $name, $attrs) { 06533 // position in a total number of elements, starting from 0 06534 // update class level pos 06535 $pos = $this->position++; 06536 // and set mine 06537 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); 06538 // depth = how many levels removed from root? 06539 // set mine as current global depth and increment global depth value 06540 $this->message[$pos]['depth'] = $this->depth++; 06541 06542 // else add self as child to whoever the current parent is 06543 if($pos != 0){ 06544 $this->message[$this->parent]['children'] .= '|'.$pos; 06545 } 06546 // set my parent 06547 $this->message[$pos]['parent'] = $this->parent; 06548 // set self as current parent 06549 $this->parent = $pos; 06550 // set self as current value for this depth 06551 $this->depth_array[$this->depth] = $pos; 06552 // get element prefix 06553 if(strpos($name,':')){ 06554 // get ns prefix 06555 $prefix = substr($name,0,strpos($name,':')); 06556 // get unqualified name 06557 $name = substr(strstr($name,':'),1); 06558 } 06559 // set status 06560 if($name == 'Envelope'){ 06561 $this->status = 'envelope'; 06562 } elseif($name == 'Header' && $this->status = 'envelope'){ 06563 $this->root_header = $pos; 06564 $this->status = 'header'; 06565 } elseif($name == 'Body' && $this->status = 'envelope'){ 06566 $this->status = 'body'; 06567 $this->body_position = $pos; 06568 // set method 06569 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){ 06570 $this->status = 'method'; 06571 $this->root_struct_name = $name; 06572 $this->root_struct = $pos; 06573 $this->message[$pos]['type'] = 'struct'; 06574 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); 06575 } 06576 // set my status 06577 $this->message[$pos]['status'] = $this->status; 06578 // set name 06579 $this->message[$pos]['name'] = htmlspecialchars($name); 06580 // set attrs 06581 $this->message[$pos]['attrs'] = $attrs; 06582 06583 // loop through atts, logging ns and type declarations 06584 $attstr = ''; 06585 foreach($attrs as $key => $value){ 06586 $key_prefix = $this->getPrefix($key); 06587 $key_localpart = $this->getLocalPart($key); 06588 // if ns declarations, add to class level array of valid namespaces 06589 if($key_prefix == 'xmlns'){ 06590 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ 06591 $this->XMLSchemaVersion = $value; 06592 $this->namespaces['xsd'] = $this->XMLSchemaVersion; 06593 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; 06594 } 06595 $this->namespaces[$key_localpart] = $value; 06596 // set method namespace 06597 if($name == $this->root_struct_name){ 06598 $this->methodNamespace = $value; 06599 } 06600 // if it's a type declaration, set type 06601 } elseif($key_localpart == 'type'){ 06602 if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { 06603 // do nothing: already processed arrayType 06604 } else { 06605 $value_prefix = $this->getPrefix($value); 06606 $value_localpart = $this->getLocalPart($value); 06607 $this->message[$pos]['type'] = $value_localpart; 06608 $this->message[$pos]['typePrefix'] = $value_prefix; 06609 if(isset($this->namespaces[$value_prefix])){ 06610 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; 06611 } else if(isset($attrs['xmlns:'.$value_prefix])) { 06612 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; 06613 } 06614 // should do something here with the namespace of specified type? 06615 } 06616 } elseif($key_localpart == 'arrayType'){ 06617 $this->message[$pos]['type'] = 'array'; 06618 /* do arrayType ereg here 06619 [1] arrayTypeValue ::= atype asize 06620 [2] atype ::= QName rank* 06621 [3] rank ::= '[' (',')* ']' 06622 [4] asize ::= '[' length~ ']' 06623 [5] length ::= nextDimension* Digit+ 06624 [6] nextDimension ::= Digit+ ',' 06625 */ 06626 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; 06627 if(ereg($expr,$value,$regs)){ 06628 $this->message[$pos]['typePrefix'] = $regs[1]; 06629 $this->message[$pos]['arrayTypePrefix'] = $regs[1]; 06630 if (isset($this->namespaces[$regs[1]])) { 06631 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; 06632 } else if (isset($attrs['xmlns:'.$regs[1]])) { 06633 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; 06634 } 06635 $this->message[$pos]['arrayType'] = $regs[2]; 06636 $this->message[$pos]['arraySize'] = $regs[3]; 06637 $this->message[$pos]['arrayCols'] = $regs[4]; 06638 } 06639 // specifies nil value (or not) 06640 } elseif ($key_localpart == 'nil'){ 06641 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); 06642 // some other attribute 06643 } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { 06644 $this->message[$pos]['xattrs']['!' . $key] = $value; 06645 } 06646 06647 if ($key == 'xmlns') { 06648 $this->default_namespace = $value; 06649 } 06650 // log id 06651 if($key == 'id'){ 06652 $this->ids[$value] = $pos; 06653 } 06654 // root 06655 if($key_localpart == 'root' && $value == 1){ 06656 $this->status = 'method'; 06657 $this->root_struct_name = $name; 06658 $this->root_struct = $pos; 06659 $this->debug("found root struct $this->root_struct_name, pos $pos"); 06660 } 06661 // for doclit 06662 $attstr .= " $key=\"$value\""; 06663 } 06664 // get namespace - must be done after namespace atts are processed 06665 if(isset($prefix)){ 06666 $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; 06667 $this->default_namespace = $this->namespaces[$prefix]; 06668 } else { 06669 $this->message[$pos]['namespace'] = $this->default_namespace; 06670 } 06671 if($this->status == 'header'){ 06672 if ($this->root_header != $pos) { 06673 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 06674 } 06675 } elseif($this->root_struct_name != ''){ 06676 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 06677 } 06678 } 06679 06687 function end_element($parser, $name) { 06688 // position of current element is equal to the last value left in depth_array for my depth 06689 $pos = $this->depth_array[$this->depth--]; 06690 06691 // get element prefix 06692 if(strpos($name,':')){ 06693 // get ns prefix 06694 $prefix = substr($name,0,strpos($name,':')); 06695 // get unqualified name 06696 $name = substr(strstr($name,':'),1); 06697 } 06698 06699 // build to native type 06700 if(isset($this->body_position) && $pos > $this->body_position){ 06701 // deal w/ multirefs 06702 if(isset($this->message[$pos]['attrs']['href'])){ 06703 // get id 06704 $id = substr($this->message[$pos]['attrs']['href'],1); 06705 // add placeholder to href array 06706 $this->multirefs[$id][$pos] = 'placeholder'; 06707 // add set a reference to it as the result value 06708 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; 06709 // build complexType values 06710 } elseif($this->message[$pos]['children'] != ''){ 06711 // if result has already been generated (struct/array) 06712 if(!isset($this->message[$pos]['result'])){ 06713 $this->message[$pos]['result'] = $this->buildVal($pos); 06714 } 06715 // build complexType values of attributes and possibly simpleContent 06716 } elseif (isset($this->message[$pos]['xattrs'])) { 06717 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 06718 $this->message[$pos]['xattrs']['!'] = null; 06719 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 06720 if (isset($this->message[$pos]['type'])) { 06721 $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'] : ''); 06722 } else { 06723 $parent = $this->message[$pos]['parent']; 06724 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 06725 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 06726 } else { 06727 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; 06728 } 06729 } 06730 } 06731 $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; 06732 // set value of simpleType (or nil complexType) 06733 } else { 06734 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); 06735 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 06736 $this->message[$pos]['xattrs']['!'] = null; 06737 } elseif (isset($this->message[$pos]['type'])) { 06738 $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'] : ''); 06739 } else { 06740 $parent = $this->message[$pos]['parent']; 06741 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 06742 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 06743 } else { 06744 $this->message[$pos]['result'] = $this->message[$pos]['cdata']; 06745 } 06746 } 06747 06748 /* add value to parent's result, if parent is struct/array 06749 $parent = $this->message[$pos]['parent']; 06750 if($this->message[$parent]['type'] != 'map'){ 06751 if(strtolower($this->message[$parent]['type']) == 'array'){ 06752 $this->message[$parent]['result'][] = $this->message[$pos]['result']; 06753 } else { 06754 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; 06755 } 06756 } 06757 */ 06758 } 06759 } 06760 06761 // for doclit 06762 if($this->status == 'header'){ 06763 if ($this->root_header != $pos) { 06764 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 06765 } 06766 } elseif($pos >= $this->root_struct){ 06767 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 06768 } 06769 // switch status 06770 if($pos == $this->root_struct){ 06771 $this->status = 'body'; 06772 $this->root_struct_namespace = $this->message[$pos]['namespace']; 06773 } elseif($name == 'Body'){ 06774 $this->status = 'envelope'; 06775 } elseif($name == 'Header'){ 06776 $this->status = 'envelope'; 06777 } elseif($name == 'Envelope'){ 06778 // 06779 } 06780 // set parent back to my parent 06781 $this->parent = $this->message[$pos]['parent']; 06782 } 06783 06791 function character_data($parser, $data){ 06792 $pos = $this->depth_array[$this->depth]; 06793 if ($this->xml_encoding=='UTF-8'){ 06794 // TODO: add an option to disable this for folks who want 06795 // raw UTF-8 that, e.g., might not map to iso-8859-1 06796 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); 06797 if($this->decode_utf8){ 06798 $data = utf8_decode($data); 06799 } 06800 } 06801 $this->message[$pos]['cdata'] .= $data; 06802 // for doclit 06803 if($this->status == 'header'){ 06804 $this->responseHeaders .= $data; 06805 } else { 06806 $this->document .= $data; 06807 } 06808 } 06809 06817 function get_response(){ 06818 return $this->soapresponse; 06819 } 06820 06827 function get_soapbody(){ 06828 return $this->soapresponse; 06829 } 06830 06837 function get_soapheader(){ 06838 return $this->soapheader; 06839 } 06840 06847 function getHeaders(){ 06848 return $this->responseHeaders; 06849 } 06850 06860 function decodeSimple($value, $type, $typens) { 06861 // TODO: use the namespace! 06862 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { 06863 return (string) $value; 06864 } 06865 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { 06866 return (int) $value; 06867 } 06868 if ($type == 'float' || $type == 'double' || $type == 'decimal') { 06869 return (double) $value; 06870 } 06871 if ($type == 'boolean') { 06872 if (strtolower($value) == 'false' || strtolower($value) == 'f') { 06873 return false; 06874 } 06875 return (boolean) $value; 06876 } 06877 if ($type == 'base64' || $type == 'base64Binary') { 06878 $this->debug('Decode base64 value'); 06879 return base64_decode($value); 06880 } 06881 // obscure numeric types 06882 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' 06883 || $type == 'nonNegativeInteger' || $type == 'positiveInteger' 06884 || $type == 'unsignedInt' 06885 || $type == 'unsignedShort' || $type == 'unsignedByte') { 06886 return (int) $value; 06887 } 06888 // bogus: parser treats array with no elements as a simple type 06889 if ($type == 'array') { 06890 return array(); 06891 } 06892 // everything else 06893 return (string) $value; 06894 } 06895 06904 function buildVal($pos){ 06905 if(!isset($this->message[$pos]['type'])){ 06906 $this->message[$pos]['type'] = ''; 06907 } 06908 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); 06909 // if there are children... 06910 if($this->message[$pos]['children'] != ''){ 06911 $this->debug('in buildVal, there are children'); 06912 $children = explode('|',$this->message[$pos]['children']); 06913 array_shift($children); // knock off empty 06914 // md array 06915 if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ 06916 $r=0; // rowcount 06917 $c=0; // colcount 06918 foreach($children as $child_pos){ 06919 $this->debug("in buildVal, got an MD array element: $r, $c"); 06920 $params[$r][] = $this->message[$child_pos]['result']; 06921 $c++; 06922 if($c == $this->message[$pos]['arrayCols']){ 06923 $c = 0; 06924 $r++; 06925 } 06926 } 06927 // array 06928 } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ 06929 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); 06930 foreach($children as $child_pos){ 06931 $params[] = &$this->message[$child_pos]['result']; 06932 } 06933 // apache Map type: java hashtable 06934 } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ 06935 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); 06936 foreach($children as $child_pos){ 06937 $kv = explode("|",$this->message[$child_pos]['children']); 06938 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; 06939 } 06940 // generic compound type 06941 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { 06942 } else { 06943 // Apache Vector type: treat as an array 06944 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); 06945 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { 06946 $notstruct = 1; 06947 } else { 06948 $notstruct = 0; 06949 } 06950 // 06951 foreach($children as $child_pos){ 06952 if($notstruct){ 06953 $params[] = &$this->message[$child_pos]['result']; 06954 } else { 06955 if (isset($params[$this->message[$child_pos]['name']])) { 06956 // de-serialize repeated element name into an array 06957 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { 06958 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); 06959 } 06960 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; 06961 } else { 06962 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; 06963 } 06964 } 06965 } 06966 } 06967 if (isset($this->message[$pos]['xattrs'])) { 06968 $this->debug('in buildVal, handling attributes'); 06969 foreach ($this->message[$pos]['xattrs'] as $n => $v) { 06970 $params[$n] = $v; 06971 } 06972 } 06973 // handle simpleContent 06974 if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 06975 $this->debug('in buildVal, handling simpleContent'); 06976 if (isset($this->message[$pos]['type'])) { 06977 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 06978 } else { 06979 $parent = $this->message[$pos]['parent']; 06980 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 06981 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 06982 } else { 06983 $params['!'] = $this->message[$pos]['cdata']; 06984 } 06985 } 06986 } 06987 $ret = is_array($params) ? $params : array(); 06988 $this->debug('in buildVal, return:'); 06989 $this->appendDebug($this->varDump($ret)); 06990 return $ret; 06991 } else { 06992 $this->debug('in buildVal, no children, building scalar'); 06993 $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; 06994 if (isset($this->message[$pos]['type'])) { 06995 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 06996 $this->debug("in buildVal, return: $ret"); 06997 return $ret; 06998 } 06999 $parent = $this->message[$pos]['parent']; 07000 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 07001 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 07002 $this->debug("in buildVal, return: $ret"); 07003 return $ret; 07004 } 07005 $ret = $this->message[$pos]['cdata']; 07006 $this->debug("in buildVal, return: $ret"); 07007 return $ret; 07008 } 07009 } 07010 } 07011 07015 class soap_parser extends nusoap_parser { 07016 } 07017 07018 ?><?php 07019 07020 07021 07042 class nusoap_client extends nusoap_base { 07043 07044 var $username = ''; // Username for HTTP authentication 07045 var $password = ''; // Password for HTTP authentication 07046 var $authtype = ''; // Type of HTTP authentication 07047 var $certRequest = array(); // Certificate for HTTP SSL authentication 07048 var $requestHeaders = false; // SOAP headers in request (text) 07049 var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) 07050 var $responseHeader = NULL; // SOAP Header from response (parsed) 07051 var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) 07052 var $endpoint; 07053 var $forceEndpoint = ''; // overrides WSDL endpoint 07054 var $proxyhost = ''; 07055 var $proxyport = ''; 07056 var $proxyusername = ''; 07057 var $proxypassword = ''; 07058 var $xml_encoding = ''; // character set encoding of incoming (response) messages 07059 var $http_encoding = false; 07060 var $timeout = 0; // HTTP connection timeout 07061 var $response_timeout = 30; // HTTP response timeout 07062 var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error 07063 var $persistentConnection = false; 07064 var $defaultRpcParams = false; // This is no longer used 07065 var $request = ''; // HTTP request 07066 var $response = ''; // HTTP response 07067 var $responseData = ''; // SOAP payload of response 07068 var $cookies = array(); // Cookies from response or for request 07069 var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() 07070 var $operations = array(); // WSDL operations, empty for WSDL initialization error 07071 var $curl_options = array(); // User-specified cURL options 07072 var $bindingType = ''; // WSDL operation binding type 07073 var $use_curl = false; // whether to always try to use cURL 07074 07075 /* 07076 * fault related variables 07077 */ 07082 var $fault; 07087 var $faultcode; 07092 var $faultstring; 07097 var $faultdetail; 07098 07113 function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ 07114 parent::nusoap_base(); 07115 $this->endpoint = $endpoint; 07116 $this->proxyhost = $proxyhost; 07117 $this->proxyport = $proxyport; 07118 $this->proxyusername = $proxyusername; 07119 $this->proxypassword = $proxypassword; 07120 $this->timeout = $timeout; 07121 $this->response_timeout = $response_timeout; 07122 07123 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 07124 $this->appendDebug('endpoint=' . $this->varDump($endpoint)); 07125 07126 // make values 07127 if($wsdl){ 07128 if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { 07129 $this->wsdl = $endpoint; 07130 $this->endpoint = $this->wsdl->wsdl; 07131 $this->wsdlFile = $this->endpoint; 07132 $this->debug('existing wsdl instance created from ' . $this->endpoint); 07133 $this->checkWSDL(); 07134 } else { 07135 $this->wsdlFile = $this->endpoint; 07136 $this->wsdl = null; 07137 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); 07138 } 07139 $this->endpointType = 'wsdl'; 07140 } else { 07141 $this->debug("instantiate SOAP with endpoint at $endpoint"); 07142 $this->endpointType = 'soap'; 07143 } 07144 } 07145 07171 function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ 07172 $this->operation = $operation; 07173 $this->fault = false; 07174 $this->setError(''); 07175 $this->request = ''; 07176 $this->response = ''; 07177 $this->responseData = ''; 07178 $this->faultstring = ''; 07179 $this->faultcode = ''; 07180 $this->opData = array(); 07181 07182 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); 07183 $this->appendDebug('params=' . $this->varDump($params)); 07184 $this->appendDebug('headers=' . $this->varDump($headers)); 07185 if ($headers) { 07186 $this->requestHeaders = $headers; 07187 } 07188 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07189 $this->loadWSDL(); 07190 if ($this->getError()) 07191 return false; 07192 } 07193 // serialize parameters 07194 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ 07195 // use WSDL for operation 07196 $this->opData = $opData; 07197 $this->debug("found operation"); 07198 $this->appendDebug('opData=' . $this->varDump($opData)); 07199 if (isset($opData['soapAction'])) { 07200 $soapAction = $opData['soapAction']; 07201 } 07202 if (! $this->forceEndpoint) { 07203 $this->endpoint = $opData['endpoint']; 07204 } else { 07205 $this->endpoint = $this->forceEndpoint; 07206 } 07207 $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; 07208 $style = $opData['style']; 07209 $use = $opData['input']['use']; 07210 // add ns to ns array 07211 if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ 07212 $nsPrefix = 'ns' . rand(1000, 9999); 07213 $this->wsdl->namespaces[$nsPrefix] = $namespace; 07214 } 07215 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); 07216 // serialize payload 07217 if (is_string($params)) { 07218 $this->debug("serializing param string for WSDL operation $operation"); 07219 $payload = $params; 07220 } elseif (is_array($params)) { 07221 $this->debug("serializing param array for WSDL operation $operation"); 07222 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); 07223 } else { 07224 $this->debug('params must be array or string'); 07225 $this->setError('params must be array or string'); 07226 return false; 07227 } 07228 $usedNamespaces = $this->wsdl->usedNamespaces; 07229 if (isset($opData['input']['encodingStyle'])) { 07230 $encodingStyle = $opData['input']['encodingStyle']; 07231 } else { 07232 $encodingStyle = ''; 07233 } 07234 $this->appendDebug($this->wsdl->getDebug()); 07235 $this->wsdl->clearDebug(); 07236 if ($errstr = $this->wsdl->getError()) { 07237 $this->debug('got wsdl error: '.$errstr); 07238 $this->setError('wsdl error: '.$errstr); 07239 return false; 07240 } 07241 } elseif($this->endpointType == 'wsdl') { 07242 // operation not in WSDL 07243 $this->appendDebug($this->wsdl->getDebug()); 07244 $this->wsdl->clearDebug(); 07245 $this->setError( 'operation '.$operation.' not present.'); 07246 $this->debug("operation '$operation' not present."); 07247 return false; 07248 } else { 07249 // no WSDL 07250 //$this->namespaces['ns1'] = $namespace; 07251 $nsPrefix = 'ns' . rand(1000, 9999); 07252 // serialize 07253 $payload = ''; 07254 if (is_string($params)) { 07255 $this->debug("serializing param string for operation $operation"); 07256 $payload = $params; 07257 } elseif (is_array($params)) { 07258 $this->debug("serializing param array for operation $operation"); 07259 foreach($params as $k => $v){ 07260 $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); 07261 } 07262 } else { 07263 $this->debug('params must be array or string'); 07264 $this->setError('params must be array or string'); 07265 return false; 07266 } 07267 $usedNamespaces = array(); 07268 if ($use == 'encoded') { 07269 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 07270 } else { 07271 $encodingStyle = ''; 07272 } 07273 } 07274 // wrap RPC calls with method element 07275 if ($style == 'rpc') { 07276 if ($use == 'literal') { 07277 $this->debug("wrapping RPC request with literal method element"); 07278 if ($namespace) { 07279 // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 07280 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 07281 $payload . 07282 "</$nsPrefix:$operation>"; 07283 } else { 07284 $payload = "<$operation>" . $payload . "</$operation>"; 07285 } 07286 } else { 07287 $this->debug("wrapping RPC request with encoded method element"); 07288 if ($namespace) { 07289 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 07290 $payload . 07291 "</$nsPrefix:$operation>"; 07292 } else { 07293 $payload = "<$operation>" . 07294 $payload . 07295 "</$operation>"; 07296 } 07297 } 07298 } 07299 // serialize envelope 07300 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); 07301 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); 07302 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); 07303 // send 07304 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); 07305 if($errstr = $this->getError()){ 07306 $this->debug('Error: '.$errstr); 07307 return false; 07308 } else { 07309 $this->return = $return; 07310 $this->debug('sent message successfully and got a(n) '.gettype($return)); 07311 $this->appendDebug('return=' . $this->varDump($return)); 07312 07313 // fault? 07314 if(is_array($return) && isset($return['faultcode'])){ 07315 $this->debug('got fault'); 07316 $this->setError($return['faultcode'].': '.$return['faultstring']); 07317 $this->fault = true; 07318 foreach($return as $k => $v){ 07319 $this->$k = $v; 07320 $this->debug("$k = $v<br>"); 07321 } 07322 return $return; 07323 } elseif ($style == 'document') { 07324 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), 07325 // we are only going to return the first part here...sorry about that 07326 return $return; 07327 } else { 07328 // array of return values 07329 if(is_array($return)){ 07330 // multiple 'out' parameters, which we return wrapped up 07331 // in the array 07332 if(sizeof($return) > 1){ 07333 return $return; 07334 } 07335 // single 'out' parameter (normally the return value) 07336 $return = array_shift($return); 07337 $this->debug('return shifted value: '); 07338 $this->appendDebug($this->varDump($return)); 07339 return $return; 07340 // nothing returned (ie, echoVoid) 07341 } else { 07342 return ""; 07343 } 07344 } 07345 } 07346 } 07347 07353 function checkWSDL() { 07354 $this->appendDebug($this->wsdl->getDebug()); 07355 $this->wsdl->clearDebug(); 07356 $this->debug('checkWSDL'); 07357 // catch errors 07358 if ($errstr = $this->wsdl->getError()) { 07359 $this->debug('got wsdl error: '.$errstr); 07360 $this->setError('wsdl error: '.$errstr); 07361 } elseif ($this->operations = $this->wsdl->getOperations('soap')) { 07362 $this->bindingType = 'soap'; 07363 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 07364 } elseif ($this->operations = $this->wsdl->getOperations('soap12')) { 07365 $this->bindingType = 'soap12'; 07366 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 07367 $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); 07368 } else { 07369 $this->debug('getOperations returned false'); 07370 $this->setError('no operations defined in the WSDL document!'); 07371 } 07372 } 07373 07379 function loadWSDL() { 07380 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); 07381 $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); 07382 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); 07383 $this->wsdl->fetchWSDL($this->wsdlFile); 07384 $this->checkWSDL(); 07385 } 07386 07394 function getOperationData($operation){ 07395 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07396 $this->loadWSDL(); 07397 if ($this->getError()) 07398 return false; 07399 } 07400 if(isset($this->operations[$operation])){ 07401 return $this->operations[$operation]; 07402 } 07403 $this->debug("No data for operation: $operation"); 07404 } 07405 07420 function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { 07421 $this->checkCookies(); 07422 // detect transport 07423 switch(true){ 07424 // http(s) 07425 case ereg('^http',$this->endpoint): 07426 $this->debug('transporting via HTTP'); 07427 if($this->persistentConnection == true && is_object($this->persistentConnection)){ 07428 $http =& $this->persistentConnection; 07429 } else { 07430 $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); 07431 if ($this->persistentConnection) { 07432 $http->usePersistentConnection(); 07433 } 07434 } 07435 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); 07436 $http->setSOAPAction($soapaction); 07437 if($this->proxyhost && $this->proxyport){ 07438 $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 07439 } 07440 if($this->authtype != '') { 07441 $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 07442 } 07443 if($this->http_encoding != ''){ 07444 $http->setEncoding($this->http_encoding); 07445 } 07446 $this->debug('sending message, length='.strlen($msg)); 07447 if(ereg('^http:',$this->endpoint)){ 07448 //if(strpos($this->endpoint,'http:')){ 07449 $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); 07450 } elseif(ereg('^https',$this->endpoint)){ 07451 //} elseif(strpos($this->endpoint,'https:')){ 07452 //if(phpversion() == '4.3.0-dev'){ 07453 //$response = $http->send($msg,$timeout,$response_timeout); 07454 //$this->request = $http->outgoing_payload; 07455 //$this->response = $http->incoming_payload; 07456 //} else 07457 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); 07458 } else { 07459 $this->setError('no http/s in endpoint url'); 07460 } 07461 $this->request = $http->outgoing_payload; 07462 $this->response = $http->incoming_payload; 07463 $this->appendDebug($http->getDebug()); 07464 $this->UpdateCookies($http->incoming_cookies); 07465 07466 // save transport object if using persistent connections 07467 if ($this->persistentConnection) { 07468 $http->clearDebug(); 07469 if (!is_object($this->persistentConnection)) { 07470 $this->persistentConnection = $http; 07471 } 07472 } 07473 07474 if($err = $http->getError()){ 07475 $this->setError('HTTP Error: '.$err); 07476 return false; 07477 } elseif($this->getError()){ 07478 return false; 07479 } else { 07480 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); 07481 return $this->parseResponse($http->incoming_headers, $this->responseData); 07482 } 07483 break; 07484 default: 07485 $this->setError('no transport found, or selected transport is not yet supported!'); 07486 return false; 07487 break; 07488 } 07489 } 07490 07499 function parseResponse($headers, $data) { 07500 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); 07501 $this->appendDebug($this->varDump($headers)); 07502 if (!strstr($headers['content-type'], 'text/xml')) { 07503 $this->setError('Response not of type text/xml: ' . $headers['content-type']); 07504 return false; 07505 } 07506 if (strpos($headers['content-type'], '=')) { 07507 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 07508 $this->debug('Got response encoding: ' . $enc); 07509 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 07510 $this->xml_encoding = strtoupper($enc); 07511 } else { 07512 $this->xml_encoding = 'US-ASCII'; 07513 } 07514 } else { 07515 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 07516 $this->xml_encoding = 'ISO-8859-1'; 07517 } 07518 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 07519 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); 07520 // add parser debug data to our debug 07521 $this->appendDebug($parser->getDebug()); 07522 // if parse errors 07523 if($errstr = $parser->getError()){ 07524 $this->setError( $errstr); 07525 // destroy the parser object 07526 unset($parser); 07527 return false; 07528 } else { 07529 // get SOAP headers 07530 $this->responseHeaders = $parser->getHeaders(); 07531 // get SOAP headers 07532 $this->responseHeader = $parser->get_soapheader(); 07533 // get decoded message 07534 $return = $parser->get_soapbody(); 07535 // add document for doclit support 07536 $this->document = $parser->document; 07537 // destroy the parser object 07538 unset($parser); 07539 // return decode message 07540 return $return; 07541 } 07542 } 07543 07551 function setCurlOption($option, $value) { 07552 $this->debug("setCurlOption option=$option, value="); 07553 $this->appendDebug($this->varDump($value)); 07554 $this->curl_options[$option] = $value; 07555 } 07556 07563 function setEndpoint($endpoint) { 07564 $this->debug("setEndpoint(\"$endpoint\")"); 07565 $this->forceEndpoint = $endpoint; 07566 } 07567 07574 function setHeaders($headers){ 07575 $this->debug("setHeaders headers="); 07576 $this->appendDebug($this->varDump($headers)); 07577 $this->requestHeaders = $headers; 07578 } 07579 07586 function getHeaders(){ 07587 return $this->responseHeaders; 07588 } 07589 07596 function getHeader(){ 07597 return $this->responseHeader; 07598 } 07599 07609 function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 07610 $this->proxyhost = $proxyhost; 07611 $this->proxyport = $proxyport; 07612 $this->proxyusername = $proxyusername; 07613 $this->proxypassword = $proxypassword; 07614 } 07615 07625 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 07626 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 07627 $this->appendDebug($this->varDump($certRequest)); 07628 $this->username = $username; 07629 $this->password = $password; 07630 $this->authtype = $authtype; 07631 $this->certRequest = $certRequest; 07632 } 07633 07640 function setHTTPEncoding($enc='gzip, deflate'){ 07641 $this->debug("setHTTPEncoding(\"$enc\")"); 07642 $this->http_encoding = $enc; 07643 } 07644 07651 function setUseCURL($use) { 07652 $this->debug("setUseCURL($use)"); 07653 $this->use_curl = $use; 07654 } 07655 07661 function useHTTPPersistentConnection(){ 07662 $this->debug("useHTTPPersistentConnection"); 07663 $this->persistentConnection = true; 07664 } 07665 07677 function getDefaultRpcParams() { 07678 return $this->defaultRpcParams; 07679 } 07680 07692 function setDefaultRpcParams($rpcParams) { 07693 $this->defaultRpcParams = $rpcParams; 07694 } 07695 07703 function getProxy() { 07704 $r = rand(); 07705 $evalStr = $this->_getProxyClassCode($r); 07706 //$this->debug("proxy class: $evalStr"); 07707 if ($this->getError()) { 07708 $this->debug("Error from _getProxyClassCode, so return NULL"); 07709 return null; 07710 } 07711 // eval the class 07712 eval($evalStr); 07713 // instantiate proxy object 07714 eval("\$proxy = new nusoap_proxy_$r('');"); 07715 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice 07716 $proxy->endpointType = 'wsdl'; 07717 $proxy->wsdlFile = $this->wsdlFile; 07718 $proxy->wsdl = $this->wsdl; 07719 $proxy->operations = $this->operations; 07720 $proxy->defaultRpcParams = $this->defaultRpcParams; 07721 // transfer other state 07722 $proxy->soap_defencoding = $this->soap_defencoding; 07723 $proxy->username = $this->username; 07724 $proxy->password = $this->password; 07725 $proxy->authtype = $this->authtype; 07726 $proxy->certRequest = $this->certRequest; 07727 $proxy->requestHeaders = $this->requestHeaders; 07728 $proxy->endpoint = $this->endpoint; 07729 $proxy->forceEndpoint = $this->forceEndpoint; 07730 $proxy->proxyhost = $this->proxyhost; 07731 $proxy->proxyport = $this->proxyport; 07732 $proxy->proxyusername = $this->proxyusername; 07733 $proxy->proxypassword = $this->proxypassword; 07734 $proxy->http_encoding = $this->http_encoding; 07735 $proxy->timeout = $this->timeout; 07736 $proxy->response_timeout = $this->response_timeout; 07737 $proxy->persistentConnection = &$this->persistentConnection; 07738 $proxy->decode_utf8 = $this->decode_utf8; 07739 $proxy->curl_options = $this->curl_options; 07740 $proxy->bindingType = $this->bindingType; 07741 $proxy->use_curl = $this->use_curl; 07742 return $proxy; 07743 } 07744 07751 function _getProxyClassCode($r) { 07752 $this->debug("in getProxy endpointType=$this->endpointType"); 07753 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); 07754 if ($this->endpointType != 'wsdl') { 07755 $evalStr = 'A proxy can only be created for a WSDL client'; 07756 $this->setError($evalStr); 07757 $evalStr = "echo \"$evalStr\";"; 07758 return $evalStr; 07759 } 07760 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07761 $this->loadWSDL(); 07762 if ($this->getError()) { 07763 return "echo \"" . $this->getError() . "\";"; 07764 } 07765 } 07766 $evalStr = ''; 07767 foreach ($this->operations as $operation => $opData) { 07768 if ($operation != '') { 07769 // create param string and param comment string 07770 if (sizeof($opData['input']['parts']) > 0) { 07771 $paramStr = ''; 07772 $paramArrayStr = ''; 07773 $paramCommentStr = ''; 07774 foreach ($opData['input']['parts'] as $name => $type) { 07775 $paramStr .= "\$$name, "; 07776 $paramArrayStr .= "'$name' => \$$name, "; 07777 $paramCommentStr .= "$type \$$name, "; 07778 } 07779 $paramStr = substr($paramStr, 0, strlen($paramStr)-2); 07780 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); 07781 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); 07782 } else { 07783 $paramStr = ''; 07784 $paramArrayStr = ''; 07785 $paramCommentStr = 'void'; 07786 } 07787 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; 07788 $evalStr .= "// $paramCommentStr 07789 function " . str_replace('.', '__', $operation) . "($paramStr) { 07790 \$params = array($paramArrayStr); 07791 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); 07792 } 07793 "; 07794 unset($paramStr); 07795 unset($paramCommentStr); 07796 } 07797 } 07798 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { 07799 '.$evalStr.' 07800 }'; 07801 return $evalStr; 07802 } 07803 07810 function getProxyClassCode() { 07811 $r = rand(); 07812 return $this->_getProxyClassCode($r); 07813 } 07814 07822 function getHTTPBody($soapmsg) { 07823 return $soapmsg; 07824 } 07825 07834 function getHTTPContentType() { 07835 return 'text/xml'; 07836 } 07837 07847 function getHTTPContentTypeCharset() { 07848 return $this->soap_defencoding; 07849 } 07850 07851 /* 07852 * whether or not parser should decode utf8 element content 07853 * 07854 * @return always returns true 07855 * @access public 07856 */ 07857 function decodeUTF8($bool){ 07858 $this->decode_utf8 = $bool; 07859 return true; 07860 } 07861 07870 function setCookie($name, $value) { 07871 if (strlen($name) == 0) { 07872 return false; 07873 } 07874 $this->cookies[] = array('name' => $name, 'value' => $value); 07875 return true; 07876 } 07877 07884 function getCookies() { 07885 return $this->cookies; 07886 } 07887 07894 function checkCookies() { 07895 if (sizeof($this->cookies) == 0) { 07896 return true; 07897 } 07898 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); 07899 $curr_cookies = $this->cookies; 07900 $this->cookies = array(); 07901 foreach ($curr_cookies as $cookie) { 07902 if (! is_array($cookie)) { 07903 $this->debug('Remove cookie that is not an array'); 07904 continue; 07905 } 07906 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 07907 if (strtotime($cookie['expires']) > time()) { 07908 $this->cookies[] = $cookie; 07909 } else { 07910 $this->debug('Remove expired cookie ' . $cookie['name']); 07911 } 07912 } else { 07913 $this->cookies[] = $cookie; 07914 } 07915 } 07916 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); 07917 return true; 07918 } 07919 07927 function UpdateCookies($cookies) { 07928 if (sizeof($this->cookies) == 0) { 07929 // no existing cookies: take whatever is new 07930 if (sizeof($cookies) > 0) { 07931 $this->debug('Setting new cookie(s)'); 07932 $this->cookies = $cookies; 07933 } 07934 return true; 07935 } 07936 if (sizeof($cookies) == 0) { 07937 // no new cookies: keep what we've got 07938 return true; 07939 } 07940 // merge 07941 foreach ($cookies as $newCookie) { 07942 if (!is_array($newCookie)) { 07943 continue; 07944 } 07945 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { 07946 continue; 07947 } 07948 $newName = $newCookie['name']; 07949 07950 $found = false; 07951 for ($i = 0; $i < count($this->cookies); $i++) { 07952 $cookie = $this->cookies[$i]; 07953 if (!is_array($cookie)) { 07954 continue; 07955 } 07956 if (!isset($cookie['name'])) { 07957 continue; 07958 } 07959 if ($newName != $cookie['name']) { 07960 continue; 07961 } 07962 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; 07963 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; 07964 if ($newDomain != $domain) { 07965 continue; 07966 } 07967 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; 07968 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; 07969 if ($newPath != $path) { 07970 continue; 07971 } 07972 $this->cookies[$i] = $newCookie; 07973 $found = true; 07974 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); 07975 break; 07976 } 07977 if (! $found) { 07978 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); 07979 $this->cookies[] = $newCookie; 07980 } 07981 } 07982 return true; 07983 } 07984 } 07985 07986 if (!extension_loaded('soap')) { 07990 class soapclient extends nusoap_client { 07991 } 07992 } 07993 ?>