Como criar um arquivo de conexão seguro em PHP usando PDO e variáveis de ambiente

Hoje em dia não dá mais pra sair conectando no banco com mysqli_connect e senha escrita no meio do código.
Além de inseguro, isso vira uma bagunça quando você precisa mudar de servidor ou separar ambiente de testes e produção.

Neste guia, vou mostrar passo a passo como criar um arquivo de conexão moderno, usando:

  • PDO (interface mais segura e flexível para bancos de dados);
  • Variáveis de ambiente (para não deixar usuário e senha expostos no código);
  • Uma classe de conexão reutilizável, fácil de usar em qualquer projeto.

Objetivo: no final você terá uma classe Conexao que retorna um objeto PDO pronto para uso, sem senha exposta no código.


1. Por que evitar a conexão “antiga” em PHP

Um código assim aqui embaixo parece inocente, mas é um problema:

<?php
$servidor = "localhost";
$usuario  = "root";
$senha    = "123456";
$banco    = "meu_banco";

$conexao = mysqli_connect($servidor, $usuario, $senha, $banco);

Problemas:

  • Senha exposta no código (qualquer um que tiver acesso ao arquivo vê tudo);
  • Dificulta ter ambientes diferentes (local, teste, produção);
  • mysqli_* é mais limitado e te incentiva a cair em SQL Injection se não tomar cuidado.

Com PDO + variáveis de ambiente, você:

  • Esconde credenciais (ficam fora do repositório Git, por exemplo);
  • Usa o mesmo código para MySQL, PostgreSQL, SQL Server, etc.;
  • Ganha suporte nativo a prepared statements (segurança contra SQL Injection).

2. Estrutura básica do projeto

Uma estrutura simples que já resolve:

/meu-projeto
  /config
    Conexao.php
  /public
    index.php
  .env
  composer.json
  vendor/  (criado pelo Composer)
  • Arquivos acessados pelo navegador (como index.php) vão em /public.
  • Arquivo de conexão e outros configs ficam fora da pasta pública.
  • O arquivo .env guarda variáveis de ambiente.

3. Criando o arquivo .env com os dados do banco

Na raiz do projeto, crie um arquivo chamado .env (sem nome antes do ponto):

DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_NAME=meu_banco
DB_USER=usuario_do_banco
DB_PASS=senha_super_secreta
DB_CHARSET=utf8mb4

Importante:

  • Nunca envie o .env para repositórios públicos.
  • No Git, coloque uma linha com .env no seu .gitignore.

4. Instalando o PHP Dotenv com Composer

Vamos usar a biblioteca vlucas/phpdotenv para carregar as variáveis do .env.

No terminal, dentro da pasta do projeto, execute:

composer require vlucas/phpdotenv

Isso vai criar/atualizar o composer.json e a pasta vendor/.


5. Criando a classe de conexão com PDO (Conexao.php)

Agora vamos criar o arquivo config/Conexao.php:

<?php
namespace Config;

use PDO;
use PDOException;
use Dotenv\Dotenv;

class Conexao
{
    private static ?PDO $instancia = null;

    private function __construct()
    {
        // Evita instanciar a classe diretamente
    }

    public static function getConexao(): PDO
    {
        if (self::$instancia === null) {
            try {
                // Carrega o .env apenas uma vez
                $caminhoBase = dirname(__DIR__); // pasta raiz do projeto
                $dotenv = Dotenv::createImmutable($caminhoBase);
                $dotenv->load();

                $driver  = $_ENV['DB_DRIVER']  ?? 'mysql';
                $host    = $_ENV['DB_HOST']    ?? 'localhost';
                $porta   = $_ENV['DB_PORT']    ?? '3306';
                $banco   = $_ENV['DB_NAME']    ?? '';
                $usuario = $_ENV['DB_USER']    ?? '';
                $senha   = $_ENV['DB_PASS']    ?? '';
                $charset = $_ENV['DB_CHARSET'] ?? 'utf8mb4';

                $dsn = "{$driver}:host={$host};port={$porta};dbname={$banco};charset={$charset}";

                $opcoes = [
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    PDO::ATTR_EMULATE_PREPARES   => false,
                ];

                self::$instancia = new PDO($dsn, $usuario, $senha, $opcoes);

            } catch (PDOException $e) {
                // Em produção, registre o erro em log em vez de exibir na tela
                die("Erro ao conectar ao banco de dados: " . $e->getMessage());
            }
        }

        return self::$instancia;
    }
}

