Skip to content

Tudo para WordPress, desenvolvimento web — e não só

💾 Fazer backup e restaurar uma base de dados MySQL via PHP

💾 Fazer backup e restaurar uma base de dados MySQL via PHP

Perder uma base de dados significa perder encomendas, utilizadores e conteúdo em segundos. Para o proprietário de um site WordPress, o backup não é «bom de ter», é obrigatório. Mas iniciar sessão manualmente no phpMyAdmin todos os dias é uma perda de tempo e, quando precisa dele, o backup simplesmente não está lá.

Um script PHP resolve o problema: fornece-lhe o acesso à base de dados e ele exporta a estrutura e os dados para um ficheiro SQL. Em cinco minutos de configuração, obtém um backup programável e repetível que não se esquecerá de fazer.

A seguir: scripts prontos a usar para backup e restauro de MySQL em PHP. Vamos detalhar como funcionam, onde obter as credenciais e como executar o backup automático de forma programada para que a sua base de dados nunca fique desprotegida.

💡 Visão geral rápida:

  • Ligar ao MySQL via mysqli, obter a lista de tabelas e exportar a estrutura
  • Criar o dump SQL: CREATE TABLE mais INSERT para cada tabela, guardar em ficheiro
  • Restaurar: ler o dump e executar as consultas num lote via mysqli_multi_query
  • A automatização via Cron (Linux) ou Agendador de Tarefas (Windows) executa o script sem a sua intervenção
  • A compressão para .gz e a rotação de cópias antigas poupam espaço e mantêm o histórico de backups

Passo 1: Credenciais e ambiente, o que precisa antes de executar

Antes de escrever código, reúna três coisas: credenciais MySQL, um diretório para armazenar os backups e uma noção de onde o script será executado.

Para se ligar à base de dados precisa do host (normalmente localhost ou 127.0.0.1), nome de utilizador, palavra-passe e nome da base de dados. Num site WordPress, estes dados residem no wp-config.php: as constantes DB_HOST (servidor), DB_USER (utilizador), DB_PASSWORD (palavra-passe) e DB_NAME (nome da base de dados).

Crie o diretório de backup fora da pasta pública do site. Coloque a pasta backups/ um nível acima de public_html, para que os ficheiros SQL não fiquem acessíveis a partir do navegador. As permissões de escrita (chmod 755 ou chmod 775) são obrigatórias: sem elas, o fopen() e o fwrite() falharão com um erro.

O script PHP é executado a partir da linha de comandos: php backup.php. A execução via web (através do navegador) também é possível, mas a linha de comandos é mais segura, ninguém adivinhará o URL do script e fará o dump da sua base de dados.

Passo 2: Script PHP para backup da base de dados

O script faz três passagens: obtém a lista de tabelas, para cada uma exporta a estrutura (SHOW CREATE TABLE) e depois os dados (SELECT *). O resultado é reunido numa única string e escrito num ficheiro .sql. Guarde o código como backup.php e execute-o a partir do terminal.

1<?php
2
3$connection = mysqli_connect('localhost', 'user', 'pass', 'my_database');
4
5if (!$connection) {
6 die('Ошибка подключения: ' . mysqli_connect_error());
7}
8
9$tables = [];
10$result = mysqli_query($connection, "SHOW TABLES");
11while ($row = mysqli_fetch_row($result)) {
12 $tables[] = $row[0];
13}
14
15$dump = '';
16foreach ($tables as $table) {
17 $dump .= 'DROP TABLE IF EXISTS ' . $table . ";\n";
18
19 $create = mysqli_query($connection, "SHOW CREATE TABLE " . $table);
20 $row = mysqli_fetch_row($create);
21 $dump .= $row[1] . ";\n\n";
22
23 $data = mysqli_query($connection, "SELECT * FROM " . $table);
24 $num_fields = mysqli_num_fields($data);
25
26 while ($row = mysqli_fetch_row($data)) {
27 $dump .= "INSERT INTO " . $table . " VALUES(";
28 for ($j = 0; $j < $num_fields; $j++) {
29 if (isset($row[$j])) {
30 $row[$j] = mysqli_real_escape_string($connection, $row[$j]);
31 $dump .= '"' . $row[$j] . '"';
32 } else {
33 $dump .= 'NULL';
34 }
35 if ($j < $num_fields - 1) {
36 $dump .= ',';
37 }
38 }
39 $dump .= ");\n";
40 }
41 $dump .= "\n\n";
42}
43
44$filename = 'backups/dump_' . date('Y-m-d_H-i-s') . '.sql';
45$handle = fopen($filename, 'w+');
46fwrite($handle, $dump);
47fclose($handle);
48
49echo "Бэкап сохранён: " . $filename . "\n";
50
51?>

