วิธีโทร PHP SOAP โดยใช้คลาส SoapClient


130

ฉันเคยเขียนโค้ด PHP แต่มักไม่ใช้การเขียนโปรแกรมเชิงวัตถุ ตอนนี้ฉันต้องโต้ตอบกับ SOAP (ในฐานะลูกค้า) และฉันไม่สามารถรับไวยากรณ์ได้ ฉันมีไฟล์ WSDL ซึ่งทำให้ฉันสามารถตั้งค่าการเชื่อมต่อใหม่โดยใช้คลาส SoapClient ได้อย่างถูกต้อง อย่างไรก็ตามฉันไม่สามารถโทรออกและรับข้อมูลคืนได้ ฉันต้องการส่งข้อมูล (ประยุกต์) ต่อไปนี้

  • ID ผู้ติดต่อ
  • ชื่อผู้ติดต่อ
  • คำอธิบายทั่วไป
  • จำนวน

มีสองฟังก์ชันที่กำหนดไว้ในเอกสาร WSDL แต่ฉันต้องการเพียงหนึ่ง ("FirstFunction" ด้านล่าง) นี่คือสคริปต์ที่ฉันเรียกใช้เพื่อรับข้อมูลเกี่ยวกับฟังก์ชันและประเภทที่มี:

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

และนี่คือผลลัพธ์ที่มันสร้าง:

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

ว่าฉันต้องการโทร FirstFunction ด้วยข้อมูล:

  • ID ผู้ติดต่อ: 100
  • ชื่อผู้ติดต่อ: John
  • รายละเอียดทั่วไป: ถังน้ำมัน
  • จำนวน: 500

สิ่งที่จะเป็นไวยากรณ์ที่ถูกต้อง? ฉันได้ลองใช้ตัวเลือกทุกประเภท แต่ดูเหมือนว่าโครงสร้างสบู่ค่อนข้างยืดหยุ่นดังนั้นจึงมีหลายวิธีในการทำเช่นนี้ ไม่สามารถเข้าใจได้จากคู่มือ ...


อัปเดต 1: ลองตัวอย่างจาก 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));

Object has no 'Contact' propertyแต่ฉันได้รับการตอบสนองนี้: อย่างที่คุณเห็นในผลลัพธ์ของgetTypes()มีการstructเรียกContactดังนั้นฉันคิดว่าฉันต้องการทำให้ชัดเจนพารามิเตอร์ของฉันรวมถึงข้อมูลการติดต่อ แต่คำถามคือ: อย่างไร

ปรับปรุง 2: ฉันได้ลองโครงสร้างเหล่านี้ด้วยข้อผิดพลาดเดียวกัน

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

เช่นเดียวกับ:

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

ข้อผิดพลาดในทั้งสองกรณี: วัตถุไม่มีคุณสมบัติ 'ติดต่อ'

php  soap 

คำตอบ:


178

นี่คือสิ่งที่คุณต้องทำ

ฉันพยายามที่จะสร้างสถานการณ์ ...


  • สำหรับตัวอย่างนี้ฉันสร้าง. NET ตัวอย่าง WebService (WS) โดยมีWebMethodชื่อเรียกว่าFunction1ต้องการพารามิเตอร์ต่อไปนี้:

Function1 (ผู้ติดต่อผู้ติดต่อรายละเอียดสตริงจำนวน int)

  • ที่ไหนContactเป็นเพียงแค่นางแบบที่มีตัวเชื่อมต่อและตัวตั้งidและและnameในกรณีของคุณ

  • คุณสามารถดาวน์โหลด. NET ตัวอย่าง WS ได้ที่:

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


รหัส.

นี่คือสิ่งที่คุณต้องทำที่ฝั่ง PHP:

(ผ่านการทดสอบและทำงาน)

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

?>

ทดสอบทุกสิ่ง

  • ถ้าคุณทำprint_r($params)คุณจะเห็นผลลัพธ์ต่อไปนี้เป็น WS ของคุณคาดหวัง:

Array ([Contact] => วัตถุที่ติดต่อ ([id] => 100 [name] => John) [description] => Barrel of Oil [จำนวน] => 500)

  • เมื่อฉัน debugged. NET ตัวอย่าง WS ฉันได้รับต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

