UPS 运输教程 (PHP)

UPS Shipping Tutorial (PHP)

我终于设法设置了 UPS 货件 XML 请求,我想与其他苦苦挣扎的人分享。因此,根据 2017 年的最新文档,这是一个完整的 PHP 面向对象的有效 XML。

Im doing this because there are not many helpful information on the internet and I want to change that.

此代码还解决了许多常见错误,您可以在 Whosebug 上找到相关问题,但大多数都没有答案。这不是问题,是给以后做UPS Shipments的人的教程。

我已经设法用我的代码解决了这些常见的 UPS 错误:

XML 文档格式不正确 -> 这个错误有点棘手,因为我已经检查了我的 XML 结构数千次并且我有它与文档中所说的 100% 相同,但我有一份旧文档,所以几乎没有什么改变,所以当我将结构重新创建为最新的结构时,问题就解决了。

XML 文档格式正确,但文档无效 -> 我真的不知道到底是什么导致了这个错误,但改变了 "sending logic"一点点解决了(你可以看看XML结构的末尾是怎么做的)。

在我解决了这两个 "biggest" 错误后,UPS Requests 开始工作,并且出现了正确的错误消息,说明了有关问题的更多详细信息...例如 "AccessLicenseNumber invalid" 等等

So the first thing you should do is to register on UPS Website and download newest documentation from there.

注意:此代码发送名为 "ConfirmRequest" 的第一个请求将获得响应 "ConfirmResponse" 和第二个名为 "AcceptRequest" 的请求,结果如下图所示 "AcceptResponse"!

这里是完整的脚本,它将创建您的 XML 结构,将它们发送到 XML 并给您回复。

<?php
// ACCESS: You will get these after you register on UPS Website
$AccessLicenseNumber = 'xxxxxxx';
$UserID = 'xxxxxxx';
$Password = 'xxxxxxxxx';
// REQUEST *********************************
$CustomerContext = "something";
$RequestAction = "ShipConfirm";     // These values are contained in documentation 
$RequestOption = "nonvalidate";
.........
.........
......... 
And many others ...

这里是 XML 结构!!我已将整个文档涂红以写下有关每个元素的必要信息,这样当您插入例如名称超过 30 个字符

时,您可以轻松调试 XML

重要提示:您可能已经注意到我只有一个 header,尽管文档说它需要两个 HEADERS,这是真的。但是我试着只用一个发送它并且它有效所以没有必要有两个。

1. ShipmentConfirmRequest

$domtree = new DOMDocument('1.0');

// <AccessRequest>
$AccessRequest = $domtree->createElement("AccessRequest");
$AccessRequest->setAttribute("xml:lang", "en_US");
$domtree->appendChild($AccessRequest);
        // <AccessLicenseNumber>
    $AccessRequest->appendChild($domtree->createElement('AccessLicenseNumber', $AccessLicenseNumber));
        // <UserId>
    $AccessRequest->appendChild($domtree->createElement('UserId', $UserID));
        // <Password>
    $AccessRequest->appendChild($domtree->createElement('Password', $Password));
// </AccessRequest>

