jueves, 18 de julio de 2013

Seguridad PHP - Validación y filtrado 2

FILTER_CALLBACK


Como habréis visto en el anterior tutorial la cantidad de filtros es bastante decente pero evidentemente no cubre todas las necesidades que puede tener un desarrollador a la hora de filtrara datos. Por lo tanto tenemos que recurrir a funciones creadas por nosotros o a un tipo de filtro especial con llamada a funciones.

El tipo de filtro FILTER_CALLBACK nos permite hacer lo que nos indica su nombre. Llamar a una función nuestra para utilizarla como filtro o como función de filtrado. Y la única opción que permite es el nombre de la función que queremos aplicar.

Vamos a ver un sencillo ejemplo:

 function convertirEspacio($cadena) {  
      return str_replace(" ", "_", $cadena);  
 }  
 $string = "Esto es un ejemplo";  
 echo filter_var($string, FILTER_CALLBACK, array("options"=>"convertirEspacio"));  

Filtrar un array de datos


Si lo que queremos es validar multiples  datos (array) a la vez, también tenemos a nuestra disposición de una función llamada filter_input_array(). Con lo que podemos hacer la validación todos los campos de un formulario en un solo paso.

 mixed filter_input_array ( int $type [, mixed $definition ] )  

La salida será un array en caso de que los valores pasen el filtro o false en caso de que no. Podemos obtener Null si la variable no esta definida.

Los parámetros de entrada serán dos, siendo el segundo de ellos opcional:
A) Array asociativo de claves en formato string con los datos a filtrar.
B) Array definiendo los argumentos, que estará compuesto de:
- Una clave válida será aquella que contiene una cadena con el nombre de una clave definida en el array de datos.
- Un valor válido será aquel que o bien es un tipo tipo de filtro (vistos en el tutorial anterior) o un array especificando opcionalmente el filtro, flags y opciones. Si el valor es un array (mirar código en negrita), las claves válidas serán:
           - filter: Definirá el tipo de filtro.
           - flags: Definirá cualquier bandera (flag) que deba aplicarse a los filtros.
           - options: Establecerá cualquier opción que se deba aplicar al filtro.

 $data = array(  
   'id_producto'  => '5',  
   'componente'   => '10',  
   'versiones'   => '2.0.33',  
 );  
 $args = array(  
   'id_producto'  => FILTER_VALIDATE_INT,  
   'componente'  => array('filter'  => FILTER_VALIDATE_INT,   
                         'options'  => array('min_range' => 1, 'max_range' => 10)  
               ),  
   'versiones'   => FILTER_SANITIZE_ENCODED,  
 );  
 $myinputs = filter_var_array($data, $args);  


Filtrado de variables externas

Además de filtrar datos internos podemos filtrar directamente datos proveniente del exterior del sistema. Ya sea datos provenientes de peticiones POST, GET, COOKIES...
Para ello tenos a nuestra disposición la función filter_input.

 mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] )  

Actúa de forma similar a filter_var (vista en el tutorial anterior) y el resultado es el mismo. Pero esta vez está formada por 4 parámetros:
1- Tipo de variable externa: Puede ser uno de los siguientes: INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER o INPUT_ENV.
2- Nombre variable Nombre de la variable a filtrar
3- ID del filtro a usar. Sirve cualquiera de los filtros explicados anteriormente.
4- Array asociativo de opciones o disyunción lógica de banderas. Si el filtro acepta banderas, se pueden añadir banderas en el array asociativo bajo la clave "flags". Al igual que con los filtros presentados anteriormente.

Y lo valores de salida son:
- En caso de éxito el valor filtrado de la variable pedida.
- FALSE si el filtro falla.
- NULL si la variable  no está definida.
Si se usa la badera FILTER_NULL_ON_FAILURE, retorna FALSE si la variable no está definida y NULL si el filtro falla.

 $pagina = filter_input(INPUT_GET, 'pagina', FILTER_VALIDATE_INT);  
 if($pagina !== false){       
 }else{       
 }  


Ejemplo completo de uso de filtros

