Secciones

Filtro


Resumen

Sanear la entrada del usuario es una parte crítica del desarrollo de software. Confiar o descuidar el saneamiento de la entrada del usuario podría provocar un acceso no autorizado al contenido de su aplicación, principalmente a los datos de usuarios, o incluso al servidor donde su aplicación se aloja.

Imagen completa en XKCD

Se puede lograr el saneado del contenido usando las clases Phalcon\Filter y Phalcon\Filter\FilterFactory.

FilterFactory

Este componente crea un nuevo localizador con filtros predefinidos adjuntos a él. Cada filtro se carga perezosamente para un rendimiento máximo. Para instanciar la fábrica y recuperar Phalcon\Filter con los saneadores establecidos necesita llamar a newInstance()

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();

$locator = $factory->newInstance();

Ahora puede usar el localizador donde lo necesite y sanear el contenido según las necesidades de su aplicación.

Filtro

El componente Phalcon\Filter implementa un servicio de localización y se puede usar como componente independiente, sin tener que inicializar los filtros incorporados.

<?php

use MyApp\Sanitizers\HelloSanitizer;
use Phalcon\Filter;

$services = [
    'hello' => HelloSanitizer::class,
];

$locator = new Filter($services);

$text = $locator->hello('World');

NOTA: El contenedor Phalcon\Di\FactoryDefault ya tiene un objeto Phalcon\Filter cargado con los saneadores predefinidos. Se puede acceder al componente utilizando el nombre del filtro (filter).

Incorporado

NOTA: Cuando sea apropiado, los saneadores convertirán el valor al tipo apropiado. Por ejemplo el saneador absint eliminará cualquier carácter no numérico de la entrada, la convertirá a entero y devolverá su valor absoluto.

A continuación se enlistan los filtros predeterminados del componente. (N. del T.: se preserva la palabra inglesa mixed [mixto], para definir que el filtro acepta como entrada [$input] tanto cadenas de caracteres [string] como matrices [array]):

absint

AbsInt( mixed $input ): int

Elimina todos los caracteres no numéricos, convierte el valor a íntegro y devuelve su valor absoluto. Internamente usa [filter_var] para la parte entera, intval para la conversión de tipos y absint.

alnum

Alnum( mixed $input ): string | array

Elimina todos los caracteres que no son números o que no pertenecen al alfabeto. Usa preg_replace que también admite vectores de cadenas como parámetros.

alpha

Alpha( mixed $input ): string | array

Elimina todos los caracteres que no pertenecen al alfabeto. Se utiliza preg_replace, que acepta cadenas y matrices como parámetros.

bool

BoolVal( mixed $input ): bool

Convierte el valor a “booleano” (verdadero o falso).

Devuelve true (verdadero) si el valor es:

  • true
  • on (encendido)
  • yes (sí)
  • y
  • 1

Devuelve false (falso) si el valor es:

  • false
  • off (apagado)
  • no
  • n
  • 0

email

Email( mixed $input ): string

Elimina todos los caracteres excepto letras, digitos y los caracteres !#$%&*+-/=?^_`{\|}[email protected][]. Internamente usa filter_var con FILTER_FLAG_EMAIL_UNICODE.

float

FloatVal( mixed $input ): float

Elimina todos los caracteres excepto dígitos, punto, signos más y menos, y convierte el valor a double (número con coma flotante de doble precisión). Internamente usa filter_var y (double).

int

IntVal( mixed $input ): int

Elimina todos los caracteres excepto dígitos, signos más y menos y convierte el valor a entero. Internamente usa filter_var y (int).

lower

Lower( mixed $input ): string

Convierte todos los caracteres a minúscula. Si está cargada la extensión mbstring, usará mb_convert_case para realizar la transformación. Como alternativa usa la función PHP strtolower, con utf8_decode.

lowerFirst

LowerFirst( mixed $input ): string

Convierte el primer carácter de la entrada a minúscula. Internamente usa lcfirst.

regex

Regex( mixed $input, mixed $pattern, mixed $replace ): string

Realiza una operación de remplazo regex utilizando un patrón ($pattern) y texto de remplazo ($replace) como parámetros. Internamente usa preg_replace.

remove

Remove( mixed $input, mixed $replace ): string

Elimina contenido de la entrada sustituyendo el parámetro de remplazo ($remove) con una cadena vacía. Internamente usa str_replace.

replace