// <ShipmentConfirmRequest>
$ShipmentConfirmRequest = $domtree->createElement("ShipmentConfirmRequest");
$ShipmentConfirmRequest->setAttribute("xml:lang", "en_US");
$domtree->appendChild($ShipmentConfirmRequest);
        // <Request>
    $Request = $domtree->createElement("Request");
    $ShipmentConfirmRequest->appendChild($Request);
                // <TransactionReference>
        $TransactionReference = $domtree->createElement("TransactionReference");
        $Request->appendChild($TransactionReference);
                    // <CustomerContext>
                    $TransactionReference->appendChild($domtree->createElement('CustomerContext', $CustomerContext)); // Length: 1-512, Required: No
                // </TransactionReference>
                // <RequestAction>
                $Request->appendChild($domtree->createElement('RequestAction', $RequestAction)); // Length: 10, Required: Yes, Must be "ShipConfirm"
                // <RequestOption>
                $Request->appendChild($domtree->createElement('RequestOption', $RequestOption)); // Length: 1-256, Required: Yes, "validate" or "nonvalidate"
        // </Request>
        // <Shipment>
        $Shipment = $domtree->createElement("Shipment");
        $ShipmentConfirmRequest->appendChild($Shipment);
            // <Shipper>
            $Shipper = $domtree->createElement("Shipper");
            $Shipment->appendChild($Shipper);
                // <Name>
                $Shipper->appendChild($domtree->createElement('Name', $ShipperName)); // Length: 1-35, Required: Yes, Company Name
                // <AttentionName>
                $Shipper->appendChild($domtree->createElement('AttentionName', $ShipperAttentionName)); // Length: 1-35, Required: Cond, Required if destination is international
                // <PhoneNumber>
                $Shipper->appendChild($domtree->createElement('PhoneNumber', $ShipperPhoneNumber)); // Length: 1-15, Required: Cond
                // <ShipperNumber>
                $Shipper->appendChild($domtree->createElement('ShipperNumber', $ShipperNumber)); // Length: 6, Required: Yes
                // <Address>
                $Address = $domtree->createElement('Address');
                $Shipper->appendChild($Address);
                    // <AddressLine1>
                    $Address->appendChild($domtree->createElement('AddressLine1', $ShipperAddressLine)); // Length: 1-35, Required: Yes
                    // <City>
                    $Address->appendChild($domtree->createElement('City', $ShipperCity)); // Length: 1-30, Required: Yes
                    // <StateProvinceCode>
                    $Address->appendChild($domtree->createElement('StateProvinceCode', $ShipperStateProvinceCode)); // Length: 2-5, Required: Cond, Required if shipper is in the US or CA.
                    // <PostalCode>
                    $Address->appendChild($domtree->createElement('PostalCode', $ShipperPostalCode)); // Length: 1-10, Required: Cond, For all other countries, the postal code is optional
                    // <CountryCode>
                    $Address->appendChild($domtree->createElement('CountryCode', $ShipperCountryCode)); // Length: 2, Required: Yes
                // </Address>
            // </Shipper>
            // <ShipTo>
            $ShipTo = $domtree->createElement("ShipTo");
            $Shipment->appendChild($ShipTo);
                // <CompanyName>
                $ShipTo->appendChild($domtree->createElement('CompanyName', $ShipToCompanyName)); // Length: 1-35, Required: Yes
                // <AttentionName>
                $ShipTo->appendChild($domtree->createElement('AttentionName', $ShipToAttentionName)); // Length: 1-35, Required: Cond, for UPS Next Day Air Early service, and when ShipTo country is different than ShipFrom country.
                // <PhoneNumber>
                $ShipTo->appendChild($domtree->createElement('PhoneNumber', $ShipTo_phone_number)); // Length: 1-15, Required: Cond, Required for UPS Next Day Air Early service, and when Ship To country is different than the ShipFrom country.
                // <Address>
                $Address2 = $domtree->createElement('Address');
                $ShipTo->appendChild($Address2);
                    // <AddressLine1>
                    $Address2->appendChild($domtree->createElement('AddressLine1', $ShipToAddressLine)); // Length: 1-35, Required: Yes
                    // <City>
                    $Address2->appendChild($domtree->createElement('City', $ShipToCity)); // Length: 1-30, Required: Yes
                    // <StateProvinceCode>
                    $Address2->appendChild($domtree->createElement('StateProvinceCode', $ShipToStateProvinceCode)); // Length: 2-5, Required: Cond, Required if shipper is in the US or CA.
                    // <PostalCode>
                    $Address2->appendChild($domtree->createElement('PostalCode', $ShipToPostalCode)); // Length: 1-10, Required: Cond, For all other countries, the postal code is optional
                    // <CountryCode>
                    $Address2->appendChild($domtree->createElement('CountryCode', $ShipToCountryCode)); // Length: 2, Required: Yes
                // </Address>
            // </ShipTo>
            // <PaymentInformation>
            $PaymentInformation = $domtree->createElement("PaymentInformation");
            $Shipment->AppendChild($PaymentInformation);
                // <Prepaid>
                $Prepaid = $domtree->createElement("Prepaid");
                $PaymentInformation->appendChild($Prepaid);
                    // <BillShipper>
                    $BillShipper = $domtree->createElement("BillShipper");
                    $Prepaid->appendChild($BillShipper);
                        // <AccountNumber>
                        $BillShipper->appendChild($domtree->createElement('AccountNumber', $AccountNumber)); // Length: 6, Required: Cond, Based on PaymentInformation container, Must be the same UPS account number as the one provided in Shipper/ShipperNumber.
                    // </BillShipper>
                // </Prepaid>
            // </PaymentInformation>
            // <Service>
            $Service = $domtree->createElement("Service");
            $Shipment->appendChild($Service);
                // <Code>
                $Service->appendChild($domtree->createElement('Code', $ServiceCode)); // Length: 2, Required: Yes, 01 = Next Day Air 02 = 2nd Day Air ...
            // </Service>


