<?php /* SOAPx4 by Dietrich Ayala (C) 2001 dietrich@ganx4.com This project began based on code from the 2 projects below, and still contains some original code. The licenses of both must be respected. XML-RPC for PHP originally by Edd Dumbill (C) 1999-2000 SOAP for PHP by Victor Zou (C) 2000-2001 <victor@gigaideas.com.cn> */ /* changelog: 2001-07-04 - abstract type system to support either 1999 or 2001 schema (arg, typing still needs much solidification.) - implemented proxy support, based on sample code from miles lott <milos@speakeasy.net> - much general cleanup of code & cleaned out what was left of original xml-rpc/gigaideas code - implemented a transport argument into send() that allows you to specify different transports (assuming you have implemented the function, and added it to the conditional statement in send() - abstracted the determination of charset in Content-type header 2001-07-5 - fixed more weird type/namespace issues */ // $path can be a complete endpoint url, with the other parameters left blank: // $soap_client = new soap_client("http://path/to/soap/server"); /* $Id$ */ // soap value object class soapval { // function soapval($name='',$type=False,$value=-1,$namespace=False,$type_namespace=False) function soapval($name='',$type=False,$value=0,$namespace=False,$type_namespace=False) { // detect type if not passed if(!$type) { if(is_array($value) && count($value) >= 1) { if(ereg("[a-zA-Z0-9\-]*",key($v))) { $type = 'struct'; } else { $type = 'array'; } } elseif(is_int($v)) { $type = 'int'; } elseif(is_float($v) || $v == 'NaN' || $v == 'INF') { $type = 'float'; } else { $type = gettype($value); } } // php type name mangle if($type == 'integer') { $type = 'int'; } $this->soapTypes = $GLOBALS['soapTypes']; $this->name = $name; $this->value = ''; $this->type = $type; $this->type_code = 0; $this->type_prefix = false; $this->array_type = ''; $this->debug_flag = False; $this->debug_str = ''; $this->debug("Entering soapval - name: '$name' type: '$type'"); if($namespace) { $this->namespace = $namespace; if(!isset($GLOBALS['namespaces'][$namespace])) { $GLOBALS['namespaces'][$namespace] = "ns".(count($GLOBALS['namespaces'])+1); } $this->prefix = $GLOBALS['namespaces'][$namespace]; } // get type prefix if(ereg(":",$type)) { $this->type = substr(strrchr($type,':'),1,strlen(strrchr($type,':'))); $this->type_prefix = substr($type,0,strpos($type,':')); } elseif($type_namespace) { if(!isset($GLOBALS['namespaces'][$type_namespace])) { $GLOBALS['namespaces'][$type_namespace] = 'ns'.(count($GLOBALS['namespaces'])+1); } $this->type_prefix = $GLOBALS['namespaces'][$type_namespace]; } // if type namespace was not explicitly passed, and we're not in a method struct: elseif(!$this->type_prefix && !isset($this->namespace)) { // try to get type prefix from typeMap if(!$this->type_prefix = $this->verify_type($type)) { // else default to method namespace $this->type_prefix = $GLOBALS['namespaces'][$GLOBALS['methodNamespace']]; } } // if scalar if($this->soapTypes[$this->type] == 1) { $this->type_code = 1; $this->addScalar($value,$this->type,$name); // if array } elseif($this->soapTypes[$this->type] == 2) { $this->type_code = 2; $this->addArray($value); // if struct } elseif($this->soapTypes[$this->type] == 3) { $this->type_code = 3; $this->addStruct($value); } else { //if($namespace == $GLOBALS['methodNamespace']){ $this->type_code = 3; $this->addStruct($value); //} } } function addScalar($value, $type, $name="") { $this->debug("adding scalar '$name' of type '$type'"); // if boolean, change value to 1 or 0 if ($type == "boolean") { if((strcasecmp($value,"true") == 0) || ($value == 1)) { $value = 1; } else { $value = 0; } } $this->value = $value; return true; } function addArray($vals) { $this->debug("adding array '$this->name' with ".count($vals)." vals"); $this->value = array(); if(is_array($vals) && count($vals) >= 1) { @reset($vals); while(list($k,$v) = @each($vals)) /* foreach($vals as $k => $v) */ { $this->debug("checking value $k : $v"); // if soapval, add.. if(get_class($v) == 'soapval') { $this->value[] = $v; $this->debug($v->debug_str); // else make obj and serialize } else { if(is_array($v)) { if(ereg("[a-zA-Z\-]*",key($v))) { $type = 'struct'; } else { $type = 'array'; } } elseif(!ereg("^[0-9]*$",$k) && in_array($k,array_keys($this->soapTypes))) { $type = $k; } elseif(is_int($v)) { $type = 'int'; } elseif(is_float($v) || $v == 'NaN' || $v == 'INF') { $type = 'float'; } else { $type = gettype($v); } $new_val = CreateObject('phpgwapi.soapval','item',$type,$v); $this->debug($new_val->debug_str); $this->value[] = $new_val; } } } return true; } function addStruct($vals) { $this->debug("adding struct '$this->name' with ".count($vals).' vals'); if(is_array($vals) && count($vals) >= 1) { @reset($vals); while(list($k,$v) = @each($vals)) /* foreach($vals as $k => $v) */ { // if serialize, if soapval if(get_class($v) == 'soapval') { $this->value[] = $v; $this->debug($v->debug_str); // else make obj and serialize } else { if(is_array($v)) { @reset($v); while(list($a,$b) = @each($v)) /* foreach($v as $a => $b) */ { if($a == "0") { $type = 'array'; } else { $type = 'struct'; } break; } } // elseif(is_array($k) && in_array($k,array_keys($this->soapTypes))) elseif(is_array($k,in_array($k,array_keys($this->soapTypes)))) { $this->debug("got type '$type' for value '$v' from soapTypes array!"); $type = $k; } elseif(is_int($v)) { $type = 'int'; } elseif(is_float($v) || $v == "NaN" || $v == "INF") { $type = 'float'; } else { $type = gettype($v); $this->debug("got type '$type' for value '$v' from php gettype()!"); } $new_val = CreateObject('phpgwapi.soapval',$k,$type,$v); $this->debug($new_val->debug_str); $this->value[] = $new_val; } } } else { $this->value = array(); } return true; } // turn soapvals into xml, woohoo! function serializeval($soapval=false) { if(!$soapval) { $soapval = $this; } $this->debug("serializing '$soapval->name' of type '$soapval->type'"); if($soapval->name == '') { $soapval->name = 'return'; } switch($soapval->type_code) { case 3: // struct $this->debug('got a struct'); if($soapval->prefix && $soapval->type_prefix) { $xml .= "<$soapval->prefix:$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n"; } elseif($soapval->type_prefix) { $xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">\n"; } elseif($soapval->prefix) { $xml .= "<$soapval->prefix:$soapval->name>\n"; } else { $xml .= "<$soapval->name>\n"; } if(is_array($soapval->value)) { @reset($soapval->value); while(list($k,$v) = @each($soapval->value)) /* foreach($soapval->value as $k => $v) */ { $xml .= $this->serializeval($v); } } if($soapval->prefix) { $xml .= "</$soapval->prefix:$soapval->name>\n"; } else { $xml .= "</$soapval->name>\n"; } break; case 2: // array @reset($soapval->value); while(list($null,$array_val) = @each($soapval->value)) /* foreach($soapval->value as $array_val) */ { $array_types[$array_val->type] = 1; $xml .= $this->serializeval($array_val); } if(count($array_types) > 1) { $array_type = 'xsd:ur-type'; } elseif(count($array_types) >= 1) { $array_type = $array_val->type_prefix.":".$array_val->type; } $xml = "<$soapval->name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_type."[".sizeof($soapval->value)."]\">\n".$xml."</$soapval->name>\n"; break; case 1: $xml .= "<$soapval->name xsi:type=\"$soapval->type_prefix:$soapval->type\">$soapval->value</$soapval->name>\n"; break; default: break; } return $xml; } // serialize function serialize() { return $this->serializeval($this); } function decode($soapval=false) { if(!$soapval) { $soapval = $this; } // scalar decode if($soapval->type_code == 1) { return $soapval->value; // array decode } elseif($soapval->type_code == 2) { if(is_array($soapval->value)) { @reset($soapval->value); while(list($null,$item) = @each($soapval->value)) /* foreach($soapval->value as $item) */ { $return[] = $this->decode($item); } return $return; } else { return array(); } // struct decode } elseif($soapval->type_code == 3) { if(is_array($soapval->value)) { @reset($soapval->value); while(list($null,$item) = @each($soapval->value)) /* foreach($soapval->value as $item) */ { $return[$item->name] = $this->decode($item); } return $return; } else { return array(); } } } // verify type function verify_type($type) { if ($type) { @reset($GLOBALS['typemap']); while(list($namespace,$types) = @each($GLOBALS['typemap'])) /* foreach($GLOBALS['typemap'] as $namespace => $types) */ { if(in_array($type,$types)) { return $GLOBALS['namespaces'][$namespace]; } } } return false; } // alias for verify_type() - pass it a type, and it returns it's prefix function get_prefix($type) { if($prefix = $this->verify_type($type)) { return $prefix; } return false; } function debug($string) { if($this->debug_flag) { $this->debug_str .= "$string\n"; } } } ?>