[php] How to make a PHP SOAP call using the SoapClient class

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`

This question is related to php soap

The answer is


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


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('.');

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 when the url is up.

Just in case the http://www.webservicex.net is down.

Here is another example using the example web service from W3C XML Web Services example, you can find more information on the link.

<?php
//Create the client object
$soapclient = new SoapClient('https://www.w3schools.com/xml/tempconvert.asmx?WSDL');

//Use the functions of the client, the params of the function are in
//the associative array
$params = array('Celsius' => '25');
$response = $soapclient->CelsiusToFahrenheit($params);

var_dump($response);

// Get the Celsius degrees from the Farenheit
$param = array('Fahrenheit' => '25');
$response = $soapclient->FahrenheitToCelsius($param);

var_dump($response);

This is working and returning the converted temperature values.

Hope this helps.


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

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

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

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>[email protected]</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' => '[email protected]',
            'language' => 'es'
        )
    );
    $result = $client->createOrder($params);
    var_dump($result);

but it successfully!


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.


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

getLastRequest():

This method works only if the SoapClient object was created with the trace option set to TRUE.

TRUE in this case is represented by 1

$wsdl = storage_path('app/mywsdl.wsdl');
try{

  $options = array(
               // 'soap_version'=>SOAP_1_1,
               'trace'=>1,
               'exceptions'=>1,

                'cache_wsdl'=>WSDL_CACHE_NONE,
             //   'stream_context' => stream_context_create($arrContextOptions)
        );
           // $client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE) );
        $client = new \SoapClient($wsdl, array('cache_wsdl' => WSDL_CACHE_NONE));
        $client     = new \SoapClient($wsdl,$options); 

worked for me.


This is what you need to do.

I tried to recreate the situation...


  • For this example, I created a .NET sample WebService (WS) with a WebMethod called Function1 expecting the following params:

Function1(Contact Contact, string description, int amount)

  • Where Contact is just a model that has getters and setters for id and name like in your case.

  • You can download the .NET sample WS 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 Contact class
class Contact {
    public function __construct($id, $name) 
    {
        $this->id = $id;
        $this->name = $name;
    }
}

// Initialize WS with the WSDL
$client = new SoapClient("http://localhost:10139/Service1.asmx?wsdl");

// Create Contact obj
$contact = new Contact(100, "John");

// Set request params
$params = array(
  "Contact" => $contact,
  "description" => "Barrel of Oil",
  "amount" => 500,
);

// Invoke WS method (Function1) with the request params 
$response = $client->__soapCall("Function1", array($params));

// Print WS response
var_dump($response);

?>

Testing the whole thing.

  • If you do print_r($params) you will see the following output, as your WS would expect:

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

  • When I debugged the .NET sample WS I got the following:

enter image description here

(As you can see, Contact object is not null nor the other params. That means your request was successfully done from PHP side)

  • The response from the .NET sample WS was the expected one and this is what I got 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)


Happy Coding!


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">