Here is a for loop which creates as many <Package> elements as you want (You can remove this if you want to send only one PACKAGE)
            for ($i = 0; $i < sizeof($Pack_IDs); $i++) {
            // <Package>
            $Package = $domtree->createElement('Package');
            $Shipment->appendChild($Package);
                // <PackagingType>
                $PackagingType = $domtree->createElement('PackagingType');
                $Package->appendChild($PackagingType);
                    // <Code>
                    $PackagingType->appendChild($domtree->createElement('Code', $PackageTypeCode)); // Length: 2, Required: Yes, 01 = UPS Letter 02 = Customer Supplied Package ...
                // </PackagingType>
                // <Description>
                $Package->appendChild($domtree->createElement('Description', $Description)); // Length: 1-35, Required: Cond, Required for shipment with return service.
                // </Description>
                // <Dimensions>
                $Dimensions = $domtree->createElement('Dimensions'); // Required: Cond, Length + 2*(Width + Height) must be less than or equal to 130 IN or 330 CM.
                $Package->appendChild($Dimensions);
                    // <UnitOfMeasurement>
                    $UnitOfMeasurement = $domtree->createElement('UnitOfMeasurement');
                    $Dimensions->appendChild($UnitOfMeasurement);
                        // <Code>
                        $UnitOfMeasurement->appendChild($domtree->createElement('Code', $DimensionUnitOfMeasurementCode)); // Length: 2, Required: Yes*, Codes are: IN = Inches, CM = Centimeters, 00 = Metric Units Of Measurement, 01 = English Units of Measurement.
                    // </UnitOfMeasurement>
                    // <Length>
                    $Dimensions->appendChild($domtree->createElement('Length', $PackageLength)); // Length: 9, Required: Yes*, Valid values are 0 to 108 IN and 0 to 270 CM.
                    // <Width>
                    $Dimensions->appendChild($domtree->createElement('Width', $PackageWidth)); // Length: 9, Required: Yes*
                    // <Height>
                    $Dimensions->appendChild($domtree->createElement('Height', $PackageHeight)); // Length: 9, Required: Yes*
                // </Dimensions>
                // <PackageWeight>
                $PackageWeight = $domtree->createElement('PackageWeight');
                $Package->appendChild($PackageWeight);
                    // <UnitOfMeasurement>
                    $UnitOfMeasurement2 = $domtree->createElement('UnitOfMeasurement');
                    $PackageWeight->appendChild($UnitOfMeasurement2);
                        // <Code>
                        $UnitOfMeasurement2->appendChild($domtree->createElement('Code', $WeightUnitOfMeasurementCode)); // Length: 3, Required: Cond, LBS = Pounds KGS = Kilograms OZS = Ounces ...
                    // <Weight>
                    $PackageWeight->appendChild($domtree->createElement('Weight', $Pack_weights[$i])); // Length: 1-5, Required: Yes*, Weight accepted for letters/envelopes.
                    // </UnitOfMeasurement>
                // </PackageWeight>
            // </Package>
            }
        // </Shipment>
        // <LabelSpecification>
        $LabelSpecification = $domtree->createElement('LabelSpecification');
        $ShipmentConfirmRequest->appendChild($LabelSpecification);
            // <LabelPrintMethod>
            $LabelPrintMethod = $domtree->createElement('LabelPrintMethod');
            $LabelSpecification->appendChild($LabelPrintMethod);
                // <Code>
                $LabelPrintMethod->appendChild($domtree->createElement('Code', $LabelCode)); // Length: 4, Required: Yes*
            // </LabelPrintMethod>
            // <LabelImageFormat>
            $LabelImageFormat = $domtree->createElement('LabelImageFormat');
            $LabelSpecification->appendChild($LabelImageFormat);
                // <Code>
                $LabelImageFormat->appendChild($domtree->createElement('Code', $LabelImageCode)); // Length: 3, Required: Cond, Required if ShipmentConfirmRequest/LabelSpecification/LabelPrintMethod/Code = GIF. Valid values are GIF or PNG. Only GIF is supported on the remote server.
            // </LabelImageFormat>
        // </LabelSpecification>
// </ShipmentConfimRequest>

所以现在我们已经准备好并填充了 XML 结构。我建议您打印 XML 结构并仔细地将其与文档进行几次比较,以避免仅仅因为您将某些内容附加到错误的 parent 或其他内容而导致的许多错误。

这是发送 XML 和接收请求所需的代码。

2。 ShipmentConfirmResponse

$domtree->preserveWhiteSpace = true;
$domtree->formatOutput = true;
$xml_string = $domtree->saveXML();

