143

我习惯编写 PHP 代码,但不经常使用面向对象的编码。我现在需要与 SOAP(作为客户端)进行交互,并且无法正确使用语法。我有一个 WSDL 文件,它允许我使用 SoapClient 类正确设置新连接。但是,我实际上无法做出正确的调用并返回数据。我需要发送以下(简化的)数据:

  • 联络号码
  • 联系人姓名
  • 一般说明
  • 数量

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:

  • 联络号码:100
  • 联系人姓名:约翰
  • 概述:油桶
  • 金额: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,
);

两种情况下的错误:对象没有“联系人”属性`

4

13 回答 13

185

这是你需要做的。

我试图重现这种情况......


  • 对于此示例,我创建了一个 .NET 示例 WebService (WS),其中WebMethod调用了Function1期望以下参数:

Function1(Contact Contact, 字符串描述, int amount)

  • Where Contactis just a model that has getter and setter for idand namelike in your case.

  • 您可以在以下位置下载 .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 所期望的那样:

数组 ( [Contact] => 接触对象 ( [id] => 100 [name] => John ) [description] => 每桶油 [amount] => 500 )

  • 当我调试 .NET 示例 WS 时,我得到以下信息:

在此处输入图像描述

(如您所见,Contact对象null既不是其他参数也不是。这意味着您的请求已从 PHP 端成功完成)

  • .NET 示例 WS 的响应是预期的,这就是我在 PHP 方面得到的:

object(stdClass)[3] public 'Function1Result' => string '您的请求的详细信息!id:100,姓名:John,描述:油桶,数量:500'(长度=98)


于 2012-07-30T01:37:29.247 回答
77

You can use SOAP services this way too:

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

This is an example with a real service, and it works when the url is up.

Just in case the http://www.webservicex.net is down.

Here is another example using the example web service from W3C XML Web Services example, you can find more information on the link.

<?php
//Create the client object
$soapclient = new SoapClient('https://www.w3schools.com/xml/tempconvert.asmx?WSDL');

//Use the functions of the client, the params of the function are in
//the associative array
$params = array('Celsius' => '25');
$response = $soapclient->CelsiusToFahrenheit($params);

var_dump($response);

// Get the Celsius degrees from the Farenheit
$param = array('Fahrenheit' => '25');
$response = $soapclient->FahrenheitToCelsius($param);

var_dump($response);

This is working and returning the converted temperature values.

于 2013-06-12T14:00:43.420 回答
31

首先初始化webservices:

$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">
于 2012-07-21T16:18:25.030 回答
23

我不知道为什么我的 web 服务和你有相同的结构,但它不需要 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);

但它成功了!

于 2013-07-17T03:17:42.133 回答
3

read this;-

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

Or

This is a good example, for the SOAP function "__call". However it is deprecated.

<?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>";
?>
于 2012-07-29T19:52:32.160 回答
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);
于 2012-07-25T14:19:15.953 回答
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变量包含 SoapClient 为您的请求编写的 xml。将此 xml 与 SoapUI 中生成的进行比较。

对我来说,SoapClient 似乎忽略了关联数组$params的键并将其解释为索引数组,从而导致 xml 中的参数数据错误。也就是说,如果我重新排序$params中的数据,则$response完全不同:

$params = ['account' => '12345', 'user' => 'Hey'];
$response = $soapClient->__soapCall('<operation>', $params);
于 2018-01-26T04:25:03.873 回答
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 是否正在更改。

在 SoapClient 选项中使用 [trace = 1, exceptions = 0]。

于 2018-06-21T14:54:51.307 回答
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);
于 2012-07-29T23:17:39.807 回答
0

您需要一个多维数组,您可以尝试以下方法:

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

在 PHP 中,数组是一种结构,非常灵活。通常在进行肥皂调用时,我使用 XML 包装器,因此不确定它是否会起作用。

编辑:

您可能想要尝试的是创建一个 json 查询来发送或使用它来创建一个 xml 购买排序,如下所示:http: //onwebdev.blogspot.com/2011/08/php-converting-rss- to-json.html

于 2012-07-23T19:29:24.210 回答
0

下面的代码可能会有所帮助

    $wsdl ='My_WSDL_Service.wsdl";
    $options = array(
        'login' => 'user-name',
        'password' => 'Password',
    );
    try {
        $client = new SoapClient($wsdl, $options);
        $params = array(
            'para1' => $para1,
            'para2' => $para2
        );
        $res = $client->My_WSDL_Service($params);
于 2021-11-11T09:34:09.120 回答
0

有一个选项可以使用 WsdlInterpreter 类生成 php5 对象。在此处查看更多信息:https ://github.com/gkwelding/WSDLInterpreter

例如:

require_once 'WSDLInterpreter-v1.0.0/WSDLInterpreter.php';
$wsdlLocation = '<your wsdl url>?wsdl';
$wsdlInterpreter = new WSDLInterpreter($wsdlLocation);
$wsdlInterpreter->savePHP('.');
于 2018-04-23T14:41:37.627 回答
0

获取最后请求():

仅当在跟踪选项设置为 TRUE 的情况下创建 SoapClient 对象时,此方法才有效。

在这种情况下 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);
于 2019-07-16T06:41:55.583 回答