【问题标题】:How to make a PHP SOAP call using the SoapClient class如何使用 SoapClient 类进行 PHP SOAP 调用
【发布时间】:2012-07-21 15:52:27
【问题描述】:

我习惯于编写 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
  • 联系人姓名:约翰
  • 一般说明:油桶
  • 金额: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() 的输出中看到的那样,有一个名为Contact 的struct,所以我想我需要以某种方式明确我的参数包括联系人数据,但问题是:如何?

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


    【解决方案1】:

    这是你需要做的。

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


    • 对于本示例,我创建了一个带有 WebMethod 的 .NET 示例 WebService (WS),名为 Function1,需要以下参数:

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

    • Contact 只是一个模型,它具有 id 和 name 的 getter 和 setter,就像你的情况一样。

    • 您可以在以下位置下载 .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 ) [描述] => 油桶 [数量] => 500 )

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

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

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

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


    【讨论】:

    • 完美!我表现得好像我对 SOAP 服务的了解比我真正了解的多一点,这让我到达了我需要的地方。
    • 我没有问这个问题,否则我会问的。不过,这个问题和这个答案得到了我的支持。
    • @user 应该接受它:) 顺便说一句,非常好的答案,完整且非常清楚。 +1
    • 谢谢!有助于理解 SOAP 结构。
    【解决方案2】:

    您也可以通过这种方式使用 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);
    

    这是一个真实服务的例子,它在 url 启动时工作。

    以防万一http://www.webservicex.net 宕机。

    这是另一个示例使用示例网络服务来自W3C XML Web Services 示例,您可以在链接上找到更多信息。

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

    这正在工作并返回转换后的温度值。

    【讨论】:

    • 我收到以下错误:object(stdClass)#70 (1) { ["GetWeatherResult"]=> string(14) "Data Not Found" } 有什么想法吗?
    • 似乎他们改变了城市的字符串。我刚刚更新了示例,再次调用他们提供的另一个服务并且它正在工作。我尝试使用它们作为城市返回的字符串,但似乎不能正常工作,无论如何 getCitiesByCountry() 函数用作如何拨打电话的示例。
    • 这个例子又挂了
    • @CSchwarz 感谢反馈使用从 W3C 页面提取的不同 Web 服务更新了答案。几乎所有的 Web 服务现在都需要 api 密钥来使用它们,我认为举个简单的例子有点过分了。
    【解决方案3】:

    首先初始化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">
    

    【讨论】:

    • 谢谢!我已经尝试过了,但我收到错误“对象没有'联系人'属性”。将用完整的细节更新我的问题。有什么想法吗?
    • @user16441 您可以发布服务的 WSDL 和架构吗?我通常首先弄清楚服务期望什么 XML,然后使用 WireShark 来确定我的客户端实际发送的内容。
    【解决方案4】:

    我不知道为什么我的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);
    

    但是成功了!

    【讨论】:

    • 你的例子更有帮助,因为它显示了结构依赖
    【解决方案5】:

    阅读这个;-

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

    【讨论】:

      【解决方案6】:

      首先,使用SoapUI 从wsdl 创建您的soap 项目。尝试发送请求以使用 wsdl 的操作。观察 xml 请求如何构成您的数据字段。

      然后,如果您在让 SoapClient 按您想要的方式运行时遇到问题,我将按照以下方式进行调试。设置选项 trace 以便函数 __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);
      

      【讨论】:

        【解决方案7】:

        如果您创建 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);
        

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题,但我只是像这样包装了参数,现在它可以工作了。

              $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]。

          【讨论】:

            【解决方案9】:

            你需要声明类Contract

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

            【讨论】:

              【解决方案10】:

              你需要一个多维数组,你可以尝试以下:

              $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

              【讨论】:

              【解决方案11】:

              有一个选项可以使用 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('.');
              

              【讨论】:

                【解决方案12】:

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

                【讨论】:

                  【解决方案13】:

                  以下代码可能会有所帮助

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

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-09-28
                    • 1970-01-01
                    相关资源
                    最近更新 更多