Blog sobre desarrollo WordPress en Español Desarrollo WordPress en Español
sanitizing

Sanitizando: cómo validar y escapar datos en WordPress

En éste artículo vamos a aprender a hacer un tratamiento de datos correcto en WordPress. Éste punto es imprescindible para cualquier desarrollo a medida que hagas, ya sea un tema, un plugin, una página de ajustes y/o configuraciones, o un formulario en el que se envían y guardan datos.

Éstas prácticas son imprescindibles para fortalecer la seguridad de nuestro desarrollo. Si tenemos un formulario con un input y hacemos submit, recibiremos el valor de ese input por $_GET o $_POST y probablemente lo guardemos en base de datos. Veremos cómo proteger posibles inyecciones de código no deseado a través de un ejemplo en el que detallaré diferentes tipos de sanitización para diferentes tipos de datos.

El ejemplo: Un formulario con los campos nombre *, e-mail *, dirección y código postal. Vamos a dividirlo en 3 fases: validación del dato enviado, guardado en base de datos, y obtención del dato para mostrarlo.

 

Validando los datos

Lo primero es verificar que el usuario ha introducido los datos correctamente, es decir, comprobaremos que estamos recibiendo lo que esperamos recibir. En éste ejemplo el campo Nombre es obligatorio, por lo tanto comprobaremos que no está vacío. En el caso del campo e-mail que también es obligatorio, verificaremos que no esté vacío y que realmente el usuario ha introducido una cadena de texto con formato de e-mail y respecto al código postal verificaremos que hemos recibido una cadena númerica de 5 cifras.

La validación de los datos es el primer paso a realizar en el procesado de cualquier formulario, de este modo podremos avisar al usuario de que hemos recibido algún dato que no tiene el formato correcto o no cumple con lo que esperábamos recibir, mejorando la experiencia de usuario y evitando descuageringar nuestra base de datos.

¿Cómo hacemos esto? Pues hay varias formas. Resumiendo, podemos hacer esta validación desde el lado del cliente antes de enviar el formulario, o desde el lado del servidor una vez enviado, aunque lo ideal es hacerlo de las dos formas.

Desde el lado del cliente al input e-mail le asignaremos el type=”email” y al código postal le estableceremos una longitud máxima de 5 caracteres. Además, los campos Nombre e E-mail son obligatorios, por lo tanto añadiremos el atributo required a estos inputs. Nuestro formulario quedaría así:

<form name="my-form" action="" method="post"> <div class="form-group"> <label for="name">Nombre *</label> <input type="text" name="name" placeholder="Introduce tu nombre" required aria-required="true"> </div> <div class="form-group"> <label for="email">E-mail *</label> <input type="email" name="email" placeholder="Introduce tu e-mail" required aria-required="true"> </div> <div class="form-group"> <label for="address">Dirección</label> <input type="text" name="address" placeholder="Introduce tu dirección"> </div> <div class="form-group"> <label for="postalcode">Código Postal</label> <input type="text" name="postalcode" maxlength="5" placeholder="Introduce tu Código Postal"> </div> <button type="submit" name="btn-submit">Enviar</button> </form>

Nota

Si queremos dar soporte a navegadores obsoletos o que no soportan HTML5 podremos utilizar librerías de validación tipo jQueryValidate

 

Lo siguiente es hacer la comprobación desde el lado del servidor, es decir, con PHP y usando funciones de WordPress así como la clase WP_Error, para avisar al usuario y no continuar con el procesado de los datos en caso de encontrar algo que no coincida con lo que esperábamos recibir:

