Calculating UPS Shipping Rate with PHP

It’s actually very easy to calculate shipping from UPS with PHP once you know how. But at first glance it seems like an impossible task to do.

Update: Although this code still works great, I have started an open source project at http://code.google.com/p/ups-php/. For easier to use code, improved documentation and a more complete feature set. The project also covers the other UPS API services.

Update 2: For a no fuss, 100% complete UPS Online Tools script with label printing support, integration support and automatic certification generation (required by UPS), I have created, RocketShipIt.

Comments have also been disabled, if you are having problems with the script please start an issue ticket at: http://code.google.com/p/ups-php

The UPS manual for XML shipping calculation is hundreds of pages long and unfortunately provides no examples written in PHP. Only ASP… Damn them! After hours of reading the UPS manual and lots of Google searching I figured out how to make my own and I thought I would share my method. So in today’s post we will look at an example ups rate calculation using PHP.

If you are looking for the United States Postal Service (USPS) function see, Calculating USPS Shipping Rates with PHP.

You can also integrate UPS Tracking features on your site once you get a handle on this.

Things you will need

  • UPS Online Tool Account – free but requires registration
  • UPS Access Key – Comes with the online tool account
  • cURL – Most LAMP (Linux, Apache, Mysql, PHP) web hosts have this installed by default.
  • PHP – You must know a little bit about using php. After all you are about to create a custom UPS shipping calculator.
  • XML – If you know what PHP is you should know what this is. If not read about it here.
  • SSH access – Many web hosts offer this. You don’t HAVE to have it but it makes troubleshooting easier.

Basically you start off by getting setup with UPS and grabbing a copy of their XML manual. Now you need to construct an XML file that will be later sent off to UPS’s server. UPS will then send a response back to you in XML format. We then use PHP to turn the XML into variables that we can use and manipulate. Even add the shipping cost into the subtotal or final checkout cost. After all, whats the use of calculating UPS shipping if you are not going to charge the user for it.

Copy the UPS PHP Function I have created into a new .txt file and name it ups.php.

Go through this function and find the parts in the XML file that are in CAPS, You will need to add your UPS shipper number, access key, username, password, departure zip, etc…

Then create another .php file and make sure to include ups.php.

It might look something like this:

require_once("ups.php")

Now all you have to do to get an accurate UPS rate for a package is call the ups function.

The basic syntax for the function is:

ups($dest_zip,$service,$weight,$length,$width,$height)

So, for example if you wanted to send a five pound package to Beverly Hills CA using UPS ground you would do this:

ups(90210,03,5,5,5,5)

Here is an already written php test file that uses the ups function.

By now you may be wondering how I know that 03 is the code for UPS ground and you also may be wondering what the code is for 2nd Day Air.

You can find all this information in the huge manual with the name dtk_RateXML_V1.zip. You can find this manual on the UPS website after you login under UPS Rates and Services Selection but to save you the time I have listed them below.

UPS Service Selection Codes

  • 01 – UPS Next Day Air
  • 02 – UPS Second Day Air
  • 03 – UPS Ground
  • 07 – UPS Worldwide Express
  • 08 – UPS Worldwide Expedited
  • 11 – UPS Standard
  • 12 – UPS Three-Day Select
  • 13 Next Day Air Saver
  • 14 – UPS Next Day Air Early AM
  • 54 – UPS Worldwide Express Plus
  • 59 – UPS Second Day Air AM
  • 65 – UPS Saver

Feel free to edit the function. The XML part of the code should be altered to fit your needs. This function only has the basic elements needed to calculate a rate. There are other attributes you can specify in the XML part of the document, such as pickup type, packaging type, etc…

Unlike some UPS Rate calculators you do not need to update the fuel surcharges or anything else. These rates come straight from UPS and are as accurate as your XML file has specified.

Troubleshooting

 
If it’s not working and you think you may have messed up the PHP code you can test to see if it is working by sending your XML file with curl.

Log into your host via SSH, make an xml file named RequestXML.txt. Then run this command.

curl -d @RequestXML.txt https://www.ups.com/ups.app/xml/Rate

If you want to use UPS’s testing server you can use this URL:

https://wwwcie.ups.com/ups.app/xml/Rate

Special Instructions for Godaddy

 
Godaddy requires a minor change in the ups function. After reading this article:

You need to have a proxy to use cURL on Godaddy.

So under this line:
“curl_setopt($ch,CURLOPT_TIMEOUT, 60);”