(อย่างที่คุณเห็นContactวัตถุไม่ได้เป็นnullหรือพารามิเตอร์อื่น ๆ นั่นหมายความว่าการร้องขอของคุณสำเร็จจากด้าน PHP)

  • การตอบสนองจาก. NET ตัวอย่าง WS คือสิ่งที่คาดหวังและนี่คือสิ่งที่ฉันได้รับจาก PHP

วัตถุ (stdClass) [3] สาธารณะ 'Function1Result' => สตริง 'ข้อมูลโดยละเอียดของคำขอของคุณ! id: 100, ชื่อ: John, คำอธิบาย: Barrel of Oil, จำนวน: 500 '(length = 98)


Happy Coding!


3
ที่สมบูรณ์แบบ! ฉันทำเหมือนว่าฉันรู้เกี่ยวกับบริการ SOAP มากกว่าที่ฉันทำและนี่ทำให้ฉันได้รับสิ่งที่ฉันต้องการ
chapman84

1
ฉันไม่ได้ถามคำถามมิฉะนั้นจะมี คำถามและคำตอบนี้ได้ upvote จากฉันแม้ว่า
chapman84

4
@user ควรยอมรับ :) BTW คำตอบที่ดีมากสมบูรณ์และชัดเจนมาก +1
Yann39

ขอบคุณสำหรับสิ่งนี้! Lil 'เพิ่มเพื่อทำความเข้าใจโครงสร้าง SOAP
EatCodePlaySleep

69

คุณสามารถใช้บริการ SOAP ด้วยวิธีนี้เช่นกัน:

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

นี่คือตัวอย่างของบริการจริงและใช้งานได้

หวังว่านี่จะช่วยได้


ฉันได้รับข้อผิดพลาดดังต่อไปนี้: object (stdClass) # 70 (1) {["GetWeatherResult"] => string (14) "ไม่พบข้อมูล"} มีความคิดอะไรไหม?
Ilker Baltaci

ดูเหมือนว่าพวกเขาเปลี่ยนเงื่อนไขของเมือง ฉันเพิ่งอัปเดตตัวอย่างด้วยการโทรไปยังบริการอื่นที่พวกเขามีให้ ฉันพยายามที่จะใช้สตริงที่พวกเขากลับมาเป็นเมือง แต่ดูเหมือนจะไม่ทำงานดีกว่านั้นฟังก์ชั่น getCitiesByCountry () ทำหน้าที่เป็นตัวอย่างในการโทรออก
Salvador P.

30

เริ่มต้นการบริการเว็บครั้งแรก:

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

จากนั้นตั้งค่าและส่งพารามิเตอร์:

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

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

โปรดทราบว่าชื่อวิธีการที่มีอยู่ใน WSDL เป็นชื่อการดำเนินงานเช่น:

<operation name="methodname">

ขอบคุณ! ฉันได้ลองแล้ว แต่ฉันพบข้อผิดพลาด "วัตถุไม่มีคุณสมบัติ" ติดต่อ " จะอัปเดตคำถามของฉันพร้อมรายละเอียดทั้งหมด ความคิดใด ๆ

@ user16441 คุณสามารถโพสต์ WSDL และสคีมาของบริการได้หรือไม่? ฉันมักจะเริ่มต้นด้วยการหาสิ่งที่ XML คาดหวังบริการจากนั้นใช้ WireShark เพื่อคิดออกสิ่งที่ลูกค้าของฉันกำลังส่งจริง
davidfmatheson

21

ฉันไม่ทราบว่าเพราะเหตุใดบริการเว็บของฉันจึงมีโครงสร้างแบบเดียวกันกับคุณ แต่ไม่ต้องการพารามิเตอร์ Class สำหรับเพียงแค่อาร์เรย์

ตัวอย่างเช่น: - 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>

ฉัน var_dump:

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

นี่คือผลลัพธ์:

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)

ดังนั้นในรหัสของฉัน:

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

แต่มันก็ประสบความสำเร็จ!


1
ตัวอย่างของคุณมีประโยชน์มากขึ้นทำให้มันแสดงโครงสร้างการพึ่งพา
vladkras

3

อ่านนี่;-

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

หรือ

นี่เป็นตัวอย่างที่ดีสำหรับฟังก์ชัน SOAP "__call" อย่างไรก็ตามมันเลิกใช้แล้ว

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

