Skip to content

Alles für WordPress, Webentwicklung — und mehr

💾 Sichern und Wiederherstellen einer MySQL-Datenbank mit PHP

💾 Sichern und Wiederherstellen einer MySQL-Datenbank mit PHP

Eine Datenbank zu verlieren bedeutet, Aufträge, Benutzer und Inhalte innerhalb von Sekunden zu verlieren. Für einen WordPress-Seitenbetreiber ist ein Backup kein „nice to have", sondern zwingend erforderlich. Sich jedoch jeden Tag manuell in phpMyAdmin einzuloggen, kostet Zeit, und wenn Sie es brauchen, ist das Backup schlichtweg nicht vorhanden.

Ein PHP-Skript löst das Problem: Sie geben ihm den Datenbankzugriff, es exportiert Struktur und Daten in eine SQL-Datei. Mit fünf Minuten Einrichtung erhalten Sie ein wiederholbares, programmierbares Backup, das Sie nicht vergessen werden.

Im nächsten Schritt: fertige Skripte für MySQL-Backup und -Restore in PHP. Wir analysieren, wie sie funktionieren, wo Sie die Zugangsdaten erhalten und wie Sie ein automatisches Backup zeitgesteuert ausführen, damit Ihre Datenbank niemals ungeschützt bleibt.

💡 Kurzer Überblick:

  • Verbindung zu MySQL via mysqli, Tabellenliste abrufen und Struktur exportieren
  • SQL-Dump erstellen: CREATE TABLE plus INSERT für jede Tabelle, in Datei speichern
  • Restore: Dump einlesen und Abfragen in einem Durchlauf via mysqli_multi_query ausführen
  • Automatisierung via Cron (Linux) oder Task Scheduler (Windows) führt das Skript ohne Ihr Zutun aus
  • Komprimierung auf .gz und Rotation alter Kopien sparen Speicherplatz und erhalten die Backup-Historie

Schritt 1: Zugangsdaten und Umgebung, was Sie vor der Ausführung benötigen

Bevor Sie Code schreiben, besorgen Sie drei Dinge: MySQL-Zugangsdaten, ein Verzeichnis zum Speichern der Backups und ein Verständnis dafür, wo das Skript ausgeführt wird.

Um sich mit der Datenbank zu verbinden, benötigen Sie Host (normalerweise localhost oder 127.0.0.1), Benutzername, Passwort und Datenbankname. Auf einer WordPress-Seite befinden sich diese Daten in wp-config.php: die Konstanten DB_HOST (Server), DB_USER (Login), DB_PASSWORD (Passwort) und DB_NAME (Datenbankname).

Erstellen Sie das Backup-Verzeichnis außerhalb des öffentlichen Ordners der Seite. Platzieren Sie den backups/-Ordner eine Ebene über public_html, sodass SQL-Dateien nicht über den Browser zugänglich sind. Schreibrechte (chmod 755 oder chmod 775) sind zwingend erforderlich: ohne sie schlagen fopen() und fwrite() mit einem Fehler fehl.

Das PHP-Skript wird über die Kommandozeile ausgeführt: php backup.php. Eine Ausführung über das Web (via Browser) ist ebenfalls möglich, aber die Kommandozeile ist sicherer, da niemand die Skript-URL erraten und Ihre Datenbank dumpen kann.

Schritt 2: PHP-Skript für das Datenbank-Backup

Das Skript durchläuft drei Schritte: Es ruft die Tabellenliste ab, exportiert für jede Tabelle die Struktur (SHOW CREATE TABLE) und dann die Daten (SELECT *). Das Ergebnis wird zu einer Zeichenkette zusammengesetzt und in eine .sql-Datei geschrieben. Speichern Sie den Code als backup.php und führen Sie ihn vom Terminal aus.

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?>

Was hier Zeile für Zeile passiert. mysqli_connect() öffnet eine Verbindung; wird der Zugriff verweigert, bricht das Skript mit einer klaren Meldung ab, anstatt stillschweigend fortzufahren. Die SHOW TABLES-Schleife sammelt die Tabellennamen in einem Array.

Für jede Tabelle liefert SHOW CREATE TABLE genau eine Zeile zurück, wobei das zweite Feld die vollständige DDL-Abfrage ist. Wir stellen DROP TABLE IF EXISTS voran, damit der Dump auf eine leere Datenbank ohne Konflikte angewendet werden kann.