O que acontece aqui, linha a linha. O mysqli_connect() abre uma ligação; se o acesso for negado, o script termina com uma mensagem clara em vez de continuar silenciosamente. O ciclo SHOW TABLES recolhe os nomes das tabelas para um array.

Para cada tabela, o SHOW CREATE TABLE devolve exatamente uma linha, sendo o segundo campo a consulta DDL completa. Adicionamos DROP TABLE IF EXISTS antes dela para que o dump possa ser aplicado a uma base de dados limpa sem conflitos.

O SELECT * lê todas as linhas. A função mysqli_real_escape_string() escapa aspas e caracteres especiais dentro dos valores; ao contrário de addslashes(), respeita a codificação da ligação e não deixa passar injeções através de sequências multibyte. Os valores NULL são inseridos como NULL, não como string vazia.

O nome do ficheiro contém a data e hora de execução, o que é conveniente para a rotação. O ficheiro é aberto em modo w+ (criar ou sobrescrever) e recebe o dump completo numa única operação fwrite().

Passo 3: Script para restauro da base de dados a partir do dump SQL

O script inverso lê o ficheiro .sql e executa as consultas na base de dados. Na prática, os dumps pesam frequentemente dezenas de megabytes, pelo que file_get_contents() e explode por ; não é a melhor opção para produção. Mas para fins de aprendizagem e bases de dados pequenas, a abordagem funciona.

Guarde como restore.php. Antes de executar, faça um backup completo da base de dados atual; o restauro sobrescreve as tabelas.

1<?php
2
3$connection = mysqli_connect('localhost', 'root', '', 'test');
4
5if (!$connection) {
6 die('Ошибка подключения: ' . mysqli_connect_error());
7}
8
9$filename = 'backups/dump_2026-06-14_12-00-00.sql';
10
11if (!file_exists($filename)) {
12 die('Файл дампа не найден: ' . $filename);
13}
14
15$contents = file_get_contents($filename);
16
17if (mysqli_multi_query($connection, $contents)) {
18 do {
19 if ($result = mysqli_store_result($connection)) {
20 mysqli_free_result($result);
21 }
22 } while (mysqli_next_result($connection));
23 echo "База восстановлена из: " . $filename . "\n";
24} else {
25 echo "Ошибка восстановления: " . mysqli_error($connection) . "\n";
26}
27
28mysqli_close($connection);
29
30?>

A diferença chave em relação ao mysqli_query() linha a linha é o mysqli_multi_query(). Este aceita uma string com várias consultas SQL e executa-as sequencialmente numa única chamada. O ciclo do...while com mysqli_next_result() é obrigatório: sem ele, as consultas subsequentes não serão executadas e a ligação ficará pendurada.

O mysqli_store_result() obtém o resultado da consulta atual e o mysqli_free_result() liberta a memória. Se a consulta for INSERT ou CREATE TABLE, o resultado será false, e isso é normal: o script simplesmente passa para a seguinte.

Nota: o script não faz DROP DATABASE nem recria a própria base de dados. Ele espera que a base de dados test já exista. Por segurança, a primeira linha do dump pode conter CREATE DATABASE IF NOT EXISTS.

Passo 4: Automatização do backup via Cron e compressão

A execução manual funciona para tarefas pontuais. Mas num site ativo, o backup deve acontecer sem si, todas as noites enquanto dorme.

Num servidor Linux, adicione uma tarefa ao Cron: crontab -e e a linha 0 3 * * * php /path/to/backup.php executa o script todos os dias às 3 da manhã. No Windows, o Agendador de Tarefas com a ação «iniciar um programa» php.exe e o argumento-caminho para o script.

Duas melhorias que transformam um script de aprendizagem num pronto para produção:

Compressão. Após escrever o ficheiro .sql, adicione exec("gzip " . $filename);, o tamanho do dump diminuirá 5 a 10 vezes. Para o restauro, o gunzip descomprime o ficheiro de volta.