<?php if (isset( $_POST['btn-submit'] )) { //El formulario ha sido enviado global $reg_errors; $reg_errors = new WP_Error; //Comprobamos que los campos obligatorios no están vacios if ( empty( $_POST['name'] ) ) { $reg_errors->add("empty-name", "El campo nombre es obligatorio"); } if ( empty( $_POST['email'] ) ) { $reg_errors->add("empty-email", "El campo e-mail es obligatorio"); } //Comprobamos que el email tenga un formato de email válido if ( !is_email( $_POST['email'] ) ) { $reg_errors->add( "invalid-email", "El e-mail no tiene un formato válido" ); } //Comprobamos que código postal tenga una longitud de 5 caracteres if ( strlen( $_POST['postalcode'] ) != 5 ) { $reg_errors->add( "invalid-postalcode", "El Código Postal debe tener 5 caracteres" ); } if ( is_wp_error( $reg_errors ) ) { if (count($reg_errors->get_error_messages()) > 0) { foreach ( $reg_errors->get_error_messages() as $error ) {?> <p><?php echo $error;?></p> <?php } } } }?>

Para validar e-mails podemos usar la función de WordPress is_mail(), que devolverá true en caso de que la cadena tenga formato de e-mail, false en caso contrario. Podríamos validar cualquier tipo de campo mediante el uso de expresiones regulares, aquí algunos ejemplos:

//Comprobar si tiene formato de usuario de twitter if (!preg_match('/^[A-Za-z0-9_]{1,15}$/', $_POST['twitter_user'])) { $reg_errors->add( "invalid-twitter-user", "El usuario de twitter no tiene un formato válido" ); } //Comprobar si tiene formato de usuario de facebook if (!preg_match('/^[a-z\d\.]{5,}$/', $_POST['facebook_user'])) { $reg_errors->add( "invalid-facebook-user", "El usuario de facebook no tiene un formato válido" ); } //Comprobar que una contraseña tenga al menos una mayúscula, una minúscula, un número o carácter especial y mínimo 8 caracteres if (!preg_match('/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/', $_POST['password'])) { $reg_errors->add( "invalid-password", "La contraseña requiere al menos una mayúscula, una minúscula, un número o carácter especial y mínimo 8 caracteres" ); } //Comprobar ISBN if (!preg_match('/(?:(?=.{17}$)97[89][ -](?:[0-9]+[ -]){2}[0-9]+[ -][0-9]|97[89][0-9]{10}|(?=.{13}$)(?:[0-9]+[ -]){2}[0-9]+[ -][0-9Xx]|[0-9]{9}[0-9Xx])/', $_POST['isbn'])) { $reg_errors->add( "invalid-isbn", "El ISBN introducido no tiene un formato válido" ); }

 

Guardado en base de datos

Una vez procesado el formulario tanto desde el lado del cliente como del lado de servidor, guardamos los datos en base de datos.

En el caso del campo nombre, hemos dispuesto solamente que sea obligatorio, pero la persona que rellena el formulario puede escribir una “a” y sería perfectamente válido ya que no está vacío. En este campo una persona podría introducir caracteres extraños o intentar hacer una inyección de código malicioso y pasaría nuestra validación.

Antes de guardar los datos, debemos sanitizarlos para limpiar posibles ataques, usando las funciones de limpieza de datos que nos provee WordPress. Estas funciones chequean que los caracteres estén codificados sobre UTF-8, convierten el carácter “<” en entidad HTML y eliminan etiquetas, líneas rotas, tabulaciones y espacios en blanco sobrantes:

  • sanitize_email()
  • sanitize_file_name()
  • sanitize_html_class()
  • sanitize_key()
  • sanitize_meta()
  • sanitize_mime_type()
  • sanitize_option()
  • sanitize_sql_orderby()
  • sanitize_text_field()
  • sanitize_title()
  • sanitize_title_for_query()
  • sanitize_title_with_dashes()
  • sanitize_user()

 

Para nuestro ejemplo usaremos sanitize_email() y sanitize_text_field(). Suponiendo que nuestro ejemplo actualice los datos de un CPT:

update_post_meta( $post_id, 'user_name', sanitize_text_field($_POST["name"])); update_post_meta( $post_id, 'user_email', sanitize_email($_POST["email"])); update_post_meta( $post_id, 'user_address', sanitize_text_field($_POST["address"])); update_post_meta( $post_id, 'user_postalcode', sanitize_text_field($_POST["postalcode"])); 

 

Mostrando el dato

Para mostrar el dato, WordPress también nos ofrece una serie de funciones de seguridad, escapando lo que tenemos guardado en base de datos:

  • esc_html()
  • esc_url()
  • esc_js()
  • esc_attr()
  • esc_textarea()

 

Cuando queramos mostrar un dato en cualquiera de nuestras plantillas:

echo esc_attr(get_post_meta( $post_id, 'user_name', true )); echo esc_attr(get_post_meta( $post_id, 'user_email', true )); echo esc_attr(get_post_meta( $post_id, 'user_address', true )); echo esc_attr(get_post_meta( $post_id, 'user_postalcode', true ));

Puedes tener un formulario para la recogida de datos y obviar estas recomendaciones…y funcionará, pero es inseguro y deja una puerta abierta a posibles ataques. Poner en práctica estas recomendaciones lleva más tiempo y aumentan el presupuesto final, pero mejorarás la experiencia de usuario y la seguridad de tu sitio.

Puede que también te interese

Optimizando el código y las consultas a base de datos para mejorar el rendimiento
Optimizando el código y las consultas a base de datos para mejorar el rendimiento
Optimizar el código y las consultas a base de datos es algo fundamental para cualquier desarrollo web, sobretodo si estás desarrollando un proyecto para sitios…
WP-CLI Parte 7, importar y exportar contenido
WP-CLI Parte 7, importar y exportar contenido
1. Instalación y primeros pasos 2. Instalando WordPress y primeros pasos y configuraciones 3. Trabajando con posts 4. Trabajando con usuarios 5. Trabajando con la…
Deshabilitar página de categorías o etiquetas
Deshabilitar página de categorías o etiquetas
Como sabrás, WordPress por defecto tiene dos taxonomías para las entradas o posts de tu sitio: categorías y etiquetas. Estas taxonomías te permiten categorizar o…
Elimina las columnas de Yoast SEO en los listados de posts
Elimina las columnas de Yoast SEO en los listados de posts
Es bastante probable que hayas utilizado un plugin para trabajar el SEO de tu web, o la de alguno de tus clientes. De hecho mucha…