add this:
“curl_setopt($ch,CURLOPT_PROXY,’http://proxy.shr.secureserver.net:3128′);”

Help Program

 
I have started a UPS API open source project at, http://code.google.com/p/ups-php. If you would like to contribute and add to my code or help create more modules for the different UPS tools come on over.

Information for Dreamhost Users

 
If you are using Dreamhost as your webhost, there is currently something wrong with the way they handle cURL. It takes almost 60 seconds to receive a response. This is not the script or UPS’s fault. As of 01-24-2008 I have a support ticket out to fix the problem. I am getting emails from them and I will update this post as soon as I get a fix or information from them.

Here are the emails I have received from Dreamhost regarding the issue:

On Thu, 24 Jan 2008, you wrote:

So I am using cURL to send a receive XML requests for the purposes of shipping products via UPS.

A year ago cURL responses were almost immediate. Today (and the last few months) they seem to take almost 60 seconds to send and receive the same XML file. Out of laziness on my part I have not complained about the issue until now. But I need to know what I can do to speed this up a bit.

Attached will be an example of the code I use.

Thanks in advance

Mark

We don’t really troubleshoot code but I would think the most likely
explanation (since cURL in itself should be very fast) is that something
changed with UPS’s site where it slowed down or the process keeps pending
for some reason until it times out. You could try setting the timeout to
a lower amount (15-20 seconds) and see if it still gets the data or not.
Another thing to test the theory if its on USP’s site would be to make a
regular static page which sends the same POST data to UPS’s site see how
long it takes to fetch the results. Please let me know if you have any
additional questions.

I guess I should have included this in my original email. I have tried this exact code on other hosting servers and it works almost instantly. I have indeed sshed and ran cURL by itself and it is extremely slow. This is definitely not a code issue or UPS slow server issue. I can send the same request via curl on my home computer and it is faster than dreamhost.

Please advise

Mark

Although normally we do not assist customers with third party software,
I’ve dealt with similar issues in the past with UPS. Could you please
send me the complete path of the PHP that’s running slowly? I can run
some debugging software on it for you to see if there is anything hanging
things up and anything I can do to fix it.

Thankyou for attempting to solve my issue. I still must insist that it is not a third party software issue. I believe this has nothing to do with UPS. As stated in my earlier email the PHP is not to blame here either. The problem lies within the response time of cURL.

To seperate php from the equation I went ahead and created an xml text file on my root directory on dreamhost. I then ran the following command:

curl -d @xml.txt https://www.ups.com/ups.app/xml/Rate

It took 56.853 seconds to receive a response from Dreamhost.
I copied the same xml.txt file to my personal home computer and ran the same command and received a response in 1.2 seconds.

I will attach a log of the commands I ran.

As you can see it takes Dreamhost way longer to send/receive responses via curl. If you want to test it yourself you can run the same command I did from my home directory. The xml file is in there.

Thanks for your help in this matter. If you have any questions about my analysis please email.

Mark

Alright, I’ve run some tests and asked some admins their opinions and
here are the results.

It appears that the slowness is because cURL is trying to reverse lookup
the IP address for www.ups.com which is timing out. This is the culprit,
but, unfortunately there is no easy fix for it if you must use cURL.

Here is the strace results:

connect(3, {sa_family=AF_INET, sin_port=htons(53),
sin_addr=inet_addr(“66.33.216.208″)}, 28) = 0
send(3, “\230\313\1\102500322801203153\7″…, 43,
0) = 43
gettimeofday({1201218751, 713629}, NULL) = 0
poll(

This is what it’s lagging on (as the DNS lookup takes 3-5 seconds to time
out)

One quick option may be to instead use fopen for the URL — of course to
do this you’ll need to install a custom PHP.ini file and customize it to
allow_url_fopen ( http://wiki.dreamhost.com/PHP.ini )

Sorry about the semi-bad news. Of course if you have any other questions

Why would a reverse look up to a well known domain such as www.ups.com fail? Why can other webhosts receive cURL responses with out a hangup?

When you say that a reverse lookup is causing a 3-5 second timeout why is curl taking over 60 seconds to receive a response? I would be more than happy to have a 3-5 second response time.

Why did curl respond much faster on Dreamhost prior to 10/09/2007? (I looked back in my emails and found the date I started having slow response times)

Mark

Sorry for the delay in getting back to you…our support system has been
pretty backlogged lately. The only explanation I can come up with is a
quirky routing issue or something…I’ve seen it before, specifically
with UPS, and the only solution was to use the IPs rather than the
hostnames. I am sorry we don’t have a better solution for you. If it is
possibly something on our end, we have no idea what it is, I’m afraid. I
apologize for the hassle.

If this article helped you in any way please consider digging this article by clicking the “digg it” link below. This will help others find the article. :)


Was this information useful?


185 Responses to "Calculating UPS Shipping Rate with PHP"
  1. Jason on November 30th, 2007

    You are my hero!

  2. Mark Sanborn on November 30th, 2007

    Thanks,

    I assume the code worked good for ya :)

  3. CJJUNE on December 1st, 2007

    I obtain an error saying Fatal error: Cannot use string offset as an array in upsxml.php

    linewith error in the code is this:
    $eta_array = explode(“-”, $this->servicesTimeintransit[$type]["date"]);

    Please help. Thanks

  4. CJJUNE on December 1st, 2007

    I obtained the code from here http://www.brandnamebatteries.com/contributions/index.htm

    Please help.

  5. CJJUNE on December 1st, 2007

    Where should I place the “RequestXML.txt” file? In the root folder?

  6. Mark Sanborn on December 1st, 2007

    I didn’t make the zen-cart UPS code so I cannot help you with that. If you want to get UPS rates you can use the code that I have listed above.

    The RequestXML.txt is just for troubleshooting if the code is not working you can send the xml file directly to UPS without PHP using CURL. It doesn’t matter where you put the RequestXML.txt. Just login via SSH and change to the directory where you saved it and execute this command, “curl -d @RequestXML.txt https://www.ups.com/ups.app/xml/Rate“.

    Remember that you have to change some of the lines in the code to include your own UPS Access key, username, password, and originating zipcode.

  7. Leon Roose on December 3rd, 2007

    I tried to copy your UPS PHP Function. I got this:

    The XML page cannot be displayed
    Cannot view XML input using XSL style sheet. Please correct the error and then click the Refresh button, or try again later.

    ——————————————————————————–

    A string literal was expected, but no opening quote character was found. Error processing resource ‘http://www.marksanborn….

    —————————–^

    Something wrong on my end?
    LR

  8. Mark Sanborn on December 3rd, 2007

    Hi Leon,

    I have some questions about your question :P

    What do you mean you try and copy the PHP function? are you clicking the link and copy and pasting the text?

    Are you having trouble opening the link to the function?

    Or is this a PHP error after you have pasted the function on your server in a .php file?

  9. Leon on December 3rd, 2007

    I clicked on the UPS PHP Function link in order to do a copy (as I think you instructed) and then to do a paste.

    My browser displayed the message given above. What should I be doing?

  10. Mark Sanborn on December 3rd, 2007

    Ok In my current browser, (firefox) I can either click on the link and text will show up that I can copy and paste elsewhere. Or, I can right click on the link and do a save link as. This will save the ups.txt file.

    I’m assuming your browser thinks that the link is an actual XML link. It is only a txt file with PHP in it, so your browser should just display text instead of parsing XML.

    What browser are you using?

  11. Christopher Malone on December 5th, 2007

    Hi Mark -

    Thanks so much for posting this code. I have been losing my mind trying to integrate the UPS Rate code into a shopping cart I’m building with PHP/MySql.

    In testing your code I have run into a problem. I wanted to test just to see what UPS would send back. I did everything necessary in the ups.php file. Then, I created a file upstest.php that has the simple code:

    When I run that, I receive the following errors on the page:

    Warning: main(upsphp): failed to open stream: No such file or directory in /home/content/o/v/e/html/upstest.php on line 3

    Fatal error: main(): Failed opening required ‘upsphp’ (include_path=’.:/usr/local/lib/php’) in /home/content/o/v/e/html/upstest.php on line 3

    Any advice on this?

    Thank you!

  12. Mark Sanborn on December 5th, 2007

    Ok make a .php file with the ups function in it. Make sure you modify the php function to include your shipper ID and password.

    Then make another .php file, include or require the ups function via the php include/require command. Then do something like this in the php, without quotes.

    “ups(90210,03,5,5,5,5)”

    The error you are recieving is saying that it cannot find the ups function that you are “requiring”. the difference between the require command and include is that the include will include it if it is there. The require says that if it isn’t there spit out a fatal error. (the one you are seeing above.

    If this isn’t clear I will write another comment later today explaining it better.

    Thanks for reading my blog :)

  13. Christopher Malone on December 5th, 2007

    You’re very welcome. I think I’m getting somewhere… almost. Ok… so I have one .php file which is the ups.php one from here. I customized it with my UPS info. I created another file that has only two lines of php code. The first is the require_once command which I have also tried as an include and the second line is the one you have in quotes above. Saved as upstest.php. Now, instead of the errors, the page waits for a while then displays nothing.

  14. Mark Sanborn on December 5th, 2007

    Try changing this line:

    “curl_setopt($ch,CURLOPT_TIMEOUT, 60);”

    to,

    “curl_setopt($ch,CURLOPT_TIMEOUT, 90);”

    What webhost do you use by chance? I use Dreamhost any recently it has been taking longer to get a cURL request back and I had to change my timeout to 60 (used to be 30).

    Let me know what you find.

  15. Christopher Malone on December 5th, 2007

    I made the changes, but it is still taking a long and not passing any information back. This site is hosted on GoDaddy, so I’m thinking that it might have to do with their curl settings, perhaps? I can tell that the code is working, but there just seems to be something that is causing this error, most likely something to do with the settings?

  16. Mark Sanborn on December 6th, 2007

    Christopher,

    I think I have a solution for you. Godaddy requires special instructions. After reading this article:
    http://help.godaddy.com/article.php?article_id=289&topic_id=435

    You need to have a proxy to use cURL on Godaddy.

    So under this line:
    “curl_setopt($ch,CURLOPT_TIMEOUT, 60);”

    add this:
    “curl_setopt($ch,CURLOPT_PROXY,’http://proxy.shr.secureserver.net:3128′);”

  17. Christopher Malone on December 6th, 2007

    Hi Mark -

    Thanks so much again for your help! I believe those fixes have worked and should be useful for anyone using GoDaddy. The only issue now is that it is giving the error “XML document must have a top level element. Error processing resource…”.

  18. Mark Sanborn on December 10th, 2007

    Hmm, Is anyone else getting this error? Try making an XML txt file and send it with curl via the command line in SSH (See the troubleshooting section of this post). See if that helps, if not I will check into it.

  19. Chris on December 13th, 2007

    Hello Mark -
    Thanks for posting this code. Once I get it working, it should work well for me! I am trying to get it into the cart application I’m building.

    As a test, I have ups_test.php calling the ups function, then calling an instance of the ups function:

    Running this returns a blank page, but when I look at the source code, there’s a bunch of XML code there.

    Among the XML code, I see:

    FailureHard10001The XML document is not well formed

    What would be causing this?

    In the meantime, I need to figure out how to get my php pages to parse the XML!

  20. Chris on December 13th, 2007

    I also wanted to mention that I have my username, password, access key and zipcodes entered in the proper places.

    Any ideas?

    Thanks again!

  21. Mark Sanborn on December 13th, 2007

    Chris,

    First off I want to thank you for checking out my site and using my blog.

    It is really easy to forget to change the XML to meet your needs since there are many things you need to change. I have now changed the UPS function in this post so you can now see everything that needs to be personalized in one central location.

    I also forgot to mention that this function will print out the XML that it receives from UPS in “html comments”. This is why you can view the source of the page and see the error. This is incredibly useful for finding out what went wrong.

    In your case it seems like the function is contacting UPS successfully and UPS is telling you that your XML portion of the function is not correct.

    Go back and copy the new UPS function, edit the area near the top and save it in a text file named ‘ups.php’. Then copy the PHP test file that I just created and linked to this post to a new file called ‘upstest.php’. Upload those to files to your host.

    It should return a monetary value of the shipping cost from your area to Beverly Hills California.

    If it doesn’t, view the source code and tell me what the error says.

    I just went through the code and tried it on my host and the code still works. So don’t give up. You are almost there. :)

  22. Chris on December 14th, 2007

    Mark –

    I tried it again using your updated code and suggestions – and it works!

    My only other question is if it is possible to use the function without passing any of the dimensions? Would it work if I pass only the destination zip and weight?

    Thanks again for your help!

  23. Mark Sanborn on December 14th, 2007

    Well, I found that UPS doesn’t really change the rate based on the dimensions so in my shopping carts I usually make the dimension always 5×5x5. I am not sure on this but when I created that function I believe that UPS required the dimension to process the rate quote.

    Is keeping the dimension always 5×5x5 an option for you? Or would you like me to look into it further?

  24. Chris on December 14th, 2007

    Not necessary. I had not anticipated needing to separate out the dimensions for the product entries in my database. I’m still early enough in the process that I am able to add it in.

    I have the dimensions being dynamically supplied to the function call now and its working. Now the trick is to keep a running tally for the dimensions of all the items in my cart…

    It would still be handy to know if the dimensions are really required, or if the weight is enough. But if you don’t have time, please don’t worry on my account.

    Thanks again for publishing this code – it REALLY saved me alot of time!

  25. Chris on December 14th, 2007

    I just tested it by removing my dynamic code and putting in 5s for those 3 values – and it still returned the same value for shipping.

    Weight and zipcode appear to be the determining factors. So I think the problem is solved!

  26. Mark Sanborn on December 14th, 2007

    Cool, now as a tip maybe in my next post I will describe how I managed to come up with exact rates for bundles of stuff in the shopping cart. Meaning it will calculate how much stuff can go in one box before having to start calculating the shipping for another package.

    This is especially useful if you have a customer buying 12 small items. You don’t want to calculate 12 separate boxes at one pound. I would be a $100 shipping charge.

    On the flip side you don’t want to calculate shipping for 10 large items as one package.

    Would that be something that would be interesting?

  27. Chris on December 14th, 2007

    Definately. In fact, thats exactly what I’m working on now.

    The cart I’m building is for a lumber company. They want to sell stuff online – from a small decorative piece for a doorway all the way up to big lumber packages.

    So that would definately be helpful.

    One other question I thought of after the fact. Is the weight we pass in ounces or pounds?

  28. Mark Sanborn on December 14th, 2007

    Pounds be default. As far as I know UPS doesn’t measure anything in unites less than 1 pound and always rounds up.

  29. Dave Alvarado on December 17th, 2007

    Hi,

    Just downloaded the code. Seems to work but I’m getting warnings. Specifically they are:

    Notice: Undefined index: value in /usr/local/apache2/htdocs/dhlovelife/v2/ups_shipping_fns2.php(118) : eval()’d code on line 1

    Notice: Undefined index: value in /usr/local/apache2/htdocs/dhlovelife/v2/ups_shipping_fns2.php(118) : eval()’d code on line 1

    They are complaining about this line:

    eval($php_stmt);

    The XML doc returned appears to be valid and I’m getting a value. But I’m a stickler for warnings so wondering if there is something I can do to make them go away. Let me know what additional info I should provide. Thanks, – Dave

  30. Mark Sanborn on December 17th, 2007

    Are these showing up on the html page or are these in a PHP error log?

    What version of PHP are you using?

  31. Dave Alvarado on December 17th, 2007

    I’m using PHP 4.4.4 on Fedora Core 6 Linux. These are showing up on the HTML page itself. I’m testing this on a development machine with the PHP error reporting set to E_ALL.

    Thanks for any info, – Dave

  32. David on December 20th, 2007

    Thanks for the coding. Works Great for US but how do I get it to do International. I tested using UPS country codes but keeps throwing The requested service is unavailable between the selected locations. Maybe wrong shipping type?

  33. David on December 20th, 2007

    Yuppers thats what it was. Works awesomely well now :)

  34. Mark Sanborn on December 20th, 2007

    David, glad you got it working. Some international areas (anything overseas) requires a different type of shipping. Its called UPS Worldwide and UPS World wide Express, etc…

    To my knowledge you can ship standard UPS ground to Mexico and Canada.

    Dave Alvarado, I am not sure why it is giving you errors were you ever able to figure it out?

  35. Klynt Maston on January 16th, 2008

    Mark,

    I’m getting this error:

    Notice: Undefined index: RATINGSERVICESELECTIONRESPONSE

    Would you know how to fix this? I kept your code mainly the same. I just added one line – curl_setopt($ch,CURLOPT_PROXY,’http://proxy.shr.secureserver.net:3128′);

    Thanks a lot!

  36. cheeby on January 17th, 2008

    Really nice.

    I was in the same boat as you until I found your post. Thanks Mark.

    Here’s what my ship_test.php looks like:

    “;

    $dest_zip = “53703″;
    $service = “03″;
    $weight = “73″;
    $length = “60″;
    $height = “14″;
    $width = “12″;

    $result = ups($dest_zip,$service,$weight,$length,$width,$height);

    // can now use $result for whatever purpose
    // for now, just echo out the cost

    echo “shipping cost is $result”;
    ?>

  37. gknight on January 19th, 2008

    Mark,
    I keep trying EVERYTHING that I can to get this thing to work. I have changed all of the information that I have needed to change and added the GoDaddy Proxy server line for cURL. No matter what I do, I keep getting the Hard Error 250000. Basically telling me that there is no XML in the request. I have copied everything from their examples to replace what you had in the file originally, but it still won’t work. Some help would REALLY be nice right now……;)

    Thanks in advance,
    GKnight

  38. gknight on January 19th, 2008

    Ummmmm, ok, uuummmmm, nevermind. It just magically started working. Don’t know what happened, but I am not complaining one bit. I will say this, I have seen some of the weirdest stuff happen while dealing with GoDaddy hosting. Oh well, it is working now. Thank you so VERY much for posting this script for free. There’s no words that can tell you how much I, and most likely a lot of other people as well, appreciate it.

    Kudos to you!!!
    GKngiht

  39. Mark Sanborn on January 19th, 2008

    I too have seen some weird things with GoDaddy hosting.

    You are welcome for the script. I love to get these comments from people. It motivates me to write more. A lot of people read my articles but don’t comment so it is hard to judge if they appreciate my work.

    For that, I thank you sir. :)

    Mark

  40. Chris on January 23rd, 2008

    Hi Mark,
    Thanks for posting your solution. I found it quite helpful.

    I also use Dreamhost and also noticed that the script is averaging just under a minute to return a rate amount on one of their shared accounts. (Interestingly, the script runs in under a second on a different ISP’s shared machine.)

    I’m wondering how you make use of the script (assuming it’s being used on Dreamhost) given that performance is rather slow in the shared hosting environment. Do you use it as part of a web application? My first impulse was to leverage the script in a cart I’m developing on DH, but I fear that it’s just too slow there to be of practical use.

    Thanks again for sharing,
    -Chris

  41. Mark Sanborn on January 24th, 2008

    Chris,

    I wrote a big long comment yesterday explaining how I was going to investigate the issue; however, for some reason it didn’t get submitted. Anyways I apologize for not responding quicker.

    I am currently sending emails back and fourth to Dreamhost trying to find out why cURL is so slow on their servers. At this time they are mostly ignoring me. They believe the problem is UPS but I am assuring them that I can request the same xml file from my home computer and receive it instantly.

    There is obviously something wrong with the way Dreamhost is handling cURL.

    As soon as I get a solid answer from Dreamhost I will post it here. Along with the emails that I have been sending back and fourth to them.

    -Mark

  42. Ken on January 29th, 2008

    Thank you. The most difficult part was getting all them damn codes from UPS.

    I plugged ‘em in, and presto your function spewed the expected result.

    Where’s your DONATE button? You saved me at least a full afternoon of messing with someone else’s poorly constructed Open Source code.

  43. Mark Sanborn on January 29th, 2008

    I know exactly how you feel. The only reason I now know how to calculate UPS shipping with PHP is because I spent hours figuring it out.

    Ken, thank you for your motivating comment. I love to hear that my articles are helping people out. Every time I get a comment like this it inspires me to write more.

    I added a donate button on the right side just for you. :)

  44. Chris on February 10th, 2008

    Hi Mark,

    Did you make any headway with DreamHost on the PHP/cURL performance issue?

    I’ve been pursuing the same problem with them and have yet to get anywhere…

    -Chris

  45. Mark Sanborn on February 11th, 2008

    Chris,

    I have not made any more headway. What are they telling you?

    If enough of us complain maybe they will fix it.

    Mark

  46. Bryan on February 13th, 2008

    Thanks, this looks great! The UPS website is a real pain though. To get an XML access key you need a developer’s key. To get that key you need a UPS account. To set up that account they need a credit card.

    Why must UPS store my credit card so I can look up some shipping rates? Did anyone find a way a round this?

  47. Chris on February 14th, 2008

    Hey Mark,

    Basically, they’re passing the buck. The latest feedback after monitoring the rate lookup script in action on my account:

    cURL is having troubles on doing a reverse lookup on ups.com’s IP, which is mis-configured (e.g.. it doesn’t reverse lookup correctly). I’m going to be speaking with an admin to hopefully find a band-aide solution to make cURL stop going this, but it actually appears the culprit is ups.com’s DNS setup.

    For the time being, you may want to consider trying an alternative method; maybe use ups.com’s IP address instead of domain or find an alternative domain name to use, another possibility would be to use fopen for the URL (Although this would require you configure your own PHP — so it may not be worth the extra effort).

  48. Conrad on February 17th, 2008

    Thanks for putting this up, you saved me a lot of time and helped my client and I out a lot!

  49. Mark Sanborn on February 18th, 2008

    Conrad,

    Glad I could help.

    Mark

  50. Brian on February 26th, 2008

    Great script works like a charm with 1and1 linux hosting!

  51. Arun on March 17th, 2008

    Hi Mark Sanborn!

    I have used your code for UPS rate calculation. its working fine. thanks for this wonderful guidance.

    I having a problem while i post the “ShipmentConfirmationRequest”

    I have put only for choices of services

    code description
    1. 02 => “UPS Second Day Air”
    2. 03 => “UPS Ground”
    3. 12 => “UPS Three-Day Select”
    4. 14 => “UPS Next Day Air® Early A.M. SM”

    when i select the fourth option, the ShipmentConfirmationRequest is come successfully. whereas i select the rest of the options I am getting the following error :

    1.00010 Failure Hard 121175 Verbal Confirmation of Delivery is unavailable with the selected service.

    So, Please help me out,

    Thanks in advance.

  52. Mark Sanborn on March 17th, 2008

    Well it means exactly what it says. UPS is telling you that they don’t support verbal confirmation with the selected service. Contact them and ask them why.

  53. Greg Walsh on March 21st, 2008

    Hi Mark

    I used your script and it appears to be working correctly but the UPS server is responding with “0FailureHard250005No Access Identification provided”. Not that it is bad mind you but that it is not provided. it is. I even stripped it down to just the access xml and i always get the same response

    i tried it using the command line and the xml content in a file

    curl -d @xmlreq.txt https://www.ups.com/ups.app/xml/Rate

    and it did work however when i tried this

    curl -d xmlreq.txt https://www.ups.com/ups.app/xml/Rate

    without the @ sign i did get back the original error message. it appears to be something in the php interface.

    thoughts?

  54. Mark Sanborn on March 25th, 2008

    “FailureHard250005No Access Identification provided”

    Usually means the xml file does not contain your credentials.

  55. Arod on April 2nd, 2008

    Hello,

    I’m trying to have a section on my site that allows for multiple shipping destinations, is there a way to execute this function twice on the same page?

  56. Mark Sanborn on April 2nd, 2008

    Arod,

    Yes of course.

    $rate1 = ups(90210,03,5,5,5,5)
    $rate2 = ups(97470,03,5,5,5,5)

    rate1 will have the UPS ground rate of a 5lb package to California.

    rate2 will have the UPS ground rate of 5lb package to Oregon.

  57. Rashmi on April 3rd, 2008

    all is working fine , html page displaying shipping amount , but along with this error notice 9.85PHP Notice: Undefined index: value in D:\www\ups.php(114) : eval()’d code on line 1 PHP Notice: Undefined index: value in D:\www\ups.php(114) : eval()’d code on line 1

    its coming on html page. i think eval($php_stmt); is the source of problem. pls let me know how to overcome with this problem.

  58. Rashmi on April 6th, 2008

    Hi, how can we run this code in test mode? pls let me know.

  59. [...] do I use the UPS API of which they supply close to 70 pages of documentation? Well, first off read this article and download his code. I am not going to take credit in creating the function I use. He also takes [...]

  60. Bob TImms on April 11th, 2008

    I keep getting a parse error and I’ve triple checked that the code is identical to that posted.

    Parse error: syntax error, unexpected T_STRING in /home/pro/public_html/ups.php on line 14

    Any suggestions would be greatly appreciated.

  61. Mark Sanborn on April 11th, 2008

    Bob Tlmms,

    The code as is in this post works when I try it. But different hosts may have php configured differently.

    I was looking at the code and your php may be erroring when it reaches, ‘?>’ <—- that part of the code on line 14.

    The $data variable is defined with double quotes. This means that it will try to execute code within before converting it to a string. Your php may be trying to end the code when it reaches the question mark-greater than.

    You can try escaping the question mark or converting is to ascii code.

    Let me know if this helps. I will also do some further investigation for fixing this in the future.

  62. Bob TImms on April 11th, 2008

    Thanks Mark. Tried both suggestions with same results. FWIW, its working the same on my local xampp which is php 4 and my vps which is php 5.

  63. Bob TImms on April 11th, 2008

    Actually I was saving the changed file to wrong directory – when I escape the ? the error starts moving down the page and the ‘ also need escaping.

  64. Bob TImms on April 11th, 2008

    Well I finally got it fixed. Added opening and closing taqs . I didn’t think they were needed in the included/required file.

  65. jared on April 18th, 2008

    Mark,

    Let me echo everyone else’s sentiments and say thanks for sharing your code. It has certainly made my life alot easier :)

    Rashmi,

    You can run Mark’s code in test mode by changing this line:

    $ch = curl_init(“https://www.ups.com/ups.app/xml/Rate”);

    to this:
    $ch = curl_init(“https://wwwcie.ups.com/ups.app/xml/Rate”);

    In UPS’s documentation, they recommend you use their staging environment so that a pickup doesn’t inadvertently get scheduled.

    I assume this is not a problem with Mark’s code?

  66. Fos on April 19th, 2008

    THANK YOU SO MUCH!!!!!!!!!!!!!!
    you just taught me how to get out of the mass with ups libcurl stuff, which I have been struggled for about 3 days! It just works perfect! I can’t thank you enough for your work and this post.

    One little note is that I had to put quotes around $service.
    ex) ups(90010, “03″, 5, 5, 5, 5);
    Otherwise, the response showed 111209 error, which is not even listed on the guide manual from UPS. It said something like Invalid Servcie Name on the XML response though.

    I hope UPS could add this onto their manul for PHP examples.

    THANK YOU once again!

  67. Mark Sanborn on April 21st, 2008

    Jared: You make a great point. UPS has a test server for testing your application. I didn’t use this in my testing since UPS comes for pickup everyday anyways. So I over looked this. I will add it into my post.

    Mark

  68. Fos on April 24th, 2008

    Hi, I came back :)
    I needed to ask something.
    I’m not getting any xml response from UPS right now…
    is it my falut?? I’m just so confused.
    The thing is that the other site with other way to get XML rate from UPS is also failing. So I don’t think it’s the problem with the code on this post, but I was just curious… am I the only experiencing failures all the sudden?

  69. Frank of Zoinks Graphics on April 29th, 2008

    Hey Mark:

    Allow me to join the choir singing your praises! Why UPS makes this so tough for PHP coders is beyond me. :/

    Feedback: I too was having trouble getting your script to work until I put in the quotes around $service as indicated a few posts above…

    BTW, I found this post via a last-ditch Google search for “ups rates on my site”. May I suggest listing on HotScripts? That’s where I generally go first for stuff like this, and I’m sure you could get a lot more traffic that way. Plus $$$ if you put up a donation link!

    Thanks again!!!

  70. Frank of Zoinks Graphics on April 29th, 2008

    Whoops, I missed the “Donate” tab right at the top of the page. Just sent you some “happy money” for getting me out of my UPS hole!

  71. Frank of Zoinks Graphics on April 29th, 2008

    Okay, one other question… My client is selling perishable items (gourmet cookie dough) and wants to have shipping based on time of year. Ie. In the winter offer slower-UPS options, but in the summer only faster ones. Is there a way to query the UPS XML for their estimated shipping times based on delivery zip code? I’m thinking I’ll have to do 2 XML queries, the first for the shipping time and the second for the resultant charges…

    Any help in this direction would be greatly appreciated!!

  72. Frank of Zoinks Graphics on April 29th, 2008

    Oops, that’s “TimeInTransitRequest” request…

  73. Mark Sanborn on April 29th, 2008

    Frank,

    Thanks for the donation. :) I am really glad that at least some of my articles are helping people.

    I will look into putting the script in other places like hotscripts. Anything to help people figure out the same problems I was having with UPS.

    You may want to subscribe to the blog. Based on the popularity of this article I am going to continue writing more articles on the topic of setting up shopping carts and calculating shipping costs.

    Mark

  74. Frank of Zoinks Graphics on April 29th, 2008

    Cool, helping people… and making a little scratch too. That’s what it’s all about!

    I’ve asked UPS for help on translating the TimeInTransit XML call, but not sure if they’ll be any help. So if you have any ideas….

  75. Girish on May 2nd, 2008

    Hi,
    Can you please tell me What is UPS shipper number ?

    Thanks in advance

    With Regards,
    S. Girish

  76. Mark Sanborn on May 4th, 2008

    Girish,

    It is the number given to you by UPS. You will need an account with them if you wish to use this service.

  77. Frank of Zoinks Graphics on May 12th, 2008

    Hey Mark:

    Did you get the email I sent you a few weeks back asking for help with time in transit calculations? I could really use your help, and would be willing to make another — more sizable — donation!

  78. Naz on May 12th, 2008

    Dear Sir,

    Thank you for the helfull code. I have one question. What is liscence number? Is this provided by UPS when anyone registers?
    Thanks for all your help!

  79. Mark Sanborn on May 12th, 2008

    Naz,

    Yes the license number is provided by UPS via Email when you register for their online services. The service is free you just need to register.

  80. [...] The function discussed below is used for communicating with the United States Postal Service (USPS). If you are looking for the United Postal Service (UPS) function see, Calculating UPS Shipping Rate with PHP. [...]

  81. Naz on May 15th, 2008

    Hello Sir

    I am getting this error

    Notice: Undefined index: RATEDSHIPMENT in /var/www/dev01/……/ups/ups.php on line 116

    line is
    return $params['RATINGSERVICESELECTIONRESPONSE']['RATEDSHIPMENT']['TOTALCHARGES']['MONETARYVALUE'];

    I have given all values required in the ups.php file at the top.
    Please guide me where I am making mistake.

    Thanks and best regards
    Naz

  82. Mark Sanborn on May 15th, 2008

    Naz,

    Try putting the rated shipment in quotes, like this:

    ups(90010, “03″, 5, 5, 5, 5);

  83. Shammi Badial on May 20th, 2008

    Hi mark,

    I got following error after adding the code. Please help. I am stuck
    ——————————–
    The XML page cannot be displayed
    Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.

    ——————————————————————————–

    Invalid at the top level of the document. Error processing resource ‘http://www.haugeprinting.com/ups2008.php’. Line 8, Po…

    <CustomerCon…

  84. Shammi Badial on May 20th, 2008

    Please tell me whether it is mandatory to add UPS shipper number in ups.php

    regards

    shammi

  85. Mark Sanborn on May 20th, 2008

    @Shammi Badial: Yes it is absolutely manditory to include your UPS shipper number.

    If you are using Internet Explorer and you don’t have any html tags you may get an error saying the XML page couldn’t be displayed.

    The reason Interenet Explorer does this is because there is some XML looking data in the PHP comments but it IS NOT an XML page. To make sure internet explorer doesn’t get confused you need to put “<html>” tags when you call the function.

    In the future I suggest you stop using Internet Explorer and use a browser that actually adheres to standards like, Opera or Firefox.

  86. iM on May 20th, 2008

    hello! great script!!

    i have a question, though: when I set the RequestOption to Shop (instead of “Rate”) to get the different types of shipping, i still got the last value from the xml.

    Is there an easy way to tweak your script so I can use the response as another array?

    Thanks,
    iM

  87. Mark Sanborn on May 20th, 2008

    @iM: Yes you can.

    Add the following line:

    echo '<pre>'. print_r($params). '</pre>';

    Right before it spits out the return $params.

    This will give you an array of the xml and the values you need to use inplace of the ones I used to get the rate.

  88. mauricio zuniga on May 23rd, 2008

    Great Script.
    I have a class I was using for this purpose but magically stopped working on the 21st. I am thinking UPS made some changes to their API.

    I just used your script as a replacement.

    Thanks again!!!!!
    Mauricio

  89. Ian on June 19th, 2008

    Has anyone found a workaround for the script not working when E_ALL is set ? I use E_ALL when in development mode to help find any little nit-picky issues.

  90. Vineesh on June 25th, 2008

    for the last 1 week i am trying for the integration of ups with my site .

    i also developed similar code as mark sanborn has done ,

    But there is still some problomes persisting .

    regarding the error handling .
    “”"”"Maximum weight constrain 150 lbs “”"”"”"”"

    any solution for this should be appreciated .
    My mailID:vineeshpoduval@hotmail.com

    thank you .. ..

  91. Randy on June 26th, 2008

    Thanks Mark for the great script. I think you saved me a lot of time integrating UPS Online Tools into my shopping cart! :-)

  92. webwired on July 1st, 2008

    I had the same issue as Shammi Badial, I was about to start cussing this as another one of these that didn’t work, BUT, you script is awesome, thanks for the contribution.

  93. Mettled on July 11th, 2008

    I just wanted to add my “thanks” here as well. And having exact rates for bundles of stuff in the shopping cart, like you mentioned, would be the icing on my cake. It’s so nice that you’re sharing your work. There’s something so frustrating about trying to invent the wheel that you know has already been invented.

  94. Mark Sanborn on July 11th, 2008

    @Mettled,
    You are welcome I am glad I could help. Stay tuned for more guides about shipping APIs.

  95. max on July 15th, 2008

    Hi Mark,

    You saved my life. Did you ever figure out why it throws this?

    7.23PHP Notice: Undefined index: value in D:\WebProjects\qqqcenter\ups.php(118) : eval()’d code on line 1 PHP Notice: Undefined index: value in D:\WebProjects\qqqcenter\ups.php(118) : eval()’d code on line 1

    I have PHP (latest version) and Errors on E_ALL since I am developing on this machine.
    Regards

    Max

  96. smithveg on July 16th, 2008

    Great Script!
    Luckily you telling me that i need some extra code in godaddy hosting.

  97. smithveg on July 17th, 2008

    Hi Mark,

    When i try to make a comparison to the shipping charges calculation in ups website.
    https://wwwapps.ups.com/ctc/request

    Ship from United States 24112
    to United States 24114
    Dimension 5×5x5 at 8lb
    How will you get your package(s) to UPS?
    - I will pay shipping charges and ship my package at a retail location such as The UPS Store™ or UPS Customer Centre
    Do you have a Daily Collection?
    - No

    This return me 8.39 USD at 8lb.

    But your script, with the following input:
    $service = ‘03′;
    $length = ‘5′;
    $width = ‘5′;
    $height = ‘5′;
    $weight = ‘8.0′;
    $dest_zip = ‘24114′;

    Return me: Rate is 7.88.

    Why the shipping charges is different?
    Probably my input information was incorrect.
    Please correct me, Mark.

  98. Mark Sanborn on July 17th, 2008

    In the UPS function On line 34-36 you will need to specify the proper pickup type.

    My script is assuming that UPS is already comming to your house/office.

    If you have any more questions please ask. :)

  99. smithveg on July 18th, 2008

    Hi Mark,

    Your pickup code = 01 (Daily Pickup)
    It result at $10.92 shipping charges

    When i try the pickup code = 06 (One Time Pickup)
    It result at $19.33 shipping charges

    Any idea why the one time pickup much expensive than the daily pickup.

    When i have another testing in RatesandServiceHTML
    I got the result as below:
    When pickuptype = ‘daily pickup’; $14.95
    When pickuptype = ‘one time pickup’; $10.92

    It seems both version result is different charges from what i experience.
    I do not want the UPS crew visit my place daily.
    That’s the reason i change the pickuptype code from 01 to 06. Any suggestion?

  100. smithveg on July 20th, 2008

    Hi, Mark,

    Any ideas why the HTML shipping charges calculation provide me the different result from your XML version(with the same input information)? Please help. I just worry that the wrong calculation make my client lost money in your businesses.

  101. Dave Wagner on July 24th, 2008

    I am sure this is a dumb question, but I cannot get past it. Your UPS.php page does not have <?php at the top of the page. Why not?

  102. Mark Sanborn on July 24th, 2008

    @Dave Wagner,

    I added it just for you… :P

  103. Jade Robbins on July 24th, 2008

    Also, if your host is set to parse .php files then you don’t need to tell it what language it is at the top!

  104. Dave Wagner on July 25th, 2008

    Thanks very much,
    All works perfectly now. As you can tell I am new to PHP. Your code is exactly what I needed.

    Thanks again,
    Dave Wagner

  105. smithveg on July 28th, 2008

    MUST i input the package sizes in the calculation? Width, Length, and Height.

    My site selling several product in different sizes.
    In my testing, 0×0x0 and 17×17x17 give me the same shipping charges. From 18×18x18, the shipping charges will change. From here, i noticed the package sizes doesn’t result in a big changes. What do you think?

  106. Mark Sanborn on July 28th, 2008

    Smithveg,

    Well you can change lines 70,71,72 and remove the $width, $length, $height variables from the function if you want to.

    UPS calculates packages by area weight. They do this because oblong or odd shaped packages will take up more space in the shelves of the veichles like a fishing pole for example. It is usually packaged in a long pole but really light. You would be charged more than you would if it were just a simple box shape. Another example might be shipping a giant box full of packaging peanuts, sure the weight is only a few pounds but the box could be 8ft wide.

    If you are shipping items that are all a similar demension and usually go in boxes then you would be fine just putting 5,5,5 for the length, height, width.

    I hope this helps.

  107. Tracking UPS Packages with PHP on July 29th, 2008

    [...] now you should know how to look up a UPS rate with PHP. Now we are going to look into tracking the package using the UPS tracking XML API. This tool uses [...]

  108. Tracking UPS Packages with PHP on July 29th, 2008

    [...] now you should know how to look up a UPS rate with PHP. Now we are going to look into tracking the package using the UPS tracking XML API. This tool uses [...]

  109. Mike on August 6th, 2008

    Hi,
    I have a question. I already register with UPS.com as u suggested link. When i select online tool, it asks me for UPS Account No. how to open UPS account no. It is compulsory to run your code. what is $AccessLicenseNumber = ‘000′; in your code…..how do we get it.
    Pl help me someone…

  110. Judi on August 7th, 2008

    Hi Mark,

    Thanks SO much for this code – I looked through the 101-page UPS pdf file and figured it would take a month to learn all that!

    But I’m getting the same Notice that several other folks have mentioned in this blog:

    Notice: Undefined index: value in /vservers/pdaroadgearc/htdocs/ups.php(116) : eval()’d code on line 1

    I get two of them in a row; they’re generated from this line in the ups.php file:

    eval ($php_stmt);

    I put an echo in the code to print out the $php_stmt, and they show up right in the middle of the $vals loop; don’t know enough to know what’s wrong, tho.

    Do you have any ideas? I’m worried that my results might be wrong…

    Thanks so much!

    Judi

  111. Judi on August 8th, 2008

    Mike, you need to register with UPS to get a username and password. Then you’ll get a Developer’s key (emailed to you, I believe), and from there you can get the Access key by going back on the website. There’s a place to request the Access key right on the website

  112. Judi on August 8th, 2008

    Hey, SUCCESS! I’ve figured out the answer to my own question above. If you replace this:

    $php_stmt .= ‘[$xml_elem[\'tag\']] = $xml_elem[\'value\'];’;

    with:

    if (isset($xml_elem['value'])) {
    $php_stmt .= ‘[$xml_elem[\'tag\']] = $xml_elem[\'value\'];’;
    }
    else {
    $php_stmt .= ‘[$xml_elem[\'tag\']] = “”;’;
    }

    … then those Notices go away.

  113. Mark Sanborn on August 8th, 2008

    Judi,
    Thanks for showing the exact line that is wrong. I know other people were having issues with this. I have not seen any adverse effects because of it, but I will look into it further.

    I would also ask if anyone else has resolved the issue to come forward with your changes.

    Mark

  114. gknight on August 28th, 2008

    Hello again Mark.I am using an extremely modified version of your script to generate the portion of the ooutgoing XML before sending the information to ups.php. Here is the question that I have…

    For shipping multiple products in one box, I have it calculate against the maximum weight, take the total volume of the items going into one package and square cubing it to give generic dimentions for the length, width and height. What the problem is, now that UPS has updated their Rate service, I am now hitting a wall with the maximum girth of the package being 165 inches(girth being 2 x width 2 x height length). What I need is to find a way to take the actual size of the items being shipped and get them to arrange in a predefined size box. Kind of a 3d packing if you will. The only problem is, I am not that advanced of a programmer. If a third item is placed in a box that already has 2 other items, if the script needs to rearrange the first 2 items to fit the third, it recalculates as needed. This way, I will not be going past the girth and/or weight max for the shipping API.

    This is a tough one even for me and I like to think that I am pretty good with at least figuring out some kind of strategy for programming it even if I can’t figure out the programming part.

    A point in the right direction would be EXTREMELY helpful, so if you have any ideas, you can send me an email or post it on here. I have this page bookmarked!

    Thanks in advance (again…..lol),
    gknight

  115. tim on August 29th, 2008

    Mark –

    Thanks so much for making this code available. Just got it working on my server in less than 40 minutes! I need to look into how to add insurance (and maybe how to tweak it for multi package shipments), but that’s no biggie. I also had the eval()’d code error others had, but Judi’s suggestion cleared that right up. (Thanks Judi!)

    Incidentally – in three years of running Virtuemart with the UPS module, I have never once had it give a 100% accurate shipping quote. I plugged in the data from a recent shipment, and your code nailed it to the penny. Virtuemart does not seem to account for package size, so when I’m shipping something large and light I lose my butt because of dimensional weight charges. My new cart will calculate carton size, so calling the dimensions in your code will be a huge help. Again – excellent job!

  116. Judi on September 4th, 2008

    Hello gknight,

    I didn’t quite understand how you figured the volume on your multi-item package, but here’s how I do it:

    Calculate the volume for each item, then add all the volumes together to get the total volume. Then take the cube root of that (round to the nearest one hundredth) to get hypothetical dimensions that you can plug into the UPS call.

    Fact is, the actual volume will be a little larger due to packaging not being perfect, so my client has me add a fixed amount to each shipping amount to make up for that.

    I’m interested in knowing how other folks do this, so if anyone has a different method, please let me know!

    Thanks,
    Jud

  117. Mark Sanborn on September 4th, 2008

    Judi and Gknight,

    Large shippers use dimensional weight. Which is a ratio of cubic volume and weight. Most carriers have extra charges for oversize packages.

    What I would recommend is to get together with the shipping department and find out which items fit in which boxes. In my situation most small items I can get 4 in a box. So I give them a value of .25. Large items that require one box get a value of 1.

    I then have a script that will go though and pack items in boxes as best as it can until it reaches a full box. If the box is a solid 1 then it is done. If it is less it will wait to close it until all items in the shopping cart are accounted for.

    If you wanted to get really fancy you can vary the weights and do multiple rate requests and find the cheapest way to pack based on distributing weight on multi-pack shipments.

    This is how I do it. Hope it helps

  118. Ben on September 7th, 2008

    Mate, you’re a legend! Thanks for putting in the time to post this up. Saved us all hours!

    Ben

  119. Etwig Weltevreden on September 8th, 2008

    Hello Mark,

    i try to use your sript. but it does not work.
    yje original script also doe s not work.
    I do not know i do wrong but, if you try log onto my site and open an account. After that try checking out with a product to pay and make your choise for shipping. you will see that you can not get an option for UPS. You can see the logo, but notting happens.

  120. jacob on September 10th, 2008

    I feel that critical concerns have been obfuscated by rudimentary php questions (which should be asked at php.net, not here).

    I’m tearing my hair out trying to discover why there is an inconsistancy between the UPS rate calculator and the RatingServiceRequest XML in general; I am wondering if you’ve discovered any solutions to this.

    My insight: It appears that there is no element for ‘drop-off method’, and i suspect that the fuel surcharge isnt actually being added.

    Wondering if you spotted anything awry.

  121. Mark Sanborn on September 10th, 2008

    Jacob,
    Are you using the production server or testing? The fuel surcharges should most definitely be in the rate request but my vary depending on if you are still on the test server.

    If I remember correctly there is an option to bring the package to a “UPS Store” for drop-off. Is this what you are referring to?

    In my tests the rates have been very accurate.

  122. Bin on September 11th, 2008

    Hello Mark, I am trying to incorporate your code with prototype javascript framework’s ajax.request. However, I would like to know what is returned from the ups function? Is it returning a XML string or simply just the ups shipping value?

  123. Mark Sanborn on September 11th, 2008

    Bin,

    Well my function returns just the monetary rate value from UPS’s XML response.

    It returns an XML string from UPS that is later converted into an Array.

    Uncomment line 92 and do a view source in your browser to see the XML code returned by UPS if you are curious.

    Mark

  124. Dan on October 3rd, 2008

    Hello Mark,

    I have noticed the same problem as Jacob did. The script works great, but when I compared the cost using this script as well as another I came out with the same shipping cost. I checked on the UPS website just to verify and got a slightly different value. It does appear to be about %5 off or so which sounds like the shipping cost.

    It seems like UPS has added these fuel surcharges to their rates, but have not updated their system to reflect it when using this interface.

  125. Mark Sanborn on October 3rd, 2008

    Are you on production?

  126. barbara on October 6th, 2008

    I’ve just run comparisons of the testing and production servers, and get the same rates returned from both servers, but they are definitely less than the rates UPS quotes of their Calculate Time and Cost page.

    It really does appear that they’re not including the fuel surcharge. In addition, on the fuel-charge explanation page (http://www.ups.com/content/us/en/shipping/cost/zones/fuel_surcharge.html), they state that the ground fuel surcharge percentage is also added to the pickup and delivery charges, and the residential surcharge. This additional surcharge also doesn’t appear to be included in the rates sent back from https://www.ups.com/ups.app/xml/Rate, since a simple addition of the rate sent back plus the surcharge percentage listed still doesn’t equal the rate they list on the Calculate Time and Cost page. :(

  127. Dan on October 6th, 2008

    Yes, I am using the UPS production URL and am specifying a weight of 23. The scripts return a value of 10.89, but when I do the same lookup using the UPS website itself I get a value of 11.89.

  128. Anthony M Powers on October 7th, 2008

    Seems that recently, a lot of the people using this script are seeing a distinct discrepancy in the value returned by it and the UPS Shipping Calculator web-tool.

    Dan (above) said “It seems like UPS has added these fuel surcharges to their rates, but have not updated their system to reflect it when using this interface.”… I would have to agree. The value returned just is *not* displaying the recent changes in fees. (I say more recent because the first comments here did not display this issue…)

    Mark:

    Great script. This doesn’t seem to be your problem. The value returned is out of your control, really. But since you’re questioning everyone, here are the answers:

    I tested this on both the Testing and Production servers, and using both web applications:

    1. http://www.ups.com/using/services/rave/qcostcgi.cgi
    2. https://www.ups.com/ups.app/xml/Rate

    FYI: Both locations result the exact same information, and both are far from equal to the web-tool (http://www.theupsstore.com/qcc/qcc.asp).

    Until UPS properly fixes this, or gives control to the developers using it, it seems we are ‘out of the loop’ on the actual prices.

    If you have any leads, Mark, please make a comment and get a hold of us (You have our emails!). Really appreciate the effort!

  129. Mark Sanborn on October 7th, 2008

    Due to the amount of people getting differing quotes from UPS I am going to do some investigation today and possibly give them a call.

    Mark

  130. New UPS PHP Project at Google Code on October 9th, 2008

    [...] of popularity I have decided to take UPS modules written in PHP found in my article, Calculating UPS Shipping Rate with PHP, over to the next level. I am rewriting all the code in object oriented PHP and publishing the code [...]

  131. Roger on October 10th, 2008

    I’m developing a shopping cart for a client. I love this program you wrote, but I’m having trouble getting the various codes to work for Next Day, 3 Day Select, Ground, etc. The XML error I get back says the option is invalid. Specifically:

    Bare Bones Rate Request1.00010FailureHard111209Invalid Service Type

    Where can I find the codes for the XML Request on UPS’s website? I can’t seem to find the online manual that has all that info and the download they have posted seems incomplete because the dev_guide folder is empty.

    By the way, I got this error using service code 01 and 03. Code 12 went through and I got a price back so I’m confident everything else is working.

    Any guidance would be appreciated. Thanks!

  132. Mark Sanborn on October 10th, 2008

    Try putting double quotes around the service.
    ups(90210,”02″,5,5,5,5);

    PHP thinks 02 is the same as 2 and causes a problem. This has been fixed in the documentation on the new project site. I will also add it here.

    Thanks,

    Mark

  133. Roger on October 11th, 2008

    Awesome. That was it, it works. Thank you!

  134. EveryonesGeek on October 18th, 2008

    Notice: Undefined index: value Message… i had it too on a new host and after 2 hours of searching google and changing code… i got it to work on a test page… but still not on the real page… then I removed the and pages worked fine. Thanks for the script, saved me DAYS !!

  135. EveryonesGeek on October 18th, 2008

    Notice: Undefined index: value Message… i had it too on a new host and after 2 hours of searching google and changing code… i got it to work on a test page… but still not on the real page… then I removed the “error_reporting (E_ALL ^ E_WARNING)” and pages worked fine. Thanks for the script, saved me DAYS !!

  136. Cedric W on November 17th, 2008

    Hey Mark,

    I have the script working. It works fine. However, I have heavy boxes I would like to ship to my end-users. UPS has a 150 LB limit on boxes. Your script as it stands seem to assume you are shipping only 1 box. Is there a way to have PHP, if the weight of what I’m sending exceeds 150, write XML that repeats the RatingServiceSelectionRequest/Shipment/Package element? Basically I want to make the XML see the request as a multiple-piece shipment if the weight is greater than 150LB.

  137. Mark Sanborn on November 17th, 2008

    Cedric W,

    If you are using the release version of upsRate.php from code.google.com/p/ups-php you would simply do multiple requests. If you had the weights for each product stored in a database you could start a new request after a specified weight was reached.

    The beta code for the UPS rates has the option to add multiple packages in one request. If you need further help on this feel free to email me through my contact form. I need a guinea pig to test the beta code.

  138. Cedric W on November 17th, 2008

    Thanks. I sent you a message through your contact form.

    Yes I’m using your upsRate.php. I just needed to know how to do multiple requests. Sorry I’m not that versed in XML =(.

  139. Mark Cloyd on December 10th, 2008

    Mark, thanks for the ONLY php script I have seen that deals with UPS tools. I have a question however about Negotiated Rates. I have added the appropriate tags RateInformation > NegotiatedRatesIndicator as per the UPS documentation and have added a value of TRUE. I am not receiving the negotiated rates… does your script handle those? I am not receiving any errors, and I have looked at the code for looping through the array vars and it seems that the response should come in if it’s available. Thanks for your time.

  140. Mark Sanborn on December 10th, 2008

    Hello fellow Mark,

    The code that we are working on right now at the Google Code page has negotiated rates built in. There is even an example in there with usage. If you want to get it up and running really fast just svn checkout the beta code.

    Let me know if you need any help. I’m always looking for people to test the new code. :)

  141. Mark Cloyd on December 10th, 2008

    Fellow Mark… I like that. Sometimes I get too focused to have fun, thanks!

    At any rate… the code from the svn trunk seems to work very nicely. I have to verify the rates I am getting are the Negotiated rates, but they sure seem to be!

    I will make sure to post feedback once I hear from the UPS rep. Thanks for the reply, and thanks again for making the UPS tools easy!

  142. Billy on December 11th, 2008

    Hi Mark,

    Thanks for such a wonder full code, i made some changes as per my requirement and its working fine. BUT i m facing a prob… if we process this function with more than 150 LBS weight or more than 30inches in any dimension, it won’t display reply or error. I have tried this with all services codes.

    Please help me out, Thanks

  143. Glen D. on December 11th, 2008

    Hi Mark,

    Thanks for making this available. I read through these comments. I tried the double quotes and that didn’t make any difference, still get the same messages I’ve copied you below. I have this gut feeling that I must be close, but it’s still not quite working. I get this PHP error message:

    Undefined index: RATEDSHIPMENT

    And this is the html comment error message that I get (the one you coded into your function):

    <!– HTTP/1.1 100 Continue

    HTTP/1.1 200 OK
    Date: Fri, 12 Dec 2008 00:24:52 GMT
    Server: Apache/2.0.52 (Red Hat) mod_ssl/2.0.52 OpenSSL/0.9.7a
    Pragma: no-cache
    Content-Length: 497
    Content-Type: application/xml

    Bare Bones Rate Request1.00010FailureHard10001The XML document is not well formed –>

    I hope the comment error message means at the very least that I am communicating with UPS, though at this point the blind date isn’t going so well.

    Any help would be appreciated . . .

    Thanks,

    Glen

  144. Glen D. on December 13th, 2008

    Hi Mark,

    I think I may have found the problem but would just like to confirm it with you. I think my site also needs to be using SSL. The documentation seems to indicate that, though doesn’t explicitly say: “Your site must also use SSL.” I hadn’t planned on using it because all the customer’s information is going to be entered at the gateway, but if I need it for the UPS tools then I’ll add it.

    Your thoughts?

    Thanks,

    Glen

  145. Mark Sanborn on December 13th, 2008

    @Glen D,
    Curl needs ssl support but you do not have to have ssl on your domain.

  146. Mark Sanborn on December 13th, 2008

    @Billy,
    UPS wont accept any packages over 150 lbs. You need to put your items in multiple packages.

  147. Glen D. on December 13th, 2008

    Rats! So any ideas why it is not working based on the error messages I get (see above)?

  148. Mark Cloyd on December 17th, 2008

    Mark,

    I told you I would post feedback… things are going VERY well! I am very pleased.

    I do have a favor to ask though… I am not well versed in xml, so… would you mind posting a way to parse the response xml for shopping rates so that user service options can be selected in a form based on the location?

    If so, I should be able to apply this code to a site within the week. I will be happy to post where the code it being used and will definitely post a credit in the source to you and your Google project page.

    Thanks again for your efforts, it is making life A LOT better!

    Best regards.

  149. Mark Sanborn on December 17th, 2008

    @Mark
    If you are using the beta (svned) code the xml response is parsed into an array automatically for you!

    $upsRate->returnResponseArray();

    Is this what you were looking for?

  150. Business Website Design on December 17th, 2008

    Great script! Thanks, man.

  151. Mark Cloyd on December 18th, 2008

    Hi Mark,

    Sorry, I must not have asked my question correctly. I do receive the array, that is all working perfectly!

    What I would like to do is take the response from that array, and create for elements from that response so that a customer can select the service and subsequently the price of shipping they would like to use.

    I.e., if a client is checking out in the shopping cart area, they should reach a point in the checkout that allows them to select things like, UPS Ground, Overnight, Express, etc. with rates for each appearing next to the options for each service respectively.

    I know it’s a simple thing, but I don’t know how to split the response into variables that I can use in this manner.

    Thanks in advance for any help you can offer!

    All the best,
    Mark

  152. Mark Sanborn on December 18th, 2008

    Mark,

    I will write you some code real quick tonight for this and post it up tomorrow.

  153. Glen D. on December 18th, 2008

    Mark,

    Thanks for your help today. I truly appreciate it. Made a donation . . . have a merry Christmas!

    Glen

  154. [...] And the UPS service code: [...]

  155. Mark Cloyd on December 19th, 2008

    Mark,

    Thank you very much! I will work on this today, see if I can get it applied and post the site it is working on!

    I just noticed too that I never posted my url. I have done so… just in case you want to go there.

    I know I speak for MANY people when I tell you that your efforts are VERY welcome.

    Have a great day, I will post results when complete.

  156. Mark Cloyd on December 19th, 2008

    Mark,

    By the way, my wife raises and trains Australian Shepherds. We currently have a litter on the ground and she tells me because of your responses and help that if you would like a puppy, she will give you a puppy if you would like… all you would have to do is pay for shipping.

    Her site is http://www.purestockaussies.com.

    Just a way of saying thank you.

  157. Mark Cloyd on December 19th, 2008

    Mark,

    Okay, everything is working very well… I still don’t seem to be getting the negotiated rates. I have looked at the code in the Google svn and don’t see anything that specifically calls for negotiated rates.

    I have been in contact with the UPS rep and he assures me that all settings on there end are “turned on” for negotiated rates… am I missing something silly?

    Thanks again for all your help.

  158. [...] one table. Not all too neat. Also, I found something thats kind of useful for self-made checkouts! Calculating UPS Shipping Rate with PHP I will use that, I wonder of fedex mades one, fedex rocks Attached Thumbnails   [...]

  159. Benocon on January 13th, 2009

    Hello Mark,

    Can you please help me te get mij shipping through UPS module to work?

    I have a zencart webshop. I am located in the netherlands. I do not get any quote. I have all i need from the ups site. I yhink i do not use the right code with the right ajustments.

    thanks in advance

  160. Jeff Shirley on January 13th, 2009

    I am currently looking at creating an internal module with the rates and service tools, does anyone have any insight on whether or not you can specify your origin and destination and calculated international rates and your landed duty paid? I want to be able to specify where the shipment is going, where it is going, enter in the dimensions and the weight and have it spit out how much it will be, is this possible?

  161. Mark Sanborn on January 14th, 2009

    Yes this is possible, be prepared however to spend a lot of time read the UPS manual to determine the correct XML requests to send.

  162. Mark Sanborn on January 14th, 2009

    You should be able to implement the shipping in zencart. The code should be compatible with everything. I am not familiar with zencart however so I can’t give you specifics. If you need help with something shoot me an email.

  163. Joey Marchy on January 15th, 2009

    @judi, @mark I can confirm that Judi’s comment on on August 8th, 2008 also resolved my issue with similar error messages. Thank you Judi.

    Notice: Undefined index: value in /Users/joeymarchy/Sites/happy0000/ee/modules/checkout/mod.checkout.php(250) : eval()’d code on line 1

    Notice: Undefined index: value in /Users/joeymarchy/Sites/happy0000/ee/modules/checkout/mod.checkout.php(250) : eval()’d code on line 1

  164. Trent Tompkins on January 16th, 2009

    If you want to add the option for Saturday delivery (otherwise UPS will only count business days), just add:

    “.
    ($sat?”1″:”)
    .”

    In place of already existing tags.

    Then add $sat=0 as the last parameter for the getRate function. When you need the Saturday rate, add a 1 as the option, or just add this function inside the getRate class:

    function getSaturdayRate($PostalCode,$dest_zip,$service,$length,$width,$height,$weight){
    return $this->getRate($PostalCode,$dest_zip,$service,$length,$width,$height,$weight,1);
    }

  165. Trent Tompkins on January 16th, 2009

    Comment system ate my code, should be:

    $sat?”1″:”

  166. Trent Tompkins on January 16th, 2009

    $sat?”<ShipmentServiceOptions><SaturdayDelivery>1</SaturdayDelivery></ShipmentServiceOptions>”:”

  167. Kris McCoy on January 19th, 2009

    Worked brilliantly. I don’t know much about XML, so this would have been a huge project for me. You took the headache out of it.

  168. Seenu on January 28th, 2009

    Hi mark thanks a lot this code works superbly tat was a great job from u. One small doubt,how can i get price for all the services(around 10 services) which UPS provide. Currently i am making separate call for each service which takes lot of time to respond back. I need to show the price for each service and let the user to choose one service from the list.

    Thanks in advance….. :)

  169. Mark Sanborn on January 28th, 2009

    UPS has a rate shop feature that will return all the available rates for that given zipcode. If you are using the beta code from code.google.com/p/ups-php there is an example on how to do it in the “tests” folder.

  170. Matt on January 29th, 2009

    Anyone figure out the deal with the rate being off? I have a client that suspects the answer has something to do with “shipping to a residence” not being factored in, but the fuel surcharge being missing sounds possible…

  171. Mark Sanborn on January 29th, 2009

    Are you using the production server?

  172. Eric on January 29th, 2009

    My UPS toolkit works on server php 4, but it doesn’t work after change to php 5 server, what code do I need to change…. ?

  173. Sean on February 18th, 2009

    I’m using upsRate.php with the address https://www.ups.com/ups.app/xml/Rate, I’m assuming that this is the production server, and just wanted to check on the discrepancies between the UPS website and the script, that can’t be accounted for entirely by the fuel surcharge. I’ve played around with it for a while and can’t resolve the difference. Thanks.

  174. Yuvraj on February 23rd, 2009

    Hi,

    when i am using above script, i am getting error
    “Fatal error: Call to undefined function curl_init() in C:\Program Files\xampp\htdocs\sites_comp\USPS test\index.php on line 16″.

    Cau u tell me, have i need any other file to call this function curl_init().

  175. Hernán on April 3rd, 2009

    how i change the currency type value? (CAD, USD or other) ? thanks

  176. Anton on April 6th, 2009

    I just wanted to thank you for your write up.
    I converted your script to perl for the rest of us out there that still use it for the heavy lifting. I made a copy available for anyone that needs it. It took about 4 minutes to convert your perfectly crafted UPS XML.

    –Anton

  177. David on April 17th, 2009

    Just wanted to thank you for this fantastic library/function thing :)

    If only UPS made it this easy.

  178. Jeremy on April 24th, 2009

    the script above works to perfection you are the man!!

    One question.. In a cart using the shipping calculator should I add up the weights, lengths, etc then send to ups.. I dont think that would give an accurate cost if anything to much..

  179. Kapur on April 28th, 2009

    Hey Mark,
    Thanks for the code..It helped me a lot…But i got into trouble about the height, and wide of the code.
    Because in my shopping cart, I know the weight of the product and destination. But I dont know hoe big box it is going to take to pack that product. Products with same weight can be some time big and some time small!!!

    How do I solve this problem?? Is there any way I can calculate shipping charges without inserting length, width, and height??

    Can somebody help me out please.

    Thank you in advance..

  180. Bill Magee on May 6th, 2009

    High Mark,

    First thanks for putting this code together. Don’t know where I would have found out how to get to UPS through PHP.

    Kapur, you might want to pay attention to this note, it seems you are in a similar situation. Feel free to contact me if you want to discuss approaches. My email is at the end of comment.

    I think a heads up on size is in order. I seem to recall in one of the notes that size doesn’t seem to matter so just use 5 inches for length, width and height.

    I am a fine art photographer opening an e-commerce store. I will be shipping some pretty big stuff. It could reach 50 inches long x 50 inches high x 6 inches wide. And even bigger.

    Being afraid that size could matter, especially since UPS requires it for rate calculation, I did a quick test. I simply put in a loop that kept everything constant except for length and height.

    Parameters are getRate(‘80133′,’99501′,’03′,$size,’5′,$size,10)

    I started with a size of 5 and incremented by 5 for each rate look up.

    The results:
    size=>5 cost=>37.84
    size=>10 cost=>37.84
    size=>15 cost=>37.84
    size=>20 cost=>37.84
    size=>25 cost=>37.84
    size=>30 cost=>37.84
    size=>35 cost=>87.14
    size=>40 cost=>106.31
    size=>45 cost=>240.07
    size=>50 cost=>240.07

    Note that size does not matter until passing 30×30x5, but then it seems to jump at almost every increment.

    I run the loop another time with weight set at 1 lb. Notice that rates are lower up until the 30×30x5 point but once passing that it seems that weight doesn’t matter since a 1 lb package costs the same as a 10 lb package.

    Parameters are getRate(‘80133′,’99501′,’03′,$size,’5′,$size,1)
    The results:
    size=>5 cost=>19.36
    size=>10 cost=>19.36
    size=>15 cost=>19.36
    size=>20 cost=>19.36
    size=>25 cost=>19.36
    size=>30 cost=>19.36
    size=>35 cost=>87.14
    size=>40 cost=>106.31
    size=>45 cost=>240.07
    size=>50 cost=>240.07

    Again thanks for your effort, it was real useful for myself.

    Bill Magee (bill@bill-magee.com)

  181. Greg on May 7th, 2009

    Kapur:
    UPS rate quotes are based on weight only until a box exceeds certain sizes, then its kicked into dimensional weight. If you have products that are large enough they will always be billed by “dimensional weight” then its best to enter their weight as what UPS will bill you for. For example i have a tank i sell that is 24×70x7. It weights 20 lbs, however dimensional weight for this product is 80lbs. So to avoid having to have dimensions for all my products, and a script which can tell me how to pack what, i simply use 80lbs as its weight, which gets me within $5-10 of what it will actually bill for.

    Mark:
    I was getting that undefined index for value error and i’ve determined it to be because im not getting these 2 fields
    [GUARANTEEDDAYSTODELIVERY] =>
    [SCHEDULEDDELIVERYTIME] =>
    both are empty in the array. I used a similar fix as to the one listed above, but any idea why im not getting this information?

  182. Andrew Slattery on May 24th, 2009

    You sir, are a hero to me. The immense UPS API reference guide made me want to run out in the street and scream at people! And I don’t have an extensive knowledge of cURL, so you have saved my life from angry clients :)

  183. neha on May 26th, 2009

    hi all, i really want to know how to get the exact shipping rates using the same ups.php page for Canada… Please help i m not able to proceed

  184. chirs on June 4th, 2009

    Add me to the list of people getting lower rates from https://www.ups.com/ups.app/xml/Rate then from the UPS site. Anyone have any idea how to resolve this?

  185. Mark Sanborn on June 4th, 2009

    To everyone having issues with lower rates.

    It is impossible to get a rate lower than from the UPS site if all the fields match exactly with the script. Why? Because the script uses the same method to get rates that UPS uses themselves.

    With that in mind, make sure that you select already scheduled pickup and input the dimensions properly when comparing rates.

    Also make sure you are using the production servers as the testing servers will give you stale rates.