Discussion:
PHP SoapClient cannot generate valid soap request
Adam Tong
2014-04-19 18:00:16 UTC
Permalink
Hi,

Below you will find my PHP script and a valid request generated by a soap
software.

I cannot figure out what I am doing wrong in the php script. Maybe it is
the array of elements that is wrong. Please help.

Thanks

PHP script:
-----------------
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$soapClient = new SoapClient("
https://webservices.rrts.com/rating/ratequote.asmx?WSDL", array('trace' =>
1));
$ns = 'https://webservices.rrts.com/ratequote/';
$headerBody = array(
'UserName' => "*************"
, 'Password' => "***************"
, 'Site' => "******************"
);
$header = new SOAPHeader($ns, 'AuthenticationHeader', $headerBody);
$soapClient->__setSoapHeaders($header);

$args=array(
'OriginZip' => 18106
,'DestinationZip' => 91752
,'ShipmentDetails' => array(
'ActualClass' => 50
,'Weight' => 1200
)
,'OriginType' => 'O'
,'PaymentType' => 'P'
,'COD' => array(
'Prepaid' => true
,'CODAmount' => 1200.00
)
);

try {
$results = $soapClient->__soapCall("RateQuote", array($args));
}
catch (Exception $ex) {
var_dump($ex->getMessage());
var_dump($soapClient->__getLastRequest());
var_dump($soapClient->__getLastResponse());
}


Valid request generated by soap software
-----------------------------------------------------------
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:rat="https://webservices.rrts.com/ratequote/">
<soap:Header>
<rat:AuthenticationHeader>
<!--Optional:-->
<rat:UserName>xxxxx</rat:UserName>
<!--Optional:-->
<rat:Password>xxxxx</rat:Password>
<!--Optional:-->
<rat:Site>xxxxxx</rat:Site>
</rat:AuthenticationHeader>
</soap:Header>
<soap:Body>
<rat:RateQuote>
<!--Optional:-->
<rat:request>
<!--Optional:-->
<rat:OriginZip>18106</rat:OriginZip>
<!--Optional:-->
<rat:DestinationZip>91752</rat:DestinationZip>
<!--Optional:-->
<rat:ShipmentDetails>
<!--Zero or more repetitions:-->
<rat:ShipmentDetail>
<rat:ActualClass>50</rat:ActualClass>
<rat:Weight>1200</rat:Weight>
</rat:ShipmentDetail>
</rat:ShipmentDetails>
<!--Optional:-->
<rat:OriginType>O</rat:OriginType>
<!--Optional:-->
<rat:PaymentType>P</rat:PaymentType>

<rat:COD>
<rat:Prepaid>true</rat:Prepaid>
<rat:CODAmount>1200.00</rat:CODAmount>
</rat:COD>
</rat:request>
</rat:RateQuote>
</soap:Body>
</soap:Envelope>
Robert Williams
2014-04-20 18:52:10 UTC
Permalink
Post by Adam Tong
Below you will find my PHP script and a valid request generated by a soap
software.
It would be helpful if you could also show us the output from your var_dump() calls.
Post by Adam Tong
I cannot figure out what I am doing wrong in the php script. Maybe it is
the array of elements that is wrong. Please help.
I think you may be missing a couple of wrapper arrays; try this:

$args = array(
‘request’ => array(
'OriginZip' => 18106,
'DestinationZip' => 91752,
'ShipmentDetails' => array(
'ShipmentDetail' => array(
'ActualClass' => 50,
'Weight' => 1200,
),
),
'OriginType' => 'O',
'PaymentType' => 'P',
'COD' => array(
'Prepaid' => true,
'CODAmount' => 1200.00,
),
),
);

You might also need to put the value of Prepaid into quotes (i.e., make it the string “true” instead of a boolean), depending on what the service is expecting.

If that doesn’t work, send us the var_dump() output, especially from the __getLastRequest() call, as it’s much easier to see where things are going wrong when you can see exactly what’s currently being passed and compare it against the known-correct XML from the SOAP utility.

As a tip, calling the service methods directly, instead of via __soapCall(), may be easier to read:

$results = $soapClient->RateQuote(...);

Also, I will often create a new class that extends SoapClient, then use @method phpDocumentor tags to document the service methods I’ll be using. Doing this enables the IDE to support features like code completion, among other benefits.


--
Bob Williams
SVP, Software Development
Newtek Business Services, Inc.
“The Small Business Authority”
http://www.thesba.com/


