Cách thực hiện cuộc gọi PHP SOAP bằng lớp SoapClient


130

Tôi đã quen viết mã PHP, nhưng không thường xuyên sử dụng mã hóa hướng đối tượng. Bây giờ tôi cần tương tác với SOAP (với tư cách là khách hàng) và không thể có được cú pháp đúng. Tôi đã có tệp WSDL cho phép tôi thiết lập đúng kết nối mới bằng lớp SoapClient. Tuy nhiên, tôi thực sự không thể thực hiện cuộc gọi đúng và nhận lại dữ liệu. Tôi cần gửi dữ liệu (đơn giản hóa) sau:

  • ID liên hệ
  • Tên Liên lạc
  • Mô tả chung
  • Số tiền

Có hai hàm được định nghĩa trong tài liệu WSDL, nhưng tôi chỉ cần một ("FirstFunction" bên dưới). Đây là kịch bản tôi chạy để lấy thông tin về các chức năng và loại có sẵn:

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

Và đây là đầu ra mà nó tạo ra:

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

Nói rằng tôi muốn thực hiện cuộc gọi đến FirstFactor với dữ liệu:

  • ID liên hệ: 100
  • Tên liên hệ: John
  • Mô tả chung: Thùng dầu
  • Số tiền: 500

Điều gì sẽ là cú pháp đúng? Tôi đã thử tất cả các loại tùy chọn nhưng có vẻ như cấu trúc xà phòng khá linh hoạt nên có rất nhiều cách để làm điều này. Không thể tìm ra nó từ hướng dẫn ...


CẬP NHẬT 1: mẫu đã thử từ 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));

Nhưng tôi nhận được phản hồi này : Object has no 'Contact' property. Như bạn có thể thấy trong đầu ra của getTypes(), có một lệnh structđược gọi Contact, vì vậy tôi đoán rằng bằng cách nào đó tôi cần phải làm rõ các tham số của mình bao gồm dữ liệu Liên hệ, nhưng câu hỏi là: làm thế nào?

CẬP NHẬT 2: Tôi cũng đã thử các cấu trúc này, cùng một lỗi.

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

Cũng như:

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

Lỗi trong cả hai trường hợp: Đối tượng không có thuộc tính 'Liên hệ'

php  soap 

Câu trả lời:


178

Đây là những gì bạn cần làm.

Tôi đã cố gắng tạo lại tình huống ...


  • Trong ví dụ này, tôi đã tạo một mẫu WebService (WS) .NET với một lệnh WebMethodđược gọi là Function1mong đợi các thông số sau:

Hàm1 (Liên hệ Liên hệ, mô tả chuỗi, số tiền int)

  • Trường hợp Contactchỉ là một mô hình có getters và setters cho idnamethích trong trường hợp của bạn.

  • Bạn có thể tải xuống WS mẫu .NET tại:

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


Mật mã.

Đây là những gì bạn cần làm ở phía PHP:

(Đã thử nghiệm và làm việc)

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

?>

Kiểm tra toàn bộ.

  • Nếu bạn làm, print_r($params)bạn sẽ thấy đầu ra sau, như WS của bạn mong đợi:

Mảng ([Liên hệ] => Đối tượng liên hệ ([id] => 100 [tên] => John) [mô tả] => Thùng dầu [số tiền] => 500)

  • Khi tôi gỡ lỗi WS mẫu .NET, tôi nhận được như sau:

nhập mô tả hình ảnh ở đây

(Như bạn có thể thấy, Contactđối tượng không nullphải là các thông số khác. Điều đó có nghĩa là yêu cầu của bạn đã được thực hiện thành công từ phía PHP)

  • Phản hồi từ WS mẫu .NET là dự kiến ​​và đây là những gì tôi nhận được ở phía PHP:

object (stdClass) [3] công khai 'Function1Result' => chuỗi 'Thông tin chi tiết về yêu cầu của bạn! id: 100, tên: John, mô tả: Thùng dầu, số tiền: 500 '(length = 98)


Chúc mừng mã hóa!


3
Hoàn hảo! Tôi đã hành động như tôi biết nhiều hơn một chút về các dịch vụ SOAP so với thực tế và điều này đã đưa tôi đến nơi tôi cần.
chapman84

1
Tôi đã không đặt câu hỏi, nếu không tôi sẽ có. Câu hỏi và câu trả lời này đã nhận được một upvote từ tôi mặc dù.
chapman84

4
@user nên chấp nhận nó :) BTW, câu trả lời rất hay, đầy đủ và rất rõ ràng. +1
Yann39

Cảm ơn vì điều đó! Lil 'tăng cường để hiểu cấu trúc SOAP.
EatCodePlayS ngủ

69

Bạn cũng có thể sử dụng dịch vụ SOAP theo cách này:

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

Đây là một ví dụ với một dịch vụ thực sự, và nó hoạt động.

Hi vọng điêu nay co ich.


Tôi nhận được lỗi sau: object (stdClass) # 70 (1) {["GetWeatherResult"] => chuỗi (14) "Không tìm thấy dữ liệu"} Có ý tưởng nào không?
Ilker Baltaci

