Source for file Server.php
Documentation is available at Server.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
// | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author |
// +----------------------------------------------------------------------+
// $Id: Server.php,v 1.44.2.3 2004/08/22 19:59:50 arnaud Exp $
require_once 'SOAP/Base.php';
require_once 'SOAP/Fault.php';
require_once 'SOAP/Parser.php';
require_once 'SOAP/Value.php';
require_once 'SOAP/WSDL.php';
$soap_server_fault = null;
// the error handler should ignore '0' errors, eg. hidden by @ - see the
// set_error_handler manual page.. (thanks to Alan Knowles)
if (!$errno || $errno == E_NOTICE ) {
global $soap_server_fault;
$detail = " Errno: $errno\nFilename: $filename\nLineno: $linenum\n";
// XXX very strange behaviour with error handling if we =& here.
$soap_server_fault = new SOAP_Fault($errmsg, 'Server', 'PHP', $detail);
* originaly based on SOAPx4 by Dietrich Ayala http://dietrich.ganx4.com/soapx4
* @version $Id: Server.php,v 1.44.2.3 2004/08/22 19:59:50 arnaud Exp $
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
* @author Dietrich Ayala <dietrich@ganx4.com> Original Author
* @var string XML-Encoding
var $result = 'successful'; // for logging interop results to db
var $__options = array ('use'=> 'encoded','style'=> 'rpc','parameters'=>0 );
if (isset ($options['use']))
$this->__options['use'] = $options['use'];
if (isset ($options['style']))
$this->__options['style'] = $options['style'];
if (isset ($options['parameters']))
$this->__options['parameters'] = $options['parameters'];
$this->_section5 = TRUE; // assume we encode with section 5
if ($this->__options['use']== 'literal') $this->_section5 = FALSE;
function _getContentEncoding ($content_type)
// get the character encoding of the incoming request
// treat incoming data as UTF-8 if no encoding set
if (strpos($content_type,'=')) {
if (!in_array($enc, $this->_encodings)) {
// parses request and posts response
function service($data, $endpoint = '', $test = FALSE )
// figure out our endpoint
// we'll try to build our endpoint
$this->endpoint = 'http://'. $_SERVER['SERVER_NAME'];
if ($_SERVER['SERVER_PORT']) $this->endpoint .= ':'. $_SERVER['SERVER_PORT'];
$this->endpoint .= $_SERVER['SCRIPT_NAME'];
// get the character encoding of the incoming request
// treat incoming data as UTF-8 if no encoding set
if (isset ($_SERVER['CONTENT_TYPE'])) {
if (strcasecmp($_SERVER['CONTENT_TYPE'],'application/dime')==0 ) {
$this->_decodeDIMEMessage ($data,$headers,$attachments);
} else if (stristr($_SERVER['CONTENT_TYPE'],'multipart/related')) {
// this is a mime message, lets decode it.
$data = 'Content-Type: '. stripslashes($_SERVER['CONTENT_TYPE']). "\r\n\r\n". $data;
$this->_decodeMimeMessage ($data,$headers,$attachments);
if (!isset ($headers['content-type'])) {
$headers['content-type'] = stripslashes($_SERVER['CONTENT_TYPE']);
!$this->_getContentEncoding ($headers['content-type'])) {
// an encoding we don't understand, return a fault
$this->_raiseSoapFault ('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8','','','Server');
// if this is not a POST with Content-Type text/xml, try to return a WSDL file
if (!$this->fault && !$test && ($_SERVER['REQUEST_METHOD'] != 'POST' ||
strncmp($headers['content-type'],'text/xml',8 ) != 0 )) {
// this is not possibly a valid soap request, try to return a WSDL file
$this->_raiseSoapFault ("Invalid SOAP request, must be POST with content-type: text/xml, got: ". (isset ($headers['content-type'])? $headers['content-type']: 'Nothing!'),'','','Server');
// $response is a soap_msg object
// handle Mime or DIME encoding
// XXX DIME Encoding should move to the transport, do it here for now
// and for ease of getting it done
if (count($this->__attachments)) {
if ($useEncoding == 'Mime') {
$soap_msg = $this->_makeMimeMessage ($soap_msg);
$soap_msg = $this->_makeDIMEMessage ($soap_msg);
$header['Content-Type'] = 'application/dime';
if (PEAR ::isError ($soap_msg)) {
return $this->raiseSoapFault ($soap_msg);
$response = $soap_msg['body'];
if (count($soap_msg['headers'])) {
$header = $soap_msg['headers'];
// make distinction between the different choice of installation,
// running php as cgi or as a module
$hdrs = " $hdrs_type 500 Soap Fault\r\n";
$response = $this->fault->message ();
$hdrs = " $hdrs_type 200 OK\r\n";
if (!isset ($header['Content-Type']))
$header['Content-Length'] = strlen($response);
foreach ($header as $k => $v) {
$this->response = $hdrs . "\r\n" . $response;
global $soap_server_fault;
$soap_server_fault = null;
// call method with parameters
// call method w/ no parameters
return is_null($soap_server_fault) ? $ret : $soap_server_fault;
// create soap_val object w/ return values from method, use method signature to determine type
function buildResult(&$method_response, &$return_type, $return_name= 'return', $namespace = '')
if (gettype($method_response) == 'object' && is_a($method_response,'soap_value')) {
$return_val = array ($method_response);
foreach ($return_type as $key => $type) {
if (is_a($method_response[$i],'soap_value')) {
$return_val[] = $method_response[$i++ ];
$qn = & new QName($key, $namespace);
$return_val[] = & new SOAP_Value($qn->fqn (),$type,$method_response[$i++ ]);
if (!is_numeric($keys[0 ])) $return_name = $keys[0 ];
$return_type = $values[0 ];
$qn = & new QName($return_name, $namespace);
$return_val[] = & new SOAP_Value($qn->fqn (),$return_type,$method_response);
// parse response, get soap parser obj
// if fault occurred during message parsing
$this->fault = $parser->fault;
//*******************************************************
// handle message headers
$request_headers = $parser->getHeaders ();
$header_results = array ();
if (!is_a($request_headers,'soap_value')) {
$this->_raiseSoapFault (" parser did not return SOAP_Value object: $request_headers" ,'','','Server');
if ($request_headers->value ) {
foreach ($request_headers->value as $header_val) {
$f_exists = $this->validateMethod($header_val->name , $header_val->namespace );
# XXX this does not take into account message routing yet
$header_val->actor == 'http://schemas.xmlsoap.org/soap/actor/next' ||
if (!$f_exists && $header_val->mustunderstand && $myactor) {
$this->_raiseSoapFault (" I don't understand header $header_val->name." ,'','','MustUnderstand');
// we only handle the header if it's for us
$isok = $f_exists && $myactor;
$header_method = $header_val->name;
$header_data = array ($this->_decode ($header_val));
// if there are parameters to pass
$hr = & $this->callMethod($header_method, $header_data);
# if they return a fault, then it's all over!
if (PEAR ::isError ($hr)) {
$this->_raiseSoapFault ($hr);
$header_results[] = array_shift($this->buildResult($hr, $this->return_type, $header_method, $header_val->namespace ));
//*******************************************************
// handle the method call
// evaluate message, getting back a SOAP_Value object
// figure out the method_namespace
$this->method_namespace = $parser->message [$parser->root_struct [0 ]]['namespace'];
$this->_setSchemaVersion ($this->_wsdl->xsd );
$dataHandler = $this->_wsdl->getDataHandler ($this->methodname,$this->method_namespace);
$this->_portName = $this->_wsdl->getPortName ($this->methodname);
if (PEAR ::isError ($this->_portName)) {
return $this->_raiseSoapFault ($this->_portName);
$opData = $this->_wsdl->getOperationData ($this->_portName, $this->methodname);
if (PEAR ::isError ($opData)) {
return $this->_raiseSoapFault ($opData);
$this->__options['style'] = $opData['style'];
$this->__options['use'] = $opData['output']['use'];
$this->__options['parameters'] = $opData['parameters'];
$this->_raiseSoapFault (" method '{{$this->method_namespace}} $this->methodname' not defined in service ",'','','Server');
if (!$request_val = $parser->getResponse ()) {
if (!is_a($request_val,'soap_value')) {
$this->_raiseSoapFault ("parser did not return SOAP_Value object: $request_val" ,'','','Server');
// verify that SOAP_Value objects in request match the methods signature
// verifyMethod creates the fault
// need to set special error detection inside the value class
// so as to differentiate between no params passed, and an error decoding
if (PEAR ::isError ($request_data)) {
return $this->_raiseSoapFault ($request_data);
if (PEAR ::isError ($method_response)) {
$this->_raiseSoapFault ($method_response);
if ($this->__options['parameters'] || !$method_response || $this->__options['style']== 'rpc') {
if (is_null($method_response))
$return_val = $this->buildResult($method_response, $this->return_type);
$methodValue = & new SOAP_Value ($qn->fqn (), 'Struct', $return_val);
$methodValue =& $method_response;
return $this->_makeEnvelope ($methodValue, $header_results, $this->response_encoding);
function &__decodeRequest($request,$shift=false)
if (!$request) return NULL;
// check for valid response
if (PEAR::isError($request)) {
return $this->_raiseSoapFault ($request);
} else if (!is_a($request,'soap_value')) {
return $this->_raiseSoapFault ("Invalid data in server::__decodeRequest");
// decode to native php datatype
$requestArray = $this->_decode ($request);
if (PEAR ::isError ($requestArray)) {
return $this->_raiseSoapFault ($requestArray);
if (is_object($requestArray)&& get_class($requestArray) == 'stdClass') {
$requestArray = get_object_vars($requestArray);
if ($this->__options['style']== 'document') {
$requestArray = array($requestArray);
if (is_array($requestArray)) {
if (isset($requestArray['faultcode']) || isset($requestArray['SOAP-ENV:faultcode'])) {
$faultcode = $faultstring = $faultdetail = $faultactor = '';
foreach ($requestArray as $k => $v) {
if (stristr($k,'faultcode')) $faultcode = $v;
if (stristr($k,'faultstring')) $faultstring = $v;
if (stristr($k,'detail')) $faultdetail = $v;
if (stristr($k,'faultactor')) $faultactor = $v;
return $this->_raiseSoapFault ($faultstring, $faultdetail, $faultactor, $faultcode);
// return array of return values
if ($shift && count($requestArray) == 1) {
return array_shift($requestArray);
function verifyMethod($request)
$params = $request->value;
// get the dispatch map if one exists
if (array_key_exists ($this->methodname, $this->dispatch_map)) {
if (method_exists($this->soapobject, '__dispatch')) {
$map = $this->soapobject->__dispatch ($this->methodname);
} else if (method_exists($this->soapobject, $this->methodname)) {
// no map, all public functions are soap functions
$this->_raiseSoapFault ("soap request specified an unhandled method ' $this->methodname' ",'','','Client');
// if we aliased the soap method name to a php function,
// change the call_method so we do the right thing.
if (array_key_exists('alias',$map) && !empty($map['alias'])) {
// if there are input parameters required...
$this->input_value = count ($sig);
// validate the number of parameters
if (count($params) == count($sig)) {
// make array of param types
foreach ($params as $param) {
$p[] = strtolower($param->type );
$sig_t = array_values($sig);
// validate each param's type
for($i=0; $i < count($p); $i++) {
// if soap types do not match, we ok it if the mapped php types match
// this allows using plain php variables to work (ie. stuff like Decimal would fail otherwise)
// we only error if the types exist in our type maps, and they differ
if (strcasecmp($sig_t[$i],$p[$i])!=0 &&
(isset($this->_typemap[SOAP_XML_SCHEMA_VERSION ][$sig_t[$i]]) &&
strcasecmp ($this->_typemap[SOAP_XML_SCHEMA_VERSION ][$sig_t[$i]],$this->_typemap[SOAP_XML_SCHEMA_VERSION ][$p[$i]])!=0 )) {
$this->_raiseSoapFault ("soap request contained mismatching parameters of name $param->name had type [{ $p[$i]}], which did not match signature's type: [{ $sig_t[$i]}], matched? ". (strcasecmp ($sig_t[$i],$p[$i])),'','','Client');
// oops, wrong number of paramss
$this->_raiseSoapFault ("soap request contained incorrect number of parameters. method ' $this->methodname' required ".count($sig).' and request provided '.count($params),'','','Client');
$this->_raiseSoapFault ("soap request contained incorrect number of parameters. method ' $this->methodname' requires ".count($sig).' parameters, and request provided none','','','Client');
// get string return type from dispatch map
function getReturnType($returndata)
if (is_array($returndata)) {
if (count($returndata) > 1) {
$type = array_shift($returndata);
function validateMethod($methodname, $namespace = NULL)
# no soap access to private functions
if ($methodname[0 ] == '_') return FALSE;
/* if it's in our function list, ok */
(!$namespace || !array_key_exists ('namespace', $this->dispatch_map[$methodname]) ||
$namespace == $this->dispatch_map[$methodname]['namespace'])) {
if (array_key_exists('namespace', $this->dispatch_map[$methodname]))
/* if it's in an object, it's ok */
for ($i=0; $i < $c; $i++ ) {
// if we have a dispatch map, and the function is not
// in the dispatch map, then it is not callable!
if (method_exists ($obj, '__dispatch')) {
if ($obj->__dispatch ($methodname)) {
if (method_exists($obj, $methodname)) {
function addObjectMap(&$obj, $namespace = null, $service_name = 'Default', $service_desc = '')
if (isset($obj->namespace )) {
// XXX a bit of backwards compatibility
$namespace = $obj->namespace;
$this->_raiseSoapFault ('No namespace provided for class!','','','Server');
// Create internal WSDL structures for object
// XXX Because some internal workings of PEAR::SOAP decide whether to
// do certain things by the presence or absence of _wsdl, we should
// only create a _wsdl structure if we know we can fill it; if
// __dispatch_map or __typedef for the object is missing, we should
// avoid creating it. Later, when we are using PHP 5 introspection,
// we will be able to make the data for all objects without any extra
// information from the developers, and this condition should be
// XXX Known issue: if imported WSDL (bindWSDL) or another WSDL source
// is used to add _wsdl structure information, then addObjectWSDL is
// used, there is a high possibility of _wsdl data corruption;
// therefore you should avoid using __dispatch_map/__typedef definitions
// AND other WSDL data sources in the same service. We exclude classes
// that don't have __typedefs to allow external WSDL files to be used
// with classes with no internal type definitions (the types are defined
// in the WSDL file). When addObjectWSDL is refactored to not cause
// corruption, this restriction can be relaxed.
// In summry, if you add an object with both a dispatch map and type
// definitions, then previous WSDL file operation and type definitions
if (isset ($obj->__dispatch_map ) && isset ($obj->__typedef )) {
$this->addObjectWSDL($obj, $namespace, $service_name, $service_desc);
// add a method to the dispatch map
function addToMap($methodname, $in, $out, $namespace = NULL, $alias=NULL)
if (!function_exists($methodname)) {
$this->_raiseSoapFault ("error mapping function\n",'','','Server');
if ($namespace) $this->dispatch_map[$methodname]['namespace'] = $namespace;
function setCallHandler($callHandler, $validation=true) {
* @deprecated use bindWSDL from now on
function bind($wsdl_url) {
* @param string a url to a WSDL resource
function bindWSDL($wsdl_url) {
// instantiate wsdl class
$this->_wsdl = & new SOAP_WSDL ($wsdl_url);
if ($this->_wsdl->fault ) {
$this->_raiseSoapFault ($this->_wsdl->fault );
function addObjectWSDL(&$wsdl_obj, $targetNamespace, $service_name, $service_desc = '') {
if (!isset($this->_wsdl)) {
$this->_wsdl = & new SOAP_WSDL;
$this->_wsdl->parseObject ($wsdl_obj, $targetNamespace, $service_name, $service_desc);
if ($this->_wsdl->fault ) {
$this->_raiseSoapFault ($this->_wsdl->fault );
Documentation generated on Mon, 11 Mar 2019 13:59:46 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|