So tätigen Sie einen PHP-SOAP-Aufruf mit der SoapClient-Klasse

130

Ich bin es gewohnt, PHP-Code zu schreiben, verwende aber nicht oft objektorientierte Codierung. Ich muss jetzt mit SOAP (als Client) interagieren und kann die Syntax nicht richtig verstehen. Ich habe eine WSDL-Datei, mit der ich mithilfe der SoapClient-Klasse eine neue Verbindung ordnungsgemäß einrichten kann. Ich kann jedoch nicht den richtigen Anruf tätigen und keine Daten zurückerhalten. Ich muss die folgenden (vereinfachten) Daten senden:

  • Kontakt-ID
  • Kontaktname
  • Allgemeine Beschreibung
  • Menge

Im WSDL-Dokument sind zwei Funktionen definiert, aber ich benötige nur eine ("FirstFunction" unten). Hier ist das Skript, das ich ausführe, um Informationen zu den verfügbaren Funktionen und Typen zu erhalten:

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

Und hier ist die Ausgabe, die es generiert:

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

Angenommen, ich möchte die FirstFunction mit den Daten aufrufen:

  • Kontakt-ID: 100
  • Name des Ansprechpartners: John
  • Allgemeine Beschreibung: Ölfass
  • Betrag: 500

Was wäre die richtige Syntax? Ich habe alle möglichen Optionen ausprobiert, aber es scheint, dass die Seifenstruktur ziemlich flexibel ist, so dass es sehr viele Möglichkeiten gibt, dies zu tun. Konnte es auch nicht aus dem Handbuch herausfinden ...


UPDATE 1: Probe von MMK ausprobiert:

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

Aber ich bekomme diese Antwort : Object has no 'Contact' property. Wie Sie in der Ausgabe von sehen können getTypes(), gibt es einen structAufruf Contact, also muss ich wohl irgendwie klarstellen, dass meine Parameter die Kontaktdaten enthalten, aber die Frage ist: Wie?

UPDATE 2: Ich habe auch diese Strukturen ausprobiert, der gleiche Fehler.

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

Ebenso gut wie:

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

