Simple Shipment Tracking CGI Script 1

Posted by JD 01/13/2011 at 10:00

Over the years, I’ve used a few different techniques to track UPS, USPS, and FedEx shipments. I’ve tried direct links to the shipper’s website, email status updates with cron, and just using the store’s shipment tracking. The email tracking interfaces have changed to be less-than-useful to me. Logging into the shipper’s website just to track a shipment became a hassle. No thanks.

None of these made me happy, so this morning I created a trivial CGI script + data file to track shipments. It isn’t anything too fancy and you need to edit the data file manually, but it feels better than the other alternatives.

What You Need

  1. Perl
  2. Web Server – or you can run this from a command or shell prompt to create an output HTML file
  3. Script File below (copy/paste)
  4. Edited Data File below (copy/paste)

Git ’er done.

The Perl Script

Place this in /cgi-bin/delivery-track.cgi and change the permissions so execute is allowed. Your web server should already know to allow CGI scripts and like the .cgi extension.

#!/usr/bin/perl
# #####################################################
# Display links to direct UPS, USPS package tracking links
# #####################################################
use strict;
use Getopt::Long;
my $tracking_data_file="delivery-track.dat"; # Data file
# ####################################################
sub tracker();

# #####################################################
my $fedex_base="http://fedex.com/Tracking?action=track&cntry_code=us&tracknumber_list=";
my $usps_base="http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?origTrackNum=";
my $ups_base=" http://wwwapps.ups.com/WebTracking/track?HTMLVersion=5.0&loc=en_US&Requester=UPSHome&WBPM_lid=&&track.x=Track&trackNums=";

# #####################################################
my $doHelp = 0;
my $ret=GetOptions ("help|?" => \$doHelp);

my $html_header = "Content-type: text/html\n\n<html> <header>
<META HTTP-EQUIV=\"refresh\" CONTENT=\"3600\">
<title>Delivery Tracker</title> </header> <body> ";
my $html_footer = "</body></html>";

# ########################################################
sub Usage()
{
   print "\nUsage: 
       $0 \n
       You need to edit $tracking_data_file to contain items to be tracked.\n\n";
       
  exit 1;
}

# ####################################################
sub StripLeadingAndTrailingWhitespace($){
   my $line = $_[0];
   return "" if ( ! length($line) );
   $line =~ s|^[\t\n\r ]*||og;
   return "" if ( ! length($line) );
   $line =~ s|[\t\n\r ]*$||og;
   return $line;
}


# #####################################################
#   main()
#  The output is a filtered html file to stdout
#
# Grab the new page
Usage() if ( $doHelp );

print "$html_header\n";
print "<h2>List of Tracking links</h2>
<ol>";
my $ret=tracker();
print "</ol>$ret\n";
print "\n$html_footer\n\n";

# #####################################################
sub tracker()
{
  my $ret="\n\n";
  open (TRACK, "<$tracking_data_file") || die "ERROR: $!";
     while (<TRACK>){
     # If there's a '#' character at the beginning, dump the line
     # 3 fields in the file, separated by a space
     # {shipper} {track_num} {Description}
     # UPS 1ZW045844444430778 Ethernet Switch
     chomp;
     my $line=$_;
     $line=StripLeadingAndTrailingWhitespace($line);
     $_ = $line;
     next if (m/^#/);  # look for comment lines
     my @entry = split(/ /, $line, 3);  # parse into 3 entries
     my $shipper=$entry[0];
     my $track_num=$entry[1];
     my $desc=$entry[2];
     # print "\n\n$shipper\t$track_num\t$desc\n\n";
     next if ( !length( $shipper ) || !length( $track_num ) );
     if ( "ups" eq lc($shipper) ){
          $ret .= "<li>UPS <a href=$ups_base$track_num>$track_num</a> $desc</li>\n";
     } elsif ( "usps" eq lc($shipper) ){
          $ret .= "<li>USPS <a href=$usps_base$track_num>$track_num</a> $desc</li>\n";
     } elsif ( "fedex" eq lc($shipper) ){
      $ret .= "<li>FedEx <a href=$fedex_base$track_num>$track_num</a> $desc </li>\n";
     } else {
       $ret .= "<li>Unknown Entry: $shipper\t$track_num\t$desc </li>\n";
     }
     }
 return $ret;
}

The Data File

Here’s the data file. Name it delivery-track.dat and place it in the same directory as the PERL script (or use a full path in the script to the file). You can change the name, just update the filename in the script to match. Be certain your web server userid has read permissions on the data file. Nobody else needs permissions.

Sorry for the formating below due to this blog software. All lines with numbers below at the beginning should have ‘#’ characters in the real file.

# a perl data file

  1. There are 3 fields in this file (space separated)
    1. a) shipper – valid entries are UPS, USPS, FEDEX (case-insensitive)
    2. b) Tracking Number
    3. c) Description to the end of line – good for order dates too
  2. Any lines that begin with ‘#’ are comments
  3. here’s an example entry
    USPS 9102927444463009888500 Ethernet Switch, ordered 1/1/2009

You can run this script manually, but it shines if you have a web server with a cgi-bin directory. Be certain to set the permissions correctly.

Eventually, the shippers will change the interface pages and you should be able to quickly update the links in the script above when that happens. Nothing on the web lasts forever.

Good enough? Sure there are lots of other ways to accomplish the same goals, even more efficiently. Still, for 30 minutes of effort, it is good enough and removes the need to use someone elses’ services or servers except each shipping company – they already know about the shipment after all.

Trackbacks

Use the following link to trackback from your own site:
https://blog.jdpfu.com/trackbacks?article_id=937

  1. JD 01/14/2011 at 04:15

    I’ve been tracking UPS, USPS, and FedEx packages with this script this week. It is amazing what lots of snow and ice will make a person have time to complete. It is working nicely.

    The script really is overkill, since having the direct link is really all you want – then you can bookmark it or use Read-It-Later in Firefox to monitor the deliveries directly at each shipper’s website (without logging in).