Como fazer uma chamada de PHP SOAP usando a classe SoapClient

estou habituado a escrever código PHP, mas não costumo usar códigos orientados a objectos. Eu agora preciso interagir com o SOAP (como um cliente) e não sou capaz de obter a sintaxe certa. Eu tenho um arquivo WSDL que me permite configurar corretamente uma nova conexão usando a classe SoapClient. No entanto, sou incapaz de fazer a chamada certa e obter dados devolvidos. Preciso enviar os seguintes dados (simplificados):

  • ID de contacto
  • Nome De Contacto
  • geral Descrição
  • montante

Existem duas funções definidas no documento WSDL, mas eu só preciso de uma ("primeira função" abaixo). Aqui está o script que corro para obter informações sobre as funções e tipos disponíveis:

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

e aqui está a saída que gera:

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"
}
Digamos que quero fazer uma chamada para a primeira função com os dados:
  • ID de contacto: 100
  • Nome De Contacto: John
  • Descrição Geral: barril de Óleo
  • montante: 500
Qual seria a sintaxe certa? Eu tenho tentado todos os tipos de opções, mas parece que a estrutura de sabão é bastante flexível, então há muitas maneiras de fazer isso. Também não consegui descobrir pelo manual...


actualização 1: amostra testada de 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));

mas eu tenho esta resposta: Object has no 'Contact' property. Como você pode ver na saída de getTypes(), há um struct chamado Contact, Então eu acho que de alguma forma preciso deixar claro meus parâmetros incluem os dados de contato, mas a questão é: como?

actualização 2: também tentei estas estruturas, mesmo erro.

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

assim como:

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

erro em ambos os casos: o objecto não tem propriedade' contacto '

 96
Author: Oscar Jara, 2012-07-21

11 answers

Isto é o que tens de fazer. Só para saber, tentei recriar a tua situação...
  • para este exemplo, fiz um servidor de amostras. net com um WebMethod Chamado Function1 e estes são os parâmetros:

Function1 (contacto, descrição do texto, int montante)

  • Em que Contact é apenas um feijão class que tem getters e setters para id e name como no teu caso.

  • Podes. obtém este serviço web de amostras. NET em:

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


O código.

Isto é o que você precisa fazer no lado do PHP:

(ensaio e funcionamento)

<?php
/* Create a class for your webservice structure, in this case: Contact */
class Contact {
    function Contact($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);

?>

Como sei que isto está a funcionar?
  • Se o fizer {[7] } irá ver esta saída, como o seu serviço web espera:

Matriz ([contacto] = > objecto de contacto ([id] = > 100 [nome] => John ] [descrição] => barril de Petróleo [Quantidade] => 500 )

  • Quando depurei o serviço web sample. net consegui isto:

enter image description here

(Como você pode ver, Contact objeto não é nulo e também os outros parâmetros, isso significa que seu pedido foi feito com sucesso do lado PHP).

  • a resposta do serviço web da amostra. net era a esperada e mostrada do lado do PHP:

Objecto (stdClass)[3] público "Function1Result" = > string " Detailed informação do seu pedido! id: 100, nome: John, descrição: barril de óleo, Quantidade: 500' (comprimento=98)


Espero que isto ajude.
 147
Author: Oscar Jara, 2018-09-21 12:44:42

Também pode usar os Serviços de sabão desta forma:

<?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);
Este é um exemplo com um serviço real, e funciona. Espero que isto ajude.
 59
Author: Salvador P., 2017-06-14 13:17:09

Inicializar os webservices pela primeira vez:

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

Em seguida, definir e passar os parâmetros:

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

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

Note que o nome do método está disponível no WSDL como nome da operação, por exemplo:

<operation name="methodname">
 26
Author: MMK, 2016-06-21 15:05:20

Eu não sei porque meu serviço web tem a mesma estrutura com você, mas ele não precisa de classe para parâmetro, apenas é array.

Por exemplo: - O meu 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());
Aqui está o resultado:
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)
Então, no meu código:
    $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);
Mas com sucesso!
 19
Author: Tín Phạm, 2013-07-17 03:17:42

Primeiro, use SoapUI para criar o seu projecto soap a partir do wsdl. Tente enviar um pedido para jogar com as operações do wsdl. Observe como o pedido xml compõe seus campos de dados.

E então, se você está tendo problemas para obter os atos de SoapClient como você quer, aqui está como eu o depuro. Defina a opção trace para que a função __getLastRequest() esteja disponível para utilização.

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

Então a variável $xml contém o xml que o SoapClient compõe a seu pedido. Compare este xml com o gerado no SoapUI.

Para mim, o SoapClient parece ignorar as chaves do array associativo $params e interpretá-lo como um array indexado, causando dados de parâmetros errados no xml. Isto é, se eu Reordenar os dados em $params, a resposta $ é completamente diferente:

$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
 3
Author: Sang Nguyen, 2018-01-26 04:25:03

Se criar o objecto do SoapParam, isto irá resolver o seu problema. Crie uma classe e mapeie-a com o tipo de objeto dado pelo WebService, inicialize os valores e envie o pedido. Ver a amostra abaixo.

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);
 2
Author: Umesh Chavan, 2018-03-03 00:20:22

Leia isto; -

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

Ou

Este é um bom exemplo, para a função SOAP "__call". No entanto, é depreciado.

<?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>";
?>
 1
Author: Abid Hussain, 2012-07-29 19:52:32

Tens de declarar o contrato da classe

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

Ou

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

Depois

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

Ou

$response = $client->__soapCall("Function1", $params);
 0
Author: Ramil Amr, 2012-07-29 23:17:39

Se precisar de um array multidimensional, pode tentar o seguinte:

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

Em PHP um array é uma estrutura e é muito flexível. Normalmente com as chamadas soap eu uso uma embalagem XML tão inseguro se ele vai funcionar.

Editar:

O que você pode querer tentar é criar uma consulta json para enviar ou usar isso para criar um tipo de compra xml de seguir o que está nesta página: http://onwebdev.blogspot.com/2011/08/php-converting-rss-to-json.html

 0
Author: James Williams, 2012-08-08 19:29:28

Existe uma opção para gerar objectos php5 com a classe WsdlInterpreter. Veja mais aqui: https://github.com/gkwelding/WSDLInterpreter

Por exemplo:

require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
 0
Author: István Döbrentei, 2018-04-23 14:47:00
Eu tinha o mesmo problema, mas acabei com os argumentos assim e agora funciona.
    $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 )));

Usando esta função:

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

Pode ver o XML do pedido, quer esteja a mudar ou não, dependendo dos seus argumentos.

Usar [ trace = 1, exceptions = 0 ] nas opções de SoapClient.

 0
Author: Martin Zvarík, 2018-06-21 14:54:51