Tutorial en el que mostramos y enseñamos los métodos más efectivos a la hora de validar y sanear datos en PHP. Todo programador debería conocer este tipo de técnicas que permitirán mantener la integridad y seguridad de sus aplicaciones… ¡no os lo perdáis!

Autor:

Intentando mejorar cada día en este mundo tan cambiante de la programación. Sígueme en Twitter o en GitHub. Actualmente estoy disponible para contratar.

Introducción: la importancia de validar y sanear datos

Un punto crítico de cualquier tipo de aplicación es la entrada de datos por parte del usuario, ya que, si no se toman las medidas oportunas, un usuario puede (intencionadamente o no) causar fallos en la aplicación.

En el mundo del desarrollo web, esto cobra mucha más importancia, pues se incrementa mucho el número de usuarios potenciales y por tanto, el número de usuarios malintencionados. Ataques conocidos y fáciles de llevar a cabo son SQL Inyection y XSS (Cross Site Scripting).

En aplicaciones web es importante realizar siempre la validación en el lado del servidor.

Otra vulnerabilidad que tiene que ver con la validación, que es debido muchas veces a la inexperiencia del desarrollador, es confiar la validación de lados al lado de cliente (Javascript). Esto es algo grave, pues existen herramientas para enviar datos a una web sin que intervenga para nada un navegador ni Javascript.

La extensión Filter

Esta extensión de PHP nos expone un conjunto de funciones que nos permitirán la validación y saneamiento de datos de una forma sencilla. La funcion filter_var nos permite filtrar una variable según el filtro especificado. El orden de los parámetros es el siguiente:

  • $var: Variable que se quiere filtrar
  • $filter: Filtro que se desea aplicar. Será una constante numérica
  • $options: Conjunto de opciones que modificarán el funcionamiento del filtro. Será una constante numérica o un array

A continuación un listado de filtros de validación posibles:

FILTER_VALIDATE_BOOLEAN
Valida la variable como un booleano.

FILTER_VALIDATE_EMAIL
Valida la variable como una dirección de correo electrónico correcta.

FILTER_VALIDATE_FLOAT
Valida que la variable sea del tipo float.

FILTER_VALIDATE_INT
Valida la variable como un número entero.

FILTER_VALIDATE_IP
Valida la variable como una dirección IP.

FILTER_VALIDATE_REGEXP
Valida la variable contra una expresión regular enviada en la variable de opciones.

FILTER_VALIDATE_URL
Valida el valor coma una URL de acuerdo con la RFC 2396.

A continuación el listado de filtros para sanear:

FILTER_SANITIZE_EMAIL
Elimina todos los caracteres execpto letras, números y !#$%&’*+-/=?^_`{|}~@.[].

FILTER_SANITIZE_ENCODED
Codifica la cadena como una URL válida.

FILTER_SANITIZE_MAGIC_QUOTES
Aplica la función addslashes.

FILTER_SANITIZE_NUMBER_FLOAT
Elimina todos los caracteres excepto números, +- y opcionalmente ,.eE.

FILTER_SANITIZE_NUMBER_INT
Elimina todos los caracteres excepto números y los signos + -.

FILTER_SANITIZE_SPECIAL_CHARS
Escapa caracteres HTML y caracteres con ASCII menor a 32.

FILTER_SANITIZE_STRING
Elimina etiquetas, opcionalmente elimina o codifica caracteres especiales.

FILTER_SANITIZE_STRIPPED
Alias del filtro anterior.

