Royal Mail Shipping API - SOAP-соединение и запрос pem / сертификата

Я пытаюсь настроить API Royal Mail Shipping (если у кого-то есть подобный опыт, я был бы признателен, если бы вы могли помочь).

В документации, которую они предоставляют, мне нужно скачать сертификат (файл .p12) и импортировать его на мой компьютер с Windows - это довольно просто, используя «Мастер импорта сертификатов». Как только он достигнет «Установить уровень безопасности», я должен выбратьВысоко & это будет запрашивать разрешение с паролем каждый раз, когда это используется.

В Internet Explorer в «Свойствах обозревателя» на вкладке «Содержимое» я могу просмотреть сертификаты и четко видеть, что этот сертификат был импортирован и срок его действия не истек.

Следующим шагом являетсяизвлечь компоненты сертификатаЗдесь я должен выполнить три следующие команды, используя OpenSSL для генерации файлов .pem.

$ openssl pkcs12 -in mycert.p12 -cacerts -nokeys -out cacert.pem
$ openssl pkcs12 -in mycert.p12 -clcerts -nokeys -out mycert.pem
$ openssl pkcs12 -in mycert.p12 -nocerts -nodes -out mykey.pem 

В документации говоритсяФайл cacert.pem может напрямую ссылаться приложением, используя сам файлЯ полагаю, что это было сделано в моем PHP-скрипте, но не ясно, куда мне поместитьmycert & mykey pem файлы.

В документации говорится следующее:

То, как приложение передает выданный клиентский SSL-сертификат при установлении сетевого SSL-подключения, зависит от приложения и среды, но по существу ему потребуется доступ как к файлам «mycert.pem» и «mykey.pem», так и в некоторых случаях к одному объединенный файл, содержащий как сертификат, так и ключ.

Так что нигде не сказано, как эти два файла используются приложением, на данный момент я просто оставил их в том же каталоге, что и файл cacert.pem.

Если я пытаюсь получить доступ к URLhttps://api.royalmail.com/shipping/onboarding прямо из браузера он запрашивает у меня сертификат, я выбираю его и затем вводу правильный пароль, когда он запрашивает «Предоставить или отказать в разрешении использовать этот ключ». Как только я ввожу правильный пароль, появляется следующая страница - может ли кто-нибудь подтвердить, будет ли это означать, что проблема на моем конце или что-то, что Royal Mail не настроило правильно с их стороны.

В дополнение к этому, реальный PHP-скрипт, который у меня есть, используется для отправки SOAP-запросов в API доставки, не работает (вероятно, относится ко всему вышеописанному).

В моем PHP-скрипте параметры soapclient настроены следующим образом:

$soapclient_options['cache_wsdl'] = 'WSDL_CACHE_NONE'; 
$soapclient_options['local_cert'] = 'certs/cacert.pem';
$soapclient_options['passphrase'] = $api_certificate_passphrase;
$soapclient_options['trace'] = true;
$soapclient_options['ssl_method'] = 'SOAP_SSL_METHOD_SSLv3';
$soapclient_options['location'] = 'https://api.royalmail.com/shipping/onboarding';

$client = new SoapClient('SAPI/ShippingAPI_V2_0_8.wsdl', $soapclient_options);
$client->__setLocation($soapclient_options['location']);

Когда я запускаю скрипт PHP (это в основном тот же код, который Royal Mail предоставляет для себя со своими личными данными для входа в API), в браузере появляется следующее сообщение:

Could not connect to host 
REQUEST: [email protected] rngfJ+4dt4Gt855a5pr6u38i3B4= ODcwMTE5Nzc3 2015-10-13T11:02:20Z 2015-10-13T11:02:201.00526348001DeliveryDSD12015-10-13bobSS23, Some AvenueLondonE10g1000000

Очевидно, что это не может соединиться с хостом по неизвестной причине, последняя - просто запрос, который был отправлен. Остальная часть сценария PHP точно такая же, как и сценарий Royal Mail, который они мне отправили и подтвердили, что он используется другими и работает нормально.

