Как да разменяте SOAP извиквания към cURL, за да работите в рамките на ограничението allow_url_fopen?

Наскоро имах проблем, при който SOAP извикванията към услугата ID3Global/адрес внезапно спряха да работят (преди това работеха добре). Вярвам, че има нещо общо с хостинг доставчика, който е изключил allow_url_fopen на нашия сървър, което сега означава, че услугата не работи.

Казаха ми, че ще трябва да премина към използване на cURL, за да взема файловете (WSDL), тъй като file_get_contents изисква 'allow_url_fopen' да бъде зададено във файла php.ini, за да работи това. Въпреки това изглежда не използвам file_get_contents в моя файл, за да получа WSDL файла.

Как мога да премина към използване на cURL?

Ето моя PHP файл, който извиква SOAP адрес:

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

$username = '[email protected]';
$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 );

Това се задейства с помощта на AJAX и ето файла JavaScript/jQuery:

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);
        }

    });

});

Преди това се опитах да превключа, използвайки следния код, за да взема WSDL файла, но не съм много сигурен какво друго трябва да направя с него:

$ch =  curl_init('https://id3global.com/ID3gWS/ID3global.svc?wsdl');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultSuper = curl_exec($ch);

person daniel blythe    schedule 17.04.2015    source източник
comment
Ако вашият хост направи такива драматични промени, без да ви предупреди предварително и да ви позволи да тествате на нови сървъри, бих помислил за смяна на хостове като важен приоритет.   -  person halfer    schedule 17.04.2015
comment
Благодаря, очакваме промяна доста скоро, но междувременно трябва да накараме тази услуга да работи отново. Имате ли някакви предложения как да използвате cURL в този файл gbgroup-address-lookup_2.php?   -  person daniel blythe    schedule 17.04.2015
comment
(Преместих вашия код във вашия въпрос - ние сме склонни да обезсърчаваме външните картони тук, тъй като връзките понякога се прекъсват и искаме въпросите да продължават).   -  person halfer    schedule 17.04.2015
comment
Това може да помогне - вижте коментара от meltir на meltir dot com. Разширете SoapClient и внедрите callCurl. Може да се наложи да го промените, тъй като вероятно нямате нужда от прокси функцията.   -  person halfer    schedule 17.04.2015
comment
Можете да използвате curl от командния ред, за да изтеглите отдалечения WSDL веднъж, след което да го запишете в папката на вашия проект. След това предайте името на локалния файл и пътя към SoapClient вместо нещо, започващо с http://.   -  person chugadie    schedule 22.04.2015
comment
Здравей Chugadie, благодаря за отговора. Ако щях да направя това, трябваше ли изобщо да използвам cURL? Не можех ли просто да запазя файла от браузъра си по някакъв начин? Освен това как ще работи, ако хората, доставящи уеб услугата, актуализират своя WSDL? Или казвате, че направете това само като тест, за да видите дали услугата все още работи?   -  person daniel blythe    schedule 22.04.2015
comment
ако изтеглите wsdl файла и го запишете някъде, не забравяйте да прехвърлите /full/path/to/the/wsdl/file, тъй като относителните пътища не работят   -  person Bob Nocraz    schedule 22.04.2015


Отговори (1)


Параметърът allow_url_fopen няма ефект върху начина, по който работи SOAP. Можете лесно да тествате това със следния скрипт:

<?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);

?>

Когато allow_url_fopen е активиран, ще видите следния изход:

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

Когато 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
SoapClient Object ( [trace] => 1 [_soap_version] => 1 [sdl] => Resource id #10 )

Забележете, че не се съобщава за SOAP грешка.

Причината за това поведение е следният код във файл ext/soap/php_xml.c в изходния код на PHP:

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

И така, allow_url_fopen е активиран за изтегляне на WSDL. Ако коментирате редовете по следния начин:

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

И компилирайте PHP с променения източник, ще видите следните резултати:

Активиран allow_url_fopen:

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

Деактивиран 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

Можете да видите, че този път имаме фатална SOAP грешка и че WSDL не може да бъде зареден. Наблюдавах това поведение с PHP 5.4.40 и PHP 5.6.8.

person VolenD    schedule 22.04.2015