downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

SoapClient::__getFunctions> <SoapClient::__construct
Last updated: Fri, 13 Nov 2009

view this page in

SoapClient::__doRequest

(PHP 5 >= 5.0.1)

SoapClient::__doRequestSOAP リクエストを実行する

説明

public string SoapClient::__doRequest ( string $request , string $location , string $action , int $version [, int $one_way = 0 ] )

HTTP 上で SOAP リクエストを実行します。

異なるトランスポート層や追加の XML を処理する、もしくは他の目的のために サブクラスでこのメソッドをオーバーライドする事ができます。

パラメータ

request

XML SOAP リクエスト

location

リクエスト先の URL

action

SOAP アクション

version

SOAP バージョン

one_way

one_way に 1 を設定すると、このメソッドは何も返しません。 レスポンスが不要なときにこれを使用します。

返り値

XML SOAP レスポンス

変更履歴

バージョン 説明
5.1.3 one_way パラメータが追加されました。

例1 SoapClient::__doRequest() の例

<?php
function Add($x,$y) {
  return 
$x+$y;
}

class 
LocalSoapClient extends SoapClient {

  function 
__construct($wsdl$options) {
    
parent::__construct($wsdl$options);
    
$this->server = new SoapServer($wsdl$options);
    
$this->server->addFunction('Add');
  }

  function 
__doRequest($request$location$action$version) {
    
ob_start();
    
$this->server->handle($request);
    
$response ob_get_contents();
    
ob_end_clean();
    return 
$response;
  }

}

$x = new LocalSoapClient(NULL,array('location'=>'test://'
                                   
'uri'=>'http://testuri.org')); 
var_dump($x->Add(3,4));
?>



SoapClient::__getFunctions> <SoapClient::__construct
Last updated: Fri, 13 Nov 2009
 
add a note add a note User Contributed Notes
SoapClient::__doRequest
lepidosteus
19-Nov-2009 07:59
If you happen to get an error during your request which says "SOAP-ERROR: Encoding: Can't decode apache map, only Strings or Longs are allowd as keys", the reason seems to be the response xml using integer for keys and php failling to understand them

Here is something that worked for me (converts integer keys to strings):

<?php
class mySoap extends SoapClient
{
    public function
__doRequest($request, $location, $action, $version)
    {
       
$result = parent::__doRequest($request, $location, $action, $version);
       
$result = str_replace('<key xsi:type="xsd:int">', '<key xsi:type="xsd:string">', $result);
        return
$result;
    }
}

// $soap = new mySoap(...
?>
Artur Graniszewski
08-Nov-2009 09:35
Beware of PHP incosistent behaviour in __doRequest() method. It seems that some arguments passed to this method are passed by reference!

If you try to create your own __doRequest() method and store it's arguments as SoapClient properties you will find that after __soapCall all of them will be null or unknown.

<?php
   
protected $__soapAction = '';

    public function
__doRequest($request, $location, $action, $version, $oneWay = 0) {
       
ob_start();
       
$this->server->handle($request);
       
$response = ob_get_contents();
       
ob_end_clean();
       
$this->__soapAction = $action;
        return
$response;
    }
?>

In above example $this->__soapAction will be null after $obj->__soapCall()..

To store $action value, you must cast it to a string (so PHP will be forced to create a new variable with different memory pointer):

<?php
   
public function __doRequest($request, $location, $action, $version, $oneWay = 0) {
       
ob_start();
       
$this->server->handle($request);
       
$response = ob_get_contents();
       
ob_end_clean();
       
$this->__soapAction = (string)$action;
        return
$response;
    }
?>
james dot ellis at gmail dot com
04-Feb-2008 09:12
If your application interacts with SOAP services and you wish to cache the responses for consumption later, then overriding SoapClient::__doRequest is the way to go.

For instance, if you know that the information presented doesn't change that often and you don't want to do a superfluous HTTP request, you can grab a response from a local cache and let SoapClient do the transformation to PHP data types.

<?php
class YourNamespace_SoapClient_Local extends SoapClient {
    protected
$cacheDocument = "";
    public function
__construct($wsdl, $options) {
       
parent::__construct($wsdl, $options);
    }

   
/**
     * SetCacheDocument() sets the previously cached document contents
     */
   
public function SetCacheDocument($document) {
       
$this->cacheDocument = $document;
    }

   
/**
     * __doRequest() overrides the standard SoapClient to handle a local request
     */
   
public function __doRequest() {
        return
$this->cacheDocument;
    }
}

//---- code snippet showing usage within a class
//$document is a cached SOAP response document from a previous request, saved with SoapClient::__getLastResponse() to some cache somewhere
//for the purpose of this example, it is assumed that $this->wsdl, $this->options, $this->method and $this->params are set.

