使用PHP通过POST方式发送XML

5
我知道在SO上有很多类似的问题,但我已经尝试过所有的解决方案,似乎都不能使它正常工作。我正在尝试直接向Web服务发送XML并获得响应。技术上,我正在尝试连接到freightquote.com,您可以在页面右上角的文档中找到相关文档。我之所以提到这一点是因为我在他们的XML中经常看到SOAP这个术语,这可能会有所影响。无论如何,我想要的是能够将XML发送到某个URL并获得响应的能力。
所以如果我有以下内容:
$xml = "<?xml version='1.0' encoding='utf-8'?>
            <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' 
            xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
            xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
            <soap:Body>
              <GetRatingEngineQuote xmlns='http://tempuri.org/'>
                <request>
                  <CustomerId>0</CustomerId> <!-- Identifier for customer provided by Freightquote -->
                  <QuoteType>B2B</QuoteType> <!-- B2B / eBay /Freightview -->
                  <ServiceType>LTL</ServiceType> <!--  LTL / Truckload / Groupage / Haulage / Al  -->
                  <QuoteShipment>
                    <IsBlind>false</IsBlind>
                    <PickupDate>2010-09-13T00:00:00</PickupDate>
                    <SortAndSegregate>false</SortAndSegregate>
                    <ShipmentLocations>
                      <Location>
                        <LocationType>Origin</LocationType>
                        <RequiresArrivalNotification>false</RequiresArrivalNotification>
                        <HasDeliveryAppointment>false</HasDeliveryAppointment>
                        <IsLimitedAccess>false</IsLimitedAccess>
                        <HasLoadingDock>false</HasLoadingDock>
                        <IsConstructionSite>false</IsConstructionSite>
                        <RequiresInsideDelivery>false</RequiresInsideDelivery>
                        <IsTradeShow>false</IsTradeShow>
                        <IsResidential>false</IsResidential>
                        <RequiresLiftgate>false</RequiresLiftgate>
                        <LocationAddress>
                          <PostalCode>30303</PostalCode>
                          <CountryCode>US</CountryCode>
                        </LocationAddress>
                        <AdditionalServices />
                      </Location>
                      <Location>
                        <LocationType>Destination</LocationType>
                        <RequiresArrivalNotification>false</RequiresArrivalNotification>
                        <HasDeliveryAppointment>false</HasDeliveryAppointment>
                        <IsLimitedAccess>false</IsLimitedAccess>
                        <HasLoadingDock>false</HasLoadingDock>
                        <IsConstructionSite>false</IsConstructionSite>
                        <RequiresInsideDelivery>false</RequiresInsideDelivery>
                        <IsTradeShow>false</IsTradeShow>
                        <IsResidential>false</IsResidential>
                        <RequiresLiftgate>false</RequiresLiftgate>
                        <LocationAddress>
                          <PostalCode>60606</PostalCode>
                          <CountryCode>US</CountryCode>
                        </LocationAddress>
                        <AdditionalServices />
                      </Location>
                    </ShipmentLocations>
                    <ShipmentProducts>
                      <Product>
                        <Class>55</Class>
                        <Weight>1200</Weight>
                        <Length>0</Length>
                        <Width>0</Width>
                        <Height>0</Height>
                        <ProductDescription>Books</ProductDescription>
                        <PackageType>Pallets_48x48</PackageType>
                        <IsStackable>false</IsStackable>
                        <DeclaredValue>0</DeclaredValue>
                        <CommodityType>GeneralMerchandise</CommodityType>
                        <ContentType>NewCommercialGoods</ContentType>
                        <IsHazardousMaterial>false</IsHazardousMaterial>
                        <PieceCount>5</PieceCount>
                        <ItemNumber>0</ItemNumber>
                      </Product>
                    </ShipmentProducts>
                    <ShipmentContacts />
                  </QuoteShipment>
                </request>
                <user>
                  <Name>someone@something.com</Name>
                  <Password>password</Password>
                </user>
              </GetRatingEngineQuote>
            </soap:Body>
            </soap:Envelope>";

我把实际的xml编辑进来了,这样可能更有助于理解。

我想要将它发送到http://www.someexample.com并获得响应。此外,我需要对其进行编码吗?我在android上已经发送了很多xml,从来没有遇到过这个问题,但这可能是我的问题的一部分。

目前,我的发送信息尝试看起来像这样:

$xml_post_string = 'XML='.urlencode($xml->asXML());  
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, 'https://b2b.Freightquote.com/WebService/QuoteService.asmx');
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$response = curl_exec($ch);
curl_close($ch);

发送该XML文件需要使用PHP代码来完成,具体代码是什么样的? - Maximus2012
我编辑了它以添加它。 - ed209
好的...那么哪一部分出了问题?你收到了任何具体的错误信息吗? - Maximus2012
没有错误...只有白屏和无输出。我正在使用CodeIgniter进行操作,除非出现灾难性错误,否则至少应该能够获得HTML而没有任何输出,所以一定是发生了灾难性的错误。 - ed209
那么我理解你的意思是说我的curl命令是100%正确的? - ed209
请查看我的回答中的帖子标题。如果您不想使用这些优秀的工具,请尝试发送内容标头和SOAPAction。 - Fanda
4个回答

