12

I've recently had a problem where the SOAP calls to the ID3Global/address service suddenly stopped working(they previously worked fine). I believe it has something to do with the hosting provider turning off allow_url_fopen on our server which now means the service doesn't work.

I've been told I'll need to switch to using cURL to grab the files (WSDL) as file_get_contents requires 'allow_url_fopen' to be set in the php.ini file for this to work. However I don't seem to be using file_get_contents in my file to get the WSDL file.

How can I to switch to using cURL?

Here's my PHP file making the SOAP address call:

<?php
ini_set("soap.wsdl_cache_enabled", "0");

$username = 'xxxxxxx@xxxxxxxx.com';
$password = 'xxxxxxx';

$profile_id = 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx';

// Live WSDL
$wsdl = 'https://id3global.com/ID3gWS/ID3global.svc?wsdl';

$postcode = $_POST['ZipPostcode'];

/**
 * Method to arrange the address into a sane
 * order for displaying back to the user
 *
 * @param $item
 * @param $key
 * @internal param $address
 */
function sortAddress(&$item, $key)
{
    // Convert the object to an array
    $address = (array) $item;

    // Reorder the address lines
    $addressLines = array(
        'Company' => $address['Company'],
        'Building' => $address['Building'],
        'SubBuilding' => $address['SubBuilding'],
        'Premise' => $address['Premise'],
        'SubStreet' => $address['SubStreet'],
        'Street' => $address['Street'],
        'City' => $address['City'],
        'StateDistrict' => $address['StateDistrict'],
        'ZipPostcode' => $address['ZipPostcode'],
        'Country' => $address['Country'],
    );

   // Remove blank address lines
   // $item = array_filter($addressLines);
   $item = $addressLines;

}

class clsWSSEAuth { 
    private $Username; 
    private $Password;  
    function __construct($username, $password) { 
        $this->Username=$username; 
        $this->Password=$password; 
    } 
} 

class clsWSSEToken { 
    private $UsernameToken; 
    function __construct ($UsernameToken){ 
        $this->UsernameToken = $UsernameToken; 
    } 
} 

$strWSSENS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; 

//Auth
$objSoapVarUser = new SoapVar($username, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS); 
$objSoapVarPass = new SoapVar($password, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS); 
$objWSSEAuth = new clsWSSEAuth($objSoapVarUser, $objSoapVarPass); 

//Token
$objSoapVarWSSEToken = new SoapVar($objWSSEAuth, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS); 
$objWSSEToken = new clsWSSEToken($objSoapVarWSSEToken); 

//Header
$objSoapVarWSSEAuth = new SoapVar($objWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS); 
$objSoapVarHeaderVal = new SoapVar($objSoapVarWSSEAuth, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'Security', $strWSSENS); 
$objSoapVarWSSEHeader = new SoapHeader($strWSSENS, 'Security', $objSoapVarHeaderVal, true); 

//Client
$client = new SoapClient($wsdl, array(
    'soap_version' => SOAP_1_1, 
    'trace' => 1, 
    'exception' => true, 
)); 

$client->__setSoapHeaders($objSoapVarWSSEHeader);

$results = $client->AddressLookup(array(
    'InputData' => array('ZipPostcode' => strtoupper($postcode)),
));

$addresses = $results->AddressLookupResult->GlobalAddress;


array_walk($addresses, 'sortAddress');
//var_dump($addresses);

echo json_encode( $addresses );

This is triggered using AJAX and here's the JavaScript/jQuery file:

jQuery(document).ready(function($) {

    var addresses = [];

    $("body").on('click', '.find-address', function(e){
        e.preventDefault();
        url = '/wp-content/themes/Cornhill/gbgroup-address-lookup_2.php';
        postode_id = $(this).data('postcode');
        address_id = $(this).data('address');
        postcode = $('#'+postode_id).val();
        console.log('Stage 1');

        if (postcode != '')
        {
            var addressList = $('#'+address_id);
            addressList.find('option').remove();
            opt = $('<option>').html('Loading...');
            opt.val('');
            addressList.append(opt);
            console.log('stage 2');

            $.ajax({
                url: url,
                dataType: 'json',
                type: 'post',
                data: {
                    'ZipPostcode': postcode
                },
                success: function(response){
                    addressList.find('option').remove();
                    addresses[address_id] = response;

                    opt = $('<option>').html('Please select');
                    opt.val('');
                    addressList.append(opt);

                    for(x=0; x<addresses[address_id].length; x++){

                        addressArray = new Array();
                        addressArray.push(addresses[address_id][x].Building);
                        addressArray.push(addresses[address_id][x].Street);
                        addressArray.push(addresses[address_id][x].City);
                        addressArray.push(addresses[address_id][x].ZipPostcode);

                        addressString = addressArray.join(', ');

                        opt = $('<option>').attr('value', x);
                        opt.html(addressString);

                        addressList.append(opt);
                    }
                }
            });
        }
        else
        {
            return;
        }
    });

    $("body").on('change', '.select-address', function(){
        address_id = $(this).attr('id');
        street_id = $(this).data('street');
        town_id = $(this).data('town');
        postcode_id = $(this).data('postcode');

        value = $(this).val();
        if(value != ''){
            address = addresses[address_id][value];

            if (address.Building != '')
            {
                $('#'+street_id).val(address.Building+' '+address.Street);
            }
            else
            {
                $('#'+street_id).val(address.Street);
            }
            $('#'+town_id).val(address.City);
            $('#'+postcode_id).val(address.ZipPostcode);
        }

    });

});