O que esse código faz

  • Usa Singleton: a conexão é criada uma única vez e reaproveitada.
  • Carrega o .env apenas na primeira chamada.
  • Configura PDO para:
    • Lançar exceções em erros (ERRMODE_EXCEPTION);
    • Retornar arrays associativos (FETCH_ASSOC);
    • Desativar emulação de prepared statements (mais seguro).

6. Usando a conexão no seu código (exemplo em index.php)

Agora vamos ver como consumir essa conexão dentro de um script.

Crie o arquivo public/index.php:

<?php
require __DIR__ . '/../vendor/autoload.php';

use Config\Conexao;

try {
    $pdo = Conexao::getConexao();

    $sql = "SELECT id, nome, email FROM usuarios LIMIT 10";
    $comando = $pdo->prepare($sql);
    $comando->execute();
    $usuarios = $comando->fetchAll();

} catch (PDOException $e) {
    die("Erro ao buscar usuários: " . $e->getMessage());
}
?>
<!doctype html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Lista de usuários</title>
</head>
<body>
    <h1>Usuários</h1>

    <?php if (empty($usuarios)): ?>
        <p>Nenhum usuário encontrado.</p>
    <?php else: ?>
        <ul>
            <?php foreach ($usuarios as $usuario): ?>
                <li>
                    <?= htmlspecialchars($usuario['nome']) ?> - 
                    <?= htmlspecialchars($usuario['email']) ?>
                </li>
            <?php endforeach; ?>
        </ul>
    <?php endif; ?>
</body>
</html>

Pontos importantes do exemplo

  • require __DIR__ . '/../vendor/autoload.php';
    Carrega automaticamente todas as classes instaladas via Composer (incluindo Conexao e Dotenv).
  • use Config\Conexao;
    Usa o namespace definido na classe.
  • htmlspecialchars()
    Protege contra XSS ao exibir conteúdo vindo do banco de dados.

7. Erros comuns e como evitar

7.1. “Class Dotenv\Dotenv not found”

Geralmente significa:

  • Composer não foi instalado/rodado;
  • Autoload não está sendo incluído.

Verifique se:

require __DIR__ . '/../vendor/autoload.php';

está correto e se a pasta vendor/ existe.


7.2. “could not find driver”

Isso quer dizer que a extensão PDO daquele banco não está habilitada no PHP (por exemplo, pdo_mysql).

No php.ini (ou no painel da hospedagem), verifique se as extensões estão habilitadas.


7.3. “Erro ao conectar ao banco de dados: Access denied…”

Verifique:

  • Usuário e senha no .env;
  • Nome do banco (DB_NAME);
  • Host (em hospedagem, às vezes o host não é localhost).

8. Checklist de segurança para sua conexão

Antes de colocar o site no ar, revise:

  • Senha e usuário não aparecem em nenhum arquivo PHP versionado;
  • Arquivo .env está fora de qualquer repositório público (adicionado ao .gitignore);
  • PDO configurado com ERRMODE_EXCEPTION;
  • Sem die($e->getMessage()) em produção (prefira logar o erro em arquivo ou serviço de log);
  • Sempre usar prepared statements (prepare + execute) para consultas com dados do usuário.

9. Vantagens práticas desse padrão

Com essa estrutura você ganha:

  • Flexibilidade: se mudar de MySQL para PostgreSQL, só ajusta o .env e a DSN;
  • Organização: todo o sistema usa a mesma classe de conexão;
  • Segurança: credenciais fora do código, uso de PDO, prepared statements;
  • Escalabilidade: fácil crescer o projeto sem virar uma bagunça de include e variáveis soltas.

Se quiser, você pode adaptar os nomes das variáveis/tabelas para o padrão que você já usa, mas mantendo a ideia central:

Conexão centralizada + PDO + .env.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima