From 83086f89007d39ed8ba41043d5958565317f615d Mon Sep 17 00:00:00 2001 From: skeeter Date: Mon, 30 Jul 2001 03:40:08 +0000 Subject: [PATCH] This brings the SOAP server up to date as of 27 July 01 with the developers release code. --- phpgwapi/inc/class.soap_client.inc.php | 18 +++- phpgwapi/inc/class.soap_parser.inc.php | 10 ++- phpgwapi/inc/class.soap_server.inc.php | 114 +++++++++++++++---------- phpgwapi/inc/class.soapmsg.inc.php | 28 ++++-- phpgwapi/inc/class.soapval.inc.php | 12 ++- 5 files changed, 117 insertions(+), 65 deletions(-) diff --git a/phpgwapi/inc/class.soap_client.inc.php b/phpgwapi/inc/class.soap_client.inc.php index 7242127842..4374935c5a 100644 --- a/phpgwapi/inc/class.soap_client.inc.php +++ b/phpgwapi/inc/class.soap_client.inc.php @@ -15,6 +15,19 @@ by Victor Zou (C) 2000-2001 */ +/* 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 +- 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"); class soap_client @@ -68,7 +81,7 @@ class soap_client function send($msg, $action, $timeout=0) { // where msg is an soapmsg - $msg->debug = $this->debug; + $msg->debug_flag = $this->debug_flag; $this->action = $action; return $this->sendPayloadHTTP10( $msg, @@ -124,13 +137,12 @@ class soap_client // get reponse while($data = fread($fp, 32768)) { - $incoming_payload .= $data; + $incoming_payload .= $data; } fclose($fp); $this->incoming_payload = $incoming_payload; // $response is a soapmsg object - //$msg->debug_flag = true; $this->response = $msg->parseResponse($incoming_payload); $this->debug($msg->debug_str); return $this->response; diff --git a/phpgwapi/inc/class.soap_parser.inc.php b/phpgwapi/inc/class.soap_parser.inc.php index 5b30b8859f..5361c32b3a 100644 --- a/phpgwapi/inc/class.soap_parser.inc.php +++ b/phpgwapi/inc/class.soap_parser.inc.php @@ -1,15 +1,16 @@ soapTypes = $soapTypes; $this->xml = $xml; - $this->xml_encoding = "UTF-8"; + $this->xml_encoding = $encoding; $this->root_struct = ""; // options: envelope,header,body,method + // determines where in the message we are (envelope,header,body,method) $this->status = ""; $this->position = 0; $this->pos_stat = 0; @@ -215,7 +216,8 @@ class soap_parser // get type if not set already if($this->message[$pos]["type"] == "") { - if($this->message[$pos]["cdata"] == "" && $this->message[$pos]["children"] != "") +// if($this->message[$pos]["cdata"] == "" && $this->message[$pos]["children"] != "") + if($this->message[$pos]["children"] != "") { $this->message[$pos]["type"] = "SOAPStruct"; } @@ -282,7 +284,7 @@ class soap_parser } // set parent back to my parent $this->parent = $this->message[$pos]["parent"]; - //$this->debug("parsed $name end, eval_str = '".trim($this->message[$pos]["eval_str"])."' and children = ".$this->message[$pos]["children"]); + $this->debug("parsed $name end, type '".$this->message[$pos]["type"]."'eval_str = '".trim($this->message[$pos]["eval_str"])."' and children = ".$this->message[$pos]["children"]); } // element content handler diff --git a/phpgwapi/inc/class.soap_server.inc.php b/phpgwapi/inc/class.soap_server.inc.php index 46562d6442..7814a52625 100644 --- a/phpgwapi/inc/class.soap_server.inc.php +++ b/phpgwapi/inc/class.soap_server.inc.php @@ -3,9 +3,26 @@ // for example usage, see the test_server.php file. +/* changelog: +2001-07-05 +- detection of character encoding in Content-Type header. server +will now call the soap_parser object with the specified encoding +- server will now return the Content-Type header with the sender's encoding type specified +must still learn more bout encoding, and figure out what i have to do to be able to +make sure that my response is *actually* encoded correctly +2001-07-21 +- force proper error reporting for windows compatibility +2001-07-27 +- get_all_headers() check for windows compatibility + +*/ + +// make errors handle properly in windows +error_reporting(2039); + class soap_server { - function soap_server($data='',$serviceNow=False) + function soap_server() { // create empty dispatch map $this->dispatch_map = array(); @@ -13,23 +30,20 @@ class soap_server $this->debug_str = ''; $this->headers = ''; $this->request = ''; - $this->result = 'successful'; + $this->xml_encoding = 'UTF-8'; $this->fault = false; $this->fault_code = ''; $this->fault_str = ''; $this->fault_actor = ''; - - if($serviceNow == 1) - { - $this->service($data); - } + // for logging interop results to db + $this->result = 'successful'; } // parses request and posts response function service($data) { // $response is a soap_msg object - $response = $this->parseRequest($data); + $response = $this->parse_request($data); $this->debug("parsed request and got an object of this class '".get_class($response)."'"); $this->debug("server sending..."); // pass along the debug string @@ -50,8 +64,9 @@ class soap_server } $header[] = "Server: SOAPx4 Server v0.344359s\r\n"; $header[] = "Connection: Close\r\n"; - $header[] = "Content-Type: text/xml; charset=UTF-8\r\n"; + $header[] = "Content-Type: text/xml; charset=$this->xml_encoding\r\n"; $header[] = "Content-Length: ".strlen($payload)."\r\n\r\n"; + reset($header); foreach($header as $hdr) { header($hdr); @@ -59,50 +74,46 @@ class soap_server print $payload; } - function parseRequest($data="") + function parse_request($data='') { global $HTTP_SERVER_VARS; - $this->debug("entering parseRequest() on ".date("H:i Y-m-d")); + $this->debug("entering parse_request() on ".date("H:i Y-m-d")); $request_uri = $HTTP_SERVER_VARS["REQUEST_URI"]; $this->debug("request uri: $request_uri"); // get headers - $headers_array = getallheaders(); - foreach($headers_array as $k=>$v) + // get headers + if(function_exists("getallheaders")) { - $dump .= "$k: $v\r\n"; - } - $dump .= "\r\n\r\n".$data; - $this->headers = $headers_array; - $this->request = $dump; - - // get SOAPAction header -> methodname - if($headers_array["SOAPAction"]) - { - $action = str_replace('"','',$headers_array["SOAPAction"]); - if(ereg("^urn:",$action)) + $this->headers = getallheaders(); + foreach($headers_array as $k=>$v) { - $this->service = substr($action,4); + $dump .= "$k: $v\r\n"; } - elseif(ereg(".php",$action)) + // get SOAPAction header + if($headers_array["SOAPAction"]) { - $this->service = ereg_replace('"|/','',substr(strrchr($action,".php"),4,strlen(strrchr($action,"/")))); + $this->SOAPAction = str_replace('"','',$headers_array["SOAPAction"]); + $this->service = $this->SOAPAction; } - $this->debug("got service: $this->service"); + // get character encoding + if(ereg("=",$headers_array["Content-Type"])) + { + $this->xml_encoding = str_replace("\"","",substr(strstr($headers_array["Content-Type"],"="),1)); + } + elseif(ereg("^text/xml",$headers_array["Content-Type"])) + { + $this->xml_encoding = "us-ascii"; + } + $this->debug("got encoding: $this->xml_encoding"); } - else - { - // throw a fault if no soapaction - $this->debug("ERROR: no SOAPAction header found"); - } - // NOTE:::: throw a fault for no/bad soapaction here? - + $this->request = $dump."\r\n\r\n".$data; // parse response, get soap parser obj $parser = CreateObject('phpgwapi.soap_parser',$data); // get/set methodname $this->methodname = $parser->root_struct_name; $this->debug("method name: $this->methodname"); - + // does method exist? if(function_exists($this->methodname)) { @@ -251,19 +262,32 @@ class soap_server call_user_method($method,$obj); } } - - /* create soap_val object w/ return values from method, use method signature to determine type */ - if(get_class($method_response) != "soapval") + /* return fault */ + if(get_class($method_response) == "soapmsg") { - $return_val = CreateObject('phpgwapi.soapval',$method,$this->return_type,$method_response); + if(eregi("fault",$method_response->value->name)) + { + $this->fault = True; + } + $return_msg = $method_response; } else { - $return_val = $method_response; + /* return soapval object */ + + if(get_class($method_response) == "soapval") + { + $return_val = $method_response; + /* create soap_val object w/ return values from method, use method signature to determine type */ + } + else + { + $return_val = CreateObject('phpgwapi.soapval',$method,$this->return_type,$method_response); + } + $this->debug($return_val->debug_str); + /* response object is a soap_msg object */ + $return_msg = CreateObject('phpgwapi.soapmsg',$method."Response",array($return_val),$this->service); } - $this->debug($return_val->debug_str); - /* response object is a soap_msg object */ - $return_msg = CreateObject('phpgwapi.soapmsg',$method."Response",array($return_val),$this->service); if($this->debug_flag) { $return_msg->debug_flag = true; @@ -400,7 +424,7 @@ class soap_server "faultactor" => $this->fault_actor, "faultdetail" => $this->fault_detail.$this->debug_str ), - "http://schemas.xmlphpgwapi.org/soap/envelope/" + "http://schemas.xmlsoap.org/soap/envelope/" ); } diff --git a/phpgwapi/inc/class.soapmsg.inc.php b/phpgwapi/inc/class.soapmsg.inc.php index 43c64470d5..c7c5212ce6 100644 --- a/phpgwapi/inc/class.soapmsg.inc.php +++ b/phpgwapi/inc/class.soapmsg.inc.php @@ -32,7 +32,7 @@ class soapmsg { $ns_string .= " xmlns:$v=\"$k\""; } - return "\n" + return "\n" . $payload . "\n"; } @@ -72,20 +72,29 @@ class soapmsg { $this->debug("Entering parseResponse()"); //$this->debug(" w/ data $data"); - // get rid of headers here - $clean_data = ereg_replace("\r\n","\n", $data); - if(ereg("^.*\r\n\r\n",$data)) + // strip headers here + //$clean_data = ereg_replace("\r\n","\n", $data); + if(ereg("^.*\r\n\r\n<",$data)) { + $this->debug("found proper seperation of headers and document"); $this->debug("getting rid of headers, stringlen: ".strlen($data)); - $clean_data = ereg_replace("^.*\r\n\r\n","", $data); + $clean_data = ereg_replace("^.*\r\n\r\n<","<", $data); $this->debug("cleaned data, stringlen: ".strlen($clean_data)); } - elseif(ereg("^.*\n\n",$data)) + else { - $this->debug("getting rid of headers, stringlen: ".strlen($data)); - $clean_data = ereg_replace("^.*\n\n","", $data); - $this->debug("cleaned data, stringlen: ".strlen($clean_data)); + // return fault + return CreateObject('phpgwapi.soapval', + 'fault', + 'SOAPStruct', + Array( + CreateObject('phpgwapi.soapval','faultcode','string','SOAP-MSG'), + CreateObject('phpgwapi.soapval','faultstring','string','HTTP Error'), + CreateObject('phpgwapi.soapval','faultdetail','string','HTTP headers were not immediately followed by \'\r\n\r\n\'') + ) + ); } +/* // if response is a proper http response, and is not a 200 if(ereg("^HTTP",$clean_data) && !ereg("200$", $clean_data)) { @@ -101,6 +110,7 @@ class soapmsg ) ); } +*/ $this->debug("about to create parser instance w/ data: $clean_data"); // parse response $response = CreateObject('phpgwapi.soap_parser',$clean_data); diff --git a/phpgwapi/inc/class.soapval.inc.php b/phpgwapi/inc/class.soapval.inc.php index e10280d7ec..175453c111 100644 --- a/phpgwapi/inc/class.soapval.inc.php +++ b/phpgwapi/inc/class.soapval.inc.php @@ -2,7 +2,8 @@ // soap value object class soapval { - function soapval($name='',$type=False,$value=-1,$namespace=False,$type_namespace=False) +// function soapval($name='',$type=False,$value=-1,$namespace=False,$type_namespace=False) + function soapval($name='',$type=False,$value=0,$namespace=False,$type_namespace=False) { global $soapTypes, $typemap, $namespaces, $methodNamespace; @@ -74,6 +75,7 @@ class soapval } $this->type_prefix = $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)) { @@ -218,7 +220,8 @@ class soapval break; } } - elseif(is_array($k) && in_array($k,array_keys($this->soapTypes))) +// 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; @@ -330,7 +333,7 @@ class soapval function serialize() { return $this->serializeval($this); - } + } function decode($soapval=false) { @@ -382,7 +385,8 @@ class soapval { if ($type) { - global $namespaces,$soapTypes,$typemap; +// global $namespaces,$soapTypes,$typemap; + global $namespaces,$typemap; foreach($typemap as $namespace => $types) {