Fehler in beiden Fällen: Objekt hat keine 'Kontakt'-Eigenschaft`


quelle

Antworten:

177

Dies ist, was Sie tun müssen.

Ich habe versucht, die Situation nachzubilden ...


  • In diesem Beispiel habe ich einen .NET-Beispiel-WebService (WS) mit einem WebMethodAufruf erstellt Function1, der die folgenden Parameter erwartet:

Funktion1 (Kontakt Kontakt, Zeichenfolgenbeschreibung, int Betrag)

  • Wo Contactist nur ein Modell, das Getter und Setter für idund namewie in Ihrem Fall hat.

  • Sie können das .NET-Beispiel-WS unter folgender Adresse herunterladen:

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


Der Code.

Dies ist, was Sie auf PHP-Seite tun müssen:

(Getestet und funktionsfähig)

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

?>

Das Ganze testen.

  • Wenn Sie dies tun print_r($params), sehen Sie die folgende Ausgabe, wie es Ihr WS erwarten würde:

Array ([Kontakt] => Kontaktobjekt ([id] => 100 [Name] => John) [Beschreibung] => Barrel Öl [Menge] => 500)

  • Beim Debuggen des .NET-Beispiel-WS wurde Folgendes angezeigt:

Geben Sie hier die Bildbeschreibung ein

(Wie Sie sehen können, ist das ContactObjekt weder das nullnoch die anderen Parameter. Das bedeutet, dass Ihre Anfrage von PHP-Seite erfolgreich ausgeführt wurde.)

  • Die Antwort vom .NET-Beispiel-WS war die erwartete und das habe ich auf PHP-Seite erhalten:

object (stdClass) [3] public 'Function1Result' => string 'Detaillierte Informationen zu Ihrer Anfrage! ID: 100, Name: John, Beschreibung: Barrel Oil, Menge: 500 '(Länge = 98)


Viel Spaß beim Codieren!

Oscar Jara
quelle
3
Perfekt! Ich tat so, als wüsste ich ein bisschen mehr über SOAP-Dienste als ich wirklich wusste, und das brachte mich dahin, wo ich sein musste.
Chapman 84
1
Ich habe die Frage nicht gestellt, sonst hätte ich. Die Frage und diese Antwort wurden jedoch von mir positiv bewertet.
chapman84
4
@ Benutzer sollte es akzeptieren :) Übrigens, sehr schöne Antwort, vollständig und sehr klar. +1
Yann39
Danke dafür! Lil 'Boost, um die SOAP-Struktur zu verstehen.
EatCodePlaySleep
69

Sie können SOAP-Dienste auch folgendermaßen verwenden:

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

Dies ist ein Beispiel mit einem echten Service, und es funktioniert.

Hoffe das hilft.

Salvador P.
quelle
Ich erhalte die folgende Fehlermeldung: object (stdClass) # 70 (1) {["GetWeatherResult"] => string (14) "Data Not Found"} Irgendeine Idee?
Ilker Baltaci
Scheint, als hätten sie die Saiten der Städte verändert. Ich habe das Beispiel gerade mit einem weiteren Aufruf eines anderen von ihnen bereitgestellten Dienstes aktualisiert und es funktioniert. Ich habe versucht, die zurückgegebenen Zeichenfolgen als Städte zu verwenden, aber es scheint nicht gut zu funktionieren. Trotzdem dient die Funktion getCitiesByCountry () als Beispiel für das Tätigen eines Aufrufs.
Salvador P.
29

Initialisieren Sie zuerst die Webservices:

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

Stellen Sie dann die Parameter ein und übergeben Sie sie:

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

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

Beachten Sie, dass der Methodenname in WSDL als Operationsname verfügbar ist, z.

<operation name="methodname">
MMK
quelle
Vielen Dank! Ich habe dies versucht, erhalte jedoch die Fehlermeldung "Objekt hat keine 'Kontakt'-Eigenschaft". Ich werde meine Frage mit allen Details aktualisieren. Irgendwelche Ideen?
@ user16441 Können Sie die WSDL und das Schema des Dienstes veröffentlichen? Normalerweise beginne ich damit, herauszufinden, welches XML der Dienst erwartet, und verwende dann WireShark, um herauszufinden, was mein Client tatsächlich sendet.
Davidfmatheson
21

Ich weiß nicht, warum mein Webdienst dieselbe Struktur wie Sie hat, aber er benötigt keine Klasse für Parameter, sondern nur ein Array.

Zum Beispiel: - Meine 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>

Ich var_dump:

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

Hier ist das Ergebnis:

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)

Also in meinem 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);

aber es erfolgreich!

Tín Phạm
quelle
1
Ihr Beispiel ist hilfreicher, weil es Strukturabhängigkeiten zeigt
vladkras
3

lesen Sie dies;-

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

Oder

Dies ist ein gutes Beispiel für die SOAP-Funktion "__call". Es ist jedoch veraltet.

<?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>";
?>
Abid Hussain
quelle
3

Verwenden Sie zuerst SoapUI , um Ihr Seifenprojekt aus der WSDL zu erstellen. Versuchen Sie, eine Anfrage zu senden, um mit den Operationen der WSDL zu spielen. Beobachten Sie, wie die XML-Anforderung Ihre Datenfelder zusammensetzt.

Und wenn Sie Probleme haben, SoapClient so zu gestalten, wie Sie es möchten, können Sie es wie folgt debuggen. Stellen Sie die Option trace so ein, dass die Funktion __getLastRequest () zur Verwendung verfügbar ist.

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

Dann die $ xml enthält die Variable die XML, die SoapClient für Ihre Anfrage erstellt. Vergleichen Sie diese XML mit der in der SoapUI generierten.

Für mich scheint SoapClient die Schlüssel des assoziativen Arrays $ params zu ignorieren und als indiziertes Array zu interpretieren, was zu falschen Parameterdaten in der XML führt. Das heißt, wenn ich die Daten in $ params neu anordne , ist die $ Antwort völlig anders:

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

Wenn Sie das Objekt von SoapParam erstellen, wird Ihr Problem dadurch behoben. Erstellen Sie eine Klasse und ordnen Sie sie dem von WebService angegebenen Objekttyp zu. Initialisieren Sie die Werte und senden Sie die Anforderung. Siehe das Beispiel unten.

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);
Umesh Chavan
quelle
1

Ich hatte das gleiche Problem, aber ich habe die Argumente einfach so verpackt und es funktioniert jetzt.

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

Mit dieser Funktion:

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

Sie können die Anforderungs-XML sehen, ob sie sich abhängig von Ihren Argumenten ändert oder nicht.

Verwenden Sie [trace = 1, Ausnahmen = 0] in den SoapClient-Optionen.

Martin Zvarík
quelle
0

Sie braucht Klasse deklariert Vertrag

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

oder

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

Dann

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

oder

$response = $client->__soapCall("Function1", $params);
Ramil Amerzyanov
quelle
0

Sie benötigen ein mehrdimensionales Array. Sie können Folgendes ausprobieren:

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

In PHP ist ein Array eine Struktur und sehr flexibel. Normalerweise verwende ich bei Seifenaufrufen einen XML-Wrapper, der nicht sicher ist, ob er funktioniert.

BEARBEITEN:

Möglicherweise möchten Sie versuchen, eine JSON-Abfrage zum Senden zu erstellen oder damit eine XML-Kaufabfrage zu erstellen. Gehen Sie dazu wie folgt vor: http://onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html

James Williams
quelle
danke, aber es hat auch nicht funktioniert. Wie genau verwenden Sie XML-Wrapper
Zuerst müssen Sie sicherstellen, dass Ihre WSDL XML-Wrapper verarbeiten kann. Ähnlich ist es jedoch, wenn Sie die Anforderung in XML erstellen und in den meisten Fällen Curl verwenden. Ich habe SOAP mit XML verwendet, um Transaktionen über Banken zu verarbeiten. Sie können diese als Startpunkt überprüfen. forums.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams
0

Es gibt eine Option zum Generieren von PHP5-Objekten mit der WsdlInterpreter-Klasse. Weitere Informationen finden Sie hier: https://github.com/gkwelding/WSDLInterpreter

beispielsweise:

require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
István Döbrentei
quelle
0

getLastRequest ():

Diese Methode funktioniert nur, wenn das SoapClient-Objekt mit der Trace-Option TRUE erstellt wurde.

TRUE wird in diesem Fall durch 1 dargestellt

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

arbeitete für mich.

CollinsKe
quelle