Я работаю в среде WAMP, хотя возможный код будет в среде Linux.Может ли кто-нибудь помочь Я действительно сбит с толку, и сами Royal Mail еще не смогли оказать серьезную техническую поддержку.

ОБНОВИТЬ

Это полное сообщение об ошибке, отображаемое в браузере (я изменил адрес электронной почты в целях безопасности)

Invalid Request REQUEST: [email protected] dgCW98Vqw3ladYgPPpNialODhvI= MTMzMjE1NjM4 2015-10-13T13:25:30Z 2015-10-13T13:25:302.00526348001DeliveryDSD12015-10-13Jon DoeSS23, Some RoadLondonE10g1000000

Я объединил два файла pem в один файл с именем bundle.pem и сослался на это в переменной local_cert для SoapClient & BINGO, к которому он теперь подключается. Это теперь дольше показываетНе может подключиться но вместо этого выдает «Неверный запрос», так что, по крайней мере, теперь он соединяется и выдает мне другую ошибку.

Весь мой PHP-скрипт ниже:

<?php

ini_set('default_socket_timeout', 120);
ini_set('soap.wsdl_cache_enabled',1);
ini_set('soap.wsdl_cache_ttl',1);

$api_password = "xxxxxxxxxxxxxx!";
$api_username = "[email protected]";
$api_application_id = "xxxxxxxxxxxx";
$api_service_type = "D";
$api_service_code = "SD1";
$api_service_format = "";
$api_certificate_passphrase = 'xxxxxxxxxx';
$api_service_enhancements = "";

$data = new ArrayObject();
$data->order_tracking_id = "";
$data->shipping_name = "Jon Doe";
$data->shipping_company = "SS";
$data->shipping_address1 = "23, Some Road"; 
$data->shipping_address2 = "";
$data->shipping_town = "London";
$data->shipping_postcode = "E1";
$data->order_tracking_boxes = "0";
$data->order_tracking_weight = "1000";    

$time = gmdate('Y-m-d\TH:i:s');
$created = gmdate('Y-m-d\TH:i:s\Z');
$nonce = mt_rand();
$nonce_date_pwd = pack("A*",$nonce) . pack("A*",$created) . pack("H*", sha1($api_password));
$passwordDigest = base64_encode(pack('H*',sha1($nonce_date_pwd)));
$ENCODEDNONCE = base64_encode($nonce);


$soapclient_options = array(); 
$soapclient_options['cache_wsdl'] = 'WSDL_CACHE_NONE'; 
$soapclient_options['local_cert'] = 'royalmail/cert/bundle.pem';
$soapclient_options['passphrase'] = $api_certificate_passphrase;
$soapclient_options['trace'] = true;
$soapclient_options['ssl_method'] = 'SOAP_SSL_METHOD_SSLv3';
$soapclient_options['exceptions'] = true;
$soapclient_options['location'] = 'https://api.royalmail.com/shipping/onboarding';

//launch soap client
$client = new SoapClient('royalmail/ShippingAPI_V2_0_8.wsdl', $soapclient_options);
$client->__setLocation($soapclient_options['location']);

//headers needed for royal mail
$HeaderObjectXML  = '<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                      xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
           <wsse:UsernameToken wsu:Id="UsernameToken-000">
              <wsse:Username>'.$api_username.'</wsse:Username>
              <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$passwordDigest.'</wsse:Password>
              <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.$ENCODEDNONCE.'</wsse:Nonce>
              <wsu:Created>'.$created.'</wsu:Created>
           </wsse:UsernameToken>
       </wsse:Security>';

//push the header into soap
$HeaderObject = new SoapVar( $HeaderObjectXML, XSD_ANYXML );