public function SoapRequest($document) {
   
$method = $this->method;
    if(
$document == "") {
       
//uncached
       
try {
           
//default options
           
$client = new SoapClient($this->wsdl, $this->options);
           
$result = $client->$method($this->params);
           
//send the response to the cache
           
$this->CacheResponse($client->__getLastResponse());
        } catch(
SoapFault $fault) {
           
//log something
           
return FALSE;
        }
    } else {
       
//cached document
       
try {
           
/**
             * the WSDL needs to be set to allow the method to be called on the client object
             * and to trigger SoapClient to decode the response to native data types
             */
           
$client = new YourNamespace_SoapClient_Local($this->wsdl, $this->options);
           
$client->SetCacheDocument($document);
           
$result = $client->$method($this->params);
        } catch (
SoapFault $fault) {
           
//log something
           
return FALSE;
        }
    }
    return
$result;
}
?>

I'll leave you to work out the caching, plenty of options there.. ;)
albert at jool dot nl
26-Mar-2007 11:28
If you want to communicate with a default configured ASP.NET server with SOAP 1.1 support, override your __doRequest with the following code. Adjust the namespace parameter, and all is good to go.

<?php
class MSSoapClient extends SoapClient {

    function
__doRequest($request, $location, $action, $version) {
       
$namespace = "http://tempuri.com";

       
$request = preg_replace('/<ns1:(\w+)/', '<$1 xmlns="'.$namespace.'"', $request, 1);
       
$request = preg_replace('/<ns1:(\w+)/', '<$1', $request);
       
$request = str_replace(array('/ns1:', 'xmlns:ns1="'.$namespace.'"'), array('/', ''), $request);

       
// parent call
       
return parent::__doRequest($request, $location, $action, $version);
    }
}

$client = new MSSoapClient(...);
?>

Hope this will save people endless hours of fiddling...
jfitz at spacelink dot com
06-Dec-2006 02:56
Note that __getLastRequest() data are buffered _before_ the call to __doRequest().  Thus any modifications you make to the XML while in __doRequest() will not be visible in the output of __getLastRequest().   This is so in at least v5.2.0
06-Jul-2006 05:17
Do you have problems with the PHP5 SoapClient when you need to send a request to a service with a ComplexType parameter?
 
Maybe because my service is build in Delphi with REMObjects SDK 3.0 I had the problems, maybe not. Anyway, this was my remedy:
<?php
$versie
= new stdClass();//define a basic class object
$versie->versieID = $aVersie->versieID();//fill it with the exact attributes as your complextype Object in the wsdl is
$versie->versieNummer = $aVersie->versieNummer();
$versie->isActief = $aVersie->isActief();     
    
$soapVersieType = new SoapVar($versie , SOAP_ENC_OBJECT, "Versie", "http://127.0.0.1:8999/SOAP?wsdl"); //create the complex soap type, Versie is the name of my complex type in the wsdl, the latter url beeing the location of my wsdl.
 
try{
 
$result $soapClient->BewaarVersie($this->sessieId,$soapVersieType); //BewaarVersie is a function derived from my WSDL with two params.
}
catch(
SoapFault $e){
 
trigger_error('Something soapy went wrong: '.$e->faultstring,E_USER_WARNING);            }
?>

After some more testing i found out that the conversion to the StdClass() object was not required. My 'Versie' local object has the attributes for the 'Versie' wsdl complex type defined as private vars and give no pain when i create the SoapVar with an instance of the local 'Versie' Object.
metator at netcabo dot pt
21-Oct-2005 08:32
You can use this method to correct the SOAP request before sending it, if necessary. You can use the DOM API to accomplish that.

<?php

public ExtendedClient extends SoapClient {

   function
__construct($wsdl, $options = null) {
     
parent::__construct($wsdl, $options);
   }

   function
__doRequest($request, $location, $action, $version) {
     
$dom = new DOMDocument('1.0');

      try {

        
//loads the SOAP request to the Document
        
$dom->loadXML($request);

      } catch (
DOMException $e) {
         die(
'Parse error with code ' . $e->code);
      }

     
//create a XPath object to query the request
     
$path = new DOMXPath($dom);

     
//search for a node
     
$nodesToFix = $path->query('//SOAP-ENV:Envelope/SOAP-ENV:Body/path/to/node');

     
//check if nodes are ok
     
$this->checkNodes($path, $nodesToFix);

     
//save the modified SOAP request
     
$request = $dom->saveXML();
     
     
//doRequest
     
return parent::__doRequest($request, $location, $action, $version);
   }

   function
checkNodes(DOMXPath $path, DOMNodeList $nodes) {
     
//iterate through the node list
     
for ($i = 0; $ < $nodes->length; $i++) {
        
$aNode = $nodes->item($i);

        
//just an example
        
if ($node->nodeValue == null) {
           
//do something. For instance, let's remove it.
           
$node->parentNode->removeChild($node);
         }
      }
   }
}
?>

This gives the developer the chance to solve interoperability problems with a web service.

SoapClient::__getFunctions> <SoapClient::__construct
Last updated: Fri, 13 Nov 2009
 
 
show source | credits | stats | sitemap | contact | advertising | mirror sites