ขั้นแรกให้ใช้SoapUIเพื่อสร้างโครงการสบู่ของคุณจาก wsdl ลองส่งคำขอเพื่อเล่นกับการทำงานของ wsdl สังเกตว่าคำขอ xml รวบรวมเขตข้อมูลของคุณอย่างไร

และถ้าคุณมีปัญหาในการทำให้ SoapClient ทำตามที่คุณต้องการนี่คือวิธีที่ฉันจะแก้ไขข้อบกพร่อง ตั้งค่าการติดตามตัวเลือกเพื่อให้ฟังก์ชัน__getLastRequest ()พร้อมใช้งาน

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

จากนั้นตัวแปร$ xmlจะมี xml ที่ SoapClient เขียนขึ้นสำหรับคำขอของคุณ เปรียบเทียบ xml นี้กับที่สร้างใน SoapUI

สำหรับฉันดูเหมือนว่า SoapClient จะไม่สนใจคีย์ของ$ paramsแบบเชื่อมโยงและตีความว่าเป็นอาร์เรย์ที่จัดทำดัชนีทำให้เกิดข้อมูลพารามิเตอร์ที่ไม่ถูกต้องใน xml นั่นคือถ้าฉันเรียงลำดับข้อมูลใน$ paramsการตอบกลับ $แตกต่างอย่างสิ้นเชิง:

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

3

หากคุณสร้างวัตถุของ SoapParam สิ่งนี้จะแก้ไขปัญหาของคุณ สร้างคลาสและแมปกับชนิดของวัตถุที่กำหนดโดย WebService เริ่มต้นค่าและส่งคำขอ ดูตัวอย่างด้านล่าง

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

ฉันมีปัญหาเดียวกัน แต่ฉันเพิ่งเอาข้อโต้แย้งแบบนี้มาใช้แล้ว

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

ใช้ฟังก์ชั่นนี้:

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

คุณสามารถดูคำขอ XML ว่ามีการเปลี่ยนแปลงหรือไม่ขึ้นอยู่กับข้อโต้แย้งของคุณ

ใช้ [ติดตาม = 1, ข้อยกเว้น = 0] ในตัวเลือก SoapClient


0

คุณต้องประกาศสัญญาของชั้นเรียน

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

หรือ

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

แล้วก็

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

หรือ

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

0

คุณต้องมีอาร์เรย์หลายมิติคุณสามารถลองต่อไปนี้:

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

ใน PHP อาร์เรย์เป็นโครงสร้างและมีความยืดหยุ่นสูง ปกติแล้วการโทรด้วยสบู่ฉันใช้ XML wrapper ดังนั้นจึงไม่แน่ใจว่ามันจะทำงานได้ดีหรือไม่

แก้ไข:

สิ่งที่คุณอาจต้องการลองคือการสร้างแบบสอบถาม json เพื่อส่งหรือใช้สิ่งนั้นเพื่อสร้าง xml buy sort ตามสิ่งที่อยู่ในหน้านี้: http://onwebdev.blogspot.com/2011/08/php-converting-rss- เพื่อ json.html


ขอบคุณ แต่มันก็ไม่ได้ผลเหมือนกัน คุณจะใช้ XML wrappers ได้อย่างไรบางทีอาจจะใช้ง่ายกว่านี้ ...

ก่อนอื่นคุณต้องให้แน่ใจว่า WSDL ของคุณสามารถจัดการ XML wrapper ได้ แต่มันก็คล้ายกันคุณสร้างคำขอใน XML และในกรณีส่วนใหญ่ใช้ curl ฉันใช้ SOAP กับ XML เพื่อประมวลผลธุรกรรมผ่านธนาคาร คุณสามารถตรวจสอบสิ่งเหล่านี้เป็นจุดเริ่มต้น forums.digitalpoint.com/showthread.php?t=424619#post4004636 w3schools.com/soap/soap_intro.asp
James Williams

0

มีตัวเลือกในการสร้างวัตถุ php5 ด้วยคลาส WsdlInterpreter ดูเพิ่มเติมได้ที่นี่: https://github.com/gkwelding/WSDLInterpreter

ตัวอย่างเช่น:

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

0

getLastRequest ():

วิธีนี้ใช้ได้เฉพาะเมื่อมีการสร้างออบเจ็กต์ SoapClient ด้วยตัวเลือกการติดตามที่ตั้งค่าเป็น TRUE

TRUE ในกรณีนี้แทนด้วย 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); 

ทำงานให้ฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.