Notice: This communication, including attachments, may contain information that is confidential. It constitutes non-public information intended to be conveyed only to the designated recipient(s). If the reader or recipient of this communication is not the intended recipient, an employee or agent of the intended recipient who is responsible for delivering it to the intended recipient, or if you believe that you have received this communication in error, please notify the sender immediately by return e-mail and promptly delete this e-mail, including attachments without reading or saving them in any manner. The unauthorized use, dissemination, distribution, or reproduction of this e-mail, including attachments, is prohibited and may be unlawful. If you have received this email in error, please notify us immediately by e-mail or telephone and delete the e-mail and the attachments (if any).
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Adam Tong
2014-04-21 06:24:08 UTC
Permalink
Hi Robert,

Thank you for taking the time to look into this. Unfortunately it is still
not working.
Regarding the prepaid parameter I tried both the boolean and the string
value of true. In the wsdl the type is boolean. I also like your sugestion
of extending the SoapClient class and I will definitely do that once I get
this working.

I tested with a soap debugging tool. The xml request generated by the tool
(I filled just the values) works perfectly, but I still cannot generate the
request using SoapClient.

Below you can find the php with all your suggestions. After the php script
you can find the var_dump content of both the request and the response.


New PHP Code
----------------------
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$soapClient = new SoapClient("
https://webservices.rrts.com/rating/ratequote.asmx?WSDL", array('trace' =>
1));
$ns = 'https://webservices.rrts.com/ratequote/';
$headerBody = array(
'UserName' => "xxxxxx"
, 'Password' => "xxxxxx"
, 'Site' => "xxxxx"
);
$header = new SOAPHeader($ns, 'AuthenticationHeader', $headerBody);
$soapClient->__setSoapHeaders($header);

$args=array(
'request' => array(
'OriginZip' => 18106
,'DestinationZip' => 91752
,'ShipmentDetails' => array(
'ShipmentDetail' => array(
'ActualClass' => 50,
'Weight' => 1200,
)
)
,'OriginType' => 'O'
,'PaymentType' => 'P'
,'COD' => array(
'Prepaid' => true
,'CODAmount' => 1200
)
)
);

try {
$results = $soapClient->RateQuote(array($args));
}
catch (SoapFault $fault) {
var_dump("SOAP Fault: (faultcode: {$fault->faultcode}, faultstring:
{$fault->faultstring})");
var_dump($soapClient->__getLastRequest());
var_dump($soapClient->__getLastResponse());
}

Request Generated by SoapClient (the body is still empty)
------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="https://webservices.rrts.com/ratequote/">
<SOAP-ENV:Header>
<ns1:AuthenticationHeader>
<ns1:UserName>xxxxx</ns1:UserName>
<ns1:Password>xxxxx</ns1:Password>
<ns1:Site>xxxxx</ns1:Site>
</ns1:AuthenticationHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:RateQuote/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Response
---------------
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="
http://www.w3.org/2001/XMLSchema">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server Exception</faultstring>
<faultactor>RateQuote</faultactor>
<detail>
<Error xmlns="https://webservices.rrts.com/ratequote/
"><ErrorNumber>99999</ErrorNumber>
<ErrorMessage>Server Exception</ErrorMessage>
<ErrorSource>RateQuote</ErrorSource>
</Error>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Post by Robert Williams
Post by Adam Tong
Below you will find my PHP script and a valid request generated by a soap
software.
It would be helpful if you could also show us the output from your var_dump() calls.
Post by Adam Tong
I cannot figure out what I am doing wrong in the php script. Maybe it is
the array of elements that is wrong. Please help.
$args = array(
‘request’ => array(
'OriginZip' => 18106,
'DestinationZip' => 91752,
'ShipmentDetails' => array(
'ShipmentDetail' => array(
'ActualClass' => 50,
'Weight' => 1200,
),
),
'OriginType' => 'O',
'PaymentType' => 'P',
'COD' => array(
'Prepaid' => true,
'CODAmount' => 1200.00,
),
),
);
You might also need to put the value of Prepaid into quotes (i.e., make it
the string “true” instead of a boolean), depending on what the service is
expecting.
If that doesn’t work, send us the var_dump() output, especially from the
__getLastRequest() call, as it’s much easier to see where things are going
wrong when you can see exactly what’s currently being passed and compare it
against the known-correct XML from the SOAP utility.
As a tip, calling the service methods directly, instead of via
$results = $soapClient->RateQuote(...);
Also, I will often create a new class that extends SoapClient, then use
@method phpDocumentor tags to document the service methods I’ll be using.
Doing this enables the IDE to support features like code completion, among
other benefits.
--
Bob Williams
SVP, Software Development
Newtek Business Services, Inc.
“The Small Business Authority”
http://www.thesba.com/
Notice: This communication, including attachments, may contain information
that is confidential. It constitutes non-public information intended to be
conveyed only to the designated recipient(s). If the reader or recipient of
this communication is not the intended recipient, an employee or agent of
the intended recipient who is responsible for delivering it to the intended
recipient, or if you believe that you have received this communication in
error, please notify the sender immediately by return e-mail and promptly
delete this e-mail, including attachments without reading or saving them in
any manner. The unauthorized use, dissemination, distribution, or
reproduction of this e-mail, including attachments, is prohibited and may
be unlawful. If you have received this email in error, please notify us
immediately by e-mail or telephone and delete the e-mail and the
attachments (if any).
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Robert Williams
2014-04-21 16:44:41 UTC
Permalink
Adam,