A continuación se muestra un pequeño script de lo que podría ser una formulario de contacto y su validación, mediante filtros, para el envio del correspondiente email.

 <?php  
 $errores = "";  
 if (isset($_POST['nombre'], $_POST['email'], $_POST['mensaje'])) {  
   if ($_POST['nombre'] != "") {  
     $_POST['nombre'] = filter_var($_POST['nombre'], FILTER_SANITIZE_STRING);  
     if ($_POST['nombre'] == "") {//despues de sanear puede quedar vacio  
       $errores .= 'Introduzca un nombre correcto.<br/><br/>';  
     }  
   } else {  
     $errores .= 'Introduzca su nombre.<br/>';  
   }  
   if ($_POST['email'] != "") {  
     $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);  
     if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {  
       $errores .= "$email <strong>NO</strong> es una dirección correcta.<br/><br/>";  
     }  
   } else {  
     $errores .= 'Por favor introduze un dirección de correo.<br/>';  
   }  
   if ($_POST['mensaje'] != "") {  
     $_POST['mensaje'] = filter_var($_POST['mensaje'], FILTER_SANITIZE_STRING);  
     if ($_POST['mensaje'] == "") {  
       $errores .= 'Por favor inserte un mesaje a enviar.<br/>';  
     }  
   } else {  
     $errores .= 'Por favor inserte un mesaje a enviar.<br/>';  
   }  
   if ($errores == "") {  
     $mail_to = 'ivanpgcs@gmail.com';  
     $subject = 'Mail de prueba';  
     $txt = 'De: ' . $_POST['nombre'] . "\n";  
     $txt .= 'Email: ' . $_POST['email'] . "\n";  
     $txt .= "Mensaje:\n" . $_POST['mensaje'] . "\n";  
     mail($mail_to, $subject, $txt);  
     echo "Gracias por enviarnos un correo!<br/><br/>";  
   } else {  
     echo '<div style="color: red">' . $errores . '<br/></div>';  
   }  
 }  
 ?>  
 <html>  
   <head>  
     <meta charset="utf-8">  
   </head>  
   <body>  
     <form name="form1" method="post" action="filtros.php">  
       Nombre: <br/>  
       <input type="text" name="nombre" value="<?php if (isset($_POST['nombre'])) echo $_POST['nombre']; ?>"/><br/><br/>  
       Email: <br/>  
       <input type="text" name="email" value="<?php if (isset($_POST['email'])) echo $_POST['email']; ?>"/> <br/><br/>  
       Mensaje: <br/>  
       <textarea name="mensaje" rows="8" cols="40"><?php if (isset($_POST['mensaje'])) echo $_POST['mensaje']; ?></textarea>  
       <br/>  
       <input type="submit" name="enviar" />  
     </form>  
   </body>  
 </html>  


Otros métodos de filtrado y saneamiento

A parte de los filtros, existen mas funciones para filtrar y sanear datos en PHP.

Funciones de tipo de dato:

- is_string(): Función que retornará true si la variable evaluada es una cadena.
- is_int(): Función que retornará true si la variable evaluada es un entero.
- is_float(): Función que retornará true si la variable evaluada es un flotante.
- is_numeric: Función que retornará true si la variable evaluada es un número o un string numérico.
- is_boolean(): Función que retornará true si la variable evaluada es de tipo bool.
- is_array(): Función que retornará true si la variable evaluada es un array.
- Expresiones regulares: otro mecanismo para asegurarnos del tipo de datos que queremos que entren al sistema.

 <?php  
 // validar teléfono USA  
 if (preg_match('/^((1-)?\d{3}-)\d{3}-\d{4}$/', $phone)) {  
   echo $phone . " tiene un formato válido.";  
 }  

Funciones de saneamiento:

- htmlspecialchars(): Convierte caracteres especiales en entidades HTML.
- htmlentities(): Convierte todos los caracteres aplicables a entidades HTML. Esta función es idéntica a la anterior en todos los aspectos, excepto que todos los caracteres que tienen equivalente HTML son convertidos a esas entidades.
- strip_tags(): Retira las etiquetas HTML y PHP de un string.
- stripslashes(): Quita las barras de un string con comillas escapadas. Devuelve un string con las barras invertidas retiradas. (\' se convierte en ' y así sucesivamente.) Barras invertidas dobles (\\) se convierten en una sencilla (\).
- mysqli_real_escape_string(): Escapa los caracteres especiales de una cadena para usarla en una sentencia SQL


Entradas relacionadas

Seguridad PHP - Validación y filtrado 1

No hay comentarios:

Publicar un comentario