SELECT * liest alle Zeilen. Die Funktion mysqli_real_escape_string() maskiert Anführungszeichen und Sonderzeichen innerhalb von Werten; im Gegensatz zu addslashes() respektiert sie die Verbindungskodierung und übersieht keine Injections durch Multibyte-Sequenzen. NULL-Werte werden als NULL eingefügt, nicht als leere Zeichenkette.

Der Dateiname enthält Ausführungsdatum und -uhrzeit, praktisch für die Rotation. Die Datei wird im Modus w+ geöffnet (erstellen oder überschreiben) und erhält den gesamten Dump in einer einzigen fwrite()-Operation.

Schritt 3: Skript für die Datenbankwiederherstellung aus einem SQL-Dump

Das umgekehrte Skript liest die .sql-Datei und führt die Abfragen gegen die Datenbank aus. In der Praxis wiegen Dumps oft mehrere zehn Megabyte, daher sind file_get_contents() und ein Explode nach ; nicht die beste Option für den Produktivbetrieb. Für Lernzwecke und kleine Datenbanken funktioniert der Ansatz jedoch.

Speichern Sie es als restore.php. Erstellen Sie vor der Ausführung ein vollständiges Backup der aktuellen Datenbank, der Restore überschreibt Tabellen.

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?>

Der wesentliche Unterschied zur zeilenweisen mysqli_query() ist mysqli_multi_query(). Diese Funktion akzeptiert eine Zeichenkette mit mehreren SQL-Abfragen und führt sie sequenziell in einem Aufruf aus. Die do...while-Schleife mit mysqli_next_result() ist zwingend erforderlich: ohne sie werden nachfolgende Abfragen nicht ausgeführt und die Verbindung hängt.

mysqli_store_result() holt das Ergebnis der aktuellen Abfrage, und mysqli_free_result() gibt den Speicher frei. Wenn die Abfrage INSERT oder CREATE TABLE ist, ist das Ergebnis false, und das ist normal: das Skript geht einfach zur nächsten über.

Beachten Sie: Das Skript führt kein DROP DATABASE aus und erstellt die Datenbank selbst nicht neu. Es erwartet, dass die Datenbank test bereits existiert. Zur Sicherheit kann die erste Zeile des Dumps CREATE DATABASE IF NOT EXISTS enthalten.

Schritt 4: Backup-Automatisierung via Cron und Komprimierung

Die manuelle Ausführung funktioniert für einmalige Aufgaben. Auf einer Live-Seite sollte das Backup jedoch ohne Ihr Zutun erfolgen, jede Nacht, während Sie schlafen.

Auf einem Linux-Server fügen Sie einen Cron-Job hinzu: crontab -e und die Zeile 0 3 * * * php /path/to/backup.php führt das Skript jeden Tag um 3 Uhr morgens aus. Unter Windows erledigt das der Task Scheduler mit der Aktion „Programm starten", php.exe und dem Argument-Pfad zum Skript.

Zwei Verbesserungen, die ein Lernskript produktionsreif machen:

Komprimierung. Fügen Sie nach dem Schreiben der .sql-Datei exec("gzip " . $filename); hinzu, die Dump-Größe schrumpft um das 5- bis 10-Fache. Für den Restore entpackt gunzip die Datei wieder.

Rotation. Behalten Sie Backups der letzten 7 Tage, löschen Sie den Rest. Eine einfache Option: Fügen Sie am Skriptanfang eine Bereinigung von Dateien hinzu, die älter als N Tage sind:

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}

Im Ergebnis haben Sie ein autonomes System: Das Skript läuft zeitgesteuert, erstellt ein komprimiertes Backup mit Datum im Dateinamen und bereinigt alte Bestände. Gerade Hände und 20 Minuten Einrichtung ersetzen ein kostenpflichtiges Plugin.

Das obige Video zeigt den vollständigen Auto-Backup-Zyklus: von der Konfigurationsdatei bis zur Prüfung der komprimierten .sql.gz im backups/-Ordner. Der Ansatz ist exakt derselbe wie in diesem Artikel beschrieben, mit zusätzlichen Fehlerprüfungen und Logging.

⁉️🤔 FAQ

Ist es sicher, das MySQL-Passwort in einem PHP-Skript zu speichern?

