Mathematics7 min readExamples run on PHP 8.5.10

base_convert()

Learn how PHP 8.4 base_convert() converts number strings between bases 2 and 36, with examples, precision limits, invalid-character behavior and mistakes to avoid.

Signature

base_convert(string $num, int $from_base, int $to_base): string

Purpose

base_convert() takes a number written as a string in one base and returns the same number written as a string in another base. Both bases must be between 2 and 36. That range covers binary, octal, decimal and hexadecimal, plus "base 36", which uses the digits 0-9 and the letters a-z.

Typical uses are showing a value in binary for debugging, turning hexadecimal into decimal, or building short identifiers from a decimal counter. The function works on text, not on PHP integer literals. 'ff' is a string of digits to interpret, not a hex literal.

Signature

Parameters

  • $num: the number to convert, as a string. For bases above 10, the letters a to z stand for the values 10 to 35. Letters are read case-insensitively, so FF and ff are the same number.
  • $from_base: the base that $num is written in. There is no default. It must be from 2 to 36.
  • $to_base: the base to convert into. There is no default. It must be from 2 to 36.

All three arguments are required.

Return value and failure cases

The function returns a string. Letter digits in the result are always lowercase, and the result has no leading zeros. If you need fixed-width output such as 8-bit binary, pad it yourself with str_pad().

The manual says that characters not valid for $from_base are silently ignored in the calculation, and that since PHP 7.4 supplying them is deprecated. The result is still computed as if those characters were not there. In practice this means '1g' read as hexadecimal quietly loses the g and a deprecation notice is raised. Characters such as a minus sign, a decimal point, spaces or separators are invalid digits too. Validate input first if it comes from users.

In PHP 8, a base outside 2 to 36 is rejected with a ValueError, so a bad base is a programming error you should not rely on handling at runtime.

Example 1: hexadecimal to binary

The first example is the classic one from the manual: each hex digit expands to four binary digits.

Example
<?php
$hexadecimal = 'a37334';
echo base_convert($hexadecimal, 16, 2), "\n";
Output
101000110111001100110100

Example 2: several conversions

This example shows decimal to hex, uppercase input, base 36, and octal to binary. Note that every returned value is a string, even when it looks like a decimal number.

Example
<?php
$results = [
    'hex' => base_convert('255', 10, 16),
    'upper_input' => base_convert('FF', 16, 10),
    'base36' => base_convert('zz', 36, 10),
    'octal_to_binary' => base_convert('777', 8, 2),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"hex":"ff","upper_input":"255","base36":"1295","octal_to_binary":"111111111"}

Example 3: validating before converting

Because invalid characters are not reported as errors, a small wrapper can make conversion stricter. It checks the bases, lowercases the text, and uses strspn() to confirm that every character is a legal digit for the source base.

Example
<?php
function safeConvert(string $num, int $from, int $to): ?string
{
    if ($from < 2 || $from > 36 || $to < 2 || $to > 36) {
        return null;
    }
    $digits = substr('0123456789abcdefghijklmnopqrstuvwxyz', 0, $from);
    $clean = strtolower($num);
    if ($clean === '' || strspn($clean, $digits) !== strlen($clean)) {
        return null;
    }
    return base_convert($clean, $from, $to);
}

echo json_encode([
    safeConvert('ff', 16, 10),
    safeConvert('fg', 16, 10),
    safeConvert('101', 2, 10),
    safeConvert('12', 2, 10),
    safeConvert('10', 1, 10),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["255",null,"5",null,null]

Edge cases

  • Large numbers: the manual warns that precision can be lost, because the conversion relies on PHP's internal float type. A long string of digits may produce a wrong result without any error. For exact big-number work, use an arbitrary-precision approach instead.
  • Leading zeros: they are not kept. Converting '000ff' from base 16 gives the same result as 'ff'.
  • Strings, not integers: you can pass an integer such as 255 for $num when strict types are off, but it is converted to the string '255' first, so the digits must make sense in $from_base. Prefer passing explicit strings.
  • Negative and fractional numbers: a leading minus sign or decimal point is not a valid digit, so the function does not handle signs or fractions meaningfully.

Common mistakes

  1. Treating the result as a number. The result is a string. Comparing base_convert('10', 2, 10) === 2 is false because the result is '2'.
  2. Trusting invalid input. Since bad characters are skipped, user input like '12' as binary does not fail loudly. Validate first, as in the third example.
  3. Forgetting padding. base_convert('5', 10, 2) gives 101, not 00000101.
  4. Using it for huge values. Long hashes or big identifiers can exceed float precision and silently corrupt.
  5. Passing the bases in the wrong order. The source base comes first, then the target base.
  • bindec(), decbin(), hexdec(), dechex(), octdec() and decoct() are fixed-base helpers for common conversions.
  • intval() can parse a string in a given base into an integer, and is listed by the manual as a related function.
  • str_pad() helps format fixed-width results.

Recap

base_convert() converts a digit string between bases 2 and 36 and returns a lowercase string without leading zeros. Letters are case-insensitive on input. Invalid characters are ignored with a deprecation notice rather than treated as hard errors, bases outside the range raise a ValueError in PHP 8, and large values can lose precision. Validate input, keep the result as a string, and pad when you need a fixed width.

Tested examples

Hexadecimal to binary
<?php
$hexadecimal = 'a37334';
echo base_convert($hexadecimal, 16, 2), "\n";
Output
101000110111001100110100
Several conversions
<?php
$results = [
    'hex' => base_convert('255', 10, 16),
    'upper_input' => base_convert('FF', 16, 10),
    'base36' => base_convert('zz', 36, 10),
    'octal_to_binary' => base_convert('777', 8, 2),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"hex":"ff","upper_input":"255","base36":"1295","octal_to_binary":"111111111"}
Validating before converting
<?php
function safeConvert(string $num, int $from, int $to): ?string
{
    if ($from < 2 || $from > 36 || $to < 2 || $to > 36) {
        return null;
    }
    $digits = substr('0123456789abcdefghijklmnopqrstuvwxyz', 0, $from);
    $clean = strtolower($num);
    if ($clean === '' || strspn($clean, $digits) !== strlen($clean)) {
        return null;
    }
    return base_convert($clean, $from, $to);
}

echo json_encode([
    safeConvert('ff', 16, 10),
    safeConvert('fg', 16, 10),
    safeConvert('101', 2, 10),
    safeConvert('12', 2, 10),
    safeConvert('10', 1, 10),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["255",null,"5",null,null]