2021-05-21 18:50:46 -06:00
< ? php
class Tracking_USPS {
2022-11-10 23:43:07 -07:00
/**
* Sometimes the API returns a city but no state or ZIP . This is a lookup table of city => state
* so the API can return a more complete response .
*/
2022-11-10 23:47:14 -07:00
public const STATELESS_CITIES = [
2022-11-10 23:43:07 -07:00
" LOS ANGELES " => " CA " ,
2022-11-10 23:51:39 -07:00
" SAN FRANCISCO " => " CA " ,
" NEW YORK " => " NY " ,
" CHICAGO " => " IL " ,
" MIAMI " => " FL "
2022-11-10 23:43:07 -07:00
];
2021-05-21 18:50:46 -06:00
/**
*
* @ param string $code
* @ return \TrackingInfo
* @ throws TrackingException
*/
public static function track ( string $code , string $carrier = " " ) : TrackingInfo {
$barcode = new TrackingBarcode ( $code );
try {
2025-01-31 12:45:05 -07:00
$resp = USPSAPIs :: getAPIRequest ( " tracking/v3/tracking/ $code ?expand=DETAIL " );
$resp = str_replace ( " <SUP>reg;</SUP> " , " ® " , $resp );
$resp = str_replace ( " <SUP>®</SUP> " , " ® " , $resp );
2025-01-31 13:37:09 -07:00
$resp = str_replace ( " <SUP>™</SUP> " , " ™ " , $resp );
2025-01-31 12:45:05 -07:00
$json = json_decode ( $resp , true );
if ( ! empty ( $json [ " error " ])) {
2025-02-13 23:55:15 -07:00
if ( ! empty ( $json [ " error " ][ " errors " ])) {
$msg = $json [ " error " ][ " errors " ][ 0 ][ " title " ];
$msg = preg_replace ( " / \ s?- \ s? $ / " , " " , $msg ); // Remove weird dash at end of message
switch ( $json [ " error " ][ " errors " ][ 0 ][ " code " ]) {
case " 150001 " :
// Tracking number not found
throw new TrackingException ( str_replace ( " 12: " , " " , $msg ));
case " 150002 " :
// Incorrect tracking number
throw new TrackingException ( str_replace ( " 7: " , " " , $msg ));
}
} else if ( ! empty ( $json [ " error " ][ " errors " ]) && ! empty ( $json [ " error " ][ " errors " ][ 0 ][ " code " ])) {
throw new TrackingException ( " The USPS tracking system is having problems: \" " . trim ( $json [ " error " ][ " message " ]) . " \" ( " . $json [ " error " ][ " errors " ][ 0 ][ " code " ] . " ) " );
} else if ( ! empty ( $json [ " error " ][ " message " ])) {
2025-01-31 12:45:05 -07:00
throw new TrackingException ( " The USPS tracking system is having problems: \" " . trim ( $json [ " error " ][ " message " ]) . " \" " );
2021-05-21 18:50:46 -06:00
}
throw new TrackingException ( " The USPS tracking system is having problems. Try again later. " );
}
2025-01-31 12:45:05 -07:00
$trackinfo = $json ;
2021-05-21 18:50:46 -06:00
} catch ( TrackingException $ex ) {
throw $ex ;
} catch ( Exception $ex ) {
2025-01-31 12:45:05 -07:00
throw new TrackingException ( " There was a server error. This code cannot be tracked right now. Try again later. " );
2021-05-21 18:50:46 -06:00
}
$info = new TrackingInfo ();
try {
2025-01-31 12:45:05 -07:00
$info -> setCode ( $trackinfo [ " trackingNumber " ]);
2021-05-21 18:50:46 -06:00
} catch ( Exception $ex ) {
throw new TrackingException ( " The USPS tracking system returned an invalid response. Try again later. " );
}
$info -> setCarrier ( " usps " );
2025-01-31 12:45:05 -07:00
$info -> setService ( new Service (( string ) $trackinfo [ " mailClass " ], ( string ) $trackinfo [ " mailClass " ]));
2021-10-09 18:01:48 -06:00
$info -> setCarrierAttributionText ( CarrierAssets :: getAttribution ( Carriers :: getCarrierCode ( $info -> getCarrier ())));
$info -> setCarrierLogo ( CarrierAssets :: getLogo ( Carriers :: getCarrierCode ( $info -> getCarrier ())));
2021-05-21 18:50:46 -06:00
2025-01-31 12:45:05 -07:00
// Current status
if ( count ( $trackinfo [ " trackingEvents " ]) > 0 ) {
$index = 0 ;
$evt = $trackinfo [ " trackingEvents " ][ $index ];
$current_status = new TrackingEntry (
TrackingStatus :: USPSEventCodeToStatus ( $evt [ " eventCode " ]),
( $evt [ " eventType " ] ? ? " Unknown " ) . ( TrackingStatus :: USPSEventCodeToStatus ( $evt [ " eventCode " ]) == TrackingStatus :: TRACKING_STATUS_UNKNOWN ? " " . $evt [ " eventCode " ] : " " ),
date ( " Y-m-d \T H:i:s " , strtotime ( $evt [ " eventTimestamp " ])),
null ,
TrackingStatus :: isUSPSEventCodeContainerScan ( $evt [ " eventCode " ])
);
$current_location = new Location ();
$current_location -> city = ( string ) $evt [ " eventCity " ] ? ? " " ;
$current_location -> state = ( string ) $evt [ " eventState " ] ? ? " " ;
$current_location -> zip = ( string ) $evt [ " eventZIP " ] ? ? " " ;
$current_location -> country = ( string ) $evt [ " eventCountry " ] ? ? " " ;
/*
* Fill in state from list above when it ' s missing from the API response
*/
if ( $current_location -> state == " " && $current_location -> zip == " " ) {
if ( array_key_exists ( strtoupper ( $current_location -> city ), self :: STATELESS_CITIES )) {
$current_location -> state = self :: STATELESS_CITIES [ $current_location -> city ];
}
2022-11-10 23:43:07 -07:00
}
2025-01-31 12:45:05 -07:00
} else {
$current_status = new TrackingEntry (
TrackingStatus :: TRACKING_STATUS_PRE_TRANSIT ,
( $trackinfo [ " statusSummary " ] ? ? " Unknown " ),
date ( " Y-m-d \T H:i:s " , strtotime ( " now " )),
null ,
false
);
$current_location = new Location ();
2022-11-10 23:43:07 -07:00
}
2021-05-21 18:50:46 -06:00
$current_status -> setLocation ( $current_location );
$info -> setCurrentStatus ( $current_status );
$from = new Location ();
2025-02-13 23:55:15 -07:00
$from -> city = ( string ) ( isset ( $trackinfo [ " originCity " ]) ? $trackinfo [ " originCity " ] : " " );
$from -> state = ( string ) ( isset ( $trackinfo [ " originState " ]) ? $trackinfo [ " originState " ] : " " );
$from -> zip = ( string ) ( isset ( $trackinfo [ " originZIP " ]) ? $trackinfo [ " originZIP " ] : " " );
2025-01-31 12:45:05 -07:00
$from -> country = ( string ) ( isset ( $trackinfo [ " originCountry " ]) ? $trackinfo [ " originCountry " ] : " " );
2021-05-21 18:50:46 -06:00
$info -> setFrom ( $from );
$to = new Location ();
2025-01-31 12:45:05 -07:00
$to -> city = ( string ) $trackinfo [ " destinationCity " ] ? ? " " ;
$to -> state = ( string ) $trackinfo [ " destinationState " ] ? ? " " ;
$to -> zip = ( string ) $trackinfo [ " destinationZIP " ] ? ? " " ;
$to -> country = ( string ) ( isset ( $trackinfo [ " destinationCountry " ]) ? $trackinfo [ " destinationCountry " ] : " " );
2021-05-21 18:50:46 -06:00
$info -> setTo ( $to );
2025-01-31 12:45:05 -07:00
for ( $i = 0 ; $i < count ( $trackinfo [ " trackingEvents " ]); $i ++ ) {
$history = $trackinfo [ " trackingEvents " ][ $i ];
2021-05-21 18:50:46 -06:00
$location = new Location ();
2025-01-31 12:45:05 -07:00
$location -> city = ( string ) $history [ " eventCity " ] ? ? " " ;
$location -> state = ( string ) $history [ " eventState " ] ? ? " " ;
$location -> zip = ( string ) $history [ " eventZIP " ] ? ? " " ;
$location -> country = ( string ) $history [ " eventCountry " ] ? ? " " ;
2022-11-10 23:43:07 -07:00
/*
* Fill in state from list above when it ' s missing from the API response
*/
if ( $location -> state == " " && $location -> zip == " " ) {
2022-11-10 23:47:14 -07:00
if ( array_key_exists ( strtoupper ( $location -> city ), self :: STATELESS_CITIES )) {
$location -> state = self :: STATELESS_CITIES [ $location -> city ];
2022-11-10 23:43:07 -07:00
}
}
2025-02-13 23:55:15 -07:00
$datetime = $history [ " eventTimestamp " ];
if ( empty ( $history [ " eventTimestamp " ])) {
if ( $i > 0 && ! empty ( $trackinfo [ " trackingEvents " ][ $i - 1 ][ " eventTimestamp " ])) {
$datetime = $trackinfo [ " trackingEvents " ][ $i - 1 ][ " eventTimestamp " ];
} else if ( $i < count ( $trackinfo [ " trackingEvents " ]) - 1 && ! empty ( $trackinfo [ " trackingEvents " ][ $i + 1 ][ " eventTimestamp " ])) {
$datetime = $trackinfo [ " trackingEvents " ][ $i + 1 ][ " eventTimestamp " ];
} else {
$datetime = " 1970-01-01 " ;
}
}
2021-05-21 18:50:46 -06:00
$info -> appendHistoryEntry ( new TrackingEntry (
2025-01-31 12:45:05 -07:00
TrackingStatus :: USPSEventCodeToStatus (( string ) $history [ " eventCode " ]),
$history [ " eventType " ] . ( TrackingStatus :: USPSEventCodeToStatus (( string ) $history [ " eventCode " ]) == TrackingStatus :: TRACKING_STATUS_UNKNOWN ? " " . ( string ) $history [ " eventCode " ] : " " ),
2025-02-13 23:55:15 -07:00
$datetime ,
2021-05-21 18:50:46 -06:00
$location ,
2025-01-31 12:45:05 -07:00
TrackingStatus :: isUSPSEventCodeContainerScan (( string ) $history [ " eventCode " ])));
2021-05-21 18:50:46 -06:00
}
return $info ;
}
}