Zugangsdaten im Klartext innerhalb eines Skripts zu speichern, ist nur dann akzeptabel, wenn die Datei außerhalb des öffentlichen Verzeichnisses der Seite liegt und vom Browser aus nicht erreichbar ist. Besser ist es, die Zugangsdaten in eine separate config.php außerhalb von public_html auszulagern und via require einzubinden. Noch zuverlässiger: Übergeben Sie das Passwort über eine Umgebungsvariable: getenv('DB_PASS').

Kann ich nur bestimmte Tabellen sichern?

Ja. Ersetzen Sie SHOW TABLES durch ein explizites Array mit Namen: $tables = ['wp_posts', 'wp_postmeta', 'wp_options'];. Oder schließen Sie unwichtige Tabellen aus via if (!in_array($table, ['wp_litespeed_cache', 'wp_actionscheduler_logs'])). In der Praxis machen Cache- und Log-Tabellen einen erheblichen Teil der Datenbankgröße aus und werden für die Wiederherstellung nicht benötigt.

Wie viel Speicherplatz beansprucht ein Backup einer durchschnittlichen WordPress-Seiten-Datenbank?

Ein unkomprimierter SQL-Dump einer Datenbank mit 500 Beiträgen und 15 Plugins wiegt 15-40 MB. Nach gzip sind es 2-8 MB. Über einen Monat täglicher Backups mit Komprimierung sammeln sich 100-300 MB an, für einen Server mit 20 GB Speicher ist das vernachlässigbar. Eine Rotation auf 7 Tage hält den belegten Speicherplatz innerhalb von 50-100 MB.

Was tun, wenn die Backup-Datei beschädigt ist?

Prüfen Sie vor dem Restore die Integrität: gunzip -t dump.sql.gz für komprimierte, head -n 20 dump.sql für unkomprimierte Dateien; stellen Sie sicher, dass die Datei mit SQL-Kommentaren beginnt, nicht mit binärem Datenmüll. Spielen Sie keinen beschädigten Dump ein, Sie würden Daten verlieren. Genau deshalb bewahren Sie mindestens 2-3 aktuelle Kopien auf.

Wie unterscheidet sich dieser Ansatz von WordPress-Backup-Plugins?

Ein Plugin wie UpdraftPlus bietet eine Weboberfläche, inkrementelle Backups und einen Cloud-Upload direkt ab Werk. Ein PHP-Skript bedeutet volle Kontrolle über den Prozess ohne zusätzlichen Code im Admin. Für einen Entwickler, der bereits mit dem Server arbeitet, ist das Skript schneller und transparenter. Für einen Kunden ohne Konsolenzugriff ist ein Plugin komfortabler.

Manuelles Skript, mysqldump oder Plugin, was Sie für Ihre Aufgabe wählen sollten

Ein PHP-Backup-Skript liefert die Hauptsache: ein Verständnis dafür, was genau mit Ihrer Datenbank während des Backups passiert. Sie vertrauen keiner Blackbox, Sie kontrollieren jede Abfrage.

Wenn die Seite produktiv ist und Geschwindigkeit zählt, verwenden Sie mysqldump. Ein Befehl mysqldump -u user -p db_name | gzip > dump.sql.gz erledigt dasselbe um ein Vielfaches schneller, da er auf Ebene der MySQL-Engine arbeitet und nicht zeilenweise per SELECT. Ein PHP-Skript ist für Lernzwecke, individuelle Szenarien (Sichern nicht der gesamten Datenbank, sondern der Ergebnisse einer bestimmten Abfrage) und Umgebungen, in denen mysqldump nicht verfügbar ist.

Wenn die Seite auf WordPress läuft und Sie nicht in die Konsole eintauchen möchten, erledigt jedes Backup-Plugin die Aufgabe ohne Code. UpdraftPlus, BackWPup, Duplicator sichern sowohl Datenbank als auch Dateien der Seite.

Beginnen Sie mit einem manuellen Skript, verstehen Sie, wie ein SQL-Dump aufgebaut ist. Richten Sie dann Cron und Komprimierung ein. Letzter Schritt: Verifizieren Sie den Restore auf einem Testserver, ein Backup ohne Wiederherstellungsprüfung gilt nicht als abgeschlossen. Welches Tool für das Datenbank-Backup verwenden Sie? Schreiben Sie es in die Kommentare.