Tony Marston's Blog About software development, PHP and OOP

A Binary-Octal-Decimal-Hexadecimal-Base36 converter

Posted on 13th June 2003 by Tony Marston

Amended on 7th April 2004

Intended Audience
Prerequisites
The Converter form
The Converter code
- Input-Output operations
- Decimal to String conversion
- String to Decimal conversion
Summary
Amendment History
Comments

Intended Audience

This tutorial is intended for developers who wish to have a utility which will quickly enable them to convert values from one number format to another. Although PHP has a series of standard functions to convert values between decimal (base 10) and binary (base 2), octal (base 8) and hexadecimal (base 16) and back again, this tutorial will show you how to build a single routine that can process other number systems such as Base 36.

Prerequisites

Access to a working PHP development environment. No special modules are required as this script uses only standard PHP functions. A basic knowledge of PHP and HTML is assumed. This exercise will help you construct a PHP script with the following characteristics:

The Converter form

The finished script will produce a form that looks like the following in your browser:

converter (14K)

To convert from decimal to another format do the following:

To convert from another format to decimal do the following:

You can run the program from here and view the complete source code from here.

The Converter code

In the following code snippets I shall ignore most of the HTML code as it should be self-explanatory. I will however give explanations for each piece of PHP code.

Input-Output operations

This first piece of code looks for input. When the program is first requested from a browser it is done using the GET method, so the POST array will be empty. Notice here that we are using the RESET button to clear all input.

// look for no POST entries, or the RESET button 
if (count($_POST) == 0 or isset($_POST['reset'])) { 
    // POST array is empty - set initial values 
    $dec_input   = null; 
    $dec_output  = null; 
    $base2value  = null; 
    $base8value  = null; 
    $base16value = null; 
    $base36value = null; 
} else { 
    // retrieve values from POST array 
    $dec_input   = &$_POST['dec_input']; 
    $dec_output  = null; 
    $base2value  = &$_POST['base2value']; 
    $base8value  = &$_POST['base8value']; 
    $base16value = &$_POST['base16value']; 
    $base36value = &$_POST['base36value']; 
} // if 

The & character is used in front of $_POST to pass the value by reference instead of making a copy of that value. This also prevents the generation of a warning message if the value does not actually exist is the POST array.

This next section of code will look for a submit button to convert from decimal to one of the other formats. Notice that we are not using any of PHP's standard functions to perform this conversion, we are using a home-made routine which is described here.

if (isset($_POST['dec-2-bin'])) { 
    $base2value = dec2string($dec_input, 2); 
} // if 
if (isset($_POST['dec-2-oct'])) { 
    $base8value = dec2string($dec_input, 8); 
} // if 
if (isset($_POST['dec-2-hex'])) { 
    $base16value = dec2string($dec_input, 16); 
} // if 
if (isset($_POST['dec-2-b36'])) { 
    $base36value = dec2string($dec_input, 36); 
} // if 

This next section of code will look for a submit button to convert into decimal from one of the other formats. Notice that we are not using any of PHP's standard functions to perform this conversion, we are using a home-made routine which is described here.

if (isset($_POST['bin-2-dec'])) { 
    $dec_output = string2dec($base2value, 2); 
    if ($error) { 
       $error['base2value'] = $error[0]; 
    } // if 
} // if 
if (isset($_POST['oct-2-dec'])) { 
    $dec_output = string2dec($base8value, 8); 
    if ($error) { 
       $error['base8value'] = $error[0]; 
    } // if 
} // if 
if (isset($_POST['hex-2-dec'])) { 
    $dec_output = string2dec($base16value, 16); 
    if ($error) { 
       $error['base16value'] = $error[0]; 
    } // if 
} // if 
if (isset($_POST['b36-2-dec'])) { 
    $dec_output = string2dec($base36value, 36); 
    if ($error) { 
       $error['base36value'] = $error[0]; 
    } // if 
} // if 

This next piece of code is a method of quickly incrementing or decrementing the decimal input.

if (isset($_POST['plus1'])) { 
   $dec_input = $dec_input +1; 
} // if 
if (isset($_POST['minus1'])) { 
   $dec_input = $dec_input -1; 
} // if 

