Integrar a verificação por SMS em uma aplicação PHP é uma maneira robusta de confirmar a identidade de um usuário, proteger contas e reduzir cadastros falsos. Este guia mostra como construir um fluxo de verificação passo a passo, desde a geração do código até a validação final.
Por que usar verificação por SMS em aplicações PHP?
A verificação por SMS, frequentemente usada para Autenticação de Dois Fatores (o que é 2FA), adiciona uma camada essencial de segurança. Para aplicações PHP, os benefícios são diretos:
- Validação de Usuário: Garante que o usuário por trás de um cadastro é real e possui acesso ao número de telefone informado.
- Prevenção de Fraudes: Dificulta a criação de contas em massa (bots), que podem ser usadas para spam ou abuso de serviços.
- Recuperação de Conta: Oferece um canal seguro para que usuários legítimos possam redefinir suas senhas ou recuperar o acesso à conta.
- Conformidade: Em muitos setores, a verificação de identidade é um requisito regulatório.
Frameworks modernos como Laravel e Symfony possuem ecossistemas que facilitam a integração de serviços de terceiros, incluindo APIs de SMS.
Pré-requisitos para enviar SMS com PHP
Antes de escrever a primeira linha de código, você precisa garantir que seu ambiente está preparado. A lista de requisitos é curta e direta:
- Ambiente PHP: Uma versão estável do PHP instalada (versão 8.0 ou superior é recomendada).
- Composer: O gerenciador de dependências do PHP. Ele será usado para instalar um cliente HTTP.
- Cliente HTTP: Uma biblioteca para fazer requisições à API de SMS. Guzzle é a escolha mais popular e robusta.
- Conta em uma API de SMS: Você precisará se cadastrar em um provedor de SMS, como a SMS VOLT, para obter uma chave de API (API Key).
Com esses itens, você já pode começar a implementação. O processo de como usar uma API de SMS é padronizado e se resume a enviar requisições HTTP para um endpoint específico.
Passo a passo: Implementando o fluxo de verificação
Vamos dividir o processo em cinco etapas lógicas, cobrindo desde a configuração do projeto até a validação do código inserido pelo usuário.
Passo 1: Estrutura do projeto e dependências
Crie um diretório para o seu projeto e, dentro dele, inicialize o Composer e adicione o Guzzle.
# Crie o diretório e entre nele
mkdir verificacao-php && cd verificacao-php
# Inicie um projeto composer
composer init --quiet
# Adicione o Guzzle
composer require guzzlehttp/guzzle
Isso criará um arquivo composer.json e um diretório vendor, contendo o Guzzle e suas dependências.
Passo 2: Gerar e armazenar o código OTP
O código de verificação (OTP - One-Time Password) deve ser gerado no servidor. Um código numérico de 6 dígitos é o padrão de mercado.
Crie uma função para gerar o código e armazene-o de forma temporária, associado ao usuário. A sessão do PHP ($_SESSION) é uma forma simples de fazer isso para fins de exemplo.
<?php
session_start();
function gerarCodigoOTP(int $length = 6): string {
return str_pad(random_int(0, 10**$length - 1), $length, '0', STR_PAD_LEFT);
}
// Gera o código
$codigo = gerarCodigoOTP();
// Armazena na sessão com um timestamp de expiração (ex: 5 minutos)
$_SESSION['otp'] = $codigo;
$_SESSION['otp_expires_at'] = time() + (5 * 60);
O armazenamento temporário é crucial. A validade do código deve ser curta para minimizar o risco de abuso. Saiba mais sobre quanto tempo dura um código OTP.
Passo 3: Enviar o SMS via API
Com o código gerado, o próximo passo é enviá-lo para o telefone do usuário usando a API de SMS. Usaremos o Guzzle para fazer a requisição POST.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
// ... (código de geração do OTP) ...
$apiKey = 'SUA_API_KEY'; // Substitua pela sua chave de API
$numeroDestino = '+55119XXXXXXXX'; // Número do usuário no formato E.164
$mensagem = "Seu código de verificação é: {$codigo}";
$client = new Client();
try {
$response = $client->request('POST', 'https://api.smsvolt.com.br/v1/send', [
'headers' => [
'Authorization' => 'Bearer ' . $apiKey,
'Accept' => 'application/json',
],
'json' => [
'to' => $numeroDestino,
'message' => $mensagem,
// 'from' => 'SeuNome' // Opcional, dependendo da API
]
]);
if ($response->getStatusCode() === 200) {
echo "SMS enviado com sucesso.";
} else {
echo "Falha ao enviar SMS: " . $response->getBody();
}
} catch (\GuzzleHttp\Exception\RequestException $e) {
echo "Erro na requisição: " . $e->getMessage();
}
Passo 4: Criar o formulário de verificação
Após o envio do SMS, apresente ao usuário um formulário simples para que ele possa inserir o código recebido.
<!DOCTYPE html>
<html lang="pt-br">
<head>
<title>Verificar Código</title>
</head>
<body>
<form action="validar_codigo.php" method="post">
<label for="codigo">Digite o código recebido por SMS:</label>
<input type="text" id="codigo" name="codigo" maxlength="6" required>
<button type="submit">Verificar</button>
</form>
</body>
</html>
Passo 5: Validar o código inserido pelo usuário
Crie o script validar_codigo.php para processar o formulário. Ele deve comparar o código enviado pelo usuário com o que foi armazenado na sessão e verificar se não expirou.
<?php
session_start();
$codigoUsuario = $_POST['codigo'] ?? '';
// Verifica se o código da sessão e a expiração existem
if (!isset($_SESSION['otp']) || !isset($_SESSION['otp_expires_at'])) {
die('Erro: Nenhuma verificação iniciada.');
}
// Verifica se o tempo não expirou
if (time() > $_SESSION['otp_expires_at']) {
unset($_SESSION['otp'], $_SESSION['otp_expires_at']); // Limpa a sessão
die('Código expirado. Por favor, solicite um novo.');
}
// Compara o código do usuário com o da sessão
if ($codigoUsuario === $_SESSION['otp']) {
unset($_SESSION['otp'], $_SESSION['otp_expires_at']); // Limpa a sessão após o sucesso
echo "Telefone verificado com sucesso!";
// Aqui você marcaria o usuário como verificado no banco de dados
} else {
// Se o código estiver errado, você pode implementar um contador de tentativas
die('Código inválido. Tente novamente.');
}
Se o usuário digitar um código errado, é importante saber o que fazer quando o código OTP é inválido para fornecer a orientação correta.
Boas práticas de segurança
Implementar o fluxo básico é o primeiro passo. Para uma aplicação em produção, considere estas práticas de segurança:
- Rate Limiting: Limite o número de tentativas de envio de código para um mesmo número ou endereço IP. Isso previne ataques de força bruta e o esgotamento de seus créditos de SMS. Saiba mais sobre rate limit em API de SMS.
- Variáveis de Ambiente: Nunca armazene sua chave de API diretamente no código. Use um arquivo
.enve uma biblioteca comovlucas/phpdotenvpara carregar as credenciais. - Validação de Input: Sempre valide e sanitize o número de telefone antes de enviá-lo para a API. Utilize um formato padrão como E.164. Veja como validar o formato de telefone E.164.
- HTTPS: Garanta que todas as comunicações entre seu servidor e a API de SMS ocorram sobre HTTPS para criptografar os dados em trânsito.
- Feedback Genérico: Em caso de falha na validação, retorne mensagens genéricas como "Código inválido ou expirado" para não informar a um atacante qual parte da validação falhou.
Perguntas frequentes
Preciso de uma biblioteca específica para enviar SMS em PHP?
Não necessariamente. Um cliente HTTP como o Guzzle ou até mesmo as funções curl_*() nativas do PHP são suficientes para consumir a maioria das APIs de SMS baseadas em REST. Bibliotecas apenas simplificam o processo.
Como posso testar o envio de SMS sem gastar créditos?
Alguns provedores de API oferecem um ambiente de "sandbox" ou "modo de teste". Nesse modo, a API aceita suas requisições e retorna uma resposta de sucesso, mas não dispara o SMS real, permitindo testar a lógica da sua aplicação sem custos.
É seguro enviar a chave da API em cada requisição?
Sim, desde que a comunicação seja feita via HTTPS e a chave esteja armazenada de forma segura no seu servidor (em variáveis de ambiente, por exemplo), e não exposta no código do lado do cliente (HTML/JavaScript). Este é o padrão de autenticação para a maioria das APIs REST.
Posso usar cURL em vez de Guzzle?
Sim. Guzzle é um wrapper que torna as requisições HTTP mais simples e legíveis, mas você pode obter o mesmo resultado usando as funções curl_*() do PHP. O código com cURL nativo tende a ser um pouco mais verboso, mas é igualmente eficaz.