I've previously tried switching using the following code to grab the WSDL file but am not really sure what else I'm supposed to do with it:

$ch =  curl_init('https://id3global.com/ID3gWS/ID3global.svc?wsdl');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultSuper = curl_exec($ch);
halfer
  • 19,824
  • 17
  • 99
  • 186
daniel blythe
  • 946
  • 2
  • 16
  • 44
  • If your host makes such dramatic changes without giving advance warning and letting you test on new servers, I would consider changing hosts as a significant priority. – halfer Apr 17 '15 at 09:28
  • Thanks, we are looking to change pretty soon but in the mean time we need to get this service working again. Do you have any suggestions on how to use cURL in that gbgroup-address-lookup_2.php file? – daniel blythe Apr 17 '15 at 09:32
  • (I've moved your code into your question - we tend to discourage external pasteboards here, as the links sometimes break, and we like questions to last). – halfer Apr 17 '15 at 09:44
  • [This might help](https://php.net/manual/en/soapclient.soapclient.php#97029) - see the comment from "meltir at meltir dot com". Extend `SoapClient` and implement `callCurl`. You may need to tweak it, as you presumably don't need the proxy feature. – halfer Apr 17 '15 at 10:05
  • You can use curl from the command line to download the remote WSDL once, then save it to your project's folder. Then pass the local file name and path to SoapClient instead of something starting with "http://". – chugadie Apr 22 '15 at 14:06
  • Hi Chugadie, thanks for the reply. If I was going to do this would I need to use cURL at all? Couldn't I just save the file from my browser somehow? Also how would it work if the people supplying the web service updated their WSDL? Or are you saying do this just as a test to see if the service still works? – daniel blythe Apr 22 '15 at 14:25
  • if you download the wsdl file and save it somewhere, make sure to pass the /full/path/to/the/wsdl/file as relative paths don't work – Bob Nocraz Apr 22 '15 at 16:03

1 Answers1

4

The parameter allow_url_fopen has no effect on the way that SOAP works. You can easily test this with the following script:

<?php

echo "allow_url_fopen status is: " . ini_get('allow_url_fopen') . "\n";

$wsdl = 'https://id3global.com/ID3gWS/ID3global.svc?wsdl';

file_get_contents($wsdl);

$client = new SoapClient($wsdl, array(
    'soap_version' => SOAP_1_1,
    'trace' => 1,
    'cache_wsdl' => WSDL_CACHE_NONE, // this is important for the purpose of the test
    'exception' => true,
));

print_r($client);

?>

When allow_url_fopen is enabled, you will see the following output:

allow_url_fopen status is: 1 SoapClient Object ( [trace] => 1 [_soap_version] => 1 [sdl] => Resource id #11 )

When allow_url_fopen is disabled, you will see the following output:

allow_url_fopen status is: 0 
Warning: file_get_contents(): https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in /var/www/test.php on line 9

Warning: file_get_contents(https://id3global.com/ID3gWS/ID3global.svc?wsdl): failed to open stream: no suitable wrapper could be found in /var/www/test.php on line 9
SoapClient Object ( [trace] => 1 [_soap_version] => 1 [sdl] => Resource id #10 )

Notice that no SOAP error is reported.

The reason for this behaviour is the following code in file ext/soap/php_xml.c in PHP's source:

old_allow_url_fopen = PG(allow_url_fopen);
PG(allow_url_fopen) = 1;
ctxt = xmlCreateFileParserCtxt(filename);
PG(allow_url_fopen) = old_allow_url_fopen;

So, allow_url_fopen is enabled for the WSDL download. If you comment the lines as follows:

/* old_allow_url_fopen = PG(allow_url_fopen);
PG(allow_url_fopen) = 1; */
ctxt = xmlCreateFileParserCtxt(filename);
/* PG(allow_url_fopen) = old_allow_url_fopen; */

And compile PHP with the changed source, you will see the following results:

Enabled allow_url_fopen:

allow_url_fopen status is: 1 SoapClient Object ( [trace] => 1 [_soap_version] => 1 [sdl] => Resource id #11 )

Disabled allow_url_fopen:

allow_url_fopen status is: 0 
Warning: file_get_contents(): https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in /var/www/test.php on line 9

Warning: file_get_contents(https://id3global.com/ID3gWS/ID3global.svc?wsdl): failed to open stream: no suitable wrapper could be found in /var/www/test.php on line 9

Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://id3global.com/ID3gWS/ID3global.svc?wsdl' : failed to load external entity "https://id3global.com/ID3gWS/ID3global.svc?wsdl" in /var/www/test.php:16 Stack trace: #0 /var/www/test.php(16): SoapClient->SoapClient('https://id3glob...', Array) #1 {main} thrown in /var/www/test.php on line 16

You can see that this time we have fatal SOAP error and that the WSDL cannot be loaded. I observed this behaviour with PHP 5.4.40 and PHP 5.6.8.

VolenD
  • 3,592
  • 18
  • 23