PHP Shipping Calculator Class...my first class as it were

Posted 12 Months Ago



So I decided it was time I dive into that mysterious world of Objected Oriented Programming.  Of course, I've worked with classes and PHP 5 and all that good stuff before.  I've used many-a-class for things like Authorize.net payment processing, Facebook applications, YouTube integration, and OpenInviter.

I had not, however, written my own class from scratch... that is until this evening.

Why a Shipping Calculator?

I must admit that I have been (and still am, come to that) a little hesitant to embrace classes.  I have not been offered a good reason for their use as opposed to well written functions.  It seems to me that you're just doing more work to create and execute more restricted functions.

However, looking through my standard website framework I decided that the three seperate shipping calculator functions (UPS, USPS, and FedEx) would probably qualify as a good candidate for one unified class so I whipped up this little class in about an hour and a half (yes, I am bragging).

Here is the result..

Features

  • Calculates shipping rates for UPS, USPS, and FedEx
  • Allows you to set package size in either inches, centimeters, or feet
  • Allows you to set package weight in either pounds, ounces, grams, or kilograms
  • Automatically converts weight and sizes
  • Handles Batch or Single Rate Calculation
  • Two ways to pass configuration
  • Built in debugging
  • Small (309 lines)

You'll find the source code at the end of this article.  Before we get to that though, let's see an example or two of what this class does:

Examples


Imlementation

To see how we got these let's first take a look at an array ($services) of the various Shipping Companies and Methods which we'll use in calculating shipping rates:

Services Array

// UPS
$services['ups']['14'] = 'Next Day Air Early AM';
$services['ups']['01'] = 'Next Day Air';
$services['ups']['65'] = 'Saver';
$services['ups']['59'] = '2nd Day Air Early AM';
$services['ups']['02'] = '2nd Day Air';
$services['ups']['12'] = '3 Day Select';
$services['ups']['03'] = 'Ground';
$services['ups']['11'] = 'Standard';
$services['ups']['07'] = 'Worldwide Express';
$services['ups']['54'] = 'Worldwide Express Plus';
$services['ups']['08'] = 'Worldwide Expedited';
// USPS
$services['usps']['EXPRESS'] = 'Express';
$services['usps']['PRIORITY'] = 'Priority';
$services['usps']['PARCEL'] = 'Parcel';
$services['usps']['FIRST CLASS'] = 'First Class';
$services['usps']['EXPRESS SH'] = 'Express SH';
$services['usps']['BPM'] = 'BPM';
$services['usps']['MEDIA '] = 'Media';
$services['usps']['LIBRARY'] = 'Library';
// FedEx
$services['fedex']['PRIORITYOVERNIGHT'] = 'Priority Overnight';
$services['fedex']['STANDARDOVERNIGHT'] = 'Standard Overnight';
$services['fedex']['FIRSTOVERNIGHT'] = 'First Overnight';
$services['fedex']['FEDEX2DAY'] = '2 Day';
$services['fedex']['FEDEXEXPRESSSAVER'] = 'Express Saver';
$services['fedex']['FEDEXGROUND'] = 'Ground';
$services['fedex']['FEDEX1DAYFREIGHT'] = 'Overnight Day Freight';
$services['fedex']['FEDEX2DAYFREIGHT'] = '2 Day Freight';
$services['fedex']['FEDEX3DAYFREIGHT'] = '3 Day Freight';
$services['fedex']['GROUNDHOMEDELIVERY'] = 'Home Delivery';
$services['fedex']['INTERNATIONALECONOMY'] = 'International Economy';
$services['fedex']['INTERNATIONALFIRST'] = 'International First';
$services['fedex']['INTERNATIONALPRIORITY'] = 'International Priority';


Here's we have the basic configuration we'll send to the class.  You'll notice we use the $services array we just created to define the shipping methods we want to find the rates for:

Configuration

// Config
$config = array(
    // Services
    'services' => $services,
    // Weight
    'weight' => 2, // Default = 1
    'weight_units' => 'lb', // lb (default), oz, gram, kg
    // Size
    'size_length' => 5, // Default = 8
    'size_width' => 6, // Default = 4
    'size_height' => 3, // Default = 2
    'size_units' => 'in', // in (default), feet, cm
    // From
    'from_zip' => 97210,
    'from_state' => "OR", // Only Required for FedEx
    'from_country' => "US",
    // To
    'to_zip' => 55455,
    'to_state' => "MN", // Only Required for FedEx
    'to_country' => "US",
   
    // Service Logins
    'ups_access' => '', // UPS Access License Key
    'ups_user' => '', // UPS Username 
    'ups_pass' => '', // UPS Password 
    'ups_account' => '', // UPS Account Number
    'usps_user' => '', // USPS User Name
    'fedex_account' => '', // FedEX Account Number
    'fedex_meter' => '' // FedEx Meter Number
);

// Create Class (with config array)
$ship = new ShippingCalculator ($config);
// Get Rates
$rates = $ship->calculate();