FILTER_SANITIZE_URL
Elimina todos los caracteres excepto números, letras y $-_.+!*’(),{}|\\^~[]`<>#%”;/?:@&=.

Validar y sanear un número entero

Vamos a ver un sencillo ejemplo de validación de un número entero.

<?php
$var = 123;
echo filter_var($var, FILTER_VALIDATE_INT);

La función nos devolverá el entero en caso de que la validación sea correcta, en caso contrario, nos devolverá FALSE.

<?php
$var = 'dos';
if(filter_var($var, FILTER_VALIDATE_INT) === false){
	echo 'Valor incorrecto';
}else{
	echo 'Valor correcto';
}

A la hora de validar un entero, podemos jugar con las opciones para hacer ajustar el comportamiento de la función a nuestras necesidades. En el siguiente ejemplo se muestra como validar un entero que esté dentro de un rango específico:

$options = array('min_range'=>10, 'max_range' => 20));

if(filter_var($var, FILTER_VALIDATE_INT, $options) === false){
	echo 'Valor incorrecto';
}else{
	echo 'Valor correcto';
}

Ahora vamos a ver como sanear un entero, para los que no entiendan, sanear significa limpiar, es decir, quitamos todo lo que no tiene cabida en nuestro campo.

<?php
$var = 'uno23';

echo filter_var($var, FILTER_SANITIZE_NUMBER_INT);

El código anterior nos devuelve ’23′ debido a que elimina todos los caracteres no numéricos de la cadena.

Validar y sanear un número float

La validación simple de un float es practicamente igual que la de un entero:

<php
$var = 1.3;

echo filter_var($var, FILTER_VALIDATE_FLOAT);

Sin embargo, con este filtro tenemos una opcion interesante que nos permite especificar cual es el caracter que separa los decimales.

<php
$var = '1,3';
$options = array('options'=>array('decimal'=>','));
echo filter_var($var, FILTER_VALIDATE_FLOAT, $options);

Saneamiento de textos

La limpieza de los textos es algo muy importante y por ello tenemos varios flags que modifican el comporamiento del filtro FILTER_SANITIZE_STRING:

FILTER_FLAG_NO_ENCODE_QUOTES
No codificará las comillas simples ni dobles.

FILTER_FLAG_STRIP_LOW
Elimina caracteres cuyo varlor ASCII sea menor a 32.

FILTER_FLAG_STRIP_HIGH
Elimina caracteres cuyo valor ASCII sea mayor a 127.

FILTER_FLAG_ENCODE_LOW
Codifica caracteres cuyo valor ASCII sea mennor a 32.

FILTER_FLAG_ENCODE_HIGH
Codifica caracteres cuyo valor ASCII sea mayor a 127.

FILTER_FLAG_ENCODE_AMP
Codifica ampersands (&).

A continuación algunos ejemplos:

<php
$text = '<p>"Hola mundo!"</p>';
echo filter_var($text, FILTER_SANITIZE_STRING);
//Resultado: &#34;Hola mundo!&#34;
<php
$text = '<p>"Hola mundo!"</p>';
echo filter_var($text, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
//Resultado: "Hola mundo!"
<php
$text = '"Ontuts & Cokidoo"';

echo filter_var($text, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES | FILTER_FLAG_ENCODE_AMP);
//Resultado: "Ontuts &amp; Cokidoo"

Obtener variables externas

Además de la función filter_var, existe una muy interesante llamada filter_input. Esta funcion nos permite obtener una variable externa por su nombre, filtrándola si es necesario.

Es importante que todas las variables externas, es decir, que nos llegan desde el lado del cliente ($_GET, $_POST, $_COOKIE…) las obtengamos a través de esta función para ahorrarnos disgustos. En el siguiente ejemplo vemos como obtener un parámetro GET de la petición con esta función:

<php
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT);

if($page !== null && $page !== false){
	//El parametro ha sido enviado y es un entero
}else{
	//El parametro no se ha enviado o no es un entero
}

Esta función nos devolverá NULL si la variable no ha sido enviada, FALSE si la variable ha sido enviada pero no validada o el valor de la variable si ha sido enviada y validada.

El primer parámetro indica de que ámbito será extraída la variable, y puede ser uno de los siguientes valores:

  • INPUT_GET
  • INPUT_POST
  • INPUT_COOKIE
  • INPUT_SERVER
  • INPUT_ENV

Otra función relacionada y muy interesante es filter_input_array que nos permite definir una serie de validaciones para múltiples campos. Es decir, podemos hacer la validación todos los campos de un formulario en un solo paso. La definición de los campos con sus validaciones se hace mediante un array como se muestra en el siguiente ejemplo:

<?php
$args = array(
    'product_id'   => FILTER_SANITIZE_ENCODED,
    'component'    => array('filter'    => FILTER_VALIDATE_INT,
                            'flags'     => FILTER_REQUIRE_ARRAY, 
                            'options'   => array('min_range' => 1, 'max_range' => 10)
                           ),
    'versions'     => FILTER_SANITIZE_ENCODED
    );

$myinputs = filter_input_array(INPUT_POST, $args);

Esta función devuelve un array del tipo clave/valor que contiene los nombres de los campos junto con su filtrado.

Conclusión

Como puedes observar, PHP nos brinda una gran librería con la cual podemos llevar a cabo validaciones y saneamientos en cuestion de segundos, cosa que antes se hacía bastante engorrosa.

Ahora no hay excusa que valga para asegurarnos de que nuestros datos estén bien limpios y seguros :) .

¡Nos vemos en la próxima publicación!

¿Necesitas desarrollar un proyecto web o para móviles? ¡Estamos disponibles!

Visitar Cokidoo

Cokidoo, los creadores de Ontuts, desarrollamos proyectos tecnológicos centrados en redes sociales y aplicaciones web, aplicaciones móviles y consultoría web y bases de datos.

Somos jóvenes, inquietos, versátiles, apasionados por la innovación y enfocados en las nuevas tecnologías. Con Ontuts tratamos de compartir nuestro conocimiento adquirido en los distintos proyectos, ayudando a la comunidad y mostrando nuestra capacidad tecnológica.

Si necesitas un presupuesto sin compromiso, estamos disponibles, no dudes en contactar con nosotros.

Comentarios en esta publicación (20 comentarios)

¿Te ha gustado esta publicación? ¡Puedes compartir tu opinión con todos nosotros! Simplemente pincha aquí mismo.

Osea, que ya no hará falta por ej usar expresiones regulares para validar un email? Desconocía totalmente esta función php.

Genial!, vital diria yo,… ¿y los frameworks PHP como manejan esto?

@alex, Codeigniter hace un perfecto saneamiento de datos; por ejemplo los datos POST usando su: $this->input->post()

http://codeigniter.com/user_guide/libraries/input.html

Al autor del post, enhorabuena, me gustó. Un pequeño fallo vi, en la función de sanear un entero con límites te faltó declarar la variable $options con el array.

@Joshua Gracias! Ya está corregido el fallo.

Olvidaron mencionar que estas funciones estan disponibles desde la version 5.2 en adelante.
aunque es poco común, alguna vez me encontré con un servidor 5.1 y obviamente no funcionaron.

Saludos y que buen post, me gusta mucho leerlos.

Javier

Yo habia creado mis propias funciones de saneamiento y tengo una que remueve algunas palabras para evitar SQL Inyection por ejemplo ’1=1′ entre otras, supongo que la funcion filter_var no protege contra el SQL Inyection, no veo la manera de evitar ciertas palabras o cadenas de textos maliciosas, igual tendriamos que usar expresiones regulares?

@Javier, ponme un ejemplo de SQL Inyection usando las funciones de saneamiento y luego lo discutimis :)

Jordi

No conocía esta función y realmente útil, lo único que después de leer los comentarios me ha quedado la duda de si es seguro o no para SQL Inyection.

Gran blog Ivan, vas directo a mi RSS Reader :)

Hola Jordi y gracias! :D

La funcion de saneamiento, nos ayuda a elminar las etiquetas y caracteres especiales, sin embargo, no está de más usar las funciones de escape para prevenir las inyecciones. Todo lo que sea seguridad…nunca está de más

cristian cena

Hola iván, 10 puntos el artículo, muchas gracias.

I will right away grab your rss feed as I can not see your electronic mail subscription hyperlink or news letter service. Do you have any kind of? Kindly let me know so that I could sign up. Many thanks.

I confess, I have not been on this web site for a long time, however, it was another joy to see such a best items and neglect it. Many thanks for assisting making people more aware of good opinions.

Edgar

Quiero un punto de vista.
Antes utilizaba muchos IF y llamadas a funciones para validar los datos en PHP, pero ahora mirando este articulo, me da la idea así:
1. Verificar si las variables existen con isset() .
2. Comprobar si están vacías con empty() .
3. Aplicar los filtros mencionados aquí y así validar y sanear los datos introducidas en las variables.
4. Creo que este seria opcional, validar la longitud de las variables (texto) o si el rango es el permitido (números).
¿Alguna otra sugerencia?

“this is very interesting. thanks for that. we need more sites like this. i commend you on your great content and excellent topic choices.”

Niko_Zen

Exelente recurso gracias….

Arturo

Recuerden que tambien pueden usar la siguiente funcion:
strip_tags — Retira las etiquetas HTML y PHP de un string

que en combinacion con
$variable = trim($variable);
$variable = strtolower($variable);
$variable = addslashes($variable);

y en consultas: mysql_real_escape_string ,hacen al tema mas completo.

Recomiendo que cada uno se haga un pequeño laboratorio donde testear estas cosas, no solo copiar y pegar, ya que ello permite generar funciones de seguridad propias que formaran parte de la “libreria permanente de todo desarrollador”

El articulo, muy bueno, prioridad para todos los que desarrollamos aplicaciones online!

Arturo

Hola, esto de la seguridad me preocupa bastante, soy novato en desarrollo con php y mysql, pero estoy haciendo una aplicación de registro de usuarios, tan compleja que recoge mas de 50 campos de texto en el form incluyendo selects, radio buttons y text areas, el formulario enviado es recogido por una página php que muestra los datos ingresados antes de ser enviados a mysql.

Ej. formulario.php (recoge los datos del usuario )
verificar.php (muestra en pantalla los datos del formulario.php y los envía a guardar.php)
guardar.php (recoge los datos de verificar.php y los envía a mysql)

Mi pregunta es: la mejor forma de limpiar los datos recogidos será por verificar.php o por guardar.php. ¿Cuales son los filtros que debo usar?

Gracias por los post. Son excelentes.

Deberías validar en ambos lados, o en el peor de los casos, en el paso final, antes de enviar a la DB