Type juggling is an expected functionality of PHP when leveraging loose comparisons. However, it can be used to subvert intended operations. In this blog, we will discuss why type juggling occurs, what are the potential impacts, and why we should use strict comparisons when developing applications in PHP.

Equal vs Identical

In PHP, there is a big difference between “==” (Equal or called “Loose Comparison”) and “===” (Identical or called “Strict Comparisons”). Equal will check to see if the variables are equal to each other after type juggling occurs. Identical checks to see if the variables are equal and are the same type.

Example of Loose Comparison

php > var_dump(‘0’ == 0);
bool(true)
Notes: This is true because type juggling changed the string 0 to the integer of zero and they are equal.

Example of Strict Comparison

php > var_dump(‘0’ === 0);
bool(false)
Notes: This is false because they have two different types. One is a string and one being an integer. That means it will not be identical or it is false.

Types

String

Any string of characters, specified by single quotes, double quotes, heredoc syntax, or nowdoc syntax.

  • single quote:
    $string = ‘This is the string’
  • double quote:
    $string = “This is the string”
  • heredoc syntax:
    $string = <<<EOT
    This is the string
    EOT;
  • nowdoc syntax:
    $string = <<<‘EOT’
    This is the string
    EOT;

Integer

An integer is a number on the number line (-2, -1, 0, 1, 2,). They can be decimal, octal, hexadecimal, binary, or _ decimal (as of PHP 7.4.0) numbers.

Float

Floats or “real numbers” are numbers with the below syn taxes
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // as of PHP 7.4.0

PHP Type Juggling

PHP does not support explicit type definition in variable declarations. This means that type is decided based on the context in which the variable is used.

  $foo = "1"; // $foo is string (ASCII 49)

  $foo *= 2; // $foo is now an integer (2)

  $foo = $foo * 1.3; // $foo is now a float (2.6)

  $foo = 5 * "10 Little Piggies"; // $foo is integer (50)

  $foo = 5 * "10 Small Pigs"; // $foo is integer (50)

Magic Hash

“e” is a numerical constant and when you have a hash like 1e1 this would equal 10 or 1 and 1 zero. Likewise, if you had a 5e10, it would be a 5 and 10 zeros.

php> var_dump(5e10 == 50000000000);
bool(true)
Notes: with type juggling we are assuming that the hash or string is represented as a string, however in PHP the type is determined by the context in which the variable is used.

php> var_dump(‘5e10qwe’ == 50000000000);
bool(true)
php > var_dump(‘5e10qwe’ == ‘50000000000’);
bool(false)

As we can see when the string is compared with an integer the string is treated as an integer. This means that if a hash starts with 0e123 it will = 0.

Note: This will more likely happen in MD5 and SHA1 hash values.

 

References

https://www.php.net/manual/en/language.types.type-juggling.php

https://www.php.net/manual/en/language.types.string.php

https://www.php.net/manual/en/language.types.integer.php

https://www.php.net/manual/en/language.types.float.php

https://owasp.org/www-pdf-archive/PHPMagicTricks-TypeJuggling.pdf