Nesta aula, vamos construir um sistema CRUD completo em PHP. CRUD é um acrônimo para Create (criar), Read (ler), Update (atualizar) e Delete (excluir) — as quatro operações básicas de persistência em bancos de dados. Implementaremos cada uma delas usando PHP com PDO e MySQL, seguindo boas práticas de segurança e organização de código.

O objetivo é que ao final você seja capaz de criar, listar, editar e excluir registros de forma segura, com validação de dados e proteção contra SQL injection. Vamos desenvolver um gerenciador simples de usuários.

Create, Read, Update, Delete

As quatro operações CRUD são a base de qualquer aplicação que manipula dados persistentes. Em PHP, cada operação corresponde a uma instrução SQL específica e a um fluxo de requisição HTTP (GET, POST, PUT, DELETE).

  • Create (INSERT): Adiciona um novo registro ao banco. Geralmente via formulário POST.
  • Read (SELECT): Recupera registros. Pode ser uma listagem ou um único registro via GET.
  • Update (UPDATE): Altera um registro existente. Normalmente via POST com ID.
  • Delete (DELETE): Remove um registro. Pode ser via GET ou POST com confirmação.

Exemplo de código para cada operação usando PDO:

// Create
$stmt = $pdo->prepare("INSERT INTO usuarios (nome, email) VALUES (:nome, :email)");
$stmt->execute(['nome' => $nome, 'email' => $email]);

// Read (todos)
$stmt = $pdo->query("SELECT * FROM usuarios");
$usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Read (único)
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE id = :id");
$stmt->execute(['id' => $id]);
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);

// Update
$stmt = $pdo->prepare("UPDATE usuarios SET nome = :nome, email = :email WHERE id = :id");
$stmt->execute(['nome' => $nome, 'email' => $email, 'id' => $id]);

// Delete
$stmt = $pdo->prepare("DELETE FROM usuarios WHERE id = :id");
$stmt->execute(['id' => $id]);

Estrutura

Organizar o código em pastas e arquivos separados facilita a manutenção. Uma estrutura comum para um CRUD simples:

/projeto
  /config
    database.php
  /includes
    header.php
    footer.php
  /public
    index.php
    create.php
    edit.php
    delete.php
  • config/database.php: Conexão PDO com MySQL.
  • includes/header.php e footer.php: Partes comuns do HTML.
  • public/index.php: Listagem de usuários.
  • public/create.php: Formulário de criação e processamento.
  • public/edit.php: Formulário de edição e processamento.
  • public/delete.php: Confirmação e exclusão.

Exemplo de config/database.php:

setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
    die("Erro na conexão: " . $e->getMessage());
}
?>

Validação

Validar os dados antes de inserir ou atualizar é essencial para segurança e integridade. Devemos verificar se os campos obrigatórios estão preenchidos, se os formatos estão corretos (email, CPF, etc.) e sanitizar as entradas.

Exemplo de validação para nome e email:

$erros = [];

if (empty($_POST['nome'])) {
    $erros[] = 'O campo nome é obrigatório.';
} elseif (strlen($_POST['nome']) < 3) {
    $erros[] = 'O nome deve ter pelo menos 3 caracteres.';
} else {
    $nome = htmlspecialchars(trim($_POST['nome']), ENT_QUOTES, 'UTF-8');
}

if (empty($_POST['email'])) {
    $erros[] = 'O campo email é obrigatório.';
} elseif (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
    $erros[] = 'Email inválido.';
} else {
    $email = filter_var(trim($_POST['email']), FILTER_SANITIZE_EMAIL);
}

if (empty($erros)) {
    // prosseguir com INSERT ou UPDATE
} else {
    // exibir erros
}

Além disso, use prepared statements para evitar SQL injection, como já demonstrado.

Exemplo prático

Vamos criar um CRUD completo de usuários. Primeiro, a tabela SQL:

CREATE TABLE usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Agora, o arquivo index.php (listagem):

query("SELECT * FROM usuarios ORDER BY criado_em DESC");
$usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>



    
    CRUD - Listar Usuários
    


    

Usuários

Novo Usuário
ID Nome Email Criado em Ações
Editar Excluir

create.php:

prepare("INSERT INTO usuarios (nome, email) VALUES (:nome, :email)");
        $stmt->execute(['nome' => $nome, 'email' => $email]);
        header('Location: index.php');
        exit;
    }
}
?>



    
    CRUD - Criar Usuário
    


    

Novo Usuário

Cancelar

edit.php e delete.php seguem padrão similar, com prepared statements e validação.

Boas práticas

  • Sempre use prepared statements ou PDO com binding para evitar SQL injection.
  • Valide e sanitize todas as entradas do usuário.
  • Use transações para operações que envolvem múltiplas queries.
  • Nunca confie em dados vindos do cliente; verifique permissões no servidor.
  • Mantenha a lógica de negócio separada da apresentação (MVC é recomendado para projetos maiores).

Referências

Exercícios

  1. Crie um novo campo 'telefone' na tabela usuarios e implemente a validação (apenas números, mínimo 10 dígitos).
  2. ✓ Resposta:
    ALTER TABLE usuarios ADD telefone VARCHAR(20);
    // No create.php e edit.php:
    if (empty($_POST['telefone'])) {
        $erros[] = 'Telefone é obrigatório.';
    } elseif (!preg_match('/^\d{10,}$/', $_POST['telefone'])) {
        $erros[] = 'Telefone deve conter apenas números e no mínimo 10 dígitos.';
    } else {
        $telefone = preg_replace('/[^\d]/', '', $_POST['telefone']);
    }
  3. Implemente uma função de busca (Read) que filtre usuários por nome ou email usando LIKE.
  4. ✓ Resposta:
    $busca = isset($_GET['busca']) ? '%'.$_GET['busca'].'%' : '%';
    $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE nome LIKE :busca OR email LIKE :busca");
    $stmt->execute(['busca' => $busca]);
    $usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);
  5. Adicione proteção CSRF nos formulários de criação e edição.
  6. ✓ Resposta:
    // No início da sessão:
    session_start();
    if (empty($_SESSION['token'])) {
        $_SESSION['token'] = bin2hex(random_bytes(32));
    }
    $token = $_SESSION['token'];
    // No formulário:
    
    // No processamento:
    if (!hash_equals($_SESSION['token'], $_POST['token'])) {
        die('Token inválido');
    }
  7. Crie uma página de confirmação antes de excluir (em vez de usar confirm() do JavaScript).
  8. ✓ Resposta:
    // delete.php:
    prepare("DELETE FROM usuarios WHERE id = :id");
        $stmt->execute(['id' => $id]);
        header('Location: index.php');
        exit;
    }
    $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE id = :id");
    $stmt->execute(['id' => $id]);
    $usuario = $stmt->fetch(PDO::FETCH_ASSOC);
    ?>
    

    Deseja realmente excluir ?

    Cancelar
  9. Implemente paginação na listagem (exibir 10 registros por página).
  10. ✓ Resposta:
    $pagina = isset($_GET['pagina']) ? (int)$_GET['pagina'] : 1;
    $limite = 10;
    $offset = ($pagina - 1) * $limite;
    $total = $pdo->query("SELECT COUNT(*) FROM usuarios")->fetchColumn();
    $paginas = ceil($total / $limite);
    $stmt = $pdo->prepare("SELECT * FROM usuarios ORDER BY id DESC LIMIT :limite OFFSET :offset");
    $stmt->bindValue(':limite', $limite, PDO::PARAM_INT);
    $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
    $stmt->execute();
    $usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // No HTML, exibir links de paginação.