Documentation TYPO3 par Ameos |
00001 <?php 00002 /* 00003 $Id: class.nusoap.php,v 1.1.2.1 2006/02/13 17:26:55 k-fish Exp $ 00004 00005 NuSOAP - Web Services Toolkit for PHP 00006 00007 Copyright (c) 2002 NuSphere Corporation 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Lesser General Public 00011 License as published by the Free Software Foundation; either 00012 version 2.1 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public 00020 License along with this library; if not, write to the Free Software 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 §§§§§ 00023 If you have any questions or comments, please email: 00024 00025 Dietrich Ayala 00026 dietrich@ganx4.com 00027 http://dietrich.ganx4.com/nusoap 00028 00029 NuSphere Corporation 00030 http://www.nusphere.com 00031 00032 */ 00033 00034 /* load classes 00035 00036 // necessary classes 00037 require_once('class.soapclient.php'); 00038 require_once('class.soap_val.php'); 00039 require_once('class.soap_parser.php'); 00040 require_once('class.soap_fault.php'); 00041 00042 // transport classes 00043 require_once('class.soap_transport_http.php'); 00044 00045 // optional add-on classes 00046 require_once('class.xmlschema.php'); 00047 require_once('class.wsdl.php'); 00048 */ 00049 00050 // class variable emulation 00051 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html 00052 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9; 00053 00062 class nusoap_base { 00069 var $title = 'NuSOAP'; 00076 var $version = '0.7.2'; 00083 var $revision = '$Revision: 1.1.2.1 $'; 00090 var $error_str = ''; 00097 var $debug_str = ''; 00105 var $charencoding = true; 00112 var $debugLevel; 00113 00120 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 00121 00128 var $soap_defencoding = 'ISO-8859-1'; 00129 //var $soap_defencoding = 'UTF-8'; 00130 00139 var $namespaces = array( 00140 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 00141 'xsd' => 'http://www.w3.org/2001/XMLSchema', 00142 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 00143 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 00144 ); 00145 00152 var $usedNamespaces = array(); 00153 00161 var $typemap = array( 00162 'http://www.w3.org/2001/XMLSchema' => array( 00163 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 00164 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 00165 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 00166 // abstract "any" types 00167 'anyType'=>'string','anySimpleType'=>'string', 00168 // derived datatypes 00169 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 00170 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 00171 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 00172 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 00173 'http://www.w3.org/2000/10/XMLSchema' => array( 00174 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00175 'float'=>'double','dateTime'=>'string', 00176 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00177 'http://www.w3.org/1999/XMLSchema' => array( 00178 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00179 'float'=>'double','dateTime'=>'string', 00180 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00181 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 00182 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 00183 'http://xml.apache.org/xml-soap' => array('Map') 00184 ); 00185 00194 var $xmlEntities = array('quot' => '"','amp' => '&', 00195 'lt' => '<','gt' => '>','apos' => "'"); 00196 00202 function nusoap_base() { 00203 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 00204 } 00205 00212 function getGlobalDebugLevel() { 00213 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 00214 } 00215 00222 function setGlobalDebugLevel($level) { 00223 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; 00224 } 00225 00232 function getDebugLevel() { 00233 return $this->debugLevel; 00234 } 00235 00242 function setDebugLevel($level) { 00243 $this->debugLevel = $level; 00244 } 00245 00252 function debug($string){ 00253 if ($this->debugLevel > 0) { 00254 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 00255 } 00256 } 00257 00264 function appendDebug($string){ 00265 if ($this->debugLevel > 0) { 00266 // it would be nice to use a memory stream here to use 00267 // memory more efficiently 00268 $this->debug_str .= $string; 00269 } 00270 } 00271 00277 function clearDebug() { 00278 // it would be nice to use a memory stream here to use 00279 // memory more efficiently 00280 $this->debug_str = ''; 00281 } 00282 00289 function &getDebug() { 00290 // it would be nice to use a memory stream here to use 00291 // memory more efficiently 00292 return $this->debug_str; 00293 } 00294 00302 function &getDebugAsXMLComment() { 00303 // it would be nice to use a memory stream here to use 00304 // memory more efficiently 00305 while (strpos($this->debug_str, '--')) { 00306 $this->debug_str = str_replace('--', '- -', $this->debug_str); 00307 } 00308 return "<!--\n" . $this->debug_str . "\n-->"; 00309 } 00310 00317 function expandEntities($val) { 00318 if ($this->charencoding) { 00319 $val = str_replace('&', '&', $val); 00320 $val = str_replace("'", ''', $val); 00321 $val = str_replace('"', '"', $val); 00322 $val = str_replace('<', '<', $val); 00323 $val = str_replace('>', '>', $val); 00324 } 00325 return $val; 00326 } 00327 00334 function getError(){ 00335 if($this->error_str != ''){ 00336 return $this->error_str; 00337 } 00338 return false; 00339 } 00340 00347 function setError($str){ 00348 $this->error_str = $str; 00349 } 00350 00358 function isArraySimpleOrStruct($val) { 00359 $keyList = array_keys($val); 00360 foreach ($keyList as $keyListValue) { 00361 if (!is_int($keyListValue)) { 00362 return 'arrayStruct'; 00363 } 00364 } 00365 return 'arraySimple'; 00366 } 00367 00382 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){ 00383 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use"); 00384 $this->appendDebug('value=' . $this->varDump($val)); 00385 $this->appendDebug('attributes=' . $this->varDump($attributes)); 00386 00387 if(is_object($val) && get_class($val) == 'soapval'){ 00388 return $val->serialize($use); 00389 } 00390 // force valid name if necessary 00391 if (is_numeric($name)) { 00392 $name = '__numeric_' . $name; 00393 } elseif (! $name) { 00394 $name = 'noname'; 00395 } 00396 // if name has ns, add ns prefix to name 00397 $xmlns = ''; 00398 if($name_ns){ 00399 $prefix = 'nu'.rand(1000,9999); 00400 $name = $prefix.':'.$name; 00401 $xmlns .= " xmlns:$prefix=\"$name_ns\""; 00402 } 00403 // if type is prefixed, create type prefix 00404 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 00405 // need to fix this. shouldn't default to xsd if no ns specified 00406 // w/o checking against typemap 00407 $type_prefix = 'xsd'; 00408 } elseif($type_ns){ 00409 $type_prefix = 'ns'.rand(1000,9999); 00410 $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 00411 } 00412 // serialize attributes if present 00413 $atts = ''; 00414 if($attributes){ 00415 foreach($attributes as $k => $v){ 00416 $atts .= " $k=\"".$this->expandEntities($v).'"'; 00417 } 00418 } 00419 // serialize null value 00420 if (is_null($val)) { 00421 if ($use == 'literal') { 00422 // TODO: depends on minOccurs 00423 return "<$name$xmlns $atts/>"; 00424 } else { 00425 if (isset($type) && isset($type_prefix)) { 00426 $type_str = " xsi:type=\"$type_prefix:$type\""; 00427 } else { 00428 $type_str = ''; 00429 } 00430 return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>"; 00431 } 00432 } 00433 // serialize if an xsd built-in primitive type 00434 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 00435 if (is_bool($val)) { 00436 if ($type == 'boolean') { 00437 $val = $val ? 'true' : 'false'; 00438 } elseif (! $val) { 00439 $val = 0; 00440 } 00441 } else if (is_string($val)) { 00442 $val = $this->expandEntities($val); 00443 } 00444 if ($use == 'literal') { 00445 return "<$name$xmlns $atts>$val</$name>"; 00446 } else { 00447 return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>"; 00448 } 00449 } 00450 // detect type and serialize 00451 $xml = ''; 00452 switch(true) { 00453 case (is_bool($val) || $type == 'boolean'): 00454 if ($type == 'boolean') { 00455 $val = $val ? 'true' : 'false'; 00456 } elseif (! $val) { 00457 $val = 0; 00458 } 00459 if ($use == 'literal') { 00460 $xml .= "<$name$xmlns $atts>$val</$name>"; 00461 } else { 00462 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; 00463 } 00464 break; 00465 case (is_int($val) || is_long($val) || $type == 'int'): 00466 if ($use == 'literal') { 00467 $xml .= "<$name$xmlns $atts>$val</$name>"; 00468 } else { 00469 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; 00470 } 00471 break; 00472 case (is_float($val)|| is_double($val) || $type == 'float'): 00473 if ($use == 'literal') { 00474 $xml .= "<$name$xmlns $atts>$val</$name>"; 00475 } else { 00476 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; 00477 } 00478 break; 00479 case (is_string($val) || $type == 'string'): 00480 $val = $this->expandEntities($val); 00481 if ($use == 'literal') { 00482 $xml .= "<$name$xmlns $atts>$val</$name>"; 00483 } else { 00484 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; 00485 } 00486 break; 00487 case is_object($val): 00488 if (! $name) { 00489 $name = get_class($val); 00490 $this->debug("In serialize_val, used class name $name as element name"); 00491 } else { 00492 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 00493 } 00494 foreach(get_object_vars($val) as $k => $v){ 00495 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 00496 } 00497 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>'; 00498 break; 00499 break; 00500 case (is_array($val) || $type): 00501 // detect if struct or array 00502 $valueType = $this->isArraySimpleOrStruct($val); 00503 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ 00504 $i = 0; 00505 if(is_array($val) && count($val)> 0){ 00506 foreach($val as $v){ 00507 if(is_object($v) && get_class($v) == 'soapval'){ 00508 $tt_ns = $v->type_ns; 00509 $tt = $v->type; 00510 } elseif (is_array($v)) { 00511 $tt = $this->isArraySimpleOrStruct($v); 00512 } else { 00513 $tt = gettype($v); 00514 } 00515 $array_types[$tt] = 1; 00516 // TODO: for literal, the name should be $name 00517 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 00518 ++$i; 00519 } 00520 if(count($array_types) > 1){ 00521 $array_typename = 'xsd:anyType'; 00522 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 00523 if ($tt == 'integer') { 00524 $tt = 'int'; 00525 } 00526 $array_typename = 'xsd:'.$tt; 00527 } elseif(isset($tt) && $tt == 'arraySimple'){ 00528 $array_typename = 'SOAP-ENC:Array'; 00529 } elseif(isset($tt) && $tt == 'arrayStruct'){ 00530 $array_typename = 'unnamed_struct_use_soapval'; 00531 } else { 00532 // if type is prefixed, create type prefix 00533 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 00534 $array_typename = 'xsd:' . $tt; 00535 } elseif ($tt_ns) { 00536 $tt_prefix = 'ns' . rand(1000, 9999); 00537 $array_typename = "$tt_prefix:$tt"; 00538 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 00539 } else { 00540 $array_typename = $tt; 00541 } 00542 } 00543 $array_type = $i; 00544 if ($use == 'literal') { 00545 $type_str = ''; 00546 } else if (isset($type) && isset($type_prefix)) { 00547 $type_str = " xsi:type=\"$type_prefix:$type\""; 00548 } else { 00549 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 00550 } 00551 // empty array 00552 } else { 00553 if ($use == 'literal') { 00554 $type_str = ''; 00555 } else if (isset($type) && isset($type_prefix)) { 00556 $type_str = " xsi:type=\"$type_prefix:$type\""; 00557 } else { 00558 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 00559 } 00560 } 00561 // TODO: for array in literal, there is no wrapper here 00562 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; 00563 } else { 00564 // got a struct 00565 if(isset($type) && isset($type_prefix)){ 00566 $type_str = " xsi:type=\"$type_prefix:$type\""; 00567 } else { 00568 $type_str = ''; 00569 } 00570 if ($use == 'literal') { 00571 $xml .= "<$name$xmlns $atts>"; 00572 } else { 00573 $xml .= "<$name$xmlns$type_str$atts>"; 00574 } 00575 foreach($val as $k => $v){ 00576 // Apache Map 00577 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 00578 $xml .= '<item>'; 00579 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 00580 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 00581 $xml .= '</item>'; 00582 } else { 00583 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 00584 } 00585 } 00586 $xml .= "</$name>"; 00587 } 00588 break; 00589 default: 00590 $xml .= 'not detected, got '.gettype($val).' for '.$val; 00591 break; 00592 } 00593 return $xml; 00594 } 00595 00608 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 00609 // TODO: add an option to automatically run utf8_encode on $body and $headers 00610 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 00611 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 00612 00613 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 00614 $this->debug("headers:"); 00615 $this->appendDebug($this->varDump($headers)); 00616 $this->debug("namespaces:"); 00617 $this->appendDebug($this->varDump($namespaces)); 00618 00619 // serialize namespaces 00620 $ns_string = ''; 00621 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 00622 $ns_string .= " xmlns:$k=\"$v\""; 00623 } 00624 if($encodingStyle) { 00625 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 00626 } 00627 00628 // serialize headers 00629 if($headers){ 00630 if (is_array($headers)) { 00631 $xml = ''; 00632 foreach ($headers as $header) { 00633 $xml .= $this->serialize_val($header, false, false, false, false, false, $use); 00634 } 00635 $headers = $xml; 00636 $this->debug("In serializeEnvelope, serialzied array of headers to $headers"); 00637 } 00638 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; 00639 } 00640 // serialize envelope 00641 return 00642 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". 00643 '<SOAP-ENV:Envelope'.$ns_string.">". 00644 $headers. 00645 "<SOAP-ENV:Body>". 00646 $body. 00647 "</SOAP-ENV:Body>". 00648 "</SOAP-ENV:Envelope>"; 00649 } 00650 00659 function formatDump($str){ 00660 $str = htmlspecialchars($str); 00661 return nl2br($str); 00662 } 00663 00671 function contractQname($qname){ 00672 // get element namespace 00673 //$this->xdebug("Contract $qname"); 00674 if (strrpos($qname, ':')) { 00675 // get unqualified name 00676 $name = substr($qname, strrpos($qname, ':') + 1); 00677 // get ns 00678 $ns = substr($qname, 0, strrpos($qname, ':')); 00679 $p = $this->getPrefixFromNamespace($ns); 00680 if ($p) { 00681 return $p . ':' . $name; 00682 } 00683 return $qname; 00684 } else { 00685 return $qname; 00686 } 00687 } 00688 00696 function expandQname($qname){ 00697 // get element prefix 00698 if(strpos($qname,':') && !ereg('^http://',$qname)){ 00699 // get unqualified name 00700 $name = substr(strstr($qname,':'),1); 00701 // get ns prefix 00702 $prefix = substr($qname,0,strpos($qname,':')); 00703 if(isset($this->namespaces[$prefix])){ 00704 return $this->namespaces[$prefix].':'.$name; 00705 } else { 00706 return $qname; 00707 } 00708 } else { 00709 return $qname; 00710 } 00711 } 00712 00721 function getLocalPart($str){ 00722 if($sstr = strrchr($str,':')){ 00723 // get unqualified name 00724 return substr( $sstr, 1 ); 00725 } else { 00726 return $str; 00727 } 00728 } 00729 00738 function getPrefix($str){ 00739 if($pos = strrpos($str,':')){ 00740 // get prefix 00741 return substr($str,0,$pos); 00742 } 00743 return false; 00744 } 00745 00753 function getNamespaceFromPrefix($prefix){ 00754 if (isset($this->namespaces[$prefix])) { 00755 return $this->namespaces[$prefix]; 00756 } 00757 //$this->setError("No namespace registered for prefix '$prefix'"); 00758 return false; 00759 } 00760 00769 function getPrefixFromNamespace($ns) { 00770 foreach ($this->namespaces as $p => $n) { 00771 if ($ns == $n || $ns == $p) { 00772 $this->usedNamespaces[$p] = $n; 00773 return $p; 00774 } 00775 } 00776 return false; 00777 } 00778 00785 function getmicrotime() { 00786 if (function_exists('gettimeofday')) { 00787 $tod = gettimeofday(); 00788 $sec = $tod['sec']; 00789 $usec = $tod['usec']; 00790 } else { 00791 $sec = time(); 00792 $usec = 0; 00793 } 00794 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 00795 } 00796 00804 function varDump($data) { 00805 ob_start(); 00806 var_dump($data); 00807 $ret_val = ob_get_contents(); 00808 ob_end_clean(); 00809 return $ret_val; 00810 } 00811 } 00812 00813 // XML Schema Datatype Helper Functions 00814 00815 //xsd:dateTime helpers 00816 00823 function timestamp_to_iso8601($timestamp,$utc=true){ 00824 $datestr = date('Y-m-d\TH:i:sO',$timestamp); 00825 if($utc){ 00826 $eregStr = 00827 '([0-9]{4})-'. // centuries & years CCYY- 00828 '([0-9]{2})-'. // months MM- 00829 '([0-9]{2})'. // days DD 00830 'T'. // separator T 00831 '([0-9]{2}):'. // hours hh: 00832 '([0-9]{2}):'. // minutes mm: 00833 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 00834 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00835 00836 if(ereg($eregStr,$datestr,$regs)){ 00837 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 00838 } 00839 return false; 00840 } else { 00841 return $datestr; 00842 } 00843 } 00844 00851 function iso8601_to_timestamp($datestr){ 00852 $eregStr = 00853 '([0-9]{4})-'. // centuries & years CCYY- 00854 '([0-9]{2})-'. // months MM- 00855 '([0-9]{2})'. // days DD 00856 'T'. // separator T 00857 '([0-9]{2}):'. // hours hh: 00858 '([0-9]{2}):'. // minutes mm: 00859 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 00860 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00861 if(ereg($eregStr,$datestr,$regs)){ 00862 // not utc 00863 if($regs[8] != 'Z'){ 00864 $op = substr($regs[8],0,1); 00865 $h = substr($regs[8],1,2); 00866 $m = substr($regs[8],strlen($regs[8])-2,2); 00867 if($op == '-'){ 00868 $regs[4] = $regs[4] + $h; 00869 $regs[5] = $regs[5] + $m; 00870 } elseif($op == '+'){ 00871 $regs[4] = $regs[4] - $h; 00872 $regs[5] = $regs[5] - $m; 00873 } 00874 } 00875 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 00876 } else { 00877 return false; 00878 } 00879 } 00880 00888 function usleepWindows($usec) 00889 { 00890 $start = gettimeofday(); 00891 00892 do 00893 { 00894 $stop = gettimeofday(); 00895 $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 00896 + $stop['usec'] - $start['usec']; 00897 } 00898 while ($timePassed < $usec); 00899 } 00900 00901 00902 00911 class soap_fault extends nusoap_base { 00917 var $faultcode; 00923 var $faultactor; 00929 var $faultstring; 00935 var $faultdetail; 00936 00945 function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ 00946 parent::nusoap_base(); 00947 $this->faultcode = $faultcode; 00948 $this->faultactor = $faultactor; 00949 $this->faultstring = $faultstring; 00950 $this->faultdetail = $faultdetail; 00951 } 00952 00959 function serialize(){ 00960 $ns_string = ''; 00961 foreach($this->namespaces as $k => $v){ 00962 $ns_string .= "\n xmlns:$k=\"$v\""; 00963 } 00964 $return_msg = 00965 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. 00966 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". 00967 '<SOAP-ENV:Body>'. 00968 '<SOAP-ENV:Fault>'. 00969 $this->serialize_val($this->faultcode, 'faultcode'). 00970 $this->serialize_val($this->faultactor, 'faultactor'). 00971 $this->serialize_val($this->faultstring, 'faultstring'). 00972 $this->serialize_val($this->faultdetail, 'detail'). 00973 '</SOAP-ENV:Fault>'. 00974 '</SOAP-ENV:Body>'. 00975 '</SOAP-ENV:Envelope>'; 00976 return $return_msg; 00977 } 00978 } 00979 00980 00981 00993 class XMLSchema extends nusoap_base { 00994 00995 // files 00996 var $schema = ''; 00997 var $xml = ''; 00998 // namespaces 00999 var $enclosingNamespaces; 01000 // schema info 01001 var $schemaInfo = array(); 01002 var $schemaTargetNamespace = ''; 01003 // types, elements, attributes defined by the schema 01004 var $attributes = array(); 01005 var $complexTypes = array(); 01006 var $complexTypeStack = array(); 01007 var $currentComplexType = null; 01008 var $elements = array(); 01009 var $elementStack = array(); 01010 var $currentElement = null; 01011 var $simpleTypes = array(); 01012 var $simpleTypeStack = array(); 01013 var $currentSimpleType = null; 01014 // imports 01015 var $imports = array(); 01016 // parser vars 01017 var $parser; 01018 var $position = 0; 01019 var $depth = 0; 01020 var $depth_array = array(); 01021 var $message = array(); 01022 var $defaultNamespace = array(); 01023 01032 function XMLSchema($schema='',$xml='',$namespaces=array()){ 01033 parent::nusoap_base(); 01034 $this->debug('xmlschema class instantiated, inside constructor'); 01035 // files 01036 $this->schema = $schema; 01037 $this->xml = $xml; 01038 01039 // namespaces 01040 $this->enclosingNamespaces = $namespaces; 01041 $this->namespaces = array_merge($this->namespaces, $namespaces); 01042 01043 // parse schema file 01044 if($schema != ''){ 01045 $this->debug('initial schema file: '.$schema); 01046 $this->parseFile($schema, 'schema'); 01047 } 01048 01049 // parse xml file 01050 if($xml != ''){ 01051 $this->debug('initial xml file: '.$xml); 01052 $this->parseFile($xml, 'xml'); 01053 } 01054 01055 } 01056 01065 function parseFile($xml,$type){ 01066 // parse xml file 01067 if($xml != ""){ 01068 $xmlStr = @join("",@file($xml)); 01069 if($xmlStr == ""){ 01070 $msg = 'Error reading XML from '.$xml; 01071 $this->setError($msg); 01072 $this->debug($msg); 01073 return false; 01074 } else { 01075 $this->debug("parsing $xml"); 01076 $this->parseString($xmlStr,$type); 01077 $this->debug("done parsing $xml"); 01078 return true; 01079 } 01080 } 01081 return false; 01082 } 01083 01091 function parseString($xml,$type){ 01092 // parse xml string 01093 if($xml != ""){ 01094 01095 // Create an XML parser. 01096 $this->parser = xml_parser_create(); 01097 // Set the options for parsing the XML data. 01098 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 01099 01100 // Set the object for the parser. 01101 xml_set_object($this->parser, $this); 01102 01103 // Set the element handlers for the parser. 01104 if($type == "schema"){ 01105 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); 01106 xml_set_character_data_handler($this->parser,'schemaCharacterData'); 01107 } elseif($type == "xml"){ 01108 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); 01109 xml_set_character_data_handler($this->parser,'xmlCharacterData'); 01110 } 01111 01112 // Parse the XML file. 01113 if(!xml_parse($this->parser,$xml,true)){ 01114 // Display an error message. 01115 $errstr = sprintf('XML error parsing XML schema on line %d: %s', 01116 xml_get_current_line_number($this->parser), 01117 xml_error_string(xml_get_error_code($this->parser)) 01118 ); 01119 $this->debug($errstr); 01120 $this->debug("XML payload:\n" . $xml); 01121 $this->setError($errstr); 01122 } 01123 01124 xml_parser_free($this->parser); 01125 } else{ 01126 $this->debug('no xml passed to parseString()!!'); 01127 $this->setError('no xml passed to parseString()!!'); 01128 } 01129 } 01130 01139 function schemaStartElement($parser, $name, $attrs) { 01140 01141 // position in the total number of elements, starting from 0 01142 $pos = $this->position++; 01143 $depth = $this->depth++; 01144 // set self as current value for this depth 01145 $this->depth_array[$depth] = $pos; 01146 $this->message[$pos] = array('cdata' => ''); 01147 if ($depth > 0) { 01148 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; 01149 } else { 01150 $this->defaultNamespace[$pos] = false; 01151 } 01152 01153 // get element prefix 01154 if($prefix = $this->getPrefix($name)){ 01155 // get unqualified name 01156 $name = $this->getLocalPart($name); 01157 } else { 01158 $prefix = ''; 01159 } 01160 01161 // loop thru attributes, expanding, and registering namespace declarations 01162 if(count($attrs) > 0){ 01163 foreach($attrs as $k => $v){ 01164 // if ns declarations, add to class level array of valid namespaces 01165 if(ereg("^xmlns",$k)){ 01166 //$this->xdebug("$k: $v"); 01167 //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); 01168 if($ns_prefix = substr(strrchr($k,':'),1)){ 01169 //$this->xdebug("Add namespace[$ns_prefix] = $v"); 01170 $this->namespaces[$ns_prefix] = $v; 01171 } else { 01172 $this->defaultNamespace[$pos] = $v; 01173 if (! $this->getPrefixFromNamespace($v)) { 01174 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; 01175 } 01176 } 01177 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ 01178 $this->XMLSchemaVersion = $v; 01179 $this->namespaces['xsi'] = $v.'-instance'; 01180 } 01181 } 01182 } 01183 foreach($attrs as $k => $v){ 01184 // expand each attribute 01185 $k = strpos($k,':') ? $this->expandQname($k) : $k; 01186 $v = strpos($v,':') ? $this->expandQname($v) : $v; 01187 $eAttrs[$k] = $v; 01188 } 01189 $attrs = $eAttrs; 01190 } else { 01191 $attrs = array(); 01192 } 01193 // find status, register data 01194 switch($name){ 01195 case 'all': // (optional) compositor content for a complexType 01196 case 'choice': 01197 case 'group': 01198 case 'sequence': 01199 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); 01200 $this->complexTypes[$this->currentComplexType]['compositor'] = $name; 01201 //if($name == 'all' || $name == 'sequence'){ 01202 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01203 //} 01204 break; 01205 case 'attribute': // complexType attribute 01206 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); 01207 $this->xdebug("parsing attribute:"); 01208 $this->appendDebug($this->varDump($attrs)); 01209 if (!isset($attrs['form'])) { 01210 $attrs['form'] = $this->schemaInfo['attributeFormDefault']; 01211 } 01212 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01213 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01214 if (!strpos($v, ':')) { 01215 // no namespace in arrayType attribute value... 01216 if ($this->defaultNamespace[$pos]) { 01217 // ...so use the default 01218 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01219 } 01220 } 01221 } 01222 if(isset($attrs['name'])){ 01223 $this->attributes[$attrs['name']] = $attrs; 01224 $aname = $attrs['name']; 01225 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ 01226 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01227 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01228 } else { 01229 $aname = ''; 01230 } 01231 } elseif(isset($attrs['ref'])){ 01232 $aname = $attrs['ref']; 01233 $this->attributes[$attrs['ref']] = $attrs; 01234 } 01235 01236 if($this->currentComplexType){ // This should *always* be 01237 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; 01238 } 01239 // arrayType attribute 01240 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ 01241 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01242 $prefix = $this->getPrefix($aname); 01243 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ 01244 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01245 } else { 01246 $v = ''; 01247 } 01248 if(strpos($v,'[,]')){ 01249 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; 01250 } 01251 $v = substr($v,0,strpos($v,'[')); // clip the [] 01252 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ 01253 $v = $this->XMLSchemaVersion.':'.$v; 01254 } 01255 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; 01256 } 01257 break; 01258 case 'complexContent': // (optional) content for a complexType 01259 break; 01260 case 'complexType': 01261 array_push($this->complexTypeStack, $this->currentComplexType); 01262 if(isset($attrs['name'])){ 01263 $this->xdebug('processing named complexType '.$attrs['name']); 01264 //$this->currentElement = false; 01265 $this->currentComplexType = $attrs['name']; 01266 $this->complexTypes[$this->currentComplexType] = $attrs; 01267 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01268 // This is for constructs like 01269 // <complexType name="ListOfString" base="soap:Array"> 01270 // <sequence> 01271 // <element name="string" type="xsd:string" 01272 // minOccurs="0" maxOccurs="unbounded" /> 01273 // </sequence> 01274 // </complexType> 01275 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01276 $this->xdebug('complexType is unusual array'); 01277 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01278 } else { 01279 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01280 } 01281 }else{ 01282 $this->xdebug('processing unnamed complexType for element '.$this->currentElement); 01283 $this->currentComplexType = $this->currentElement . '_ContainedType'; 01284 //$this->currentElement = false; 01285 $this->complexTypes[$this->currentComplexType] = $attrs; 01286 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01287 // This is for constructs like 01288 // <complexType name="ListOfString" base="soap:Array"> 01289 // <sequence> 01290 // <element name="string" type="xsd:string" 01291 // minOccurs="0" maxOccurs="unbounded" /> 01292 // </sequence> 01293 // </complexType> 01294 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01295 $this->xdebug('complexType is unusual array'); 01296 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01297 } else { 01298 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01299 } 01300 } 01301 break; 01302 case 'element': 01303 array_push($this->elementStack, $this->currentElement); 01304 // elements defined as part of a complex type should 01305 // not really be added to $this->elements, but for some 01306 // reason, they are 01307 if (!isset($attrs['form'])) { 01308 $attrs['form'] = $this->schemaInfo['elementFormDefault']; 01309 } 01310 if(isset($attrs['type'])){ 01311 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); 01312 if (! $this->getPrefix($attrs['type'])) { 01313 if ($this->defaultNamespace[$pos]) { 01314 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; 01315 $this->xdebug('used default namespace to make type ' . $attrs['type']); 01316 } 01317 } 01318 // This is for constructs like 01319 // <complexType name="ListOfString" base="soap:Array"> 01320 // <sequence> 01321 // <element name="string" type="xsd:string" 01322 // minOccurs="0" maxOccurs="unbounded" /> 01323 // </sequence> 01324 // </complexType> 01325 if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { 01326 $this->xdebug('arrayType for unusual array is ' . $attrs['type']); 01327 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; 01328 } 01329 $this->currentElement = $attrs['name']; 01330 $this->elements[ $attrs['name'] ] = $attrs; 01331 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01332 $ename = $attrs['name']; 01333 } elseif(isset($attrs['ref'])){ 01334 $this->xdebug("processing element as ref to ".$attrs['ref']); 01335 $this->currentElement = "ref to ".$attrs['ref']; 01336 $ename = $this->getLocalPart($attrs['ref']); 01337 } else { 01338 $this->xdebug("processing untyped element ".$attrs['name']); 01339 $this->currentElement = $attrs['name']; 01340 $this->elements[ $attrs['name'] ] = $attrs; 01341 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01342 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType'; 01343 $this->elements[ $attrs['name'] ]['type'] = $attrs['type']; 01344 $ename = $attrs['name']; 01345 } 01346 if(isset($ename) && $this->currentComplexType){ 01347 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; 01348 } 01349 break; 01350 case 'enumeration': // restriction value list member 01351 $this->xdebug('enumeration ' . $attrs['value']); 01352 if ($this->currentSimpleType) { 01353 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; 01354 } elseif ($this->currentComplexType) { 01355 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; 01356 } 01357 break; 01358 case 'extension': // simpleContent or complexContent type extension 01359 $this->xdebug('extension ' . $attrs['base']); 01360 if ($this->currentComplexType) { 01361 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; 01362 } 01363 break; 01364 case 'import': 01365 if (isset($attrs['schemaLocation'])) { 01366 //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); 01367 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 01368 } else { 01369 //$this->xdebug('import namespace ' . $attrs['namespace']); 01370 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 01371 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 01372 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 01373 } 01374 } 01375 break; 01376 case 'list': // simpleType value list 01377 break; 01378 case 'restriction': // simpleType, simpleContent or complexContent value restriction 01379 $this->xdebug('restriction ' . $attrs['base']); 01380 if($this->currentSimpleType){ 01381 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; 01382 } elseif($this->currentComplexType){ 01383 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; 01384 if(strstr($attrs['base'],':') == ':Array'){ 01385 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01386 } 01387 } 01388 break; 01389 case 'schema': 01390 $this->schemaInfo = $attrs; 01391 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); 01392 if (isset($attrs['targetNamespace'])) { 01393 $this->schemaTargetNamespace = $attrs['targetNamespace']; 01394 } 01395 if (!isset($attrs['elementFormDefault'])) { 01396 $this->schemaInfo['elementFormDefault'] = 'unqualified'; 01397 } 01398 if (!isset($attrs['attributeFormDefault'])) { 01399 $this->schemaInfo['attributeFormDefault'] = 'unqualified'; 01400 } 01401 break; 01402 case 'simpleContent': // (optional) content for a complexType 01403 break; 01404 case 'simpleType': 01405 array_push($this->simpleTypeStack, $this->currentSimpleType); 01406 if(isset($attrs['name'])){ 01407 $this->xdebug("processing simpleType for name " . $attrs['name']); 01408 $this->currentSimpleType = $attrs['name']; 01409 $this->simpleTypes[ $attrs['name'] ] = $attrs; 01410 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; 01411 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; 01412 } else { 01413 $this->xdebug('processing unnamed simpleType for element '.$this->currentElement); 01414 $this->currentSimpleType = $this->currentElement . '_ContainedType'; 01415 //$this->currentElement = false; 01416 $this->simpleTypes[$this->currentSimpleType] = $attrs; 01417 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; 01418 } 01419 break; 01420 case 'union': // simpleType type list 01421 break; 01422 default: 01423 //$this->xdebug("do not have anything to do for element $name"); 01424 } 01425 } 01426 01434 function schemaEndElement($parser, $name) { 01435 // bring depth down a notch 01436 $this->depth--; 01437 // position of current element is equal to the last value left in depth_array for my depth 01438 if(isset($this->depth_array[$this->depth])){ 01439 $pos = $this->depth_array[$this->depth]; 01440 } 01441 // get element prefix 01442 if ($prefix = $this->getPrefix($name)){ 01443 // get unqualified name 01444 $name = $this->getLocalPart($name); 01445 } else { 01446 $prefix = ''; 01447 } 01448 // move on... 01449 if($name == 'complexType'){ 01450 $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); 01451 $this->currentComplexType = array_pop($this->complexTypeStack); 01452 //$this->currentElement = false; 01453 } 01454 if($name == 'element'){ 01455 $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); 01456 $this->currentElement = array_pop($this->elementStack); 01457 } 01458 if($name == 'simpleType'){ 01459 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); 01460 $this->currentSimpleType = array_pop($this->simpleTypeStack); 01461 } 01462 } 01463 01471 function schemaCharacterData($parser, $data){ 01472 $pos = $this->depth_array[$this->depth - 1]; 01473 $this->message[$pos]['cdata'] .= $data; 01474 } 01475 01481 function serializeSchema(){ 01482 01483 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); 01484 $xml = ''; 01485 // imports 01486 if (sizeof($this->imports) > 0) { 01487 foreach($this->imports as $ns => $list) { 01488 foreach ($list as $ii) { 01489 if ($ii['location'] != '') { 01490 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; 01491 } else { 01492 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; 01493 } 01494 } 01495 } 01496 } 01497 // complex types 01498 foreach($this->complexTypes as $typeName => $attrs){ 01499 $contentStr = ''; 01500 // serialize child elements 01501 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ 01502 foreach($attrs['elements'] as $element => $eParts){ 01503 if(isset($eParts['ref'])){ 01504 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; 01505 } else { 01506 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; 01507 foreach ($eParts as $aName => $aValue) { 01508 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable 01509 if ($aName != 'name' && $aName != 'type') { 01510 $contentStr .= " $aName=\"$aValue\""; 01511 } 01512 } 01513 $contentStr .= "/>\n"; 01514 } 01515 } 01516 // compositor wraps elements 01517 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { 01518 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; 01519 } 01520 } 01521 // attributes 01522 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ 01523 foreach($attrs['attrs'] as $attr => $aParts){ 01524 $contentStr .= " <$schemaPrefix:attribute"; 01525 foreach ($aParts as $a => $v) { 01526 if ($a == 'ref' || $a == 'type') { 01527 $contentStr .= " $a=\"".$this->contractQName($v).'"'; 01528 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { 01529 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; 01530 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; 01531 } else { 01532 $contentStr .= " $a=\"$v\""; 01533 } 01534 } 01535 $contentStr .= "/>\n"; 01536 } 01537 } 01538 // if restriction 01539 if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ 01540 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; 01541 // complex or simple content 01542 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ 01543 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; 01544 } 01545 } 01546 // finalize complex type 01547 if($contentStr != ''){ 01548 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; 01549 } else { 01550 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; 01551 } 01552 $xml .= $contentStr; 01553 } 01554 // simple types 01555 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ 01556 foreach($this->simpleTypes as $typeName => $eParts){ 01557 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n"; 01558 if (isset($eParts['enumeration'])) { 01559 foreach ($eParts['enumeration'] as $e) { 01560 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; 01561 } 01562 } 01563 $xml .= " </$schemaPrefix:simpleType>"; 01564 } 01565 } 01566 // elements 01567 if(isset($this->elements) && count($this->elements) > 0){ 01568 foreach($this->elements as $element => $eParts){ 01569 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; 01570 } 01571 } 01572 // attributes 01573 if(isset($this->attributes) && count($this->attributes) > 0){ 01574 foreach($this->attributes as $attr => $aParts){ 01575 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; 01576 } 01577 } 01578 // finish 'er up 01579 $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n"; 01580 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { 01581 $el .= " xmlns:$nsp=\"$ns\"\n"; 01582 } 01583 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; 01584 return $xml; 01585 } 01586 01593 function xdebug($string){ 01594 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); 01595 } 01596 01609 function getPHPType($type,$ns){ 01610 if(isset($this->typemap[$ns][$type])){ 01611 //print "found type '$type' and ns $ns in typemap<br>"; 01612 return $this->typemap[$ns][$type]; 01613 } elseif(isset($this->complexTypes[$type])){ 01614 //print "getting type '$type' and ns $ns from complexTypes array<br>"; 01615 return $this->complexTypes[$type]['phpType']; 01616 } 01617 return false; 01618 } 01619 01642 function getTypeDef($type){ 01643 //$this->debug("in getTypeDef for type $type"); 01644 if(isset($this->complexTypes[$type])){ 01645 $this->xdebug("in getTypeDef, found complexType $type"); 01646 return $this->complexTypes[$type]; 01647 } elseif(isset($this->simpleTypes[$type])){ 01648 $this->xdebug("in getTypeDef, found simpleType $type"); 01649 if (!isset($this->simpleTypes[$type]['phpType'])) { 01650 // get info for type to tack onto the simple type 01651 // TODO: can this ever really apply (i.e. what is a simpleType really?) 01652 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); 01653 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); 01654 $etype = $this->getTypeDef($uqType); 01655 if ($etype) { 01656 $this->xdebug("in getTypeDef, found type for simpleType $type:"); 01657 $this->xdebug($this->varDump($etype)); 01658 if (isset($etype['phpType'])) { 01659 $this->simpleTypes[$type]['phpType'] = $etype['phpType']; 01660 } 01661 if (isset($etype['elements'])) { 01662 $this->simpleTypes[$type]['elements'] = $etype['elements']; 01663 } 01664 } 01665 } 01666 return $this->simpleTypes[$type]; 01667 } elseif(isset($this->elements[$type])){ 01668 $this->xdebug("in getTypeDef, found element $type"); 01669 if (!isset($this->elements[$type]['phpType'])) { 01670 // get info for type to tack onto the element 01671 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); 01672 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); 01673 $etype = $this->getTypeDef($uqType); 01674 if ($etype) { 01675 $this->xdebug("in getTypeDef, found type for element $type:"); 01676 $this->xdebug($this->varDump($etype)); 01677 if (isset($etype['phpType'])) { 01678 $this->elements[$type]['phpType'] = $etype['phpType']; 01679 } 01680 if (isset($etype['elements'])) { 01681 $this->elements[$type]['elements'] = $etype['elements']; 01682 } 01683 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { 01684 $this->xdebug("in getTypeDef, element $type is an XSD type"); 01685 $this->elements[$type]['phpType'] = 'scalar'; 01686 } 01687 } 01688 return $this->elements[$type]; 01689 } elseif(isset($this->attributes[$type])){ 01690 $this->xdebug("in getTypeDef, found attribute $type"); 01691 return $this->attributes[$type]; 01692 } elseif (ereg('_ContainedType$', $type)) { 01693 $this->xdebug("in getTypeDef, have an untyped element $type"); 01694 $typeDef['typeClass'] = 'simpleType'; 01695 $typeDef['phpType'] = 'scalar'; 01696 $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; 01697 return $typeDef; 01698 } 01699 $this->xdebug("in getTypeDef, did not find $type"); 01700 return false; 01701 } 01702 01711 function serializeTypeDef($type){ 01712 //print "in sTD() for type $type<br>"; 01713 if($typeDef = $this->getTypeDef($type)){ 01714 $str .= '<'.$type; 01715 if(is_array($typeDef['attrs'])){ 01716 foreach($attrs as $attName => $data){ 01717 $str .= " $attName=\"{type = ".$data['type']."}\""; 01718 } 01719 } 01720 $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; 01721 if(count($typeDef['elements']) > 0){ 01722 $str .= ">"; 01723 foreach($typeDef['elements'] as $element => $eData){ 01724 $str .= $this->serializeTypeDef($element); 01725 } 01726 $str .= "</$type>"; 01727 } elseif($typeDef['typeClass'] == 'element') { 01728 $str .= "></$type>"; 01729 } else { 01730 $str .= "/>"; 01731 } 01732 return $str; 01733 } 01734 return false; 01735 } 01736 01747 function typeToForm($name,$type){ 01748 // get typedef 01749 if($typeDef = $this->getTypeDef($type)){ 01750 // if struct 01751 if($typeDef['phpType'] == 'struct'){ 01752 $buffer .= '<table>'; 01753 foreach($typeDef['elements'] as $child => $childDef){ 01754 $buffer .= " 01755 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> 01756 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; 01757 } 01758 $buffer .= '</table>'; 01759 // if array 01760 } elseif($typeDef['phpType'] == 'array'){ 01761 $buffer .= '<table>'; 01762 for($i=0;$i < 3; $i++){ 01763 $buffer .= " 01764 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> 01765 <td><input type='text' name='parameters[".$name."][]'></td></tr>"; 01766 } 01767 $buffer .= '</table>'; 01768 // if scalar 01769 } else { 01770 $buffer .= "<input type='text' name='parameters[$name]'>"; 01771 } 01772 } else { 01773 $buffer .= "<input type='text' name='parameters[$name]'>"; 01774 } 01775 return $buffer; 01776 } 01777 01819 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ 01820 $this->complexTypes[$name] = array( 01821 'name' => $name, 01822 'typeClass' => $typeClass, 01823 'phpType' => $phpType, 01824 'compositor'=> $compositor, 01825 'restrictionBase' => $restrictionBase, 01826 'elements' => $elements, 01827 'attrs' => $attrs, 01828 'arrayType' => $arrayType 01829 ); 01830 01831 $this->xdebug("addComplexType $name:"); 01832 $this->appendDebug($this->varDump($this->complexTypes[$name])); 01833 } 01834 01847 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 01848 $this->simpleTypes[$name] = array( 01849 'name' => $name, 01850 'typeClass' => $typeClass, 01851 'phpType' => $phpType, 01852 'type' => $restrictionBase, 01853 'enumeration' => $enumeration 01854 ); 01855 01856 $this->xdebug("addSimpleType $name:"); 01857 $this->appendDebug($this->varDump($this->simpleTypes[$name])); 01858 } 01859 01867 function addElement($attrs) { 01868 if (! $this->getPrefix($attrs['type'])) { 01869 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; 01870 } 01871 $this->elements[ $attrs['name'] ] = $attrs; 01872 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01873 01874 $this->xdebug("addElement " . $attrs['name']); 01875 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); 01876 } 01877 } 01878 01879 01880 01892 class soapval extends nusoap_base { 01899 var $name; 01906 var $type; 01913 var $value; 01920 var $element_ns; 01927 var $type_ns; 01934 var $attributes; 01935 01947 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { 01948 parent::nusoap_base(); 01949 $this->name = $name; 01950 $this->type = $type; 01951 $this->value = $value; 01952 $this->element_ns = $element_ns; 01953 $this->type_ns = $type_ns; 01954 $this->attributes = $attributes; 01955 } 01956 01964 function serialize($use='encoded') { 01965 return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use); 01966 } 01967 01974 function decode(){ 01975 return $this->value; 01976 } 01977 } 01978 01979 01980 01989 class soap_transport_http extends nusoap_base { 01990 01991 var $url = ''; 01992 var $uri = ''; 01993 var $digest_uri = ''; 01994 var $scheme = ''; 01995 var $host = ''; 01996 var $port = ''; 01997 var $path = ''; 01998 var $request_method = 'POST'; 01999 var $protocol_version = '1.0'; 02000 var $encoding = ''; 02001 var $outgoing_headers = array(); 02002 var $incoming_headers = array(); 02003 var $incoming_cookies = array(); 02004 var $outgoing_payload = ''; 02005 var $incoming_payload = ''; 02006 var $useSOAPAction = true; 02007 var $persistentConnection = false; 02008 var $ch = false; // cURL handle 02009 var $username = ''; 02010 var $password = ''; 02011 var $authtype = ''; 02012 var $digestRequest = array(); 02013 var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional) 02014 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' 02015 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' 02016 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' 02017 // passphrase: SSL key password/passphrase 02018 // verifypeer: default is 1 02019 // verifyhost: default is 1 02020 02024 function soap_transport_http($url){ 02025 parent::nusoap_base(); 02026 $this->setURL($url); 02027 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 02028 $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')'; 02029 $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']); 02030 } 02031 02032 function setURL($url) { 02033 $this->url = $url; 02034 02035 $u = parse_url($url); 02036 foreach($u as $k => $v){ 02037 $this->debug("$k = $v"); 02038 $this->$k = $v; 02039 } 02040 02041 // add any GET params to path 02042 if(isset($u['query']) && $u['query'] != ''){ 02043 $this->path .= '?' . $u['query']; 02044 } 02045 02046 // set default port 02047 if(!isset($u['port'])){ 02048 if($u['scheme'] == 'https'){ 02049 $this->port = 443; 02050 } else { 02051 $this->port = 80; 02052 } 02053 } 02054 02055 $this->uri = $this->path; 02056 $this->digest_uri = $this->uri; 02057 02058 // build headers 02059 if (!isset($u['port'])) { 02060 $this->outgoing_headers['Host'] = $this->host; 02061 } else { 02062 $this->outgoing_headers['Host'] = $this->host.':'.$this->port; 02063 } 02064 $this->debug('set Host: ' . $this->outgoing_headers['Host']); 02065 02066 if (isset($u['user']) && $u['user'] != '') { 02067 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); 02068 } 02069 } 02070 02071 function connect($connection_timeout=0,$response_timeout=30){ 02072 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like 02073 // "regular" socket. 02074 // TODO: disabled for now because OpenSSL must be *compiled* in (not just 02075 // loaded), and until PHP5 stream_get_wrappers is not available. 02076 // if ($this->scheme == 'https') { 02077 // if (version_compare(phpversion(), '4.3.0') >= 0) { 02078 // if (extension_loaded('openssl')) { 02079 // $this->scheme = 'ssl'; 02080 // $this->debug('Using SSL over OpenSSL'); 02081 // } 02082 // } 02083 // } 02084 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); 02085 if ($this->scheme == 'http' || $this->scheme == 'ssl') { 02086 // use persistent connection 02087 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ 02088 if (!feof($this->fp)) { 02089 $this->debug('Re-use persistent connection'); 02090 return true; 02091 } 02092 fclose($this->fp); 02093 $this->debug('Closed persistent connection at EOF'); 02094 } 02095 02096 // munge host if using OpenSSL 02097 if ($this->scheme == 'ssl') { 02098 $host = 'ssl://' . $this->host; 02099 } else { 02100 $host = $this->host; 02101 } 02102 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); 02103 02104 // open socket 02105 if($connection_timeout > 0){ 02106 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); 02107 } else { 02108 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); 02109 } 02110 02111 // test pointer 02112 if(!$this->fp) { 02113 $msg = 'Couldn\'t open socket connection to server ' . $this->url; 02114 if ($this->errno) { 02115 $msg .= ', Error ('.$this->errno.'): '.$this->error_str; 02116 } else { 02117 $msg .= ' prior to connect(). This is often a problem looking up the host name.'; 02118 } 02119 $this->debug($msg); 02120 $this->setError($msg); 02121 return false; 02122 } 02123 02124 // set response timeout 02125 $this->debug('set response timeout to ' . $response_timeout); 02126 socket_set_timeout( $this->fp, $response_timeout); 02127 02128 $this->debug('socket connected'); 02129 return true; 02130 } else if ($this->scheme == 'https') { 02131 if (!extension_loaded('curl')) { 02132 $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); 02133 return false; 02134 } 02135 $this->debug('connect using https'); 02136 // init CURL 02137 $this->ch = curl_init(); 02138 // set url 02139 $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host"; 02140 // add path 02141 $hostURL .= $this->path; 02142 curl_setopt($this->ch, CURLOPT_URL, $hostURL); 02143 // follow location headers (re-directs) 02144 curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1); 02145 // ask for headers in the response output 02146 curl_setopt($this->ch, CURLOPT_HEADER, 1); 02147 // ask for the response output as the return value 02148 curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1); 02149 // encode 02150 // We manage this ourselves through headers and encoding 02151 // if(function_exists('gzuncompress')){ 02152 // curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate'); 02153 // } 02154 // persistent connection 02155 if ($this->persistentConnection) { 02156 // The way we send data, we cannot use persistent connections, since 02157 // there will be some "junk" at the end of our request. 02158 //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true); 02159 $this->persistentConnection = false; 02160 $this->outgoing_headers['Connection'] = 'close'; 02161 $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); 02162 } 02163 // set timeout 02164 if ($connection_timeout != 0) { 02165 curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout); 02166 } 02167 // TODO: cURL has added a connection timeout separate from the response timeout 02168 //if ($connection_timeout != 0) { 02169 // curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); 02170 //} 02171 //if ($response_timeout != 0) { 02172 // curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_timeout); 02173 //} 02174 02175 // recent versions of cURL turn on peer/host checking by default, 02176 // while PHP binaries are not compiled with a default location for the 02177 // CA cert bundle, so disable peer/host checking. 02178 //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); 02179 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0); 02180 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0); 02181 02182 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) 02183 if ($this->authtype == 'certificate') { 02184 if (isset($this->certRequest['cainfofile'])) { 02185 curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']); 02186 } 02187 if (isset($this->certRequest['verifypeer'])) { 02188 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); 02189 } else { 02190 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1); 02191 } 02192 if (isset($this->certRequest['verifyhost'])) { 02193 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); 02194 } else { 02195 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1); 02196 } 02197 if (isset($this->certRequest['sslcertfile'])) { 02198 curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); 02199 } 02200 if (isset($this->certRequest['sslkeyfile'])) { 02201 curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); 02202 } 02203 if (isset($this->certRequest['passphrase'])) { 02204 curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']); 02205 } 02206 } 02207 $this->debug('cURL connection set up'); 02208 return true; 02209 } else { 02210 $this->setError('Unknown scheme ' . $this->scheme); 02211 $this->debug('Unknown scheme ' . $this->scheme); 02212 return false; 02213 } 02214 } 02215 02226 function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { 02227 02228 $this->debug('entered send() with data of length: '.strlen($data)); 02229 02230 $this->tryagain = true; 02231 $tries = 0; 02232 while ($this->tryagain) { 02233 $this->tryagain = false; 02234 if ($tries++ < 2) { 02235 // make connnection 02236 if (!$this->connect($timeout, $response_timeout)){ 02237 return false; 02238 } 02239 02240 // send request 02241 if (!$this->sendRequest($data, $cookies)){ 02242 return false; 02243 } 02244 02245 // get response 02246 $respdata = $this->getResponse(); 02247 } else { 02248 $this->setError('Too many tries to get an OK response'); 02249 } 02250 } 02251 $this->debug('end of send()'); 02252 return $respdata; 02253 } 02254 02255 02266 function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { 02267 return $this->send($data, $timeout, $response_timeout, $cookies); 02268 } 02269 02280 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { 02281 $this->debug("Set credentials for authtype $authtype"); 02282 // cf. RFC 2617 02283 if ($authtype == 'basic') { 02284 $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$username).':'.$password); 02285 } elseif ($authtype == 'digest') { 02286 if (isset($digestRequest['nonce'])) { 02287 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; 02288 02289 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) 02290 02291 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd 02292 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; 02293 02294 // H(A1) = MD5(A1) 02295 $HA1 = md5($A1); 02296 02297 // A2 = Method ":" digest-uri-value 02298 $A2 = 'POST:' . $this->digest_uri; 02299 02300 // H(A2) 02301 $HA2 = md5($A2); 02302 02303 // KD(secret, data) = H(concat(secret, ":", data)) 02304 // if qop == auth: 02305 // request-digest = <"> < KD ( H(A1), unq(nonce-value) 02306 // ":" nc-value 02307 // ":" unq(cnonce-value) 02308 // ":" unq(qop-value) 02309 // ":" H(A2) 02310 // ) <"> 02311 // if qop is missing, 02312 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> 02313 02314 $unhashedDigest = ''; 02315 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; 02316 $cnonce = $nonce; 02317 if ($digestRequest['qop'] != '') { 02318 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; 02319 } else { 02320 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; 02321 } 02322 02323 $hashedDigest = md5($unhashedDigest); 02324 02325 $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'; 02326 } 02327 } elseif ($authtype == 'certificate') { 02328 $this->certRequest = $certRequest; 02329 } 02330 $this->username = $username; 02331 $this->password = $password; 02332 $this->authtype = $authtype; 02333 $this->digestRequest = $digestRequest; 02334 02335 if (isset($this->outgoing_headers['Authorization'])) { 02336 $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...'); 02337 } else { 02338 $this->debug('Authorization header not set'); 02339 } 02340 } 02341 02348 function setSOAPAction($soapaction) { 02349 $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"'; 02350 $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']); 02351 } 02352 02359 function setEncoding($enc='gzip, deflate') { 02360 if (function_exists('gzdeflate')) { 02361 $this->protocol_version = '1.1'; 02362 $this->outgoing_headers['Accept-Encoding'] = $enc; 02363 $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']); 02364 if (!isset($this->outgoing_headers['Connection'])) { 02365 $this->outgoing_headers['Connection'] = 'close'; 02366 $this->persistentConnection = false; 02367 $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); 02368 } 02369 set_magic_quotes_runtime(0); 02370 // deprecated 02371 $this->encoding = $enc; 02372 } 02373 } 02374 02384 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 02385 $this->uri = $this->url; 02386 $this->host = $proxyhost; 02387 $this->port = $proxyport; 02388 if ($proxyusername != '' && $proxypassword != '') { 02389 $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword); 02390 $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']); 02391 } 02392 } 02393 02404 function decodeChunked($buffer, $lb){ 02405 // length := 0 02406 $length = 0; 02407 $new = ''; 02408 02409 // read chunk-size, chunk-extension (if any) and CRLF 02410 // get the position of the linebreak 02411 $chunkend = strpos($buffer, $lb); 02412 if ($chunkend == FALSE) { 02413 $this->debug('no linebreak found in decodeChunked'); 02414 return $new; 02415 } 02416 $temp = substr($buffer,0,$chunkend); 02417 $chunk_size = hexdec( trim($temp) ); 02418 $chunkstart = $chunkend + strlen($lb); 02419 // while (chunk-size > 0) { 02420 while ($chunk_size > 0) { 02421 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); 02422 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); 02423 02424 // Just in case we got a broken connection 02425 if ($chunkend == FALSE) { 02426 $chunk = substr($buffer,$chunkstart); 02427 // append chunk-data to entity-body 02428 $new .= $chunk; 02429 $length += strlen($chunk); 02430 break; 02431 } 02432 02433 // read chunk-data and CRLF 02434 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02435 // append chunk-data to entity-body 02436 $new .= $chunk; 02437 // length := length + chunk-size 02438 $length += strlen($chunk); 02439 // read chunk-size and CRLF 02440 $chunkstart = $chunkend + strlen($lb); 02441 02442 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); 02443 if ($chunkend == FALSE) { 02444 break; //Just in case we got a broken connection 02445 } 02446 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02447 $chunk_size = hexdec( trim($temp) ); 02448 $chunkstart = $chunkend; 02449 } 02450 return $new; 02451 } 02452 02453 /* 02454 * Writes payload, including HTTP headers, to $this->outgoing_payload. 02455 */ 02456 function buildPayload($data, $cookie_str = '') { 02457 // add content-length header 02458 $this->outgoing_headers['Content-Length'] = strlen($data); 02459 $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']); 02460 02461 // start building outgoing payload: 02462 $req = "$this->request_method $this->uri HTTP/$this->protocol_version"; 02463 $this->debug("HTTP request: $req"); 02464 $this->outgoing_payload = "$req\r\n"; 02465 02466 // loop thru headers, serializing 02467 foreach($this->outgoing_headers as $k => $v){ 02468 $hdr = $k.': '.$v; 02469 $this->debug("HTTP header: $hdr"); 02470 $this->outgoing_payload .= "$hdr\r\n"; 02471 } 02472 02473 // add any cookies 02474 if ($cookie_str != '') { 02475 $hdr = 'Cookie: '.$cookie_str; 02476 $this->debug("HTTP header: $hdr"); 02477 $this->outgoing_payload .= "$hdr\r\n"; 02478 } 02479 02480 // header/body separator 02481 $this->outgoing_payload .= "\r\n"; 02482 02483 // add data 02484 $this->outgoing_payload .= $data; 02485 } 02486 02487 function sendRequest($data, $cookies = NULL) { 02488 // build cookie string 02489 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); 02490 02491 // build payload 02492 $this->buildPayload($data, $cookie_str); 02493 02494 if ($this->scheme == 'http' || $this->scheme == 'ssl') { 02495 // send payload 02496 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { 02497 $this->setError('couldn\'t write message data to socket'); 02498 $this->debug('couldn\'t write message data to socket'); 02499 return false; 02500 } 02501 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); 02502 return true; 02503 } else if ($this->scheme == 'https') { 02504 // set payload 02505 // TODO: cURL does say this should only be the verb, and in fact it 02506 // turns out that the URI and HTTP version are appended to this, which 02507 // some servers refuse to work with 02508 //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); 02509 foreach($this->outgoing_headers as $k => $v){ 02510 $curl_headers[] = "$k: $v"; 02511 } 02512 if ($cookie_str != '') { 02513 $curl_headers[] = 'Cookie: ' . $cookie_str; 02514 } 02515 curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers); 02516 if ($this->request_method == "POST") { 02517 curl_setopt($this->ch, CURLOPT_POST, 1); 02518 curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data); 02519 } else { 02520 } 02521 $this->debug('set cURL payload'); 02522 return true; 02523 } 02524 } 02525 02526 function getResponse(){ 02527 $this->incoming_payload = ''; 02528 02529 if ($this->scheme == 'http' || $this->scheme == 'ssl') { 02530 // loop until headers have been retrieved 02531 $data = ''; 02532 while (!isset($lb)){ 02533 02534 // We might EOF during header read. 02535 if(feof($this->fp)) { 02536 $this->incoming_payload = $data; 02537 $this->debug('found no headers before EOF after length ' . strlen($data)); 02538 $this->debug("received before EOF:\n" . $data); 02539 $this->setError('server failed to send headers'); 02540 return false; 02541 } 02542 02543 $tmp = fgets($this->fp, 256); 02544 $tmplen = strlen($tmp); 02545 $this->debug("read line of $tmplen bytes: " . trim($tmp)); 02546 02547 if ($tmplen == 0) { 02548 $this->incoming_payload = $data; 02549 $this->debug('socket read of headers timed out after length ' . strlen($data)); 02550 $this->debug("read before timeout: " . $data); 02551 $this->setError('socket read of headers timed out'); 02552 return false; 02553 } 02554 02555 $data .= $tmp; 02556 $pos = strpos($data,"\r\n\r\n"); 02557 if($pos > 1){ 02558 $lb = "\r\n"; 02559 } else { 02560 $pos = strpos($data,"\n\n"); 02561 if($pos > 1){ 02562 $lb = "\n"; 02563 } 02564 } 02565 // remove 100 header 02566 if(isset($lb) && ereg('^HTTP/1.1 100',$data)){ 02567 unset($lb); 02568 $data = ''; 02569 }// 02570 } 02571 // store header data 02572 $this->incoming_payload .= $data; 02573 $this->debug('found end of headers after length ' . strlen($data)); 02574 // process headers 02575 $header_data = trim(substr($data,0,$pos)); 02576 $header_array = explode($lb,$header_data); 02577 $this->incoming_headers = array(); 02578 $this->incoming_cookies = array(); 02579 foreach($header_array as $header_line){ 02580 $arr = explode(':',$header_line, 2); 02581 if(count($arr) > 1){ 02582 $header_name = strtolower(trim($arr[0])); 02583 $this->incoming_headers[$header_name] = trim($arr[1]); 02584 if ($header_name == 'set-cookie') { 02585 // TODO: allow multiple cookies from parseCookie 02586 $cookie = $this->parseCookie(trim($arr[1])); 02587 if ($cookie) { 02588 $this->incoming_cookies[] = $cookie; 02589 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 02590 } else { 02591 $this->debug('did not find cookie in ' . trim($arr[1])); 02592 } 02593 } 02594 } else if (isset($header_name)) { 02595 // append continuation line to previous header 02596 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 02597 } 02598 } 02599 02600 // loop until msg has been received 02601 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { 02602 $content_length = 2147483647; // ignore any content-length header 02603 $chunked = true; 02604 $this->debug("want to read chunked content"); 02605 } elseif (isset($this->incoming_headers['content-length'])) { 02606 $content_length = $this->incoming_headers['content-length']; 02607 $chunked = false; 02608 $this->debug("want to read content of length $content_length"); 02609 } else { 02610 $content_length = 2147483647; 02611 $chunked = false; 02612 $this->debug("want to read content to EOF"); 02613 } 02614 $data = ''; 02615 do { 02616 if ($chunked) { 02617 $tmp = fgets($this->fp, 256); 02618 $tmplen = strlen($tmp); 02619 $this->debug("read chunk line of $tmplen bytes"); 02620 if ($tmplen == 0) { 02621 $this->incoming_payload = $data; 02622 $this->debug('socket read of chunk length timed out after length ' . strlen($data)); 02623 $this->debug("read before timeout:\n" . $data); 02624 $this->setError('socket read of chunk length timed out'); 02625 return false; 02626 } 02627 $content_length = hexdec(trim($tmp)); 02628 $this->debug("chunk length $content_length"); 02629 } 02630 $strlen = 0; 02631 while (($strlen < $content_length) && (!feof($this->fp))) { 02632 $readlen = min(8192, $content_length - $strlen); 02633 $tmp = fread($this->fp, $readlen); 02634 $tmplen = strlen($tmp); 02635 $this->debug("read buffer of $tmplen bytes"); 02636 if (($tmplen == 0) && (!feof($this->fp))) { 02637 $this->incoming_payload = $data; 02638 $this->debug('socket read of body timed out after length ' . strlen($data)); 02639 $this->debug("read before timeout:\n" . $data); 02640 $this->setError('socket read of body timed out'); 02641 return false; 02642 } 02643 $strlen += $tmplen; 02644 $data .= $tmp; 02645 } 02646 if ($chunked && ($content_length > 0)) { 02647 $tmp = fgets($this->fp, 256); 02648 $tmplen = strlen($tmp); 02649 $this->debug("read chunk terminator of $tmplen bytes"); 02650 if ($tmplen == 0) { 02651 $this->incoming_payload = $data; 02652 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); 02653 $this->debug("read before timeout:\n" . $data); 02654 $this->setError('socket read of chunk terminator timed out'); 02655 return false; 02656 } 02657 } 02658 } while ($chunked && ($content_length > 0) && (!feof($this->fp))); 02659 if (feof($this->fp)) { 02660 $this->debug('read to EOF'); 02661 } 02662 $this->debug('read body of length ' . strlen($data)); 02663 $this->incoming_payload .= $data; 02664 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); 02665 02666 // close filepointer 02667 if( 02668 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 02669 (! $this->persistentConnection) || feof($this->fp)){ 02670 fclose($this->fp); 02671 $this->fp = false; 02672 $this->debug('closed socket'); 02673 } 02674 02675 // connection was closed unexpectedly 02676 if($this->incoming_payload == ''){ 02677 $this->setError('no response from server'); 02678 return false; 02679 } 02680 02681 // decode transfer-encoding 02682 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ 02683 // if(!$data = $this->decodeChunked($data, $lb)){ 02684 // $this->setError('Decoding of chunked data failed'); 02685 // return false; 02686 // } 02687 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; 02688 // set decoded payload 02689 // $this->incoming_payload = $header_data.$lb.$lb.$data; 02690 // } 02691 02692 } else if ($this->scheme == 'https') { 02693 // send and receive 02694 $this->debug('send and receive with cURL'); 02695 $this->incoming_payload = curl_exec($this->ch); 02696 $data = $this->incoming_payload; 02697 02698 $cErr = curl_error($this->ch); 02699 if ($cErr != '') { 02700 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>'; 02701 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE 02702 foreach(curl_getinfo($this->ch) as $k => $v){ 02703 $err .= "$k: $v<br>"; 02704 } 02705 $this->debug($err); 02706 $this->setError($err); 02707 curl_close($this->ch); 02708 return false; 02709 } else { 02710 //echo '<pre>'; 02711 //var_dump(curl_getinfo($this->ch)); 02712 //echo '</pre>'; 02713 } 02714 // close curl 02715 $this->debug('No cURL error, closing cURL'); 02716 curl_close($this->ch); 02717 02718 // remove 100 header(s) 02719 while (ereg('^HTTP/1.1 100',$data)) { 02720 if ($pos = strpos($data,"\r\n\r\n")) { 02721 $data = ltrim(substr($data,$pos)); 02722 } elseif($pos = strpos($data,"\n\n") ) { 02723 $data = ltrim(substr($data,$pos)); 02724 } 02725 } 02726 02727 // separate content from HTTP headers 02728 if ($pos = strpos($data,"\r\n\r\n")) { 02729 $lb = "\r\n"; 02730 } elseif( $pos = strpos($data,"\n\n")) { 02731 $lb = "\n"; 02732 } else { 02733 $this->debug('no proper separation of headers and document'); 02734 $this->setError('no proper separation of headers and document'); 02735 return false; 02736 } 02737 $header_data = trim(substr($data,0,$pos)); 02738 $header_array = explode($lb,$header_data); 02739 $data = ltrim(substr($data,$pos)); 02740 $this->debug('found proper separation of headers and document'); 02741 $this->debug('cleaned data, stringlen: '.strlen($data)); 02742 // clean headers 02743 foreach ($header_array as $header_line) { 02744 $arr = explode(':',$header_line,2); 02745 if(count($arr) > 1){ 02746 $header_name = strtolower(trim($arr[0])); 02747 $this->incoming_headers[$header_name] = trim($arr[1]); 02748 if ($header_name == 'set-cookie') { 02749 // TODO: allow multiple cookies from parseCookie 02750 $cookie = $this->parseCookie(trim($arr[1])); 02751 if ($cookie) { 02752 $this->incoming_cookies[] = $cookie; 02753 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 02754 } else { 02755 $this->debug('did not find cookie in ' . trim($arr[1])); 02756 } 02757 } 02758 } else if (isset($header_name)) { 02759 // append continuation line to previous header 02760 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 02761 } 02762 } 02763 } 02764 02765 $arr = explode(' ', $header_array[0], 3); 02766 $http_version = $arr[0]; 02767 $http_status = intval($arr[1]); 02768 $http_reason = count($arr) > 2 ? $arr[2] : ''; 02769 02770 // see if we need to resend the request with http digest authentication 02771 if (isset($this->incoming_headers['location']) && $http_status == 301) { 02772 $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']); 02773 $this->setURL($this->incoming_headers['location']); 02774 $this->tryagain = true; 02775 return false; 02776 } 02777 02778 // see if we need to resend the request with http digest authentication 02779 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { 02780 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); 02781 if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { 02782 $this->debug('Server wants digest authentication'); 02783 // remove "Digest " from our elements 02784 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); 02785 02786 // parse elements into array 02787 $digestElements = explode(',', $digestString); 02788 foreach ($digestElements as $val) { 02789 $tempElement = explode('=', trim($val), 2); 02790 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); 02791 } 02792 02793 // should have (at least) qop, realm, nonce 02794 if (isset($digestRequest['nonce'])) { 02795 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); 02796 $this->tryagain = true; 02797 return false; 02798 } 02799 } 02800 $this->debug('HTTP authentication failed'); 02801 $this->setError('HTTP authentication failed'); 02802 return false; 02803 } 02804 02805 if ( 02806 ($http_status >= 300 && $http_status <= 307) || 02807 ($http_status >= 400 && $http_status <= 417) || 02808 ($http_status >= 501 && $http_status <= 505) 02809 ) { 02810 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); 02811 return false; 02812 } 02813 02814 // decode content-encoding 02815 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ 02816 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ 02817 // if decoding works, use it. else assume data wasn't gzencoded 02818 if(function_exists('gzinflate')){ 02819 //$timer->setMarker('starting decoding of gzip/deflated content'); 02820 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) 02821 // this means there are no Zlib headers, although there should be 02822 $this->debug('The gzinflate function exists'); 02823 $datalen = strlen($data); 02824 if ($this->incoming_headers['content-encoding'] == 'deflate') { 02825 if ($degzdata = @gzinflate($data)) { 02826 $data = $degzdata; 02827 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); 02828 if (strlen($data) < $datalen) { 02829 // test for the case that the payload has been compressed twice 02830 $this->debug('The inflated payload is smaller than the gzipped one; try again'); 02831 if ($degzdata = @gzinflate($data)) { 02832 $data = $degzdata; 02833 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); 02834 } 02835 } 02836 } else { 02837 $this->debug('Error using gzinflate to inflate the payload'); 02838 $this->setError('Error using gzinflate to inflate the payload'); 02839 } 02840 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { 02841 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best 02842 $data = $degzdata; 02843 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); 02844 if (strlen($data) < $datalen) { 02845 // test for the case that the payload has been compressed twice 02846 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); 02847 if ($degzdata = @gzinflate(substr($data, 10))) { 02848 $data = $degzdata; 02849 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); 02850 } 02851 } 02852 } else { 02853 $this->debug('Error using gzinflate to un-gzip the payload'); 02854 $this->setError('Error using gzinflate to un-gzip the payload'); 02855 } 02856 } 02857 //$timer->setMarker('finished decoding of gzip/deflated content'); 02858 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; 02859 // set decoded payload 02860 $this->incoming_payload = $header_data.$lb.$lb.$data; 02861 } else { 02862 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 02863 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 02864 } 02865 } else { 02866 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 02867 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 02868 } 02869 } else { 02870 $this->debug('No Content-Encoding header'); 02871 } 02872 02873 if(strlen($data) == 0){ 02874 $this->debug('no data after headers!'); 02875 $this->setError('no data present after HTTP headers'); 02876 return false; 02877 } 02878 02879 return $data; 02880 } 02881 02882 function setContentType($type, $charset = false) { 02883 $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : ''); 02884 $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']); 02885 } 02886 02887 function usePersistentConnection(){ 02888 if (isset($this->outgoing_headers['Accept-Encoding'])) { 02889 return false; 02890 } 02891 $this->protocol_version = '1.1'; 02892 $this->persistentConnection = true; 02893 $this->outgoing_headers['Connection'] = 'Keep-Alive'; 02894 $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); 02895 return true; 02896 } 02897 02905 /* 02906 * TODO: allow a Set-Cookie string to be parsed into multiple cookies 02907 */ 02908 function parseCookie($cookie_str) { 02909 $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; 02910 $data = split(';', $cookie_str); 02911 $value_str = $data[0]; 02912 02913 $cookie_param = 'domain='; 02914 $start = strpos($cookie_str, $cookie_param); 02915 if ($start > 0) { 02916 $domain = substr($cookie_str, $start + strlen($cookie_param)); 02917 $domain = substr($domain, 0, strpos($domain, ';')); 02918 } else { 02919 $domain = ''; 02920 } 02921 02922 $cookie_param = 'expires='; 02923 $start = strpos($cookie_str, $cookie_param); 02924 if ($start > 0) { 02925 $expires = substr($cookie_str, $start + strlen($cookie_param)); 02926 $expires = substr($expires, 0, strpos($expires, ';')); 02927 } else { 02928 $expires = ''; 02929 } 02930 02931 $cookie_param = 'path='; 02932 $start = strpos($cookie_str, $cookie_param); 02933 if ( $start > 0 ) { 02934 $path = substr($cookie_str, $start + strlen($cookie_param)); 02935 $path = substr($path, 0, strpos($path, ';')); 02936 } else { 02937 $path = '/'; 02938 } 02939 02940 $cookie_param = ';secure;'; 02941 if (strpos($cookie_str, $cookie_param) !== FALSE) { 02942 $secure = true; 02943 } else { 02944 $secure = false; 02945 } 02946 02947 $sep_pos = strpos($value_str, '='); 02948 02949 if ($sep_pos) { 02950 $name = substr($value_str, 0, $sep_pos); 02951 $value = substr($value_str, $sep_pos + 1); 02952 $cookie= array( 'name' => $name, 02953 'value' => $value, 02954 'domain' => $domain, 02955 'path' => $path, 02956 'expires' => $expires, 02957 'secure' => $secure 02958 ); 02959 return $cookie; 02960 } 02961 return false; 02962 } 02963 02972 function getCookiesForRequest($cookies, $secure=false) { 02973 $cookie_str = ''; 02974 if ((! is_null($cookies)) && (is_array($cookies))) { 02975 foreach ($cookies as $cookie) { 02976 if (! is_array($cookie)) { 02977 continue; 02978 } 02979 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); 02980 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 02981 if (strtotime($cookie['expires']) <= time()) { 02982 $this->debug('cookie has expired'); 02983 continue; 02984 } 02985 } 02986 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { 02987 $domain = preg_quote($cookie['domain']); 02988 if (! preg_match("'.*$domain$'i", $this->host)) { 02989 $this->debug('cookie has different domain'); 02990 continue; 02991 } 02992 } 02993 if ((isset($cookie['path'])) && (! empty($cookie['path']))) { 02994 $path = preg_quote($cookie['path']); 02995 if (! preg_match("'^$path.*'i", $this->path)) { 02996 $this->debug('cookie is for a different path'); 02997 continue; 02998 } 02999 } 03000 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { 03001 $this->debug('cookie is secure, transport is not'); 03002 continue; 03003 } 03004 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; 03005 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); 03006 } 03007 } 03008 return $cookie_str; 03009 } 03010 } 03011 03012 03013 03021 class wsdl extends nusoap_base { 03022 // URL or filename of the root of this WSDL 03023 var $wsdl; 03024 // define internal arrays of bindings, ports, operations, messages, etc. 03025 var $schemas = array(); 03026 var $currentSchema; 03027 var $message = array(); 03028 var $complexTypes = array(); 03029 var $messages = array(); 03030 var $currentMessage; 03031 var $currentOperation; 03032 var $portTypes = array(); 03033 var $currentPortType; 03034 var $bindings = array(); 03035 var $currentBinding; 03036 var $ports = array(); 03037 var $currentPort; 03038 var $opData = array(); 03039 var $status = ''; 03040 var $documentation = false; 03041 var $endpoint = ''; 03042 // array of wsdl docs to import 03043 var $import = array(); 03044 // parser vars 03045 var $parser; 03046 var $position = 0; 03047 var $depth = 0; 03048 var $depth_array = array(); 03049 // for getting wsdl 03050 var $proxyhost = ''; 03051 var $proxyport = ''; 03052 var $proxyusername = ''; 03053 var $proxypassword = ''; 03054 var $timeout = 0; 03055 var $response_timeout = 30; 03056 03069 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){ 03070 parent::nusoap_base(); 03071 $this->wsdl = $wsdl; 03072 $this->proxyhost = $proxyhost; 03073 $this->proxyport = $proxyport; 03074 $this->proxyusername = $proxyusername; 03075 $this->proxypassword = $proxypassword; 03076 $this->timeout = $timeout; 03077 $this->response_timeout = $response_timeout; 03078 03079 // parse wsdl file 03080 if ($wsdl != "") { 03081 $this->debug('initial wsdl URL: ' . $wsdl); 03082 $this->parseWSDL($wsdl); 03083 } 03084 // imports 03085 // TODO: handle imports more properly, grabbing them in-line and nesting them 03086 $imported_urls = array(); 03087 $imported = 1; 03088 while ($imported > 0) { 03089 $imported = 0; 03090 // Schema imports 03091 foreach ($this->schemas as $ns => $list) { 03092 foreach ($list as $xs) { 03093 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 03094 foreach ($xs->imports as $ns2 => $list2) { 03095 for ($ii = 0; $ii < count($list2); $ii++) { 03096 if (! $list2[$ii]['loaded']) { 03097 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 03098 $url = $list2[$ii]['location']; 03099 if ($url != '') { 03100 $urlparts = parse_url($url); 03101 if (!isset($urlparts['host'])) { 03102 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 03103 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 03104 } 03105 if (! in_array($url, $imported_urls)) { 03106 $this->parseWSDL($url); 03107 $imported++; 03108 $imported_urls[] = $url; 03109 } 03110 } else { 03111 $this->debug("Unexpected scenario: empty URL for unloaded import"); 03112 } 03113 } 03114 } 03115 } 03116 } 03117 } 03118 // WSDL imports 03119 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 03120 foreach ($this->import as $ns => $list) { 03121 for ($ii = 0; $ii < count($list); $ii++) { 03122 if (! $list[$ii]['loaded']) { 03123 $this->import[$ns][$ii]['loaded'] = true; 03124 $url = $list[$ii]['location']; 03125 if ($url != '') { 03126 $urlparts = parse_url($url); 03127 if (!isset($urlparts['host'])) { 03128 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 03129 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 03130 } 03131 if (! in_array($url, $imported_urls)) { 03132 $this->parseWSDL($url); 03133 $imported++; 03134 $imported_urls[] = $url; 03135 } 03136 } else { 03137 $this->debug("Unexpected scenario: empty URL for unloaded import"); 03138 } 03139 } 03140 } 03141 } 03142 } 03143 // add new data to operation data 03144 foreach($this->bindings as $binding => $bindingData) { 03145 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 03146 foreach($bindingData['operations'] as $operation => $data) { 03147 $this->debug('post-parse data gathering for ' . $operation); 03148 $this->bindings[$binding]['operations'][$operation]['input'] = 03149 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 03150 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 03151 $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 03152 $this->bindings[$binding]['operations'][$operation]['output'] = 03153 isset($this->bindings[$binding]['operations'][$operation]['output']) ? 03154 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 03155 $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 03156 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ 03157 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 03158 } 03159 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ 03160 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 03161 } 03162 if (isset($bindingData['style'])) { 03163 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 03164 } 03165 $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 03166 $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 03167 $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 03168 } 03169 } 03170 } 03171 } 03172 03179 function parseWSDL($wsdl = '') 03180 { 03181 if ($wsdl == '') { 03182 $this->debug('no wsdl passed to parseWSDL()!!'); 03183 $this->setError('no wsdl passed to parseWSDL()!!'); 03184 return false; 03185 } 03186 03187 // parse $wsdl for url format 03188 $wsdl_props = parse_url($wsdl); 03189 03190 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 03191 $this->debug('getting WSDL http(s) URL ' . $wsdl); 03192 // get wsdl 03193 $tr = new soap_transport_http($wsdl); 03194 $tr->request_method = 'GET'; 03195 $tr->useSOAPAction = false; 03196 if($this->proxyhost && $this->proxyport){ 03197 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 03198 } 03199 $tr->setEncoding('gzip, deflate'); 03200 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 03201 //$this->debug("WSDL request\n" . $tr->outgoing_payload); 03202 //$this->debug("WSDL response\n" . $tr->incoming_payload); 03203 $this->appendDebug($tr->getDebug()); 03204 // catch errors 03205 if($err = $tr->getError() ){ 03206 $errstr = 'HTTP ERROR: '.$err; 03207 $this->debug($errstr); 03208 $this->setError($errstr); 03209 unset($tr); 03210 return false; 03211 } 03212 unset($tr); 03213 $this->debug("got WSDL URL"); 03214 } else { 03215 // $wsdl is not http(s), so treat it as a file URL or plain file path 03216 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 03217 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 03218 } else { 03219 $path = $wsdl; 03220 } 03221 $this->debug('getting WSDL file ' . $path); 03222 if ($fp = @fopen($path, 'r')) { 03223 $wsdl_string = ''; 03224 while ($data = fread($fp, 32768)) { 03225 $wsdl_string .= $data; 03226 } 03227 fclose($fp); 03228 } else { 03229 $errstr = "Bad path to WSDL file $path"; 03230 $this->debug($errstr); 03231 $this->setError($errstr); 03232 return false; 03233 } 03234 } 03235 $this->debug('Parse WSDL'); 03236 // end new code added 03237 // Create an XML parser. 03238 $this->parser = xml_parser_create(); 03239 // Set the options for parsing the XML data. 03240 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 03241 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 03242 // Set the object for the parser. 03243 xml_set_object($this->parser, $this); 03244 // Set the element handlers for the parser. 03245 xml_set_element_handler($this->parser, 'start_element', 'end_element'); 03246 xml_set_character_data_handler($this->parser, 'character_data'); 03247 // Parse the XML file. 03248 if (!xml_parse($this->parser, $wsdl_string, true)) { 03249 // Display an error message. 03250 $errstr = sprintf( 03251 'XML error parsing WSDL from %s on line %d: %s', 03252 $wsdl, 03253 xml_get_current_line_number($this->parser), 03254 xml_error_string(xml_get_error_code($this->parser)) 03255 ); 03256 $this->debug($errstr); 03257 $this->debug("XML payload:\n" . $wsdl_string); 03258 $this->setError($errstr); 03259 return false; 03260 } 03261 // free the parser 03262 xml_parser_free($this->parser); 03263 $this->debug('Parsing WSDL done'); 03264 // catch wsdl parse errors 03265 if($this->getError()){ 03266 return false; 03267 } 03268 return true; 03269 } 03270 03279 function start_element($parser, $name, $attrs) 03280 { 03281 if ($this->status == 'schema') { 03282 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 03283 $this->appendDebug($this->currentSchema->getDebug()); 03284 $this->currentSchema->clearDebug(); 03285 } elseif (ereg('schema$', $name)) { 03286 $this->debug('Parsing WSDL schema'); 03287 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 03288 $this->status = 'schema'; 03289 $this->currentSchema = new xmlschema('', '', $this->namespaces); 03290 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 03291 $this->appendDebug($this->currentSchema->getDebug()); 03292 $this->currentSchema->clearDebug(); 03293 } else { 03294 // position in the total number of elements, starting from 0 03295 $pos = $this->position++; 03296 $depth = $this->depth++; 03297 // set self as current value for this depth 03298 $this->depth_array[$depth] = $pos; 03299 $this->message[$pos] = array('cdata' => ''); 03300 // process attributes 03301 if (count($attrs) > 0) { 03302 // register namespace declarations 03303 foreach($attrs as $k => $v) { 03304 if (ereg("^xmlns", $k)) { 03305 if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 03306 $this->namespaces[$ns_prefix] = $v; 03307 } else { 03308 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 03309 } 03310 if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 03311 $this->XMLSchemaVersion = $v; 03312 $this->namespaces['xsi'] = $v . '-instance'; 03313 } 03314 } 03315 } 03316 // expand each attribute prefix to its namespace 03317 foreach($attrs as $k => $v) { 03318 $k = strpos($k, ':') ? $this->expandQname($k) : $k; 03319 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 03320 $v = strpos($v, ':') ? $this->expandQname($v) : $v; 03321 } 03322 $eAttrs[$k] = $v; 03323 } 03324 $attrs = $eAttrs; 03325 } else { 03326 $attrs = array(); 03327 } 03328 // get element prefix, namespace and name 03329 if (ereg(':', $name)) { 03330 // get ns prefix 03331 $prefix = substr($name, 0, strpos($name, ':')); 03332 // get ns 03333 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 03334 // get unqualified name 03335 $name = substr(strstr($name, ':'), 1); 03336 } 03337 // process attributes, expanding any prefixes to namespaces 03338 // find status, register data 03339 switch ($this->status) { 03340 case 'message': 03341 if ($name == 'part') { 03342 if (isset($attrs['type'])) { 03343 $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); 03344 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 03345 } 03346 if (isset($attrs['element'])) { 03347 $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); 03348 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element']; 03349 } 03350 } 03351 break; 03352 case 'portType': 03353 switch ($name) { 03354 case 'operation': 03355 $this->currentPortOperation = $attrs['name']; 03356 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 03357 if (isset($attrs['parameterOrder'])) { 03358 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 03359 } 03360 break; 03361 case 'documentation': 03362 $this->documentation = true; 03363 break; 03364 // merge input/output data 03365 default: 03366 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 03367 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 03368 break; 03369 } 03370 break; 03371 case 'binding': 03372 switch ($name) { 03373 case 'binding': 03374 // get ns prefix 03375 if (isset($attrs['style'])) { 03376 $this->bindings[$this->currentBinding]['prefix'] = $prefix; 03377 } 03378 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 03379 break; 03380 case 'header': 03381 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 03382 break; 03383 case 'operation': 03384 if (isset($attrs['soapAction'])) { 03385 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 03386 } 03387 if (isset($attrs['style'])) { 03388 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 03389 } 03390 if (isset($attrs['name'])) { 03391 $this->currentOperation = $attrs['name']; 03392 $this->debug("current binding operation: $this->currentOperation"); 03393 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 03394 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 03395 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 03396 } 03397 break; 03398 case 'input': 03399 $this->opStatus = 'input'; 03400 break; 03401 case 'output': 03402 $this->opStatus = 'output'; 03403 break; 03404 case 'body': 03405 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 03406 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 03407 } else { 03408 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 03409 } 03410 break; 03411 } 03412 break; 03413 case 'service': 03414 switch ($name) { 03415 case 'port': 03416 $this->currentPort = $attrs['name']; 03417 $this->debug('current port: ' . $this->currentPort); 03418 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 03419 03420 break; 03421 case 'address': 03422 $this->ports[$this->currentPort]['location'] = $attrs['location']; 03423 $this->ports[$this->currentPort]['bindingType'] = $namespace; 03424 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 03425 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 03426 break; 03427 } 03428 break; 03429 } 03430 // set status 03431 switch ($name) { 03432 case 'import': 03433 if (isset($attrs['location'])) { 03434 $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 03435 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 03436 } else { 03437 $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 03438 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 03439 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 03440 } 03441 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 03442 } 03443 break; 03444 //wait for schema 03445 //case 'types': 03446 // $this->status = 'schema'; 03447 // break; 03448 case 'message': 03449 $this->status = 'message'; 03450 $this->messages[$attrs['name']] = array(); 03451 $this->currentMessage = $attrs['name']; 03452 break; 03453 case 'portType': 03454 $this->status = 'portType'; 03455 $this->portTypes[$attrs['name']] = array(); 03456 $this->currentPortType = $attrs['name']; 03457 break; 03458 case "binding": 03459 if (isset($attrs['name'])) { 03460 // get binding name 03461 if (strpos($attrs['name'], ':')) { 03462 $this->currentBinding = $this->getLocalPart($attrs['name']); 03463 } else { 03464 $this->currentBinding = $attrs['name']; 03465 } 03466 $this->status = 'binding'; 03467 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 03468 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 03469 } 03470 break; 03471 case 'service': 03472 $this->serviceName = $attrs['name']; 03473 $this->status = 'service'; 03474 $this->debug('current service: ' . $this->serviceName); 03475 break; 03476 case 'definitions': 03477 foreach ($attrs as $name => $value) { 03478 $this->wsdl_info[$name] = $value; 03479 } 03480 break; 03481 } 03482 } 03483 } 03484 03492 function end_element($parser, $name){ 03493 // unset schema status 03494 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) { 03495 $this->status = ""; 03496 $this->appendDebug($this->currentSchema->getDebug()); 03497 $this->currentSchema->clearDebug(); 03498 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 03499 $this->debug('Parsing WSDL schema done'); 03500 } 03501 if ($this->status == 'schema') { 03502 $this->currentSchema->schemaEndElement($parser, $name); 03503 } else { 03504 // bring depth down a notch 03505 $this->depth--; 03506 } 03507 // end documentation 03508 if ($this->documentation) { 03509 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 03510 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 03511 $this->documentation = false; 03512 } 03513 } 03514 03522 function character_data($parser, $data) 03523 { 03524 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 03525 if (isset($this->message[$pos]['cdata'])) { 03526 $this->message[$pos]['cdata'] .= $data; 03527 } 03528 if ($this->documentation) { 03529 $this->documentation .= $data; 03530 } 03531 } 03532 03533 function getBindingData($binding) 03534 { 03535 if (is_array($this->bindings[$binding])) { 03536 return $this->bindings[$binding]; 03537 } 03538 } 03539 03547 function getOperations($bindingType = 'soap') 03548 { 03549 $ops = array(); 03550 if ($bindingType == 'soap') { 03551 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 03552 } 03553 // loop thru ports 03554 foreach($this->ports as $port => $portData) { 03555 // binding type of port matches parameter 03556 if ($portData['bindingType'] == $bindingType) { 03557 //$this->debug("getOperations for port $port"); 03558 //$this->debug("port data: " . $this->varDump($portData)); 03559 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 03560 // merge bindings 03561 if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 03562 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 03563 } 03564 } 03565 } 03566 return $ops; 03567 } 03568 03577 function getOperationData($operation, $bindingType = 'soap') 03578 { 03579 if ($bindingType == 'soap') { 03580 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 03581 } 03582 // loop thru ports 03583 foreach($this->ports as $port => $portData) { 03584 // binding type of port matches parameter 03585 if ($portData['bindingType'] == $bindingType) { 03586 // get binding 03587 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 03588 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 03589 // note that we could/should also check the namespace here 03590 if ($operation == $bOperation) { 03591 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 03592 return $opData; 03593 } 03594 } 03595 } 03596 } 03597 } 03598 03607 function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 03608 if ($bindingType == 'soap') { 03609 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 03610 } 03611 // loop thru ports 03612 foreach($this->ports as $port => $portData) { 03613 // binding type of port matches parameter 03614 if ($portData['bindingType'] == $bindingType) { 03615 // loop through operations for the binding 03616 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 03617 if ($opData['soapAction'] == $soapAction) { 03618 return $opData; 03619 } 03620 } 03621 } 03622 } 03623 } 03624 03643 function getTypeDef($type, $ns) { 03644 $this->debug("in getTypeDef: type=$type, ns=$ns"); 03645 if ((! $ns) && isset($this->namespaces['tns'])) { 03646 $ns = $this->namespaces['tns']; 03647 $this->debug("in getTypeDef: type namespace forced to $ns"); 03648 } 03649 if (isset($this->schemas[$ns])) { 03650 $this->debug("in getTypeDef: have schema for namespace $ns"); 03651 for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 03652 $xs = &$this->schemas[$ns][$i]; 03653 $t = $xs->getTypeDef($type); 03654 $this->appendDebug($xs->getDebug()); 03655 $xs->clearDebug(); 03656 if ($t) { 03657 if (!isset($t['phpType'])) { 03658 // get info for type to tack onto the element 03659 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 03660 $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 03661 $etype = $this->getTypeDef($uqType, $ns); 03662 if ($etype) { 03663 $this->debug("found type for [element] $type:"); 03664 $this->debug($this->varDump($etype)); 03665 if (isset($etype['phpType'])) { 03666 $t['phpType'] = $etype['phpType']; 03667 } 03668 if (isset($etype['elements'])) { 03669 $t['elements'] = $etype['elements']; 03670 } 03671 if (isset($etype['attrs'])) { 03672 $t['attrs'] = $etype['attrs']; 03673 } 03674 } 03675 } 03676 return $t; 03677 } 03678 } 03679 } else { 03680 $this->debug("in getTypeDef: do not have schema for namespace $ns"); 03681 } 03682 return false; 03683 } 03684 03690 function webDescription(){ 03691 global $HTTP_SERVER_VARS; 03692 03693 if (isset($_SERVER)) { 03694 $PHP_SELF = $_SERVER['PHP_SELF']; 03695 } elseif (isset($HTTP_SERVER_VARS)) { 03696 $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 03697 } else { 03698 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 03699 } 03700 03701 $b = ' 03702 <html><head><title>NuSOAP: '.$this->serviceName.'</title> 03703 <style type="text/css"> 03704 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 03705 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 03706 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 03707 ul { margin-top: 10px; margin-left: 20px; } 03708 li { list-style-type: none; margin-top: 10px; color: #000000; } 03709 .content{ 03710 margin-left: 0px; padding-bottom: 2em; } 03711 .nav { 03712 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 03713 margin-top: 10px; margin-left: 0px; color: #000000; 03714 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 03715 .title { 03716 font-family: arial; font-size: 26px; color: #ffffff; 03717 background-color: #999999; width: 105%; margin-left: 0px; 03718 padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} 03719 .hidden { 03720 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 03721 font-family: arial; overflow: hidden; width: 600; 03722 padding: 20px; font-size: 10px; background-color: #999999; 03723 layer-background-color:#FFFFFF; } 03724 a,a:active { color: charcoal; font-weight: bold; } 03725 a:visited { color: #666666; font-weight: bold; } 03726 a:hover { color: cc3300; font-weight: bold; } 03727 </style> 03728 <script language="JavaScript" type="text/javascript"> 03729 <!-- 03730 // POP-UP CAPTIONS... 03731 function lib_bwcheck(){ //Browsercheck (needed) 03732 this.ver=navigator.appVersion 03733 this.agent=navigator.userAgent 03734 this.dom=document.getElementById?1:0 03735 this.opera5=this.agent.indexOf("Opera 5")>-1 03736 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 03737 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 03738 this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 03739 this.ie=this.ie4||this.ie5||this.ie6 03740 this.mac=this.agent.indexOf("Mac")>-1 03741 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 03742 this.ns4=(document.layers && !this.dom)?1:0; 03743 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 03744 return this 03745 } 03746 var bw = new lib_bwcheck() 03747 //Makes crossbrowser object. 03748 function makeObj(obj){ 03749 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 03750 if(!this.evnt) return false 03751 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 03752 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 03753 this.writeIt=b_writeIt; 03754 return this 03755 } 03756 // A unit of measure that will be added when setting the position of a layer. 03757 //var px = bw.ns4||window.opera?"":"px"; 03758 function b_writeIt(text){ 03759 if (bw.ns4){this.wref.write(text);this.wref.close()} 03760 else this.wref.innerHTML = text 03761 } 03762 //Shows the messages 03763 var oDesc; 03764 function popup(divid){ 03765 if(oDesc = new makeObj(divid)){ 03766 oDesc.css.visibility = "visible" 03767 } 03768 } 03769 function popout(){ // Hides message 03770 if(oDesc) oDesc.css.visibility = "hidden" 03771 } 03772 //--> 03773 </script> 03774 </head> 03775 <body> 03776 <div class=content> 03777 <br><br> 03778 <div class=title>'.$this->serviceName.'</div> 03779 <div class=nav> 03780 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 03781 Click on an operation name to view it's details.</p> 03782 <ul>'; 03783 foreach($this->getOperations() as $op => $data){ 03784 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 03785 // create hidden div 03786 $b .= "<div id='$op' class='hidden'> 03787 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 03788 foreach($data as $donnie => $marie){ // loop through opdata 03789 if($donnie == 'input' || $donnie == 'output'){ // show input/output data 03790 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 03791 foreach($marie as $captain => $tenille){ // loop through data 03792 if($captain == 'parts'){ // loop thru parts 03793 $b .= " $captain:<br>"; 03794 //if(is_array($tenille)){ 03795 foreach($tenille as $joanie => $chachi){ 03796 $b .= " $joanie: $chachi<br>"; 03797 } 03798 //} 03799 } else { 03800 $b .= " $captain: $tenille<br>"; 03801 } 03802 } 03803 } else { 03804 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 03805 } 03806 } 03807 $b .= '</div>'; 03808 } 03809 $b .= ' 03810 <ul> 03811 </div> 03812 </div></body></html>'; 03813 return $b; 03814 } 03815 03823 function serialize($debug = 0) 03824 { 03825 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 03826 $xml .= "\n<definitions"; 03827 foreach($this->namespaces as $k => $v) { 03828 $xml .= " xmlns:$k=\"$v\""; 03829 } 03830 // 10.9.02 - add poulter fix for wsdl and tns declarations 03831 if (isset($this->namespaces['wsdl'])) { 03832 $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 03833 } 03834 if (isset($this->namespaces['tns'])) { 03835 $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 03836 } 03837 $xml .= '>'; 03838 // imports 03839 if (sizeof($this->import) > 0) { 03840 foreach($this->import as $ns => $list) { 03841 foreach ($list as $ii) { 03842 if ($ii['location'] != '') { 03843 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 03844 } else { 03845 $xml .= '<import namespace="' . $ns . '" />'; 03846 } 03847 } 03848 } 03849 } 03850 // types 03851 if (count($this->schemas)>=1) { 03852 $xml .= "\n<types>"; 03853 foreach ($this->schemas as $ns => $list) { 03854 foreach ($list as $xs) { 03855 $xml .= $xs->serializeSchema(); 03856 } 03857 } 03858 $xml .= '</types>'; 03859 } 03860 // messages 03861 if (count($this->messages) >= 1) { 03862 foreach($this->messages as $msgName => $msgParts) { 03863 $xml .= "\n<message name=\"" . $msgName . '">'; 03864 if(is_array($msgParts)){ 03865 foreach($msgParts as $partName => $partType) { 03866 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 03867 if (strpos($partType, ':')) { 03868 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 03869 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 03870 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 03871 $typePrefix = 'xsd'; 03872 } else { 03873 foreach($this->typemap as $ns => $types) { 03874 if (isset($types[$partType])) { 03875 $typePrefix = $this->getPrefixFromNamespace($ns); 03876 } 03877 } 03878 if (!isset($typePrefix)) { 03879 die("$partType has no namespace!"); 03880 } 03881 } 03882 $ns = $this->getNamespaceFromPrefix($typePrefix); 03883 $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns); 03884 if ($typeDef['typeClass'] == 'element') { 03885 $elementortype = 'element'; 03886 } else { 03887 $elementortype = 'type'; 03888 } 03889 $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />'; 03890 } 03891 } 03892 $xml .= '</message>'; 03893 } 03894 } 03895 // bindings & porttypes 03896 if (count($this->bindings) >= 1) { 03897 $binding_xml = ''; 03898 $portType_xml = ''; 03899 foreach($this->bindings as $bindingName => $attrs) { 03900 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 03901 $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 03902 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 03903 foreach($attrs['operations'] as $opName => $opParts) { 03904 $binding_xml .= '<operation name="' . $opName . '">'; 03905 $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 03906 if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 03907 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 03908 } else { 03909 $enc_style = ''; 03910 } 03911 $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 03912 if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 03913 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 03914 } else { 03915 $enc_style = ''; 03916 } 03917 $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 03918 $binding_xml .= '</operation>'; 03919 $portType_xml .= '<operation name="' . $opParts['name'] . '"'; 03920 if (isset($opParts['parameterOrder'])) { 03921 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 03922 } 03923 $portType_xml .= '>'; 03924 if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 03925 $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 03926 } 03927 $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>'; 03928 $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>'; 03929 $portType_xml .= '</operation>'; 03930 } 03931 $portType_xml .= '</portType>'; 03932 $binding_xml .= '</binding>'; 03933 } 03934 $xml .= $portType_xml . $binding_xml; 03935 } 03936 // services 03937 $xml .= "\n<service name=\"" . $this->serviceName . '">'; 03938 if (count($this->ports) >= 1) { 03939 foreach($this->ports as $pName => $attrs) { 03940 $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 03941 $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 03942 $xml .= '</port>'; 03943 } 03944 } 03945 $xml .= '</service>'; 03946 return $xml . "\n</definitions>"; 03947 } 03948 03962 function serializeRPCParameters($operation, $direction, $parameters) 03963 { 03964 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 03965 $this->appendDebug('parameters=' . $this->varDump($parameters)); 03966 03967 if ($direction != 'input' && $direction != 'output') { 03968 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 03969 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 03970 return false; 03971 } 03972 if (!$opData = $this->getOperationData($operation)) { 03973 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 03974 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 03975 return false; 03976 } 03977 $this->debug('opData:'); 03978 $this->appendDebug($this->varDump($opData)); 03979 03980 // Get encoding style for output and set to current 03981 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 03982 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 03983 $encodingStyle = $opData['output']['encodingStyle']; 03984 $enc_style = $encodingStyle; 03985 } 03986 03987 // set input params 03988 $xml = ''; 03989 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 03990 03991 $use = $opData[$direction]['use']; 03992 $this->debug('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize'); 03993 if (is_array($parameters)) { 03994 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 03995 $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize'); 03996 foreach($opData[$direction]['parts'] as $name => $type) { 03997 $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 03998 // Track encoding style 03999 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 04000 $encodingStyle = $opData[$direction]['encodingStyle']; 04001 $enc_style = $encodingStyle; 04002 } else { 04003 $enc_style = false; 04004 } 04005 // NOTE: add error handling here 04006 // if serializeType returns false, then catch global error and fault 04007 if ($parametersArrayType == 'arraySimple') { 04008 $p = array_shift($parameters); 04009 $this->debug('calling serializeType w/indexed param'); 04010 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 04011 } elseif (isset($parameters[$name])) { 04012 $this->debug('calling serializeType w/named param'); 04013 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 04014 } else { 04015 // TODO: only send nillable 04016 $this->debug('calling serializeType w/null param'); 04017 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 04018 } 04019 } 04020 } else { 04021 $this->debug('no parameters passed.'); 04022 } 04023 } 04024 $this->debug("serializeRPCParameters returning: $xml"); 04025 return $xml; 04026 } 04027 04041 function serializeParameters($operation, $direction, $parameters) 04042 { 04043 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 04044 $this->appendDebug('parameters=' . $this->varDump($parameters)); 04045 04046 if ($direction != 'input' && $direction != 'output') { 04047 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 04048 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 04049 return false; 04050 } 04051 if (!$opData = $this->getOperationData($operation)) { 04052 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 04053 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 04054 return false; 04055 } 04056 $this->debug('opData:'); 04057 $this->appendDebug($this->varDump($opData)); 04058 04059 // Get encoding style for output and set to current 04060 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 04061 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 04062 $encodingStyle = $opData['output']['encodingStyle']; 04063 $enc_style = $encodingStyle; 04064 } 04065 04066 // set input params 04067 $xml = ''; 04068 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 04069 04070 $use = $opData[$direction]['use']; 04071 $this->debug("use=$use"); 04072 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 04073 if (is_array($parameters)) { 04074 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 04075 $this->debug('have ' . $parametersArrayType . ' parameters'); 04076 foreach($opData[$direction]['parts'] as $name => $type) { 04077 $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 04078 // Track encoding style 04079 if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 04080 $encodingStyle = $opData[$direction]['encodingStyle']; 04081 $enc_style = $encodingStyle; 04082 } else { 04083 $enc_style = false; 04084 } 04085 // NOTE: add error handling here 04086 // if serializeType returns false, then catch global error and fault 04087 if ($parametersArrayType == 'arraySimple') { 04088 $p = array_shift($parameters); 04089 $this->debug('calling serializeType w/indexed param'); 04090 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 04091 } elseif (isset($parameters[$name])) { 04092 $this->debug('calling serializeType w/named param'); 04093 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 04094 } else { 04095 // TODO: only send nillable 04096 $this->debug('calling serializeType w/null param'); 04097 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 04098 } 04099 } 04100 } else { 04101 $this->debug('no parameters passed.'); 04102 } 04103 } 04104 $this->debug("serializeParameters returning: $xml"); 04105 return $xml; 04106 } 04107 04120 function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 04121 { 04122 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 04123 $this->appendDebug("value=" . $this->varDump($value)); 04124 if($use == 'encoded' && $encodingStyle) { 04125 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 04126 } 04127 04128 // if a soapval has been supplied, let its type override the WSDL 04129 if (is_object($value) && get_class($value) == 'soapval') { 04130 if ($value->type_ns) { 04131 $type = $value->type_ns . ':' . $value->type; 04132 $forceType = true; 04133 $this->debug("in serializeType: soapval overrides type to $type"); 04134 } elseif ($value->type) { 04135 $type = $value->type; 04136 $forceType = true; 04137 $this->debug("in serializeType: soapval overrides type to $type"); 04138 } else { 04139 $forceType = false; 04140 $this->debug("in serializeType: soapval does not override type"); 04141 } 04142 $attrs = $value->attributes; 04143 $value = $value->value; 04144 $this->debug("in serializeType: soapval overrides value to $value"); 04145 if ($attrs) { 04146 if (!is_array($value)) { 04147 $value['!'] = $value; 04148 } 04149 foreach ($attrs as $n => $v) { 04150 $value['!' . $n] = $v; 04151 } 04152 $this->debug("in serializeType: soapval provides attributes"); 04153 } 04154 } else { 04155 $forceType = false; 04156 } 04157 04158 $xml = ''; 04159 if (strpos($type, ':')) { 04160 $uqType = substr($type, strrpos($type, ':') + 1); 04161 $ns = substr($type, 0, strrpos($type, ':')); 04162 $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 04163 if ($this->getNamespaceFromPrefix($ns)) { 04164 $ns = $this->getNamespaceFromPrefix($ns); 04165 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 04166 } 04167 04168 if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ 04169 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 04170 if ($unqualified && $use == 'literal') { 04171 $elementNS = " xmlns=\"\""; 04172 } else { 04173 $elementNS = ''; 04174 } 04175 if (is_null($value)) { 04176 if ($use == 'literal') { 04177 // TODO: depends on minOccurs 04178 $xml = "<$name$elementNS/>"; 04179 } else { 04180 // TODO: depends on nillable, which should be checked before calling this method 04181 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 04182 } 04183 $this->debug("in serializeType: returning: $xml"); 04184 return $xml; 04185 } 04186 if ($uqType == 'boolean') { 04187 if ((is_string($value) && $value == 'false') || (! $value)) { 04188 $value = 'false'; 04189 } else { 04190 $value = 'true'; 04191 } 04192 } 04193 if ($uqType == 'string' && gettype($value) == 'string') { 04194 $value = $this->expandEntities($value); 04195 } 04196 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 04197 $value = sprintf("%.0lf", $value); 04198 } 04199 // it's a scalar 04200 // TODO: what about null/nil values? 04201 // check type isn't a custom type extending xmlschema namespace 04202 if (!$this->getTypeDef($uqType, $ns)) { 04203 if ($use == 'literal') { 04204 if ($forceType) { 04205 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 04206 } else { 04207 $xml = "<$name$elementNS>$value</$name>"; 04208 } 04209 } else { 04210 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 04211 } 04212 $this->debug("in serializeType: returning: $xml"); 04213 return $xml; 04214 } 04215 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 04216 } else if ($ns == 'http://xml.apache.org/xml-soap') { 04217 $this->debug('in serializeType: appears to be Apache SOAP type'); 04218 if ($uqType == 'Map') { 04219 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 04220 if (! $tt_prefix) { 04221 $this->debug('in serializeType: Add namespace for Apache SOAP type'); 04222 $tt_prefix = 'ns' . rand(1000, 9999); 04223 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 04224 // force this to be added to usedNamespaces 04225 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 04226 } 04227 $contents = ''; 04228 foreach($value as $k => $v) { 04229 $this->debug("serializing map element: key $k, value $v"); 04230 $contents .= '<item>'; 04231 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); 04232 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); 04233 $contents .= '</item>'; 04234 } 04235 if ($use == 'literal') { 04236 if ($forceType) { 04237 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 04238 } else { 04239 $xml = "<$name>$contents</$name>"; 04240 } 04241 } else { 04242 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 04243 } 04244 $this->debug("in serializeType: returning: $xml"); 04245 return $xml; 04246 } 04247 $this->debug('in serializeType: Apache SOAP type, but only support Map'); 04248 } 04249 } else { 04250 // TODO: should the type be compared to types in XSD, and the namespace 04251 // set to XSD if the type matches? 04252 $this->debug("in serializeType: No namespace for type $type"); 04253 $ns = ''; 04254 $uqType = $type; 04255 } 04256 if(!$typeDef = $this->getTypeDef($uqType, $ns)){ 04257 $this->setError("$type ($uqType) is not a supported type."); 04258 $this->debug("in serializeType: $type ($uqType) is not a supported type."); 04259 return false; 04260 } else { 04261 $this->debug("in serializeType: found typeDef"); 04262 $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 04263 } 04264 $phpType = $typeDef['phpType']; 04265 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 04266 // if php type == struct, map value to the <all> element names 04267 if ($phpType == 'struct') { 04268 if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 04269 $elementName = $uqType; 04270 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 04271 $elementNS = " xmlns=\"$ns\""; 04272 } else { 04273 $elementNS = " xmlns=\"\""; 04274 } 04275 } else { 04276 $elementName = $name; 04277 if ($unqualified) { 04278 $elementNS = " xmlns=\"\""; 04279 } else { 04280 $elementNS = ''; 04281 } 04282 } 04283 if (is_null($value)) { 04284 if ($use == 'literal') { 04285 // TODO: depends on minOccurs 04286 $xml = "<$elementName$elementNS/>"; 04287 } else { 04288 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 04289 } 04290 $this->debug("in serializeType: returning: $xml"); 04291 return $xml; 04292 } 04293 if (is_object($value)) { 04294 $value = get_object_vars($value); 04295 } 04296 if (is_array($value)) { 04297 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 04298 if ($use == 'literal') { 04299 if ($forceType) { 04300 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 04301 } else { 04302 $xml = "<$elementName$elementNS$elementAttrs>"; 04303 } 04304 } else { 04305 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 04306 } 04307 04308 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 04309 $xml .= "</$elementName>"; 04310 } else { 04311 $this->debug("in serializeType: phpType is struct, but value is not an array"); 04312 $this->setError("phpType is struct, but value is not an array: see debug output for details"); 04313 $xml = ''; 04314 } 04315 } elseif ($phpType == 'array') { 04316 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 04317 $elementNS = " xmlns=\"$ns\""; 04318 } else { 04319 if ($unqualified) { 04320 $elementNS = " xmlns=\"\""; 04321 } else { 04322 $elementNS = ''; 04323 } 04324 } 04325 if (is_null($value)) { 04326 if ($use == 'literal') { 04327 // TODO: depends on minOccurs 04328 $xml = "<$name$elementNS/>"; 04329 } else { 04330 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 04331 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 04332 ":Array\" " . 04333 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 04334 ':arrayType="' . 04335 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 04336 ':' . 04337 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 04338 } 04339 $this->debug("in serializeType: returning: $xml"); 04340 return $xml; 04341 } 04342 if (isset($typeDef['multidimensional'])) { 04343 $nv = array(); 04344 foreach($value as $v) { 04345 $cols = ',' . sizeof($v); 04346 $nv = array_merge($nv, $v); 04347 } 04348 $value = $nv; 04349 } else { 04350 $cols = ''; 04351 } 04352 if (is_array($value) && sizeof($value) >= 1) { 04353 $rows = sizeof($value); 04354 $contents = ''; 04355 foreach($value as $k => $v) { 04356 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 04357 //if (strpos($typeDef['arrayType'], ':') ) { 04358 if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { 04359 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 04360 } else { 04361 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 04362 } 04363 } 04364 } else { 04365 $rows = 0; 04366 $contents = null; 04367 } 04368 // TODO: for now, an empty value will be serialized as a zero element 04369 // array. Revisit this when coding the handling of null/nil values. 04370 if ($use == 'literal') { 04371 $xml = "<$name$elementNS>" 04372 .$contents 04373 ."</$name>"; 04374 } else { 04375 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 04376 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 04377 .':arrayType="' 04378 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 04379 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 04380 .$contents 04381 ."</$name>"; 04382 } 04383 } elseif ($phpType == 'scalar') { 04384 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 04385 $elementNS = " xmlns=\"$ns\""; 04386 } else { 04387 if ($unqualified) { 04388 $elementNS = " xmlns=\"\""; 04389 } else { 04390 $elementNS = ''; 04391 } 04392 } 04393 if ($use == 'literal') { 04394 if ($forceType) { 04395 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 04396 } else { 04397 $xml = "<$name$elementNS>$value</$name>"; 04398 } 04399 } else { 04400 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 04401 } 04402 } 04403 $this->debug("in serializeType: returning: $xml"); 04404 return $xml; 04405 } 04406 04417 function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 04418 $xml = ''; 04419 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 04420 $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 04421 if (is_array($value)) { 04422 $xvalue = $value; 04423 } elseif (is_object($value)) { 04424 $xvalue = get_object_vars($value); 04425 } else { 04426 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 04427 $xvalue = array(); 04428 } 04429 foreach ($typeDef['attrs'] as $aName => $attrs) { 04430 if (isset($xvalue['!' . $aName])) { 04431 $xname = '!' . $aName; 04432 $this->debug("value provided for attribute $aName with key $xname"); 04433 } elseif (isset($xvalue[$aName])) { 04434 $xname = $aName; 04435 $this->debug("value provided for attribute $aName with key $xname"); 04436 } elseif (isset($attrs['default'])) { 04437 $xname = '!' . $aName; 04438 $xvalue[$xname] = $attrs['default']; 04439 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 04440 } else { 04441 $xname = ''; 04442 $this->debug("no value provided for attribute $aName"); 04443 } 04444 if ($xname) { 04445 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 04446 } 04447 } 04448 } else { 04449 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 04450 } 04451 if (isset($typeDef['extensionBase'])) { 04452 $ns = $this->getPrefix($typeDef['extensionBase']); 04453 $uqType = $this->getLocalPart($typeDef['extensionBase']); 04454 if ($this->getNamespaceFromPrefix($ns)) { 04455 $ns = $this->getNamespaceFromPrefix($ns); 04456 } 04457 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 04458 $this->debug("serialize attributes for extension base $ns:$uqType"); 04459 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 04460 } else { 04461 $this->debug("extension base $ns:$uqType is not a supported type"); 04462 } 04463 } 04464 return $xml; 04465 } 04466 04479 function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 04480 $xml = ''; 04481 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 04482 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 04483 if (is_array($value)) { 04484 $xvalue = $value; 04485 } elseif (is_object($value)) { 04486 $xvalue = get_object_vars($value); 04487 } else { 04488 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 04489 $xvalue = array(); 04490 } 04491 // toggle whether all elements are present - ideally should validate against schema 04492 if (count($typeDef['elements']) != count($xvalue)){ 04493 $optionals = true; 04494 } 04495 foreach ($typeDef['elements'] as $eName => $attrs) { 04496 if (!isset($xvalue[$eName])) { 04497 if (isset($attrs['default'])) { 04498 $xvalue[$eName] = $attrs['default']; 04499 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 04500 } 04501 } 04502 // if user took advantage of a minOccurs=0, then only serialize named parameters 04503 if (isset($optionals) 04504 && (!isset($xvalue[$eName])) 04505 && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 04506 ){ 04507 if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 04508 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 04509 } 04510 // do nothing 04511 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 04512 } else { 04513 // get value 04514 if (isset($xvalue[$eName])) { 04515 $v = $xvalue[$eName]; 04516 } else { 04517 $v = null; 04518 } 04519 if (isset($attrs['form'])) { 04520 $unqualified = ($attrs['form'] == 'unqualified'); 04521 } else { 04522 $unqualified = false; 04523 } 04524 if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 04525 $vv = $v; 04526 foreach ($vv as $k => $v) { 04527 if (isset($attrs['type']) || isset($attrs['ref'])) { 04528 // serialize schema-defined type 04529 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 04530 } else { 04531 // serialize generic type (can this ever really happen?) 04532 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 04533 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 04534 } 04535 } 04536 } else { 04537 if (isset($attrs['type']) || isset($attrs['ref'])) { 04538 // serialize schema-defined type 04539 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 04540 } else { 04541 // serialize generic type (can this ever really happen?) 04542 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 04543 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 04544 } 04545 } 04546 } 04547 } 04548 } else { 04549 $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 04550 } 04551 if (isset($typeDef['extensionBase'])) { 04552 $ns = $this->getPrefix($typeDef['extensionBase']); 04553 $uqType = $this->getLocalPart($typeDef['extensionBase']); 04554 if ($this->getNamespaceFromPrefix($ns)) { 04555 $ns = $this->getNamespaceFromPrefix($ns); 04556 } 04557 if ($typeDef = $this->getTypeDef($uqType, $ns)) { 04558 $this->debug("serialize elements for extension base $ns:$uqType"); 04559 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 04560 } else { 04561 $this->debug("extension base $ns:$uqType is not a supported type"); 04562 } 04563 } 04564 return $xml; 04565 } 04566 04581 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { 04582 if (count($elements) > 0) { 04583 foreach($elements as $n => $e){ 04584 // expand each element 04585 foreach ($e as $k => $v) { 04586 $k = strpos($k,':') ? $this->expandQname($k) : $k; 04587 $v = strpos($v,':') ? $this->expandQname($v) : $v; 04588 $ee[$k] = $v; 04589 } 04590 $eElements[$n] = $ee; 04591 } 04592 $elements = $eElements; 04593 } 04594 04595 if (count($attrs) > 0) { 04596 foreach($attrs as $n => $a){ 04597 // expand each attribute 04598 foreach ($a as $k => $v) { 04599 $k = strpos($k,':') ? $this->expandQname($k) : $k; 04600 $v = strpos($v,':') ? $this->expandQname($v) : $v; 04601 $aa[$k] = $v; 04602 } 04603 $eAttrs[$n] = $aa; 04604 } 04605 $attrs = $eAttrs; 04606 } 04607 04608 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 04609 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; 04610 04611 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 04612 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); 04613 } 04614 04626 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 04627 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 04628 04629 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 04630 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 04631 } 04632 04640 function addElement($attrs) { 04641 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 04642 $this->schemas[$typens][0]->addElement($attrs); 04643 } 04644 04659 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ 04660 if ($use == 'encoded' && $encodingStyle == '') { 04661 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 04662 } 04663 04664 if ($style == 'document') { 04665 $elements = array(); 04666 foreach ($in as $n => $t) { 04667 $elements[$n] = array('name' => $n, 'type' => $t); 04668 } 04669 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 04670 $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 04671 $in = array('parameters' => 'tns:' . $name); 04672 04673 $elements = array(); 04674 foreach ($out as $n => $t) { 04675 $elements[$n] = array('name' => $n, 'type' => $t); 04676 } 04677 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 04678 $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType')); 04679 $out = array('parameters' => 'tns:' . $name . 'Response'); 04680 } 04681 04682 // get binding 04683 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 04684 array( 04685 'name' => $name, 04686 'binding' => $this->serviceName . 'Binding', 04687 'endpoint' => $this->endpoint, 04688 'soapAction' => $soapaction, 04689 'style' => $style, 04690 'input' => array( 04691 'use' => $use, 04692 'namespace' => $namespace, 04693 'encodingStyle' => $encodingStyle, 04694 'message' => $name . 'Request', 04695 'parts' => $in), 04696 'output' => array( 04697 'use' => $use, 04698 'namespace' => $namespace, 04699 'encodingStyle' => $encodingStyle, 04700 'message' => $name . 'Response', 04701 'parts' => $out), 04702 'namespace' => $namespace, 04703 'transport' => 'http://schemas.xmlsoap.org/soap/http', 04704 'documentation' => $documentation); 04705 // add portTypes 04706 // add messages 04707 if($in) 04708 { 04709 foreach($in as $pName => $pType) 04710 { 04711 if(strpos($pType,':')) { 04712 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 04713 } 04714 $this->messages[$name.'Request'][$pName] = $pType; 04715 } 04716 } else { 04717 $this->messages[$name.'Request']= '0'; 04718 } 04719 if($out) 04720 { 04721 foreach($out as $pName => $pType) 04722 { 04723 if(strpos($pType,':')) { 04724 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 04725 } 04726 $this->messages[$name.'Response'][$pName] = $pType; 04727 } 04728 } else { 04729 $this->messages[$name.'Response']= '0'; 04730 } 04731 return true; 04732 } 04733 } 04734 04735 04736 04745 class soap_parser extends nusoap_base { 04746 04747 var $xml = ''; 04748 var $xml_encoding = ''; 04749 var $method = ''; 04750 var $root_struct = ''; 04751 var $root_struct_name = ''; 04752 var $root_struct_namespace = ''; 04753 var $root_header = ''; 04754 var $document = ''; // incoming SOAP body (text) 04755 // determines where in the message we are (envelope,header,body,method) 04756 var $status = ''; 04757 var $position = 0; 04758 var $depth = 0; 04759 var $default_namespace = ''; 04760 var $namespaces = array(); 04761 var $message = array(); 04762 var $parent = ''; 04763 var $fault = false; 04764 var $fault_code = ''; 04765 var $fault_str = ''; 04766 var $fault_detail = ''; 04767 var $depth_array = array(); 04768 var $debug_flag = true; 04769 var $soapresponse = NULL; 04770 var $responseHeaders = ''; // incoming SOAP headers (text) 04771 var $body_position = 0; 04772 // for multiref parsing: 04773 // array of id => pos 04774 var $ids = array(); 04775 // array of id => hrefs => pos 04776 var $multirefs = array(); 04777 // toggle for auto-decoding element content 04778 var $decode_utf8 = true; 04779 04789 function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ 04790 parent::nusoap_base(); 04791 $this->xml = $xml; 04792 $this->xml_encoding = $encoding; 04793 $this->method = $method; 04794 $this->decode_utf8 = $decode_utf8; 04795 04796 // Check whether content has been read. 04797 if(!empty($xml)){ 04798 // Check XML encoding 04799 $pos_xml = strpos($xml, '<?xml'); 04800 if ($pos_xml !== FALSE) { 04801 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); 04802 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { 04803 $xml_encoding = $res[1]; 04804 if (strtoupper($xml_encoding) != $encoding) { 04805 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; 04806 $this->debug($err); 04807 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { 04808 $this->setError($err); 04809 return; 04810 } 04811 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed 04812 } else { 04813 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); 04814 } 04815 } else { 04816 $this->debug('No encoding specified in XML declaration'); 04817 } 04818 } else { 04819 $this->debug('No XML declaration'); 04820 } 04821 $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding); 04822 // Create an XML parser - why not xml_parser_create_ns? 04823 $this->parser = xml_parser_create($this->xml_encoding); 04824 // Set the options for parsing the XML data. 04825 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 04826 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 04827 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); 04828 // Set the object for the parser. 04829 xml_set_object($this->parser, $this); 04830 // Set the element handlers for the parser. 04831 xml_set_element_handler($this->parser, 'start_element','end_element'); 04832 xml_set_character_data_handler($this->parser,'character_data'); 04833 04834 // Parse the XML file. 04835 if(!xml_parse($this->parser,$xml,true)){ 04836 // Display an error message. 04837 $err = sprintf('XML error parsing SOAP payload on line %d: %s', 04838 xml_get_current_line_number($this->parser), 04839 xml_error_string(xml_get_error_code($this->parser))); 04840 $this->debug($err); 04841 $this->debug("XML payload:\n" . $xml); 04842 $this->setError($err); 04843 } else { 04844 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); 04845 // get final value 04846 $this->soapresponse = $this->message[$this->root_struct]['result']; 04847 // get header value: no, because this is documented as XML string 04848 // if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ 04849 // $this->responseHeaders = $this->message[$this->root_header]['result']; 04850 // } 04851 // resolve hrefs/ids 04852 if(sizeof($this->multirefs) > 0){ 04853 foreach($this->multirefs as $id => $hrefs){ 04854 $this->debug('resolving multirefs for id: '.$id); 04855 $idVal = $this->buildVal($this->ids[$id]); 04856 if (is_array($idVal) && isset($idVal['!id'])) { 04857 unset($idVal['!id']); 04858 } 04859 foreach($hrefs as $refPos => $ref){ 04860 $this->debug('resolving href at pos '.$refPos); 04861 $this->multirefs[$id][$refPos] = $idVal; 04862 } 04863 } 04864 } 04865 } 04866 xml_parser_free($this->parser); 04867 } else { 04868 $this->debug('xml was empty, didn\'t parse!'); 04869 $this->setError('xml was empty, didn\'t parse!'); 04870 } 04871 } 04872 04881 function start_element($parser, $name, $attrs) { 04882 // position in a total number of elements, starting from 0 04883 // update class level pos 04884 $pos = $this->position++; 04885 // and set mine 04886 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); 04887 // depth = how many levels removed from root? 04888 // set mine as current global depth and increment global depth value 04889 $this->message[$pos]['depth'] = $this->depth++; 04890 04891 // else add self as child to whoever the current parent is 04892 if($pos != 0){ 04893 $this->message[$this->parent]['children'] .= '|'.$pos; 04894 } 04895 // set my parent 04896 $this->message[$pos]['parent'] = $this->parent; 04897 // set self as current parent 04898 $this->parent = $pos; 04899 // set self as current value for this depth 04900 $this->depth_array[$this->depth] = $pos; 04901 // get element prefix 04902 if(strpos($name,':')){ 04903 // get ns prefix 04904 $prefix = substr($name,0,strpos($name,':')); 04905 // get unqualified name 04906 $name = substr(strstr($name,':'),1); 04907 } 04908 // set status 04909 if($name == 'Envelope'){ 04910 $this->status = 'envelope'; 04911 } elseif($name == 'Header'){ 04912 $this->root_header = $pos; 04913 $this->status = 'header'; 04914 } elseif($name == 'Body'){ 04915 $this->status = 'body'; 04916 $this->body_position = $pos; 04917 // set method 04918 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){ 04919 $this->status = 'method'; 04920 $this->root_struct_name = $name; 04921 $this->root_struct = $pos; 04922 $this->message[$pos]['type'] = 'struct'; 04923 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); 04924 } 04925 // set my status 04926 $this->message[$pos]['status'] = $this->status; 04927 // set name 04928 $this->message[$pos]['name'] = htmlspecialchars($name); 04929 // set attrs 04930 $this->message[$pos]['attrs'] = $attrs; 04931 04932 // loop through atts, logging ns and type declarations 04933 $attstr = ''; 04934 foreach($attrs as $key => $value){ 04935 $key_prefix = $this->getPrefix($key); 04936 $key_localpart = $this->getLocalPart($key); 04937 // if ns declarations, add to class level array of valid namespaces 04938 if($key_prefix == 'xmlns'){ 04939 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ 04940 $this->XMLSchemaVersion = $value; 04941 $this->namespaces['xsd'] = $this->XMLSchemaVersion; 04942 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; 04943 } 04944 $this->namespaces[$key_localpart] = $value; 04945 // set method namespace 04946 if($name == $this->root_struct_name){ 04947 $this->methodNamespace = $value; 04948 } 04949 // if it's a type declaration, set type 04950 } elseif($key_localpart == 'type'){ 04951 $value_prefix = $this->getPrefix($value); 04952 $value_localpart = $this->getLocalPart($value); 04953 $this->message[$pos]['type'] = $value_localpart; 04954 $this->message[$pos]['typePrefix'] = $value_prefix; 04955 if(isset($this->namespaces[$value_prefix])){ 04956 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; 04957 } else if(isset($attrs['xmlns:'.$value_prefix])) { 04958 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; 04959 } 04960 // should do something here with the namespace of specified type? 04961 } elseif($key_localpart == 'arrayType'){ 04962 $this->message[$pos]['type'] = 'array'; 04963 /* do arrayType ereg here 04964 [1] arrayTypeValue ::= atype asize 04965 [2] atype ::= QName rank* 04966 [3] rank ::= '[' (',')* ']' 04967 [4] asize ::= '[' length~ ']' 04968 [5] length ::= nextDimension* Digit+ 04969 [6] nextDimension ::= Digit+ ',' 04970 */ 04971 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; 04972 if(ereg($expr,$value,$regs)){ 04973 $this->message[$pos]['typePrefix'] = $regs[1]; 04974 $this->message[$pos]['arrayTypePrefix'] = $regs[1]; 04975 if (isset($this->namespaces[$regs[1]])) { 04976 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; 04977 } else if (isset($attrs['xmlns:'.$regs[1]])) { 04978 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; 04979 } 04980 $this->message[$pos]['arrayType'] = $regs[2]; 04981 $this->message[$pos]['arraySize'] = $regs[3]; 04982 $this->message[$pos]['arrayCols'] = $regs[4]; 04983 } 04984 // specifies nil value (or not) 04985 } elseif ($key_localpart == 'nil'){ 04986 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); 04987 // some other attribute 04988 } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { 04989 $this->message[$pos]['xattrs']['!' . $key] = $value; 04990 } 04991 04992 if ($key == 'xmlns') { 04993 $this->default_namespace = $value; 04994 } 04995 // log id 04996 if($key == 'id'){ 04997 $this->ids[$value] = $pos; 04998 } 04999 // root 05000 if($key_localpart == 'root' && $value == 1){ 05001 $this->status = 'method'; 05002 $this->root_struct_name = $name; 05003 $this->root_struct = $pos; 05004 $this->debug("found root struct $this->root_struct_name, pos $pos"); 05005 } 05006 // for doclit 05007 $attstr .= " $key=\"$value\""; 05008 } 05009 // get namespace - must be done after namespace atts are processed 05010 if(isset($prefix)){ 05011 $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; 05012 $this->default_namespace = $this->namespaces[$prefix]; 05013 } else { 05014 $this->message[$pos]['namespace'] = $this->default_namespace; 05015 } 05016 if($this->status == 'header'){ 05017 if ($this->root_header != $pos) { 05018 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 05019 } 05020 } elseif($this->root_struct_name != ''){ 05021 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 05022 } 05023 } 05024 05032 function end_element($parser, $name) { 05033 // position of current element is equal to the last value left in depth_array for my depth 05034 $pos = $this->depth_array[$this->depth--]; 05035 05036 // get element prefix 05037 if(strpos($name,':')){ 05038 // get ns prefix 05039 $prefix = substr($name,0,strpos($name,':')); 05040 // get unqualified name 05041 $name = substr(strstr($name,':'),1); 05042 } 05043 05044 // build to native type 05045 if(isset($this->body_position) && $pos > $this->body_position){ 05046 // deal w/ multirefs 05047 if(isset($this->message[$pos]['attrs']['href'])){ 05048 // get id 05049 $id = substr($this->message[$pos]['attrs']['href'],1); 05050 // add placeholder to href array 05051 $this->multirefs[$id][$pos] = 'placeholder'; 05052 // add set a reference to it as the result value 05053 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; 05054 // build complexType values 05055 } elseif($this->message[$pos]['children'] != ''){ 05056 // if result has already been generated (struct/array) 05057 if(!isset($this->message[$pos]['result'])){ 05058 $this->message[$pos]['result'] = $this->buildVal($pos); 05059 } 05060 // build complexType values of attributes and possibly simpleContent 05061 } elseif (isset($this->message[$pos]['xattrs'])) { 05062 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 05063 $this->message[$pos]['xattrs']['!'] = null; 05064 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 05065 if (isset($this->message[$pos]['type'])) { 05066 $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'] : ''); 05067 } else { 05068 $parent = $this->message[$pos]['parent']; 05069 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 05070 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 05071 } else { 05072 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; 05073 } 05074 } 05075 } 05076 $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; 05077 // set value of simpleType (or nil complexType) 05078 } else { 05079 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); 05080 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 05081 $this->message[$pos]['xattrs']['!'] = null; 05082 } elseif (isset($this->message[$pos]['type'])) { 05083 $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'] : ''); 05084 } else { 05085 $parent = $this->message[$pos]['parent']; 05086 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 05087 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 05088 } else { 05089 $this->message[$pos]['result'] = $this->message[$pos]['cdata']; 05090 } 05091 } 05092 05093 /* add value to parent's result, if parent is struct/array 05094 $parent = $this->message[$pos]['parent']; 05095 if($this->message[$parent]['type'] != 'map'){ 05096 if(strtolower($this->message[$parent]['type']) == 'array'){ 05097 $this->message[$parent]['result'][] = $this->message[$pos]['result']; 05098 } else { 05099 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; 05100 } 05101 } 05102 */ 05103 } 05104 } 05105 05106 // for doclit 05107 if($this->status == 'header'){ 05108 if ($this->root_header != $pos) { 05109 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 05110 } 05111 } elseif($pos >= $this->root_struct){ 05112 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 05113 } 05114 // switch status 05115 if($pos == $this->root_struct){ 05116 $this->status = 'body'; 05117 $this->root_struct_namespace = $this->message[$pos]['namespace']; 05118 } elseif($name == 'Body'){ 05119 $this->status = 'envelope'; 05120 } elseif($name == 'Header'){ 05121 $this->status = 'envelope'; 05122 } elseif($name == 'Envelope'){ 05123 // 05124 } 05125 // set parent back to my parent 05126 $this->parent = $this->message[$pos]['parent']; 05127 } 05128 05136 function character_data($parser, $data){ 05137 $pos = $this->depth_array[$this->depth]; 05138 if ($this->xml_encoding=='UTF-8'){ 05139 // TODO: add an option to disable this for folks who want 05140 // raw UTF-8 that, e.g., might not map to iso-8859-1 05141 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); 05142 if($this->decode_utf8){ 05143 $data = utf8_decode($data); 05144 } 05145 } 05146 $this->message[$pos]['cdata'] .= $data; 05147 // for doclit 05148 if($this->status == 'header'){ 05149 $this->responseHeaders .= $data; 05150 } else { 05151 $this->document .= $data; 05152 } 05153 } 05154 05161 function get_response(){ 05162 return $this->soapresponse; 05163 } 05164 05171 function getHeaders(){ 05172 return $this->responseHeaders; 05173 } 05174 05184 function decodeSimple($value, $type, $typens) { 05185 // TODO: use the namespace! 05186 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { 05187 return (string) $value; 05188 } 05189 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { 05190 return (int) $value; 05191 } 05192 if ($type == 'float' || $type == 'double' || $type == 'decimal') { 05193 return (double) $value; 05194 } 05195 if ($type == 'boolean') { 05196 if (strtolower($value) == 'false' || strtolower($value) == 'f') { 05197 return false; 05198 } 05199 return (boolean) $value; 05200 } 05201 if ($type == 'base64' || $type == 'base64Binary') { 05202 $this->debug('Decode base64 value'); 05203 return base64_decode($value); 05204 } 05205 // obscure numeric types 05206 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' 05207 || $type == 'nonNegativeInteger' || $type == 'positiveInteger' 05208 || $type == 'unsignedInt' 05209 || $type == 'unsignedShort' || $type == 'unsignedByte') { 05210 return (int) $value; 05211 } 05212 // bogus: parser treats array with no elements as a simple type 05213 if ($type == 'array') { 05214 return array(); 05215 } 05216 // everything else 05217 return (string) $value; 05218 } 05219 05228 function buildVal($pos){ 05229 if(!isset($this->message[$pos]['type'])){ 05230 $this->message[$pos]['type'] = ''; 05231 } 05232 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); 05233 // if there are children... 05234 if($this->message[$pos]['children'] != ''){ 05235 $this->debug('in buildVal, there are children'); 05236 $children = explode('|',$this->message[$pos]['children']); 05237 array_shift($children); // knock off empty 05238 // md array 05239 if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ 05240 $r=0; // rowcount 05241 $c=0; // colcount 05242 foreach($children as $child_pos){ 05243 $this->debug("in buildVal, got an MD array element: $r, $c"); 05244 $params[$r][] = $this->message[$child_pos]['result']; 05245 $c++; 05246 if($c == $this->message[$pos]['arrayCols']){ 05247 $c = 0; 05248 $r++; 05249 } 05250 } 05251 // array 05252 } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ 05253 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); 05254 foreach($children as $child_pos){ 05255 $params[] = &$this->message[$child_pos]['result']; 05256 } 05257 // apache Map type: java hashtable 05258 } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ 05259 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); 05260 foreach($children as $child_pos){ 05261 $kv = explode("|",$this->message[$child_pos]['children']); 05262 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; 05263 } 05264 // generic compound type 05265 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { 05266 } else { 05267 // Apache Vector type: treat as an array 05268 $this->debug('in buildVal, adding Java Vector '.$this->message[$pos]['name']); 05269 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { 05270 $notstruct = 1; 05271 } else { 05272 $notstruct = 0; 05273 } 05274 // 05275 foreach($children as $child_pos){ 05276 if($notstruct){ 05277 $params[] = &$this->message[$child_pos]['result']; 05278 } else { 05279 if (isset($params[$this->message[$child_pos]['name']])) { 05280 // de-serialize repeated element name into an array 05281 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { 05282 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); 05283 } 05284 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; 05285 } else { 05286 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; 05287 } 05288 } 05289 } 05290 } 05291 if (isset($this->message[$pos]['xattrs'])) { 05292 $this->debug('in buildVal, handling attributes'); 05293 foreach ($this->message[$pos]['xattrs'] as $n => $v) { 05294 $params[$n] = $v; 05295 } 05296 } 05297 // handle simpleContent 05298 if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 05299 $this->debug('in buildVal, handling simpleContent'); 05300 if (isset($this->message[$pos]['type'])) { 05301 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 05302 } else { 05303 $parent = $this->message[$pos]['parent']; 05304 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 05305 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 05306 } else { 05307 $params['!'] = $this->message[$pos]['cdata']; 05308 } 05309 } 05310 } 05311 return is_array($params) ? $params : array(); 05312 } else { 05313 $this->debug('in buildVal, no children, building scalar'); 05314 $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; 05315 if (isset($this->message[$pos]['type'])) { 05316 return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 05317 } 05318 $parent = $this->message[$pos]['parent']; 05319 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 05320 return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 05321 } 05322 return $this->message[$pos]['cdata']; 05323 } 05324 } 05325 } 05326 05327 05328 05348 class soapclient extends nusoap_base { 05349 05350 var $username = ''; 05351 var $password = ''; 05352 var $authtype = ''; 05353 var $certRequest = array(); 05354 var $requestHeaders = false; // SOAP headers in request (text) 05355 var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) 05356 var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) 05357 var $endpoint; 05358 var $forceEndpoint = ''; // overrides WSDL endpoint 05359 var $proxyhost = ''; 05360 var $proxyport = ''; 05361 var $proxyusername = ''; 05362 var $proxypassword = ''; 05363 var $xml_encoding = ''; // character set encoding of incoming (response) messages 05364 var $http_encoding = false; 05365 var $timeout = 0; // HTTP connection timeout 05366 var $response_timeout = 30; // HTTP response timeout 05367 var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error 05368 var $persistentConnection = false; 05369 var $defaultRpcParams = false; // This is no longer used 05370 var $request = ''; // HTTP request 05371 var $response = ''; // HTTP response 05372 var $responseData = ''; // SOAP payload of response 05373 var $cookies = array(); // Cookies from response or for request 05374 var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() 05375 var $operations = array(); // WSDL operations, empty for WSDL initialization error 05376 05377 /* 05378 * fault related variables 05379 */ 05384 var $fault; 05389 var $faultcode; 05394 var $faultstring; 05399 var $faultdetail; 05400 05415 function soapclient($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ 05416 parent::nusoap_base(); 05417 $this->endpoint = $endpoint; 05418 $this->proxyhost = $proxyhost; 05419 $this->proxyport = $proxyport; 05420 $this->proxyusername = $proxyusername; 05421 $this->proxypassword = $proxypassword; 05422 $this->timeout = $timeout; 05423 $this->response_timeout = $response_timeout; 05424 05425 // make values 05426 if($wsdl){ 05427 if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { 05428 $this->wsdl = $endpoint; 05429 $this->endpoint = $this->wsdl->wsdl; 05430 $this->wsdlFile = $this->endpoint; 05431 $this->debug('existing wsdl instance created from ' . $this->endpoint); 05432 } else { 05433 $this->wsdlFile = $this->endpoint; 05434 05435 // instantiate wsdl object and parse wsdl file 05436 $this->debug('instantiating wsdl class with doc: '.$endpoint); 05437 $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout); 05438 } 05439 $this->appendDebug($this->wsdl->getDebug()); 05440 $this->wsdl->clearDebug(); 05441 // catch errors 05442 if($errstr = $this->wsdl->getError()){ 05443 $this->debug('got wsdl error: '.$errstr); 05444 $this->setError('wsdl error: '.$errstr); 05445 } elseif($this->operations = $this->wsdl->getOperations()){ 05446 $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile); 05447 $this->endpointType = 'wsdl'; 05448 } else { 05449 $this->debug( 'getOperations returned false'); 05450 $this->setError('no operations defined in the WSDL document!'); 05451 } 05452 } else { 05453 $this->debug("instantiate SOAP with endpoint at $endpoint"); 05454 $this->endpointType = 'soap'; 05455 } 05456 } 05457 05483 function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ 05484 $this->operation = $operation; 05485 $this->fault = false; 05486 $this->setError(''); 05487 $this->request = ''; 05488 $this->response = ''; 05489 $this->responseData = ''; 05490 $this->faultstring = ''; 05491 $this->faultcode = ''; 05492 $this->opData = array(); 05493 05494 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); 05495 $this->appendDebug('params=' . $this->varDump($params)); 05496 $this->appendDebug('headers=' . $this->varDump($headers)); 05497 if ($headers) { 05498 $this->requestHeaders = $headers; 05499 } 05500 // serialize parameters 05501 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ 05502 // use WSDL for operation 05503 $this->opData = $opData; 05504 $this->debug("found operation"); 05505 $this->appendDebug('opData=' . $this->varDump($opData)); 05506 if (isset($opData['soapAction'])) { 05507 $soapAction = $opData['soapAction']; 05508 } 05509 if (! $this->forceEndpoint) { 05510 $this->endpoint = $opData['endpoint']; 05511 } else { 05512 $this->endpoint = $this->forceEndpoint; 05513 } 05514 $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; 05515 $style = $opData['style']; 05516 $use = $opData['input']['use']; 05517 // add ns to ns array 05518 if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ 05519 $nsPrefix = 'ns' . rand(1000, 9999); 05520 $this->wsdl->namespaces[$nsPrefix] = $namespace; 05521 } 05522 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); 05523 // serialize payload 05524 if (is_string($params)) { 05525 $this->debug("serializing param string for WSDL operation $operation"); 05526 $payload = $params; 05527 } elseif (is_array($params)) { 05528 $this->debug("serializing param array for WSDL operation $operation"); 05529 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params); 05530 } else { 05531 $this->debug('params must be array or string'); 05532 $this->setError('params must be array or string'); 05533 return false; 05534 } 05535 $usedNamespaces = $this->wsdl->usedNamespaces; 05536 if (isset($opData['input']['encodingStyle'])) { 05537 $encodingStyle = $opData['input']['encodingStyle']; 05538 } else { 05539 $encodingStyle = ''; 05540 } 05541 $this->appendDebug($this->wsdl->getDebug()); 05542 $this->wsdl->clearDebug(); 05543 if ($errstr = $this->wsdl->getError()) { 05544 $this->debug('got wsdl error: '.$errstr); 05545 $this->setError('wsdl error: '.$errstr); 05546 return false; 05547 } 05548 } elseif($this->endpointType == 'wsdl') { 05549 // operation not in WSDL 05550 $this->appendDebug($this->wsdl->getDebug()); 05551 $this->wsdl->clearDebug(); 05552 $this->setError( 'operation '.$operation.' not present.'); 05553 $this->debug("operation '$operation' not present."); 05554 return false; 05555 } else { 05556 // no WSDL 05557 //$this->namespaces['ns1'] = $namespace; 05558 $nsPrefix = 'ns' . rand(1000, 9999); 05559 // serialize 05560 $payload = ''; 05561 if (is_string($params)) { 05562 $this->debug("serializing param string for operation $operation"); 05563 $payload = $params; 05564 } elseif (is_array($params)) { 05565 $this->debug("serializing param array for operation $operation"); 05566 foreach($params as $k => $v){ 05567 $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); 05568 } 05569 } else { 05570 $this->debug('params must be array or string'); 05571 $this->setError('params must be array or string'); 05572 return false; 05573 } 05574 $usedNamespaces = array(); 05575 if ($use == 'encoded') { 05576 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 05577 } else { 05578 $encodingStyle = ''; 05579 } 05580 } 05581 // wrap RPC calls with method element 05582 if ($style == 'rpc') { 05583 if ($use == 'literal') { 05584 $this->debug("wrapping RPC request with literal method element"); 05585 if ($namespace) { 05586 $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>"; 05587 } else { 05588 $payload = "<$operation>" . $payload . "</$operation>"; 05589 } 05590 } else { 05591 $this->debug("wrapping RPC request with encoded method element"); 05592 if ($namespace) { 05593 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 05594 $payload . 05595 "</$nsPrefix:$operation>"; 05596 } else { 05597 $payload = "<$operation>" . 05598 $payload . 05599 "</$operation>"; 05600 } 05601 } 05602 } 05603 // serialize envelope 05604 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); 05605 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); 05606 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); 05607 // send 05608 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); 05609 if($errstr = $this->getError()){ 05610 $this->debug('Error: '.$errstr); 05611 return false; 05612 } else { 05613 $this->return = $return; 05614 $this->debug('sent message successfully and got a(n) '.gettype($return)); 05615 $this->appendDebug('return=' . $this->varDump($return)); 05616 05617 // fault? 05618 if(is_array($return) && isset($return['faultcode'])){ 05619 $this->debug('got fault'); 05620 $this->setError($return['faultcode'].': '.$return['faultstring']); 05621 $this->fault = true; 05622 foreach($return as $k => $v){ 05623 $this->$k = $v; 05624 $this->debug("$k = $v<br>"); 05625 } 05626 return $return; 05627 } elseif ($style == 'document') { 05628 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), 05629 // we are only going to return the first part here...sorry about that 05630 return $return; 05631 } else { 05632 // array of return values 05633 if(is_array($return)){ 05634 // multiple 'out' parameters, which we return wrapped up 05635 // in the array 05636 if(sizeof($return) > 1){ 05637 return $return; 05638 } 05639 // single 'out' parameter (normally the return value) 05640 $return = array_shift($return); 05641 $this->debug('return shifted value: '); 05642 $this->appendDebug($this->varDump($return)); 05643 return $return; 05644 // nothing returned (ie, echoVoid) 05645 } else { 05646 return ""; 05647 } 05648 } 05649 } 05650 } 05651 05659 function getOperationData($operation){ 05660 if(isset($this->operations[$operation])){ 05661 return $this->operations[$operation]; 05662 } 05663 $this->debug("No data for operation: $operation"); 05664 } 05665 05680 function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { 05681 $this->checkCookies(); 05682 // detect transport 05683 switch(true){ 05684 // http(s) 05685 case ereg('^http',$this->endpoint): 05686 $this->debug('transporting via HTTP'); 05687 if($this->persistentConnection == true && is_object($this->persistentConnection)){ 05688 $http =& $this->persistentConnection; 05689 } else { 05690 $http = new soap_transport_http($this->endpoint); 05691 if ($this->persistentConnection) { 05692 $http->usePersistentConnection(); 05693 } 05694 } 05695 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); 05696 $http->setSOAPAction($soapaction); 05697 if($this->proxyhost && $this->proxyport){ 05698 $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 05699 } 05700 if($this->authtype != '') { 05701 $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 05702 } 05703 if($this->http_encoding != ''){ 05704 $http->setEncoding($this->http_encoding); 05705 } 05706 $this->debug('sending message, length='.strlen($msg)); 05707 if(ereg('^http:',$this->endpoint)){ 05708 //if(strpos($this->endpoint,'http:')){ 05709 $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); 05710 } elseif(ereg('^https',$this->endpoint)){ 05711 //} elseif(strpos($this->endpoint,'https:')){ 05712 //if(phpversion() == '4.3.0-dev'){ 05713 //$response = $http->send($msg,$timeout,$response_timeout); 05714 //$this->request = $http->outgoing_payload; 05715 //$this->response = $http->incoming_payload; 05716 //} else 05717 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); 05718 } else { 05719 $this->setError('no http/s in endpoint url'); 05720 } 05721 $this->request = $http->outgoing_payload; 05722 $this->response = $http->incoming_payload; 05723 $this->appendDebug($http->getDebug()); 05724 $this->UpdateCookies($http->incoming_cookies); 05725 05726 // save transport object if using persistent connections 05727 if ($this->persistentConnection) { 05728 $http->clearDebug(); 05729 if (!is_object($this->persistentConnection)) { 05730 $this->persistentConnection = $http; 05731 } 05732 } 05733 05734 if($err = $http->getError()){ 05735 $this->setError('HTTP Error: '.$err); 05736 return false; 05737 } elseif($this->getError()){ 05738 return false; 05739 } else { 05740 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); 05741 return $this->parseResponse($http->incoming_headers, $this->responseData); 05742 } 05743 break; 05744 default: 05745 $this->setError('no transport found, or selected transport is not yet supported!'); 05746 return false; 05747 break; 05748 } 05749 } 05750 05759 function parseResponse($headers, $data) { 05760 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); 05761 if (!strstr($headers['content-type'], 'text/xml')) { 05762 $this->setError('Response not of type text/xml'); 05763 return false; 05764 } 05765 if (strpos($headers['content-type'], '=')) { 05766 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 05767 $this->debug('Got response encoding: ' . $enc); 05768 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 05769 $this->xml_encoding = strtoupper($enc); 05770 } else { 05771 $this->xml_encoding = 'US-ASCII'; 05772 } 05773 } else { 05774 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 05775 $this->xml_encoding = 'ISO-8859-1'; 05776 } 05777 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser'); 05778 $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); 05779 // add parser debug data to our debug 05780 $this->appendDebug($parser->getDebug()); 05781 // if parse errors 05782 if($errstr = $parser->getError()){ 05783 $this->setError( $errstr); 05784 // destroy the parser object 05785 unset($parser); 05786 return false; 05787 } else { 05788 // get SOAP headers 05789 $this->responseHeaders = $parser->getHeaders(); 05790 // get decoded message 05791 $return = $parser->get_response(); 05792 // add document for doclit support 05793 $this->document = $parser->document; 05794 // destroy the parser object 05795 unset($parser); 05796 // return decode message 05797 return $return; 05798 } 05799 } 05800 05807 function setEndpoint($endpoint) { 05808 $this->forceEndpoint = $endpoint; 05809 } 05810 05817 function setHeaders($headers){ 05818 $this->requestHeaders = $headers; 05819 } 05820 05827 function getHeaders(){ 05828 return $this->responseHeaders; 05829 } 05830 05840 function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 05841 $this->proxyhost = $proxyhost; 05842 $this->proxyport = $proxyport; 05843 $this->proxyusername = $proxyusername; 05844 $this->proxypassword = $proxypassword; 05845 } 05846 05856 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 05857 $this->username = $username; 05858 $this->password = $password; 05859 $this->authtype = $authtype; 05860 $this->certRequest = $certRequest; 05861 } 05862 05869 function setHTTPEncoding($enc='gzip, deflate'){ 05870 $this->http_encoding = $enc; 05871 } 05872 05878 function useHTTPPersistentConnection(){ 05879 $this->persistentConnection = true; 05880 } 05881 05893 function getDefaultRpcParams() { 05894 return $this->defaultRpcParams; 05895 } 05896 05908 function setDefaultRpcParams($rpcParams) { 05909 $this->defaultRpcParams = $rpcParams; 05910 } 05911 05919 function getProxy(){ 05920 $r = rand(); 05921 $evalStr = $this->_getProxyClassCode($r); 05922 //$this->debug("proxy class: $evalStr"; 05923 // eval the class 05924 eval($evalStr); 05925 // instantiate proxy object 05926 eval("\$proxy = new soap_proxy_$r('');"); 05927 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice 05928 $proxy->endpointType = 'wsdl'; 05929 $proxy->wsdlFile = $this->wsdlFile; 05930 $proxy->wsdl = $this->wsdl; 05931 $proxy->operations = $this->operations; 05932 $proxy->defaultRpcParams = $this->defaultRpcParams; 05933 // transfer other state 05934 $proxy->username = $this->username; 05935 $proxy->password = $this->password; 05936 $proxy->authtype = $this->authtype; 05937 $proxy->proxyhost = $this->proxyhost; 05938 $proxy->proxyport = $this->proxyport; 05939 $proxy->proxyusername = $this->proxyusername; 05940 $proxy->proxypassword = $this->proxypassword; 05941 $proxy->timeout = $this->timeout; 05942 $proxy->response_timeout = $this->response_timeout; 05943 $proxy->http_encoding = $this->http_encoding; 05944 $proxy->persistentConnection = $this->persistentConnection; 05945 $proxy->requestHeaders = $this->requestHeaders; 05946 $proxy->soap_defencoding = $this->soap_defencoding; 05947 $proxy->endpoint = $this->endpoint; 05948 $proxy->forceEndpoint = $this->forceEndpoint; 05949 return $proxy; 05950 } 05951 05958 function _getProxyClassCode($r) { 05959 if ($this->endpointType != 'wsdl') { 05960 $evalStr = 'A proxy can only be created for a WSDL client'; 05961 $this->setError($evalStr); 05962 return $evalStr; 05963 } 05964 $evalStr = ''; 05965 foreach ($this->operations as $operation => $opData) { 05966 if ($operation != '') { 05967 // create param string and param comment string 05968 if (sizeof($opData['input']['parts']) > 0) { 05969 $paramStr = ''; 05970 $paramArrayStr = ''; 05971 $paramCommentStr = ''; 05972 foreach ($opData['input']['parts'] as $name => $type) { 05973 $paramStr .= "\$$name, "; 05974 $paramArrayStr .= "'$name' => \$$name, "; 05975 $paramCommentStr .= "$type \$$name, "; 05976 } 05977 $paramStr = substr($paramStr, 0, strlen($paramStr)-2); 05978 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); 05979 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); 05980 } else { 05981 $paramStr = ''; 05982 $paramCommentStr = 'void'; 05983 } 05984 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; 05985 $evalStr .= "// $paramCommentStr 05986 function " . str_replace('.', '__', $operation) . "($paramStr) { 05987 \$params = array($paramArrayStr); 05988 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); 05989 } 05990 "; 05991 unset($paramStr); 05992 unset($paramCommentStr); 05993 } 05994 } 05995 $evalStr = 'class soap_proxy_'.$r.' extends soapclient { 05996 '.$evalStr.' 05997 }'; 05998 return $evalStr; 05999 } 06000 06007 function getProxyClassCode() { 06008 $r = rand(); 06009 return $this->_getProxyClassCode($r); 06010 } 06011 06019 function getHTTPBody($soapmsg) { 06020 return $soapmsg; 06021 } 06022 06031 function getHTTPContentType() { 06032 return 'text/xml'; 06033 } 06034 06044 function getHTTPContentTypeCharset() { 06045 return $this->soap_defencoding; 06046 } 06047 06048 /* 06049 * whether or not parser should decode utf8 element content 06050 * 06051 * @return always returns true 06052 * @access public 06053 */ 06054 function decodeUTF8($bool){ 06055 $this->decode_utf8 = $bool; 06056 return true; 06057 } 06058 06067 function setCookie($name, $value) { 06068 if (strlen($name) == 0) { 06069 return false; 06070 } 06071 $this->cookies[] = array('name' => $name, 'value' => $value); 06072 return true; 06073 } 06074 06081 function getCookies() { 06082 return $this->cookies; 06083 } 06084 06091 function checkCookies() { 06092 if (sizeof($this->cookies) == 0) { 06093 return true; 06094 } 06095 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); 06096 $curr_cookies = $this->cookies; 06097 $this->cookies = array(); 06098 foreach ($curr_cookies as $cookie) { 06099 if (! is_array($cookie)) { 06100 $this->debug('Remove cookie that is not an array'); 06101 continue; 06102 } 06103 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 06104 if (strtotime($cookie['expires']) > time()) { 06105 $this->cookies[] = $cookie; 06106 } else { 06107 $this->debug('Remove expired cookie ' . $cookie['name']); 06108 } 06109 } else { 06110 $this->cookies[] = $cookie; 06111 } 06112 } 06113 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); 06114 return true; 06115 } 06116 06124 function UpdateCookies($cookies) { 06125 if (sizeof($this->cookies) == 0) { 06126 // no existing cookies: take whatever is new 06127 if (sizeof($cookies) > 0) { 06128 $this->debug('Setting new cookie(s)'); 06129 $this->cookies = $cookies; 06130 } 06131 return true; 06132 } 06133 if (sizeof($cookies) == 0) { 06134 // no new cookies: keep what we've got 06135 return true; 06136 } 06137 // merge 06138 foreach ($cookies as $newCookie) { 06139 if (!is_array($newCookie)) { 06140 continue; 06141 } 06142 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { 06143 continue; 06144 } 06145 $newName = $newCookie['name']; 06146 06147 $found = false; 06148 for ($i = 0; $i < count($this->cookies); $i++) { 06149 $cookie = $this->cookies[$i]; 06150 if (!is_array($cookie)) { 06151 continue; 06152 } 06153 if (!isset($cookie['name'])) { 06154 continue; 06155 } 06156 if ($newName != $cookie['name']) { 06157 continue; 06158 } 06159 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; 06160 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; 06161 if ($newDomain != $domain) { 06162 continue; 06163 } 06164 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; 06165 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; 06166 if ($newPath != $path) { 06167 continue; 06168 } 06169 $this->cookies[$i] = $newCookie; 06170 $found = true; 06171 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); 06172 break; 06173 } 06174 if (! $found) { 06175 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); 06176 $this->cookies[] = $newCookie; 06177 } 06178 } 06179 return true; 06180 } 06181 } 06182 ?>