Saltar al contenido

Forzar desbordamiento de enteros de PHP

Por fin después de mucho luchar hemos dado con la solución de este atasco que muchos lectores de nuestro espacio tienen. Si deseas aportar algún detalle no dejes de aportar tu información.

Solución:

Así que resolví el problema y descubrí mucho sobre PHP (al menos en la forma en que maneja el desbordamiento de enteros).

1) Dependía completamente de un cruce entre la plataforma en la que se ejecutaba la máquina, la versión de PHP, si tenía o no Suhosin Hardened PHP ejecutándose y para cuántos bits se compiló (32 o 64). 6 máquinas se comportaron de la manera que esperaba (que en realidad estaba mal, al menos mal según su documentación) y 3 máquinas se comportaron de una manera que aún no puedo explicar, y 3 máquinas se comportaron de acuerdo con lo que dice el comando intval que hace en el documentación.

2) Se supone que Intval devuelve PHP_INT_MAX cuando int > PHP_INT_MAX (no int & 0xffffffff), pero esto solo ocurre en algunas versiones de PHP4 y PHP5. Diferentes versiones de PHP devuelven valores diferentes cuando int > PHP_INT_MAX.

3) El siguiente código puede devolver 3 resultados diferentes (ver 1):


Puede regresar (lo que parece correcto para Intval pero incorrecto para & 0xffffff)

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

Y puede devolver (lo que contradice la documentación de PHP para intval):

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

Y en máquinas de 64 bits devuelve (lo cual es correcto):

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

Solución

De todos modos, necesitaba una solución que funcionara en todas estas plataformas y que no dependiera de las peculiaridades de una versión particular de PHP compilada con un Max int particular. Por lo tanto, se me ocurrió la siguiente función de PHP cruzado ThirtyTwoBitIntval:

function thirtyTwoBitIntval($value)

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

Comentario

Creo que los diseñadores de PHP deberían haber dicho que un Int es un Int de 32 bits, sin importar si se ejecuta en una máquina de 32, 64 o 128 bits (como DotNet CLR, por ejemplo), y no lo convirtieron aleatoriamente a un flotar dependiendo de la cantidad de Bits en los que se compila PHP.

Si desea tener una solución que funcione al 100% para intervalos de 32 bits en plataformas de 32 y 64 bits, le sugiero que utilice la siguiente solución:

function intval32bits($value)

    $value = ($value & 0xFFFFFFFF);

    if ($value & 0x80000000)
        $value = -((~$value & 0xFFFFFFFF) + 1);

    return $value;

Internamente, PHP usa un tipo “entero” para la mayoría de los números. Sin embargo, esto solo llega hasta cierto punto: si agrega un número entero grande a un número entero grande, PHP verá que el resultado es demasiado grande para caber en un número entero normal y lo asignará a un número de coma flotante. Sin embargo, los números de coma flotante (flotantes) en sí mismos solo llegan hasta cierto punto, y hay un punto alrededor de la marca de dieciséis dígitos en el que PHP simplemente perderá la trama por completo.

Hay una opción para usar matemáticas de precisión arbitraria que admite números de cualquier tamaño y precisión, representados como cadenas. Ver más aquí: http://us2.php.net/bc

Si para ti ha sido de utilidad nuestro artículo, agradeceríamos que lo compartas con otros programadores y nos ayudes a dar difusión a este contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 5 Promedio: 4)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *