Desarrollo

Cómo validar datos de un formulario en PHP – funciones básicas

Desarrollo HTML PHP

Validar datos de un formulario es fundamental, por muchos motivos. Aparte de por seguridad como vimos en el anterior artículo, también para hacer un filtro importante sobre los datos que recibimos. Gracias a ello, podremos validar datos de un formulario y evitar posibles errores en cuanto a tipos de datos o también errores más difíciles de detectar mientras se programa, como por ejemplo recibir un dato que no es válido.

Por ejemplo, imaginemos que tenemos un formulario en el que solicitamos la edad mediante un <input> de tipo number. El <input> ya cogerá únicamente números, pero puede contener números negativos. O, imaginemos, solo queremos a mayores de edad. ¿Cómo hacemos para que nadie pueda introducir un 17? Gracias a validar datos de un formulario podremos hacerlo.

Antes de nada, ¿tiene permisos?

Antes de comenzar a ver funciones para validar datos de un formulario, lo primero que debéis pensar es, ¿quien sea que esté ejecutando este archivo PHP tiene permisos para realizarlo? Es decir, la primera validación debe venir por ahí, y aunque es un tema más para desarrollar cada uno por su cuenta, debe ser el principal.

Pensad en acciones que realizan formularios cuyos usuarios están conectados a la página. O algunos usuarios que han pagado una cuota o un servicio. Siempre que tengamos un caso así (es decir, no estemos en un formulario “público” por así decirlo), lo más necesario es validar que ese usuario tiene permisos para hacer lo que hace. Si no, podemos arrepentirnos después.

Utilizando funciones predefinidas para validar datos de un formulario

En este primer artículo sobre validar datos de un formulario nos vamos a dedicar, únicamente, a ver funciones ya predefinidas en PHP que podemos utilizar a voluntad. El próximo artículo lo dedicaremos a construir algunas funciones útiles para ampliar y facilitar las validaciones.

Así pues, vamos a empezar viendo funciones predefinidas muy útiles para los intereses que tengamos en cada momento. Algunas de estas funciones las vimos cuando hablamos de las funciones predefinidas en PHP, pero no está mal recordarlas ahora y ampliarlas en algunos casos.

is_numeric

Esta función comprueba si una variable es un número o un string que representa a un número. Es decir, para esta función el número 1234 es numérico al igual que el string “1234” también es numérico. Sin embargo, el string “1234a” devolvería false y, por tanto, no se considera numérico, como es evidente.

De igual forma, esta función también contabiliza como numéricos aquellos números que, en su momento, vimos que también se podían escribir como hexadecimales y binarios.

is_int

La función anterior está muy bien porque permite evaluar si una cadena numérica es un número. La función actual, is_int, evalúa únicamente si los datos proporcionados son de tipo entero. Es decir, que esta función devolverá true si le pasamos el número 1234, pero devolverá false si le pasamos “1234” o 1234.0 que es un número decimal. Además, hay que tener en cuenta la limitación. Un número extremadamente grande y que supere la capacidad de los enteros en PHP dará false con este método Esta función tiene una que es equivalente llamada is_integer.

Atención
Un formulario de HTML envía los datos siempre como strings, por tanto hay que tener cuidado en utilizar is_int para validar si un dato recibido desde un formulario es un número, pues nunca será cierto aunque le pasemos “realmente” un número. El formulario lo interpreta como string, por lo que deberíamos, o transformarlo antes a entero, o utilizar la función is_numeric.

is_float

Comprendida la función anterior, en este caso tenemos la función que se encarga de comprobar si el valor que se le pasa es un número decimal. En este caso, tiene dos funciones equivalentes llamadas is_double y también is_real (declarado obsoleto en las últimas versiones de PHP).

is_bool

Comprueba que el valor que se le indique es booleano, es decir, si es true o false únicamente.

is_string

También muy sencilla, pues nos dice si la variable es un string o no.

Trabajar con arrays

Vimos cómo trabajar con arrays y, viendo funciones predefinidas, también algunas funciones que trabajan con arrays y que nos podían ser útiles para validar datos de un formulario. Vamos a repasar unas pocas de ellas más útiles para esta validación.

is_array

Al hilo de las anteriores funciones, con esta función podemos comprobar si lo que nos indican se corresponde con un array.

array_key_exists

Muy útil para comprobar si un índice dado existe en realidad en un array concretado. De esta forma, evitaremos errores de intentar acceder a un elemento que no existe.

