Come effettuare una chiamata SOAP PHP usando la classe SoapClient


130

Sono abituato a scrivere codice PHP, ma spesso non uso la codifica orientata agli oggetti. Ora ho bisogno di interagire con SOAP (come client) e non sono in grado di ottenere la sintassi corretta. Ho un file WSDL che mi permette di impostare correttamente una nuova connessione usando la classe SoapClient. Tuttavia, non sono in grado di effettuare effettivamente la chiamata giusta e ottenere la restituzione dei dati. Devo inviare i seguenti dati (semplificati):

  • ID contatto
  • Nome del contatto
  • Descrizione generale
  • Quantità

Esistono due funzioni definite nel documento WSDL, ma ne ho bisogno solo una ("FirstFunction" di seguito). Ecco lo script che eseguo per ottenere informazioni sulle funzioni e sui tipi disponibili:

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

Ed ecco l'output che genera:

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

Di 'che voglio fare una chiamata a FirstFunction con i dati:

  • ID contatto: 100
  • Nome di contatto: John
  • Descrizione generale: barile di petrolio
  • Importo: 500

Quale sarebbe la giusta sintassi? Ho provato molte opzioni, ma sembra che la struttura del sapone sia abbastanza flessibile, quindi ci sono molti modi per farlo. Neanche a capire dal manuale ...


AGGIORNAMENTO 1: campione provato da 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));

Ma ottengo questa risposta: Object has no 'Contact' property. Come puoi vedere nell'output di getTypes(), c'è un structchiamato Contact, quindi suppongo che in qualche modo debba chiarire che i miei parametri includono i dati di contatto, ma la domanda è: come?

AGGIORNAMENTO 2: Ho provato anche queste strutture, stesso errore.

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

Così come:

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

Errore in entrambi i casi: l'oggetto non ha proprietà "Contact"

php  soap 

Risposte:


178

Questo è quello che hai bisogno di fare.

Ho provato a ricreare la situazione ...


  • Per questo esempio, ho creato un WebService (WS) di esempio .NET con un WebMethodchiamato in Function1attesa dei seguenti parametri:

Funzione 1 (contatto contatto, descrizione stringa, quantità int)

  • Dov'è Contactsolo un modello che ha getter e setter ide namecome nel tuo caso.

  • È possibile scaricare l'esempio .NET WS all'indirizzo:

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


Il codice.

Questo è ciò che devi fare sul lato PHP:

(Testato e funzionante)

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

?>

Testare tutto.

  • Se lo fai print_r($params)vedrai il seguente output, come il tuo WS si aspetterebbe:

Array ([Contact] => Contact Object ([id] => 100 [name] => John) [description] => Barile di petrolio [quantità] => 500)

  • Quando ho eseguito il debug dell'esempio .NET WS ho ottenuto quanto segue:

inserisci qui la descrizione dell'immagine

(Come puoi vedere, l' Contactoggetto non è nullné gli altri parametri. Ciò significa che la tua richiesta è stata eseguita con successo dal lato PHP)

  • La risposta dell'esempio .NET WS era quella attesa e questo è ciò che ho ottenuto dal lato PHP:

object (stdClass) [3] public 'Function1Result' => string 'Informazioni dettagliate sulla tua richiesta! id: 100, nome: John, descrizione: barile di petrolio, quantità: 500 '(lunghezza = 98)


Buona programmazione!


3
Perfetto! Mi sono comportato come se sapessi qualcosa di più sui servizi SOAP di quanto non facessi davvero e questo mi ha portato dove dovevo essere.
chapman84,

1
Non ho fatto la domanda, altrimenti avrei. La domanda e questa risposta mi hanno comunque dato un voto positivo.
chapman84,

4
@utente dovrebbe accettarlo :) A proposito, risposta molto bella, completa e molto chiara. +1
Yann39

Grazie per questo! Lil 'boost per capire la struttura SOAP.
EatCodePlaySleep

69

Puoi usare anche i servizi SOAP in questo modo:

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

Questo è un esempio con un servizio reale e funziona.

Spero che questo ti aiuti.


Ottengo il seguente errore: object (stdClass) # 70 (1) {["GetWeatherResult"] => string (14) "Data Not Found"} Qualche idea?
Ilker Baltaci,

