USPS Web Tools for Address Validation, part one

(Note: this was originally written in 2010, to the best of my memory. While some references may be outdated, the code still works, as I’m still using it today.)

To use the USPS Web Tools API, you have to sign up and get a user ID and password. This is easy enough to do. Go to the Web Tools sign-up page and give them the expected sort of information. Shortly, you will receive an email with a user ID and password.

They also provide an implementation guide that is a little less than perfect. They start with the warning that you need to have a handle on web development with the usual sorts of languages, html, xml, etc. Essentially, any language capable of sending and receiving xml to and from remote servers will work – VB, Perl, PHP, etc. They will tell you what you need to send, but now how to send it. That’s all on you.

For me, I needed PHP, as that’s only one I’ve really worked with to have any sort of idea of what I’m doing. I spent an entire Saturday, 10 or so hours, searching the web looking for code that would work for me. I didn’t get very far. There was a wealth of code people had used, but I couldn’t figure out a way to modify it for my purposes. I will again point out that I have a shaky handle at best on PHP, so it may entirely be that any of them would have worked, had I been smart enough to figure it out. But I couldn’t, so I kicked it old school with some GTA San Andreas instead.

Sunday night, I couldn’t let it go, so I searched again. This time, I found something that looked likely – it was a short little bit of code, and I could see exactly how I could use it on the existing page I was using to give me the results I wanted. I found that here in the post by Denver Dave. It is apparently unknown who wrote it originally, but thank god he did, and thank god Denver Dave reposted it.

$url=’http://testing.shippingapis.com/ShippingAPITest.dll?API=ZipCodeLookup&XML=’;
$msg=’
<ZipCodeLookupRequest USERID=”xxxxxxxx”>
<Address ID=”0”>
<Address1></Address1>
<Address2>6406 Ivy Lane</Address2>
<City>Greenbelt</City>
<State>MD</State>
</Address>
</ZipCodeLookupRequest>
’;

//get the response from the USPS
$newurl = $url . urlencode($msg);
$contents=file_get_contents($newurl);
echo $contents;

Incidentally, if you haven’t looked at it yet, this is the first ‘scripted’ test USPS will have you run. When you have gotten your User ID, you have to run two scripted tests on their testing server. Once you have gotten those to work, there are some more hoops to jump through (more on that later.)

For this, simply plug your User ID in where the code reads USERID=”xxxxxxxx”. The test server will return the response in $newurl, and you use the $contents=file_get_contents($newurl) to retrieve it. I used a little variation on this, as simply echoing $contents doesn’t do me any good. I needed to parse out the xml into something that could be put on an HTML page. To do that, once I’ve gotten the response, I used this:

$xml = $newurl;
$parser = xml_parser_create();
// open a file and read data
$fp = fopen($xml, ‘r’);
$xmldata = fread($fp, 4096);
xml_parse_into_struct($parser,$xmldata,$values);
xml_parser_free($parser);
echo $xmldata;

Looking at the code, I likely don’t need the $xml = $newurl line, as I’m simply creating a new variable out of one that already exists. However, I’m sure it seemed like a logical decision at the time, and I simply haven’t gone back through all this code to clean it up.

The final line, echo $xmldata;, is used for testing. Usually if I’m coding something like this, I like to simply echo it to the page to see what it’s returning before I move forward. If you run this code, it will display like so, at least echoed to an HTML page in Opera 11:

6406 IVY LNGREENBELTMD207701440

It looks like this because it is not parsing the xml or using any html formatting. If you view source, it looks like this:

<ZipCodeLookupResponse><Address ID=”0”><Address2>6406 IVY LN</Address2><City>GREENBELT</City><State>MD><Zip5>20770</Zip5>

Which is exactly what it should return on a successful test. Perfect!

What next? Well, now we need to parse the xml into something usable. To do that, we need to use the array $contents that the xml has been put in. I didn’t keep the gory details handy of the entire structure of the array, unfortunately, and I CBA to rerun it, but essentially, this is what I did:

if ($values[2][tag] != ‘ERROR’) {
$vAdd1 = $values[2][value];
$vAdd2 = $values[3][value];
$vAdd3 = $values[4][value];
$vAdd4 = $values[5][value];
$vAdd5 = $values[6][value];
}
if (array_key_exists($values[7][value], $values)) {
$vAdd6 = $values[7][value];
}

What the hell is this mess, you ask? Well, one other thing the USPS mentions is that you need error handling, in case the address comes back as invalid. If the address comes back bad, the $values[2][tag] will == ERROR. So if it doesn’t come back with errors, I need to check how many $values came back, as the count will be different depending on whether the address has a suite # or not. If the $values[7] key exists, this becomes the $vAdd6 value, which would be the +4 part of the ZIP. Otherwise, the +4 will be in $values[6]. This may not matter for your application, but it was critical in my case.

The rest of this code block, if the address does come back as bad, simply writes ‘Error. The address could not be verified.’ The full code for this is like so:

if ($values[2][tag] != ‘ERROR’) {
$vAdd1 = $values[2][value];
$vAdd2 = $values[3][value];
$vAdd3 = $values[4][value];
$vAdd4 = $values[5][value];
$vAdd5 = $values[6][value];
if (array_key_exists($values[7][value], $values)) {
$vAdd6 = $values[7][value];
}
$verifiedBlock = ("
<tr><td valign=’top’ style=’color:#000000;background-color:#EBEBEB;text-align:left;font-weight:bold;font-size:14px;’>Verified Address:</td><td style=’color:#000000;background-color:#EBEBEB;font-weight:normal;font-size:14px;’>$uCompany<br />
$vAdd1<br />
$vAdd2<br />
$vAdd3 &nbsp $vAdd4 &nbsp $vAdd5 &nbsp $vAdd6
");
}
else {
$verifiedBlock = ("
<tr><td valign=’top’ style=’color:#000000;background-color:#EBEBEB;text-align:left;font-weight:bold;font-size:14px;’>Verified Address:</td><td style=’color:#000000;background-color:#EBEBEB;font-weight:normal;font-size:14px;’>Error<br />
The address could not be verified<br />
");
};
if (strlen($vAdd5) == 4) {
$vZip5 = $vAdd4;
$vZip4 = $vAdd5;
}
else {
$vZip5 = $vAdd5;
$vZip4 = $vAdd6;
};

The end of this, where I’m checking the length of $vAdd5, is so I can find the ZIP and Zip+4 values. For my purposes, this is the most important part of this whole endeavor.

The $verifiedBlock variable is mostly css styling so I can lay it out properly on the email I receive when the form is submitted. What I’ve done is left the address as provided by the person filling out the form in a block, and the address as returned by the Web Tools API below that. That way, if the address comes back as bad, I have what was originally provided so I can look into what the problem with the address is.

One thing to watch for here once you are live is that the USPS system is picky about how the address is provided. For my part, I am only passing the Address1, Address2, City, & State fields to the API. I’ve noticed in using their web form that providing a wrong ZIP code makes it break. If you don’t pass it, you won’t break it.

 

Leave a Reply

Your email address will not be published.