Introducción
¿Cómo hacer para estar seguro de que un parámetro obtenido por GET (o POST) es un número entero?
Intentando resolver esta pregunta he intentado varias técnicas a lo largo del tiempo, y haciendo esas pruebas he llegado a entender más sobre cómo funcionan las comparaciones y las conversiones automáticas de tipos en PHP.
Lo primero que hay que considerar es que no sirve usar una conversión directa con (int), o intval(), ya que si bien estaría seguro de que el valor obtenido es entero, eso no quiere decir que sea un valor válido, ya que cualquier cadena puede convertirse a entero (si no comienza con números, su valor es cero). Ante la duda, nada mejor que consultar la página sobre manipulación de tipos del manual de PHP.
Primer intento: is_int
La primera idea es comprobar con la función is_int.
Sin embargo, esto no funciona, porque PHP considera cadenas a estas variables.
¿Cómo lo sé? Por 2 motivos:
- La propia página del manual lo advierte: "Para probar si una variable es un número o una cadena numérica (como en el caso de la entrada de un formulario, que es siempre una cadena), debe usar is_numeric()".
gettype($_GET['uno']);
Devuelve "string", aunque el valor de $_GET['uno'] sea 12, por ejemplo.
is_int($_GET['uno']);
Devuelve false, en el mismo caso que el anterior.
Segundo intento: is_numeric
is_numeric serviría, excepto porque también acepta números con coma (punto, en realidad). De nuevo, podríamos simplemente convertirlo a entero con (int), pero no sería el valor original y por lo tanto no sería un valor válido.
Tercer intento: comparación con entero
Otra opción puede ser hacer una comparación como
$_GET['var'] == (int) $_GET['var'];
En teoría funcionaría, pero no es así.
PHP es un tanto "especial" en lo que refiere a las conversiones de tipos: siempre que haya un entero en un lado de la comparación, convertirá el otro lado en entero.
Por lo tanto, la comparación SIEMPRE será cierta, ya que el lado izquierdo de la comparación será convertido también, resultando en lo mismo que si escribiese
(int) $_GET['var'] == (int) $_GET['var'];
Cuarto intento: comparación de idénticos
Bueno, si PHP convierte a entero ambos lados y por eso no sirve el ejemplo anterior, bastaría con usar el comparador ===, ¿no?
¡NO! Porque siempre serán de tipos diferentes, ya que como se dijo antes, las variables GET son tomadas como cadenas.
Quinto intento: complicado pero funciona
Finalmente decidí ir por algo más complejo pero que evita todos los problemas de los casos anteriores.
¿Qué hacer? La comparación con un entero es necesaria, porque después de todo lo que necesitamos es un entero, pero no podemos comparar una cadena con un entero porque la cadena será convertida…
La solución que se me ocurrió es simplemente volver a convertir al entero en una cadena:
$_GET['var'] == (string) intval($_GET['var']);
Luego de mucho experimentar, la anterior es la mejor solución que he encontrado.
Por ejemplo, si $_GET['var'] tiene el valor "12", el proceso sería:
intval("12") # --> entero 12
(string) intval("12") # --> cadena "12"
"12" == "12" # --> verdadero, contienen el mismo valor.
Si ahora $_GET['var'] tiene el valor "hola":
intval("hola") # --> entero 0
(string) intval("hola") # --> cadena "0"
"12" == "0" # --> falso, la cadena pasada no es un entero.
Y finalmente, el caso que hace que las conversiones fallen: una cadena con valores numéricos y letras. Supongamos que $_GET['var'] tiene el valor "12hola".
intval("12hola") # --> entero 12
(string) intval("12hola") # --> cadena "12"
"12hola" == "12" # --> falso. Al evitar la conversión automática, no hay problemas.
De todas formas me gustaría saber si por ahí existe una solución mejor.











23/11/2008, a las 22:50
Muy bueno el articulo che.
Igual en todos los casos yo prefiero las expresiones regulares, que obvio son mas lentas…pero en algunos casos te salvan la vida ya que son mas seguras a la quinta pata al gato.
if(eregi("^[0-9]+$",$_GET['var']))
{
}
23/11/2008, a las 22:53
Lo que quiero decir, si son cadenas, tratemoslo como cadenas, pero comparemos con enteros y flotantes…
perdon que no termine de copiar el codigo
if(eregi("^[0-9]+$",$_GET['var']))
{
echo "Es un entero";
}
El cast es malo porque al castearlo a int ya no me sirve siempre dara por verdadero el is_integer,is_int
jeje.
Saludos muy buena tu solucion.
23/11/2008, a las 23:21
Te agradezco el comentario y la sugerencia.
Queda claro que hay muchas formas de hacer esto, creo que cada uno termina haciendo la que le quede más cómoda.
Quiero dejar claro que esta es una función de comparación, no de obtención del valor numérico. Siendo así, no se modifica el valor original y por tanto podés usar cualquier función que sea necesaria.
Le agregué un ejemplo para explicar mejor cómo funciona.