Sembra che abbiano cambiato le corde delle città. Ho appena aggiornato l'esempio con un'altra chiamata a un altro servizio che forniscono e funziona. Ho provato a usare le stringhe che restituiscono come città, ma non sembra funzionare bene, comunque la funzione getCitiesByCountry () serve da esempio su come effettuare una chiamata.
Salvador P.

30

Inizializza prima i servizi web:

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

Quindi impostare e passare i parametri:

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

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

Si noti che il nome del metodo è disponibile in WSDL come nome dell'operazione, ad esempio:

<operation name="methodname">

Grazie! Ho provato questo, ma viene visualizzato l'errore "L'oggetto non ha proprietà 'Contact'". Aggiornerò la mia domanda con tutti i dettagli. Qualche idea?

@ user16441 Puoi pubblicare il WSDL e lo schema del servizio? Di solito comincio a capire quale XML si aspetta il servizio, quindi usando WireShark per capire cosa sta effettivamente inviando il mio cliente.
davidfmatheson,

21

Non so perché il mio servizio web abbia la stessa struttura con te ma non ha bisogno di Class per parametro, è solo array.

Ad esempio: - Il mio 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());

Ecco il risultato:

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)

Quindi nel mio codice:

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

ma con successo!


1
Il tuo esempio è più utile, perché mostra le dipendenze della struttura
vladkras,

3

leggi questo; -

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

O

Questo è un buon esempio per la funzione SOAP "__call". Tuttavia è deprecato.

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

3

Innanzitutto, usa SoapUI per creare il tuo progetto soap dal wsdl. Prova a inviare una richiesta per giocare con le operazioni di wsdl. Osserva come la richiesta xml compone i campi di dati.

E quindi, se hai problemi a ottenere SoapClient come desideri, ecco come eseguo il debug. Impostare l'opzione trace in modo che la funzione __getLastRequest () sia disponibile per l'uso.

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

Quindi la variabile $ xml contiene l'xml che SoapClient compone per la tua richiesta. Confronta questo xml con quello generato in SoapUI.

A mio avviso, SoapClient sembra ignorare le chiavi dell'array associativo $ params e interpretarlo come array indicizzato, causando dati di parametri errati nell'xml. Cioè, se riordinare i dati in $ params , la risposta $ è completamente diversa:

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

3

Se si crea l'oggetto di SoapParam, questo risolverà il problema. Crea una classe e mappala con il tipo di oggetto fornito da WebService, inizializza i valori e invia la richiesta. Vedi l'esempio sotto.

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

1

Ho avuto lo stesso problema, ma ho appena concluso gli argomenti in questo modo e ora funziona.

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

Utilizzando questa funzione:

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

Puoi vedere l'XML della richiesta se sta cambiando o meno a seconda dei tuoi argomenti.

Utilizzare [trace = 1, exceptions = 0] nelle opzioni SoapClient.


0

È necessario dichiarare il contratto di 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,
);

o

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

Poi

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

o

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

0

È necessario un array multidimensionale, è possibile provare quanto segue:

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

in PHP un array è una struttura ed è molto flessibile. Normalmente con le chiamate soap uso un wrapper XML, quindi non sono sicuro che funzionerà.

MODIFICARE:

Quello che potresti voler provare è creare una query json da inviare o usarla per creare un tipo di acquisto xml che segue quanto segue in questa pagina: http://onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html


grazie, ma non ha funzionato neanche. Come usi esattamente i wrapper XML, forse è più facile da usare di così ...

Per prima cosa devi assicurarti che il tuo WSDL sia in grado di gestire wrapper XML. Ma è simile, costruisci la richiesta in XML e nella maggior parte dei casi usi curl. Ho usato SOAP con XML per elaborare le transazioni attraverso le banche. Puoi verificarli come punto di partenza. forum.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams

0

C'è un'opzione per generare oggetti php5 con la classe WsdlInterpreter. Scopri di più qui: https://github.com/gkwelding/WSDLInterpreter

per esempio:

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

0

getLastRequest ():

Questo metodo funziona solo se l'oggetto SoapClient è stato creato con l'opzione di traccia impostata su TRUE.

VERO in questo caso è rappresentato da 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); 

ha funzionato per me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.