Force PHP Integer Overflow

Force PHP integer overflow

So I solved the problem, and discovered a lot about PHP (at least in the way it handles Integer overflow).

1) It completely depended on a cross between which platform the machine was running on, which version of PHP, whether or not it had Suhosin Hardened PHP running, and how many bits it was compiled for (32 or 64). 6 machines behaved the way I expected (which was actually wrong, at least wrong according to their documentation) and 3 machines behaved in a way I still can't explain, and 3 machines behaved according to what the intval command says it does in the documentation.

2) Intval is supposed to return PHP_INT_MAX when int > PHP_INT_MAX (not int & 0xffffffff), but this only happens on some versions of PHP4 and PHP5. Different versions of PHP return different values when int > PHP_INT_MAX.

3) The following code can return 3 different results (see 1):

<?php
echo "Php max int: ".PHP_INT_MAX."\n";
echo "The Val: ".(-1580033017 + -2072974554)."\n";
echo "Intval of the val: ".intval(-3653007571)."\n";
echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."\n";
?>

It can return (which appears to be right for Intval but wrong for & 0xffffff)

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -2147483648
And of the val: -2147483648

And it can return (which contradicts the PHP documentation for intval):

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -641959725
And of the val: -641959725

And on 64 Bit machines it returns (which is correct):

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -3653007571
And of the val: -641959725

Solution

Anyhow, I needed a solution that would work on all these platforms, and not be dependent upon quirks of a particular version of PHP compiled with a particular Max int. Thus I cam up with the following cross-PHP thirtyTwoBitIntval function:

function thirtyTwoBitIntval($value)
{
if ($value < -2147483648)
{
return -(-($value) & 0xffffffff);
}
elseif ($value > 2147483647)
{
return ($value & 0xffffffff);
}
return $value;
}

Comment

I do think the designers of PHP should have said an Int is a 32 Bit Int no matter whether it is running on a 32 or 64 or 128 bit machine (like the DotNet CLR for example), and didn't randomly upconvert it to a float depending on the number of Bits that PHP is compiler under.

Testing integer overflow in PHP

Use the PHP_INT_MAX constant:

$this->assertEquals( PHP_INT_MAX, $text );

This will fix your problem, AND make your test more portable (e.g. it will work on 32bit systems too).

PHP_INT_MAX's value is the larger representable int by your PHP build.

See http://php.net/manual/en/reserved.constants.php

PHP: how to force property of method to be integer?

You can't force strict types in function prototypes in PHP inherently, because it's not a strictly typed language. PHP is a weakly typed language and trying to go against the grain will only hurt you in many situations. Also, is_numeric does not guarantee that your value is of type int (for what it's worth).

What you can do is analyze your need for why you think this approach is necessary in the first place and decide on how to best implement this without creating potential for bugs.

For example, take the following scenario where what your method expects is an ID for a database query.

class MyClass {
public function getUser($id) {
if (!is_int($id)) {
throw new Exception("Invalid argument supplied. Expecting (int), but argument is of type (" . gettype($id) . ").");
}
// Otherwise continue
$db = new PDO($dsn);
$stmt = $db->prepare("SELECT username FROM users WHERE user_id = ?");
$stmt->execute(array($id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}

$MyObject = new MyClass;
$result = $MyObject->getUser($_POST['id']);
/* The problem here is $_POST will always be of type string. */

What this should tell you is that it makes no sense to force type checking here since PHP will have done the right thing for you had you just let it alone.

The question you need to be asking yourself is not "How do I force strict typing?", but rather "Why would I need to force strict typing at all?".

PHP - Force integer conversion to float with three decimals

Try using sprintf()

$numbers2[] = sprintf("%+07.3f", $fnum);

How to force arguments to be integer/string

Scalar TypeHints are available as of PHP 7:

Scalar type declarations come in two flavours: coercive (default) and strict. The following types for parameters can now be enforced (either coercively or strictly): strings (string), integers (int), floating-point numbers (float), and booleans (bool). They augment the other types introduced in PHP 5: class names, interfaces, array and callable.

There is no Type Hints for scalars before PHP7. PHP 5.3.99 did have scalar typehints but it wasn't finalised at that point if they stay and how they will work then.

Nevertheless, there is options for enforcing scalar arguments before PHP7.

There is a couple of is_* functions that let you do that, e.g.

  • is_int — Find whether the type of a variable is integer
  • is_string — Find whether the type of a variable is string
  • more

To raise a Warning, you'd use

  • trigger_error — Generates a user-level error/warning/notice message

with an E_USER_WARNING for $errorType.

Example

function setInteger($integer)
{
if (FALSE === is_int($integer)) {
trigger_error('setInteger expected Argument 1 to be Integer', E_USER_WARNING);
}
// do something with $integer
}

Alternative

If you want to use Scalar Type Hints desperately, have a look at

  • http://edorian.github.io/2010-03-30-typehints-hack-for-literal-values-in-php/

which shows a technique for enforcing scalar typehints via a custom Error Handler.

PHP String-to-Integer Exception

And here's another hacky solution using the try {..} catch mechanism:

try {
new ReflectionClass('ReflectionClass' . ((int)$SS . "" !== $SS));
echo $SS;
} catch (Exception $e) {
echo "Bad StringBad String";
}

It works like this: if the string $SS doesn't actually resolve to an integer, the code will try to lookup the ReflectionClass1 class, which, in the end, will throw a ReflectionException.

The parsing works by simply casting $SS to int and then back to string and comparing it to the initial value.



Related Topics



Leave a reply



Submit