Rotação. Mantenha os backups dos últimos 7 dias e elimine o resto. Opção simples: adicione a limpeza de ficheiros com mais de N dias ao início do script:

1$retention_days = 7;
2$backup_dir = 'backups/';
3foreach (glob($backup_dir . '*.sql.gz') as $file) {
4 if (filemtime($file) < time() - $retention_days * 86400) {
5 unlink($file);
6 }
7}

Como resultado, tem um sistema autónomo: o script é executado de forma programada, cria um backup comprimido com a data no nome do ficheiro e limpa o material antigo. Mãos experientes e 20 minutos de configuração substituem um plugin pago.

O vídeo acima mostra o ciclo completo de backup automático: do ficheiro de configuração à verificação do .sql.gz comprimido na pasta backups/. A abordagem é exatamente a mesma descrita neste artigo, com verificações de erro e registo adicionais.

⁉️🤔 FAQ

É seguro guardar a palavra-passe do MySQL num script PHP?

Armazenar credenciais em texto simples dentro de um script só é aceitável se o ficheiro residir fora do diretório público do site e estiver inacessível a partir do navegador. É melhor mover as credenciais para um config.php separado, fora de public_html, e incluí-lo via require. Ainda mais fiável: passe a palavra-passe através de uma variável de ambiente: getenv('DB_PASS').

Posso fazer backup apenas de tabelas específicas?

Sim. Substitua SHOW TABLES por um array explícito de nomes: $tables = ['wp_posts', 'wp_postmeta', 'wp_options'];. Ou exclua tabelas não importantes via if (!in_array($table, ['wp_litespeed_cache', 'wp_actionscheduler_logs'])). Na prática, as tabelas de cache e de logs ocupam uma parte significativa do tamanho da base de dados e não são necessárias para o restauro.

Quanto espaço ocupa um backup da base de dados de um site WordPress médio?

Um dump SQL não comprimido de uma base de dados com 500 artigos e 15 plugins pesa entre 15 e 40 MB. Após gzip, entre 2 e 8 MB. Ao longo de um mês de backups diários com compressão, acumulam-se 100 a 300 MB; para um servidor com 20 GB de disco, isto é negligenciável. A rotação para 7 dias mantém o espaço ocupado entre 50 e 100 MB.

O que fazer se o ficheiro de backup estiver corrompido?

Antes de restaurar, verifique a integridade: gunzip -t dump.sql.gz para comprimido, head -n 20 dump.sql para não comprimido; certifique-se de que o ficheiro começa com comentários SQL, não com lixo binário. Não restaure um dump corrompido, pois perderá dados. É exatamente por isso que mantém pelo menos 2 ou 3 das cópias mais recentes.

Em que difere esta abordagem dos plugins de backup para WordPress?

Um plugin como o UpdraftPlus oferece uma interface web, backups incrementais e envio para a nuvem «pronto a usar». Um script PHP é o controlo total sobre o processo, sem código extra no admin. Para um programador que já trabalha com o servidor, o script é mais rápido e transparente. Para um cliente sem acesso à consola, um plugin é mais conveniente.

Script manual, mysqldump ou plugin: o que escolher para a sua tarefa

Um script de backup em PHP dá-lhe o principal: a compreensão exata do que acontece à sua base de dados durante o backup. Não confia numa caixa negra, controla cada consulta.

Se o site está em produção e a velocidade é importante, use o mysqldump. Um único comando mysqldump -u user -p db_name | gzip > dump.sql.gz faz o mesmo, mas muitas vezes mais rápido, porque trabalha ao nível do motor do MySQL, e não com SELECT linha a linha. Um script PHP é para fins de aprendizagem, cenários personalizados (fazer backup não de toda a base de dados, mas dos resultados de uma consulta específica) e ambientes onde o mysqldump não está disponível.

Se o site está em WordPress e não quer mergulhar na consola, qualquer plugin de backup resolverá a tarefa sem código. O UpdraftPlus, o BackWPup, o Duplicator capturam tanto a base de dados como os ficheiros do site.

Comece com um script manual, perceba como um dump SQL é formado. Depois, configure o Cron e a compressão. Último passo: verifique o restauro num servidor de teste; um backup sem verificação de restauro não é considerado concluído. Que ferramenta usa para o backup da base de dados? Escreva nos comentários.