When you call the service methods directly, you don’t need the array wrapper on the parameter since the SoapClient class will take care of it for you. Thus:

$results = $soapClient->RateQuote(array($args));

should just be:

$results = $soapClient->RateQuote($args);

Back on my dev machine this morning, I gave your code a shot, and with the above change, it works. The service complained about a missing ‘Pieces’ value, though. I looked at the WSDL, and Pieces is a required value. Looks like ShipDate is also required. Adding both, I get this code:

$args = array(
'request' => array(
'OriginZip' => 18106,
'DestinationZip' => 91752,
'ShipmentDetails' => array(
'ShipmentDetail' => array(
'ActualClass' => 50,
'Weight' => 1200,
),
),
'OriginType' => 'O',
'PaymentType' => 'P',
'COD' => array(
'Prepaid' => true,
'CODAmount' => 1200,
),
'Pieces' => 1,
'ShipDate' => '2014-04-24T00:00:00-00:00',
),
);

which works, generating this XML:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://webservices.rrts.com/ratequote/">
<SOAP-ENV:Header>
<ns1:AuthenticationHeader>
<ns1:UserName>xxxxxx</ns1:UserName>
<ns1:Password>xxxxxx</ns1:Password>
<ns1:Site>xxxxx</ns1:Site>
</ns1:AuthenticationHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:RateQuote>
<ns1:request>
<ns1:OriginZip>18106</ns1:OriginZip>
<ns1:DestinationZip>91752</ns1:DestinationZip>
<ns1:ShipmentDetails>
<ns1:ShipmentDetail>
<ns1:ActualClass>50</ns1:ActualClass>
<ns1:Weight>1200</ns1:Weight>
</ns1:ShipmentDetail>
</ns1:ShipmentDetails>
<ns1:OriginType>O</ns1:OriginType>
<ns1:PaymentType>P</ns1:PaymentType>
<ns1:Pieces>1</ns1:Pieces>
<ns1:COD>
<ns1:Prepaid>true</ns1:Prepaid>
<ns1:CODAmount>1200</ns1:CODAmount>
</ns1:COD>
<ns1:ShipDate>2014-04-24T00:00:00-00:00</ns1:ShipDate>
</ns1:request>
</ns1:RateQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

As another tip, I noticed that you prepend your array elements with a comma. Presumably, this is to make adding new elements later less error-prone, which always a good idea. However, PHP offers an extremely useful feature that’s even better: dangling commas. Instead of this:

$foo = array(
‘apple’
,‘banana’
,‘pear’
,‘mango’
);

You can do this:

$foo = array(
‘apple’,
‘banana’,
‘pear’,
‘mango’,
);

Note the dangling comma after the last element. This idiom keeps code looking a bit more like natural language and also avoids future editing errors at the beginning of the array, which the comma-as-prefix arrangement doesn’t address. And if you ever find yourself generating array syntax programmatically, this feature makes doing so dead-simple.


--
Robert E. Williams, Jr.
Senior Vice President of Software Development
Newtek Businesss Services, Inc. -- The Small Business Authority
https://www.newtekreferrals.com/rewjr
http://www.thesba.com/


