PHP: Salesforce Conversion to 18 Character from 15 Character Id

Problem

If you run reports in Salesforce you can only see a 15 character Id field.  If you request a dump or access the API with case insensitive Id fields enabled you see an 18 character Id.  Obviously, you may be doing both and need to correlate the Id fields.
Salesforce Id fields are 15 character base62 encoded case sensitive strings.  SQL databases such as MySQL and Microsoft SQL as well as many applications such as Microsoft Excel treat primary keys as case insensitive.  To overcome this limitation Salesforce appends a 3 character checksum-like sequence which is designed to make the string case insensitive.

Solution

<?php
/**
 * Salesforce Validation and Conversion
 * 
 * Function for converting or verifying a salesforce Id. 
 *      Salesforce Id fields are case sensitive.  
 *      SQL databases are case insensitive by default such as MySQL or MS SQL.
 *      Salesforce adds a 3 character checksum which also makes the string case insensitive.
 *      The Id is 15 characters and optional checksum is 3 characters.
 * @author David L Norris
 * @version 1.0
 * @package salesforce_hacks
 */
 
 
/* list of sample keys with one bad entry */
$list = array(
    "00130000004EQCnAA1",
    "00130000004EQCpAAO",
    "00130000004EQCqAAO",
    "00130000004EQRvAAO",
    "00130000004EpE4AAK",
);
 
/* loop through the list */
foreach( $list as $val ){
    try {
        $id = validSalesforceId( $val );
        print "$id should match $val<br>";
    }
    catch(Exception $e){
        print "Caught Error: " . $e->getMessage() . "<br>";
    }
}
 
 
/**
 * generate 18 character Id from 15 character Id or verify checksum of 18 character Id
 * @param string $salesforceId salesforce Id from dump or report
 * @return string
 */ 
function  validSalesforceId( $salesforceId ){
    /*  http://forceguru.blogspot.com/2010/12/how-salesforce-18-digit-id-is.html
     *  Generate a 18 digit case-insensitive id from a 15 digit case sensitive id
     */
        /* map of characters to be used for in checksum */
        $map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345';
        $checksum = '';
 
        /* verify the checksum on 18 digit IDs */
        switch( strlen($salesforceId) ){
                case 18: // validate checksum, this can help you detect mangled case but is not foolproof.
                        $input = $salesforceId;
                        $salesforceId = substr( $input, 0, 15 );
                        break;
                case 15:
                        // generate checksum
                        $input = false;
                        break;
                default:
                        // throw an error
                        throw new Exception( 'Wrong length for ' . $salesforceId . '. Expected 15 or 18 characters' );
        }
 
        /* split into the 3 extra characters */ 
        $chunks = str_split($salesforceId, 5);
        /* for each of the 3 characters */
        foreach ($chunks as $chunk) {
                /* place each character into an array */
                $chars = str_split($chunk, 1);
                $bits = ''; // reset the value
                /* for each character */
                foreach ($chars as $char) {
                        /* replace upper case characters with a 1 and lower case with a 0 */
                        $bits .= (!is_numeric($char) &amp;&amp; $char == strtoupper($char)) ? '1' : '0';
                }
 
                /* convert from big endian binary to decimal 
                 * append the character in that position of the map to the checksum 
                 */
                $checksum .= substr($map, bindec( strrev($bits) ), 1);
        }
 
        /* if we were given a 18 digit id then verify the checksum */
        if( $input &amp;&amp; ($salesforceId.$checksum != $input) ){
                throw new Exception( 'Checksum mismatch for ' . $input . '.  Expected ' . $salesforceId.$checksum . '.' );
        }
 
        return $salesforceId . $checksum;
}
 
---