How to make a PHP SOAP call using the SoapClient c

2019-01-01 08:37发布

问题:

I\'m used to writing PHP code, but do not often use Object-Oriented coding. I now need to interact with SOAP (as a client) and am not able to get the syntax right. I\'ve got a WSDL file which allows me to properly set up a new connection using the SoapClient class. However, I\'m unable to actually make the right call and get data returned. I need to send the following (simplified) data:

  • Contact ID
  • Contact Name
  • General Description
  • Amount

There are two functions defined in the WSDL document, but I only need one (\"FirstFunction\" below). Here is the script I run to get information on the available functions and types:

$client = new SoapClient(\"http://example.com/webservices?wsdl\");
var_dump($client->__getFunctions()); 
var_dump($client->__getTypes()); 

And here is the output it generates:

array(
  [0] => \"FirstFunction Function1(FirstFunction $parameters)\",
  [1] => \"SecondFunction Function2(SecondFunction $parameters)\",
);

array(
  [0] => struct Contact {
    id id;
    name name;
  }
  [1] => string \"string description\"
  [2] => string \"int amount\"
}

Say I want to make a call to the FirstFunction with the data:

  • Contact ID: 100
  • Contact Name: John
  • General Description: Barrel of Oil
  • Amount: 500

What would be the right syntax? I\'ve been trying all sorts of options but it appears the soap structure is quite flexible so there are very many ways of doing this. Couldn\'t figure it out from the manual either...


UPDATE 1: tried sample from MMK:

$client = new SoapClient(\"http://example.com/webservices?wsdl\");

$params = array(
  \"id\" => 100,
  \"name\" => \"John\",
  \"description\" => \"Barrel of Oil\",
  \"amount\" => 500,
);
$response = $client->__soapCall(\"Function1\", array($params));

But I get this response: Object has no \'Contact\' property. As you can see in the output of getTypes(), there is a struct called Contact, so I guess I somehow need to make clear my parameters include the Contact data, but the question is: how?

UPDATE 2: I\'ve also tried these structures, same error.

$params = array(
  array(
    \"id\" => 100,
    \"name\" => \"John\",
  ),
  \"Barrel of Oil\",
  500,
);

As well as:

$params = array(
  \"Contact\" => array(
    \"id\" => 100,
    \"name\" => \"John\",
  ),
  \"description\" => \"Barrel of Oil\",
  \"amount\" => 500,
);

Error in both cases: Object has no \'Contact\' property`

回答1:

This is what you need to do.

Just to know, I tried to recreate your situation...


  • For this example, I made a .NET sample webservice with a WebMethod called Function1 and these are the parameters:

Function1(Contact Contact, string description, int amount)

  • In which Contact is just a bean class that has getters and setters for id and name like in your case.

  • You can download this .NET sample webservice at:

https://www.dropbox.com/s/6pz1w94a52o5xah/11593623.zip


The code.

This is what you need to do at PHP side:

(Tested and working)

<?php
/* Create a class for your webservice structure, in this case: Contact */
class Contact {
    public function __construct($id, $name) 
    {
        $this->id = $id;
        $this->name = $name;
    }
}

/* Initialize webservice with your WSDL */
$client = new SoapClient(\"http://localhost:10139/Service1.asmx?wsdl\");

/* Fill your Contact Object */
$contact = new Contact(100, \"John\");

/* Set your parameters for the request */
$params = array(
  \"Contact\" => $contact,
  \"description\" => \"Barrel of Oil\",
  \"amount\" => 500,
);

/* Invoke webservice method with your parameters, in this case: Function1 */
$response = $client->__soapCall(\"Function1\", array($params));

/* Print webservice response */
var_dump($response);

?>

How I know this is working?

  • If you do print_r($params); you will see this output, as your webservice expects:

Array ( [Contact] => Contact Object ( [id] => 100 [name] => John ) [description] => Barrel of Oil [amount] => 500 )

  • When I debugged the sample .NET webservice I got this:

\"enter

(As you can see, Contact object is not null and also the other parameters, that means your request was successfully done from PHP side).

  • The response from .NET sample webservice was the expected one and shown at PHP side:

object(stdClass)[3] public \'Function1Result\' => string \'Detailed information of your request! id: 100, name: John, description: Barrel of Oil, amount: 500\' (length=98)


Hope this helps :-)



回答2:

You can use SOAP services this way too:

<?php 
//Create the client object
$soapclient = new SoapClient(\'http://www.webservicex.net/globalweather.asmx?WSDL\');

//Use the functions of the client, the params of the function are in 
//the associative array
$params = array(\'CountryName\' => \'Spain\', \'CityName\' => \'Alicante\');
$response = $soapclient->getWeather($params);

var_dump($response);

// Get the Cities By Country
$param = array(\'CountryName\' => \'Spain\');
$response = $soapclient->getCitiesByCountry($param);

var_dump($response);

This is an example with a real service, and it works.

Hope this helps.



回答3:

First initialize webservices:

$client = new SoapClient(\"http://example.com/webservices?wsdl\");

Then set and pass the parameters:

$params = array (
    \"arg0\" => $contactid,
    \"arg1\" => $desc,
    \"arg2\" => $contactname
);

$response = $client->__soapCall(\'methodname\', array($params));

Note that the method name is available in WSDL as operation name, e.g.:

<operation name=\"methodname\">


回答4:

I don\'t know why my web service has the same structure with you but it doesn\'t need Class for parameter, just is array.

For example: - My WSDL:

<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
                  xmlns:ns=\"http://www.kiala.com/schemas/psws/1.0\">
    <soapenv:Header/>
    <soapenv:Body>
        <ns:createOrder reference=\"260778\">
            <identification>
                <sender>5390a7006cee11e0ae3e0800200c9a66</sender>
                <hash>831f8c1ad25e1dc89cf2d8f23d2af...fa85155f5c67627</hash>
                <originator>VITS-STAELENS</originator>
            </identification>
            <delivery>
                <from country=\"ES\" node=””/>
                <to country=\"ES\" node=\"0299\"/>
            </delivery>
            <parcel>
                <description>Zoethout thee</description>
                <weight>0.100</weight>
                <orderNumber>10K24</orderNumber>
                <orderDate>2012-12-31</orderDate>
            </parcel>
            <receiver>
                <firstName>Gladys</firstName>
                <surname>Roldan de Moras</surname>
                <address>
                    <line1>Calle General Oraá 26</line1>
                    <line2>(4º izda)</line2>
                    <postalCode>28006</postalCode>
                    <city>Madrid</city>
                    <country>ES</country>
                </address>
                <email>gverbruggen@kiala.com</email>
                <language>es</language>
            </receiver>
        </ns:createOrder>
    </soapenv:Body>
</soapenv:Envelope>

I var_dump:

var_dump($client->getFunctions());
var_dump($client->getTypes());

Here is result:

array
  0 => string \'OrderConfirmation createOrder(OrderRequest $createOrder)\' (length=56)

array
  0 => string \'struct OrderRequest {
 Identification identification;
 Delivery delivery;
 Parcel parcel;
 Receiver receiver;
 string reference;
}\' (length=130)
  1 => string \'struct Identification {
 string sender;
 string hash;
 string originator;
}\' (length=75)
  2 => string \'struct Delivery {
 Node from;
 Node to;
}\' (length=41)
  3 => string \'struct Node {
 string country;
 string node;
}\' (length=46)
  4 => string \'struct Parcel {
 string description;
 decimal weight;
 string orderNumber;
 date orderDate;
}\' (length=93)
  5 => string \'struct Receiver {
 string firstName;
 string surname;
 Address address;
 string email;
 string language;
}\' (length=106)
  6 => string \'struct Address {
 string line1;
 string line2;
 string postalCode;
 string city;
 string country;
}\' (length=99)
  7 => string \'struct OrderConfirmation {
 string trackingNumber;
 string reference;
}\' (length=71)
  8 => string \'struct OrderServiceException {
 string code;
 OrderServiceException faultInfo;
 string message;
}\' (length=97)

So in my code:

    $client  = new SoapClient(\'http://packandship-ws.kiala.com/psws/order?wsdl\');

    $params = array(
        \'reference\' => $orderId,
        \'identification\' => array(
            \'sender\' => param(\'kiala\', \'sender_id\'),
            \'hash\' => hash(\'sha512\', $orderId . param(\'kiala\', \'sender_id\') . param(\'kiala\', \'password\')),
            \'originator\' => null,
        ),
        \'delivery\' => array(
            \'from\' => array(
                \'country\' => \'es\',
                \'node\' => \'\',
            ),
            \'to\' => array(
                \'country\' => \'es\',
                \'node\' => \'0299\'
            ),
        ),
        \'parcel\' => array(
            \'description\' => \'Description\',
            \'weight\' => 0.200,
            \'orderNumber\' => $orderId,
            \'orderDate\' => date(\'Y-m-d\')
        ),
        \'receiver\' => array(
            \'firstName\' => \'Customer First Name\',
            \'surname\' => \'Customer Sur Name\',
            \'address\' => array(
                \'line1\' => \'Line 1 Adress\',
                \'line2\' => \'Line 2 Adress\',
                \'postalCode\' => 28006,
                \'city\' => \'Madrid\',
                \'country\' => \'es\',
                ),
            \'email\' => \'test.ceres@yahoo.com\',
            \'language\' => \'es\'
        )
    );
    $result = $client->createOrder($params);
    var_dump($result);