Comprobar la existencia

Cuántas veces, empezando a programar especialmente, nos habremos encontrado con el típico error de que una variable no existe y nuestro programa haya dispuesto un error por ese motivo. Por ello, comprobar que una variable existe es, prácticamente, la primera validación que se debe hacer cuando se va a utilizar un valor recibido por un formulario.

empty

Esta función ya la vimos y es la que se encarga de determinar si una variable está vacía o no. Pero, cuidado con esta función si queremos hacer validaciones con ella, pues debemos recordar que, para esta función, el valor 0, la cadena vacía “” o un array vacío son situaciones en las que una variable está vacía, y puede no ser así.

Habrá situaciones donde, realmente, el valor 0 será un valor útil en nuestros programas, o una cadena vacía indicará que sí hay algo y podremos seguir. Por tanto, cuidado con empty en estas situaciones, pues normalmente se utiliza más la siguiente función.

isset

Esta función es la que veréis mucho si veis ejemplos de cómo recoger valores desde un formulario, pues es la más utilizada y la que aparece prácticamente al principio cuando se ha recogido el valor. Determina si una variable está definida y no es null (veremos qué es null dentro de pocos artículos).

Así pues, una variable que contenga un 0 o un string vacío serán variables definidas y, por tanto, isset nos devolverá true. Y es que, si un usuario nos dice que tiene 0 en algo, debemos pensar que es un valor válido en muchas situaciones.

Comprobar el tipo de caracteres

En ocasiones lo que más nos va a preocupar es si todos los caracteres recibidos son de un tipo u otro. Para ello, existen las funciones ctype_ que realizan todas estas comprobaciones. Vamos a repasarlas rápidamente, pues son muy simples:

  • ctype_alnum comprueba que todos los caracteres sean alfanuméricos. Así, un string “dia24horas” es alfanumérico pero “¡dia24horas!” no lo es
  • ctype_alpha comprueba, por su parte, que todos los caracteres sean alfabéticos. Por ello, el ejemplo anterior “dia24horas” no se considera alfabético
  • ctype_cntrl nos devolverá true si todos los caracteres del string son caracteres de control, es decir, caracteres como \t (tabulador) o \n (salto de línea)
  • ctype_digit puede ser muy útil, pues comprueba que todos los caracteres sean dígitos. Nos puede servir para comprobar números enteros positivos, pues todos los caracteres serán números
  • ctype_graph comprueba que todos los caracteres son visiblemente imprimibles, excepto el espacio en blanco. Es decir, la cadena “dia24horas” tiene sus caracteres imprimibles, pero “dia\n24\nhoras” no, pues \n es un carácter de control que no se ve al imprimirse
  • ctype_lower es una sencilla función que nos indica si todos los caracteres son minúsculas
  • ctype_print es muy parecida a ctype_graph pero, en esta ocasión, sí incluye los espacios en blanco
  • ctype_punct comprueba que todos los caracteres son signos de puntuación. Por ejemplo el string “*&$()” se considera que tiene todos sus caracteres como signos de puntuación
  • ctype_space nos dice si un string genera completamente espacios en blanco. Además del propio espacio, se consideran espacios a los caracteres de tabulación, tabulación vertical, alimentación de línea, retorno de carro y alimentación de formulario
  • ctype_upper hace lo contrario a ctype_lower, comprobando si todos los caracteres son mayúsculas
  • ctype_xdigit por último, comprueba si los caracteres son dígitos hexadecimales

Filtrar valores

Existe una serie de funciones que nos pueden permitir validar algunos valores de una forma un poco más especial, aunque hay que tener cuidado con alguna situación especial que puede que no acabe de gustarnos.

filter_var

