SoapClient sınıfını kullanarak PHP SOAP çağrısı nasıl yapılır


130

PHP kodu yazmaya alışkınım, ancak Nesneye Yönelik kodlamayı sıklıkla kullanmıyorum. Şimdi (bir istemci olarak) SOAP ile etkileşime girmem gerekiyor ve sözdizimini doğru yapamıyorum. SoapClient sınıfını kullanarak düzgün bir şekilde yeni bir bağlantı kurmama izin veren bir WSDL dosyam var. Ancak, aslında doğru aramayı yapıp verileri geri alamıyorum. Aşağıdaki (basitleştirilmiş) verileri göndermem gerekiyor:

  • Kişi Kimliği
  • Kişi Adı
  • Genel açıklama
  • Miktar

WSDL belgesinde tanımlanmış iki işlev vardır, ancak yalnızca birine ihtiyacım var (aşağıdaki "FirstFunction"). Kullanılabilir işlevler ve türler hakkında bilgi almak için çalıştırdığım komut dosyası şu şekildedir:

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

Ve işte ürettiği çıktı:

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

Veriyle FirstFunction'a bir çağrı yapmak istediğimi varsayalım:

  • İletişim ID: 100
  • Kişi Adı: John
  • Genel Açıklama: Varil Petrol
  • Miktar: 500

Doğru sözdizimi ne olurdu? Her türlü seçeneği deniyorum ama görünüşe göre sabun yapısı oldukça esnek, bu yüzden bunu yapmanın birçok yolu var. Kılavuzdan da anlayamadım ...


GÜNCELLEME 1: MMK'dan denenmiş örnek:

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

Ama bu yanıt almak: Object has no 'Contact' property. Çıktısında görebileceğiniz gibi getTypes(), bir structçağrı varContact , bu yüzden sanırım bir şekilde parametrelerimin İletişim verilerini içerdiğini netleştirmem gerekiyor, ancak soru şu: nasıl?

GÜNCELLEME 2: Bu yapıları da denedim, aynı hatayı.

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

Hem de:

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

Her iki durumda da hata: Nesnede "İletişim" özelliği yok "

php  soap 

Yanıtlar:


178

Yapman gereken bu.

Durumu yeniden yaratmaya çalıştım ...


  • Bu örnek için, aşağıdaki parametreleri bekleyen bir WebMethodadlı .NET örnek Web Hizmeti (WS) oluşturdum Function1:

Function1 (Contact Contact, string açıklaması, int miktar)

  • Nerede Contactiçin Alıcılar ve ayarlayıcılar olan bir modeli adildir idve namesevdiği durumda.

  • NET örnek WS'yi şu adresten indirebilirsiniz:

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


Kod.

PHP tarafında yapmanız gereken bu:

(Test edildi ve çalışıyor)

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

?>

Her şeyi test ediyorum.

  • Bunu yaparsanız print_r($params), WS'nizin beklediği gibi aşağıdaki çıktıyı göreceksiniz:

Dizi ([Contact] => İletişim Nesnesi ([id] => 100 [isim] => John) [description] => Petrol Varili [miktar] => 500)

  • .NET örneği WS'de hata ayıkladığımda aşağıdakileri aldım:

görüntü açıklamasını buraya girin

(Gördüğünüz gibi, Contactnesne nullveya diğer parametreler değildir. Bu, isteğinizin PHP tarafından başarıyla gerçekleştirildiği anlamına gelir)

  • .NET örneği WS'nin yanıtı beklenen bir yanıttı ve PHP tarafında şunu elde ettim:

nesne (stdClass) [3] public 'Function1Result' => string 'Talebinize ilişkin ayrıntılı bilgi! id: 100, isim: John, açıklama: Varil Petrol, miktar: 500 '(uzunluk = 98)


Mutlu Kodlama!


3
Mükemmel! SOAP hizmetleri hakkında gerçekten bildiğimden biraz daha fazlasını biliyormuşum gibi davrandım ve bu beni olmam gereken yere getirdi.
chapman84

1
Soruyu ben sormadım, yoksa yapardım. Soru ve bu cevap benden yine de olumlu oy aldı.
chapman84

4
@ kullanıcı bunu kabul etmeli :) BTW, çok güzel cevap, eksiksiz ve çok net. +1
Yann39

Bunun için teşekkürler! SABUN yapısını anlamak için Lil 'destek.
EatCodePlaySleep

69

SABUN servislerini şu şekilde de kullanabilirsiniz:

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

Bu gerçek bir hizmet örneğidir ve işe yaramaktadır.

Bu yardımcı olur umarım.


Şu hatayı alıyorum: object (stdClass) # 70 (1) {["GetWeatherResult"] => string (14) "Veri Bulunamadı"} Herhangi bir fikriniz var mı?
İlker Baltacı