Note: You'll have to get the various usernames, passwords, and accounts from UPS, USPS, and FedEx to run this class.  I've added several links and the exact things you need at the very end of this article.

Finally, here's how we call the class and get our rates:


Implemetation

// Create Class (with config array)
$ship = new ShippingCalculator ($config);
// Get Rates
$rates = $ship->calculate();


Results

This class spits out information via the calculate(); method.  In our example above $rates is an array of the rates we calculated.  I ran a quick example using a few shipping methods from each company (not all of them); here's what the results look like:

Rates Array

Array (
    [ups] => Array (
        [12] => 15.07
        [03] => 8.35
        [11] =>
    )
    [usps] => Array (
        [PRIORITY] => 8.10
        [PARCEL] => 7.62
        [FIRST CLASS] =>
    )
    [fedex] => Array (
        [FEDEX2DAY] => 18.55
        [FEDEXEXPRESSSAVER] => 13.53
        [FEDEXGROUND] => 6.34
    )
)

You'll notice some are empty. This means that, for one reason or another, the shipping company doesn't ship your query via that method.  Perhaps it was a worldwide shipping method and your shippment is local, etc.

One more note before I leave you.  If you wanted to match these rates with their more user friendly names (as seen in the original $services array) and wanted to simultaneously print some radio buttons where a user could select their shipping method you could do something simple like this:

Printing Radio Buttons

foreach($rates as $company => $codes) {
    foreach($codes as $code => $rate) print "
<input type='checkbox' name='shipping' value='".$rate."' /> ".$services[$company][$code]."<br />";
}

And of course, here's the source code:

Download Source Code
 

Enjoy! and let me know if you have any input, find any bugs, etc.

Update: 03-20-2010


  • Fixed the link to the source code.
  • Fixed incorrect name of constructor function
  • Added 'batch' rate lookup for USPS (the only company that lets you get rates for more than one method at a time).

And, as promised, here is some info about obtaining all the proper access keys, etc. from the different shipping companies (all are free):

UPS Online Tools Account

Link: https://www.ups.com/upsdeveloperkit?loc=en_US
What You Need:
  • Username
  • Password
  • Access License Key
  • Account Number

USPS Webtools Account
Link: https://secure.shippingapis.com/registration/
What You Need:
  • Username

FedEX Developer Account
Link: http://www.fedex.com/us/developer/
What You Need (test account versions are fine):
  • Account Number
  • Meter Number



Tags: php, class, shipping, conversion, ups, usps, fedex, rates





Comments

Name
E-mail
Website

Optional



Heinz

Posted 4 Days Ago


did you know Fedex is changing over to web services
Your class will not work  in 2012

tried to find a class that  uses the new fedex  wihout any luck

Bari Khan

Posted 3 Months Ago


Great Job......
Well Done buddy....


hoangth

Posted 3 Months Ago


thanks for share :)

Posted 4 Months Ago


@Nate
I looked into the speed thing, but didn't see much of a problem.  Here's an example of looking up one UPS rate:

http://charleskonsor.com/code/ShippingCalculator/example_single_live.php

It takes about half a second for me.  Perhaps you were looking up all UPS rates instead of just one.

Also, I tweaked the script so that rate lookups for USPS get rates for all methods in one request which makes it a lot faster (1 curl request instead of 8).  As far as I could tell, neither FedEx or UPS offer the ability to get rates for multiple shipping methods in one request.  If you or anyone else discovers differently let me know and I'll implement it.

Posted 4 Months Ago


@John, @aamir
Thanks for letting me know, I've fixed the link to the source code

@Nate
I've fixed the construction function name, thanks for pointing it out.
I'll take a look at the ups-php class you mentioned and see if i can't speed things up a bit. (I also fixed the bug that was stripping hyphens in comments, thanks for letting me know about it).

John

Posted 5 Months Ago


Source Code link isn't working. No more code?



Nate

Posted 9 Months Ago


For the record, it seems that this code is very, very slow ... looking up a UPS rate (only a UPS rate) takes an average of over 5 seconds for me with your code, whereas looking up the same rate with ups php (http://code.google.com/p/ups php/) takes an average of under half a second. Not sure what the problem is, but I'll post back here if I take the time to figure it out.

Note: for whatever reason, hyphens are stripped out of these comments. If anyone wishes to use the link above, replace the space between "ups" and "php" with a hyphen.

Nate

Posted 10 Months Ago


Yeah, that error is because he named the constructor incorrectly as "shipping_calculator" rather than "ShippingCalculator" – edit line 32 in shipping_calculator.php and that error will not occur.

Posted 11 Months Ago


The ideal object oriented structure would probably have an abstract ShippingCalculator class which declares the methods and general variables (if any), and then have concrete implementations like UPSCalculator, USPSCalculator, and FedExCalculator.

aamir

Posted 12 Months Ago


Hi,
     nice code, but when i run this i get this error
Warning: Invalid argument supplied for foreach() in C:AppServwwwshipshipping_calculator.php on line 46