Esta función filtrará una variable con el filtro que se le indique, pues acepta la variable y un filtro, que ya está predefinido, teniendo la opción también de indicarle algunos parámetros más. Si el filtro se omitiera, se utilizaría el dado por defecto. Un listado de los filtros que existen es el siguiente:

  • FILTER_VALIDATE_BOOLEAN que valida si una variable es “true”, “1”, “on” o “yes” devolviendo el valor true
  • FILTER_VALIDATE_EMAIL para validar emails (aunque hay que leer la documentación para ver el tipo de email que permite). Normalmente nos servirá siempre y será muy útil para hacer una validación de que se introduce un email correctamente
  • FILTER_VALIDATE_FLOAT valida si el valor es un número decimal, con lo que actúa de forma idéntica a is_float
  • FILTER_VALIDATE_INT hará lo mismo pero validando si el valor es un entero
  • FILTER_VALIDATE_IP viene muy bien si necesitamos validar una IP, pues además se le puede indicar si deseamos sólo validar una IPv4 o IPv6 y algunas otras opciones
  • FILTER_VALIDATE_MAC valida una dirección MAC
  • FILTER_VALIDATE_REGEXP sirve para validar un valor contra regexp, una expresión regular “Perl-compatible”. No la utilizaremos para nuestros intereses principales
  • FILTER_VALIDATE_URL será otra de las validaciones útiles, pues nos permitirá saber si la URL que nos han pasado es correcta. Sin embargo hay que tener cuidado de indicar el protocolo HTTP exacto para no obtener errores con ella

Para conocer mejor los detalles en cada caso, mejor consultar el propio manual que contiene una table simple y detallada y las opciones más específicas que pueden tener algunos de estos filtros.

La función preg_match

La función preg_match puede ser, y de hecho será, una función muy útil cuando queramos hacer validaciones. Esta función realiza una comparación con una expresión regular. Es decir, le vamos a indicar un patrón en base a unas reglas que ahora veremos y, en base a ese patrón, nos va a indicar si el string que le hemos pasado es correcto o no.

Antes de nada, saber que esta función devolverá 1 si el string tiene el patrón correcto, 0 en caso contrario y false si ha ocurrido algún error.

Delimitadores

En primer lugar tendremos que conocer cómo construir los patrones, pues tienen su complejidad. El delimitador que más se utiliza es una barra inclinada (/), pero también se pueden utilizar almohadillas, paréntesis, corchetes… Además, para escapar un valor (es decir, para que no nos cuente como delimitador) se utiliza la barra invertida (\).

Por ejemplo, un sencillo patrón sería /abc/, es decir, que en la cadena existirá en algún momento el patrón abc. Esto puede servir para buscar, por ejemplo, si el texto que un usuario ha introducido contiene algo que nos interesa o que es obligatorio. Por ejemplo, para una URL tendríamos que buscar /http/ en la cadena que introduzca el usuario. O, mejor aún, ponerle los dos puntos y las barras, pero al ser los delimitadores tendremos que utilizar la barra invertida y se vería como /http:\/\//, lo que puede ser lioso, pero tiene su lógica.

Encontrar una cadena dentro de un string

Pese a que existen funciones que ya hacen esto, podemos construirlo también con un patrón y llamar a preg_match. Vamos con el ejemplo anterior en el que queremos buscar si una cadena contiene abc.

$letras = 'abcdefghijklmnñopqrstuvwxyz';
echo preg_match('/abc/', $letras);

Este pequeño programa imprimiría 1 por pantalla, pues en la variable $letras se encuentra el patrón abc que es el que buscábamos. Sin embargo, este ejemplo es demasiado sencillo, pues ya tenemos strpos y strstr para buscar subcadenas dentro de una cadena.

Metacaracteres

Antes de seguir con ejemplos de patrones, vamos a ver primero los metacaracteres, pues los necesitaremos para ir construyendo todos los demás patrones. Para codificar nuestro patrón deberemos utilizar metacaracteres, que no son otra cosa que caracteres que indican algo dentro del patrón, ya sea el inicio de algo, coincidencia, subpatrón, etc. Veámoslos en la siguiente tabla.

MetacarácterFuncionalidad
\Permite escapar cualquiera de los otros caracteres si deben estar dentro del propio patrón
^Indica un inicio de string o de línea
$Indica un final de string o de línea
.Se usa para indicar coincidencia con cualquier carácter excepto con el que representa a una nueva línea
[Inicia una definición de clase carácter
]Finaliza una definición de clase carácter
|Inicia una rama alternativa
(Inicia la definición de un subpatrón
)Finaliza la definición de un subpatrón
?Ampliará el significa del subpatrón o cuantificador
*Cuantificador 0 o más
+Cunatificador 1 o más
{Inicio de cuantificador mínimo/máximo
}Final de cuantificador mínimo/máximo
Los siguientes caracteres se usan dentro de []
^Niega la clase, pero sólo si es el primer carácter
Indica el rango de caracteres

No os preocupéis ahora de si no entendéis muchas de las funcionalidades. Vamos a ir ejemplos donde, con la utilización, se verá más claramente.

