我正在尝试使用 PHP 和 SoapClient 来利用 UPS Ratings Web 服务。我找到了一个名为 WSDLInterpreter 的好工具来创建用于创建服务请求的起点库,但无论我尝试什么,我都会不断收到相同的(非描述性)错误:
EXCEPTION=SoapFault::__set_state(array(
'message' => 'An exception has been raised as a result of client data.',
'string' => '',
'code' => 0,
嗯,好吧,这到底是什么意思?
与我实施的其他一些 Web 服务工具不同,UPS Soap 需要在标题中放入一个安全块。我尝试做原始关联数组数据,但如果我正确注入标题部分,我不确定 100%。使用 WSDLInterpreter,它提取了一个带有 ProcessRate 方法的 RateService 类,除了它自己的(实例)数据结构用于 RateRequest 和 UPSSecurity 部分,但以上所有内容都会产生相同的错误。
这是我正在使用的调用解释器定义的类的代码示例:
require_once "Shipping/UPS/RateService.php"; // WSDLInterpreter class library
class Query
{
// constants removed for stackoverflow that define (proprietary) security items
private $_upss;
private $_shpr;
// use Interpreter code's RateRequest class to send with ProcessRate
public function soapRateRequest(RateRequest $req, UPSSecurity $upss = null)
{
$res = false;
if (!isset($upss)) {
$upss = $this->__getUPSS();
}
echo "SECURITY:\n" . var_export($upss, 1) . "\n";
$upsrs = new RateService(self::UPS_WSDL);
try {
$res = $upsrs->ProcessRate($req, $upss);
} catch (SoapFault $exception) {
echo 'EXCEPTION=' . var_export($exception, 1) . "\n";
}
return $res;
}
// create a soap data structure to send to web service from shipment
public function getRequestSoap(Shipment $shpmnt)
{
$qs = new RateRequest();
// pickup information
$qs->PickupType->Code = '01';
$qs->Shipment->Shipper = $this->__getAcctInfo();
// Ship To address
$qs->Shipment->ShipTo->Address->AddressLine = $this->__getAddressArray($shpmnt->destAddress->address1, $shpmnt->destAddress->address2);
$qs->Shipment->ShipTo->Address->City = $shpmnt->destAddress->city;
$qs->Shipment->ShipTo->Address->StateProvinceCode = $shpmnt->destAddress->state;
$qs->Shipment->ShipTo->Address->PostalCode = $shpmnt->destAddress->zip;
$qs->Shipment->ShipTo->Address->CountryCode = $shpmnt->destAddress->country;
$qs->Shipment->ShipTo->Name = $shpmnt->destAddress->name;
// Ship From address
$qs->Shipment->ShipFrom->Address->AddressLine = $this->__getAddressArray($shpmnt->origAddress->address1, $shpmnt->origAddress->address2);
$qs->Shipment->ShipFrom->Address->City = $shpmnt->origAddress->city;
$qs->Shipment->ShipFrom->Address->StateProvinceCode = $shpmnt->origAddress->state;
$qs->Shipment->ShipFrom->Address->PostalCode = $shpmnt->origAddress->zip;
$qs->Shipment->ShipFrom->Address->CountryCode = $shpmnt->origAddress->country;
$qs->Shipment->ShipFrom->Name = $shpmnt->origAddress->name;
// Service type
// TODO cycle through available services
$qs->Shipment->Service->Code = "03";
$qs->Shipment->Service->Description = "UPS Ground";
// Package information
$pkg = new PackageType();
$pkg->PackagingType->Code = "02";
$pkg->PackagingType->Description = "Package/customer supplied";
// dimensions
$pkg->Dimensions->UnitOfMeasurement->Code = $shpmnt->dimensions->dimensionsUnit;
$pkg->Dimensions->Length = $shpmnt->dimensions->length;
$pkg->Dimensions->Width = $shpmnt->dimensions->width;
$pkg->Dimensions->Height = $shpmnt->dimensions->height;
$pkg->PackageServiceOptions->DeclaredValue->CurrencyCode = "USD";
$pkg->PackageServiceOptions->DeclaredValue->MonetaryValue = $shpmnt->dimensions->value;
$pkg->PackageServiceOptions->DeclaredValue->CurrencyCode = "USD";
$pkg->PackageWeight->UnitOfMeasurement = $this->__getWeightUnit($shpmnt->dimensions->weightUnit);
$pkg->PackageWeight->Weight = $shpmnt->dimensions->weight;
$qs->Shipment->Package = $pkg;
$qs->CustomerClassification->Code = 123456;
$qs->CustomerClassification->Description = "test_rate_request";
return $qs;
}
// fill out and return a UPSSecurity data structure
private function __getUPSS()
{
if (!isset($this->_upss)) {
$unmt = new UsernameToken();
$unmt->Username = self::UPSS_USERNAME;
$unmt->Password = self::UPSS_PASSWORD;
$sat = new ServiceAccessToken();
$sat->AccessLicenseNumber = self::UPSS_ACCESS_LICENSE_NUMBER;
$upss = new UPSSecurity();
$upss->UsernameToken = $unmt;
$upss->ServiceAccessToken = $sat;
$this->_upss = $upss;
}
return $this->_upss;
}
// get our shipper/account info (some items blanked for stackoverflow)
private function __getAcctInfo()
{
if (!isset($this->_shpr)) {
$shpr = new ShipperType();
$shpr->Address->AddressLine = array(
"CONTACT",
"STREET ADDRESS"
);
$shpr->Address->City = "CITY";
$shpr->Address->StateProvinceCode = "MI";
$shpr->Address->PostalCode = "ZIPCODE";
$shpr->Address->CountryCode = "US";
$shpr = new ShipperType();
$shpr->Name = "COMPANY NAME";
$shpr->ShipperNumber = self::UPS_ACCOUNT_NUMBER;
$shpr->Address = $addr;
$this->_shpr = $shpr;
}
return $this->_shpr;
}
private function __getAddressArray($adr1, $adr2 = null)
{
if (isset($adr2) && $adr2 !== '') {
return array($adr1, $adr2);
} else {
return array($adr1);
}
}
}
它甚至似乎还没有达到通过 Soap 发送任何东西的地步,所以我假设它由于与 WSDL 信息不匹配的东西而死亡。(请记住,我尝试使用相同的 WSDL 文件将正确播种的键/值详细信息数组发送到手动创建的 SoapClient 并产生相同的错误)如果有错误让我知道什么就好了关于“客户数据”是个问题。这个 PHP 肥皂实现并没有给我留下深刻印象!