什么是pom? pom作为项目对象模型。通过xml表示maven项目,使用pom.xml来实现。主要描述了项目:包括配置文件;开发者需要遵循的规则,缺陷管理系统,组织和licenses,项目的url,项目的依赖性,以及其他所有的项目相关因素。 快速察看: xml 代码 <project> <modelVersion>4.0.0</modelVersion> <groupId>...</groupId> <artifactId>...</artifactId>…
PHP: USPS API, USPS 运费计算, USPS接口, USPS Shipping Calculator
项目地址:https://github.com/scottbedard/shipping
USPS Shipping Calculator
安装 Instructions
注册web tools ID:The first step to requesting a shipping quote is injecting your USPS Web Tools ID.
use Bedard\Shipping\Usps; $shipment = new Usps('YOUR-WEB-ID');
If you would like to run the calculator on the USPS testing server, call useTestingServer()
.
$shipment->useTestingServer();
美国国内只写邮编 Once this is done, it’s time to build up the data you’ll be sending to USPS. Length, width, and height are all specified in inches. Pounds, ounces, and setValue() are all optional.
$rates = $shipment ->setOrigin('12345') ->setDestination('90210') ->setDimensions([ 'length' => 12, 'width' => 12, 'height' => 4, 'pounds' => 0, 'ounces' => 1 ]) ->setValue(49.99) ->calculate();
跨国直接写国家单词 The above is an example of a domestic shipment. To request an international rate, simply pass the destination country into setDestination()
instead of a postal code.
$shipment->setDestination('Canada');
结果如下 Once you’ve called calculate()
, shipping rates will be returned in the following format. Results will be ordered by cost in ascending order.
1 => array (size=3) 'code' => string '01' (length=2) 'name' => string 'First-Class Mail Large Envelope' (length=31) 'cost' => float 0.98 2 => array (size=3) 'code' => string '00' (length=2) 'name' => string 'First-Class Mail Parcel' (length=23) 'cost' => float 2.32 3 => array (size=3) 'code' => string '1' (length=1) 'name' => string 'Priority Mail 2-Day' (length=19) 'cost' => float 5.75
方法就是采用curl形式调用web xml,xml提交的格式如下:
us.xml
<RateV4Request USERID="xxxx"> <Revision>2</Revision> <Package ID="1ST"> <Service>FIRST CLASS</Service> <FirstClassMailType>LETTER</FirstClassMailType> <ZipOrigination>44106</ZipOrigination> <ZipDestination>20770</ZipDestination> <Pounds>0</Pounds> <Ounces>3.12345678</Ounces> <Container/> <Size>REGULAR</Size> <Machinable>true</Machinable> </Package> <Package ID="2ND"> <Service>PRIORITY</Service> <ZipOrigination>44106</ZipOrigination> <ZipDestination>20770</ZipDestination> <Pounds>1</Pounds> <Ounces>8</Ounces> <Container>NONRECTANGULAR</Container> <Size>LARGE</Size> <Width>15</Width> <Length>30</Length> <Height>15</Height> <Girth>55</Girth> <Value>1000</Value> <SpecialServices> <SpecialService>1</SpecialService> </SpecialServices> </Package> <Package ID="3RD"> <Service>ALL</Service> <ZipOrigination>90210</ZipOrigination> <ZipDestination>96698</ZipDestination> <Pounds>8</Pounds> <Ounces>32</Ounces> <Container/> <Size>REGULAR</Size> <Machinable>true</Machinable> <DropOffTime>23:59</DropOffTime> <ShipDate>2016-03-23</ShipDate> <RatePriceType></RatePriceType> <RatePaymentType></RatePaymentType> </Package> </RateV4Request>
international.xml
<IntlRateV2Request USERID="prodsolclient"> <Revision>2</Revision> <Package ID="1ST"> <Pounds>15.12345678</Pounds> <Ounces>0</Ounces> <Machinable>True</Machinable> <MailType>Package</MailType> <GXG> <POBoxFlag>Y</POBoxFlag> <GiftFlag>Y</GiftFlag> </GXG> <ValueOfContents>200</ValueOfContents> <Country>Australia</Country> <Container>RECTANGULAR</Container> <Size>LARGE</Size> <Width>10</Width> <Length>15</Length> <Height>10</Height> <Girth>0</Girth> <OriginZip>18701</OriginZip> <CommercialFlag>N</CommercialFlag> <AcceptanceDateTime>2016-03-24T13:15:00-06:00</AcceptanceDateTime> <DestinationPostalCode>2046</DestinationPostalCode> </Package> <Package ID="2ND"> <Pounds>0</Pounds> <Ounces>3.12345678</Ounces> <MailType>Envelope</MailType> <ValueOfContents>75</ValueOfContents> <Country>Algeria</Country> <Container> </Container> <Size>REGULAR</Size> <Width></Width> <Length></Length> <Height></Height> <Girth></Girth> <OriginZip/> <CommercialFlag>N</CommercialFlag> <ExtraServices> <ExtraService>6</ExtraService> </ExtraServices> </Package> </IntlRateV2Request>
更多参看:
1. Web Tools 2018 Release Notes (PDF)
3. 包裹规格
项目里面计算国际单时,会出现错误,原因时xml获取的node不对,我做了下面单修改:
调用:
<?php include_once 'usps.class.php'; $shipment = new Usps('YOUR-WEB-ID'); $rates = $shipment ->from('10001') ->to('China') ->package([ 'length' => 12, 'width' => 12, 'height' => 4, 'pounds' => 10, 'ounces' => 0 ]) // ->setValue(49.99) ->calculate(); echo '<pre>'; print_r($rates); echo '</pre>';
usps.class.php
<?php //namespace Bedard\Shipping; /* * Domestic Codes * 00 First-Class Mail Parcel * 01 First-Class Mail Large Envelope * 02 First-Class Mail Stamped Letter * 03 First-Class Mail Postcards * 1 Priority Mail * 2 Priority Mail Express Hold For Pickup * 3 Priority Mail Express * 4 Standard Post * 6 Media Mail Parcel * 7 Library Mail Parcel * 13 Priority Mail Express Flat Rate Envelope * 15 First-Class Mail Large Postcards * 16 Priority Mail Flat Rate Envelope * 17 Priority Mail Medium Flat Rate Box * 22 Priority Mail Large Flat Rate Box * 27 Priority Mail Express Flat Rate Envelope Hold For Pickup * 28 Priority Mail Small Flat Rate Box * 29 Priority Mail Padded Flat Rate Envelope * 30 Priority Mail Express Legal Flat Rate Envelope * 31 Priority Mail Express Legal Flat Rate Envelope Hold For Pickup * 33 Priority Mail Hold For Pickup * 34 Priority Mail Large Flat Rate Box Hold For Pickup * 35 Priority Mail Medium Flat Rate Box Hold For Pickup * 36 Priority Mail Small Flat Rate Box Hold For Pickup * 37 Priority Mail Flat Rate Envelope Hold For Pickup * 38 Priority Mail Gift Card Flat Rate Envelope * 39 Priority Mail Gift Card Flat Rate Envelope Hold For Pickup * 40 Priority Mail Window Flat Rate Envelope * 41 Priority Mail Window Flat Rate Envelope Hold For Pickup * 42 Priority Mail Small Flat Rate Envelope * 43 Priority Mail Small Flat Rate Envelope Hold For Pickup * 44 Priority Mail Legal Flat Rate Envelope * 45 Priority Mail Legal Flat Rate Envelope Hold For Pickup * 46 Priority Mail Padded Flat Rate Envelope Hold For Pickup * 47 Priority Mail Regional Rate Box A * 48 Priority Mail Regional Rate Box A Hold For Pickup * 49 Priority Mail Regional Rate Box B * 50 Priority Mail Regional Rate Box B Hold For Pickup * 53 First-Class Package Service Hold For Pickup * 55 Priority Mail Express Flat Rate Boxes * 56 Priority Mail Express Flat Rate Boxes Hold For Pickup * 58 Priority Mail Regional Rate Box C * 59 Priority Mail Regional Rate Box C Hold For Pickup * 61 First-Class Package Service * 62 Priority Mail Express Padded Flat Rate Envelope * 63 Priority Mail Express Padded Flat Rate Envelope Hold For Pickup * 78 First-Class Mail Metered Letter * * International Codes * 1 Priority Mail Express International * 2 Priority Mail International * 4 Global Express Guaranteed (GXG) * 8 Priority Mail International Flat Rate Envelope * 9 Priority Mail International Medium Flat Rate Box * 10 Priority Mail Express International Flat Rate Envelope * 11 Priority Mail International Large Flat Rate Box * 12 USPS GXG Envelopes * 15 First-Class Package International Service * 16 Priority Mail International Small Flat Rate Box * 17 Priority Mail Express International Legal Flat Rate Envelope * 18 Priority Mail International Gift Card Flat Rate Envelope * 19 Priority Mail International Window Flat Rate Envelope * 20 Priority Mail International Small Flat Rate Envelope * 22 Priority Mail International Legal Flat Rate Envelope * 23 Priority Mail International Padded Flat Rate Envelope * 24 Priority Mail International DVD Flat Rate priced box * 25 Priority Mail International Large Video Flat Rate priced box * 26 Priority Mail Express International Flat Rate Boxes * 27 Priority Mail Express International Padded Flat Rate Envelope */ //use DOMDocument; //use Exception; class Usps { /** * @var string USPS credentials */ protected $userId; /** * @var string USPS endpoint */ protected $endpoint = 'http://production.shippingapis.com/ShippingAPI.dll'; /** * @var string Origin postal code */ protected $originPostalCode; /** * @var string Destination postal code */ protected $destinationPostalCode; /** * @var string Destination country code */ protected $destinationCountry; /** * @var array Package dimensions [ length, width, height, ounces ] */ protected $dimensions; /** * @var string (numeric) Package value */ protected $value = 0; /** * Set up credentials and environment * @param string $userId */ public function __construct($userId) { $this->userId = $userId; } /** * Changes the USPS endpoint to the testing server */ public function useTestingServer() { $this->endpoint = 'http://testing.shippingapis.com/ShippingAPI.dll'; return $this; } /** * * Sets the origin postal code * @param $originPostalCode: integer / string * @return $this * @throws Exception */ public function from($originPostalCode) { $this->originPostalCode = $this->validatePostalCode($originPostalCode); return $this; } /** * Sets the destination postal code and country * @param $destination: integer / string * @return $this * @throws Exception */ public function to($destination) { if ($destination == 'US' || $destination == 'USA' || $destination == 'United States') { throw new Exception('The destination must be a postal code for domestic shipments.'); } // Domestic if (!preg_match('/[a-z]/i', $destination)) { $this->destinationCountry = 'US'; $this->destinationPostalCode = $this->validatePostalCode($destination); } // International else { $this->destinationCountry = $destination; $this->destinationPostalCode = FALSE; } return $this; } /** * Validates a domestic postal code * @param $postalCode: integer / string * @return string * @throws Exception */ private function validatePostalCode($postalCode) { if (!preg_match('/^\d{5}(?:[-\s]\d{4})?$/', strval($postalCode))) { throw new Exception('Invalid postal code "'.strval($postalCode).'".'); } return strval($postalCode); } /** * Validate and set the package dimensions */ public function package($dimensions) { // Set omitted weight dimensions to zero if (!isset($dimensions['pounds'])) { $dimensions['pounds'] = 0; } if (!isset($dimensions['ounces'])) { $dimensions['ounces'] = 0; } // Check for and validate required dimension keys $keys = ['length', 'width', 'height', 'pounds', 'ounces']; foreach ($keys as $key) { if (!array_key_exists($key, $dimensions)) { throw new Exception('Missing dimensions key "'.$key.'".'); } if (!is_numeric($dimensions[$key]) || $dimensions[$key] < 0) { throw new Exception('Invalid dimensions value "'.$key.'".'); } } // Convert the weight dimensions if needed $dimensions['ounces'] += $dimensions['pounds'] * 16; $dimensions['pounds'] = floor($dimensions['ounces'] / 16); $dimensions['ounces'] -= $dimensions['pounds'] * 16; $this->dimensions = $dimensions; return $this; } /** * Sets the package value */ public function setValue($value) { if (!is_numeric($value) || $value < 0) { throw new Exception('Invalid package value.'); } $this->value = number_format($value, 2); return $this; } /** * Prepares the XML to send to USPS * @return string (XML) */ private function prepareData() { // Prepare domestic data if ($this->destinationCountry == 'US') { $data = 'API=RateV4&XML=<RateV4Request USERID="'.$this->userId.'"> <Revision/> <Package ID="1"> <Service>ONLINE</Service> <ZipOrigination>'.$this->originPostalCode.'</ZipOrigination> <ZipDestination>'.$this->destinationPostalCode.'</ZipDestination> <Pounds>'.$this->dimensions['pounds'].'</Pounds> <Ounces>'.$this->dimensions['ounces'].'</Ounces> <Container>VARIABLE</Container> <Size>REGULAR</Size> <Machinable>TRUE</Machinable> </Package> </RateV4Request>'; } // Prepare international data else { $data = 'API=IntlRateV2&XML=<IntlRateV2Request USERID="'.$this->userId.'"> <Package ID="1ST"> <Pounds>'.$this->dimensions['pounds'].'</Pounds> <Ounces>'.$this->dimensions['ounces'].'</Ounces> <Machinable>True</Machinable> <MailType>All</MailType> <GXG> <POBoxFlag>N</POBoxFlag> <GiftFlag>Y</GiftFlag> </GXG> <ValueOfContents>'.$this->value.'</ValueOfContents> <Country>'.$this->destinationCountry.'</Country> <Container>RECTANGULAR</Container> <Size>REGULAR</Size> <Width>'.$this->dimensions['width'].'</Width> <Length>'.$this->dimensions['length'].'</Length> <Height>'.$this->dimensions['height'].'</Height> <Girth>0</Girth> <CommercialFlag>N</CommercialFlag> </Package> </IntlRateV2Request>'; } return $data; } /** * Processes domestic repsponses * @return array */ private function parseDomesticResponse(DOMDocument $dom) { $rates = []; $postage_list = $dom->getElementsByTagName('Postage'); foreach ($postage_list as $postage) { $code = $postage->getAttribute('CLASSID'); $cost = $postage->getElementsByTagName('Rate')->item(0)->nodeValue; if ($cost == 0) continue; $name = preg_replace('/<(.*)>/is', '', $postage->getElementsByTagName('MailService')->item(0)->nodeValue); // Fix duplicate class IDs if ($code === '0') { if ($name == 'First-Class Mail Parcel') $code = '00'; if ($name == 'First-Class Mail Large Envelope') $code = '01'; if ($name == 'First-Class Mail Stamped Letter') $code = '02'; if ($name == 'First-Class Mail Postcards') $code = '03'; } $rates[] = [ 'code' => $code, 'name' => $name, 'cost' => (float) $cost, ]; } return $rates; } /** * Processes international repsponses * @return array */ private function parseInternationalResponse(DOMDocument $dom) { $rates = []; $postage_list = $dom->getElementsByTagName('Service'); foreach ($postage_list as $postage) { $code = $postage->getAttribute('ID'); $cost = $postage->getElementsByTagName('Postage')->item(0)->nodeValue; if ($cost == 0) continue; $name = preg_replace('/<(.*)>/is', '', $postage->getElementsByTagName('SvcDescription')->item(0)->nodeValue); $rates[] = [ 'code' => $code, 'name' => $name, 'cost' => (float) $cost, ]; } return $rates; } /** * Send the rate request off to USPS and parse the response * @return array */ public function calculate() { // Ensure we have an origin, destination, dimensions if (is_null($this->originPostalCode) || is_null($this->destinationPostalCode) || is_null($this->destinationCountry || is_null($this->dimensions))) { throw new Exception('Failed to calculate rate, missing required information.'); } // Build our XML data $data = $this->prepareData(); // Send the request to USPS $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->endpoint); curl_setopt($ch, CURLOPT_HEADER, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $response = curl_exec($ch); // Load the XML from our response $dom = new DOMDocument('1.0', 'UTF-8'); $dom->loadXml($response); // Pass dom to the appropriate parser $rates = $this->destinationCountry == 'US' ? $this->parseDomesticResponse($dom) : $this->parseInternationalResponse($dom); // Sort and return the results $cost = []; foreach ($rates as $key => $row) { $cost[$key] = $row['cost']; } array_multisort($cost, SORT_ASC, $rates); return $rates; } }
本文:PHP: USPS API, USPS 运费计算, USPS接口