Comprobar si un string empieza con unos caracteres concretos

$codigo = 'IB09';
echo preg_match('/^IB/', $codigo);

Como hemos indicado en la tabla, el símbolo ^ se utilizará para indicar si el string comienza por el patrón que indiquemos. En este caso nos devolvería un valor 1, pues ciertamente se cumpliría, pues en el inicio de la cadena vemos que aparece IB como hemos indicado en el patrón.

Sin embargo sólo funcionaría si coinciden mayúsculas y minúsculas. Si quisiéramos que no tuviera en cuenta este aspecto, deberíamos indicarle al final un modificador de patrón, en este caso una simple i (indica insensitive).

$codigo = 'IB09';
echo preg_match('/^IB/i', $codigo);

Ahora, si $codigo tuviera la cadena “ib09”, o “Ib09”, o también “iB09”, el patrón sería también correcto.

Comprobar si un string finaliza con unos caracteres concretos

Viendo la tabla podemos ver que, para realizar lo siguiente, vamos a tener que utilizar el carácter $ al final del patrón para que compruebe si el string finaliza con ese patrón. Por ejemplo:

$despedida = 'adiós';
echo preg_match('/adiós$/', $despedida);

El patrón se cumpliría en este ejemplo pues esperamos que el string termine con la cadena “adiós” y así ha sido. Recordad que podéis colocar una i al final para que no sea sensible a mayúsculas y minúsculas. Si tuviéramos un string con muchas líneas (con el carácter \n), podríamos colocar también al final un modificador m para indicarle que busque en todas las líneas.

Coincidir con un rango de caracteres

En muchas ocasiones vamos a querer que el texto coincida con un rango específico de caracteres. Por ejemplo cuando queremos que un texto tenga sólo letras o cuando tenga un rango de números específico.

$texto = 'Prueba de texto con números 12345';
echo preg_match('/Pru[aeiou]ba/', $texto);
echo preg_match('/[1234]/', $texto);
echo preg_match('/[5678]/', $texto);

Estas tres llamadas a preg_match darían un 1 como resultado, pues en todas se cumplen. Analicémoslas. En la primera estamos buscando que el string tenga un patrón con una cadena que tenga “Pru”, luego cualquiera de las cinco vocales, y seguidamente “ba”. ¿Se cumple? Sí, tenemos “Prueba”, pero también se cumpliría si tuviéramos “Pruaba”, “Pruiba”, “Pruoba” y “Pruuba”, pues todas entran en el rango especificado.

Las otras dos también se cumplen. La primera pregunta si el string tiene alguno de esos números. En este caso los tiene todos, así que nos va a devolver un 1 con seguridad. El tercer caso puede liar más, pues no vemos ni el 6, ni el 7, ni el 8 en el string. Pero recordemos que estamos en un rango de caracteres, por lo que, como el 5 sí está y el rango es que esté entre el 5, 6, 7 u 8, entonces nos devolverá que sí está.

Los rangos pueden venir bien, por ejemplo, para validar un email en el que sólo queremos que contengan caracteres de la a a la z y, por ejemplo, en minúsculas. Para ello podemos representar este rango como a-z y ya nos cogería abc…xyz. Con los números podríamos hacer igual.

Cualquier carácter válido

El punto indica que admitimos cualquier valor. Por ejemplo:

$texto = 'Prutba de texto con números 12345';
echo preg_match('/Pru.ba/', $texto);

Un ejemplo sencillo, aunque imagino que sin utilidad real. Nos va a devolver un 1, pues el . va a indicar que podemos poner ahí lo que queramos, y como “Pru” seguido de algo y terminado en “ba” existe, entonces el patrón es correcto.

Muchas, o ninguna, ocurrencia de un carácter

Podemos controlar si un carácter aparece una, muchas, o ninguna vez:

$texto1 = 'Valor';
echo preg_match('/Val*or/', $texto1);
$texto2 = 'Vaor';
echo preg_match('/Val*or/', $texto2);
$texto3 = 'Vallllllor';
echo preg_match('/Val*or/', $texto3);

Estos ejemplos devolverían siempre un 1. Cuidado, el asterisco indicará repetición, o no, del carácter que le precede, en este caso la ele. Puede haber una ele (primer caso), ninguna ele (segundo caso) o muchas eles (tercer caso).