Now we come to actually constructing the HTML output. We start with the form tag which tells the browser to call itself using the POST method when one of the buttons is pressed.

<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST"> 

For each line on the screen we need to supply a label, a text box which contains the current value (which may be empty), and we must also look for the possibility of an error message to be displayed for this field. Note here that <?= is just a shorthand version of <?php echo.

    <td>Decimal (input)</td> 
    <td><input type="text" name="dec_input" value="<?= $dec_input ?>" /> 
    <?php
    if (array_key_exists('dec_input', $error)) { 
        echo '<p class="error">' .$error['dec_input'] .'</p>'; 
    } // if 
    ?>
    </td>

I shall not bother with all the other input fields as the code is very similar. You can view the complete source here.

Decimal to String conversion

This routine will convert a decimal number (base 10) into a number with a different base. First we assign the global area to hold any error message and initialise the output.

function dec2string ($decimal, $base) 
{
    global $error; 
    $string = null; 

The next step is to make sure that the base number is valid. Note that this value can be any number between 2 and 36.

    $base = (int)$base; 
    if ($base < 2 | $base > 36 | $base == 10) { 
       echo 'BASE must be in the range 2-9 or 11-36'; 
       exit; 
    } // if; 

Next we set up the list of possible output characters, then chop off any characters beyond the limit specified by $base.

    $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $charset = substr($charset, 0, $base); 

Here we are checking that the input value is acceptable - a positive integer between 1 and 16 digits long.

    if (!ereg('(^[0-9]{1,16}$)', trim($decimal))) { 
       $error['dec_input'] = 'Value must be a positive integer'; 
       return false; 
    } // if
    $decimal = (int)$decimal;  

Here we are starting what is known as a do loop.

    do {

Step 1 inside the loop is to get the remainder after dividing $decimal by $base.

       $remainder = ($decimal % $base); 

Step 2 is to extract the character that corresponds to this remainder and add it to the front of the output string.

       $char   = substr($charset, $remainder, 1); 
       $string = "$char$string"; 

Step 3 is to reduce the decimal value by the number we have just processed. This is done by subtracting $remainder then dividing by $base.

       $decimal   = ($decimal - $remainder) / $base; 

This terminates the do loop when the input value has been reduced to zero.

    } while ($decimal > 0); 

The function ends by passing back the completed string value to the calling process.

    return $string; 

} // dec2string 

String to Decimal conversion

This routine will convert a number in base X to a decimal number. First we assign the global area to hold any error message and initialise the output.

function string2dec ($string, $base) 
{ 
    global $error; 
    $decimal = 0; 

The next step is to make sure that the base number is valid. Note that this value can be any number between 2 and 36.

    $base = (int)$base; 
    if ($base < 2 | $base > 36 | $base == 10) { 
       echo 'BASE must be in the range 2-9 or 11-36'; 
       exit; 
    } // if; 

Next we set up the list of possible output characters, then chop off any characters beyond the limit specified by $base.

    $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $charset = substr($charset, 0, $base); 

Here we are just checking that the input string is not empty.

    $string = trim($string);
    if (empty($string) { 
       $error[] = 'Input string is empty'; 
       return false; 
    } // if 

Here we start a do loop to process every character in the input string.

    do {

Next we extract the first character from the input string, then remove it from the string.

       $char   = substr($string, 0, 1); 
       $string = substr($string, 1); 

Here we obtain the position of $char in $charset.

       $pos = strpos($charset, $char); 
       if ($pos === false) { 
          $error[] = "Illegal character ($char) in INPUT string"; 
          return false; 
       } // if 

Here we increment the decimal value by the value of the character we have just extracted from the input string.

       $decimal = ($decimal * $base) + $pos; 

Finally we can terminate the do loop and return the decimal value to the calling process.

    } while($string <> null); 
 
    return $decimal; 
     
} // string2dec 

Summary

This may be a simple PHP script, but as well as a training exercise it produces a function which you may find useful some day.


Amendment history:

7th April 2004 Switched to BCMATH functions in order to deal with numbers greater than a 32 bit integer.

counter