Replace( mixed $input, mixed $from, mixed $to ): string

Remplaza en la entrada el parámetro $from con el parámetro $to. Internamente usa str_replace.

special

Special( mixed $input ): string

Escapa los caracteres HTML, '"<>& y ASCII con valor inferior a 32 de la entrada. Internamente usa filter_var.

specialFull

SpecialFull( mixed $input ): string

Convierte todos los caracteres especiales de la entrada a entidades HTML (incluidos comillas y apóstrofes). Internamente usa filter_var.

string

StringVal( mixed $input ): string

Elimina las etiquetas y codifica las entidades HTML, incluyendo las comillas y apóstrofes. Internamente usa filter_var.

striptags

StripTags( mixed $input ): int

Elimina todas las etiquetas HTML y PHP de la entrada. Internamente usa strip_tags.

trim

Trim( mixed $input ): string

Elimina los espacios en blanco al inicio y final de la entrada. Internamente usa trim.

upper

Upper( mixed $input ): string

Capitaliza todos los caracteres. Si está cargada la extensión mbstring, usará mb_convert_case para realizar la transformación. Como alternativa usa la función PHP strtoupper, con utf8_decode.

upperFirst

UpperFirst( mixed $input ): string

Capitaliza el primer carácter de la entrada. Internamente usa ucfirst.

upperWords

UpperWords( mixed $input ): string

Capitaliza la primera letra de cada palabra. Internamente usa ucwords.

url

Url( mixed $input ): string

Listado resumido de constantes disponibles para definir el tipo de limpieza a realizar:

<?php

const FILTER_ABSINT      = 'absint';
const FILTER_ALNUM       = 'alnum';
const FILTER_ALPHA       = 'alpha';
const FILTER_BOOL        = 'bool';
const FILTER_EMAIL       = 'email';
const FILTER_FLOAT       = 'float';
const FILTER_INT         = 'int';
const FILTER_LOWER       = 'lower';
const FILTER_LOWERFIRST  = 'lowerFirst';
const FILTER_REGEX       = 'regex';
const FILTER_REMOVE      = 'remove';
const FILTER_REPLACE     = 'replace';
const FILTER_SPECIAL     = 'special';
const FILTER_SPECIALFULL = 'specialFull';
const FILTER_STRING      = 'string';
const FILTER_STRIPTAGS   = 'striptags';
const FILTER_TRIM        = 'trim';
const FILTER_UPPER       = 'upper';
const FILTER_UPPERFIRST  = 'upperFirst';
const FILTER_UPPERWORDS  = 'upperWords';
const FILTER_URL         = 'url';

Saneamiento de Datos

Es el proceso de desinfección o saneamiento que elimina caracteres específicos de un valor, bien por ser innecesarios o bien por ser indeseados por el usuario o aplicación. Al desinfectar la entrada nos aseguramos que la integridad de las aplicaciones permanecerá intacta.

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();
$locator = $factory->newInstance();

// '[email protected]'
$locator->sanitize('some(one)@exa\mple.com', 'email');

// 'hello'
$locator->sanitize('hello<<', 'string');

// '100019'
$locator->sanitize('!100a019', 'int');

// '100019.01'
$locator->sanitize('!100a019.01a', 'float');

Controladores

Puede acceder al objeto Phalcon\Filter desde sus controladores al acceder a los datos de la entrada GET o POST (a través del objeto de la petición). El primer parámetro es el nombre de la variable que se desea obtener; el segundo es el filtro que se desea aplicar. El segundo parámetro también puede ser una matriz con todos los limpiadores a utilizar.

<?php

use Phalcon\Filter;
use Phalcon\Http\Request;
use Phalcon\Mvc\Controller;

/**
 * Class ProductsController
 * 
 * @property Request $request
 */
class ProductsController extends Controller
{
    public function saveAction()
    {
        if (true === $this->request->isPost()) {
            $price = $this->request->getPost('price', 'double');

            $email = $this->request->getPost(
                'customerEmail',
                Filter::FILTER_EMAIL
            );
        }
    }
}

Parámetros de la Acción

Si usa Phalcon\Di\FactoryDefault como contenedor DI, Phalcon\Filter está registrado con los saneadores por defecto. Para emplearlo se utiliza la palabra clave filter. Si no usa el contenedor Phalcon\Di\FactoryDefault, necesita configurar el servicio, para que esté accesible en sus controladores.

