La validación de formularios es el procedimiento de filtrar y revisar los datos enviados al servidor luego de hacer clic en el botón submit del formulario. Por ejemplo, queremos hacer las siguientes revisiones en el formulario de contacto:
Queremos revisar que la dirección de correo electrónico, el asunto del mensaje y el cuerpo del mensaje están presentes (porque son campos required).
Queremos estar seguros de que el usuario ingreso una dirección de correo electrónico valida como name@example.com.
El usuario podría agregar un espacio en blanco al principio y/o al final de la dirección de correo electrónico por lo que deberíamos filtrar esos caracteres ejecutando una operación para cortarlos.
Sería útil revisar el tamaño mínimo y máximo permitido para el asunto del mensaje y del cuerpo de texto.
Para el asunto del mensaje nos gustaría quitar los caracteres de salto de línea y las etiquetas HTML 22.
Además, queremos quitar las etiquetas HTML del cuerpo del mensaje.
22) Podrían haber usuarios maliciosos que agregan código HTML en el mensaje. Si abrimos ese código en el navegador podríamos ver contenido indeseado. Para evitar esto necesitamos reemplazar las etiquetas HTML del asunto y del cuerpo del mensaje.
Los requerimientos de arriba se llaman filtros y reglas de validación. Estas reglas pueden ser divididas dentro de dos categorías: filtros y validadores.
Los filtros transforman los datos ingresados por el usuario para reparar errores y asegurar que cumplen un determinado formato. Los filtros generalmente se aplican primero y los validadores se aplican de último.
Los validadores revisan si los datos son aceptables o no. Si todos los datos son correctos el formulario se considera valido y los datos pueden ser usados por la capa de la lógica de negocio. Si determinado campo es invalido, un validador levanta una bandera de error. En este caso, generalmente el formulario se muestra de nuevo al usuario al que se le pide que corrija cualquier error de entrada y que reenvíe el formulario al servidor.
¿Que sucede si no se agrega una regla de validación a un determinado campo del formulario?
Si no se agrega una regla de validación entonces los valores de los campos enviados por el usuario no serán revisados dejando un hueco en la seguridad del sitio web. Siempre es recomendable agregar una regla de validación a cada campo que el usuario llena del formulario y agregar tantas revisiones por campo como sea necesario para mantener el formulario seguro.
En ZF3 guardamos los filtros y la reglas de validación con la ayuda de la clase
InputFilter
. La clase
InputFilter
está definida en el componente
Zend\InputFilter
. Un filtro de entrada es un contenedor para las entradas
(inputs). Generalmente agregamos un filtro de entrada por cada campo de nuestro
modelo de formulario.
Una entrada puede consistir en filtros y/o validadores y alguna información adicional. Por ejemplo, una entrada puede contener la bandera que señala si el campo es obligatorio o si su valor puede faltar en la petición HTTP.
De una manera análoga a como agregamos campos al modelo del formulario existen
dos formas de agregar entradas al contenedor de filtros: pasando una instancia
de la clase entrada como argumento del método add()
o pasando un
arreglo de especificaciones 23. En la sección siguiente
describiremos la última forma, ella es preferible porque necesitamos escribir
menos código.
23) En el caso siguiente en el que usamos un arreglo de
especificaciones la entrada se creará automáticamente
con la ayuda de la clase Zend\InputFilter\Factory
.
Para agregar una entrada al filtro de entrada usamos el método add()
que
toma un solo argumento, un arreglo con las especificaciones de la entrada como
se muestra a continuación:
[
'name' => '<name>',
'type' => '<type>',
'required' => <required>,
'filters' => [
// Add filters configuration here ...
],
'validators' => [
// Add validators configuration here ...
]
]
En el arreglo de arriba tenemos las siguientes llaves:
La llave name
(línea 2) define el nombre de la entrada. El nombre debe ser
el mismo que el nombre del campo en el modelo de formulario. Si el nombre
de la entrada no coincide con el nombre del campo en el modelo de formulario
la regla de validacion no se aplicará al campo.
La llave type
(línea 3) define el nombre de la clase de entrada. Esta llave
es opcional. Por defecto (cuando el valor se omite) se usa la clase
Zend\InputFilter\Input
. Las clases de entrada disponibles se muestran en
la figura 7.16. En la figura 7.16 la clase Input
está diseñada para ser usada con valores escalares regulares, el ArrayInput
se usa para filtrar/validar arreglo de valores y FileInput
se usa para
revisar los archivos cargados.
La llave required
(línea 4) dice si el campo del formulario es obligatorio
u opcional. Si el campo es obligatorio el usuario del sitio deberá llenarlo
de lo contrario recibirá un error de validación.
Los llaves filters
(línea 5) y validators
(línea 8) pueden contener la
configuración de ninguno, uno o varios filtros y/o validadores que se aplican
al campo del modelo de formulario.
Figura 7.16. Herencia de la clase Input
La configuración de un filtro típico se muestra abajo:
[
'name' => '<filter_name>',
'priority' => <priority>,
'options' => [
// Filter options go here ...
]
],
La llave name
(línea 2) es el nombre para el filtro. Este puede ser o el
nombre completo de la clase filtro, es decir StringTrim::class
, o un
alias, StringTrim
.
La llave opcional priority
(línea 3) define la prioridad del filtro en la
lista de filtros. La prioridad debe ser un número entero. El filtro con la
prioridad más alta será aplicado primero. Por defecto se asigna la constante
FilterChain::DEFAULT_PRIORITY
(valor 1000).
El arreglo de options
(línea 4) es especifico para cada filtro
y puede contener parámetros para configurar el filtro.
Una configuración típica para el validador se presenta abajo:
[
'name' => '<validator_name>',
'break_chain_on_failure' => <flag>,
'options' => [
// Validator options go here ...
]
],
La llave name
(línea 2) es el nombre para el validador. Este puede ser el
nombre completo de la clase validador (EmailAddress::class
) o un alias
(EmailAddress
).
La llave opcional break_chain_on_failure
(línea 3) define el comportamiento
en el caso de que el validador falle. Si es igual a true
los siguientes
validadores en la lista no serán ejecutados de lo contrario cada validador
en la lista será ejecutado sin depender del resultado de los otros validadores.
El arreglo de options
(línea 4) es especifico para una determinada clase
validador y puede contener parámetros para configurar el validador.
Una vez que hemos creado y llenado el contenedor para el filtro de entrada
debemos añadirlo al modelo del formulario. La clase base Form
provee el
método setInputFilter()
que esta pensado con este propósito (ver tabla 7.10).
Nombre del Método | Descripción |
---|---|
setInputFilter($inputFilter) |
Añade el contenedor de filtro de entrada al formulario. |
getInputFilter() |
Recupera el filtro de entrada añadido a un formulario. |
Ahora que tenemos un idea general sobre como definir y llenar el contenedor
del filtro de entrada con filtros y validadores para cada campo vamos a
completar nuestra clase de modelo de formulario ContactForm
. Abajo agregamos
el método privado addInputFilter()
que define las reglas de filtrado/validación,
las guarda en el contenedor de filtro de entrada y asocia el filtro de
entrada al modelo de formulario.
<?php
// ...
use Zend\InputFilter\InputFilter;
class ContactForm extends Form
{
public function __construct()
{
// ... call this method to add filtering/validation rules
$this->addInputFilter();
}
// ...
// This method creates input filter (used for form filtering/validation).
private function addInputFilter()
{
$inputFilter = new InputFilter();
$this->setInputFilter($inputFilter);
$inputFilter->add([
'name' => 'email',
'required' => true,
'filters' => [
['name' => 'StringTrim'],
],
'validators' => [
[
'name' => 'EmailAddress',
'options' => [
'allow' => \Zend\Validator\Hostname::ALLOW_DNS,
'useMxCheck' => false,
],
],
],
]
);
$inputFilter->add([
'name' => 'subject',
'required' => true,
'filters' => [
['name' => 'StringTrim'],
['name' => 'StripTags'],
['name' => 'StripNewlines'],
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 1,
'max' => 128
],
],
],
]
);
$inputFilter->add([
'name' => 'body',
'required' => true,
'filters' => [
['name' => 'StripTags'],
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 1,
'max' => 4096
],
],
],
]
);
}
}
Como podemos ver en el código de arriba primero declaramos el alias para la
clase Zend\InputFilter\InputFilter
(línea 3).
En el constructor del modelo de formulario (línea 10) llamamos al método
addInputFilter()
que está definido entre las líneas 16-76.
El objetivo del método addInputFilter()
es crear el contenedor InputFilter
(línea 18), asociarlo al modelo de formulario (línea 19) y agregar
reglas de filtrado/validación (líneas 21-75). Para asociar el filtro de entrada
al modelo de formulario usamos el método setInputFilter()
provisto por
la clase Form
. Para insertar reglas de filtrado/validación dentro del
contenedor de filtro de entrada usamos el método add()
que provee la clase
InputFilter
y que toma el arreglo de especificaciones de la entrada que se
quiere crear.
Agregamos tres entradas una por cada campo de nuestro formulario excepto el botón submit:
Para el campo email
colocamos la bandera required
en true
para así obligar
a que se llene el campo. Usamos el filtro StringTrim
para remover los
espacios en blanco del principio y el final de la dirección de correo
electrónico. Además, usamos el validador EmailAddress
para revisar la
dirección de correo electrónico ingresada por el usuario. Configuramos el
validador EmailAddress
para permitir nombres de dominio como direcciones
de correo electrónico (la bandera Zend\Validator\Hostname::ALLOW_DNS
)
y desactivamos la revisión del registro MX (colocamos la opción useMxCheck
en false
).
Hacemos obligatorio al campo subject
y usamos el filtro StringTrim
para
remover los espacios en blanco del principio y el final. Además, usamos los
filtros StripNewlines
y StripTags
para respectivamente quitar los
caracteres de nueva línea y las etiquetas HTML. Limitamos la longitud de la
cadena entre 1 y 128 caracteres usando el validador StringLength
.
Necesitamos que el campo body
sea obligatorio, usamos el filtro
StripTags
para quitar las etiquetas HTML del texto. Además, usamos el
validador StringLength
para limitar el tamaño del texto entre 1 y 4096
caracteres.
En la figura 7.17 podemos encontrar el esquema gráfico del filtro de entrada que hemos creado.
Figura 7.17. El filtro de entrada para el ContactForm
Arriba describimos brevemente como crear un filtro de entrada para el modelo de formulario. Para información detallada sobre lo que mencionamos arriba, filtros y validadores, y sobre otras cosas podemos revisar Transformar los Datos de Entrada con Filtros y Revisar los Datos de Entrada con Validadores en donde encontraremos además ejemplos de uso.