A modest collection of PHP libraries used at SparkFun.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
6.6 KiB

  1. <?php
  2. namespace SparkLib\UPS;
  3. use SparkLib\UPS\StreetAddressValidate\AddressKeyFormatType,
  4. SparkLib\UPS\StreetAddressValidate\RequestType,
  5. SparkLib\UPS\StreetAddressValidate\ServiceAccessToken,
  6. SparkLib\UPS\StreetAddressValidate\StreetAddressValidateException,
  7. SparkLib\UPS\StreetAddressValidate\UPSSecurity,
  8. SparkLib\UPS\StreetAddressValidate\UsernameToken,
  9. SparkLib\UPS\StreetAddressValidate\XAVRequest;
  10. use DOMDocument,
  11. SoapClient,
  12. SoapHeader,
  13. SoapFault;
  14. class StreetAddressValidate {
  15. const UNKNOWN = 0;
  16. const COMMERCIAL = 1;
  17. const RESIDENTIAL = 2;
  18. const INVALID = 0;
  19. const VALID = 1;
  20. const AMBIGUOUS = 2;
  21. const OPTION_VALIDATE = 1;
  22. const OPTION_CLASSIFY = 2;
  23. const OPTION_BOTH = 3;
  24. private $_wsdl = UPS_XAV_WSDL;
  25. private $_endpoint = UPS_XAV_SERVER;
  26. private $_schema = UPS_SCHEMA;
  27. private $_user = UPS_USERID;
  28. private $_pass = UPS_USERPASS;
  29. private $_key = UPS_APIKEY;
  30. private $_client;
  31. private $_response;
  32. private $_requestOption;
  33. private $_streetAddress;
  34. public function __construct($countryCode = 'US') {
  35. $this->initAddress();
  36. $this->setCountryCode($countryCode);
  37. }
  38. private function initAddress() {
  39. if (! isset($this->_streetAddress))
  40. $this->_streetAddress = new AddressKeyFormatType();
  41. }
  42. public function setName($name) {
  43. $name = $name;
  44. $this->_streetAddress->setConsigneeName($name);
  45. return $this;
  46. }
  47. public function setAddressLine($address) {
  48. if (! is_array($address))
  49. $address = [ $address ];
  50. $this->_streetAddress->setAddressLine($address);
  51. return $this;
  52. }
  53. public function setProvince($province) {
  54. $province = $province;
  55. $this->_streetAddress->setPoliticalDivision1($province);
  56. return $this;
  57. }
  58. public function setState($state) {
  59. $state = $state;
  60. return $this->setProvince($state);
  61. }
  62. public function setCity($city) {
  63. $city = $city;
  64. $this->_streetAddress->setPoliticalDivision2($city);
  65. return $this;
  66. }
  67. public function setZipcode($zip) {
  68. $parts = [];
  69. if (preg_match('/([a-zA-Z0-9]{5})[\-\+_\s]?(\d{4})?/', trim($zip), $parts)) {
  70. $this->setPostcode($parts[1]);
  71. if(isset($parts[2]))
  72. $this->setPlusFour($parts[2]);
  73. }
  74. return $this;
  75. }
  76. public function setPostcode($postcode) {
  77. $this->_streetAddress->setPostcodePrimaryLow($postcode);
  78. return $this;
  79. }
  80. public function setPlusFour($plusFour) {
  81. $plusFour = trim($plusFour);
  82. $code = $this->getCountryCode();
  83. if (! $code) {
  84. throw new StreetAddressValidateException('Must set country code before setting plus four zip code.');
  85. } else if ($code != 'US') {
  86. throw new StreetAddressValidateException('Plus four can only be used for U.S. addresses.');
  87. } else if (! preg_match('/\d{4}/', $plusFour)) {
  88. throw new StreetAddressValidateException('Plus four must be exactly four digits.');
  89. } else {
  90. $this->_streetAddress->setPostcodeExtendedLow($plusFour);
  91. }
  92. return $this;
  93. }
  94. private function getCountryCode() {
  95. if (isset($this->_streetAddress) && isset($this->_streetAddress->CountryCode))
  96. return $this->_streetAddress->CountryCode;
  97. }
  98. public function setCountryCode($code = 'US') {
  99. if ($code == 'US') {
  100. $this->_requestOption = self::OPTION_BOTH;
  101. } else if ($code == 'PR') {
  102. $this->_requestOption = self::OPTION_VALIDATE;
  103. } else if ($code == 'CA') {
  104. $this->_requestOption = self::OPTION_CLASSIFY;
  105. } else {
  106. throw new StreetAddressValidateException(
  107. 'Street address validation can only be performed for addresses in ' .
  108. 'the U.S., Puerto Rico, and Canada.'
  109. );
  110. }
  111. $this->_streetAddress->setCountryCode($code);
  112. return $this;
  113. }
  114. public function send() {
  115. $RequestType = new RequestType(self::OPTION_BOTH);
  116. $request = new XAVRequest($RequestType, null, null, $this->_streetAddress);
  117. $UsernameToken = new UsernameToken();
  118. $ServiceAccessToken = new ServiceAccessToken();
  119. $UPSSecurity = new UPSSecurity($UsernameToken, $ServiceAccessToken);
  120. $UsernameToken->setUsername($this->_user);
  121. $UsernameToken->setPassword($this->_pass);
  122. $ServiceAccessToken->setAccessLicenseNumber($this->_key);
  123. $header = new SoapHeader($this->_schema, 'UPSSecurity', $UPSSecurity);
  124. $options = [
  125. 'soap_version' => 'SOAP_1_1',
  126. 'exceptions' => true,
  127. 'location' => $this->_endpoint,
  128. 'trace' => true
  129. ];
  130. $wsdl = $this->_wsdl;
  131. $this->_client = new SoapClient($wsdl, $options);
  132. $this->_client->__setSoapHeaders($header);
  133. try {
  134. $this->_response = $this->_client->ProcessXAV($request, $options);
  135. } catch (SoapFault $s) {
  136. if (isset($s->detail)) {
  137. $err = $s->detail->Errors->ErrorDetail->PrimaryErrorCode->Description;
  138. throw new StreetAddressValidateException($err);
  139. }
  140. }
  141. return $this;
  142. }
  143. public function getAddressClassification() {
  144. if (! isset($this->_response))
  145. throw new StreetAddressValidateException('No server response has been set.');
  146. if ($this->getCountryCode() == 'PR')
  147. throw new StreetAddressValidateException('Cannot validate Puerto Rico addresses.');
  148. if (isset($this->_response->ValidAddressIndicator))
  149. return intval($this->_response->AddressClassification->Code);
  150. return static::UNKNOWN;
  151. }
  152. public function isResidential() {
  153. return $this->getAddressClassification() == static::RESIDENTIAL;
  154. }
  155. public function isCommercial() {
  156. return $this->getAddressClassification() == static::COMMERCIAL;
  157. }
  158. public function getAddressValidity() {
  159. if (! isset($this->_response))
  160. throw new StreetAddressValidateException('No server response has been set.');
  161. if (isset($this->_response->ValidAddressIndicator))
  162. return static::VALID;
  163. else if (isset($this->_response->NoCandidates))
  164. return static::INVALID;
  165. else if (isset($this->_response->AmbiguousAddressIndicator))
  166. return static::AMBIGUOUS;
  167. }
  168. public function valid() {
  169. return $this->getAddressValidity() == static::VALID;
  170. }
  171. public function getLastRequest() {
  172. $request = $this->_client->__getLastRequest();
  173. if ($request) {
  174. $dom = new DOMDocument;
  175. $dom->preserveWhiteSpace = FALSE;
  176. $dom->formatOutput = TRUE;
  177. $dom->loadXML($request);
  178. return $dom->saveXml();
  179. }
  180. }
  181. public function getLastResponse() {
  182. $request = $this->_client->__getLastResponse();
  183. if ($request) {
  184. $dom = new DOMDocument;
  185. $dom->preserveWhiteSpace = FALSE;
  186. $dom->formatOutput = TRUE;
  187. $dom->loadXML($request);
  188. return $dom->saveXml();
  189. }
  190. }
  191. }