Có vẻ như họ đã thay đổi chuỗi của các thành phố. Tôi vừa cập nhật ví dụ với một cuộc gọi khác đến một dịch vụ khác mà họ cung cấp và nó đang hoạt động. Tôi đã cố gắng sử dụng các chuỗi họ trả về dưới dạng thành phố, nhưng dường như không hoạt động tốt, dù sao thì hàm getCitiesByCountry () đóng vai trò là ví dụ về cách thực hiện cuộc gọi.
Salvador P.

29

Đầu tiên khởi tạo dịch vụ web:

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

Sau đó thiết lập và truyền các tham số:

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

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

Lưu ý rằng tên phương thức có sẵn trong WSDL dưới dạng tên hoạt động, ví dụ:

<operation name="methodname">

Cảm ơn! Tôi đã thử điều này nhưng tôi nhận được lỗi "Đối tượng không có thuộc tính 'Liên hệ'. Sẽ cập nhật câu hỏi của tôi với đầy đủ chi tiết. Có ý kiến ​​gì không?

@ user16441 Bạn có thể đăng WSDL và lược đồ của dịch vụ không? Tôi thường bắt đầu bằng cách tìm ra XML mà dịch vụ mong đợi, sau đó sử dụng WireShark để tìm hiểu xem khách hàng của tôi thực sự đang gửi cái gì.
davidfmatheson

21

Tôi không biết tại sao dịch vụ web của tôi có cùng cấu trúc với bạn nhưng nó không cần Class cho tham số, chỉ là mảng.

Ví dụ: - WSDL của tôi:

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

Tôi thay đổi:

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

Đây là kết quả:

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)

Vì vậy, trong mã của tôi:

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

nhưng nó thành công


1
Ví dụ của bạn hữu ích hơn, vì nó hiển thị các phụ thuộc cấu trúc
vladkras

3

đọc này;-

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

Hoặc là

Đây là một ví dụ hay, cho hàm SOAP "__call". Tuy nhiên nó không được dùng nữa.

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

Đầu tiên, sử dụng SoapUI để tạo dự án xà phòng của bạn từ wsdl. Cố gắng gửi yêu cầu để chơi với các hoạt động của wsdl. Quan sát cách yêu cầu xml tổng hợp các trường dữ liệu của bạn.

Và sau đó, nếu bạn gặp vấn đề với việc SoapClient hoạt động như bạn muốn, đây là cách tôi gỡ lỗi. Đặt theo dõi tùy chọn sao cho hàm __getLastRequest () có sẵn để sử dụng.

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

Sau đó, biến $ xml chứa xml mà SoapClient soạn cho yêu cầu của bạn. So sánh xml này với cái được tạo trong SoapUI.

Đối với tôi, SoapClient dường như bỏ qua các khóa của mảng kết hợp $ params và diễn giải nó là mảng được lập chỉ mục, gây ra dữ liệu tham số sai trong xml. Đó là, nếu tôi sắp xếp lại dữ liệu theo $ params , phản hồi $ hoàn toàn khác:

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

3

Nếu bạn tạo đối tượng của SoapParam, Điều này sẽ giải quyết vấn đề của bạn. Tạo một lớp và ánh xạ nó với loại đối tượng được cung cấp bởi WebService, Khởi tạo các giá trị và gửi yêu cầu. Xem mẫu dưới đây.

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

Tôi đã có cùng một vấn đề, nhưng tôi chỉ gói gọn các đối số như thế này và nó hoạt động ngay bây giờ.

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

Sử dụng chức năng này:

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

Bạn có thể thấy XML Yêu cầu cho dù nó có thay đổi hay không tùy thuộc vào đối số của bạn.

Sử dụng [dấu vết = 1, ngoại lệ = 0] trong tùy chọn SoapClient.


0

Bạn cần khai báo Hợp đồng lớp

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

hoặc là

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

Sau đó

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

hoặc là

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

0

Bạn cần một mảng đa chiều, bạn có thể thử như sau:

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

trong PHP một mảng là một cấu trúc và rất linh hoạt. Thông thường với các cuộc gọi xà phòng, tôi sử dụng trình bao bọc XML nên không chắc nó có hoạt động không.

BIÊN TẬP:

Những gì bạn có thể muốn thử là tạo một truy vấn json để gửi hoặc sử dụng truy vấn đó để tạo ra một loại mua xml theo sau trên trang này: http://onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html


cảm ơn, nhưng nó cũng không hoạt động. Làm thế nào để bạn sử dụng các trình bao bọc XML chính xác, có lẽ nó dễ sử dụng hơn thế này ...

Trước tiên, bạn phải đảm bảo rằng WSDL của bạn có thể xử lý các trình bao bọc XML. Nhưng nó cũng tương tự, bạn xây dựng yêu cầu bằng XML và trong hầu hết các trường hợp sử dụng curl. Tôi đã sử dụng SOAP với XML để xử lý các giao dịch qua ngân hàng. Bạn có thể kiểm tra những điều này như là một điểm khởi đầu. forum.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams

0

Có một tùy chọn để tạo các đối tượng php5 với lớp WsdlInterpreter. Xem thêm tại đây: https://github.com/gkwelding/WSDLInterpreter

ví dụ:

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

0

getLastRequest ():

Phương thức này chỉ hoạt động nếu đối tượng SoapClient được tạo với tùy chọn theo dõi được đặt thành TRUE.

TRUE trong trường hợp này được đại diện bởi 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); 

đã làm cho tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.