//push soap header
$header = new SoapHeader( 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Security', $HeaderObject );
$client->__setSoapHeaders($header);

//build the request
$request = array(
    'integrationHeader' => array(
        'dateTime' => $time,
        'version' => '1.0',
        'identification' => array(
            'applicationId' => $api_application_id,
            'transactionId' => $data->order_tracking_id
        )
    ),
    'requestedShipment' => array(
                                'shipmentType' => array('code' => 'Delivery'),
                                'serviceOccurence' => '1',
                                'serviceType' => array('code' => $api_service_type),
                                'serviceOffering' => array('serviceOfferingCode' => array('code' => $api_service_code)),
                                'serviceFormat' => array('serviceFormatCode' => array('code' => $api_service_format)),
                                'shippingDate' => date('Y-m-d'),
                                'recipientContact' => array('name' => $data->shipping_name, 'complementaryName' => $data->shipping_company),
                                'recipientAddress' => array('addressLine1' => $data->shipping_address1,  'addressLine2' => $data->shipping_address2, 'postTown' => $data->shipping_town, 'postcode' => $data->shipping_postcode),
                                'items' => array('item' => array(
                                            'numberOfItems' => $data->order_tracking_boxes,
                                            'weight' => array( 'unitOfMeasure' => array('unitOfMeasureCode' => array('code' => 'g')), 'value' => ($data->order_tracking_weight*1000) //weight of each individual item
                                                             )
                                                                )
                                                )
                                )               
);


//if any enhancements, add it into the array
if($api_service_enhancements != "") {
    $request['requestedShipment']['serviceEnhancements'] = array('enhancementType' => array('serviceEnhancementCode' => array('code' => $api_service_enhancements)));
}

//try make the call
try { 
    $response = $client->__soapCall( 'createShipment', array($request), array('soapaction' => 'https://api.royalmail.com/shipping/onboarding') );
} catch (Exception $e) {
    //catch the error message and echo the last request for debug
    echo $e->getMessage(); 
    echo " REQUEST:\n" . $client->__getLastRequest() . "\n";
    die;
}

//check for any errors
if(isset($response->integrationFooter->errors)) { 
    $build = "";

    //check it wasn't a single error message
    if(isset($response->integrationFooter->errors->error->errorCode)) { 
        $build .= $output_error->errorCode.": ".$output_error->errorDescription."<br/>"; 
    } else {
        //loop out each error message, throw exception will be added ehre
        foreach($response->integrationFooter->errors->error as $output_error) { 
            $build .= $output_error->errorCode.": ".$output_error->errorDescription."<br/>";
        }
    }

    echo $build; die;

}

print_r($response);

echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
die;            
?>

Просто для большей ясности я добавил дамп переменной $ request непосредственно перед тем, как она достигнет блока try / catch (обратите внимание, это довольно долго).

Array
(
    [integrationHeader] => Array
        (
        [dateTime] => 2015-10-13T13:34:44
        [version] => 1.0
        [identification] => Array
            (
                [applicationId] => 0526348001
                [transactionId] => 
            )

    )

[requestedShipment] => Array
    (
        [shipmentType] => Array
            (
                [code] => Delivery
            )

        [serviceOccurence] => 1
        [serviceType] => Array
            (
                [code] => D
            )

        [serviceOffering] => Array
            (
                [serviceOfferingCode] => Array
                    (
                        [code] => SD1
                    )

            )

        [serviceFormat] => Array
            (
                [serviceFormatCode] => Array
                    (
                        [code] => 
                    )

            )

        [shippingDate] => 2015-10-13
        [recipientContact] => Array
            (
                [name] => Jon Doe
                [complementaryName] => SS
            )

        [recipientAddress] => Array
            (
                [addressLine1] => 23, Some Road
                [addressLine2] => 
                [postTown] => London
                [postcode] => E1
            )

        [items] => Array
            (
                [item] => Array
                    (
                        [numberOfItems] => 0
                        [weight] => Array
                            (
                                [unitOfMeasure] => Array
                                    (
                                        [unitOfMeasureCode] => Array
                                            (
                                                [code] => g
                                            )

                                    )

                                [value] => 1000000
                            )

                    )

            )

    )

)

Ответы на вопрос(2)

Ваш ответ на вопрос