Si queremos que encuentre una o más de una y, por tanto, devuelva un 0 cuando no encuentra ninguna, se utiliza el +:

$texto1 = 'Valor';
echo preg_match('/Val+or/', $texto1);
$texto2 = 'Vaor';
echo preg_match('/Val+or/', $texto2);
$texto3 = 'Vallllllor';
echo preg_match('/Val+or/', $texto3);

Ahora el primer y tercer string son válidos, pero no el segundo.

Sin embargo, si queremos que sólo aparezca cero o una vez (es decir, hacer el carácter opcional pero no infinito), utilizamos el signo ?:

$texto = 'Valor';
echo preg_match('/Val?or/', $texto);
$texto = 'Vaor';
echo preg_match('/Val?or/', $texto);
$texto = 'Vallllllor';
echo preg_match('/Val?or/', $texto);

Ahora son la primera y segunda opción las válidas, e inválida la tercera.

Indicar un número exacto de repeticiones

Podemos preguntarle sobre un número máximo de repeticiones con las llaves {} de la siguiente forma:

$texto1 = "Valooor";
$texto2 = "Valoooooor";
$texto3 = "Valoor";
$texto4 = "Valouour";
$texto5 = "Valr";
echo preg_match("/Valo{3}r/", $texto1);
echo preg_match("/Valo{3,}r/", $texto2);
echo preg_match("/Valo{2,3}r/", $texto3);
echo preg_match("/Val[aeiou]{4}r/", $texto4);
echo preg_match("/Valo{0}r/", $texto5);

En el primer caso tenemos un texto con tres veces la letra o. El patrón entre llaves indica que se esperan tres caracteres con la letra o, por tanto sería correcto. En el segundo caso la coma indica que puede ser desde 3 hasta cualquier valor, así que siempre que haya más de 3 será válido. En el tercer caso se especifica más el rango e indica que es válido si tiene de 2 a 3 valores. En el cuarto, vemos que debe repetir cuatro veces cualquier carácter que se encuentre en ese rango, es decir, que valdría también “Valaeior” por ejemplo. Y, en el último, se indica que no debe tener el valor. Todos estos ejemplos dan validez si los probáramos, pues cumplen los patrones indicados.

Alternar coincidencias y crear subpatrones

En ocasiones nos puede que haya varias opciones posibles para un texto, por ejemplo:

$texto1 = "Él se puso a programar";
echo preg_match("/Él|Ella/", $texto1);
$texto2 = "Ella se puso a programar";
echo preg_match("/Él|Ella/", $texto2);

Ambas cadenas son válidas, pues se utiliza el símbolo | para indicar que son válidos tanto unas formas como las otras. Podemos ser más explícitos y buscar dentro de subpatrones, indicados entre paréntesis como se indica a continuación:

$texto1 = "Se puso a programar";
echo preg_match("/(estudi|program)ar/", $texto1);
$texto2 = "Se puso a estudiar";
echo preg_match("/(estudi|program)ar/", $texto2);

Ambas opciones son válidas. Hemos definido un subpatrón con los paréntesis y, dentro de él, las distintas formas válidas que hemos admitido en el string. De esta forma, ambos son válidos.

Todo esto y mucho más con preg_match

La función preg_match todavía tiene unos cuantos detalles más para construir patrones más avanzados que, de momento, no vamos a ver pero que sirven igualmente para validar datos de un formulario. Podéis ver el manual de esta función si queréis profundizar. Además, encontraréis también la existencia de otras funciones parecías como preg_match_all para devolver todos los valores que coinciden con el patrón o preg_replace para sustituir el patrón encontrado por alguna otra cadena.

Las posibilidades son muchas y veremos algunas en el próximo artículo, donde utilizaremos preg_match para validar datos como cuentas bancarias, números de identificación fiscal o emails.

Pierde tiempo en la validación

Exacto, pierde tiempo, todo el que necesites, en validar tus datos. Si quieres controlar que tus programas presenten los mínimos errores posibles (es decir, ninguno), valida siempre los datos que llegan. No te confíes de que un usuario va a escribir un dato (por ejemplo, el DNI en España) correctamente, o que puede intentar que tu programa dé error expresamente colocando datos incorrectos. Valida, siempre valida, no te olvides de validar datos de un formulario.

En el próximo artículo veremos funciones definidas por el programador para validar datos más complejos como los que hemos indicado. Será una buena forma de ver la utilidad de todas estas funciones.

Deja una respuesta