Şehirlerin iplerini değiştirmiş gibi görünüyorlar. Örneği, sağladıkları başka bir hizmete yapılan başka bir arama ile güncelledim ve çalışıyor. Şehir olarak döndükleri dizeleri kullanmaya çalıştım, ancak iyi çalışmıyor gibi görünüyor, yine de getCitiesByCountry () işlevi nasıl çağrı yapılacağına örnek olarak hizmet ediyor.
Salvador P.

30

Önce web hizmetlerini başlatın:

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

Ardından parametreleri ayarlayın ve iletin:

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

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

Yöntem adının WSDL'de işlem adı olarak bulunduğunu unutmayın, örneğin:

<operation name="methodname">

Teşekkürler! Bunu denedim, ancak "Nesnenin 'İletişim' özelliği yok" hatasını alıyorum. Sorum tüm ayrıntılarıyla güncellenecek. Herhangi bir fikir?

@ user16441 Hizmetin WSDL ve şemasını gönderebilir misiniz? Genelde hizmetin hangi XML'i beklediğini bulmakla başlayıp, ardından müşterimin gerçekte ne gönderdiğini anlamak için WireShark'ı kullanıyorum.
davidfmatheson

21

Web servisimin neden sizinle aynı yapıya sahip olduğunu bilmiyorum ama parametre için Class'a ihtiyacı yok, sadece dizi.

Örneğin: - WSDL'm:

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

Var_dump:

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

İşte sonuç:

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)

Yani benim kodumda:

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

ama başarılı bir şekilde!



3

Oku bunu;-

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

Veya

Bu, SABUN işlevi "__call" için iyi bir örnektir. Ancak kullanımdan kaldırılmıştır.

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

Öncelikle, sabun projenizi wsdl'den oluşturmak için SoapUI kullanın. Wsdl'nin işlemleriyle oynamak için bir istek göndermeyi deneyin. Xml isteğinin veri alanlarınızı nasıl oluşturduğunu gözlemleyin.

Ve sonra, SoapClient'in istediğiniz gibi davranmasını sağlamakta sorun yaşıyorsanız, işte nasıl hata ayıklayacağım. İzleme seçeneğini , __getLastRequest () işlevinin kullanılabileceği şekilde ayarlayın.

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

Daha sonra $ xml değişkeni, SoapClient'in isteğiniz için oluşturduğu xml'yi içerir. Bu xml'yi SoapUI'de oluşturulanla karşılaştırın.

Benim için, SoapClient $ params ilişkilendirilebilir dizisinin anahtarlarını görmezden geliyor ve bunu indekslenmiş dizi olarak yorumlayarak xml'de yanlış parametre verilerine neden oluyor gibi görünüyor . Yani, verileri $ params cinsinden yeniden sıralarsam , $ yanıtı tamamen farklıdır:

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

3

SoapParam nesnesini oluşturursanız, bu sorununuzu çözecektir. Bir sınıf oluşturun ve WebService tarafından verilen nesne türüyle eşleyin, Değerleri başlatın ve istekte gönderin. Aşağıdaki örneğe bakın.

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

Ben de aynı sorunu yaşadım, ancak argümanları sadece şöyle sardım ve şimdi işe yarıyor.

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

Bu işlevi kullanarak:

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

Argümanlarınıza bağlı olarak istek XML'inin değişip değişmediğini görebilirsiniz.

SoapClient seçeneklerinde [trace = 1, exceptions = 0] kullanın.


0

Sınıf sözleşmesini beyan etmeniz gerekiyor

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

veya

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

Sonra

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

veya

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

0

Çok boyutlu bir diziye ihtiyacınız var, aşağıdakileri deneyebilirsiniz:

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

PHP'de dizi bir yapıdır ve çok esnektir. Normalde sabun çağrılarında bir XML sarıcı kullanıyorum, bu yüzden çalışıp çalışmayacağından emin değilim.

DÜZENLE:

Denemek isteyebileceğiniz şey, göndermek için bir json sorgusu oluşturmak veya bu sayfada bulunanları takip eden bir xml satın alma türü oluşturmak için kullanmaktır: http://onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html


teşekkürler, ama işe yaramadı. XML sarmalayıcıları tam olarak nasıl kullanıyorsunuz, belki de kullanımı bundan daha kolaydır ...

Öncelikle WSDL'nizin XML sarmalayıcıları işleyebildiğinden emin olmalısınız. Ancak benzerdir, isteği XML'de oluşturursunuz ve çoğu durumda curl kullanırsınız. Bankalar aracılığıyla işlemleri işlemek için XML ile SOAP kullanıyorum. Bunları bir başlangıç ​​noktası olarak kontrol edebilirsiniz. forums.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams

0

WsdlInterpreter sınıfı ile php5 nesneleri oluşturma seçeneği vardır. Daha fazlasını burada görün: https://github.com/gkwelding/WSDLInterpreter

Örneğin:

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

0

getLastRequest ():

Bu yöntem yalnızca, SoapClient nesnesi izleme seçeneği TRUE olarak ayarlanmış şekilde oluşturulmuşsa çalışır.

Bu durumda DOĞRU 1 ile temsil edilir

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

benim için çalıştı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.