Cara membuat panggilan SOAP PHP menggunakan kelas SoapClient

130

Saya terbiasa menulis kode PHP, tetapi tidak sering menggunakan pengkodean Object-Oriented. Saya sekarang perlu berinteraksi dengan SOAP (sebagai klien) dan saya tidak bisa mendapatkan sintaks yang benar. Saya punya file WSDL yang memungkinkan saya untuk mengatur koneksi baru dengan benar menggunakan kelas SoapClient. Namun, saya tidak dapat benar-benar melakukan panggilan yang benar dan mendapatkan kembali data. Saya perlu mengirim data berikut (disederhanakan):

  • ID kontak
  • Nama Kontak
  • Gambaran umum
  • Jumlah

Ada dua fungsi yang didefinisikan dalam dokumen WSDL, tetapi saya hanya perlu satu ("FirstFunction" di bawah). Berikut ini skrip yang saya jalankan untuk mendapatkan informasi tentang fungsi dan tipe yang tersedia:

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

Dan inilah output yang dihasilkannya:

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

Katakanlah saya ingin melakukan panggilan ke FirstFunction dengan data:

  • ID Kontak: 100
  • Nama Kontak: John
  • Deskripsi Umum: Barel Minyak
  • Jumlah: 500

Apa sintaks yang tepat? Saya sudah mencoba segala macam pilihan tetapi tampaknya struktur sabunnya cukup fleksibel sehingga ada banyak cara untuk melakukan ini. Tidak dapat menemukannya dari manual juga ...


PEMBARUAN 1: mencoba sampel dari 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));

Tapi aku mendapatkan respons ini: Object has no 'Contact' property. Seperti yang Anda lihat di output dari getTypes(), ada yang structdipanggil Contact, jadi saya kira saya entah bagaimana harus menjelaskan parameter saya termasuk data Kontak, tetapi pertanyaannya adalah: bagaimana?

UPDATE 2: Saya juga mencoba struktur ini, kesalahan yang sama.

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

Sebaik:

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

