├── README.md └── application ├── config └── routes.php ├── controllers └── nuSoapServer.php └── libraries ├── NuSOAP └── lib │ ├── changelog │ ├── class.nusoap_base.php │ ├── class.soap_fault.php │ ├── class.soap_parser.php │ ├── class.soap_server.php │ ├── class.soap_transport_http.php │ ├── class.soap_val.php │ ├── class.soapclient.php │ ├── class.wsdl.php │ ├── class.wsdlcache.php │ ├── class.xmlschema.php │ ├── nusoap.php │ └── nusoapmime.php └── nuSoap_lib.php /README.md: -------------------------------------------------------------------------------- 1 | soapserver_codeigniter 2 | ====================== 3 | 4 | Creating a SOAP server in CodeIgniter 5 | 6 | Let’s take a look what NuSOAP is and what is used for the library NuSOAP. This library, which is very useful and widely used, is a toolkit to develop Web Services under the PHP language. It consists of a series of classes that will make us much easier to develop Web Services. Provides support for the development of clients (those consuming Web Services) and servers (those that provide the Web Services). Once we know what NuSOAP is, we move on to integrate it into our development framework. The first thing that we need to do is to download the library, unzip it and include it in the directory application/libraries of our CodeIgniter framework 7 | 8 | Once we know what NuSOAP is, we move on to integrate it into our development framework. The first thing that we need to do is to download the library, unzip it and include it in the directory application/libraries of our CodeIgniter framework. The easiest way to integrate this library in CodeIgniter is by creating our own “pseudo” CodeIgniter’s library, which at the same time allows the use of the real NuSOAP library, that we have previously downloaded. 9 | 10 | We move on to develop our own library CodeIgniter, for that, we have to create a new file called nuSoap_lib.php (or whatever you want to call it, the name depends only on your imagination) in the application/libraries, the same level as the directory that contains the NuSOAP library. 11 | 12 | In the file nuSoap_lib.php we have to put the following code: 13 | 14 | ``` 15 | 22 | ``` 23 | 24 | NuSOAP server will be a controller which does not need to have its own view file, since it will only be accessed to perform certain tasks (even interact with the models if it would be necessary) and return their results via web to its remote client, so at no time it will be necessary to show the data on the screen directly from the server. 25 | 26 | We now have to create the file “nuSoapServer.php” into the folder “application / controller” in which we insert the following code: 27 | 28 | 29 | ## Quick start: 30 | ``` 31 | load->library("nuSoap_lib"); 36 | $this->nusoap_server = new soap_server(); 37 | $this->nusoap_server->configureWSDL("cartWSDL", "urn:cartWSDL"); 38 | $this->nusoap_server->wsdl->addComplexType( 39 | "Member", 40 | "complexType", 41 | "array", 42 | "", 43 | "SOAP-ENC:Array", 44 | array( 45 | "id"=>array("name"=>"id", "type"=>"xsd:int"), 46 | "first_name"=>array("name"=>"first_name", "type"=>"xsd:string"), 47 | "surname"=>array("name"=>"surname", "type"=>"xsd:string") 48 | ) 49 | ); 50 | $this->nusoap_server->register( 51 | "getMember", 52 | array( 53 | "id" => "xsd:int", 54 | ), 55 | array("return"=>"tns:Member"), 56 | "urn:cartWSDL", 57 | "urn:cartWSDL#getMember", 58 | "rpc", 59 | "encoded", 60 | "Returns the information of a certain member" 61 | ); 62 | } 63 | function index() { 64 | if($this->uri->segment(3) == "wsdl") { 65 | $_SERVER['QUERY_STRING'] = "wsdl"; 66 | } else { 67 | $_SERVER['QUERY_STRING'] = ""; 68 | } 69 | $this->nusoap_server->service(file_get_contents("php://input")); 70 | } 71 | 72 | function get_member() { 73 | function getMember($id) { 74 | echo "True"; 75 | /* //in this example i just return "True" ..if you want to access next model and fetch the DB value, it is written here 76 | $CI =& get_instance(); 77 | $CI->load->model("Customer"); 78 | $row = $CI->Customer->getMemberInfo($id); 79 | return $row; 80 | */ 81 | } 82 | $this->nusoap_server->service(file_get_contents("php://input")); 83 | } 84 | } 85 | ?> 86 | 87 | ``` 88 | 89 | With this, we have almost done our NuSOAP web services server. All we need now is a detail in the configuration. In the file “application / config / routes.php” we have to add the following path: 90 | ``` 91 | $route['nuSoapServer/getMember/wsdl'] = 'nuSoapServer/index/wsdl'; 92 | ``` 93 | -------------------------------------------------------------------------------- /application/config/routes.php: -------------------------------------------------------------------------------- 1 | load->library("nuSoap_lib"); 6 | $this->nusoap_server = new soap_server(); 7 | $this->nusoap_server->configureWSDL("cartWSDL", "urn:cartWSDL"); 8 | $this->nusoap_server->wsdl->addComplexType( 9 | "Member", 10 | "complexType", 11 | "array", 12 | "", 13 | "SOAP-ENC:Array", 14 | array( 15 | "id"=>array("name"=>"id", "type"=>"xsd:int"), 16 | "first_name"=>array("name"=>"first_name", "type"=>"xsd:string"), 17 | "surname"=>array("name"=>"surname", "type"=>"xsd:string") 18 | ) 19 | ); 20 | $this->nusoap_server->register( 21 | "getMember", 22 | array( 23 | "id" => "xsd:int", 24 | ), 25 | array("return"=>"tns:Member"), 26 | "urn:cartWSDL", 27 | "urn:cartWSDL#getMember", 28 | "rpc", 29 | "encoded", 30 | "Returns the information of a certain member" 31 | ); 32 | } 33 | function index() { 34 | if($this->uri->segment(3) == "wsdl") { 35 | $_SERVER['QUERY_STRING'] = "wsdl"; 36 | } else { 37 | $_SERVER['QUERY_STRING'] = ""; 38 | } 39 | $this->nusoap_server->service(file_get_contents("php://input")); 40 | } 41 | 42 | function get_member() { 43 | function getMember($id) { 44 | echo "True"; 45 | /* //in this example i just return "True" ..if you want to access next model and fetch the DB value, it is written here 46 | $CI =& get_instance(); 47 | $CI->load->model("Customer"); 48 | $row = $CI->Customer->getMemberInfo($id); 49 | return $row; 50 | */ 51 | } 52 | $this->nusoap_server->service(file_get_contents("php://input")); 53 | } 54 | } 55 | ?> 56 | 57 | 58 | -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/changelog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusagar/soapserver_codeigniter/73d40c51d3b8551f013cbe15d9b0951f1151808b/application/libraries/NuSOAP/lib/changelog -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.nusoap_base.php: -------------------------------------------------------------------------------- 1 | globalDebugLevel = 9; 76 | 77 | /** 78 | * 79 | * nusoap_base 80 | * 81 | * @author Dietrich Ayala 82 | * @author Scott Nichol 83 | * @version $Id: class.nusoap_base.php,v 1.51 2007/11/06 15:17:46 snichol Exp $ 84 | * @access public 85 | */ 86 | class nusoap_base { 87 | /** 88 | * Identification for HTTP headers. 89 | * 90 | * @var string 91 | * @access private 92 | */ 93 | var $title = 'NuSOAP'; 94 | /** 95 | * Version for HTTP headers. 96 | * 97 | * @var string 98 | * @access private 99 | */ 100 | var $version = '0.7.3'; 101 | /** 102 | * CVS revision for HTTP headers. 103 | * 104 | * @var string 105 | * @access private 106 | */ 107 | var $revision = '$Revision: 1.51 $'; 108 | /** 109 | * Current error string (manipulated by getError/setError) 110 | * 111 | * @var string 112 | * @access private 113 | */ 114 | var $error_str = ''; 115 | /** 116 | * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) 117 | * 118 | * @var string 119 | * @access private 120 | */ 121 | var $debug_str = ''; 122 | /** 123 | * toggles automatic encoding of special characters as entities 124 | * (should always be true, I think) 125 | * 126 | * @var boolean 127 | * @access private 128 | */ 129 | var $charencoding = true; 130 | /** 131 | * the debug level for this instance 132 | * 133 | * @var integer 134 | * @access private 135 | */ 136 | var $debugLevel; 137 | 138 | /** 139 | * set schema version 140 | * 141 | * @var string 142 | * @access public 143 | */ 144 | var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 145 | 146 | /** 147 | * charset encoding for outgoing messages 148 | * 149 | * @var string 150 | * @access public 151 | */ 152 | var $soap_defencoding = 'ISO-8859-1'; 153 | //var $soap_defencoding = 'UTF-8'; 154 | 155 | /** 156 | * namespaces in an array of prefix => uri 157 | * 158 | * this is "seeded" by a set of constants, but it may be altered by code 159 | * 160 | * @var array 161 | * @access public 162 | */ 163 | var $namespaces = array( 164 | 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 165 | 'xsd' => 'http://www.w3.org/2001/XMLSchema', 166 | 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 167 | 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 168 | ); 169 | 170 | /** 171 | * namespaces used in the current context, e.g. during serialization 172 | * 173 | * @var array 174 | * @access private 175 | */ 176 | var $usedNamespaces = array(); 177 | 178 | /** 179 | * XML Schema types in an array of uri => (array of xml type => php type) 180 | * is this legacy yet? 181 | * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. 182 | * @var array 183 | * @access public 184 | */ 185 | var $typemap = array( 186 | 'http://www.w3.org/2001/XMLSchema' => array( 187 | 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 188 | 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 189 | 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 190 | // abstract "any" types 191 | 'anyType'=>'string','anySimpleType'=>'string', 192 | // derived datatypes 193 | 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 194 | 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 195 | 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 196 | 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 197 | 'http://www.w3.org/2000/10/XMLSchema' => array( 198 | 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 199 | 'float'=>'double','dateTime'=>'string', 200 | 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 201 | 'http://www.w3.org/1999/XMLSchema' => array( 202 | 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 203 | 'float'=>'double','dateTime'=>'string', 204 | 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 205 | 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 206 | 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 207 | 'http://xml.apache.org/xml-soap' => array('Map') 208 | ); 209 | 210 | /** 211 | * XML entities to convert 212 | * 213 | * @var array 214 | * @access public 215 | * @deprecated 216 | * @see expandEntities 217 | */ 218 | var $xmlEntities = array('quot' => '"','amp' => '&', 219 | 'lt' => '<','gt' => '>','apos' => "'"); 220 | 221 | /** 222 | * constructor 223 | * 224 | * @access public 225 | */ 226 | function nusoap_base() { 227 | $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 228 | } 229 | 230 | /** 231 | * gets the global debug level, which applies to future instances 232 | * 233 | * @return integer Debug level 0-9, where 0 turns off 234 | * @access public 235 | */ 236 | function getGlobalDebugLevel() { 237 | return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel; 238 | } 239 | 240 | /** 241 | * sets the global debug level, which applies to future instances 242 | * 243 | * @param int $level Debug level 0-9, where 0 turns off 244 | * @access public 245 | */ 246 | function setGlobalDebugLevel($level) { 247 | $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level; 248 | } 249 | 250 | /** 251 | * gets the debug level for this instance 252 | * 253 | * @return int Debug level 0-9, where 0 turns off 254 | * @access public 255 | */ 256 | function getDebugLevel() { 257 | return $this->debugLevel; 258 | } 259 | 260 | /** 261 | * sets the debug level for this instance 262 | * 263 | * @param int $level Debug level 0-9, where 0 turns off 264 | * @access public 265 | */ 266 | function setDebugLevel($level) { 267 | $this->debugLevel = $level; 268 | } 269 | 270 | /** 271 | * adds debug data to the instance debug string with formatting 272 | * 273 | * @param string $string debug data 274 | * @access private 275 | */ 276 | function debug($string){ 277 | if ($this->debugLevel > 0) { 278 | $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 279 | } 280 | } 281 | 282 | /** 283 | * adds debug data to the instance debug string without formatting 284 | * 285 | * @param string $string debug data 286 | * @access public 287 | */ 288 | function appendDebug($string){ 289 | if ($this->debugLevel > 0) { 290 | // it would be nice to use a memory stream here to use 291 | // memory more efficiently 292 | $this->debug_str .= $string; 293 | } 294 | } 295 | 296 | /** 297 | * clears the current debug data for this instance 298 | * 299 | * @access public 300 | */ 301 | function clearDebug() { 302 | // it would be nice to use a memory stream here to use 303 | // memory more efficiently 304 | $this->debug_str = ''; 305 | } 306 | 307 | /** 308 | * gets the current debug data for this instance 309 | * 310 | * @return debug data 311 | * @access public 312 | */ 313 | function &getDebug() { 314 | // it would be nice to use a memory stream here to use 315 | // memory more efficiently 316 | return $this->debug_str; 317 | } 318 | 319 | /** 320 | * gets the current debug data for this instance as an XML comment 321 | * this may change the contents of the debug data 322 | * 323 | * @return debug data as an XML comment 324 | * @access public 325 | */ 326 | function &getDebugAsXMLComment() { 327 | // it would be nice to use a memory stream here to use 328 | // memory more efficiently 329 | while (strpos($this->debug_str, '--')) { 330 | $this->debug_str = str_replace('--', '- -', $this->debug_str); 331 | } 332 | $ret = ""; 333 | return $ret; 334 | } 335 | 336 | /** 337 | * expands entities, e.g. changes '<' to '<'. 338 | * 339 | * @param string $val The string in which to expand entities. 340 | * @access private 341 | */ 342 | function expandEntities($val) { 343 | if ($this->charencoding) { 344 | $val = str_replace('&', '&', $val); 345 | $val = str_replace("'", ''', $val); 346 | $val = str_replace('"', '"', $val); 347 | $val = str_replace('<', '<', $val); 348 | $val = str_replace('>', '>', $val); 349 | } 350 | return $val; 351 | } 352 | 353 | /** 354 | * returns error string if present 355 | * 356 | * @return mixed error string or false 357 | * @access public 358 | */ 359 | function getError(){ 360 | if($this->error_str != ''){ 361 | return $this->error_str; 362 | } 363 | return false; 364 | } 365 | 366 | /** 367 | * sets error string 368 | * 369 | * @return boolean $string error string 370 | * @access private 371 | */ 372 | function setError($str){ 373 | $this->error_str = $str; 374 | } 375 | 376 | /** 377 | * detect if array is a simple array or a struct (associative array) 378 | * 379 | * @param mixed $val The PHP array 380 | * @return string (arraySimple|arrayStruct) 381 | * @access private 382 | */ 383 | function isArraySimpleOrStruct($val) { 384 | $keyList = array_keys($val); 385 | foreach ($keyList as $keyListValue) { 386 | if (!is_int($keyListValue)) { 387 | return 'arrayStruct'; 388 | } 389 | } 390 | return 'arraySimple'; 391 | } 392 | 393 | /** 394 | * serializes PHP values in accordance w/ section 5. Type information is 395 | * not serialized if $use == 'literal'. 396 | * 397 | * @param mixed $val The value to serialize 398 | * @param string $name The name (local part) of the XML element 399 | * @param string $type The XML schema type (local part) for the element 400 | * @param string $name_ns The namespace for the name of the XML element 401 | * @param string $type_ns The namespace for the type of the element 402 | * @param array $attributes The attributes to serialize as name=>value pairs 403 | * @param string $use The WSDL "use" (encoded|literal) 404 | * @param boolean $soapval Whether this is called from soapval. 405 | * @return string The serialized element, possibly with child elements 406 | * @access public 407 | */ 408 | function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { 409 | $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); 410 | $this->appendDebug('value=' . $this->varDump($val)); 411 | $this->appendDebug('attributes=' . $this->varDump($attributes)); 412 | 413 | if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { 414 | $this->debug("serialize_val: serialize soapval"); 415 | $xml = $val->serialize($use); 416 | $this->appendDebug($val->getDebug()); 417 | $val->clearDebug(); 418 | $this->debug("serialize_val of soapval returning $xml"); 419 | return $xml; 420 | } 421 | // force valid name if necessary 422 | if (is_numeric($name)) { 423 | $name = '__numeric_' . $name; 424 | } elseif (! $name) { 425 | $name = 'noname'; 426 | } 427 | // if name has ns, add ns prefix to name 428 | $xmlns = ''; 429 | if($name_ns){ 430 | $prefix = 'nu'.rand(1000,9999); 431 | $name = $prefix.':'.$name; 432 | $xmlns .= " xmlns:$prefix=\"$name_ns\""; 433 | } 434 | // if type is prefixed, create type prefix 435 | if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 436 | // need to fix this. shouldn't default to xsd if no ns specified 437 | // w/o checking against typemap 438 | $type_prefix = 'xsd'; 439 | } elseif($type_ns){ 440 | $type_prefix = 'ns'.rand(1000,9999); 441 | $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 442 | } 443 | // serialize attributes if present 444 | $atts = ''; 445 | if($attributes){ 446 | foreach($attributes as $k => $v){ 447 | $atts .= " $k=\"".$this->expandEntities($v).'"'; 448 | } 449 | } 450 | // serialize null value 451 | if (is_null($val)) { 452 | $this->debug("serialize_val: serialize null"); 453 | if ($use == 'literal') { 454 | // TODO: depends on minOccurs 455 | $xml = "<$name$xmlns$atts/>"; 456 | $this->debug("serialize_val returning $xml"); 457 | return $xml; 458 | } else { 459 | if (isset($type) && isset($type_prefix)) { 460 | $type_str = " xsi:type=\"$type_prefix:$type\""; 461 | } else { 462 | $type_str = ''; 463 | } 464 | $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; 465 | $this->debug("serialize_val returning $xml"); 466 | return $xml; 467 | } 468 | } 469 | // serialize if an xsd built-in primitive type 470 | if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 471 | $this->debug("serialize_val: serialize xsd built-in primitive type"); 472 | if (is_bool($val)) { 473 | if ($type == 'boolean') { 474 | $val = $val ? 'true' : 'false'; 475 | } elseif (! $val) { 476 | $val = 0; 477 | } 478 | } else if (is_string($val)) { 479 | $val = $this->expandEntities($val); 480 | } 481 | if ($use == 'literal') { 482 | $xml = "<$name$xmlns$atts>$val"; 483 | $this->debug("serialize_val returning $xml"); 484 | return $xml; 485 | } else { 486 | $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; 487 | $this->debug("serialize_val returning $xml"); 488 | return $xml; 489 | } 490 | } 491 | // detect type and serialize 492 | $xml = ''; 493 | switch(true) { 494 | case (is_bool($val) || $type == 'boolean'): 495 | $this->debug("serialize_val: serialize boolean"); 496 | if ($type == 'boolean') { 497 | $val = $val ? 'true' : 'false'; 498 | } elseif (! $val) { 499 | $val = 0; 500 | } 501 | if ($use == 'literal') { 502 | $xml .= "<$name$xmlns$atts>$val"; 503 | } else { 504 | $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; 505 | } 506 | break; 507 | case (is_int($val) || is_long($val) || $type == 'int'): 508 | $this->debug("serialize_val: serialize int"); 509 | if ($use == 'literal') { 510 | $xml .= "<$name$xmlns$atts>$val"; 511 | } else { 512 | $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; 513 | } 514 | break; 515 | case (is_float($val)|| is_double($val) || $type == 'float'): 516 | $this->debug("serialize_val: serialize float"); 517 | if ($use == 'literal') { 518 | $xml .= "<$name$xmlns$atts>$val"; 519 | } else { 520 | $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; 521 | } 522 | break; 523 | case (is_string($val) || $type == 'string'): 524 | $this->debug("serialize_val: serialize string"); 525 | $val = $this->expandEntities($val); 526 | if ($use == 'literal') { 527 | $xml .= "<$name$xmlns$atts>$val"; 528 | } else { 529 | $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; 530 | } 531 | break; 532 | case is_object($val): 533 | $this->debug("serialize_val: serialize object"); 534 | if (get_class($val) == 'soapval') { 535 | $this->debug("serialize_val: serialize soapval object"); 536 | $pXml = $val->serialize($use); 537 | $this->appendDebug($val->getDebug()); 538 | $val->clearDebug(); 539 | } else { 540 | if (! $name) { 541 | $name = get_class($val); 542 | $this->debug("In serialize_val, used class name $name as element name"); 543 | } else { 544 | $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 545 | } 546 | foreach(get_object_vars($val) as $k => $v){ 547 | $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 548 | } 549 | } 550 | if(isset($type) && isset($type_prefix)){ 551 | $type_str = " xsi:type=\"$type_prefix:$type\""; 552 | } else { 553 | $type_str = ''; 554 | } 555 | if ($use == 'literal') { 556 | $xml .= "<$name$xmlns$atts>$pXml"; 557 | } else { 558 | $xml .= "<$name$xmlns$type_str$atts>$pXml"; 559 | } 560 | break; 561 | break; 562 | case (is_array($val) || $type): 563 | // detect if struct or array 564 | $valueType = $this->isArraySimpleOrStruct($val); 565 | if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ 566 | $this->debug("serialize_val: serialize array"); 567 | $i = 0; 568 | if(is_array($val) && count($val)> 0){ 569 | foreach($val as $v){ 570 | if(is_object($v) && get_class($v) == 'soapval'){ 571 | $tt_ns = $v->type_ns; 572 | $tt = $v->type; 573 | } elseif (is_array($v)) { 574 | $tt = $this->isArraySimpleOrStruct($v); 575 | } else { 576 | $tt = gettype($v); 577 | } 578 | $array_types[$tt] = 1; 579 | // TODO: for literal, the name should be $name 580 | $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 581 | ++$i; 582 | } 583 | if(count($array_types) > 1){ 584 | $array_typename = 'xsd:anyType'; 585 | } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 586 | if ($tt == 'integer') { 587 | $tt = 'int'; 588 | } 589 | $array_typename = 'xsd:'.$tt; 590 | } elseif(isset($tt) && $tt == 'arraySimple'){ 591 | $array_typename = 'SOAP-ENC:Array'; 592 | } elseif(isset($tt) && $tt == 'arrayStruct'){ 593 | $array_typename = 'unnamed_struct_use_soapval'; 594 | } else { 595 | // if type is prefixed, create type prefix 596 | if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 597 | $array_typename = 'xsd:' . $tt; 598 | } elseif ($tt_ns) { 599 | $tt_prefix = 'ns' . rand(1000, 9999); 600 | $array_typename = "$tt_prefix:$tt"; 601 | $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 602 | } else { 603 | $array_typename = $tt; 604 | } 605 | } 606 | $array_type = $i; 607 | if ($use == 'literal') { 608 | $type_str = ''; 609 | } else if (isset($type) && isset($type_prefix)) { 610 | $type_str = " xsi:type=\"$type_prefix:$type\""; 611 | } else { 612 | $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 613 | } 614 | // empty array 615 | } else { 616 | if ($use == 'literal') { 617 | $type_str = ''; 618 | } else if (isset($type) && isset($type_prefix)) { 619 | $type_str = " xsi:type=\"$type_prefix:$type\""; 620 | } else { 621 | $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 622 | } 623 | } 624 | // TODO: for array in literal, there is no wrapper here 625 | $xml = "<$name$xmlns$type_str$atts>".$xml.""; 626 | } else { 627 | // got a struct 628 | $this->debug("serialize_val: serialize struct"); 629 | if(isset($type) && isset($type_prefix)){ 630 | $type_str = " xsi:type=\"$type_prefix:$type\""; 631 | } else { 632 | $type_str = ''; 633 | } 634 | if ($use == 'literal') { 635 | $xml .= "<$name$xmlns$atts>"; 636 | } else { 637 | $xml .= "<$name$xmlns$type_str$atts>"; 638 | } 639 | foreach($val as $k => $v){ 640 | // Apache Map 641 | if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 642 | $xml .= ''; 643 | $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 644 | $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 645 | $xml .= ''; 646 | } else { 647 | $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 648 | } 649 | } 650 | $xml .= ""; 651 | } 652 | break; 653 | default: 654 | $this->debug("serialize_val: serialize unknown"); 655 | $xml .= 'not detected, got '.gettype($val).' for '.$val; 656 | break; 657 | } 658 | $this->debug("serialize_val returning $xml"); 659 | return $xml; 660 | } 661 | 662 | /** 663 | * serializes a message 664 | * 665 | * @param string $body the XML of the SOAP body 666 | * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array 667 | * @param array $namespaces optional the namespaces used in generating the body and headers 668 | * @param string $style optional (rpc|document) 669 | * @param string $use optional (encoded|literal) 670 | * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 671 | * @return string the message 672 | * @access public 673 | */ 674 | function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 675 | // TODO: add an option to automatically run utf8_encode on $body and $headers 676 | // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 677 | // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 678 | 679 | $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 680 | $this->debug("headers:"); 681 | $this->appendDebug($this->varDump($headers)); 682 | $this->debug("namespaces:"); 683 | $this->appendDebug($this->varDump($namespaces)); 684 | 685 | // serialize namespaces 686 | $ns_string = ''; 687 | foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 688 | $ns_string .= " xmlns:$k=\"$v\""; 689 | } 690 | if($encodingStyle) { 691 | $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 692 | } 693 | 694 | // serialize headers 695 | if($headers){ 696 | if (is_array($headers)) { 697 | $xml = ''; 698 | foreach ($headers as $k => $v) { 699 | if (is_object($v) && get_class($v) == 'soapval') { 700 | $xml .= $this->serialize_val($v, false, false, false, false, false, $use); 701 | } else { 702 | $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); 703 | } 704 | } 705 | $headers = $xml; 706 | $this->debug("In serializeEnvelope, serialized array of headers to $headers"); 707 | } 708 | $headers = "".$headers.""; 709 | } 710 | // serialize envelope 711 | return 712 | 'soap_defencoding .'"?'.">". 713 | '". 714 | $headers. 715 | "". 716 | $body. 717 | "". 718 | ""; 719 | } 720 | 721 | /** 722 | * formats a string to be inserted into an HTML stream 723 | * 724 | * @param string $str The string to format 725 | * @return string The formatted string 726 | * @access public 727 | * @deprecated 728 | */ 729 | function formatDump($str){ 730 | $str = htmlspecialchars($str); 731 | return nl2br($str); 732 | } 733 | 734 | /** 735 | * contracts (changes namespace to prefix) a qualified name 736 | * 737 | * @param string $qname qname 738 | * @return string contracted qname 739 | * @access private 740 | */ 741 | function contractQname($qname){ 742 | // get element namespace 743 | //$this->xdebug("Contract $qname"); 744 | if (strrpos($qname, ':')) { 745 | // get unqualified name 746 | $name = substr($qname, strrpos($qname, ':') + 1); 747 | // get ns 748 | $ns = substr($qname, 0, strrpos($qname, ':')); 749 | $p = $this->getPrefixFromNamespace($ns); 750 | if ($p) { 751 | return $p . ':' . $name; 752 | } 753 | return $qname; 754 | } else { 755 | return $qname; 756 | } 757 | } 758 | 759 | /** 760 | * expands (changes prefix to namespace) a qualified name 761 | * 762 | * @param string $qname qname 763 | * @return string expanded qname 764 | * @access private 765 | */ 766 | function expandQname($qname){ 767 | // get element prefix 768 | if(strpos($qname,':') && !ereg('^http://',$qname)){ 769 | // get unqualified name 770 | $name = substr(strstr($qname,':'),1); 771 | // get ns prefix 772 | $prefix = substr($qname,0,strpos($qname,':')); 773 | if(isset($this->namespaces[$prefix])){ 774 | return $this->namespaces[$prefix].':'.$name; 775 | } else { 776 | return $qname; 777 | } 778 | } else { 779 | return $qname; 780 | } 781 | } 782 | 783 | /** 784 | * returns the local part of a prefixed string 785 | * returns the original string, if not prefixed 786 | * 787 | * @param string $str The prefixed string 788 | * @return string The local part 789 | * @access public 790 | */ 791 | function getLocalPart($str){ 792 | if($sstr = strrchr($str,':')){ 793 | // get unqualified name 794 | return substr( $sstr, 1 ); 795 | } else { 796 | return $str; 797 | } 798 | } 799 | 800 | /** 801 | * returns the prefix part of a prefixed string 802 | * returns false, if not prefixed 803 | * 804 | * @param string $str The prefixed string 805 | * @return mixed The prefix or false if there is no prefix 806 | * @access public 807 | */ 808 | function getPrefix($str){ 809 | if($pos = strrpos($str,':')){ 810 | // get prefix 811 | return substr($str,0,$pos); 812 | } 813 | return false; 814 | } 815 | 816 | /** 817 | * pass it a prefix, it returns a namespace 818 | * 819 | * @param string $prefix The prefix 820 | * @return mixed The namespace, false if no namespace has the specified prefix 821 | * @access public 822 | */ 823 | function getNamespaceFromPrefix($prefix){ 824 | if (isset($this->namespaces[$prefix])) { 825 | return $this->namespaces[$prefix]; 826 | } 827 | //$this->setError("No namespace registered for prefix '$prefix'"); 828 | return false; 829 | } 830 | 831 | /** 832 | * returns the prefix for a given namespace (or prefix) 833 | * or false if no prefixes registered for the given namespace 834 | * 835 | * @param string $ns The namespace 836 | * @return mixed The prefix, false if the namespace has no prefixes 837 | * @access public 838 | */ 839 | function getPrefixFromNamespace($ns) { 840 | foreach ($this->namespaces as $p => $n) { 841 | if ($ns == $n || $ns == $p) { 842 | $this->usedNamespaces[$p] = $n; 843 | return $p; 844 | } 845 | } 846 | return false; 847 | } 848 | 849 | /** 850 | * returns the time in ODBC canonical form with microseconds 851 | * 852 | * @return string The time in ODBC canonical form with microseconds 853 | * @access public 854 | */ 855 | function getmicrotime() { 856 | if (function_exists('gettimeofday')) { 857 | $tod = gettimeofday(); 858 | $sec = $tod['sec']; 859 | $usec = $tod['usec']; 860 | } else { 861 | $sec = time(); 862 | $usec = 0; 863 | } 864 | return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 865 | } 866 | 867 | /** 868 | * Returns a string with the output of var_dump 869 | * 870 | * @param mixed $data The variable to var_dump 871 | * @return string The output of var_dump 872 | * @access public 873 | */ 874 | function varDump($data) { 875 | ob_start(); 876 | var_dump($data); 877 | $ret_val = ob_get_contents(); 878 | ob_end_clean(); 879 | return $ret_val; 880 | } 881 | 882 | /** 883 | * represents the object as a string 884 | * 885 | * @return string 886 | * @access public 887 | */ 888 | function __toString() { 889 | return $this->varDump($this); 890 | } 891 | } 892 | 893 | // XML Schema Datatype Helper Functions 894 | 895 | //xsd:dateTime helpers 896 | 897 | /** 898 | * convert unix timestamp to ISO 8601 compliant date string 899 | * 900 | * @param string $timestamp Unix time stamp 901 | * @param boolean $utc Whether the time stamp is UTC or local 902 | * @access public 903 | */ 904 | function timestamp_to_iso8601($timestamp,$utc=true){ 905 | $datestr = date('Y-m-d\TH:i:sO',$timestamp); 906 | if($utc){ 907 | $eregStr = 908 | '([0-9]{4})-'. // centuries & years CCYY- 909 | '([0-9]{2})-'. // months MM- 910 | '([0-9]{2})'. // days DD 911 | 'T'. // separator T 912 | '([0-9]{2}):'. // hours hh: 913 | '([0-9]{2}):'. // minutes mm: 914 | '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 915 | '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 916 | 917 | if(ereg($eregStr,$datestr,$regs)){ 918 | return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 919 | } 920 | return false; 921 | } else { 922 | return $datestr; 923 | } 924 | } 925 | 926 | /** 927 | * convert ISO 8601 compliant date string to unix timestamp 928 | * 929 | * @param string $datestr ISO 8601 compliant date string 930 | * @access public 931 | */ 932 | function iso8601_to_timestamp($datestr){ 933 | $eregStr = 934 | '([0-9]{4})-'. // centuries & years CCYY- 935 | '([0-9]{2})-'. // months MM- 936 | '([0-9]{2})'. // days DD 937 | 'T'. // separator T 938 | '([0-9]{2}):'. // hours hh: 939 | '([0-9]{2}):'. // minutes mm: 940 | '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 941 | '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 942 | if(ereg($eregStr,$datestr,$regs)){ 943 | // not utc 944 | if($regs[8] != 'Z'){ 945 | $op = substr($regs[8],0,1); 946 | $h = substr($regs[8],1,2); 947 | $m = substr($regs[8],strlen($regs[8])-2,2); 948 | if($op == '-'){ 949 | $regs[4] = $regs[4] + $h; 950 | $regs[5] = $regs[5] + $m; 951 | } elseif($op == '+'){ 952 | $regs[4] = $regs[4] - $h; 953 | $regs[5] = $regs[5] - $m; 954 | } 955 | } 956 | return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 957 | // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 958 | } else { 959 | return false; 960 | } 961 | } 962 | 963 | /** 964 | * sleeps some number of microseconds 965 | * 966 | * @param string $usec the number of microseconds to sleep 967 | * @access public 968 | * @deprecated 969 | */ 970 | function usleepWindows($usec) 971 | { 972 | $start = gettimeofday(); 973 | 974 | do 975 | { 976 | $stop = gettimeofday(); 977 | $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 978 | + $stop['usec'] - $start['usec']; 979 | } 980 | while ($timePassed < $usec); 981 | } 982 | 983 | 984 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.soap_fault.php: -------------------------------------------------------------------------------- 1 | 11 | * @version $Id: class.soap_fault.php,v 1.14 2007/04/11 15:49:47 snichol Exp $ 12 | * @access public 13 | */ 14 | class nusoap_fault extends nusoap_base { 15 | /** 16 | * The fault code (client|server) 17 | * @var string 18 | * @access private 19 | */ 20 | var $faultcode; 21 | /** 22 | * The fault actor 23 | * @var string 24 | * @access private 25 | */ 26 | var $faultactor; 27 | /** 28 | * The fault string, a description of the fault 29 | * @var string 30 | * @access private 31 | */ 32 | var $faultstring; 33 | /** 34 | * The fault detail, typically a string or array of string 35 | * @var mixed 36 | * @access private 37 | */ 38 | var $faultdetail; 39 | 40 | /** 41 | * constructor 42 | * 43 | * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) 44 | * @param string $faultactor only used when msg routed between multiple actors 45 | * @param string $faultstring human readable error message 46 | * @param mixed $faultdetail detail, typically a string or array of string 47 | */ 48 | function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ 49 | parent::nusoap_base(); 50 | $this->faultcode = $faultcode; 51 | $this->faultactor = $faultactor; 52 | $this->faultstring = $faultstring; 53 | $this->faultdetail = $faultdetail; 54 | } 55 | 56 | /** 57 | * serialize a fault 58 | * 59 | * @return string The serialization of the fault instance. 60 | * @access public 61 | */ 62 | function serialize(){ 63 | $ns_string = ''; 64 | foreach($this->namespaces as $k => $v){ 65 | $ns_string .= "\n xmlns:$k=\"$v\""; 66 | } 67 | $return_msg = 68 | 'soap_defencoding.'"?>'. 69 | '\n". 70 | ''. 71 | ''. 72 | $this->serialize_val($this->faultcode, 'faultcode'). 73 | $this->serialize_val($this->faultactor, 'faultactor'). 74 | $this->serialize_val($this->faultstring, 'faultstring'). 75 | $this->serialize_val($this->faultdetail, 'detail'). 76 | ''. 77 | ''. 78 | ''; 79 | return $return_msg; 80 | } 81 | } 82 | 83 | /** 84 | * Backward compatibility 85 | */ 86 | class soap_fault extends nusoap_fault { 87 | } 88 | 89 | 90 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.soap_parser.php: -------------------------------------------------------------------------------- 1 | 11 | * @author Scott Nichol 12 | * @version $Id: class.soap_parser.php,v 1.40 2007/04/17 16:34:03 snichol Exp $ 13 | * @access public 14 | */ 15 | class nusoap_parser extends nusoap_base { 16 | 17 | var $xml = ''; 18 | var $xml_encoding = ''; 19 | var $method = ''; 20 | var $root_struct = ''; 21 | var $root_struct_name = ''; 22 | var $root_struct_namespace = ''; 23 | var $root_header = ''; 24 | var $document = ''; // incoming SOAP body (text) 25 | // determines where in the message we are (envelope,header,body,method) 26 | var $status = ''; 27 | var $position = 0; 28 | var $depth = 0; 29 | var $default_namespace = ''; 30 | var $namespaces = array(); 31 | var $message = array(); 32 | var $parent = ''; 33 | var $fault = false; 34 | var $fault_code = ''; 35 | var $fault_str = ''; 36 | var $fault_detail = ''; 37 | var $depth_array = array(); 38 | var $debug_flag = true; 39 | var $soapresponse = NULL; // parsed SOAP Body 40 | var $soapheader = NULL; // parsed SOAP Header 41 | var $responseHeaders = ''; // incoming SOAP headers (text) 42 | var $body_position = 0; 43 | // for multiref parsing: 44 | // array of id => pos 45 | var $ids = array(); 46 | // array of id => hrefs => pos 47 | var $multirefs = array(); 48 | // toggle for auto-decoding element content 49 | var $decode_utf8 = true; 50 | 51 | /** 52 | * constructor that actually does the parsing 53 | * 54 | * @param string $xml SOAP message 55 | * @param string $encoding character encoding scheme of message 56 | * @param string $method method for which XML is parsed (unused?) 57 | * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 58 | * @access public 59 | */ 60 | function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ 61 | parent::nusoap_base(); 62 | $this->xml = $xml; 63 | $this->xml_encoding = $encoding; 64 | $this->method = $method; 65 | $this->decode_utf8 = $decode_utf8; 66 | 67 | // Check whether content has been read. 68 | if(!empty($xml)){ 69 | // Check XML encoding 70 | $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); 73 | if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { 74 | $xml_encoding = $res[1]; 75 | if (strtoupper($xml_encoding) != $encoding) { 76 | $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; 77 | $this->debug($err); 78 | if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { 79 | $this->setError($err); 80 | return; 81 | } 82 | // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed 83 | } else { 84 | $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); 85 | } 86 | } else { 87 | $this->debug('No encoding specified in XML declaration'); 88 | } 89 | } else { 90 | $this->debug('No XML declaration'); 91 | } 92 | $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); 93 | // Create an XML parser - why not xml_parser_create_ns? 94 | $this->parser = xml_parser_create($this->xml_encoding); 95 | // Set the options for parsing the XML data. 96 | //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 97 | xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 98 | xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); 99 | // Set the object for the parser. 100 | xml_set_object($this->parser, $this); 101 | // Set the element handlers for the parser. 102 | xml_set_element_handler($this->parser, 'start_element','end_element'); 103 | xml_set_character_data_handler($this->parser,'character_data'); 104 | 105 | // Parse the XML file. 106 | if(!xml_parse($this->parser,$xml,true)){ 107 | // Display an error message. 108 | $err = sprintf('XML error parsing SOAP payload on line %d: %s', 109 | xml_get_current_line_number($this->parser), 110 | xml_error_string(xml_get_error_code($this->parser))); 111 | $this->debug($err); 112 | $this->debug("XML payload:\n" . $xml); 113 | $this->setError($err); 114 | } else { 115 | $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); 116 | // get final value 117 | $this->soapresponse = $this->message[$this->root_struct]['result']; 118 | // get header value 119 | if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ 120 | $this->soapheader = $this->message[$this->root_header]['result']; 121 | } 122 | // resolve hrefs/ids 123 | if(sizeof($this->multirefs) > 0){ 124 | foreach($this->multirefs as $id => $hrefs){ 125 | $this->debug('resolving multirefs for id: '.$id); 126 | $idVal = $this->buildVal($this->ids[$id]); 127 | if (is_array($idVal) && isset($idVal['!id'])) { 128 | unset($idVal['!id']); 129 | } 130 | foreach($hrefs as $refPos => $ref){ 131 | $this->debug('resolving href at pos '.$refPos); 132 | $this->multirefs[$id][$refPos] = $idVal; 133 | } 134 | } 135 | } 136 | } 137 | xml_parser_free($this->parser); 138 | } else { 139 | $this->debug('xml was empty, didn\'t parse!'); 140 | $this->setError('xml was empty, didn\'t parse!'); 141 | } 142 | } 143 | 144 | /** 145 | * start-element handler 146 | * 147 | * @param resource $parser XML parser object 148 | * @param string $name element name 149 | * @param array $attrs associative array of attributes 150 | * @access private 151 | */ 152 | function start_element($parser, $name, $attrs) { 153 | // position in a total number of elements, starting from 0 154 | // update class level pos 155 | $pos = $this->position++; 156 | // and set mine 157 | $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); 158 | // depth = how many levels removed from root? 159 | // set mine as current global depth and increment global depth value 160 | $this->message[$pos]['depth'] = $this->depth++; 161 | 162 | // else add self as child to whoever the current parent is 163 | if($pos != 0){ 164 | $this->message[$this->parent]['children'] .= '|'.$pos; 165 | } 166 | // set my parent 167 | $this->message[$pos]['parent'] = $this->parent; 168 | // set self as current parent 169 | $this->parent = $pos; 170 | // set self as current value for this depth 171 | $this->depth_array[$this->depth] = $pos; 172 | // get element prefix 173 | if(strpos($name,':')){ 174 | // get ns prefix 175 | $prefix = substr($name,0,strpos($name,':')); 176 | // get unqualified name 177 | $name = substr(strstr($name,':'),1); 178 | } 179 | // set status 180 | if($name == 'Envelope'){ 181 | $this->status = 'envelope'; 182 | } elseif($name == 'Header' && $this->status = 'envelope'){ 183 | $this->root_header = $pos; 184 | $this->status = 'header'; 185 | } elseif($name == 'Body' && $this->status = 'envelope'){ 186 | $this->status = 'body'; 187 | $this->body_position = $pos; 188 | // set method 189 | } elseif($this->status == 'body' && $pos == ($this->body_position+1)){ 190 | $this->status = 'method'; 191 | $this->root_struct_name = $name; 192 | $this->root_struct = $pos; 193 | $this->message[$pos]['type'] = 'struct'; 194 | $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); 195 | } 196 | // set my status 197 | $this->message[$pos]['status'] = $this->status; 198 | // set name 199 | $this->message[$pos]['name'] = htmlspecialchars($name); 200 | // set attrs 201 | $this->message[$pos]['attrs'] = $attrs; 202 | 203 | // loop through atts, logging ns and type declarations 204 | $attstr = ''; 205 | foreach($attrs as $key => $value){ 206 | $key_prefix = $this->getPrefix($key); 207 | $key_localpart = $this->getLocalPart($key); 208 | // if ns declarations, add to class level array of valid namespaces 209 | if($key_prefix == 'xmlns'){ 210 | if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ 211 | $this->XMLSchemaVersion = $value; 212 | $this->namespaces['xsd'] = $this->XMLSchemaVersion; 213 | $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; 214 | } 215 | $this->namespaces[$key_localpart] = $value; 216 | // set method namespace 217 | if($name == $this->root_struct_name){ 218 | $this->methodNamespace = $value; 219 | } 220 | // if it's a type declaration, set type 221 | } elseif($key_localpart == 'type'){ 222 | if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { 223 | // do nothing: already processed arrayType 224 | } else { 225 | $value_prefix = $this->getPrefix($value); 226 | $value_localpart = $this->getLocalPart($value); 227 | $this->message[$pos]['type'] = $value_localpart; 228 | $this->message[$pos]['typePrefix'] = $value_prefix; 229 | if(isset($this->namespaces[$value_prefix])){ 230 | $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; 231 | } else if(isset($attrs['xmlns:'.$value_prefix])) { 232 | $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; 233 | } 234 | // should do something here with the namespace of specified type? 235 | } 236 | } elseif($key_localpart == 'arrayType'){ 237 | $this->message[$pos]['type'] = 'array'; 238 | /* do arrayType ereg here 239 | [1] arrayTypeValue ::= atype asize 240 | [2] atype ::= QName rank* 241 | [3] rank ::= '[' (',')* ']' 242 | [4] asize ::= '[' length~ ']' 243 | [5] length ::= nextDimension* Digit+ 244 | [6] nextDimension ::= Digit+ ',' 245 | */ 246 | $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; 247 | if(ereg($expr,$value,$regs)){ 248 | $this->message[$pos]['typePrefix'] = $regs[1]; 249 | $this->message[$pos]['arrayTypePrefix'] = $regs[1]; 250 | if (isset($this->namespaces[$regs[1]])) { 251 | $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; 252 | } else if (isset($attrs['xmlns:'.$regs[1]])) { 253 | $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; 254 | } 255 | $this->message[$pos]['arrayType'] = $regs[2]; 256 | $this->message[$pos]['arraySize'] = $regs[3]; 257 | $this->message[$pos]['arrayCols'] = $regs[4]; 258 | } 259 | // specifies nil value (or not) 260 | } elseif ($key_localpart == 'nil'){ 261 | $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); 262 | // some other attribute 263 | } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { 264 | $this->message[$pos]['xattrs']['!' . $key] = $value; 265 | } 266 | 267 | if ($key == 'xmlns') { 268 | $this->default_namespace = $value; 269 | } 270 | // log id 271 | if($key == 'id'){ 272 | $this->ids[$value] = $pos; 273 | } 274 | // root 275 | if($key_localpart == 'root' && $value == 1){ 276 | $this->status = 'method'; 277 | $this->root_struct_name = $name; 278 | $this->root_struct = $pos; 279 | $this->debug("found root struct $this->root_struct_name, pos $pos"); 280 | } 281 | // for doclit 282 | $attstr .= " $key=\"$value\""; 283 | } 284 | // get namespace - must be done after namespace atts are processed 285 | if(isset($prefix)){ 286 | $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; 287 | $this->default_namespace = $this->namespaces[$prefix]; 288 | } else { 289 | $this->message[$pos]['namespace'] = $this->default_namespace; 290 | } 291 | if($this->status == 'header'){ 292 | if ($this->root_header != $pos) { 293 | $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 294 | } 295 | } elseif($this->root_struct_name != ''){ 296 | $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 297 | } 298 | } 299 | 300 | /** 301 | * end-element handler 302 | * 303 | * @param resource $parser XML parser object 304 | * @param string $name element name 305 | * @access private 306 | */ 307 | function end_element($parser, $name) { 308 | // position of current element is equal to the last value left in depth_array for my depth 309 | $pos = $this->depth_array[$this->depth--]; 310 | 311 | // get element prefix 312 | if(strpos($name,':')){ 313 | // get ns prefix 314 | $prefix = substr($name,0,strpos($name,':')); 315 | // get unqualified name 316 | $name = substr(strstr($name,':'),1); 317 | } 318 | 319 | // build to native type 320 | if(isset($this->body_position) && $pos > $this->body_position){ 321 | // deal w/ multirefs 322 | if(isset($this->message[$pos]['attrs']['href'])){ 323 | // get id 324 | $id = substr($this->message[$pos]['attrs']['href'],1); 325 | // add placeholder to href array 326 | $this->multirefs[$id][$pos] = 'placeholder'; 327 | // add set a reference to it as the result value 328 | $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; 329 | // build complexType values 330 | } elseif($this->message[$pos]['children'] != ''){ 331 | // if result has already been generated (struct/array) 332 | if(!isset($this->message[$pos]['result'])){ 333 | $this->message[$pos]['result'] = $this->buildVal($pos); 334 | } 335 | // build complexType values of attributes and possibly simpleContent 336 | } elseif (isset($this->message[$pos]['xattrs'])) { 337 | if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 338 | $this->message[$pos]['xattrs']['!'] = null; 339 | } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 340 | if (isset($this->message[$pos]['type'])) { 341 | $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'] : ''); 342 | } else { 343 | $parent = $this->message[$pos]['parent']; 344 | if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 345 | $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 346 | } else { 347 | $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; 348 | } 349 | } 350 | } 351 | $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; 352 | // set value of simpleType (or nil complexType) 353 | } else { 354 | //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); 355 | if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 356 | $this->message[$pos]['xattrs']['!'] = null; 357 | } elseif (isset($this->message[$pos]['type'])) { 358 | $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'] : ''); 359 | } else { 360 | $parent = $this->message[$pos]['parent']; 361 | if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 362 | $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 363 | } else { 364 | $this->message[$pos]['result'] = $this->message[$pos]['cdata']; 365 | } 366 | } 367 | 368 | /* add value to parent's result, if parent is struct/array 369 | $parent = $this->message[$pos]['parent']; 370 | if($this->message[$parent]['type'] != 'map'){ 371 | if(strtolower($this->message[$parent]['type']) == 'array'){ 372 | $this->message[$parent]['result'][] = $this->message[$pos]['result']; 373 | } else { 374 | $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; 375 | } 376 | } 377 | */ 378 | } 379 | } 380 | 381 | // for doclit 382 | if($this->status == 'header'){ 383 | if ($this->root_header != $pos) { 384 | $this->responseHeaders .= ""; 385 | } 386 | } elseif($pos >= $this->root_struct){ 387 | $this->document .= ""; 388 | } 389 | // switch status 390 | if($pos == $this->root_struct){ 391 | $this->status = 'body'; 392 | $this->root_struct_namespace = $this->message[$pos]['namespace']; 393 | } elseif($name == 'Body'){ 394 | $this->status = 'envelope'; 395 | } elseif($name == 'Header'){ 396 | $this->status = 'envelope'; 397 | } elseif($name == 'Envelope'){ 398 | // 399 | } 400 | // set parent back to my parent 401 | $this->parent = $this->message[$pos]['parent']; 402 | } 403 | 404 | /** 405 | * element content handler 406 | * 407 | * @param resource $parser XML parser object 408 | * @param string $data element content 409 | * @access private 410 | */ 411 | function character_data($parser, $data){ 412 | $pos = $this->depth_array[$this->depth]; 413 | if ($this->xml_encoding=='UTF-8'){ 414 | // TODO: add an option to disable this for folks who want 415 | // raw UTF-8 that, e.g., might not map to iso-8859-1 416 | // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); 417 | if($this->decode_utf8){ 418 | $data = utf8_decode($data); 419 | } 420 | } 421 | $this->message[$pos]['cdata'] .= $data; 422 | // for doclit 423 | if($this->status == 'header'){ 424 | $this->responseHeaders .= $data; 425 | } else { 426 | $this->document .= $data; 427 | } 428 | } 429 | 430 | /** 431 | * get the parsed message (SOAP Body) 432 | * 433 | * @return mixed 434 | * @access public 435 | * @deprecated use get_soapbody instead 436 | */ 437 | function get_response(){ 438 | return $this->soapresponse; 439 | } 440 | 441 | /** 442 | * get the parsed SOAP Body (NULL if there was none) 443 | * 444 | * @return mixed 445 | * @access public 446 | */ 447 | function get_soapbody(){ 448 | return $this->soapresponse; 449 | } 450 | 451 | /** 452 | * get the parsed SOAP Header (NULL if there was none) 453 | * 454 | * @return mixed 455 | * @access public 456 | */ 457 | function get_soapheader(){ 458 | return $this->soapheader; 459 | } 460 | 461 | /** 462 | * get the unparsed SOAP Header 463 | * 464 | * @return string XML or empty if no Header 465 | * @access public 466 | */ 467 | function getHeaders(){ 468 | return $this->responseHeaders; 469 | } 470 | 471 | /** 472 | * decodes simple types into PHP variables 473 | * 474 | * @param string $value value to decode 475 | * @param string $type XML type to decode 476 | * @param string $typens XML type namespace to decode 477 | * @return mixed PHP value 478 | * @access private 479 | */ 480 | function decodeSimple($value, $type, $typens) { 481 | // TODO: use the namespace! 482 | if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { 483 | return (string) $value; 484 | } 485 | if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { 486 | return (int) $value; 487 | } 488 | if ($type == 'float' || $type == 'double' || $type == 'decimal') { 489 | return (double) $value; 490 | } 491 | if ($type == 'boolean') { 492 | if (strtolower($value) == 'false' || strtolower($value) == 'f') { 493 | return false; 494 | } 495 | return (boolean) $value; 496 | } 497 | if ($type == 'base64' || $type == 'base64Binary') { 498 | $this->debug('Decode base64 value'); 499 | return base64_decode($value); 500 | } 501 | // obscure numeric types 502 | if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' 503 | || $type == 'nonNegativeInteger' || $type == 'positiveInteger' 504 | || $type == 'unsignedInt' 505 | || $type == 'unsignedShort' || $type == 'unsignedByte') { 506 | return (int) $value; 507 | } 508 | // bogus: parser treats array with no elements as a simple type 509 | if ($type == 'array') { 510 | return array(); 511 | } 512 | // everything else 513 | return (string) $value; 514 | } 515 | 516 | /** 517 | * builds response structures for compound values (arrays/structs) 518 | * and scalars 519 | * 520 | * @param integer $pos position in node tree 521 | * @return mixed PHP value 522 | * @access private 523 | */ 524 | function buildVal($pos){ 525 | if(!isset($this->message[$pos]['type'])){ 526 | $this->message[$pos]['type'] = ''; 527 | } 528 | $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); 529 | // if there are children... 530 | if($this->message[$pos]['children'] != ''){ 531 | $this->debug('in buildVal, there are children'); 532 | $children = explode('|',$this->message[$pos]['children']); 533 | array_shift($children); // knock off empty 534 | // md array 535 | if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ 536 | $r=0; // rowcount 537 | $c=0; // colcount 538 | foreach($children as $child_pos){ 539 | $this->debug("in buildVal, got an MD array element: $r, $c"); 540 | $params[$r][] = $this->message[$child_pos]['result']; 541 | $c++; 542 | if($c == $this->message[$pos]['arrayCols']){ 543 | $c = 0; 544 | $r++; 545 | } 546 | } 547 | // array 548 | } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ 549 | $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); 550 | foreach($children as $child_pos){ 551 | $params[] = &$this->message[$child_pos]['result']; 552 | } 553 | // apache Map type: java hashtable 554 | } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ 555 | $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); 556 | foreach($children as $child_pos){ 557 | $kv = explode("|",$this->message[$child_pos]['children']); 558 | $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; 559 | } 560 | // generic compound type 561 | //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { 562 | } else { 563 | // Apache Vector type: treat as an array 564 | $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); 565 | if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { 566 | $notstruct = 1; 567 | } else { 568 | $notstruct = 0; 569 | } 570 | // 571 | foreach($children as $child_pos){ 572 | if($notstruct){ 573 | $params[] = &$this->message[$child_pos]['result']; 574 | } else { 575 | if (isset($params[$this->message[$child_pos]['name']])) { 576 | // de-serialize repeated element name into an array 577 | if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { 578 | $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); 579 | } 580 | $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; 581 | } else { 582 | $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; 583 | } 584 | } 585 | } 586 | } 587 | if (isset($this->message[$pos]['xattrs'])) { 588 | $this->debug('in buildVal, handling attributes'); 589 | foreach ($this->message[$pos]['xattrs'] as $n => $v) { 590 | $params[$n] = $v; 591 | } 592 | } 593 | // handle simpleContent 594 | if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 595 | $this->debug('in buildVal, handling simpleContent'); 596 | if (isset($this->message[$pos]['type'])) { 597 | $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 598 | } else { 599 | $parent = $this->message[$pos]['parent']; 600 | if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 601 | $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 602 | } else { 603 | $params['!'] = $this->message[$pos]['cdata']; 604 | } 605 | } 606 | } 607 | $ret = is_array($params) ? $params : array(); 608 | $this->debug('in buildVal, return:'); 609 | $this->appendDebug($this->varDump($ret)); 610 | return $ret; 611 | } else { 612 | $this->debug('in buildVal, no children, building scalar'); 613 | $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; 614 | if (isset($this->message[$pos]['type'])) { 615 | $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 616 | $this->debug("in buildVal, return: $ret"); 617 | return $ret; 618 | } 619 | $parent = $this->message[$pos]['parent']; 620 | if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 621 | $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 622 | $this->debug("in buildVal, return: $ret"); 623 | return $ret; 624 | } 625 | $ret = $this->message[$pos]['cdata']; 626 | $this->debug("in buildVal, return: $ret"); 627 | return $ret; 628 | } 629 | } 630 | } 631 | 632 | /** 633 | * Backward compatibility 634 | */ 635 | class soap_parser extends nusoap_parser { 636 | } 637 | 638 | 639 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.soap_server.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Scott Nichol 13 | * @version $Id: class.soap_server.php,v 1.58 2007/10/30 18:50:30 snichol Exp $ 14 | * @access public 15 | */ 16 | class nusoap_server extends nusoap_base { 17 | /** 18 | * HTTP headers of request 19 | * @var array 20 | * @access private 21 | */ 22 | var $headers = array(); 23 | /** 24 | * HTTP request 25 | * @var string 26 | * @access private 27 | */ 28 | var $request = ''; 29 | /** 30 | * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) 31 | * @var string 32 | * @access public 33 | */ 34 | var $requestHeaders = ''; 35 | /** 36 | * SOAP Headers from request (parsed) 37 | * @var mixed 38 | * @access public 39 | */ 40 | var $requestHeader = NULL; 41 | /** 42 | * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) 43 | * @var string 44 | * @access public 45 | */ 46 | var $document = ''; 47 | /** 48 | * SOAP payload for request (text) 49 | * @var string 50 | * @access public 51 | */ 52 | var $requestSOAP = ''; 53 | /** 54 | * requested method namespace URI 55 | * @var string 56 | * @access private 57 | */ 58 | var $methodURI = ''; 59 | /** 60 | * name of method requested 61 | * @var string 62 | * @access private 63 | */ 64 | var $methodname = ''; 65 | /** 66 | * method parameters from request 67 | * @var array 68 | * @access private 69 | */ 70 | var $methodparams = array(); 71 | /** 72 | * SOAP Action from request 73 | * @var string 74 | * @access private 75 | */ 76 | var $SOAPAction = ''; 77 | /** 78 | * character set encoding of incoming (request) messages 79 | * @var string 80 | * @access public 81 | */ 82 | var $xml_encoding = ''; 83 | /** 84 | * toggles whether the parser decodes element content w/ utf8_decode() 85 | * @var boolean 86 | * @access public 87 | */ 88 | var $decode_utf8 = true; 89 | 90 | /** 91 | * HTTP headers of response 92 | * @var array 93 | * @access public 94 | */ 95 | var $outgoing_headers = array(); 96 | /** 97 | * HTTP response 98 | * @var string 99 | * @access private 100 | */ 101 | var $response = ''; 102 | /** 103 | * SOAP headers for response (text or array of soapval or associative array) 104 | * @var mixed 105 | * @access public 106 | */ 107 | var $responseHeaders = ''; 108 | /** 109 | * SOAP payload for response (text) 110 | * @var string 111 | * @access private 112 | */ 113 | var $responseSOAP = ''; 114 | /** 115 | * method return value to place in response 116 | * @var mixed 117 | * @access private 118 | */ 119 | var $methodreturn = false; 120 | /** 121 | * whether $methodreturn is a string of literal XML 122 | * @var boolean 123 | * @access public 124 | */ 125 | var $methodreturnisliteralxml = false; 126 | /** 127 | * SOAP fault for response (or false) 128 | * @var mixed 129 | * @access private 130 | */ 131 | var $fault = false; 132 | /** 133 | * text indication of result (for debugging) 134 | * @var string 135 | * @access private 136 | */ 137 | var $result = 'successful'; 138 | 139 | /** 140 | * assoc array of operations => opData; operations are added by the register() 141 | * method or by parsing an external WSDL definition 142 | * @var array 143 | * @access private 144 | */ 145 | var $operations = array(); 146 | /** 147 | * wsdl instance (if one) 148 | * @var mixed 149 | * @access private 150 | */ 151 | var $wsdl = false; 152 | /** 153 | * URL for WSDL (if one) 154 | * @var mixed 155 | * @access private 156 | */ 157 | var $externalWSDLURL = false; 158 | /** 159 | * whether to append debug to response as XML comment 160 | * @var boolean 161 | * @access public 162 | */ 163 | var $debug_flag = false; 164 | 165 | 166 | /** 167 | * constructor 168 | * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. 169 | * 170 | * @param mixed $wsdl file path or URL (string), or wsdl instance (object) 171 | * @access public 172 | */ 173 | function nusoap_server($wsdl=false){ 174 | parent::nusoap_base(); 175 | // turn on debugging? 176 | global $debug; 177 | global $HTTP_SERVER_VARS; 178 | 179 | if (isset($_SERVER)) { 180 | $this->debug("_SERVER is defined:"); 181 | $this->appendDebug($this->varDump($_SERVER)); 182 | } elseif (isset($HTTP_SERVER_VARS)) { 183 | $this->debug("HTTP_SERVER_VARS is defined:"); 184 | $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); 185 | } else { 186 | $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); 187 | } 188 | 189 | if (isset($debug)) { 190 | $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); 191 | $this->debug_flag = $debug; 192 | } elseif (isset($_SERVER['QUERY_STRING'])) { 193 | $qs = explode('&', $_SERVER['QUERY_STRING']); 194 | foreach ($qs as $v) { 195 | if (substr($v, 0, 6) == 'debug=') { 196 | $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); 197 | $this->debug_flag = substr($v, 6); 198 | } 199 | } 200 | } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 201 | $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); 202 | foreach ($qs as $v) { 203 | if (substr($v, 0, 6) == 'debug=') { 204 | $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); 205 | $this->debug_flag = substr($v, 6); 206 | } 207 | } 208 | } 209 | 210 | // wsdl 211 | if($wsdl){ 212 | $this->debug("In nusoap_server, WSDL is specified"); 213 | if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { 214 | $this->wsdl = $wsdl; 215 | $this->externalWSDLURL = $this->wsdl->wsdl; 216 | $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); 217 | } else { 218 | $this->debug('Create wsdl from ' . $wsdl); 219 | $this->wsdl = new wsdl($wsdl); 220 | $this->externalWSDLURL = $wsdl; 221 | } 222 | $this->appendDebug($this->wsdl->getDebug()); 223 | $this->wsdl->clearDebug(); 224 | if($err = $this->wsdl->getError()){ 225 | die('WSDL ERROR: '.$err); 226 | } 227 | } 228 | } 229 | 230 | /** 231 | * processes request and returns response 232 | * 233 | * @param string $data usually is the value of $HTTP_RAW_POST_DATA 234 | * @access public 235 | */ 236 | function service($data){ 237 | global $HTTP_SERVER_VARS; 238 | 239 | if (isset($_SERVER['QUERY_STRING'])) { 240 | $qs = $_SERVER['QUERY_STRING']; 241 | } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 242 | $qs = $HTTP_SERVER_VARS['QUERY_STRING']; 243 | } else { 244 | $qs = ''; 245 | } 246 | $this->debug("In service, query string=$qs"); 247 | 248 | if (ereg('wsdl', $qs) ){ 249 | $this->debug("In service, this is a request for WSDL"); 250 | if($this->externalWSDLURL){ 251 | if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL 252 | header('Location: '.$this->externalWSDLURL); 253 | } else { // assume file 254 | header("Content-Type: text/xml\r\n"); 255 | $fp = fopen($this->externalWSDLURL, 'r'); 256 | fpassthru($fp); 257 | } 258 | } elseif ($this->wsdl) { 259 | header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); 260 | print $this->wsdl->serialize($this->debug_flag); 261 | if ($this->debug_flag) { 262 | $this->debug('wsdl:'); 263 | $this->appendDebug($this->varDump($this->wsdl)); 264 | print $this->getDebugAsXMLComment(); 265 | } 266 | } else { 267 | header("Content-Type: text/html; charset=ISO-8859-1\r\n"); 268 | print "This service does not provide WSDL"; 269 | } 270 | } elseif ($data == '' && $this->wsdl) { 271 | $this->debug("In service, there is no data, so return Web description"); 272 | print $this->wsdl->webDescription(); 273 | } else { 274 | $this->debug("In service, invoke the request"); 275 | $this->parse_request($data); 276 | if (! $this->fault) { 277 | $this->invoke_method(); 278 | } 279 | if (! $this->fault) { 280 | $this->serialize_return(); 281 | } 282 | $this->send_response(); 283 | } 284 | } 285 | 286 | /** 287 | * parses HTTP request headers. 288 | * 289 | * The following fields are set by this function (when successful) 290 | * 291 | * headers 292 | * request 293 | * xml_encoding 294 | * SOAPAction 295 | * 296 | * @access private 297 | */ 298 | function parse_http_headers() { 299 | global $HTTP_SERVER_VARS; 300 | 301 | $this->request = ''; 302 | $this->SOAPAction = ''; 303 | if(function_exists('getallheaders')){ 304 | $this->debug("In parse_http_headers, use getallheaders"); 305 | $headers = getallheaders(); 306 | foreach($headers as $k=>$v){ 307 | $k = strtolower($k); 308 | $this->headers[$k] = $v; 309 | $this->request .= "$k: $v\r\n"; 310 | $this->debug("$k: $v"); 311 | } 312 | // get SOAPAction header 313 | if(isset($this->headers['soapaction'])){ 314 | $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); 315 | } 316 | // get the character encoding of the incoming request 317 | if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ 318 | $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); 319 | if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 320 | $this->xml_encoding = strtoupper($enc); 321 | } else { 322 | $this->xml_encoding = 'US-ASCII'; 323 | } 324 | } else { 325 | // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 326 | $this->xml_encoding = 'ISO-8859-1'; 327 | } 328 | } elseif(isset($_SERVER) && is_array($_SERVER)){ 329 | $this->debug("In parse_http_headers, use _SERVER"); 330 | foreach ($_SERVER as $k => $v) { 331 | if (substr($k, 0, 5) == 'HTTP_') { 332 | $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); 333 | } else { 334 | $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); 335 | } 336 | if ($k == 'soapaction') { 337 | // get SOAPAction header 338 | $k = 'SOAPAction'; 339 | $v = str_replace('"', '', $v); 340 | $v = str_replace('\\', '', $v); 341 | $this->SOAPAction = $v; 342 | } else if ($k == 'content-type') { 343 | // get the character encoding of the incoming request 344 | if (strpos($v, '=')) { 345 | $enc = substr(strstr($v, '='), 1); 346 | $enc = str_replace('"', '', $enc); 347 | $enc = str_replace('\\', '', $enc); 348 | if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 349 | $this->xml_encoding = strtoupper($enc); 350 | } else { 351 | $this->xml_encoding = 'US-ASCII'; 352 | } 353 | } else { 354 | // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 355 | $this->xml_encoding = 'ISO-8859-1'; 356 | } 357 | } 358 | $this->headers[$k] = $v; 359 | $this->request .= "$k: $v\r\n"; 360 | $this->debug("$k: $v"); 361 | } 362 | } elseif (is_array($HTTP_SERVER_VARS)) { 363 | $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); 364 | foreach ($HTTP_SERVER_VARS as $k => $v) { 365 | if (substr($k, 0, 5) == 'HTTP_') { 366 | $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); 367 | } else { 368 | $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); 369 | } 370 | if ($k == 'soapaction') { 371 | // get SOAPAction header 372 | $k = 'SOAPAction'; 373 | $v = str_replace('"', '', $v); 374 | $v = str_replace('\\', '', $v); 375 | $this->SOAPAction = $v; 376 | } else if ($k == 'content-type') { 377 | // get the character encoding of the incoming request 378 | if (strpos($v, '=')) { 379 | $enc = substr(strstr($v, '='), 1); 380 | $enc = str_replace('"', '', $enc); 381 | $enc = str_replace('\\', '', $enc); 382 | if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 383 | $this->xml_encoding = strtoupper($enc); 384 | } else { 385 | $this->xml_encoding = 'US-ASCII'; 386 | } 387 | } else { 388 | // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 389 | $this->xml_encoding = 'ISO-8859-1'; 390 | } 391 | } 392 | $this->headers[$k] = $v; 393 | $this->request .= "$k: $v\r\n"; 394 | $this->debug("$k: $v"); 395 | } 396 | } else { 397 | $this->debug("In parse_http_headers, HTTP headers not accessible"); 398 | $this->setError("HTTP headers not accessible"); 399 | } 400 | } 401 | 402 | /** 403 | * parses a request 404 | * 405 | * The following fields are set by this function (when successful) 406 | * 407 | * headers 408 | * request 409 | * xml_encoding 410 | * SOAPAction 411 | * request 412 | * requestSOAP 413 | * methodURI 414 | * methodname 415 | * methodparams 416 | * requestHeaders 417 | * document 418 | * 419 | * This sets the fault field on error 420 | * 421 | * @param string $data XML string 422 | * @access private 423 | */ 424 | function parse_request($data='') { 425 | $this->debug('entering parse_request()'); 426 | $this->parse_http_headers(); 427 | $this->debug('got character encoding: '.$this->xml_encoding); 428 | // uncompress if necessary 429 | if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { 430 | $this->debug('got content encoding: ' . $this->headers['content-encoding']); 431 | if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { 432 | // if decoding works, use it. else assume data wasn't gzencoded 433 | if (function_exists('gzuncompress')) { 434 | if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { 435 | $data = $degzdata; 436 | } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { 437 | $data = $degzdata; 438 | } else { 439 | $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); 440 | return; 441 | } 442 | } else { 443 | $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); 444 | return; 445 | } 446 | } 447 | } 448 | $this->request .= "\r\n".$data; 449 | $data = $this->parseRequest($this->headers, $data); 450 | $this->requestSOAP = $data; 451 | $this->debug('leaving parse_request'); 452 | } 453 | 454 | /** 455 | * invokes a PHP function for the requested SOAP method 456 | * 457 | * The following fields are set by this function (when successful) 458 | * 459 | * methodreturn 460 | * 461 | * Note that the PHP function that is called may also set the following 462 | * fields to affect the response sent to the client 463 | * 464 | * responseHeaders 465 | * outgoing_headers 466 | * 467 | * This sets the fault field on error 468 | * 469 | * @access private 470 | */ 471 | function invoke_method() { 472 | $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); 473 | 474 | if ($this->wsdl) { 475 | if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { 476 | $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); 477 | $this->appendDebug('opData=' . $this->varDump($this->opData)); 478 | } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { 479 | // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element 480 | $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); 481 | $this->appendDebug('opData=' . $this->varDump($this->opData)); 482 | $this->methodname = $this->opData['name']; 483 | } else { 484 | $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); 485 | $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); 486 | return; 487 | } 488 | } else { 489 | $this->debug('in invoke_method, no WSDL to validate method'); 490 | } 491 | 492 | // if a . is present in $this->methodname, we see if there is a class in scope, 493 | // which could be referred to. We will also distinguish between two deliminators, 494 | // to allow methods to be called a the class or an instance 495 | $class = ''; 496 | $method = ''; 497 | if (strpos($this->methodname, '..') > 0) { 498 | $delim = '..'; 499 | } else if (strpos($this->methodname, '.') > 0) { 500 | $delim = '.'; 501 | } else { 502 | $delim = ''; 503 | } 504 | 505 | if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && 506 | class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { 507 | // get the class and method name 508 | $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); 509 | $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); 510 | $this->debug("in invoke_method, class=$class method=$method delim=$delim"); 511 | } 512 | 513 | // does method exist? 514 | if ($class == '') { 515 | if (!function_exists($this->methodname)) { 516 | $this->debug("in invoke_method, function '$this->methodname' not found!"); 517 | $this->result = 'fault: method not found'; 518 | $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 519 | return; 520 | } 521 | } else { 522 | $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; 523 | if (!in_array($method_to_compare, get_class_methods($class))) { 524 | $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); 525 | $this->result = 'fault: method not found'; 526 | $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 527 | return; 528 | } 529 | } 530 | 531 | // evaluate message, getting back parameters 532 | // verify that request parameters match the method's signature 533 | if(! $this->verify_method($this->methodname,$this->methodparams)){ 534 | // debug 535 | $this->debug('ERROR: request not verified against method signature'); 536 | $this->result = 'fault: request failed validation against method signature'; 537 | // return fault 538 | $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); 539 | return; 540 | } 541 | 542 | // if there are parameters to pass 543 | $this->debug('in invoke_method, params:'); 544 | $this->appendDebug($this->varDump($this->methodparams)); 545 | $this->debug("in invoke_method, calling '$this->methodname'"); 546 | if (!function_exists('call_user_func_array')) { 547 | if ($class == '') { 548 | $this->debug('in invoke_method, calling function using eval()'); 549 | $funcCall = "\$this->methodreturn = $this->methodname("; 550 | } else { 551 | if ($delim == '..') { 552 | $this->debug('in invoke_method, calling class method using eval()'); 553 | $funcCall = "\$this->methodreturn = ".$class."::".$method."("; 554 | } else { 555 | $this->debug('in invoke_method, calling instance method using eval()'); 556 | // generate unique instance name 557 | $instname = "\$inst_".time(); 558 | $funcCall = $instname." = new ".$class."(); "; 559 | $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; 560 | } 561 | } 562 | if ($this->methodparams) { 563 | foreach ($this->methodparams as $param) { 564 | if (is_array($param) || is_object($param)) { 565 | $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); 566 | return; 567 | } 568 | $funcCall .= "\"$param\","; 569 | } 570 | $funcCall = substr($funcCall, 0, -1); 571 | } 572 | $funcCall .= ');'; 573 | $this->debug('in invoke_method, function call: '.$funcCall); 574 | @eval($funcCall); 575 | } else { 576 | if ($class == '') { 577 | $this->debug('in invoke_method, calling function using call_user_func_array()'); 578 | $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() 579 | } elseif ($delim == '..') { 580 | $this->debug('in invoke_method, calling class method using call_user_func_array()'); 581 | $call_arg = array ($class, $method); 582 | } else { 583 | $this->debug('in invoke_method, calling instance method using call_user_func_array()'); 584 | $instance = new $class (); 585 | $call_arg = array(&$instance, $method); 586 | } 587 | if (is_array($this->methodparams)) { 588 | $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); 589 | } else { 590 | $this->methodreturn = call_user_func_array($call_arg, array()); 591 | } 592 | } 593 | $this->debug('in invoke_method, methodreturn:'); 594 | $this->appendDebug($this->varDump($this->methodreturn)); 595 | $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); 596 | } 597 | 598 | /** 599 | * serializes the return value from a PHP function into a full SOAP Envelope 600 | * 601 | * The following fields are set by this function (when successful) 602 | * 603 | * responseSOAP 604 | * 605 | * This sets the fault field on error 606 | * 607 | * @access private 608 | */ 609 | function serialize_return() { 610 | $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); 611 | // if fault 612 | if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { 613 | $this->debug('got a fault object from method'); 614 | $this->fault = $this->methodreturn; 615 | return; 616 | } elseif ($this->methodreturnisliteralxml) { 617 | $return_val = $this->methodreturn; 618 | // returned value(s) 619 | } else { 620 | $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); 621 | $this->debug('serializing return value'); 622 | if($this->wsdl){ 623 | if (sizeof($this->opData['output']['parts']) > 1) { 624 | $this->debug('more than one output part, so use the method return unchanged'); 625 | $opParams = $this->methodreturn; 626 | } elseif (sizeof($this->opData['output']['parts']) == 1) { 627 | $this->debug('exactly one output part, so wrap the method return in a simple array'); 628 | // TODO: verify that it is not already wrapped! 629 | //foreach ($this->opData['output']['parts'] as $name => $type) { 630 | // $this->debug('wrap in element named ' . $name); 631 | //} 632 | $opParams = array($this->methodreturn); 633 | } 634 | $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); 635 | $this->appendDebug($this->wsdl->getDebug()); 636 | $this->wsdl->clearDebug(); 637 | if($errstr = $this->wsdl->getError()){ 638 | $this->debug('got wsdl error: '.$errstr); 639 | $this->fault('SOAP-ENV:Server', 'unable to serialize result'); 640 | return; 641 | } 642 | } else { 643 | if (isset($this->methodreturn)) { 644 | $return_val = $this->serialize_val($this->methodreturn, 'return'); 645 | } else { 646 | $return_val = ''; 647 | $this->debug('in absence of WSDL, assume void return for backward compatibility'); 648 | } 649 | } 650 | } 651 | $this->debug('return value:'); 652 | $this->appendDebug($this->varDump($return_val)); 653 | 654 | $this->debug('serializing response'); 655 | if ($this->wsdl) { 656 | $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); 657 | if ($this->opData['style'] == 'rpc') { 658 | $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); 659 | if ($this->opData['output']['use'] == 'literal') { 660 | // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 661 | $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; 662 | } else { 663 | $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; 664 | } 665 | } else { 666 | $this->debug('style is not rpc for serialization: assume document'); 667 | $payload = $return_val; 668 | } 669 | } else { 670 | $this->debug('do not have WSDL for serialization: assume rpc/encoded'); 671 | $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; 672 | } 673 | $this->result = 'successful'; 674 | if($this->wsdl){ 675 | //if($this->debug_flag){ 676 | $this->appendDebug($this->wsdl->getDebug()); 677 | // } 678 | if (isset($opData['output']['encodingStyle'])) { 679 | $encodingStyle = $opData['output']['encodingStyle']; 680 | } else { 681 | $encodingStyle = ''; 682 | } 683 | // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. 684 | $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); 685 | } else { 686 | $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); 687 | } 688 | $this->debug("Leaving serialize_return"); 689 | } 690 | 691 | /** 692 | * sends an HTTP response 693 | * 694 | * The following fields are set by this function (when successful) 695 | * 696 | * outgoing_headers 697 | * response 698 | * 699 | * @access private 700 | */ 701 | function send_response() { 702 | $this->debug('Enter send_response'); 703 | if ($this->fault) { 704 | $payload = $this->fault->serialize(); 705 | $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; 706 | $this->outgoing_headers[] = "Status: 500 Internal Server Error"; 707 | } else { 708 | $payload = $this->responseSOAP; 709 | // Some combinations of PHP+Web server allow the Status 710 | // to come through as a header. Since OK is the default 711 | // just do nothing. 712 | // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; 713 | // $this->outgoing_headers[] = "Status: 200 OK"; 714 | } 715 | // add debug data if in debug mode 716 | if(isset($this->debug_flag) && $this->debug_flag){ 717 | $payload .= $this->getDebugAsXMLComment(); 718 | } 719 | $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; 720 | ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 721 | $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; 722 | // Let the Web server decide about this 723 | //$this->outgoing_headers[] = "Connection: Close\r\n"; 724 | $payload = $this->getHTTPBody($payload); 725 | $type = $this->getHTTPContentType(); 726 | $charset = $this->getHTTPContentTypeCharset(); 727 | $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); 728 | //begin code to compress payload - by John 729 | // NOTE: there is no way to know whether the Web server will also compress 730 | // this data. 731 | if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { 732 | if (strstr($this->headers['accept-encoding'], 'gzip')) { 733 | if (function_exists('gzencode')) { 734 | if (isset($this->debug_flag) && $this->debug_flag) { 735 | $payload .= ""; 736 | } 737 | $this->outgoing_headers[] = "Content-Encoding: gzip"; 738 | $payload = gzencode($payload); 739 | } else { 740 | if (isset($this->debug_flag) && $this->debug_flag) { 741 | $payload .= ""; 742 | } 743 | } 744 | } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { 745 | // Note: MSIE requires gzdeflate output (no Zlib header and checksum), 746 | // instead of gzcompress output, 747 | // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) 748 | if (function_exists('gzdeflate')) { 749 | if (isset($this->debug_flag) && $this->debug_flag) { 750 | $payload .= ""; 751 | } 752 | $this->outgoing_headers[] = "Content-Encoding: deflate"; 753 | $payload = gzdeflate($payload); 754 | } else { 755 | if (isset($this->debug_flag) && $this->debug_flag) { 756 | $payload .= ""; 757 | } 758 | } 759 | } 760 | } 761 | //end code 762 | $this->outgoing_headers[] = "Content-Length: ".strlen($payload); 763 | reset($this->outgoing_headers); 764 | foreach($this->outgoing_headers as $hdr){ 765 | header($hdr, false); 766 | } 767 | print $payload; 768 | $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; 769 | } 770 | 771 | /** 772 | * takes the value that was created by parsing the request 773 | * and compares to the method's signature, if available. 774 | * 775 | * @param string $operation The operation to be invoked 776 | * @param array $request The array of parameter values 777 | * @return boolean Whether the operation was found 778 | * @access private 779 | */ 780 | function verify_method($operation,$request){ 781 | if(isset($this->wsdl) && is_object($this->wsdl)){ 782 | if($this->wsdl->getOperationData($operation)){ 783 | return true; 784 | } 785 | } elseif(isset($this->operations[$operation])){ 786 | return true; 787 | } 788 | return false; 789 | } 790 | 791 | /** 792 | * processes SOAP message received from client 793 | * 794 | * @param array $headers The HTTP headers 795 | * @param string $data unprocessed request data from client 796 | * @return mixed value of the message, decoded into a PHP type 797 | * @access private 798 | */ 799 | function parseRequest($headers, $data) { 800 | $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']); 801 | if (!strstr($headers['content-type'], 'text/xml')) { 802 | $this->setError('Request not of type text/xml'); 803 | return false; 804 | } 805 | if (strpos($headers['content-type'], '=')) { 806 | $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 807 | $this->debug('Got response encoding: ' . $enc); 808 | if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 809 | $this->xml_encoding = strtoupper($enc); 810 | } else { 811 | $this->xml_encoding = 'US-ASCII'; 812 | } 813 | } else { 814 | // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 815 | $this->xml_encoding = 'ISO-8859-1'; 816 | } 817 | $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 818 | // parse response, get soap parser obj 819 | $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); 820 | // parser debug 821 | $this->debug("parser debug: \n".$parser->getDebug()); 822 | // if fault occurred during message parsing 823 | if($err = $parser->getError()){ 824 | $this->result = 'fault: error in msg parsing: '.$err; 825 | $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); 826 | // else successfully parsed request into soapval object 827 | } else { 828 | // get/set methodname 829 | $this->methodURI = $parser->root_struct_namespace; 830 | $this->methodname = $parser->root_struct_name; 831 | $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); 832 | $this->debug('calling parser->get_soapbody()'); 833 | $this->methodparams = $parser->get_soapbody(); 834 | // get SOAP headers 835 | $this->requestHeaders = $parser->getHeaders(); 836 | // get SOAP Header 837 | $this->requestHeader = $parser->get_soapheader(); 838 | // add document for doclit support 839 | $this->document = $parser->document; 840 | } 841 | } 842 | 843 | /** 844 | * gets the HTTP body for the current response. 845 | * 846 | * @param string $soapmsg The SOAP payload 847 | * @return string The HTTP body, which includes the SOAP payload 848 | * @access private 849 | */ 850 | function getHTTPBody($soapmsg) { 851 | return $soapmsg; 852 | } 853 | 854 | /** 855 | * gets the HTTP content type for the current response. 856 | * 857 | * Note: getHTTPBody must be called before this. 858 | * 859 | * @return string the HTTP content type for the current response. 860 | * @access private 861 | */ 862 | function getHTTPContentType() { 863 | return 'text/xml'; 864 | } 865 | 866 | /** 867 | * gets the HTTP content type charset for the current response. 868 | * returns false for non-text content types. 869 | * 870 | * Note: getHTTPBody must be called before this. 871 | * 872 | * @return string the HTTP content type charset for the current response. 873 | * @access private 874 | */ 875 | function getHTTPContentTypeCharset() { 876 | return $this->soap_defencoding; 877 | } 878 | 879 | /** 880 | * add a method to the dispatch map (this has been replaced by the register method) 881 | * 882 | * @param string $methodname 883 | * @param string $in array of input values 884 | * @param string $out array of output values 885 | * @access public 886 | * @deprecated 887 | */ 888 | function add_to_map($methodname,$in,$out){ 889 | $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); 890 | } 891 | 892 | /** 893 | * register a service function with the server 894 | * 895 | * @param string $name the name of the PHP function, class.method or class..method 896 | * @param array $in assoc array of input values: key = param name, value = param type 897 | * @param array $out assoc array of output values: key = param name, value = param type 898 | * @param mixed $namespace the element namespace for the method or false 899 | * @param mixed $soapaction the soapaction for the method or false 900 | * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically 901 | * @param mixed $use optional (encoded|literal) or false 902 | * @param string $documentation optional Description to include in WSDL 903 | * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 904 | * @access public 905 | */ 906 | function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ 907 | global $HTTP_SERVER_VARS; 908 | 909 | if($this->externalWSDLURL){ 910 | die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); 911 | } 912 | if (! $name) { 913 | die('You must specify a name when you register an operation'); 914 | } 915 | if (!is_array($in)) { 916 | die('You must provide an array for operation inputs'); 917 | } 918 | if (!is_array($out)) { 919 | die('You must provide an array for operation outputs'); 920 | } 921 | if(false == $namespace) { 922 | } 923 | if(false == $soapaction) { 924 | if (isset($_SERVER)) { 925 | $SERVER_NAME = $_SERVER['SERVER_NAME']; 926 | $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 927 | $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 928 | } elseif (isset($HTTP_SERVER_VARS)) { 929 | $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 930 | $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 931 | $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 932 | } else { 933 | $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 934 | } 935 | if ($HTTPS == '1' || $HTTPS == 'on') { 936 | $SCHEME = 'https'; 937 | } else { 938 | $SCHEME = 'http'; 939 | } 940 | $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; 941 | } 942 | if(false == $style) { 943 | $style = "rpc"; 944 | } 945 | if(false == $use) { 946 | $use = "encoded"; 947 | } 948 | if ($use == 'encoded' && $encodingStyle = '') { 949 | $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 950 | } 951 | 952 | $this->operations[$name] = array( 953 | 'name' => $name, 954 | 'in' => $in, 955 | 'out' => $out, 956 | 'namespace' => $namespace, 957 | 'soapaction' => $soapaction, 958 | 'style' => $style); 959 | if($this->wsdl){ 960 | $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); 961 | } 962 | return true; 963 | } 964 | 965 | /** 966 | * Specify a fault to be returned to the client. 967 | * This also acts as a flag to the server that a fault has occured. 968 | * 969 | * @param string $faultcode 970 | * @param string $faultstring 971 | * @param string $faultactor 972 | * @param string $faultdetail 973 | * @access public 974 | */ 975 | function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ 976 | if ($faultdetail == '' && $this->debug_flag) { 977 | $faultdetail = $this->getDebug(); 978 | } 979 | $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); 980 | $this->fault->soap_defencoding = $this->soap_defencoding; 981 | } 982 | 983 | /** 984 | * Sets up wsdl object. 985 | * Acts as a flag to enable internal WSDL generation 986 | * 987 | * @param string $serviceName, name of the service 988 | * @param mixed $namespace optional 'tns' service namespace or false 989 | * @param mixed $endpoint optional URL of service endpoint or false 990 | * @param string $style optional (rpc|document) WSDL style (also specified by operation) 991 | * @param string $transport optional SOAP transport 992 | * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false 993 | */ 994 | function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) 995 | { 996 | global $HTTP_SERVER_VARS; 997 | 998 | if (isset($_SERVER)) { 999 | $SERVER_NAME = $_SERVER['SERVER_NAME']; 1000 | $SERVER_PORT = $_SERVER['SERVER_PORT']; 1001 | $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 1002 | $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 1003 | } elseif (isset($HTTP_SERVER_VARS)) { 1004 | $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 1005 | $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; 1006 | $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 1007 | $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 1008 | } else { 1009 | $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 1010 | } 1011 | // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) 1012 | $colon = strpos($SERVER_NAME,":"); 1013 | if ($colon) { 1014 | $SERVER_NAME = substr($SERVER_NAME, 0, $colon); 1015 | } 1016 | if ($SERVER_PORT == 80) { 1017 | $SERVER_PORT = ''; 1018 | } else { 1019 | $SERVER_PORT = ':' . $SERVER_PORT; 1020 | } 1021 | if(false == $namespace) { 1022 | $namespace = "http://$SERVER_NAME/soap/$serviceName"; 1023 | } 1024 | 1025 | if(false == $endpoint) { 1026 | if ($HTTPS == '1' || $HTTPS == 'on') { 1027 | $SCHEME = 'https'; 1028 | } else { 1029 | $SCHEME = 'http'; 1030 | } 1031 | $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; 1032 | } 1033 | 1034 | if(false == $schemaTargetNamespace) { 1035 | $schemaTargetNamespace = $namespace; 1036 | } 1037 | 1038 | $this->wsdl = new wsdl; 1039 | $this->wsdl->serviceName = $serviceName; 1040 | $this->wsdl->endpoint = $endpoint; 1041 | $this->wsdl->namespaces['tns'] = $namespace; 1042 | $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; 1043 | $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; 1044 | if ($schemaTargetNamespace != $namespace) { 1045 | $this->wsdl->namespaces['types'] = $schemaTargetNamespace; 1046 | } 1047 | $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); 1048 | if ($style == 'document') { 1049 | $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; 1050 | } 1051 | $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; 1052 | $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); 1053 | $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); 1054 | $this->wsdl->bindings[$serviceName.'Binding'] = array( 1055 | 'name'=>$serviceName.'Binding', 1056 | 'style'=>$style, 1057 | 'transport'=>$transport, 1058 | 'portType'=>$serviceName.'PortType'); 1059 | $this->wsdl->ports[$serviceName.'Port'] = array( 1060 | 'binding'=>$serviceName.'Binding', 1061 | 'location'=>$endpoint, 1062 | 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); 1063 | } 1064 | } 1065 | 1066 | /** 1067 | * Backward compatibility 1068 | */ 1069 | class soap_server extends nusoap_server { 1070 | } 1071 | 1072 | 1073 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.soap_val.php: -------------------------------------------------------------------------------- 1 | 14 | * @version $Id: class.soap_val.php,v 1.11 2007/04/06 13:56:32 snichol Exp $ 15 | * @access public 16 | */ 17 | class soapval extends nusoap_base { 18 | /** 19 | * The XML element name 20 | * 21 | * @var string 22 | * @access private 23 | */ 24 | var $name; 25 | /** 26 | * The XML type name (string or false) 27 | * 28 | * @var mixed 29 | * @access private 30 | */ 31 | var $type; 32 | /** 33 | * The PHP value 34 | * 35 | * @var mixed 36 | * @access private 37 | */ 38 | var $value; 39 | /** 40 | * The XML element namespace (string or false) 41 | * 42 | * @var mixed 43 | * @access private 44 | */ 45 | var $element_ns; 46 | /** 47 | * The XML type namespace (string or false) 48 | * 49 | * @var mixed 50 | * @access private 51 | */ 52 | var $type_ns; 53 | /** 54 | * The XML element attributes (array or false) 55 | * 56 | * @var mixed 57 | * @access private 58 | */ 59 | var $attributes; 60 | 61 | /** 62 | * constructor 63 | * 64 | * @param string $name optional name 65 | * @param mixed $type optional type name 66 | * @param mixed $value optional value 67 | * @param mixed $element_ns optional namespace of value 68 | * @param mixed $type_ns optional namespace of type 69 | * @param mixed $attributes associative array of attributes to add to element serialization 70 | * @access public 71 | */ 72 | function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { 73 | parent::nusoap_base(); 74 | $this->name = $name; 75 | $this->type = $type; 76 | $this->value = $value; 77 | $this->element_ns = $element_ns; 78 | $this->type_ns = $type_ns; 79 | $this->attributes = $attributes; 80 | } 81 | 82 | /** 83 | * return serialized value 84 | * 85 | * @param string $use The WSDL use value (encoded|literal) 86 | * @return string XML data 87 | * @access public 88 | */ 89 | function serialize($use='encoded') { 90 | return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); 91 | } 92 | 93 | /** 94 | * decodes a soapval object into a PHP native type 95 | * 96 | * @return mixed 97 | * @access public 98 | */ 99 | function decode(){ 100 | return $this->value; 101 | } 102 | } 103 | 104 | 105 | 106 | 107 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.soapclient.php: -------------------------------------------------------------------------------- 1 | call( string methodname [ ,array parameters] ); 17 | * 18 | * // bye bye client 19 | * unset($soapclient); 20 | * 21 | * @author Dietrich Ayala 22 | * @author Scott Nichol 23 | * @version $Id: class.soapclient.php,v 1.64 2007/10/22 01:15:17 snichol Exp $ 24 | * @access public 25 | */ 26 | class nusoap_client extends nusoap_base { 27 | 28 | var $username = ''; // Username for HTTP authentication 29 | var $password = ''; // Password for HTTP authentication 30 | var $authtype = ''; // Type of HTTP authentication 31 | var $certRequest = array(); // Certificate for HTTP SSL authentication 32 | var $requestHeaders = false; // SOAP headers in request (text) 33 | var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) 34 | var $responseHeader = NULL; // SOAP Header from response (parsed) 35 | var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) 36 | var $endpoint; 37 | var $forceEndpoint = ''; // overrides WSDL endpoint 38 | var $proxyhost = ''; 39 | var $proxyport = ''; 40 | var $proxyusername = ''; 41 | var $proxypassword = ''; 42 | var $xml_encoding = ''; // character set encoding of incoming (response) messages 43 | var $http_encoding = false; 44 | var $timeout = 0; // HTTP connection timeout 45 | var $response_timeout = 30; // HTTP response timeout 46 | var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error 47 | var $persistentConnection = false; 48 | var $defaultRpcParams = false; // This is no longer used 49 | var $request = ''; // HTTP request 50 | var $response = ''; // HTTP response 51 | var $responseData = ''; // SOAP payload of response 52 | var $cookies = array(); // Cookies from response or for request 53 | var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() 54 | var $operations = array(); // WSDL operations, empty for WSDL initialization error 55 | var $curl_options = array(); // User-specified cURL options 56 | var $bindingType = ''; // WSDL operation binding type 57 | var $use_curl = false; // whether to always try to use cURL 58 | 59 | /* 60 | * fault related variables 61 | */ 62 | /** 63 | * @var fault 64 | * @access public 65 | */ 66 | var $fault; 67 | /** 68 | * @var faultcode 69 | * @access public 70 | */ 71 | var $faultcode; 72 | /** 73 | * @var faultstring 74 | * @access public 75 | */ 76 | var $faultstring; 77 | /** 78 | * @var faultdetail 79 | * @access public 80 | */ 81 | var $faultdetail; 82 | 83 | /** 84 | * constructor 85 | * 86 | * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) 87 | * @param bool $wsdl optional, set to true if using WSDL 88 | * @param int $portName optional portName in WSDL document 89 | * @param string $proxyhost 90 | * @param string $proxyport 91 | * @param string $proxyusername 92 | * @param string $proxypassword 93 | * @param integer $timeout set the connection timeout 94 | * @param integer $response_timeout set the response timeout 95 | * @access public 96 | */ 97 | function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ 98 | parent::nusoap_base(); 99 | $this->endpoint = $endpoint; 100 | $this->proxyhost = $proxyhost; 101 | $this->proxyport = $proxyport; 102 | $this->proxyusername = $proxyusername; 103 | $this->proxypassword = $proxypassword; 104 | $this->timeout = $timeout; 105 | $this->response_timeout = $response_timeout; 106 | 107 | $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 108 | $this->appendDebug('endpoint=' . $this->varDump($endpoint)); 109 | 110 | // make values 111 | if($wsdl){ 112 | if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { 113 | $this->wsdl = $endpoint; 114 | $this->endpoint = $this->wsdl->wsdl; 115 | $this->wsdlFile = $this->endpoint; 116 | $this->debug('existing wsdl instance created from ' . $this->endpoint); 117 | $this->checkWSDL(); 118 | } else { 119 | $this->wsdlFile = $this->endpoint; 120 | $this->wsdl = null; 121 | $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); 122 | } 123 | $this->endpointType = 'wsdl'; 124 | } else { 125 | $this->debug("instantiate SOAP with endpoint at $endpoint"); 126 | $this->endpointType = 'soap'; 127 | } 128 | } 129 | 130 | /** 131 | * calls method, returns PHP native type 132 | * 133 | * @param string $operation SOAP server URL or path 134 | * @param mixed $params An array, associative or simple, of the parameters 135 | * for the method call, or a string that is the XML 136 | * for the call. For rpc style, this call will 137 | * wrap the XML in a tag named after the method, as 138 | * well as the SOAP Envelope and Body. For document 139 | * style, this will only wrap with the Envelope and Body. 140 | * IMPORTANT: when using an array with document style, 141 | * in which case there 142 | * is really one parameter, the root of the fragment 143 | * used in the call, which encloses what programmers 144 | * normally think of parameters. A parameter array 145 | * *must* include the wrapper. 146 | * @param string $namespace optional method namespace (WSDL can override) 147 | * @param string $soapAction optional SOAPAction value (WSDL can override) 148 | * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array 149 | * @param boolean $rpcParams optional (no longer used) 150 | * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) 151 | * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) 152 | * @return mixed response from SOAP call 153 | * @access public 154 | */ 155 | function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ 156 | $this->operation = $operation; 157 | $this->fault = false; 158 | $this->setError(''); 159 | $this->request = ''; 160 | $this->response = ''; 161 | $this->responseData = ''; 162 | $this->faultstring = ''; 163 | $this->faultcode = ''; 164 | $this->opData = array(); 165 | 166 | $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); 167 | $this->appendDebug('params=' . $this->varDump($params)); 168 | $this->appendDebug('headers=' . $this->varDump($headers)); 169 | if ($headers) { 170 | $this->requestHeaders = $headers; 171 | } 172 | if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 173 | $this->loadWSDL(); 174 | if ($this->getError()) 175 | return false; 176 | } 177 | // serialize parameters 178 | if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ 179 | // use WSDL for operation 180 | $this->opData = $opData; 181 | $this->debug("found operation"); 182 | $this->appendDebug('opData=' . $this->varDump($opData)); 183 | if (isset($opData['soapAction'])) { 184 | $soapAction = $opData['soapAction']; 185 | } 186 | if (! $this->forceEndpoint) { 187 | $this->endpoint = $opData['endpoint']; 188 | } else { 189 | $this->endpoint = $this->forceEndpoint; 190 | } 191 | $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; 192 | $style = $opData['style']; 193 | $use = $opData['input']['use']; 194 | // add ns to ns array 195 | if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ 196 | $nsPrefix = 'ns' . rand(1000, 9999); 197 | $this->wsdl->namespaces[$nsPrefix] = $namespace; 198 | } 199 | $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); 200 | // serialize payload 201 | if (is_string($params)) { 202 | $this->debug("serializing param string for WSDL operation $operation"); 203 | $payload = $params; 204 | } elseif (is_array($params)) { 205 | $this->debug("serializing param array for WSDL operation $operation"); 206 | $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); 207 | } else { 208 | $this->debug('params must be array or string'); 209 | $this->setError('params must be array or string'); 210 | return false; 211 | } 212 | $usedNamespaces = $this->wsdl->usedNamespaces; 213 | if (isset($opData['input']['encodingStyle'])) { 214 | $encodingStyle = $opData['input']['encodingStyle']; 215 | } else { 216 | $encodingStyle = ''; 217 | } 218 | $this->appendDebug($this->wsdl->getDebug()); 219 | $this->wsdl->clearDebug(); 220 | if ($errstr = $this->wsdl->getError()) { 221 | $this->debug('got wsdl error: '.$errstr); 222 | $this->setError('wsdl error: '.$errstr); 223 | return false; 224 | } 225 | } elseif($this->endpointType == 'wsdl') { 226 | // operation not in WSDL 227 | $this->appendDebug($this->wsdl->getDebug()); 228 | $this->wsdl->clearDebug(); 229 | $this->setError( 'operation '.$operation.' not present.'); 230 | $this->debug("operation '$operation' not present."); 231 | return false; 232 | } else { 233 | // no WSDL 234 | //$this->namespaces['ns1'] = $namespace; 235 | $nsPrefix = 'ns' . rand(1000, 9999); 236 | // serialize 237 | $payload = ''; 238 | if (is_string($params)) { 239 | $this->debug("serializing param string for operation $operation"); 240 | $payload = $params; 241 | } elseif (is_array($params)) { 242 | $this->debug("serializing param array for operation $operation"); 243 | foreach($params as $k => $v){ 244 | $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); 245 | } 246 | } else { 247 | $this->debug('params must be array or string'); 248 | $this->setError('params must be array or string'); 249 | return false; 250 | } 251 | $usedNamespaces = array(); 252 | if ($use == 'encoded') { 253 | $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 254 | } else { 255 | $encodingStyle = ''; 256 | } 257 | } 258 | // wrap RPC calls with method element 259 | if ($style == 'rpc') { 260 | if ($use == 'literal') { 261 | $this->debug("wrapping RPC request with literal method element"); 262 | if ($namespace) { 263 | // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 264 | $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 265 | $payload . 266 | ""; 267 | } else { 268 | $payload = "<$operation>" . $payload . ""; 269 | } 270 | } else { 271 | $this->debug("wrapping RPC request with encoded method element"); 272 | if ($namespace) { 273 | $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 274 | $payload . 275 | ""; 276 | } else { 277 | $payload = "<$operation>" . 278 | $payload . 279 | ""; 280 | } 281 | } 282 | } 283 | // serialize envelope 284 | $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); 285 | $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); 286 | $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); 287 | // send 288 | $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); 289 | if($errstr = $this->getError()){ 290 | $this->debug('Error: '.$errstr); 291 | return false; 292 | } else { 293 | $this->return = $return; 294 | $this->debug('sent message successfully and got a(n) '.gettype($return)); 295 | $this->appendDebug('return=' . $this->varDump($return)); 296 | 297 | // fault? 298 | if(is_array($return) && isset($return['faultcode'])){ 299 | $this->debug('got fault'); 300 | $this->setError($return['faultcode'].': '.$return['faultstring']); 301 | $this->fault = true; 302 | foreach($return as $k => $v){ 303 | $this->$k = $v; 304 | $this->debug("$k = $v
"); 305 | } 306 | return $return; 307 | } elseif ($style == 'document') { 308 | // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), 309 | // we are only going to return the first part here...sorry about that 310 | return $return; 311 | } else { 312 | // array of return values 313 | if(is_array($return)){ 314 | // multiple 'out' parameters, which we return wrapped up 315 | // in the array 316 | if(sizeof($return) > 1){ 317 | return $return; 318 | } 319 | // single 'out' parameter (normally the return value) 320 | $return = array_shift($return); 321 | $this->debug('return shifted value: '); 322 | $this->appendDebug($this->varDump($return)); 323 | return $return; 324 | // nothing returned (ie, echoVoid) 325 | } else { 326 | return ""; 327 | } 328 | } 329 | } 330 | } 331 | 332 | /** 333 | * check WSDL passed as an instance or pulled from an endpoint 334 | * 335 | * @access private 336 | */ 337 | function checkWSDL() { 338 | $this->appendDebug($this->wsdl->getDebug()); 339 | $this->wsdl->clearDebug(); 340 | $this->debug('checkWSDL'); 341 | // catch errors 342 | if ($errstr = $this->wsdl->getError()) { 343 | $this->debug('got wsdl error: '.$errstr); 344 | $this->setError('wsdl error: '.$errstr); 345 | } elseif ($this->operations = $this->wsdl->getOperations('soap')) { 346 | $this->bindingType = 'soap'; 347 | $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 348 | } elseif ($this->operations = $this->wsdl->getOperations('soap12')) { 349 | $this->bindingType = 'soap12'; 350 | $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 351 | $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); 352 | } else { 353 | $this->debug('getOperations returned false'); 354 | $this->setError('no operations defined in the WSDL document!'); 355 | } 356 | } 357 | 358 | /** 359 | * instantiate wsdl object and parse wsdl file 360 | * 361 | * @access public 362 | */ 363 | function loadWSDL() { 364 | $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); 365 | $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); 366 | $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); 367 | $this->wsdl->fetchWSDL($this->wsdlFile); 368 | $this->checkWSDL(); 369 | } 370 | 371 | /** 372 | * get available data pertaining to an operation 373 | * 374 | * @param string $operation operation name 375 | * @return array array of data pertaining to the operation 376 | * @access public 377 | */ 378 | function getOperationData($operation){ 379 | if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 380 | $this->loadWSDL(); 381 | if ($this->getError()) 382 | return false; 383 | } 384 | if(isset($this->operations[$operation])){ 385 | return $this->operations[$operation]; 386 | } 387 | $this->debug("No data for operation: $operation"); 388 | } 389 | 390 | /** 391 | * send the SOAP message 392 | * 393 | * Note: if the operation has multiple return values 394 | * the return value of this method will be an array 395 | * of those values. 396 | * 397 | * @param string $msg a SOAPx4 soapmsg object 398 | * @param string $soapaction SOAPAction value 399 | * @param integer $timeout set connection timeout in seconds 400 | * @param integer $response_timeout set response timeout in seconds 401 | * @return mixed native PHP types. 402 | * @access private 403 | */ 404 | function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { 405 | $this->checkCookies(); 406 | // detect transport 407 | switch(true){ 408 | // http(s) 409 | case ereg('^http',$this->endpoint): 410 | $this->debug('transporting via HTTP'); 411 | if($this->persistentConnection == true && is_object($this->persistentConnection)){ 412 | $http =& $this->persistentConnection; 413 | } else { 414 | $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); 415 | if ($this->persistentConnection) { 416 | $http->usePersistentConnection(); 417 | } 418 | } 419 | $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); 420 | $http->setSOAPAction($soapaction); 421 | if($this->proxyhost && $this->proxyport){ 422 | $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 423 | } 424 | if($this->authtype != '') { 425 | $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 426 | } 427 | if($this->http_encoding != ''){ 428 | $http->setEncoding($this->http_encoding); 429 | } 430 | $this->debug('sending message, length='.strlen($msg)); 431 | if(ereg('^http:',$this->endpoint)){ 432 | //if(strpos($this->endpoint,'http:')){ 433 | $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); 434 | } elseif(ereg('^https',$this->endpoint)){ 435 | //} elseif(strpos($this->endpoint,'https:')){ 436 | //if(phpversion() == '4.3.0-dev'){ 437 | //$response = $http->send($msg,$timeout,$response_timeout); 438 | //$this->request = $http->outgoing_payload; 439 | //$this->response = $http->incoming_payload; 440 | //} else 441 | $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); 442 | } else { 443 | $this->setError('no http/s in endpoint url'); 444 | } 445 | $this->request = $http->outgoing_payload; 446 | $this->response = $http->incoming_payload; 447 | $this->appendDebug($http->getDebug()); 448 | $this->UpdateCookies($http->incoming_cookies); 449 | 450 | // save transport object if using persistent connections 451 | if ($this->persistentConnection) { 452 | $http->clearDebug(); 453 | if (!is_object($this->persistentConnection)) { 454 | $this->persistentConnection = $http; 455 | } 456 | } 457 | 458 | if($err = $http->getError()){ 459 | $this->setError('HTTP Error: '.$err); 460 | return false; 461 | } elseif($this->getError()){ 462 | return false; 463 | } else { 464 | $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); 465 | return $this->parseResponse($http->incoming_headers, $this->responseData); 466 | } 467 | break; 468 | default: 469 | $this->setError('no transport found, or selected transport is not yet supported!'); 470 | return false; 471 | break; 472 | } 473 | } 474 | 475 | /** 476 | * processes SOAP message returned from server 477 | * 478 | * @param array $headers The HTTP headers 479 | * @param string $data unprocessed response data from server 480 | * @return mixed value of the message, decoded into a PHP type 481 | * @access private 482 | */ 483 | function parseResponse($headers, $data) { 484 | $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); 485 | $this->appendDebug($this->varDump($headers)); 486 | if (!strstr($headers['content-type'], 'text/xml')) { 487 | $this->setError('Response not of type text/xml: ' . $headers['content-type']); 488 | return false; 489 | } 490 | if (strpos($headers['content-type'], '=')) { 491 | $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 492 | $this->debug('Got response encoding: ' . $enc); 493 | if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 494 | $this->xml_encoding = strtoupper($enc); 495 | } else { 496 | $this->xml_encoding = 'US-ASCII'; 497 | } 498 | } else { 499 | // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 500 | $this->xml_encoding = 'ISO-8859-1'; 501 | } 502 | $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 503 | $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); 504 | // add parser debug data to our debug 505 | $this->appendDebug($parser->getDebug()); 506 | // if parse errors 507 | if($errstr = $parser->getError()){ 508 | $this->setError( $errstr); 509 | // destroy the parser object 510 | unset($parser); 511 | return false; 512 | } else { 513 | // get SOAP headers 514 | $this->responseHeaders = $parser->getHeaders(); 515 | // get SOAP headers 516 | $this->responseHeader = $parser->get_soapheader(); 517 | // get decoded message 518 | $return = $parser->get_soapbody(); 519 | // add document for doclit support 520 | $this->document = $parser->document; 521 | // destroy the parser object 522 | unset($parser); 523 | // return decode message 524 | return $return; 525 | } 526 | } 527 | 528 | /** 529 | * sets user-specified cURL options 530 | * 531 | * @param mixed $option The cURL option (always integer?) 532 | * @param mixed $value The cURL option value 533 | * @access public 534 | */ 535 | function setCurlOption($option, $value) { 536 | $this->debug("setCurlOption option=$option, value="); 537 | $this->appendDebug($this->varDump($value)); 538 | $this->curl_options[$option] = $value; 539 | } 540 | 541 | /** 542 | * sets the SOAP endpoint, which can override WSDL 543 | * 544 | * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override 545 | * @access public 546 | */ 547 | function setEndpoint($endpoint) { 548 | $this->debug("setEndpoint(\"$endpoint\")"); 549 | $this->forceEndpoint = $endpoint; 550 | } 551 | 552 | /** 553 | * set the SOAP headers 554 | * 555 | * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers 556 | * @access public 557 | */ 558 | function setHeaders($headers){ 559 | $this->debug("setHeaders headers="); 560 | $this->appendDebug($this->varDump($headers)); 561 | $this->requestHeaders = $headers; 562 | } 563 | 564 | /** 565 | * get the SOAP response headers (namespace resolution incomplete) 566 | * 567 | * @return string 568 | * @access public 569 | */ 570 | function getHeaders(){ 571 | return $this->responseHeaders; 572 | } 573 | 574 | /** 575 | * get the SOAP response Header (parsed) 576 | * 577 | * @return mixed 578 | * @access public 579 | */ 580 | function getHeader(){ 581 | return $this->responseHeader; 582 | } 583 | 584 | /** 585 | * set proxy info here 586 | * 587 | * @param string $proxyhost 588 | * @param string $proxyport 589 | * @param string $proxyusername 590 | * @param string $proxypassword 591 | * @access public 592 | */ 593 | function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 594 | $this->proxyhost = $proxyhost; 595 | $this->proxyport = $proxyport; 596 | $this->proxyusername = $proxyusername; 597 | $this->proxypassword = $proxypassword; 598 | } 599 | 600 | /** 601 | * if authenticating, set user credentials here 602 | * 603 | * @param string $username 604 | * @param string $password 605 | * @param string $authtype (basic|digest|certificate|ntlm) 606 | * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) 607 | * @access public 608 | */ 609 | function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 610 | $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 611 | $this->appendDebug($this->varDump($certRequest)); 612 | $this->username = $username; 613 | $this->password = $password; 614 | $this->authtype = $authtype; 615 | $this->certRequest = $certRequest; 616 | } 617 | 618 | /** 619 | * use HTTP encoding 620 | * 621 | * @param string $enc HTTP encoding 622 | * @access public 623 | */ 624 | function setHTTPEncoding($enc='gzip, deflate'){ 625 | $this->debug("setHTTPEncoding(\"$enc\")"); 626 | $this->http_encoding = $enc; 627 | } 628 | 629 | /** 630 | * Set whether to try to use cURL connections if possible 631 | * 632 | * @param boolean $use Whether to try to use cURL 633 | * @access public 634 | */ 635 | function setUseCURL($use) { 636 | $this->debug("setUseCURL($use)"); 637 | $this->use_curl = $use; 638 | } 639 | 640 | /** 641 | * use HTTP persistent connections if possible 642 | * 643 | * @access public 644 | */ 645 | function useHTTPPersistentConnection(){ 646 | $this->debug("useHTTPPersistentConnection"); 647 | $this->persistentConnection = true; 648 | } 649 | 650 | /** 651 | * gets the default RPC parameter setting. 652 | * If true, default is that call params are like RPC even for document style. 653 | * Each call() can override this value. 654 | * 655 | * This is no longer used. 656 | * 657 | * @return boolean 658 | * @access public 659 | * @deprecated 660 | */ 661 | function getDefaultRpcParams() { 662 | return $this->defaultRpcParams; 663 | } 664 | 665 | /** 666 | * sets the default RPC parameter setting. 667 | * If true, default is that call params are like RPC even for document style 668 | * Each call() can override this value. 669 | * 670 | * This is no longer used. 671 | * 672 | * @param boolean $rpcParams 673 | * @access public 674 | * @deprecated 675 | */ 676 | function setDefaultRpcParams($rpcParams) { 677 | $this->defaultRpcParams = $rpcParams; 678 | } 679 | 680 | /** 681 | * dynamically creates an instance of a proxy class, 682 | * allowing user to directly call methods from wsdl 683 | * 684 | * @return object soap_proxy object 685 | * @access public 686 | */ 687 | function getProxy() { 688 | $r = rand(); 689 | $evalStr = $this->_getProxyClassCode($r); 690 | //$this->debug("proxy class: $evalStr"); 691 | if ($this->getError()) { 692 | $this->debug("Error from _getProxyClassCode, so return NULL"); 693 | return null; 694 | } 695 | // eval the class 696 | eval($evalStr); 697 | // instantiate proxy object 698 | eval("\$proxy = new nusoap_proxy_$r('');"); 699 | // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice 700 | $proxy->endpointType = 'wsdl'; 701 | $proxy->wsdlFile = $this->wsdlFile; 702 | $proxy->wsdl = $this->wsdl; 703 | $proxy->operations = $this->operations; 704 | $proxy->defaultRpcParams = $this->defaultRpcParams; 705 | // transfer other state 706 | $proxy->soap_defencoding = $this->soap_defencoding; 707 | $proxy->username = $this->username; 708 | $proxy->password = $this->password; 709 | $proxy->authtype = $this->authtype; 710 | $proxy->certRequest = $this->certRequest; 711 | $proxy->requestHeaders = $this->requestHeaders; 712 | $proxy->endpoint = $this->endpoint; 713 | $proxy->forceEndpoint = $this->forceEndpoint; 714 | $proxy->proxyhost = $this->proxyhost; 715 | $proxy->proxyport = $this->proxyport; 716 | $proxy->proxyusername = $this->proxyusername; 717 | $proxy->proxypassword = $this->proxypassword; 718 | $proxy->http_encoding = $this->http_encoding; 719 | $proxy->timeout = $this->timeout; 720 | $proxy->response_timeout = $this->response_timeout; 721 | $proxy->persistentConnection = &$this->persistentConnection; 722 | $proxy->decode_utf8 = $this->decode_utf8; 723 | $proxy->curl_options = $this->curl_options; 724 | $proxy->bindingType = $this->bindingType; 725 | $proxy->use_curl = $this->use_curl; 726 | return $proxy; 727 | } 728 | 729 | /** 730 | * dynamically creates proxy class code 731 | * 732 | * @return string PHP/NuSOAP code for the proxy class 733 | * @access private 734 | */ 735 | function _getProxyClassCode($r) { 736 | $this->debug("in getProxy endpointType=$this->endpointType"); 737 | $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); 738 | if ($this->endpointType != 'wsdl') { 739 | $evalStr = 'A proxy can only be created for a WSDL client'; 740 | $this->setError($evalStr); 741 | $evalStr = "echo \"$evalStr\";"; 742 | return $evalStr; 743 | } 744 | if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 745 | $this->loadWSDL(); 746 | if ($this->getError()) { 747 | return "echo \"" . $this->getError() . "\";"; 748 | } 749 | } 750 | $evalStr = ''; 751 | foreach ($this->operations as $operation => $opData) { 752 | if ($operation != '') { 753 | // create param string and param comment string 754 | if (sizeof($opData['input']['parts']) > 0) { 755 | $paramStr = ''; 756 | $paramArrayStr = ''; 757 | $paramCommentStr = ''; 758 | foreach ($opData['input']['parts'] as $name => $type) { 759 | $paramStr .= "\$$name, "; 760 | $paramArrayStr .= "'$name' => \$$name, "; 761 | $paramCommentStr .= "$type \$$name, "; 762 | } 763 | $paramStr = substr($paramStr, 0, strlen($paramStr)-2); 764 | $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); 765 | $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); 766 | } else { 767 | $paramStr = ''; 768 | $paramArrayStr = ''; 769 | $paramCommentStr = 'void'; 770 | } 771 | $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; 772 | $evalStr .= "// $paramCommentStr 773 | function " . str_replace('.', '__', $operation) . "($paramStr) { 774 | \$params = array($paramArrayStr); 775 | return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); 776 | } 777 | "; 778 | unset($paramStr); 779 | unset($paramCommentStr); 780 | } 781 | } 782 | $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { 783 | '.$evalStr.' 784 | }'; 785 | return $evalStr; 786 | } 787 | 788 | /** 789 | * dynamically creates proxy class code 790 | * 791 | * @return string PHP/NuSOAP code for the proxy class 792 | * @access public 793 | */ 794 | function getProxyClassCode() { 795 | $r = rand(); 796 | return $this->_getProxyClassCode($r); 797 | } 798 | 799 | /** 800 | * gets the HTTP body for the current request. 801 | * 802 | * @param string $soapmsg The SOAP payload 803 | * @return string The HTTP body, which includes the SOAP payload 804 | * @access private 805 | */ 806 | function getHTTPBody($soapmsg) { 807 | return $soapmsg; 808 | } 809 | 810 | /** 811 | * gets the HTTP content type for the current request. 812 | * 813 | * Note: getHTTPBody must be called before this. 814 | * 815 | * @return string the HTTP content type for the current request. 816 | * @access private 817 | */ 818 | function getHTTPContentType() { 819 | return 'text/xml'; 820 | } 821 | 822 | /** 823 | * gets the HTTP content type charset for the current request. 824 | * returns false for non-text content types. 825 | * 826 | * Note: getHTTPBody must be called before this. 827 | * 828 | * @return string the HTTP content type charset for the current request. 829 | * @access private 830 | */ 831 | function getHTTPContentTypeCharset() { 832 | return $this->soap_defencoding; 833 | } 834 | 835 | /* 836 | * whether or not parser should decode utf8 element content 837 | * 838 | * @return always returns true 839 | * @access public 840 | */ 841 | function decodeUTF8($bool){ 842 | $this->decode_utf8 = $bool; 843 | return true; 844 | } 845 | 846 | /** 847 | * adds a new Cookie into $this->cookies array 848 | * 849 | * @param string $name Cookie Name 850 | * @param string $value Cookie Value 851 | * @return boolean if cookie-set was successful returns true, else false 852 | * @access public 853 | */ 854 | function setCookie($name, $value) { 855 | if (strlen($name) == 0) { 856 | return false; 857 | } 858 | $this->cookies[] = array('name' => $name, 'value' => $value); 859 | return true; 860 | } 861 | 862 | /** 863 | * gets all Cookies 864 | * 865 | * @return array with all internal cookies 866 | * @access public 867 | */ 868 | function getCookies() { 869 | return $this->cookies; 870 | } 871 | 872 | /** 873 | * checks all Cookies and delete those which are expired 874 | * 875 | * @return boolean always return true 876 | * @access private 877 | */ 878 | function checkCookies() { 879 | if (sizeof($this->cookies) == 0) { 880 | return true; 881 | } 882 | $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); 883 | $curr_cookies = $this->cookies; 884 | $this->cookies = array(); 885 | foreach ($curr_cookies as $cookie) { 886 | if (! is_array($cookie)) { 887 | $this->debug('Remove cookie that is not an array'); 888 | continue; 889 | } 890 | if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 891 | if (strtotime($cookie['expires']) > time()) { 892 | $this->cookies[] = $cookie; 893 | } else { 894 | $this->debug('Remove expired cookie ' . $cookie['name']); 895 | } 896 | } else { 897 | $this->cookies[] = $cookie; 898 | } 899 | } 900 | $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); 901 | return true; 902 | } 903 | 904 | /** 905 | * updates the current cookies with a new set 906 | * 907 | * @param array $cookies new cookies with which to update current ones 908 | * @return boolean always return true 909 | * @access private 910 | */ 911 | function UpdateCookies($cookies) { 912 | if (sizeof($this->cookies) == 0) { 913 | // no existing cookies: take whatever is new 914 | if (sizeof($cookies) > 0) { 915 | $this->debug('Setting new cookie(s)'); 916 | $this->cookies = $cookies; 917 | } 918 | return true; 919 | } 920 | if (sizeof($cookies) == 0) { 921 | // no new cookies: keep what we've got 922 | return true; 923 | } 924 | // merge 925 | foreach ($cookies as $newCookie) { 926 | if (!is_array($newCookie)) { 927 | continue; 928 | } 929 | if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { 930 | continue; 931 | } 932 | $newName = $newCookie['name']; 933 | 934 | $found = false; 935 | for ($i = 0; $i < count($this->cookies); $i++) { 936 | $cookie = $this->cookies[$i]; 937 | if (!is_array($cookie)) { 938 | continue; 939 | } 940 | if (!isset($cookie['name'])) { 941 | continue; 942 | } 943 | if ($newName != $cookie['name']) { 944 | continue; 945 | } 946 | $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; 947 | $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; 948 | if ($newDomain != $domain) { 949 | continue; 950 | } 951 | $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; 952 | $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; 953 | if ($newPath != $path) { 954 | continue; 955 | } 956 | $this->cookies[$i] = $newCookie; 957 | $found = true; 958 | $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); 959 | break; 960 | } 961 | if (! $found) { 962 | $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); 963 | $this->cookies[] = $newCookie; 964 | } 965 | } 966 | return true; 967 | } 968 | } 969 | 970 | if (!extension_loaded('soap')) { 971 | /** 972 | * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. 973 | */ 974 | class soapclient extends nusoap_client { 975 | } 976 | } 977 | ?> 978 | -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.wsdlcache.php: -------------------------------------------------------------------------------- 1 | 14 | * @author Ingo Fischer 15 | * @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $ 16 | * @access public 17 | */ 18 | class nusoap_wsdlcache { 19 | /** 20 | * @var resource 21 | * @access private 22 | */ 23 | var $fplock; 24 | /** 25 | * @var integer 26 | * @access private 27 | */ 28 | var $cache_lifetime; 29 | /** 30 | * @var string 31 | * @access private 32 | */ 33 | var $cache_dir; 34 | /** 35 | * @var string 36 | * @access public 37 | */ 38 | var $debug_str = ''; 39 | 40 | /** 41 | * constructor 42 | * 43 | * @param string $cache_dir directory for cache-files 44 | * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited 45 | * @access public 46 | */ 47 | function nusoap_wsdlcache($cache_dir='.', $cache_lifetime=0) { 48 | $this->fplock = array(); 49 | $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; 50 | $this->cache_lifetime = $cache_lifetime; 51 | } 52 | 53 | /** 54 | * creates the filename used to cache a wsdl instance 55 | * 56 | * @param string $wsdl The URL of the wsdl instance 57 | * @return string The filename used to cache the instance 58 | * @access private 59 | */ 60 | function createFilename($wsdl) { 61 | return $this->cache_dir.'/wsdlcache-' . md5($wsdl); 62 | } 63 | 64 | /** 65 | * adds debug data to the class level debug string 66 | * 67 | * @param string $string debug data 68 | * @access private 69 | */ 70 | function debug($string){ 71 | $this->debug_str .= get_class($this).": $string\n"; 72 | } 73 | 74 | /** 75 | * gets a wsdl instance from the cache 76 | * 77 | * @param string $wsdl The URL of the wsdl instance 78 | * @return object wsdl The cached wsdl instance, null if the instance is not in the cache 79 | * @access public 80 | */ 81 | function get($wsdl) { 82 | $filename = $this->createFilename($wsdl); 83 | if ($this->obtainMutex($filename, "r")) { 84 | // check for expired WSDL that must be removed from the cache 85 | if ($this->cache_lifetime > 0) { 86 | if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { 87 | unlink($filename); 88 | $this->debug("Expired $wsdl ($filename) from cache"); 89 | $this->releaseMutex($filename); 90 | return null; 91 | } 92 | } 93 | // see what there is to return 94 | if (!file_exists($filename)) { 95 | $this->debug("$wsdl ($filename) not in cache (1)"); 96 | $this->releaseMutex($filename); 97 | return null; 98 | } 99 | $fp = @fopen($filename, "r"); 100 | if ($fp) { 101 | $s = implode("", @file($filename)); 102 | fclose($fp); 103 | $this->debug("Got $wsdl ($filename) from cache"); 104 | } else { 105 | $s = null; 106 | $this->debug("$wsdl ($filename) not in cache (2)"); 107 | } 108 | $this->releaseMutex($filename); 109 | return (!is_null($s)) ? unserialize($s) : null; 110 | } else { 111 | $this->debug("Unable to obtain mutex for $filename in get"); 112 | } 113 | return null; 114 | } 115 | 116 | /** 117 | * obtains the local mutex 118 | * 119 | * @param string $filename The Filename of the Cache to lock 120 | * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode 121 | * @return boolean Lock successfully obtained ?! 122 | * @access private 123 | */ 124 | function obtainMutex($filename, $mode) { 125 | if (isset($this->fplock[md5($filename)])) { 126 | $this->debug("Lock for $filename already exists"); 127 | return false; 128 | } 129 | $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); 130 | if ($mode == "r") { 131 | return flock($this->fplock[md5($filename)], LOCK_SH); 132 | } else { 133 | return flock($this->fplock[md5($filename)], LOCK_EX); 134 | } 135 | } 136 | 137 | /** 138 | * adds a wsdl instance to the cache 139 | * 140 | * @param object wsdl $wsdl_instance The wsdl instance to add 141 | * @return boolean WSDL successfully cached 142 | * @access public 143 | */ 144 | function put($wsdl_instance) { 145 | $filename = $this->createFilename($wsdl_instance->wsdl); 146 | $s = serialize($wsdl_instance); 147 | if ($this->obtainMutex($filename, "w")) { 148 | $fp = fopen($filename, "w"); 149 | if (! $fp) { 150 | $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); 151 | $this->releaseMutex($filename); 152 | return false; 153 | } 154 | fputs($fp, $s); 155 | fclose($fp); 156 | $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); 157 | $this->releaseMutex($filename); 158 | return true; 159 | } else { 160 | $this->debug("Unable to obtain mutex for $filename in put"); 161 | } 162 | return false; 163 | } 164 | 165 | /** 166 | * releases the local mutex 167 | * 168 | * @param string $filename The Filename of the Cache to lock 169 | * @return boolean Lock successfully released 170 | * @access private 171 | */ 172 | function releaseMutex($filename) { 173 | $ret = flock($this->fplock[md5($filename)], LOCK_UN); 174 | fclose($this->fplock[md5($filename)]); 175 | unset($this->fplock[md5($filename)]); 176 | if (! $ret) { 177 | $this->debug("Not able to release lock for $filename"); 178 | } 179 | return $ret; 180 | } 181 | 182 | /** 183 | * removes a wsdl instance from the cache 184 | * 185 | * @param string $wsdl The URL of the wsdl instance 186 | * @return boolean Whether there was an instance to remove 187 | * @access public 188 | */ 189 | function remove($wsdl) { 190 | $filename = $this->createFilename($wsdl); 191 | if (!file_exists($filename)) { 192 | $this->debug("$wsdl ($filename) not in cache to be removed"); 193 | return false; 194 | } 195 | // ignore errors obtaining mutex 196 | $this->obtainMutex($filename, "w"); 197 | $ret = unlink($filename); 198 | $this->debug("Removed ($ret) $wsdl ($filename) from cache"); 199 | $this->releaseMutex($filename); 200 | return $ret; 201 | } 202 | } 203 | 204 | /** 205 | * For backward compatibility 206 | */ 207 | class wsdlcache extends nusoap_wsdlcache { 208 | } 209 | ?> 210 | -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/class.xmlschema.php: -------------------------------------------------------------------------------- 1 | 11 | * @author Scott Nichol 12 | * @version $Id: class.xmlschema.php,v 1.49 2007/11/06 14:17:53 snichol Exp $ 13 | * @access public 14 | */ 15 | class nusoap_xmlschema extends nusoap_base { 16 | 17 | // files 18 | var $schema = ''; 19 | var $xml = ''; 20 | // namespaces 21 | var $enclosingNamespaces; 22 | // schema info 23 | var $schemaInfo = array(); 24 | var $schemaTargetNamespace = ''; 25 | // types, elements, attributes defined by the schema 26 | var $attributes = array(); 27 | var $complexTypes = array(); 28 | var $complexTypeStack = array(); 29 | var $currentComplexType = null; 30 | var $elements = array(); 31 | var $elementStack = array(); 32 | var $currentElement = null; 33 | var $simpleTypes = array(); 34 | var $simpleTypeStack = array(); 35 | var $currentSimpleType = null; 36 | // imports 37 | var $imports = array(); 38 | // parser vars 39 | var $parser; 40 | var $position = 0; 41 | var $depth = 0; 42 | var $depth_array = array(); 43 | var $message = array(); 44 | var $defaultNamespace = array(); 45 | 46 | /** 47 | * constructor 48 | * 49 | * @param string $schema schema document URI 50 | * @param string $xml xml document URI 51 | * @param string $namespaces namespaces defined in enclosing XML 52 | * @access public 53 | */ 54 | function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ 55 | parent::nusoap_base(); 56 | $this->debug('nusoap_xmlschema class instantiated, inside constructor'); 57 | // files 58 | $this->schema = $schema; 59 | $this->xml = $xml; 60 | 61 | // namespaces 62 | $this->enclosingNamespaces = $namespaces; 63 | $this->namespaces = array_merge($this->namespaces, $namespaces); 64 | 65 | // parse schema file 66 | if($schema != ''){ 67 | $this->debug('initial schema file: '.$schema); 68 | $this->parseFile($schema, 'schema'); 69 | } 70 | 71 | // parse xml file 72 | if($xml != ''){ 73 | $this->debug('initial xml file: '.$xml); 74 | $this->parseFile($xml, 'xml'); 75 | } 76 | 77 | } 78 | 79 | /** 80 | * parse an XML file 81 | * 82 | * @param string $xml path/URL to XML file 83 | * @param string $type (schema | xml) 84 | * @return boolean 85 | * @access public 86 | */ 87 | function parseFile($xml,$type){ 88 | // parse xml file 89 | if($xml != ""){ 90 | $xmlStr = @join("",@file($xml)); 91 | if($xmlStr == ""){ 92 | $msg = 'Error reading XML from '.$xml; 93 | $this->setError($msg); 94 | $this->debug($msg); 95 | return false; 96 | } else { 97 | $this->debug("parsing $xml"); 98 | $this->parseString($xmlStr,$type); 99 | $this->debug("done parsing $xml"); 100 | return true; 101 | } 102 | } 103 | return false; 104 | } 105 | 106 | /** 107 | * parse an XML string 108 | * 109 | * @param string $xml path or URL 110 | * @param string $type (schema|xml) 111 | * @access private 112 | */ 113 | function parseString($xml,$type){ 114 | // parse xml string 115 | if($xml != ""){ 116 | 117 | // Create an XML parser. 118 | $this->parser = xml_parser_create(); 119 | // Set the options for parsing the XML data. 120 | xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 121 | 122 | // Set the object for the parser. 123 | xml_set_object($this->parser, $this); 124 | 125 | // Set the element handlers for the parser. 126 | if($type == "schema"){ 127 | xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); 128 | xml_set_character_data_handler($this->parser,'schemaCharacterData'); 129 | } elseif($type == "xml"){ 130 | xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); 131 | xml_set_character_data_handler($this->parser,'xmlCharacterData'); 132 | } 133 | 134 | // Parse the XML file. 135 | if(!xml_parse($this->parser,$xml,true)){ 136 | // Display an error message. 137 | $errstr = sprintf('XML error parsing XML schema on line %d: %s', 138 | xml_get_current_line_number($this->parser), 139 | xml_error_string(xml_get_error_code($this->parser)) 140 | ); 141 | $this->debug($errstr); 142 | $this->debug("XML payload:\n" . $xml); 143 | $this->setError($errstr); 144 | } 145 | 146 | xml_parser_free($this->parser); 147 | } else{ 148 | $this->debug('no xml passed to parseString()!!'); 149 | $this->setError('no xml passed to parseString()!!'); 150 | } 151 | } 152 | 153 | /** 154 | * gets a type name for an unnamed type 155 | * 156 | * @param string Element name 157 | * @return string A type name for an unnamed type 158 | * @access private 159 | */ 160 | function CreateTypeName($ename) { 161 | $scope = ''; 162 | for ($i = 0; $i < count($this->complexTypeStack); $i++) { 163 | $scope .= $this->complexTypeStack[$i] . '_'; 164 | } 165 | return $scope . $ename . '_ContainedType'; 166 | } 167 | 168 | /** 169 | * start-element handler 170 | * 171 | * @param string $parser XML parser object 172 | * @param string $name element name 173 | * @param string $attrs associative array of attributes 174 | * @access private 175 | */ 176 | function schemaStartElement($parser, $name, $attrs) { 177 | 178 | // position in the total number of elements, starting from 0 179 | $pos = $this->position++; 180 | $depth = $this->depth++; 181 | // set self as current value for this depth 182 | $this->depth_array[$depth] = $pos; 183 | $this->message[$pos] = array('cdata' => ''); 184 | if ($depth > 0) { 185 | $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; 186 | } else { 187 | $this->defaultNamespace[$pos] = false; 188 | } 189 | 190 | // get element prefix 191 | if($prefix = $this->getPrefix($name)){ 192 | // get unqualified name 193 | $name = $this->getLocalPart($name); 194 | } else { 195 | $prefix = ''; 196 | } 197 | 198 | // loop thru attributes, expanding, and registering namespace declarations 199 | if(count($attrs) > 0){ 200 | foreach($attrs as $k => $v){ 201 | // if ns declarations, add to class level array of valid namespaces 202 | if(ereg("^xmlns",$k)){ 203 | //$this->xdebug("$k: $v"); 204 | //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); 205 | if($ns_prefix = substr(strrchr($k,':'),1)){ 206 | //$this->xdebug("Add namespace[$ns_prefix] = $v"); 207 | $this->namespaces[$ns_prefix] = $v; 208 | } else { 209 | $this->defaultNamespace[$pos] = $v; 210 | if (! $this->getPrefixFromNamespace($v)) { 211 | $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; 212 | } 213 | } 214 | if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ 215 | $this->XMLSchemaVersion = $v; 216 | $this->namespaces['xsi'] = $v.'-instance'; 217 | } 218 | } 219 | } 220 | foreach($attrs as $k => $v){ 221 | // expand each attribute 222 | $k = strpos($k,':') ? $this->expandQname($k) : $k; 223 | $v = strpos($v,':') ? $this->expandQname($v) : $v; 224 | $eAttrs[$k] = $v; 225 | } 226 | $attrs = $eAttrs; 227 | } else { 228 | $attrs = array(); 229 | } 230 | // find status, register data 231 | switch($name){ 232 | case 'all': // (optional) compositor content for a complexType 233 | case 'choice': 234 | case 'group': 235 | case 'sequence': 236 | //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); 237 | $this->complexTypes[$this->currentComplexType]['compositor'] = $name; 238 | //if($name == 'all' || $name == 'sequence'){ 239 | // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 240 | //} 241 | break; 242 | case 'attribute': // complexType attribute 243 | //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); 244 | $this->xdebug("parsing attribute:"); 245 | $this->appendDebug($this->varDump($attrs)); 246 | if (!isset($attrs['form'])) { 247 | $attrs['form'] = $this->schemaInfo['attributeFormDefault']; 248 | } 249 | if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 250 | $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 251 | if (!strpos($v, ':')) { 252 | // no namespace in arrayType attribute value... 253 | if ($this->defaultNamespace[$pos]) { 254 | // ...so use the default 255 | $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 256 | } 257 | } 258 | } 259 | if(isset($attrs['name'])){ 260 | $this->attributes[$attrs['name']] = $attrs; 261 | $aname = $attrs['name']; 262 | } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ 263 | if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 264 | $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 265 | } else { 266 | $aname = ''; 267 | } 268 | } elseif(isset($attrs['ref'])){ 269 | $aname = $attrs['ref']; 270 | $this->attributes[$attrs['ref']] = $attrs; 271 | } 272 | 273 | if($this->currentComplexType){ // This should *always* be 274 | $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; 275 | } 276 | // arrayType attribute 277 | if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ 278 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 279 | $prefix = $this->getPrefix($aname); 280 | if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ 281 | $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 282 | } else { 283 | $v = ''; 284 | } 285 | if(strpos($v,'[,]')){ 286 | $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; 287 | } 288 | $v = substr($v,0,strpos($v,'[')); // clip the [] 289 | if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ 290 | $v = $this->XMLSchemaVersion.':'.$v; 291 | } 292 | $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; 293 | } 294 | break; 295 | case 'complexContent': // (optional) content for a complexType 296 | break; 297 | case 'complexType': 298 | array_push($this->complexTypeStack, $this->currentComplexType); 299 | if(isset($attrs['name'])){ 300 | // TODO: what is the scope of named complexTypes that appear 301 | // nested within other c complexTypes? 302 | $this->xdebug('processing named complexType '.$attrs['name']); 303 | //$this->currentElement = false; 304 | $this->currentComplexType = $attrs['name']; 305 | $this->complexTypes[$this->currentComplexType] = $attrs; 306 | $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 307 | // This is for constructs like 308 | // 309 | // 310 | // 312 | // 313 | // 314 | if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 315 | $this->xdebug('complexType is unusual array'); 316 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 317 | } else { 318 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 319 | } 320 | } else { 321 | $name = $this->CreateTypeName($this->currentElement); 322 | $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); 323 | $this->currentComplexType = $name; 324 | //$this->currentElement = false; 325 | $this->complexTypes[$this->currentComplexType] = $attrs; 326 | $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 327 | // This is for constructs like 328 | // 329 | // 330 | // 332 | // 333 | // 334 | if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 335 | $this->xdebug('complexType is unusual array'); 336 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 337 | } else { 338 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 339 | } 340 | } 341 | break; 342 | case 'element': 343 | array_push($this->elementStack, $this->currentElement); 344 | if (!isset($attrs['form'])) { 345 | $attrs['form'] = $this->schemaInfo['elementFormDefault']; 346 | } 347 | if(isset($attrs['type'])){ 348 | $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); 349 | if (! $this->getPrefix($attrs['type'])) { 350 | if ($this->defaultNamespace[$pos]) { 351 | $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; 352 | $this->xdebug('used default namespace to make type ' . $attrs['type']); 353 | } 354 | } 355 | // This is for constructs like 356 | // 357 | // 358 | // 360 | // 361 | // 362 | if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { 363 | $this->xdebug('arrayType for unusual array is ' . $attrs['type']); 364 | $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; 365 | } 366 | $this->currentElement = $attrs['name']; 367 | $ename = $attrs['name']; 368 | } elseif(isset($attrs['ref'])){ 369 | $this->xdebug("processing element as ref to ".$attrs['ref']); 370 | $this->currentElement = "ref to ".$attrs['ref']; 371 | $ename = $this->getLocalPart($attrs['ref']); 372 | } else { 373 | $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); 374 | $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); 375 | $this->currentElement = $attrs['name']; 376 | $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; 377 | $ename = $attrs['name']; 378 | } 379 | if (isset($ename) && $this->currentComplexType) { 380 | $this->xdebug("add element $ename to complexType $this->currentComplexType"); 381 | $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; 382 | } elseif (!isset($attrs['ref'])) { 383 | $this->xdebug("add element $ename to elements array"); 384 | $this->elements[ $attrs['name'] ] = $attrs; 385 | $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 386 | } 387 | break; 388 | case 'enumeration': // restriction value list member 389 | $this->xdebug('enumeration ' . $attrs['value']); 390 | if ($this->currentSimpleType) { 391 | $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; 392 | } elseif ($this->currentComplexType) { 393 | $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; 394 | } 395 | break; 396 | case 'extension': // simpleContent or complexContent type extension 397 | $this->xdebug('extension ' . $attrs['base']); 398 | if ($this->currentComplexType) { 399 | $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; 400 | } 401 | break; 402 | case 'import': 403 | if (isset($attrs['schemaLocation'])) { 404 | //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); 405 | $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 406 | } else { 407 | //$this->xdebug('import namespace ' . $attrs['namespace']); 408 | $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 409 | if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 410 | $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 411 | } 412 | } 413 | break; 414 | case 'list': // simpleType value list 415 | break; 416 | case 'restriction': // simpleType, simpleContent or complexContent value restriction 417 | $this->xdebug('restriction ' . $attrs['base']); 418 | if($this->currentSimpleType){ 419 | $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; 420 | } elseif($this->currentComplexType){ 421 | $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; 422 | if(strstr($attrs['base'],':') == ':Array'){ 423 | $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 424 | } 425 | } 426 | break; 427 | case 'schema': 428 | $this->schemaInfo = $attrs; 429 | $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); 430 | if (isset($attrs['targetNamespace'])) { 431 | $this->schemaTargetNamespace = $attrs['targetNamespace']; 432 | } 433 | if (!isset($attrs['elementFormDefault'])) { 434 | $this->schemaInfo['elementFormDefault'] = 'unqualified'; 435 | } 436 | if (!isset($attrs['attributeFormDefault'])) { 437 | $this->schemaInfo['attributeFormDefault'] = 'unqualified'; 438 | } 439 | break; 440 | case 'simpleContent': // (optional) content for a complexType 441 | break; 442 | case 'simpleType': 443 | array_push($this->simpleTypeStack, $this->currentSimpleType); 444 | if(isset($attrs['name'])){ 445 | $this->xdebug("processing simpleType for name " . $attrs['name']); 446 | $this->currentSimpleType = $attrs['name']; 447 | $this->simpleTypes[ $attrs['name'] ] = $attrs; 448 | $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; 449 | $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; 450 | } else { 451 | $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); 452 | $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); 453 | $this->currentSimpleType = $name; 454 | //$this->currentElement = false; 455 | $this->simpleTypes[$this->currentSimpleType] = $attrs; 456 | $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; 457 | } 458 | break; 459 | case 'union': // simpleType type list 460 | break; 461 | default: 462 | //$this->xdebug("do not have anything to do for element $name"); 463 | } 464 | } 465 | 466 | /** 467 | * end-element handler 468 | * 469 | * @param string $parser XML parser object 470 | * @param string $name element name 471 | * @access private 472 | */ 473 | function schemaEndElement($parser, $name) { 474 | // bring depth down a notch 475 | $this->depth--; 476 | // position of current element is equal to the last value left in depth_array for my depth 477 | if(isset($this->depth_array[$this->depth])){ 478 | $pos = $this->depth_array[$this->depth]; 479 | } 480 | // get element prefix 481 | if ($prefix = $this->getPrefix($name)){ 482 | // get unqualified name 483 | $name = $this->getLocalPart($name); 484 | } else { 485 | $prefix = ''; 486 | } 487 | // move on... 488 | if($name == 'complexType'){ 489 | $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); 490 | $this->currentComplexType = array_pop($this->complexTypeStack); 491 | //$this->currentElement = false; 492 | } 493 | if($name == 'element'){ 494 | $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); 495 | $this->currentElement = array_pop($this->elementStack); 496 | } 497 | if($name == 'simpleType'){ 498 | $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); 499 | $this->currentSimpleType = array_pop($this->simpleTypeStack); 500 | } 501 | } 502 | 503 | /** 504 | * element content handler 505 | * 506 | * @param string $parser XML parser object 507 | * @param string $data element content 508 | * @access private 509 | */ 510 | function schemaCharacterData($parser, $data){ 511 | $pos = $this->depth_array[$this->depth - 1]; 512 | $this->message[$pos]['cdata'] .= $data; 513 | } 514 | 515 | /** 516 | * serialize the schema 517 | * 518 | * @access public 519 | */ 520 | function serializeSchema(){ 521 | 522 | $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); 523 | $xml = ''; 524 | // imports 525 | if (sizeof($this->imports) > 0) { 526 | foreach($this->imports as $ns => $list) { 527 | foreach ($list as $ii) { 528 | if ($ii['location'] != '') { 529 | $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; 530 | } else { 531 | $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; 532 | } 533 | } 534 | } 535 | } 536 | // complex types 537 | foreach($this->complexTypes as $typeName => $attrs){ 538 | $contentStr = ''; 539 | // serialize child elements 540 | if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ 541 | foreach($attrs['elements'] as $element => $eParts){ 542 | if(isset($eParts['ref'])){ 543 | $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; 544 | } else { 545 | $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; 546 | foreach ($eParts as $aName => $aValue) { 547 | // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable 548 | if ($aName != 'name' && $aName != 'type') { 549 | $contentStr .= " $aName=\"$aValue\""; 550 | } 551 | } 552 | $contentStr .= "/>\n"; 553 | } 554 | } 555 | // compositor wraps elements 556 | if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { 557 | $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; 558 | } 559 | } 560 | // attributes 561 | if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ 562 | foreach($attrs['attrs'] as $attr => $aParts){ 563 | $contentStr .= " <$schemaPrefix:attribute"; 564 | foreach ($aParts as $a => $v) { 565 | if ($a == 'ref' || $a == 'type') { 566 | $contentStr .= " $a=\"".$this->contractQName($v).'"'; 567 | } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { 568 | $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; 569 | $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; 570 | } else { 571 | $contentStr .= " $a=\"$v\""; 572 | } 573 | } 574 | $contentStr .= "/>\n"; 575 | } 576 | } 577 | // if restriction 578 | if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ 579 | $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; 580 | // complex or simple content 581 | if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ 582 | $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; 583 | } 584 | } 585 | // finalize complex type 586 | if($contentStr != ''){ 587 | $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; 588 | } else { 589 | $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; 590 | } 591 | $xml .= $contentStr; 592 | } 593 | // simple types 594 | if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ 595 | foreach($this->simpleTypes as $typeName => $eParts){ 596 | $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; 597 | if (isset($eParts['enumeration'])) { 598 | foreach ($eParts['enumeration'] as $e) { 599 | $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; 600 | } 601 | } 602 | $xml .= " \n "; 603 | } 604 | } 605 | // elements 606 | if(isset($this->elements) && count($this->elements) > 0){ 607 | foreach($this->elements as $element => $eParts){ 608 | $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; 609 | } 610 | } 611 | // attributes 612 | if(isset($this->attributes) && count($this->attributes) > 0){ 613 | foreach($this->attributes as $attr => $aParts){ 614 | $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; 615 | } 616 | } 617 | // finish 'er up 618 | $attr = ''; 619 | foreach ($this->schemaInfo as $k => $v) { 620 | if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { 621 | $attr .= " $k=\"$v\""; 622 | } 623 | } 624 | $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; 625 | foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { 626 | $el .= " xmlns:$nsp=\"$ns\""; 627 | } 628 | $xml = $el . ">\n".$xml."\n"; 629 | return $xml; 630 | } 631 | 632 | /** 633 | * adds debug data to the clas level debug string 634 | * 635 | * @param string $string debug data 636 | * @access private 637 | */ 638 | function xdebug($string){ 639 | $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); 640 | } 641 | 642 | /** 643 | * get the PHP type of a user defined type in the schema 644 | * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays 645 | * returns false if no type exists, or not w/ the given namespace 646 | * else returns a string that is either a native php type, or 'struct' 647 | * 648 | * @param string $type name of defined type 649 | * @param string $ns namespace of type 650 | * @return mixed 651 | * @access public 652 | * @deprecated 653 | */ 654 | function getPHPType($type,$ns){ 655 | if(isset($this->typemap[$ns][$type])){ 656 | //print "found type '$type' and ns $ns in typemap
"; 657 | return $this->typemap[$ns][$type]; 658 | } elseif(isset($this->complexTypes[$type])){ 659 | //print "getting type '$type' and ns $ns from complexTypes array
"; 660 | return $this->complexTypes[$type]['phpType']; 661 | } 662 | return false; 663 | } 664 | 665 | /** 666 | * returns an associative array of information about a given type 667 | * returns false if no type exists by the given name 668 | * 669 | * For a complexType typeDef = array( 670 | * 'restrictionBase' => '', 671 | * 'phpType' => '', 672 | * 'compositor' => '(sequence|all)', 673 | * 'elements' => array(), // refs to elements array 674 | * 'attrs' => array() // refs to attributes array 675 | * ... and so on (see addComplexType) 676 | * ) 677 | * 678 | * For simpleType or element, the array has different keys. 679 | * 680 | * @param string $type 681 | * @return mixed 682 | * @access public 683 | * @see addComplexType 684 | * @see addSimpleType 685 | * @see addElement 686 | */ 687 | function getTypeDef($type){ 688 | //$this->debug("in getTypeDef for type $type"); 689 | if (substr($type, -1) == '^') { 690 | $is_element = 1; 691 | $type = substr($type, 0, -1); 692 | } else { 693 | $is_element = 0; 694 | } 695 | 696 | if((! $is_element) && isset($this->complexTypes[$type])){ 697 | $this->xdebug("in getTypeDef, found complexType $type"); 698 | return $this->complexTypes[$type]; 699 | } elseif((! $is_element) && isset($this->simpleTypes[$type])){ 700 | $this->xdebug("in getTypeDef, found simpleType $type"); 701 | if (!isset($this->simpleTypes[$type]['phpType'])) { 702 | // get info for type to tack onto the simple type 703 | // TODO: can this ever really apply (i.e. what is a simpleType really?) 704 | $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); 705 | $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); 706 | $etype = $this->getTypeDef($uqType); 707 | if ($etype) { 708 | $this->xdebug("in getTypeDef, found type for simpleType $type:"); 709 | $this->xdebug($this->varDump($etype)); 710 | if (isset($etype['phpType'])) { 711 | $this->simpleTypes[$type]['phpType'] = $etype['phpType']; 712 | } 713 | if (isset($etype['elements'])) { 714 | $this->simpleTypes[$type]['elements'] = $etype['elements']; 715 | } 716 | } 717 | } 718 | return $this->simpleTypes[$type]; 719 | } elseif(isset($this->elements[$type])){ 720 | $this->xdebug("in getTypeDef, found element $type"); 721 | if (!isset($this->elements[$type]['phpType'])) { 722 | // get info for type to tack onto the element 723 | $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); 724 | $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); 725 | $etype = $this->getTypeDef($uqType); 726 | if ($etype) { 727 | $this->xdebug("in getTypeDef, found type for element $type:"); 728 | $this->xdebug($this->varDump($etype)); 729 | if (isset($etype['phpType'])) { 730 | $this->elements[$type]['phpType'] = $etype['phpType']; 731 | } 732 | if (isset($etype['elements'])) { 733 | $this->elements[$type]['elements'] = $etype['elements']; 734 | } 735 | } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { 736 | $this->xdebug("in getTypeDef, element $type is an XSD type"); 737 | $this->elements[$type]['phpType'] = 'scalar'; 738 | } 739 | } 740 | return $this->elements[$type]; 741 | } elseif(isset($this->attributes[$type])){ 742 | $this->xdebug("in getTypeDef, found attribute $type"); 743 | return $this->attributes[$type]; 744 | } elseif (ereg('_ContainedType$', $type)) { 745 | $this->xdebug("in getTypeDef, have an untyped element $type"); 746 | $typeDef['typeClass'] = 'simpleType'; 747 | $typeDef['phpType'] = 'scalar'; 748 | $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; 749 | return $typeDef; 750 | } 751 | $this->xdebug("in getTypeDef, did not find $type"); 752 | return false; 753 | } 754 | 755 | /** 756 | * returns a sample serialization of a given type, or false if no type by the given name 757 | * 758 | * @param string $type name of type 759 | * @return mixed 760 | * @access public 761 | * @deprecated 762 | */ 763 | function serializeTypeDef($type){ 764 | //print "in sTD() for type $type
"; 765 | if($typeDef = $this->getTypeDef($type)){ 766 | $str .= '<'.$type; 767 | if(is_array($typeDef['attrs'])){ 768 | foreach($typeDef['attrs'] as $attName => $data){ 769 | $str .= " $attName=\"{type = ".$data['type']."}\""; 770 | } 771 | } 772 | $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; 773 | if(count($typeDef['elements']) > 0){ 774 | $str .= ">"; 775 | foreach($typeDef['elements'] as $element => $eData){ 776 | $str .= $this->serializeTypeDef($element); 777 | } 778 | $str .= ""; 779 | } elseif($typeDef['typeClass'] == 'element') { 780 | $str .= ">"; 781 | } else { 782 | $str .= "/>"; 783 | } 784 | return $str; 785 | } 786 | return false; 787 | } 788 | 789 | /** 790 | * returns HTML form elements that allow a user 791 | * to enter values for creating an instance of the given type. 792 | * 793 | * @param string $name name for type instance 794 | * @param string $type name of type 795 | * @return string 796 | * @access public 797 | * @deprecated 798 | */ 799 | function typeToForm($name,$type){ 800 | // get typedef 801 | if($typeDef = $this->getTypeDef($type)){ 802 | // if struct 803 | if($typeDef['phpType'] == 'struct'){ 804 | $buffer .= ''; 805 | foreach($typeDef['elements'] as $child => $childDef){ 806 | $buffer .= " 807 | 808 | "; 809 | } 810 | $buffer .= '
$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
'; 811 | // if array 812 | } elseif($typeDef['phpType'] == 'array'){ 813 | $buffer .= ''; 814 | for($i=0;$i < 3; $i++){ 815 | $buffer .= " 816 | 817 | "; 818 | } 819 | $buffer .= '
array item (type: $typeDef[arrayType]):
'; 820 | // if scalar 821 | } else { 822 | $buffer .= ""; 823 | } 824 | } else { 825 | $buffer .= ""; 826 | } 827 | return $buffer; 828 | } 829 | 830 | /** 831 | * adds a complex type to the schema 832 | * 833 | * example: array 834 | * 835 | * addType( 836 | * 'ArrayOfstring', 837 | * 'complexType', 838 | * 'array', 839 | * '', 840 | * 'SOAP-ENC:Array', 841 | * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), 842 | * 'xsd:string' 843 | * ); 844 | * 845 | * example: PHP associative array ( SOAP Struct ) 846 | * 847 | * addType( 848 | * 'SOAPStruct', 849 | * 'complexType', 850 | * 'struct', 851 | * 'all', 852 | * array('myVar'=> array('name'=>'myVar','type'=>'string') 853 | * ); 854 | * 855 | * @param name 856 | * @param typeClass (complexType|simpleType|attribute) 857 | * @param phpType: currently supported are array and struct (php assoc array) 858 | * @param compositor (all|sequence|choice) 859 | * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 860 | * @param elements = array ( name = array(name=>'',type=>'') ) 861 | * @param attrs = array( 862 | * array( 863 | * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", 864 | * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" 865 | * ) 866 | * ) 867 | * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) 868 | * @access public 869 | * @see getTypeDef 870 | */ 871 | function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ 872 | $this->complexTypes[$name] = array( 873 | 'name' => $name, 874 | 'typeClass' => $typeClass, 875 | 'phpType' => $phpType, 876 | 'compositor'=> $compositor, 877 | 'restrictionBase' => $restrictionBase, 878 | 'elements' => $elements, 879 | 'attrs' => $attrs, 880 | 'arrayType' => $arrayType 881 | ); 882 | 883 | $this->xdebug("addComplexType $name:"); 884 | $this->appendDebug($this->varDump($this->complexTypes[$name])); 885 | } 886 | 887 | /** 888 | * adds a simple type to the schema 889 | * 890 | * @param string $name 891 | * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) 892 | * @param string $typeClass (should always be simpleType) 893 | * @param string $phpType (should always be scalar) 894 | * @param array $enumeration array of values 895 | * @access public 896 | * @see nusoap_xmlschema 897 | * @see getTypeDef 898 | */ 899 | function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 900 | $this->simpleTypes[$name] = array( 901 | 'name' => $name, 902 | 'typeClass' => $typeClass, 903 | 'phpType' => $phpType, 904 | 'type' => $restrictionBase, 905 | 'enumeration' => $enumeration 906 | ); 907 | 908 | $this->xdebug("addSimpleType $name:"); 909 | $this->appendDebug($this->varDump($this->simpleTypes[$name])); 910 | } 911 | 912 | /** 913 | * adds an element to the schema 914 | * 915 | * @param array $attrs attributes that must include name and type 916 | * @see nusoap_xmlschema 917 | * @access public 918 | */ 919 | function addElement($attrs) { 920 | if (! $this->getPrefix($attrs['type'])) { 921 | $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; 922 | } 923 | $this->elements[ $attrs['name'] ] = $attrs; 924 | $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 925 | 926 | $this->xdebug("addElement " . $attrs['name']); 927 | $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); 928 | } 929 | } 930 | 931 | /** 932 | * Backward compatibility 933 | */ 934 | class XMLSchema extends nusoap_xmlschema { 935 | } 936 | 937 | 938 | ?> -------------------------------------------------------------------------------- /application/libraries/NuSOAP/lib/nusoapmime.php: -------------------------------------------------------------------------------- 1 | 50 | * @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list 51 | * @version $Id: nusoapmime.php,v 1.12 2007/04/17 16:34:03 snichol Exp $ 52 | * @access public 53 | */ 54 | class nusoap_client_mime extends nusoap_client { 55 | /** 56 | * @var array Each array element in the return is an associative array with keys 57 | * data, filename, contenttype, cid 58 | * @access private 59 | */ 60 | var $requestAttachments = array(); 61 | /** 62 | * @var array Each array element in the return is an associative array with keys 63 | * data, filename, contenttype, cid 64 | * @access private 65 | */ 66 | var $responseAttachments; 67 | /** 68 | * @var string 69 | * @access private 70 | */ 71 | var $mimeContentType; 72 | 73 | /** 74 | * adds a MIME attachment to the current request. 75 | * 76 | * If the $data parameter contains an empty string, this method will read 77 | * the contents of the file named by the $filename parameter. 78 | * 79 | * If the $cid parameter is false, this method will generate the cid. 80 | * 81 | * @param string $data The data of the attachment 82 | * @param string $filename The filename of the attachment (default is empty string) 83 | * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) 84 | * @param string $cid The content-id (cid) of the attachment (default is false) 85 | * @return string The content-id (cid) of the attachment 86 | * @access public 87 | */ 88 | function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { 89 | if (! $cid) { 90 | $cid = md5(uniqid(time())); 91 | } 92 | 93 | $info['data'] = $data; 94 | $info['filename'] = $filename; 95 | $info['contenttype'] = $contenttype; 96 | $info['cid'] = $cid; 97 | 98 | $this->requestAttachments[] = $info; 99 | 100 | return $cid; 101 | } 102 | 103 | /** 104 | * clears the MIME attachments for the current request. 105 | * 106 | * @access public 107 | */ 108 | function clearAttachments() { 109 | $this->requestAttachments = array(); 110 | } 111 | 112 | /** 113 | * gets the MIME attachments from the current response. 114 | * 115 | * Each array element in the return is an associative array with keys 116 | * data, filename, contenttype, cid. These keys correspond to the parameters 117 | * for addAttachment. 118 | * 119 | * @return array The attachments. 120 | * @access public 121 | */ 122 | function getAttachments() { 123 | return $this->responseAttachments; 124 | } 125 | 126 | /** 127 | * gets the HTTP body for the current request. 128 | * 129 | * @param string $soapmsg The SOAP payload 130 | * @return string The HTTP body, which includes the SOAP payload 131 | * @access private 132 | */ 133 | function getHTTPBody($soapmsg) { 134 | if (count($this->requestAttachments) > 0) { 135 | $params['content_type'] = 'multipart/related; type="text/xml"'; 136 | $mimeMessage =& new Mail_mimePart('', $params); 137 | unset($params); 138 | 139 | $params['content_type'] = 'text/xml'; 140 | $params['encoding'] = '8bit'; 141 | $params['charset'] = $this->soap_defencoding; 142 | $mimeMessage->addSubpart($soapmsg, $params); 143 | 144 | foreach ($this->requestAttachments as $att) { 145 | unset($params); 146 | 147 | $params['content_type'] = $att['contenttype']; 148 | $params['encoding'] = 'base64'; 149 | $params['disposition'] = 'attachment'; 150 | $params['dfilename'] = $att['filename']; 151 | $params['cid'] = $att['cid']; 152 | 153 | if ($att['data'] == '' && $att['filename'] <> '') { 154 | if ($fd = fopen($att['filename'], 'rb')) { 155 | $data = fread($fd, filesize($att['filename'])); 156 | fclose($fd); 157 | } else { 158 | $data = ''; 159 | } 160 | $mimeMessage->addSubpart($data, $params); 161 | } else { 162 | $mimeMessage->addSubpart($att['data'], $params); 163 | } 164 | } 165 | 166 | $output = $mimeMessage->encode(); 167 | $mimeHeaders = $output['headers']; 168 | 169 | foreach ($mimeHeaders as $k => $v) { 170 | $this->debug("MIME header $k: $v"); 171 | if (strtolower($k) == 'content-type') { 172 | // PHP header() seems to strip leading whitespace starting 173 | // the second line, so force everything to one line 174 | $this->mimeContentType = str_replace("\r\n", " ", $v); 175 | } 176 | } 177 | 178 | return $output['body']; 179 | } 180 | 181 | return parent::getHTTPBody($soapmsg); 182 | } 183 | 184 | /** 185 | * gets the HTTP content type for the current request. 186 | * 187 | * Note: getHTTPBody must be called before this. 188 | * 189 | * @return string the HTTP content type for the current request. 190 | * @access private 191 | */ 192 | function getHTTPContentType() { 193 | if (count($this->requestAttachments) > 0) { 194 | return $this->mimeContentType; 195 | } 196 | return parent::getHTTPContentType(); 197 | } 198 | 199 | /** 200 | * gets the HTTP content type charset for the current request. 201 | * returns false for non-text content types. 202 | * 203 | * Note: getHTTPBody must be called before this. 204 | * 205 | * @return string the HTTP content type charset for the current request. 206 | * @access private 207 | */ 208 | function getHTTPContentTypeCharset() { 209 | if (count($this->requestAttachments) > 0) { 210 | return false; 211 | } 212 | return parent::getHTTPContentTypeCharset(); 213 | } 214 | 215 | /** 216 | * processes SOAP message returned from server 217 | * 218 | * @param array $headers The HTTP headers 219 | * @param string $data unprocessed response data from server 220 | * @return mixed value of the message, decoded into a PHP type 221 | * @access private 222 | */ 223 | function parseResponse($headers, $data) { 224 | $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); 225 | $this->responseAttachments = array(); 226 | if (strstr($headers['content-type'], 'multipart/related')) { 227 | $this->debug('Decode multipart/related'); 228 | $input = ''; 229 | foreach ($headers as $k => $v) { 230 | $input .= "$k: $v\r\n"; 231 | } 232 | $params['input'] = $input . "\r\n" . $data; 233 | $params['include_bodies'] = true; 234 | $params['decode_bodies'] = true; 235 | $params['decode_headers'] = true; 236 | 237 | $structure = Mail_mimeDecode::decode($params); 238 | 239 | foreach ($structure->parts as $part) { 240 | if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { 241 | $this->debug('Have root part of type ' . $part->headers['content-type']); 242 | $root = $part->body; 243 | $return = parent::parseResponse($part->headers, $part->body); 244 | } else { 245 | $this->debug('Have an attachment of type ' . $part->headers['content-type']); 246 | $info['data'] = $part->body; 247 | $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; 248 | $info['contenttype'] = $part->headers['content-type']; 249 | $info['cid'] = $part->headers['content-id']; 250 | $this->responseAttachments[] = $info; 251 | } 252 | } 253 | 254 | if (isset($return)) { 255 | $this->responseData = $root; 256 | return $return; 257 | } 258 | 259 | $this->setError('No root part found in multipart/related content'); 260 | return ''; 261 | } 262 | $this->debug('Not multipart/related'); 263 | return parent::parseResponse($headers, $data); 264 | } 265 | } 266 | 267 | /* 268 | * For backwards compatiblity, define soapclientmime unless the PHP SOAP extension is loaded. 269 | */ 270 | if (!extension_loaded('soap')) { 271 | class soapclientmime extends nusoap_client_mime { 272 | } 273 | } 274 | 275 | /** 276 | * nusoap_server_mime server supporting MIME attachments defined at 277 | * http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. 278 | * 279 | * @author Scott Nichol 280 | * @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list 281 | * @version $Id: nusoapmime.php,v 1.12 2007/04/17 16:34:03 snichol Exp $ 282 | * @access public 283 | */ 284 | class nusoap_server_mime extends nusoap_server { 285 | /** 286 | * @var array Each array element in the return is an associative array with keys 287 | * data, filename, contenttype, cid 288 | * @access private 289 | */ 290 | var $requestAttachments = array(); 291 | /** 292 | * @var array Each array element in the return is an associative array with keys 293 | * data, filename, contenttype, cid 294 | * @access private 295 | */ 296 | var $responseAttachments; 297 | /** 298 | * @var string 299 | * @access private 300 | */ 301 | var $mimeContentType; 302 | 303 | /** 304 | * adds a MIME attachment to the current response. 305 | * 306 | * If the $data parameter contains an empty string, this method will read 307 | * the contents of the file named by the $filename parameter. 308 | * 309 | * If the $cid parameter is false, this method will generate the cid. 310 | * 311 | * @param string $data The data of the attachment 312 | * @param string $filename The filename of the attachment (default is empty string) 313 | * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) 314 | * @param string $cid The content-id (cid) of the attachment (default is false) 315 | * @return string The content-id (cid) of the attachment 316 | * @access public 317 | */ 318 | function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { 319 | if (! $cid) { 320 | $cid = md5(uniqid(time())); 321 | } 322 | 323 | $info['data'] = $data; 324 | $info['filename'] = $filename; 325 | $info['contenttype'] = $contenttype; 326 | $info['cid'] = $cid; 327 | 328 | $this->responseAttachments[] = $info; 329 | 330 | return $cid; 331 | } 332 | 333 | /** 334 | * clears the MIME attachments for the current response. 335 | * 336 | * @access public 337 | */ 338 | function clearAttachments() { 339 | $this->responseAttachments = array(); 340 | } 341 | 342 | /** 343 | * gets the MIME attachments from the current request. 344 | * 345 | * Each array element in the return is an associative array with keys 346 | * data, filename, contenttype, cid. These keys correspond to the parameters 347 | * for addAttachment. 348 | * 349 | * @return array The attachments. 350 | * @access public 351 | */ 352 | function getAttachments() { 353 | return $this->requestAttachments; 354 | } 355 | 356 | /** 357 | * gets the HTTP body for the current response. 358 | * 359 | * @param string $soapmsg The SOAP payload 360 | * @return string The HTTP body, which includes the SOAP payload 361 | * @access private 362 | */ 363 | function getHTTPBody($soapmsg) { 364 | if (count($this->responseAttachments) > 0) { 365 | $params['content_type'] = 'multipart/related; type="text/xml"'; 366 | $mimeMessage =& new Mail_mimePart('', $params); 367 | unset($params); 368 | 369 | $params['content_type'] = 'text/xml'; 370 | $params['encoding'] = '8bit'; 371 | $params['charset'] = $this->soap_defencoding; 372 | $mimeMessage->addSubpart($soapmsg, $params); 373 | 374 | foreach ($this->responseAttachments as $att) { 375 | unset($params); 376 | 377 | $params['content_type'] = $att['contenttype']; 378 | $params['encoding'] = 'base64'; 379 | $params['disposition'] = 'attachment'; 380 | $params['dfilename'] = $att['filename']; 381 | $params['cid'] = $att['cid']; 382 | 383 | if ($att['data'] == '' && $att['filename'] <> '') { 384 | if ($fd = fopen($att['filename'], 'rb')) { 385 | $data = fread($fd, filesize($att['filename'])); 386 | fclose($fd); 387 | } else { 388 | $data = ''; 389 | } 390 | $mimeMessage->addSubpart($data, $params); 391 | } else { 392 | $mimeMessage->addSubpart($att['data'], $params); 393 | } 394 | } 395 | 396 | $output = $mimeMessage->encode(); 397 | $mimeHeaders = $output['headers']; 398 | 399 | foreach ($mimeHeaders as $k => $v) { 400 | $this->debug("MIME header $k: $v"); 401 | if (strtolower($k) == 'content-type') { 402 | // PHP header() seems to strip leading whitespace starting 403 | // the second line, so force everything to one line 404 | $this->mimeContentType = str_replace("\r\n", " ", $v); 405 | } 406 | } 407 | 408 | return $output['body']; 409 | } 410 | 411 | return parent::getHTTPBody($soapmsg); 412 | } 413 | 414 | /** 415 | * gets the HTTP content type for the current response. 416 | * 417 | * Note: getHTTPBody must be called before this. 418 | * 419 | * @return string the HTTP content type for the current response. 420 | * @access private 421 | */ 422 | function getHTTPContentType() { 423 | if (count($this->responseAttachments) > 0) { 424 | return $this->mimeContentType; 425 | } 426 | return parent::getHTTPContentType(); 427 | } 428 | 429 | /** 430 | * gets the HTTP content type charset for the current response. 431 | * returns false for non-text content types. 432 | * 433 | * Note: getHTTPBody must be called before this. 434 | * 435 | * @return string the HTTP content type charset for the current response. 436 | * @access private 437 | */ 438 | function getHTTPContentTypeCharset() { 439 | if (count($this->responseAttachments) > 0) { 440 | return false; 441 | } 442 | return parent::getHTTPContentTypeCharset(); 443 | } 444 | 445 | /** 446 | * processes SOAP message received from client 447 | * 448 | * @param array $headers The HTTP headers 449 | * @param string $data unprocessed request data from client 450 | * @return mixed value of the message, decoded into a PHP type 451 | * @access private 452 | */ 453 | function parseRequest($headers, $data) { 454 | $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); 455 | $this->requestAttachments = array(); 456 | if (strstr($headers['content-type'], 'multipart/related')) { 457 | $this->debug('Decode multipart/related'); 458 | $input = ''; 459 | foreach ($headers as $k => $v) { 460 | $input .= "$k: $v\r\n"; 461 | } 462 | $params['input'] = $input . "\r\n" . $data; 463 | $params['include_bodies'] = true; 464 | $params['decode_bodies'] = true; 465 | $params['decode_headers'] = true; 466 | 467 | $structure = Mail_mimeDecode::decode($params); 468 | 469 | foreach ($structure->parts as $part) { 470 | if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { 471 | $this->debug('Have root part of type ' . $part->headers['content-type']); 472 | $return = parent::parseRequest($part->headers, $part->body); 473 | } else { 474 | $this->debug('Have an attachment of type ' . $part->headers['content-type']); 475 | $info['data'] = $part->body; 476 | $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; 477 | $info['contenttype'] = $part->headers['content-type']; 478 | $info['cid'] = $part->headers['content-id']; 479 | $this->requestAttachments[] = $info; 480 | } 481 | } 482 | 483 | if (isset($return)) { 484 | return $return; 485 | } 486 | 487 | $this->setError('No root part found in multipart/related content'); 488 | return; 489 | } 490 | $this->debug('Not multipart/related'); 491 | return parent::parseRequest($headers, $data); 492 | } 493 | } 494 | 495 | /* 496 | * For backwards compatiblity 497 | */ 498 | class nusoapservermime extends nusoap_server_mime { 499 | } 500 | 501 | ?> 502 | -------------------------------------------------------------------------------- /application/libraries/nuSoap_lib.php: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------