but it successfully!



回答5:

First, use SoapUI to create your soap project from the wsdl. Try to send a request to play with the wsdl\'s operations. Observe how the xml request composes your data fields.

And then, if you are having problem getting SoapClient acts as you want, here is how I debug it. Set the option trace so that the function __getLastRequest() is available for use.

$soapClient = new SoapClient(\'http://yourwdsdlurl.com?wsdl\', [\'trace\' => true]);
$params = [\'user\' => \'Hey\', \'account\' => \'12345\'];
$response = $soapClient->__soapCall(\'<operation>\', $params);
$xml = $soapClient->__getLastRequest();

Then the $xml variable contains the xml that SoapClient compose for your request. Compare this xml with the one generated in the SoapUI.

For me, SoapClient seems to ignore the keys of the associative array $params and interpret it as indexed array, causing wrong parameter data in the xml. That is, if I reorder the data in $params, the $response is completely different:

$params = [\'account\' => \'12345\', \'user\' => \'Hey\'];
$response = $soapClient->__soapCall(\'<operation>\', $params);


回答6:

If you create the object of SoapParam, This will resolve your problem. Create a class and map it with object type given by WebService, Initialize the values and send in the request. See the sample below.

struct Contact {

    function Contact ($pid, $pname)
    {
      id = $pid;
      name = $pname;
  }
}

$struct = new Contact(100,\"John\");

$soapstruct = new SoapVar($struct, SOAP_ENC_OBJECT, \"Contact\",\"http://soapinterop.org/xsd\");

$ContactParam = new SoapParam($soapstruct, \"Contact\")

$response = $client->Function1($ContactParam);


回答7:

read this;-

http://php.net/manual/en/soapclient.call.php

Or

This is a good example, for the SOAP function \"__call\". However it is deprecated.

<?php
    $wsdl = \"http://webservices.tekever.eu/ctt/?wsdl\";
    $int_zona = 5;
    $int_peso = 1001;
    $cliente = new SoapClient($wsdl);
    print \"<p>Envio Internacional: \";
    $vem = $cliente->__call(\'CustoEMSInternacional\',array($int_zona, $int_peso));
    print $vem;
    print \"</p>\";
?>


回答8:

You need declare class Contract

class Contract {
  public $id;
  public $name;
}

$contract = new Contract();
$contract->id = 100;
$contract->name = \"John\";

$params = array(
  \"Contact\" => $contract,
  \"description\" => \"Barrel of Oil\",
  \"amount\" => 500,
);

or

$params = array(
  $contract,
  \"description\" => \"Barrel of Oil\",
  \"amount\" => 500,
);

Then

$response = $client->__soapCall(\"Function1\", array(\"FirstFunction\" => $params));

or

$response = $client->__soapCall(\"Function1\", $params);


回答9:

You need a multi-dimensional array, you can try the following:

$params = array(
   array(
      \"id\" => 100,
      \"name\" => \"John\",
   ),
   \"Barrel of Oil\",
   500
);

in PHP an array is a structure and is very flexible. Normally with soap calls I use an XML wrapper so unsure if it will work.

EDIT:

What you may want to try is creating a json query to send or using that to create a xml buy sort of following what is on this page: http://onwebdev.blogspot.com/2011/08/php-converting-rss-to-json.html



回答10:

There is an option to generate php5 objects with WsdlInterpreter class. See more here: https://github.com/gkwelding/WSDLInterpreter

for example:

require_once \'WSDLInterpreter-v1.0.0/WSDLInterpreter.php\';
$wsdlLocation = \'<your wsdl url>?wsdl\';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP(\'.\');


回答11:

I had the same issue, but I just wrapped the arguments like this and it works now.

    $args = array();
    $args[\'Header\'] = array(
        \'CustomerCode\' => \'dsadsad\',
        \'Language\' => \'fdsfasdf\'
    );
    $args[\'RequestObject\'] = $whatever;

    // this was the catch, double array with \"Request\"
    $response = $this->client->__soapCall($name, array(array( \'Request\' => $args )));

Using this function:

 print_r($this->client->__getLastRequest());

You can see the Request XML whether it\'s changing or not depending on your arguments.

Use [ trace = 1, exceptions = 0 ] in SoapClient options.



标签: php soap