Kesalahan dalam kedua kasus: Objek tidak memiliki properti 'Kontak'`


sumber

Jawaban:

178

Ini adalah hal yang perlu kamu lakukan.

Saya mencoba untuk menciptakan kembali situasi ...


  • Untuk contoh ini, saya membuat .NET sample WebService (WS) dengan yang WebMethoddisebut Function1mengharapkan params berikut:

Function1 (Kontak Kontak, deskripsi string, jumlah int)

  • Di mana Contacthanya model yang memiliki getter dan setter untuk iddan namesuka dalam kasus Anda.

  • Anda dapat mengunduh .NET sample WS di:

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


Kode.

Inilah yang perlu Anda lakukan di sisi PHP:

(Diuji dan bekerja)

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

?>

Menguji semuanya.

  • Jika Anda melakukannya, print_r($params)Anda akan melihat output berikut, seperti WS Anda harapkan:

Array ([Kontak] => Objek Kontak ([id] => 100 [nama] => John) [deskripsi] => Barel Minyak [jumlah] => 500)

  • Ketika saya men-debug sampel .NET WS saya mendapat yang berikut:

masukkan deskripsi gambar di sini

(Seperti yang Anda lihat, Contactobjek bukan nullatau params lainnya. Itu berarti permintaan Anda berhasil dilakukan dari sisi PHP)

  • Tanggapan dari sampel NET. WS adalah yang diharapkan dan ini adalah apa yang saya dapatkan di sisi PHP:

object (stdClass) [3] publik 'Function1Result' => string 'Informasi detail permintaan Anda! id: 100, nama: John, deskripsi: Barrel of Oil, jumlah: 500 '(panjang = 98)


Selamat Coding!

Oscar Jara
sumber
3
Sempurna! Saya bertindak seolah-olah saya tahu sedikit lebih banyak tentang layanan SOAP daripada yang benar-benar saya lakukan dan ini membuat saya di mana saya perlu.
chapman84
1
Saya tidak mengajukan pertanyaan, kalau tidak saya akan bertanya. Pertanyaan dan jawaban ini mendapat dukungan dari saya.
chapman84
4
@ pengguna harus menerimanya :) BTW, jawaban yang sangat bagus, lengkap dan sangat jelas. +1
Yann39
Terima kasih untuk ini! Lil meningkatkan untuk memahami struktur SOAP.
EatCodePlaySleep
69

Anda dapat menggunakan layanan SOAP dengan cara ini juga:

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

Ini adalah contoh dengan layanan nyata, dan berfungsi.

Semoga ini membantu.

Salvador P.
sumber
Saya mendapatkan kesalahan berikut: objek (stdClass) # 70 (1) {["GetWeatherResult"] => string (14) "Data Tidak Ditemukan"} Ada ide?
Ilker Baltaci
Tampaknya mereka telah mengubah string kota. Saya baru saja memperbarui contoh dengan panggilan lain ke layanan lain yang mereka berikan dan berfungsi. Saya mencoba menggunakan string yang mereka kembalikan sebagai kota, tetapi sepertinya tidak berfungsi dengan baik, bagaimanapun fungsi getCitiesByCountry () berfungsi sebagai contoh tentang cara melakukan panggilan.
Salvador P.
30

Inisialisasi layanan web pertama kali:

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

Kemudian atur dan lewati parameter:

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

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

Perhatikan bahwa nama metode tersedia di WSDL sebagai nama operasi, misalnya:

<operation name="methodname">
MMK
sumber
Terima kasih! Saya sudah mencoba ini tetapi saya mendapatkan kesalahan "Objek tidak memiliki properti 'Kontak'". Akan memperbarui pertanyaan saya dengan detail lengkap. Ada ide?
@ user16441 Bisakah Anda memposting WSDL dan skema layanan? Saya biasanya mulai dengan mencari tahu apa yang diharapkan dari layanan XML, kemudian menggunakan WireShark untuk mencari tahu apa yang sebenarnya dikirim oleh klien saya.
davidfmatheson
21

Saya tidak tahu mengapa layanan web saya memiliki struktur yang sama dengan Anda tetapi tidak perlu Kelas untuk parameter, hanya array.

Misalnya: - WSDL saya:

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

Saya var_dump:

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

Ini hasilnya:

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)

Jadi dalam kode saya:

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

tetapi berhasil!

Tín Phạm
sumber
1
Contoh Anda lebih bermanfaat, karena menunjukkan struktur dependecies
vladkras
3

Baca ini;-

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

Atau

Ini adalah contoh yang baik, untuk fungsi SOAP "__call". Namun itu sudah usang.

<?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
sumber
3

Pertama, gunakan SoapUI untuk membuat proyek sabun Anda dari wsdl. Cobalah untuk mengirim permintaan untuk bermain dengan operasi wsdl. Amati bagaimana permintaan xml menyusun bidang data Anda.

Dan kemudian, jika Anda mengalami masalah dalam mendapatkan tindakan SoapClient seperti yang Anda inginkan, inilah cara saya men-debug-nya. Setel opsi penelusuran sehingga fungsi __getLastRequest () tersedia untuk digunakan.

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

Kemudian variabel $ xml berisi xml yang dibuat oleh SoapClient untuk permintaan Anda. Bandingkan xml ini dengan yang dihasilkan di SoapUI.

Bagi saya, SoapClient tampaknya mengabaikan kunci array asosiatif $ params dan menafsirkannya sebagai array yang diindeks, menyebabkan data parameter yang salah dalam xml. Yaitu, jika saya menyusun ulang data dalam $ params , $ response sama sekali berbeda:

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

Jika Anda membuat objek dari SoapParam, ini akan menyelesaikan masalah Anda. Buat kelas dan petakan dengan tipe objek yang diberikan oleh WebService, Inisialisasi nilai dan kirim permintaan. Lihat contoh di bawah ini.

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
sumber
1

Saya memiliki masalah yang sama, tetapi saya hanya membungkus argumen seperti ini dan itu berhasil sekarang.

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

Menggunakan fungsi ini:

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

Anda dapat melihat XML Permintaan apakah itu berubah atau tidak tergantung pada argumen Anda.

Gunakan [trace = 1, pengecualian = 0] dalam opsi SoapClient.

Martin Zvarík
sumber
0

Anda perlu mendeklarasikan Kontrak kelas

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

atau

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

Kemudian

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

atau

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

Anda memerlukan array multi dimensi, Anda dapat mencoba yang berikut:

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

dalam PHP array adalah struktur dan sangat fleksibel. Biasanya dengan panggilan sabun saya menggunakan pembungkus XML jadi tidak yakin apakah itu akan berhasil.

EDIT:

Apa yang mungkin ingin Anda coba adalah membuat kueri json untuk mengirim atau menggunakannya untuk membuat semacam pembelian xml mengikuti apa yang ada di halaman ini: http://onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html

James Williams
sumber
terima kasih, tetapi tidak berhasil juga. Bagaimana Anda menggunakan pembungkus XML dengan tepat, mungkin itu lebih mudah digunakan daripada ini ...
Pertama, Anda harus memastikan bahwa WSDL Anda dapat menangani pembungkus XML. Tetapi mirip, Anda membangun permintaan dalam XML dan dalam kebanyakan kasus menggunakan curl. Saya telah menggunakan SOAP dengan XML untuk memproses transaksi melalui bank. Anda dapat melihatnya sebagai titik awal. forums.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams
0

Ada opsi untuk menghasilkan objek php5 dengan kelas WsdlInterpreter. Lihat lebih lanjut di sini: https://github.com/gkwelding/WSDLInterpreter

sebagai contoh:

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

getLastRequest ():

Metode ini hanya berfungsi jika objek SoapClient dibuat dengan opsi jejak diatur ke TRUE.

BENAR dalam hal ini diwakili oleh 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); 

bekerja untukku.

CollinsKe
sumber