This class works great in PHP 5.2 but in PHP 5.4 the __doRequest method in the private function callMethod returns NULL.

As a result the output of the script is "NULL SOAP RESPONSE".. Been banging my head against the wall all day trying to figure this out:mad:

__getLastRequestHeaders();
__getLastRequest();
__getLastResponseHeaders();

...are all empty despite having trace set to 1

Any ideas?

<?php
class ipm
{
    //BEGIN VARIABLES
    public $soapVersion;
    public $soapLocation;
    public $soapContext;
    public $soapParameters;
    public $soapClient;
    public $soapCookies;
    public $soapService;

const groupID = '104362395629'; //MAIN GROUP NUMBER WITHIN IPM, NEVER CHANGES
//END VARIABLES

//BEGIN CONSTRUCTOR
function __construct($soapService)
{
        $this->soapService = $soapService; //STATUS OR CONFIG
        $this->soapVersion = '1.2';
        $this->soapLocation = 'https://webservice.domain/soap/'.$this->soapService.'.asmx';
        $this->soapContext = stream_context_create(array('ssl' => array('verify_peer' => TRUE)));
        $this->soapParameters = array (
                                        'location' => $this->soapLocation,
                                        'login' => 'user',
                                        'password' => 'password',
                                        'stream_context' => $this->soapContext,
                                        'trace' => 1,
                                        'keep_alive' => 1,
                                        'cache_wsdl' => WSDL_CACHE_NONE
                                        );
        $this->soapClient = new SoapClient('./'.$this->soapService.'.wsdl',$this->soapParameters);
}
//END CONSTRUCTOR

//BEGIN PRIVATE FUNCTIONS
private function schemaOpen($fn='',$vars)
{
        $tmp = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">';

        if(empty($vars))
        {
        return $tmp.'<soap:Body><'.$fn.' xmlns="'.$this->schemaBase().'" />';
        }
        else
        {
        return $tmp.'<soap:Body><'.$fn.' xmlns="'.$this->schemaBase().'">';
        }

}
private function schemaClose($fn='',$vars)
{
        if(empty($vars))
        {
        return '</soap:Body></soap:Envelope>';
        }
        else
        {
        return '</'.$fn.'></soap:Body></soap:Envelope>';
        }

}
private function schemaBase($fn='')
{
        return 'http://schemas.ipmonitor.com/ipm70/'.$fn;
}
private function dumpDOMnodeList($xml)
{
        $docTmp = new DOMDocument();
        foreach($xml as $n) $docTmp->appendChild($docTmp->importNode($n,true));
        echo '<pre>';
        print_r(htmlentities($docTmp->saveHTML()));
        echo '</pre>';
}
private function debugSoap()
{
        echo '<pre>';
        echo $this->soapClient->__getLastRequestHeaders();
        echo $this->soapClient->__getLastRequest();
        echo $this->soapClient->__getLastResponseHeaders();
        echo '</pre>';
}
private function soapRequest($fn='',$vars=array())
{
        $xml=$this->schemaOpen($fn,$vars);
        foreach($vars as $key=>$val)
        {
                $xml .= '<'.$key.'>'.$val.'</'.$key.'>';
        }
        $xml.=$this->schemaClose($fn,$vars);

        return $xml;
}
private function callMethod($fn,$vars=array())
{
        $soapRequest = $this->soapRequest($fn,$vars);
        $soapAction  = $this->schemaBase($fn);

        $soapResponse =  $this->soapClient->__doRequest($soapRequest, $this->soapLocation, $soapAction, $this->soapVersion,0);
        $this->logSoap($soapRequest, $this->soapLocation, $soapAction, $this->soapVersion, $soapResponse,$this->debugSoap());

        return $soapResponse;

}
private function logSoap($request, $location, $action, $version, $reponse, $debug)
{
        file_put_contents('soap_log', date('m-d-Y H:i:s')."\r\nRequest: $request\r\n\r\nLocation: $location\r\nAction: $action\r\nVersion: $version\r\nResponse: $response\r\nDebug: $debug\r\n\r\n");
}
//END PRIVATE FUNCTIONS

//BEGIN METHODS
public function GetGroup($rtGroupID)
{
        /*
        GetGroup returns the status and some minor details about a specific Monitor.
        */

        return $this->callMethod(__FUNCTION__,array('id'=>$rtGroupID));
}
public function GetGroups()
{
        /*
        GetGroups returns the status of members and depends of a specific Group
        */

        return $this->callMethod(__FUNCTION__,array());
}
public function GetMonitors($rtGroupID)
{
        /*
        GetMonitor returns the status of the members and depends of a specific Group.
        */

        return $this->callMethod(__FUNCTION__,array('groupid'=>$rtGroupID,'bTroubleOnly'=>'TRUE'));
}
public function GetMonitor($rtMonitorID)
{
        /*
        GetMonitor returns the status and some minor details about a specific Monitor.
        */

        return $this->callMethod(__FUNCTION__,array('id'=>$rtMonitorID));
}
public function MonitorView($rtMonitorID)
{
        /*
        MonitorView retrieves an ipMonitor 7 Monitor objects's settings in xml format.
        */

        return $this->callMethod(__FUNCTION__,array('mon_id'=>$rtMonitorID));
}
public function GroupList()
{
        /*
        GroupList retrieves the ID's of all the existing Group objects.
        */

        return $this->callMethod(__FUNCTION__,array());
}
public function GroupView($rtGroupID)
{
        /*
        GroupView retrieves an ipMonitor 7 Group objects's settings in xml format.
        */

        return $this->callMethod(__FUNCTION__,array('groupid'=>$rtGroupID));
}
//END METHODS
}
/*  BEGIN GET ALL DOWN MONITORS  */
$ipm            = new ipm('status');
$ipmGroups      = $ipm->GetGroups();
if(!empty($ipmGroups))
{
    $doc = new DOMDocument();
    $doc->LoadXML($ipmGroups);
    $xpath = new DOMXpath($doc);
    $xpath->registerNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
    $xpath->registerNamespace('def', 'http://schemas.ipmonitor.com/ipm70/');
    $ipmGroupsAlarming = $xpath->query("/soap:Envelope/soap:Body/def:GetGroupsResponse/def:GetGroupsResult/def:rtGroup[(contains(def:status,'lost') or contains(def:status,'warn') or contains(def:status,'down')) and contains(def:isroot,'false')]");

$numGroupsAlarming = $ipmGroupsAlarming->length;
if($numGroupsAlarming === 0)
{
        echo 'No issues'."\r\n";
}
else
{
        unset($ipm,$ipmGroups,$doc,$xpath,$numGroupsAlarming);
        foreach($ipmGroupsAlarming as $ipmGroupAlarming)
        {
                $groupName              = $ipmGroupAlarming->getElementsByTagName('name')->item(0)->nodeValue;
                $groupStatus    = $ipmGroupAlarming->getElementsByTagName('status')->item(0)->nodeValue;
                $groupID                = $ipmGroupAlarming->getElementsByTagName('id')->item(0)->nodeValue;

                echo $groupName.'<br/>'."\r\n";

                $ipm            = new ipm('status');
                $ipmMonitors= $ipm->GetMonitors($groupID);

                $doc = new DOMDocument();
                $doc->LoadXML($ipmMonitors);
                $xpath = new DOMXpath($doc);
                $xpath->registerNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
                $xpath->registerNamespace('def', 'http://schemas.ipmonitor.com/ipm70/');
                $ipmMonitorsAlarming = $xpath->query("/soap:Envelope/soap:Body/def:GetMonitorsResponse/def:GetMonitorsResult/def:rtMonitor");

                $numMonitorsAlarming = $ipmMonitorsAlarming->length;
                if($numMonitorsAlarming === 0)
                {
                        echo 'No Monitors Down Under This Device<br/>'."\r\n";
                }
                else
                {
                        foreach($ipmMonitorsAlarming as $ipmMonitorAlarming)
                        {
                                $monitorName    = $ipmMonitorAlarming->getElementsByTagName('name')->item(0)->nodeValue;
                                $monitorStatus  = $ipmMonitorAlarming->getElementsByTagName('status')->item(0)->nodeValue;
                                $monitorID              = $ipmMonitorAlarming->getElementsByTagName('id')->item(0)->nodeValue;

                                echo '--&gt; '.$monitorStatus.' - '.$monitorName.'<br/>'."\r\n";
                        }
                }
                unset($ipm,$ipmMonitors,$doc,$xpath,$numMonitorsAlarming,$ipmMonitorsAlarming);
                echo '<br/>';
        }
}
}
elseif($ipmGroups == NULL) {echo 'NULL SOAP RESPONSE';}
else
{
echo 'No issues'."\r\n";
}
/*  END GET ALL DOWN MONITORS  */
?>

    So for whatever reason when I came in this morning, the soap logger on the PHP 5.4 server magically started giving details... I will output the debug from both...

    The only difference I see is that on the 5.2 server, the authentication is digest and on the 5.4 server the authentication is basic (yet the code is the same?)

    That and there is no "response" back from the server where as 5.2 gives an HTTP 200/OK

    PHP 5.4 debug:

    Request: <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body><GetGroups xmlns="http://schemas.ipmonitor.com/ipm70/" /></soap:Body>
    </soap:Envelope>
    
    Location: https://webservice.domain/soap/status.asmx
    Action: http://schemas.ipmonitor.com/ipm70/GetGroups
    Version: 1.2
    Response:
    Debug: POST /soap/status.asmx HTTP/1.1
    Host: webservice.domain
    Connection: Keep-Alive
    User-Agent: PHP-SOAP/5.4.17
    Content-Type: text/xml; charset=utf-8
    SOAPAction: "http://schemas.ipmonitor.com/ipm70/GetGroups"
    Content-Length: 303
    Authorization: Basic blah blah blah
    

    PHP 5.2 debug:

    Request: <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body><GetGroups xmlns="http://schemas.ipmonitor.com/ipm70/" /></soap:Body>
    </soap:Envelope>
    
    Location: https://webservice.domain/soap/status.asmx
    Action: http://schemas.ipmonitor.com/ipm70/GetGroups
    Version: 1.2
    Response: <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>...</soap:Body></soap:Envelope>
    Debug: POST /soap/status.asmx HTTP/1.1
    Host: webservice.domain
    Connection: Keep-Alive
    User-Agent: PHP-SOAP/5.2.10
    Content-Type: text/xml; charset=utf-8
    SOAPAction: "http://schemas.ipmonitor.com/ipm70/GetGroups"
    Content-Length: 303
    Authorization: Digest username="usename", realm="ipMonitor@ipmonitor.com" ...
    
    HTTP/1.0 200 ok
    Server: ipMonitor 10.6
    Content-Type: text/xml; charset=utf-8
    Date: Thu, 16 Jan 2014 12:31:23 GMT
    Connection: Keep-Alive
    Content-Length: 99492
    

    If I try setting:

    'authentication' => SOAP_AUTHENTICATION_DIGEST,
    

    ...then the debug is void of the "authorization" line entirely.

      You might try having your script print all the parameters for the __doRequest method; some of them may be being passed by reference, and that behavior may have changed.

      Just a thought ...

        dale,

        thanks for the reply, this already being done via:

        $this->logSoap($soapRequest, $this->soapLocation, $soapAction, $this->soapVersion, $soapResponse,$this->debugSoap());

        $this->debugSoap() includes:

        $this->soapClient->getLastRequestHeaders();
        $this->soapClient->
        getLastRequest();
        $this->soapClient->__getLastResponseHeaders();

        My last post was the resultant of logSoap on both the 5.2 and 5.4 server... It's every piece of information available to me

          Actually, an additional piece of info, when I go to the webservice path via lynx, i'm getting:

          Show the 401 message body? (y/n)

          401 is unauthorized... I figure lynx would ask for a username and password...

          That being said, this is the same behaviour I see on both the 5.2 and 5.4 server and might just be related to lynx not being able to prompt for a login

            I have no idea what differences exist between 5.2 and 5.4.

            The first thing I'd try is to send the exact same request from 5.4 (server) that you do from 5.2 As in use curl, set the same headers and send the same xml. Success?

            Secondly, I'm guessing certificates are involved because of your ssl context. Do both servers have and use valid certificates?

            Thirdly, I have read something about possibly needing to prefetch the wsdl document because soap authentication doesn't come into play until after the wsdl document has been fetched and the actual soap calls are being made. But the only way I can see this being meaningful is if the implementation of soap client changed regarding this from 5.2 to 5.4 and I do not find it all too likely. Still, who knows.

            Also, would it be possible to get a separate php 5.4 on your 5.2 server and try sending the request using 5.4 from the 5.2 server. Perhaps that would actually shed some light on if it's the php versions that differ or your server environments?

              John,

              I'm using local WSDL's on my calls. I went so far as to re-download them and disable WSDL caching but no luck there either...

              If I try to reach the remote wsdl via lynx, e.g status.asmx?wsdl, I get the same thing, 401.

              If I fudge the path to say statusss.asmx I get a 404 so I'm reaching the server.

              I am able to rebuild PHP on the fly on this server... When its running 5.2 no issues, when its running 5.4 (same server) issues...

              Unfortunately the server providing the web service (ip monitor by Solarwinds) has zero logging or debug for the soap API and forget looking at thwack, it's a dead end.

              I haven't tried with curl yet but I guess I might just have too 🙁

                No go with curl 🙁

                <?php
                	//Data, connection, auth
                	$soapUrl = "https://webservice.domain/soap/status.asmx?wsdl"; // asmx URL of WSDL
                	$soapUser = "username";  //  username
                	$soapPassword = "password"; // password
                
                // xml post structure
                
                $xml_post_string = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetGroups xmlns="http://schemas.ipmonitor.com/ipm70/" /></soap:Body></soap:Envelope>';
                
                $headers = array(
                            "Content-type: text/xml;charset=\"utf-8\"",
                            "Accept: text/xml",
                            "Cache-Control: no-cache",
                            "Pragma: no-cache",
                            "SOAPAction: http://schemas.ipmonitor.com/ipm70/GetGroups",
                            "Content-length: ".strlen($xml_post_string),
                        ); //SOAPAction: your op URL
                
                $url = $soapUrl;
                
                // PHP cURL  for https connection with auth
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_USERPWD, $soapUser.":".$soapPassword); // username and password - declared at the top of the doc
                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
                curl_setopt($ch, CURLOPT_TIMEOUT, 10);
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); // the SOAP request
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
                
                // converting
                $response = curl_exec($ch);
                echo '<pre>';
                print_r(curl_getinfo($ch));
                curl_close($ch);
                
                // converting
                $response1 = str_replace("<soap:Body>","",$response);
                $response2 = str_replace("</soap:Body>","",$response1);
                
                // convertingc to XML
                echo $parser = simplexml_load_string($response2);
                // user $parser to get your data out of XML response and to display it.
                   ?>
                
                Array
                (
                    [url] => https://webservice.domain/soap/status.asmx?wsdl
                    [content_type] => 
                    [http_code] => 0
                    [header_size] => 0
                    [request_size] => 554
                    [filetime] => -1
                    [ssl_verify_result] => 0
                    [redirect_count] => 0
                    [total_time] => 0.033172
                    [namelookup_time] => 0.002885
                    [connect_time] => 0.003412
                    [pretransfer_time] => 0.032178
                    [size_upload] => 303
                    [size_download] => 0
                    [speed_download] => 0
                    [speed_upload] => 9134
                    [download_content_length] => -1
                    [upload_content_length] => 303
                    [starttransfer_time] => 0.033113
                    [redirect_time] => 0
                    [certinfo] => Array
                        (
                        )
                
                [primary_ip] => x.x.x.x
                [primary_port] => 443
                [local_ip] => x.x.x.x
                [local_port] => 33051
                [redirect_url] => 
                )
                

                  OK, I got curl to work, but only by going to HTTP on port 8080...

                  Same thing for the class, only works on port 8080 no HTTPS.

                  I'm using a valid SSL from GlobalSign and the webservice server has the CA and roots installed.

                  WTF wierd.

                    Any thoughts why it wouldn't work with SSL with curl and soap but via a web browser i am prompted for and can successfully authenticate?

                      I would inspect each and every request and response, both headers and bodies. If you do that both with your browser of choice and using curl and compare the them, there are bound to be differences.

                        Write a Reply...