// UPS Address
$url = 'https://wwwcie.ups.com/ups.app/xml/ShipConfirm'; // IMPORTANT: This is a testing URL address, dont be scared to send your request (Real URL is different -> documentation)
// SEND THE REQUEST
$stream_options = array(
    'http' => array(
       'method'  => 'POST',
       'header'  => 'Content-type: application/x-www-form-urlencoded',
       'content' => "$xml_string",
    ),
);
$context  = stream_context_create($stream_options);
$response = file_get_contents($url, null, $context); // Response XML structure 

现在您已将响应 XML 结构存储在 $response 变量中,因此您可以从中访问您想要的任何数据

// Response handling
$ShipmentConfirmResponse = new SimpleXMLElement($response);
if ((string)$ShipmentConfirmResponse->Response->ResponseStatusCode == 1) { // If the response is "success" then continue with second request
    // If ShipmentCofirmRequest is successful, send ShipmentAcceptRequest
    $ShipmentDigest = $ShipmentConfirmResponse->ShipmentDigest;
    AcceptRequest($AccessLicenseNumber, $UserID, $Password, $CustomerContext, $ShipmentDigest, $ShipmentID, $connect); // After first successful request call a function which will send AcceptRequest

} else {
    echo $ShipmentConfirmResponse->Response->Error->ErrorDescription;
}

所以这是发送第二个请求的函数"AcceptRequest" 它的代码相同,但具有不同的 XML 结构。

3。 ShipmentAcceptRequest

function AcceptRequest ($AccessLicenseNumber, $UserID, $Password, $CustomerContext, $ShipmentDigest) {
    $RequestAction = "ShipAccept";

    $domtree = new DOMDocument('1.0');

    // <AccessRequest>
    $AccessRequest = $domtree->createElement("AccessRequest");
    $domtree->appendChild($AccessRequest);
            // <AccessLicenseNumber>
        $AccessRequest->appendChild($domtree->createElement('AccessLicenseNumber', $AccessLicenseNumber));
            // <UserId>
        $AccessRequest->appendChild($domtree->createElement('UserId', $UserID));
            // <Password>
        $AccessRequest->appendChild($domtree->createElement('Password', $Password));
    // </AccessRequest>
    // <ShipmentAcceptRequest>
    $ShipmentAcceptRequest = $domtree->createElement("ShipmentAcceptRequest");
    $domtree->appendChild($ShipmentAcceptRequest);
            // <Request>
        $Request = $domtree->createElement("Request");
        $ShipmentAcceptRequest->appendChild($Request);
                    // <TransactionReference>
            $TransactionReference = $domtree->createElement("TransactionReference");
            $Request->appendChild($TransactionReference);
                        // <CustomerContext>
                        $TransactionReference->appendChild($domtree->createElement('CustomerContext', $CustomerContext));
                    // </TransactionReference>
                    // <RequestAction>
                    $Request->appendChild($domtree->createElement('RequestAction', $RequestAction));
            // </Request>
            // <ShipmentDigest>
            $ShipmentAcceptRequest->appendChild($domtree->createElement('ShipmentDigest', $ShipmentDigest));
    // </ShipmentAcceptRequest>

您再次使用此代码发送它。然后您需要查看 $response 变量内部是否成功,您可以存储跟踪 ID 和运费并使用它做任何您想做的事情。

重要提示:您还将获得 Base64 编码的标签图像

4. ShipmentAcceptResponse

    $domtree->preserveWhiteSpace = true;
    $domtree->formatOutput = true;
    $xml_string = $domtree->saveXML();
    $url = 'https://wwwcie.ups.com/ups.app/xml/ShipAccept'; // Again testing URL

    $stream_options = array(
        'http' => array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => "$xml_string",
    ),
);
    $context  = stream_context_create($stream_options);
    $response = file_get_contents($url, null, $context);

    $ShipmentAcceptResponse = new SimpleXMLElement($response);

    if ((string)$ShipmentAcceptResponse->Response->ResponseStatusCode == 1) {

        $Tracking_ID = $ShipmentAcceptResponse->ShipmentResults->PackageResults->TrackingNumber;
        $Price = $ShipmentAcceptResponse->ShipmentResults->ShipmentCharges->TransportationCharges->MonetaryValue;
        $ImageBase64 = $ShipmentAcceptResponse->ShipmentResults->PackageResults->LabelImage->GraphicImage;

    } else {
        echo $ShipmentAcceptResponse->Response->Error->ErrorDescription;
    }
}