7
如果你需要使用SOAP服务,我强烈建议你先学习基础知识,然后再反复使用这个伟大的工具。有许多功能可以直接使用,否则你将会重新发明轮子并且难以生成xml文件、解析xml文件、处理错误等问题。使用预先准备好的工具,你的生活会更加容易,你的代码也会更好(bug更少)。
请查看http://www.php.net/manual/en/soapclient.soapcall.php#example-5266了解如何使用SOAP webservice。这并不难理解。
以下是一些代码,可以用来分析webserivce。然后将类型映射到类中,只需发送和接收php对象即可。你可以寻找一些自动生成类的工具(http://www.urdalen.no/wsdl2php/manual.php)。
<?php
try
{
    $client = new SoapClient('http://b2b.freightquote.com/WebService/QuoteService.asmx?WSDL');

    // read function list
    $funcstions = $client->__getFunctions();
    var_dump($funcstions);

    // read some request obejct
    $response = $client->__getTypes();
    var_dump($response);
}
catch (SoapFault $e)
{
    // do some service level error stuff
}
catch (Exception $e)
{
    // do some application level error stuff
}

如果您使用wsdl2php生成工具,一切都非常简单:

<?php

require_once('./QuoteService.php');

try
{
    $client = new QuoteService();

    // create request
    $tracking = new TrackingRequest();
    $tracking->BOLNumber = 67635735;

    $request = new GetTrackingInformation();
    $request->request = $tracking;

    // send request
    $response = $client->GetTrackingInformation($request);
    var_dump($response);
}
catch (SoapFault $e)
{
    // do some service level error stuff
    echo 'Soap fault ' . $e->getMessage();
}
catch (Exception $e)
{
    // do some application level error stuff
    echo 'Error ' . $e->getMessage();
}

以下是生成的QuoteService.php的PHP代码,您可以在此处查看:http://pastie.org/8165331

下面是请求的通信内容:

请求

POST /WebService/QuoteService.asmx HTTP/1.1
Host: b2b.freightquote.com
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.4.17
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/GetTrackingInformation"
Content-Length: 324

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/">
    <SOAP-ENV:Body>
        <ns1:GetTrackingInformation>
            <ns1:request>
                <ns1:BOLNumber>67635735</ns1:BOLNumber>
            </ns1:request>
        </ns1:GetTrackingInformation>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

响应

HTTP/1.1 200 OK
Date: Mon, 22 Jul 2013 21:46:06 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 660
Set-Cookie: BIGipServerb2b_freightquote_com=570501130.20480.0000; path=/

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetTrackingInformationResponse xmlns="http://tempuri.org/">
            <GetTrackingInformationResult>
                <BOLNumber>0</BOLNumber>
                <EstimatedDelivery>0001-01-01T00:00:00</EstimatedDelivery>
                <TrackingLogs />
                <ValidationErrors>
                    <B2BError>
                        <ErrorType>Validation</ErrorType>
                        <ErrorMessage>Unable to find shipment with BOL 67635735.</ErrorMessage>
                    </B2BError>
                </ValidationErrors>
            </GetTrackingInformationResult>
        </GetTrackingInformationResponse>
    </soap:Body>
</soap:Envelope>

我已经编辑了我的帖子,包含了我的实际xml....共识似乎是我的curl没问题,但我的xml有问题? - ed209
也许你有共识,但不是更好的方式。 :-) - Fanda
我希望我能够给这个答案50个投票,因为它非常棒。 - ed209

1
您可以使用stream_context_createfile_get_contents来发送XML数据并进行POST请求。
$xml = "<your_xml_string>";
$send_context = stream_context_create(array(
    'http' => array(
    'method' => 'POST',
    'header' => 'Content-Type: application/xml',
    'content' => $xml
    )
));

print file_get_contents($url, false, $send_context);

1

首先,如果你的代码是像这样编写的,我怀疑这会出现问题,因为引号的原因...你应该在xml周围使用双引号:

$my_xml = "<?xml version='1.0' standalone='yes'?>
           <user> 
               <Name>xmltest@freightquote.com</Name> 
               <Password>XML</Password> 
           </user>";

此外,您可以使用poster,这是一个Firefox插件(在Chrome上可能有相应的插件),帮助您处理请求,特别是如果您使用WebServices。这样,您就可以看到错误是服务器端还是客户端引起的。这应该有助于您进行调试。

1
我使用这个命令行脚本来测试SOAP调用:

#!/usr/bin/php
<?php
//file client-test.php
$xml_data = file_get_contents('php://stdin');

$ch = curl_init('http://example.com/server/');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('SOAPAction', 'MySoapAction'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);

print_r($output);

使用方法(在命令行中):

$ client-test.php < yourSoapEnveloppe.xml

在这个例子中,yourSoapEnveloppe.xml 文件是你的 $xml 变量的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接