Resumo : neste tutorial, você aprenderá a construir uma biblioteca de validação PHP reutilizável do zero.
Nos tutoriais anteriores, você aprendeu como validar um campo de formulário usando as funções filter_input()
e filter_var()
. Por exemplo, o seguinte limpa e valida o email
campo na POST
solicitação:
// validate email
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$inputs['email'] = $email;
if ($email) {
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
if (!$email) {
$errors['email'] = 'Please enter a valid email';
}
} else {
$errors['email'] = 'Please enter an email';
}
Linguagem de código: PHP ( php )
Este código funciona bem. No entanto, é bastante demorado. Além disso, não é reutilizável. Então, vamos construir uma biblioteca de validação reutilizável.
Definir regras de validação
Cada campo possui uma ou mais regras de validação. Por exemplo, o email
campo é obrigatório e deve ser um endereço de e-mail válido, portanto o campo de e-mail tem duas regras:
- obrigatório
O username
é obrigatório e tem entre 3 e 255 caracteres. Além disso, deve conter apenas letras e números. Portanto, o username
campo possui três regras:
- obrigatório
- entre 3 e 20 caracteres
- alfanumérico
Para definir regras para campos, você pode definir um $fields
array como este:
$fields = [
'email'=> 'required | email',
'username' => 'required | alphanumeric | between: 3,255
];
Linguagem de código: PHP ( php )
Cada elemento da $fields
matriz tem o key
nome do campo e o valor como regras. Você usa o | personagem para separar duas regras.
Se uma regra tiver parâmetros, por exemplo, between: 3, 25
, você utiliza o :
caractere para separar o nome da regra e seus parâmetros. Além disso, usamos a vírgula ,
para separar dois parâmetros.
Você criará as seguintes regras:
Regra | Nome da regra | Parâmetro | Significado |
---|---|---|---|
obrigatório | obrigatório | Não | O campo está definido e não vazio |
alfanumérico | alfanumérico | Não | O campo contém apenas letras e números |
Não | O campo é um endereço de e-mail válido | ||
seguro | seguro | Não | O campo deve ter entre 8 e 64 caracteres e conter pelo menos um número, uma letra maiúscula, uma letra minúscula e um caractere especial. Esta regra é para o campo de senha. |
min: 3 | min | Um número inteiro especifica o comprimento mínimo do campo | O comprimento do campo deve ser maior ou igual ao comprimento mínimo, por exemplo, 3 |
máximo: 255 | máx. | Um número inteiro especifica o comprimento máximo do campo | O comprimento do campo deve ser menor ou igual ao comprimento mínimo, por exemplo, 255 |
mesmo: outro_campo | mesmo | O nome de outro campo | O valor do campo deve ser igual ao valor de another_field |
entre: mínimo, máximo | entre | min e max são números inteiros que especificam o comprimento mínimo e máximo do campo | O comprimento do campo deve estar entre mínimo e máximo. |
único: tabela, coluna | exclusivo | coluna e tabela em um banco de dados relacional. Ou campo e coleção em um banco de dados NoSQL | O valor do campo deve ser exclusivo na coluna da tabela em um banco de dados |
O exemplo a seguir define os campos com regras:
$fields = [
'firstname' => 'required, max:255',
'lastname' => 'required, max: 255',
'address' => 'required | min: 10, max:255',
'zipcode' => 'between: 5,6',
'username' => 'required | alphanumeric | between: 3,255 | unique: users,username',
'email' => 'required | email | unique: users,email',
'password' => 'required | secure',
'password2' => 'required | same:password'
];
Linguagem de código: PHP ( php )
A função validar()
A biblioteca de validação deve ter a validate()
função que aceita um array associativo de dados para validar $data
e o $fields
array que contém as regras de validação:
function validate(array $data, array $fields)
Linguagem de código: PHP ( php )
Deve retornar um array que contém os erros de validação, em que a chave de cada elemento é o nome do campo e o valor é a mensagem de erro:
function validate(array $data, array $fields): array
{
// implementation
}
Linguagem de código: PHP ( php )
A validate()
função precisará iterar sobre o $fields
. Para cada campo, ele percorre as regras e valida o valor em relação a cada regra. Se a validação falhar, uma mensagem de erro será adicionada a um $errors
array:
function validate(array $data, array $fields) : array
{
$errors = [];
foreach ($fields as $field => $option) {
// get the rules of the field
$rules = split($option);
foreach ($rules as $rule) {
// run a validation rule for each field
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Como as regras de um campo são uma string, você precisa separar as regras usando o |
caractere. Além disso, você precisa remover todos os espaços em branco. Para fazer isso, você pode definir uma função de seta para:
- Primeiro, divida uma string por um separador.
- Em seguida, corte cada item na matriz de resultados e retorne-o.
A função de seta ficará assim:
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
Linguagem de código: PHP ( php )
A função de seta aceita uma string e um separador. A explode()
função divide o $str
por $separator
. O resultado da explode()
função é um array de strings.
A array_map()
função executa a trim()
função em cada item e retorna um novo array de itens com os espaços em branco removidos.
A função validar() é atualizada para incluir a função de seta da seguinte forma:
function validate(array $data, array $fields)
{
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
$errors = [];
foreach ($fields as $field => $option) {
// get the rules of the field
$rules = $split($option, '|');
foreach ($rules as $rule) {
// run a validation on each rule
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Podem $rule
ou não ter parâmetros. Se tiver parâmetros, conterá o :
caractere. O código a seguir extrai o nome da regra e seus parâmetros:
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($$param_str, ',');
} else {
$rule_name = trim($rule);
}
Linguagem de código: PHP ( php )
Você usa a $split
função de seta neste código para dividir a regra pelo :
caractere. Por exemplo:
between: 3,255
Linguagem de código: PHP ( php )
se tornará duas strings:
'between'
'3,255'
Linguagem de código: PHP ( php )
O seguinte usa a desestruturação do array para atribuir o primeiro e o segundo elementos do resultado da $split
função ao $rule_name
and $param_str
:
[$rule_name, $param_str] = $split($rule, ':');
Linguagem de código: PHP ( php )
Por exemplo, a regra "between : 3, 255"
resultará em:
$rule_name = 'between';
$param_str = '3, 255'
Linguagem de código: PHP ( php )
Para obter a lista de parâmetros, você passa o $param_str
para a $split()
função:
$params = $split($param_str, ',');
Linguagem de código: PHP ( php )
A validate()
função ficará parecida com a seguinte:
function validate(array $data, array $fields): array
{
$errors = [];
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
$params = [];
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Agora você tem campos e seus nomes de regras com parâmetros.
Para executar a validação para cada regra, você pode ter uma if-elseif
declaração grande como esta:
if($rule_name === 'required') {
} elseif($rule_name === 'email') {
} ...
Linguagem de código: PHP ( php )
No entanto, esta abordagem tem dois problemas:
- Primeiro, é difícil manter um grande if-elseif.
- Segundo, se quiser adicionar uma nova regra, você precisará alterar a função activate(), o que não é o ideal.
Você deseja que a função validar() seja mais dinâmica para que não precisemos alterar a função quando você adicionar uma nova regra posteriormente. Para fazer isso, você pode usar a variável funções .
Para cada regra, você chama a função de validação dinamicamente assim:
$rule_name($data, $field, ...$params);
Linguagem de código: PHP ( php )
O primeiro e o segundo argumentos da função de validação são $data
e $field
. O terceiro argumento é uma lista de argumentos espalhados pelo array $params
.
Por exemplo, se $params
for [3,255]
, ...$params
retornará 3 e 255.
Portanto, a regra 'between: 3, 255'
do username
com o valor "john"
resultará na seguinte chamada de função:
between($data, 'username', 3, 255)
Linguagem de código: PHP ( php )
Para evitar que a função de validação colida com a função padrão como min
, você pode prefixar nossa função de validação com a string is_
. Por exemplo, a between
regra executará a is_between
função de validação.
O seguinte mostra a validate()
função atualizada:
function validate(array $data, array $fields): array
{
$errors = [];
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
$params = [];
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
$fn = 'is_' . $rule_name;
if (is_callable($fn)) {
$pass = $fn($data, $field, ...$params);
}
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Nesta validate()
função, você usa a is_callable()
função para verificar se is_rule_name
pode ser chamada antes de chamá-la.
Retornando mensagens de erro
Cada regra deve ter uma mensagem de erro específica. Se a validação falhar, você precisará armazenar a mensagem de erro no $error
array. Além disso, você poderá retornar uma mensagem de erro com os parâmetros.
Por exemplo, se a seguinte regra falhar:
'username' => 'between: 3, 255'
Linguagem de código: PHP ( php )
Você deve retornar a mensagem de erro:
The username should be between 3 and 255 characters.
Linguagem de código: PHP ( php )
Para fazer isso, primeiro você define as mensagens de erro de validação padrão:
const DEFAULT_VALIDATION_ERRORS = [
'required' => 'Please enter the %s',
'email' => 'The %s is not a valid email address',
'min' => 'The %s must have at least %s characters',
'max' => 'The %s must have at most %s characters',
'between' => 'The %s must have between %d and %d characters',
'same' => 'The %s must match with %s',
'alphanumeric' => 'The %s should have only letters and numbers',
'secure' => 'The %s must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and one special character',
'unique' => 'The %s already exists',
];
Linguagem de código: PHP ( php )
Na DEFAULT_VALIDATION_ERRORS
matriz, a chave é o nome da regra, enquanto o valor é a mensagem de erro. A mensagem de erro possui %s
espaços %d
reservados para que você possa usar a sprintf()
função para formatar a mensagem de erro com parâmetros como este:
sprintf(DEFAULT_VALIDATION_ERRORS[$rule_name], $field, ...$params);
Linguagem de código: PHP ( php )
Aqui está a validate()
função com mensagens de erro:
function validate(array $data, array $fields): array
{
$errors = [];
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
$params = [];
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
$fn = 'is_' . $rule_name;
if (is_callable($fn)) {
$pass = $fn($data, $field , ...$params);
if (!$pass) {
$errors[$field] = sprintf(DEFAULT_VALIDATION_ERRORS[$rule_name], $field, ...$params);
}
}
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Adicionando mensagens de erro personalizadas
A validate()
função usa as mensagens de erro padrão. No entanto, às vezes, você precisa passar nossa mensagem de erro personalizada.
Por exemplo, você pode querer usar uma mensagem como 'The username is required'
a required
regra em vez de usar a padrão.
Para fazer isso, você pode adicionar um terceiro parâmetro à validate()
função para armazenar as mensagens de erro personalizadas. Este parâmetro é uma matriz de itens cuja chave é o nome do campo e o valor é a mensagem de erro. Por exemplo:
['required' => 'The %s is required']
Linguagem de código: PHP ( php )
Se você passar o array de mensagens de erro personalizado para a validate()
função, ele será usado em vez do padrão.
Aqui está a validate()
função com as mensagens de erro personalizadas:
function validate(array $data, array $fields, array $messages = []): array
{
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
// set the validation messages
$validation_errors = array_merge(DEFAULT_VALIDATION_ERRORS, $messages);
$errors = [];
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
$params = [];
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
$fn = 'is_' . $rule_name;
if (is_callable($fn)) {
$pass = $fn($data, $field, ...$params);
if (!$pass) {
$errors[$field] = sprintf($validation_errors[$rule_name], $field, ...$params);
}
}
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Na validate()
função:
Primeiro, mescle as mensagens de erro padrão com as mensagens de erro personalizadas. A mensagem de erro personalizada substituirá as mensagens de erro padrão:
$validation_errors = array_merge(DEFAULT_VALIDATION_ERRORS, $messages);
Linguagem de código: PHP ( php )
Segundo, obtenha as mensagens de erro do array $validation_errors
em vez do DEFAULT_VALIDATION_ERRORS
array:
$errors[$field] = sprintf($validation_errors[$rule_name], $field, ...$params);
Linguagem de código: PHP ( php )
Adicione uma mensagem de erro personalizada para cada campo e regra
Até agora, uma mensagem de erro personalizada é aplicada a uma regra específica de todos os campos. Por exemplo:
['required' => 'The % is required']
Linguagem de código: CSS ( css )
E você tem dois campos:
[
'username' => 'required',
'password' => 'required'
]
Linguagem de código: PHP ( php )
A mensagem de erro personalizada será aplicada aos campos username
e password
.
Às vezes, você deseja aplicar uma mensagem de erro personalizada para um campo específico. Por exemplo, você deseja que a regra obrigatória do nome de usuário tenha uma mensagem como:
Please use your username to sign in
Linguagem de código: PHP ( php )
E a mensagem de erro personalizada para o campo de senha é:
Use your password to sign in
Linguagem de código: PHP ( php )
Para fazer isso, você precisa aprimorar a validate()
função:
function validate(array $data, array $fields, array $messages = []): array
Linguagem de código: PHP ( php )
A $messages
variável terá a seguinte aparência para oferecer suporte a uma mensagem personalizada para uma regra e um campo específicos:
[
'required' => 'The %s is required',
'username' => ['required'=> 'Please use your username to sign in']
]
Linguagem de código: PHP ( php )
O primeiro elemento definirá a mensagem de erro para a regra obrigatória de todos os campos:
'required' => 'The %s is required'
Linguagem de código: PHP ( php )
E o segundo elemento definirá a mensagem de erro para a regra necessária do nome de usuário:
'username' => ['required'=> 'Please use your username to sign in']
Linguagem de código: PHP ( php )
Se o valor do elemento for uma string, será a mensagem de erro de uma regra de todos os campos. A chave é o nome da regra e o valor é uma mensagem de erro.
Entretanto, se o valor do elemento for um array, a chave será o nome do campo e o valor será um array de regras e mensagens de erro.
O seguinte retorna uma matriz que contém uma lista de regras e mensagens de erro:
$rule_messages = array_filter($messages, fn($message) => is_string($message));
Linguagem de código: PHP ( php )
Depois de ter esse $rule_messages
array, você pode mesclá-lo com as mensagens de erro padrão:
$validation_errors = array_merge(DEFAULT_VALIDATION_ERRORS, $rule_messages);
Linguagem de código: PHP ( php )
A seguir, obtém-se a mensagem de erro para um campo e uma regra, se existir:
$message[$field][$rule]
Linguagem de código: PHP ( php )
Caso contrário, você pode receber a mensagem de erro acima $validation_errors
:
$validation_errors[$rule_name]
Linguagem de código: PHP ( php )
Veja a seguir a validate()
função com a nova lógica para mensagens de erro personalizadas:
/**
* Validate
* @param array $data
* @param array $fields
* @param array $messages
* @return array
*/
function validate(array $data, array $fields, array $messages = []): array
{
// Split the array by a separator, trim each element
// and return the array
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
// get the message rules
$rule_messages = array_filter($messages, fn($message) => is_string($message));
// overwrite the default message
$validation_errors = array_merge(DEFAULT_VALIDATION_ERRORS, $rule_messages);
$errors = [];
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
// get rule name params
$params = [];
// if the rule has parameters e.g., min: 1
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
// by convention, the callback should be is_<rule> e.g.,is_required
$fn = 'is_' . $rule_name;
if (is_callable($fn)) {
$pass = $fn($data, $field, ...$params);
if (!$pass) {
// get the error message for a specific field and rule if exists
// otherwise get the error message from the $validation_errors
$errors[$field] = sprintf(
$messages[$field][$rule_name] ?? $validation_errors[$rule_name],
$field,
...$params
);
}
}
}
}
return $errors;
}
Linguagem de código: PHP ( php )
Até agora, você completou a validate()
função. Vamos definir a função de validação para cada regra.
Funções de validação
Cada função de validação deve ter a seguinte assinatura:
function validation_function(array $data, string $field, ....$params) : bool
Linguagem de código: PHP ( php )
regra obrigatória
A is_required()
função a seguir retorna verdadeiro se o valor estiver definido e não vazio:
function is_required(array $data, string $field): bool
{
return isset($data[$field]) && trim($data[$field]) !== '';
}
Linguagem de código: PHP ( php )
regra de e-mail
A is_email()
função a seguir retorna verdadeiro se o valor for um endereço de e-mail válido:
function is_email(array $data, string $field): bool
{
if (empty($data[$field])) {
return true;
}
return filter_var($data[$field], FILTER_VALIDATE_EMAIL);
}
Linguagem de código: PHP ( php )
Se $data[$field]
não estiver definido ou vazio, a is_email()
função também retornará true
.
regra mínima
A is_min()
função a seguir retorna verdadeiro se o comprimento do valor do campo for maior ou igual a $min:
function is_min(array $data, string $field, int $min): bool
{
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) >= $min;
}
Linguagem de código: PHP ( php )
regra máxima
A is_max()
função a seguir retorna verdadeiro se o comprimento do valor do campo for menor ou igual a $max:
function is_max(array $data, string $field, int $max): bool
{
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) <= $max;
}
Linguagem de código: PHP ( php )
entre regra
A is_between()
função a seguir retorna true
se o comprimento do valor do campo estiver entre $min
e $max
:
function is_between(array $data, string $field, int $min, int $max): bool
{
if (!isset($data[$field])) {
return true;
}
$len = mb_strlen($data[$field]);
return $len >= $min && $len <= $max;
}
Linguagem de código: PHP ( php )
regra alfanumérica
O is_alphanumeric()
retorna verdadeiro se o valor do campo contiver apenas letras ou caracteres:
function is_alphanumeric(array $data, string $field): bool
{
if (!isset($data[$field])) {
return true;
}
return ctype_alnum($data[$field]);
}
Linguagem de código: PHP ( php )
mesma regra
A is_same()
função retorna true
se o valor do campo for igual ao valor do outro campo:
function is_same(array $data, string $field, string $other): bool
{
if (isset($data[$field], $data[$other])) {
return $data[$field] === $data[$other];
}
if (!isset($data[$field]) && !isset($data[$other])) {
return true;
}
return false;
}
Linguagem de código: PHP ( php )
regra segura
O is_secure()
retorno é verdadeiro se o valor do campo deve ter entre 8 e 64 caracteres e conter pelo menos um número, uma letra maiúscula, uma letra minúscula e um caractere especial:
function is_secure(array $data, string $field): bool
{
if (!isset($data[$field])) {
return false;
}
$pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#";
return preg_match($pattern, $data[$field]);
}
Linguagem de código: PHP ( php )
regra única
Para a unique
regra, você precisa de uma conexão com o banco de dados e selecionar o valor $column
especificado $table
nos parâmetros da regra.
Primeiro, crie um novo arquivo chamado database.php
na config
pasta e adicione as seguintes constantes:
<?php
const DB_HOST = 'localhost';
const DB_NAME = 'auth';
const DB_USER = 'root';
const DB_PASSWORD = '';
Linguagem de código: PHP ( php )
Segundo, carregue config/database.php
e defina uma função para conectar-se ao banco de dados :
function db()
{
static $pdo;
if (!$pdo) {
$pdo = connect(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
}
return $pdo;
}
Linguagem de código: PHP ( php )
A is_unique()
função a seguir retorna verdadeiro se o valor for $column
único $table
:
function is_unique(array $data, string $field, string $table, string $column): bool
{
if (!isset($data[$field])) {
return true;
}
$sql = "SELECT $column FROM $table WHERE $column = :value";
$stmt = db()->prepare($sql);
$stmt->bindValue(":value", $data[$field]);
$stmt->execute();
return $stmt->fetchColumn() === false;
}
Linguagem de código: PHP ( php )
Juntando tudo
O seguinte mostra todas as funções na biblioteca de validação:
<?php
require __DIR__ . '/../config/database.php';
const DEFAULT_VALIDATION_ERRORS = [
'required' => 'Please enter the %s',
'email' => 'The %s is not a valid email address',
'min' => 'The %s must have at least %s characters',
'max' => 'The %s must have at most %s characters',
'between' => 'The %s must have between %d and %d characters',
'same' => 'The %s must match with %s',
'alphanumeric' => 'The %s should have only letters and numbers',
'secure' => 'The %s must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and one special character',
'unique' => 'The %s already exists',
];
/**
* Validate
* @param array $data
* @param array $fields
* @param array $messages
* @return array
*/
function validate(array $data, array $fields, array $messages = []): array
{
// Split the array by a separator, trim each element
// and return the array
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
// get the message rules
$rule_messages = array_filter($messages, fn($message) => is_string($message));
// overwrite the default message
$validation_errors = array_merge(DEFAULT_VALIDATION_ERRORS, $rule_messages);
$errors = [];
foreach ($fields as $field => $option) {
$rules = $split($option, '|');
foreach ($rules as $rule) {
// get rule name params
$params = [];
// if the rule has parameters e.g., min: 1
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
// by convention, the callback should be is_<rule> e.g.,is_required
$fn = 'is_' . $rule_name;
if (is_callable($fn)) {
$pass = $fn($data, $field, ...$params);
if (!$pass) {
// get the error message for a specific field and rule if exists
// otherwise get the error message from the $validation_errors
$errors[$field] = sprintf(
$messages[$field][$rule_name] ?? $validation_errors[$rule_name],
$field,
...$params
);
}
}
}
}
return $errors;
}
/**
* Return true if a string is not empty
* @param array $data
* @param string $field
* @return bool
*/
function is_required(array $data, string $field): bool
{
return isset($data[$field]) && trim($data[$field]) !== '';
}
/**
* Return true if the value is a valid email
* @param array $data
* @param string $field
* @return bool
*/
function is_email(array $data, string $field): bool
{
if (empty($data[$field])) {
return true;
}
return filter_var($data[$field], FILTER_VALIDATE_EMAIL);
}
/**
* Return true if a string has at least min length
* @param array $data
* @param string $field
* @param int $min
* @return bool
*/
function is_min(array $data, string $field, int $min): bool
{
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) >= $min;
}
/**
* Return true if a string cannot exceed max length
* @param array $data
* @param string $field
* @param int $max
* @return bool
*/
function is_max(array $data, string $field, int $max): bool
{
if (!isset($data[$field])) {
return true;
}
return mb_strlen($data[$field]) <= $max;
}
/**
* @param array $data
* @param string $field
* @param int $min
* @param int $max
* @return bool
*/
function is_between(array $data, string $field, int $min, int $max): bool
{
if (!isset($data[$field])) {
return true;
}
$len = mb_strlen($data[$field]);
return $len >= $min && $len <= $max;
}
/**
* Return true if a string equals the other
* @param array $data
* @param string $field
* @param string $other
* @return bool
*/
function is_same(array $data, string $field, string $other): bool
{
if (isset($data[$field], $data[$other])) {
return $data[$field] === $data[$other];
}
if (!isset($data[$field]) && !isset($data[$other])) {
return true;
}
return false;
}
/**
* Return true if a string is alphanumeric
* @param array $data
* @param string $field
* @return bool
*/
function is_alphanumeric(array $data, string $field): bool
{
if (!isset($data[$field])) {
return true;
}
return ctype_alnum($data[$field]);
}
/**
* Return true if a password is secure
* @param array $data
* @param string $field
* @return bool
*/
function is_secure(array $data, string $field): bool
{
if (!isset($data[$field])) {
return false;
}
$pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#";
return preg_match($pattern, $data[$field]);
}
/**
* Connect to the database and returns an instance of PDO class
* or false if the connection fails
*
* @return PDO
*/
function db(): PDO
{
static $pdo;
// if the connection is not initialized
// connect to the database
if (!$pdo) {
$pdo = new PDO(
sprintf("mysql:host=%s;dbname=%s;charset=UTF8", DB_HOST, DB_NAME),
DB_USER,
DB_PASSWORD,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
}
return $pdo;
}
/**
* Return true if the $value is unique in the column of a table
* @param array $data
* @param string $field
* @param string $table
* @param string $column
* @return bool
*/
function is_unique(array $data, string $field, string $table, string $column): bool
{
if (!isset($data[$field])) {
return true;
}
$sql = "SELECT $column FROM $table WHERE $column = :value";
$stmt = db()->prepare($sql);
$stmt->bindValue(":value", $data[$field]);
$stmt->execute();
return $stmt->fetchColumn() === false;
}
Linguagem de código: PHP ( php )
Testando a biblioteca de validação
Para testar a unique
regra, é necessário criar um novo banco de dados e uma tabela com o username
campo, por exemplo.
Primeiro, crie um novo banco de dados chamado auth
:
CREATE DATABASE auth;
Linguagem de código: SQL (linguagem de consulta estruturada) ( sql )
Segundo, crie uma nova users
tabela:
CREATE TABLE users(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(300) NOT NULL UNIQUE
);
Linguagem de código: SQL (linguagem de consulta estruturada) ( sql )
Observe que para fins de teste, não precisamos ter o password
campo.
Terceiro, insira uma linha na users
tabela:
INSERT INTO users(username, email)
VALUES('bob', '[email protected]');
Linguagem de código: SQL (linguagem de consulta estruturada) ( sql )
O exemplo a seguir usa a validate()
função para executar um teste:
<?php
require __DIR__ . '/validation.php';
$data = [
'firstname' => '',
'username' => 'bob',
'address' => 'This is my address',
'zipcode' => '999',
'email' => 'jo@',
'password' => 'test123',
'password2' => 'test',
];
$fields = [
'firstname' => 'required, max:255',
'lastname' => 'required, max: 255',
'address' => 'required | min: 10, max:255',
'zipcode' => 'between: 5,6',
'username' => 'required | alphanumeric | between: 3,255 | unique: users,username',
'email' => 'required | email | unique: users,email',
'password' => 'required | secure',
'password2' => 'required | same:password'
];
$errors = validate($data, $fields, [
'required' => 'The %s is required',
'password2' => ['same'=> 'Please enter the same password again']]
);
print_r($errors);
Linguagem de código: PHP ( php )
Saída:
Array
(
[firstname] => The firstname is required
[lastname] => The lastname is required
[zipcode] => The zipcode must have between 5 and 6 characters
[username] => The username already exists
[email] => The email is not a valid email address
[password] => The password must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and o
ne special character
[password2] => Please enter the same password again
)
Linguagem de código: PHP ( php )
Adicionando uma nova regra de validação
Para adicionar uma nova regra, você precisa fazer duas coisas:
Primeiro, adicione uma mensagem de erro padrão ao DEFAULT_VALIDATION_ERRORS
array.
const DEFAULT_VALIDATION_ERRORS = [
// ...
new_rule => "Error message for the new rule"
];
Linguagem de código: JavaScript ( javascript )
Segundo, defina uma função de validação com a seguinte assinatura:
function is_new_rule(array $data, string $field, ....$params) : bool
Linguagem de código: PHP ( php )
Neste tutorial, você aprendeu como construir uma biblioteca de validação reutilizável em PHP.