Notice: This communication, including attachments, may contain information that is confidential. It constitutes non-public information intended to be conveyed only to the designated recipient(s). If the reader or recipient of this communication is not the intended recipient, an employee or agent of the intended recipient who is responsible for delivering it to the intended recipient, or if you believe that you have received this communication in error, please notify the sender immediately by return e-mail and promptly delete this e-mail, including attachments without reading or saving them in any manner. The unauthorized use, dissemination, distribution, or reproduction of this e-mail, including attachments, is prohibited and may be unlawful. If you have received this email in error, please notify us immediately by e-mail or telephone and delete the e-mail and the attachments (if any).
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Adam Tong
2014-04-21 18:12:49 UTC
Permalink
Hi Robert,

Everything is working fine now with your fix.

Thank you for the time you spent on this to help me.

I really appreciate it.

Thank you so much!
Adam,
When you call the service methods directly, you don’t need the array
wrapper on the parameter since the SoapClient class will take care of it
$results = $soapClient->RateQuote(array($args));
$results = $soapClient->RateQuote($args);
Back on my dev machine this morning, I gave your code a shot, and with the
above change, it works. The service complained about a missing ‘Pieces’
value, though. I looked at the WSDL, and Pieces is a required value. Looks
$args = array(
'request' => array(
'OriginZip' => 18106,
'DestinationZip' => 91752,
'ShipmentDetails' => array(
'ShipmentDetail' => array(
'ActualClass' => 50,
'Weight' => 1200,
),
),
'OriginType' => 'O',
'PaymentType' => 'P',
'COD' => array(
'Prepaid' => true,
'CODAmount' => 1200,
),
'Pieces' => 1,
'ShipDate' => '2014-04-24T00:00:00-00:00',
),
);
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="
https://webservices.rrts.com/ratequote/">
<SOAP-ENV:Header>
<ns1:AuthenticationHeader>
<ns1:UserName>xxxxxx</ns1:UserName>
<ns1:Password>xxxxxx</ns1:Password>
<ns1:Site>xxxxx</ns1:Site>
</ns1:AuthenticationHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:RateQuote>
<ns1:request>
<ns1:OriginZip>18106</ns1:OriginZip>
<ns1:DestinationZip>91752</ns1:DestinationZip>
<ns1:ShipmentDetails>
<ns1:ShipmentDetail>
<ns1:ActualClass>50</ns1:ActualClass>
<ns1:Weight>1200</ns1:Weight>
</ns1:ShipmentDetail>
</ns1:ShipmentDetails>
<ns1:OriginType>O</ns1:OriginType>
<ns1:PaymentType>P</ns1:PaymentType>
<ns1:Pieces>1</ns1:Pieces>
<ns1:COD>
<ns1:Prepaid>true</ns1:Prepaid>
<ns1:CODAmount>1200</ns1:CODAmount>
</ns1:COD>
<ns1:ShipDate>2014-04-24T00:00:00-00:00</ns1:ShipDate>
</ns1:request>
</ns1:RateQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As another tip, I noticed that you prepend your array elements with a
comma. Presumably, this is to make adding new elements later less
error-prone, which always a good idea. However, PHP offers an extremely
$foo = array(
‘apple’
,‘banana’
,‘pear’
,‘mango’
);
$foo = array(
‘apple’,
‘banana’,
‘pear’,
‘mango’,
);
Note the dangling comma after the last element. This idiom keeps code
looking a bit more like natural language and also avoids future editing
errors at the beginning of the array, which the comma-as-prefix arrangement
doesn’t address. And if you ever find yourself generating array syntax
programmatically, this feature makes doing so dead-simple.
--
Robert E. Williams, Jr.
Senior Vice President of Software Development
Newtek Businesss Services, Inc. -- The Small Business Authority
https://www.newtekreferrals.com/rewjr
http://www.thesba.com/
Notice: This communication, including attachments, may contain information
that is confidential. It constitutes non-public information intended to be
conveyed only to the designated recipient(s). If the reader or recipient of
this communication is not the intended recipient, an employee or agent of
the intended recipient who is responsible for delivering it to the intended
recipient, or if you believe that you have received this communication in
error, please notify the sender immediately by return e-mail and promptly
delete this e-mail, including attachments without reading or saving them in
any manner. The unauthorized use, dissemination, distribution, or
reproduction of this e-mail, including attachments, is prohibited and may
be unlawful. If you have received this email in error, please notify us
immediately by e-mail or telephone and delete the e-mail and the
attachments (if any).
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Loading...