A continuación un ejemplo de cómo limpiar los valores pasados a las acciones del controlador:

<?php

use Phalcon\Filter;
use Phalcon\Mvc\Controller;

/**
 * Class ProductsController
 * 
 * @property Filter $filter
 */
class ProductsController extends Controller
{
    public function showAction($productId)
    {
        $productId = $this->filter->sanitize($productId, 'absint');
    }
}

Filtrado de Datos

Phalcon\Filter filtra y sanea los datos, dependiendo de los saneadores usados. Por ejemplo, el limpiador trim eliminará todos los espacios antes y después de la entrada sin afectar su contenido. La descripción de cada saneador (ver Saneadores Incorporados) puede ayudarle a entender y usar los saneadores acorde a sus necesidades.

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();

$locator = $factory->newInstance();

// 'Hello'
$locator->sanitize('<h1>Hello</h1>', 'striptags');

// 'Hello'
$locator->sanitize('  Hello   ', 'trim');

Añadir Saneadores

Puede añadir sus propios saneadores a Phalcon\Filter. El nuevo limpiador puede ser una función anónima cuando se inicializa el localizador:

<?php

use Phalcon\Filter;

$services = [
    'md5' => function ($input) {
        return md5($input);
    },
];

$locator = new Filter($services);

$sanitized = $locator->sanitize($value, 'md5');

Si ya tiene un objeto localizador de filtro instanciado (si ha usado Phalcon\Filter\FilterFactory y newInstance() por ejemplo), entonces puede simplemente añadir el filtro personalizado:

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();

$locator = $factory->newInstance();

$locator->set(
    'md5',
    function ($input) {
        return md5($input);
    }
);

$sanitized = $locator->sanitize($value, 'md5');

O, si lo prefiere, puede implementar el filtro en una clase:

<?php

use Phalcon\Filter\FilterFactory;

class IPv4
{
    public function __invoke($value)
    {
        return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
    }
}

$factory = new FilterFactory();

$locator = $factory->newInstance();

$locator->set(
    'ipv4',
    new Ipv4()
);

// Sanitize with the 'ipv4' filter
$filteredIp = $locator->sanitize('127.0.0.1', 'ipv4');

Combinación de limpiadores

Hay ocasiones en las que usar un solo limpiador no es suficiente para sanear los datos. Un caso muy común, por ejemplo, es el uso de los limpiadores striptags y trim para las entradas de texto. El componente Phalcon\Filter ofrece la habilidad de aceptar un vector con el nombre de los saneadores a aplicar sobre los valores de la entrada. Por ejemplo:

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();

$locator = $factory->newInstance();

// Returns 'Hello'
$locator->sanitize(
    '   <h1> Hello </h1>   ',
    [
        'striptags',
        'trim',
    ]
);

Esta cualidad también se puede utilizar con el objeto Phalcon\Http\Request, cuando se utilizan los métodos getQuery() y getPost() para procesar las entradas GET y POST. Por ejemplo:

<?php

use Phalcon\Filter;
use Phalcon\Http\Request;
use Phalcon\Mvc\Controller;

/**
 * Class ProductsController
 * 
 * @property Request $request
 */
class ProductsController extends Controller
{
    public function saveAction()
    {
        if (true === $this->request->isPost()) {
            $message =  $this->request->getPost(
                '   <h1> Hello </h1>   ',
                [
                    'striptags',
                    'trim',
                ]
            );

        }
    }
}

Saneador Personalizado

Se puede implementar un limpiador personalizado como función anónima. Sin embargo, si prefieres usar una clase como limpiador, todo lo que necesitas hacer es hacerlo de una manera llamable, implementando el método __invoke con los parámetros relevantes.

<?php

use Phalcon\Filter\FilterFactory;

$factory = new FilterFactory();

$locator = $factory->newInstance();

$locator->set(
    'md5',
    function ($input) {
        return md5($input);
    }
);

$sanitized = $locator->sanitize($value, 'md5');

O también se puede implementar el limpiador en una clase:

<?php

use Phalcon\Filter\FilterFactory;

class IPv4
{
    public function __invoke($value)
    {
        return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
    }
}

$factory = new FilterFactory();

$locator = $factory->newInstance();

$locator->set(
    'ipv4',
    function () {
        return new Ipv4();
    }
);

// Sanitize with the 'ipv4' filter
$filteredIp = $locator->sanitize('127.0.0.1', 'ipv4');