
💾 Резервне копіювання та відновлення бази даних MySQL через PHP
Втрата бази даних означає втрату замовлень, користувачів і контенту за секунди. Для власника сайту на WordPress резервне копіювання не «бажане», а обов’язкове. Але ручний вхід у phpMyAdmin щодня забирає час, і в потрібний момент бекапу просто немає.
PHP-скрипт вирішує проблему: ви даєте йому доступ до бази, він вивантажує структуру та дані в SQL-файл. За п’ять хвилин налаштування ви отримуєте повторюваний, програмований бекап, про який не забудете.
Далі: готові скрипти резервного копіювання та відновлення MySQL на PHP. Розберемо, як вони працюють, де взяти доступи та як запустити автобекап за розкладом, щоб база даних never залишалася без захисту.
💡 Швидкий огляд:
- Підключаємося до MySQL через
mysqli, отримуємо список таблиць і вивантажуємо структуру - Формуємо SQL-дамп:
CREATE TABLEплюсINSERTдля кожної таблиці, зберігаємо у файл - Відновлення: читаємо дамп і виконуємо запити одним пакетом через
mysqli_multi_query - Автоматизація через Cron (Linux) або Task Scheduler (Windows) запускає скрипт без вашої участі
- Стиснення в
.gzі ротація старих копій економлять місце та зберігають історію бекапів
Шаг 1: Доступи та оточення: що потрібно перед запуском
Перед тим як писати код, зберіть три речі: облікові дані MySQL, директорію для зберігання бекапів і розуміння, де запускатиметься скрипт.
Для підключення до бази потрібні хост (зазвичай localhost або 127.0.0.1), ім’я користувача, пароль і назва бази. На WordPress-сайті ці дані лежать у wp-config.php: константи DB_HOST (сервер), DB_USER (логін), DB_PASSWORD (пароль) і DB_NAME (ім’я бази).
Директорію для бекапів створіть поза публічною папкою сайту. Покладіть папку backups/ на рівень вище за public_html, так до SQL-файлів не буде доступу з браузера. Права на запис (chmod 755 або chmod 775) обов’язкові: без них fopen() і fwrite() впадуть із помилкою.
PHP-скрипт запускається з командного рядка: php backup.php. Вебзапуск (через браузер) теж можливий, але командний рядок безпечніший, ніхто не підбере URL скрипта і не зіллє вашу базу.
Шаг 2: PHP-скрипт резервного копіювання бази даних
Скрипт робить три проходи: отримує список таблиць, для кожної вивантажує структуру (SHOW CREATE TABLE), потім дані (SELECT *). Результат збирається в один рядок і записується у .sql-файл. Збережіть код як backup.php і запустіть із терміналу.
1 <?php 2 3 $connection = mysqli_connect('localhost', 'user', 'pass', 'my_database'); 4 5 if (!$connection) { 6 die('Ошибка подключения: ' . mysqli_connect_error()); 7 } 8 9 $tables = []; 10 $result = mysqli_query($connection, "SHOW TABLES"); 11 while ($row = mysqli_fetch_row($result)) { 12 $tables[] = $row[0]; 13 } 14 15 $dump = ''; 16 foreach ($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+'); 46 fwrite($handle, $dump); 47 fclose($handle); 48 49 echo "Бэкап сохранён: " . $filename . "\n"; 50 51 ?>
Що тут відбувається порядково. mysqli_connect() відкриває з’єднання, якщо доступу немає, скрипт падає зі зрозумілим повідомленням, а не продовжує мовчки. Цикл SHOW TABLES збирає імена таблиць у масив.
Для кожної таблиці SHOW CREATE TABLE повертає рівно один рядок із другим полем, повним DDL-запитом. Ми додаємо DROP TABLE IF EXISTS перед ним, щоб дамп можна було накотити на чисту базу без конфліктів.
SELECT * читає всі рядки. Функція mysqli_real_escape_string() екранує лапки та спецсимволи всередині значень, на відміну від addslashes(), вона враховує кодування з’єднання і не пропускає ін’єкції через багатобайтові послідовності. NULL-значення вставляються як NULL, а не як порожній рядок.
Ім’я файлу містить дату та час запуску, зручно для ротації. Файл відкривається в режимі w+ (створити або перезаписати) і отримує весь дамп однією операцією fwrite().
Шаг 3: Скрипт відновлення бази даних із SQL-дампа
Зворотний скрипт читає .sql-файл і виконує запити до бази. На практиці дамп часто важить десятки мегабайт, тому file_get_contents() і explode по ;, не найкращий варіант для продакшену. Але для навчальних цілей і невеликих баз підхід робочий.
Збережіть як restore.php. Перед запуском зробіть повний бекап поточної бази, відновлення перезаписує таблиці.
1 <?php 2 3 $connection = mysqli_connect('localhost', 'root', '', 'test'); 4 5 if (!$connection) { 6 die('Ошибка подключения: ' . mysqli_connect_error()); 7 } 8 9 $filename = 'backups/dump_2026-06-14_12-00-00.sql'; 10 11 if (!file_exists($filename)) { 12 die('Файл дампа не найден: ' . $filename); 13 } 14 15 $contents = file_get_contents($filename); 16 17 if (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 28 mysqli_close($connection); 29 30 ?>
Ключова відмінність від порядкового mysqli_query(), mysqli_multi_query(). Вона приймає рядок із кількома SQL-запитами і виконує їх послідовно за один виклик. Цикл do...while із mysqli_next_result() обов’язковий: без нього наступні запити не виконаються, а з’єднання зависне.
mysqli_store_result() забирає результат поточного запиту, а mysqli_free_result() звільняє пам’ять. Якщо запит, INSERT або CREATE TABLE, результат буде false, і це нормально: скрипт просто переходить до наступного.
Зверніть увагу: скрипт не робить DROP DATABASE і не перестворює саму базу. Він очікує, що база test уже існує. Для перестраховки можна першим рядком дампа тримати CREATE DATABASE IF NOT EXISTS.
Шаг 4: Автоматизація бекапу через Cron і стиснення
Ручний запуск працює для разових задач. Але на бойовому сайті бекап має робитися без вас, щоночі, поки ви спите.
На Linux-сервері додайте задачу в Cron: crontab -e і рядок 0 3 * * * php /path/to/backup.php запускає скрипт щодня о 3 годині ночі. На Windows, Task Scheduler із дією «запустити програму» php.exe та аргументом-шляхом до скрипта.
Два доопрацювання, які перетворюють навчальний скрипт на production-ready:
Стиснення. Після запису .sql-файлу додайте exec("gzip " . $filename);, розмір дампа зменшиться в 5-10 разів. Для відновлення gunzip розпакує файл назад.
Ротація. Бекапи за останні 7 днів зберігайте, решту видаляйте. Простий варіант: на початок скрипта додайте очищення файлів, старіших за N днів:
1 $retention_days = 7; 2 $backup_dir = 'backups/'; 3 foreach (glob($backup_dir . '*.sql.gz') as $file) { 4 if (filemtime($file) < time() - $retention_days * 86400) { 5 unlink($file); 6 } 7 }
У результаті ви маєте автономну систему: скрипт запускається за розкладом, створює стиснений бекап із датою в імені та чистить старе. Прямі руки і 20 хвилин налаштування замінюють платний плагін.
На відео вище, повний цикл автобекапу: від конфігураційного файлу до перевірки стисненого .sql.gz у папці backups/. Підхід точно такий самий, як описано в цій статті, з додатковими перевірками помилок і логуванням.
⁉️🤔 Часті питання
Чи безпечно зберігати пароль MySQL у PHP-скрипті?
Зберігати облікові дані у відкритому вигляді всередині скрипта прийнятно, тільки якщо файл лежить поза публічною директорією сайту і недоступний із браузера. Краще винести доступи в окремий
config.phpза межамиpublic_htmlі підключати черезrequire. Ще надійніше, передавати пароль через змінну оточення:getenv('DB_PASS').
Чи можна робити бекап лише певних таблиць?
Так. Замініть
SHOW TABLESна явний масив імен:$tables = ['wp_posts', 'wp_postmeta', 'wp_options'];. Або виключіть неважливі таблиці черезif (!in_array($table, ['wp_litespeed_cache', 'wp_actionscheduler_logs'])). На практиці таблиці кешів і логів займають значну частину розміру бази і не потрібні для відновлення.
Скільки місця займає бекап бази середнього WordPress-сайту?
Нестиснений SQL-дамп бази на 500 записів і 15 плагінів важить 15-40 МБ. Після
gzip, 2-8 МБ. За місяць щоденних бекапів зі стисненням накопичується 100-300 МБ, для сервера з 20 ГБ диска це непомітно. Ротація за 7 днів тримає зайняте місце в межах 50-100 МБ.
Що робити, якщо бекап-файл пошкоджений?
Перед відновленням перевірте цілісність:
gunzip -t dump.sql.gzдля стиснених,head -n 20 dump.sqlдля нестиснених, переконайтеся, що файл починається з SQL-коментарів, а не з бінарного сміття. Пошкоджений дамп не відновлюйте, ви втратите дані. Саме тому тримайте щонайменше 2-3 останні копії.
Чим цей підхід відрізняється від плагінів резервного копіювання WordPress?
Плагін на кшталт UpdraftPlus дає вебінтерфейс, інкрементальні бекапи та завантаження в хмару «з коробки». PHP-скрипт — це повний контроль над процесом без зайвого коду в адмінці. Для розробника, який і так працює з сервером, скрипт швидший і прозоріший. Для клієнта без доступу до консолі плагін зручніший.
Ручний скрипт, mysqldump чи плагін: що обрати під вашу задачу
PHP-скрипт резервного копіювання дає головне, розуміння того, що саме відбувається з вашою базою під час бекапу. Ви не довіряєте чорному ящику, а контролюєте кожен запит.
Якщо сайт на продакшені і важлива швидкість, беріть mysqldump. Одна команда mysqldump -u user -p db_name | gzip > dump.sql.gz робить те саме, але в рази швидше, тому що працює на рівні рушія MySQL, а не порядковим SELECT. Скрипт PHP, для навчальних цілей, кастомних сценаріїв (бекап не всієї бази, а результатів конкретного запиту) і середовищ, де mysqldump недоступний.
Якщо сайт на WordPress і ви не хочете лізти в консоль, будь-який плагін резервного копіювання закриє задачу без коду. UpdraftPlus, BackWPup, Duplicator забирають і базу, і файли сайту.
Почніть із ручного скрипта, зрозумійте, як формується SQL-дамп. Потім налаштуйте Cron і стиснення. Останній крок, перевірка відновлення на тестовому сервері: бекап без перевірки відновлення не вважається зробленим. Який інструмент для бекапу баз даних використовуєте ви? Напишіть у коментарях.



