Skip to content

Allt om WordPress, webbutveckling — och mer därtill

💾 Säkerhetskopiera och återställa en MySQL-databas via PHP

💾 Säkerhetskopiera och återställa en MySQL-databas via PHP

Att förlora en databas innebär att förlora ordrar, användare och innehåll på sekunder. För en WordPress-webbplatsägare är backup inte "bra att ha", det är obligatoriskt. Men att manuellt logga in i phpMyAdmin varje dag slösar tid, och när du behöver den finns backupen helt enkelt inte där.

Ett PHP-skript löser problemet: du ger det databasåtkomst, det exporterar struktur och data till en SQL-fil. Med fem minuters installation får du en repeterbar, programmerbar backup som du inte glömmer att göra.

Härnäst: färdiga skript för MySQL-backup och återställning i PHP. Vi går igenom hur de fungerar, var du hämtar inloggningsuppgifter och hur du kör automatisk backup enligt schema så att din databas aldrig lämnas oskyddad.

💡 Snabb översikt:

  • Anslut till MySQL via mysqli, hämta tabellista och exportera struktur
  • Skapa SQL-dump: CREATE TABLE plus INSERT för varje tabell, spara till fil
  • Återställ: läs dump och kör frågor i en batch via mysqli_multi_query
  • Automatisering via Cron (Linux) eller Aktivitetshanteraren (Windows) kör skriptet utan din inblandning
  • Komprimering till .gz och rotering av gamla kopior sparar utrymme och bevarar backuphistorik

Steg 1: Inloggningsuppgifter och miljö, vad du behöver innan du kör

Innan du skriver kod, samla ihop tre saker: MySQL-inloggningsuppgifter, en katalog för att lagra backuper och en förståelse för var skriptet kommer att köras.

För att ansluta till databasen behöver du värd (vanligtvis localhost eller 127.0.0.1), användarnamn, lösenord och databasnamn. På en WordPress-webbplats finns dessa uppgifter i wp-config.php: konstanterna DB_HOST (server), DB_USER (användarnamn), DB_PASSWORD (lösenord) och DB_NAME (databasnamn).

Skapa backupkatalogen utanför webbplatsens publika mapp. Placera mappen backups/ en nivå ovanför public_html, så att SQL-filer inte blir åtkomliga från webbläsaren. Skrivrättigheter (chmod 755 eller chmod 775) är obligatoriska: utan dem kommer fopen() och fwrite() att misslyckas med ett fel.

PHP-skriptet körs från kommandoraden: php backup.php. Körning via webben (via webbläsare) är också möjlig, men kommandoraden är säkrare, ingen kommer att gissa skriptets URL och dumpa din databas.

Steg 2: PHP-skript för databasbackup

Skriptet gör tre genomgångar: hämtar tabellista, för varje exporterar det struktur (SHOW CREATE TABLE), sedan data (SELECT *). Resultatet sätts ihop till en sträng och skrivs till en .sql-fil. Spara koden som backup.php och kör från terminalen.

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

Vad som händer här rad för rad. mysqli_connect() öppnar en anslutning, om åtkomst nekas avslutas skriptet med ett tydligt meddelande istället för att tyst fortsätta. Loopen SHOW TABLES samlar tabellnamn i en array.

För varje tabell returnerar SHOW CREATE TABLE exakt en rad där det andra fältet är den fullständiga DDL-frågan. Vi lägger till DROP TABLE IF EXISTS före den så att dumpen kan tillämpas på en ren databas utan konflikter.

SELECT * läser alla rader. Funktionen mysqli_real_escape_string() escapar citattecken och specialtecken inuti värden, till skillnad från addslashes() respekterar den anslutningens kodning och missar inte injektioner via multibytesekvenser. NULL-värden infogas som NULL, inte som tom sträng.

Filnamnet innehåller körningsdatum och tid, praktiskt för rotering. Filen öppnas i w+-läge (skapa eller skriv över) och tar emot hela dumpen i en enda fwrite()-operation.

Steg 3: Skript för databasåterställning från SQL-dump

Det omvända skriptet läser .sql-filen och kör frågor mot databasen. I praktiken väger dumpar ofta tiotals megabyte, så file_get_contents() och explode med ; är inte det bästa alternativet för produktion. Men för inlärningsändamål och små databaser fungerar tillvägagångssättet.

Spara som restore.php. Innan du kör, gör en fullständig backup av den aktuella databasen, återställning skriver över tabeller.

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

Den viktigaste skillnaden från rad-för-rad mysqli_query() är mysqli_multi_query(). Den tar emot en sträng med flera SQL-frågor och kör dem sekventiellt i ett anrop. Loopen do...while med mysqli_next_result() är obligatorisk: utan den kommer efterföljande frågor inte att köras och anslutningen kommer att hänga sig.

mysqli_store_result() hämtar resultatet av den aktuella frågan, och mysqli_free_result() frigör minne. Om frågan är INSERT eller CREATE TABLE kommer resultatet att vara false, och det är normalt: skriptet går bara vidare till nästa.

Observera: skriptet gör inte DROP DATABASE och återskapar inte själva databasen. Det förväntar sig att databasen test redan finns. För säkerhets skull kan den första raden i dumpen innehålla CREATE DATABASE IF NOT EXISTS.

Steg 4: Backupautomatisering via Cron och komprimering

Manuell körning fungerar för engångsuppgifter. Men på en aktiv webbplats bör backup ske utan dig, varje natt medan du sover.

På en Linux-server lägger du till en uppgift i Cron: crontab -e och raden 0 3 * * * php /path/to/backup.php kör skriptet varje dag klockan 03.00. På Windows använder du Aktivitetshanteraren med åtgärden "starta ett program" php.exe och argument-sökväg till skriptet.

Två förbättringar som gör ett inlärningsskript produktionsredo:

Komprimering. Efter att ha skrivit .sql-filen lägg till exec("gzip " . $filename);, dumpens storlek krymper 5-10 gånger. För återställning packar gunzip upp filen igen.

Rotering. Behåll backuper för de senaste 7 dagarna, radera resten. Ett enkelt alternativ, lägg till rensning av filer äldre än N dagar i början av skriptet:

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}

Som resultat har du ett autonomt system: skriptet körs enligt schema, skapar komprimerad backup med datum i filnamnet och rensar gammalt material. Raka händer och 20 minuters installation ersätter ett betalplugin.

Videon ovan visar den fullständiga automatiska backupcykeln: från konfigurationsfil till kontroll av komprimerad .sql.gz i mappen backups/. Tillvägagångssättet är exakt detsamma som beskrivs i denna artikel, med ytterligare felkontroller och loggning.

⁉️🤔 FAQ

Är det säkert att lagra MySQL-lösenord i ett PHP-skript?

Att lagra inloggningsuppgifter i klartext inuti ett skript är acceptabelt endast om filen finns utanför webbplatsens publika katalog och är oåtkomlig från webbläsaren. Bättre är att flytta inloggningsuppgifter till en separat config.php utanför public_html och inkludera via require. Ännu mer tillförlitligt, skicka lösenordet via miljövariabel: getenv('DB_PASS').

Kan jag bara säkerhetskopiera specifika tabeller?

Ja. Ersätt SHOW TABLES med en explicit array av namn: $tables = ['wp_posts', 'wp_postmeta', 'wp_options'];. Eller exkludera oviktiga tabeller via if (!in_array($table, ['wp_litespeed_cache', 'wp_actionscheduler_logs'])). I praktiken tar cache- och loggtabeller upp en betydande del av databasstorleken och behövs inte för återställning.

Hur mycket utrymme tar en backup av en genomsnittlig WordPress-webbplats databas?

Okomprimerad SQL-dump av en databas med 500 inlägg och 15 plugins väger 15-40 MB. Efter gzip, 2-8 MB. Under en månad med dagliga backuper med komprimering ackumuleras 100-300 MB, för en server med 20 GB disk är detta försumbart. Rotering i 7 dagar håller upptaget utrymme inom 50-100 MB.

Vad gör man om backupfilen är korrupt?

Innan återställning, kontrollera integriteten: gunzip -t dump.sql.gz för komprimerad, head -n 20 dump.sql för okomprimerad, säkerställ att filen börjar med SQL-kommentarer, inte binärt skräp. Återställ inte en korrupt dump, du kommer att förlora data. Det är precis därför du behåller minst 2-3 senaste kopior.

Hur skiljer sig detta tillvägagångssätt från WordPress backup-plugins?

Ett plugin som UpdraftPlus ger ett webbgränssnitt, inkrementella backuper och molnuppladdning "out of the box". Ett PHP-skript ger full kontroll över processen utan extra kod i admin. För en utvecklare som redan arbetar med servern är skriptet snabbare och mer transparent. För en kund utan konsollåtkomst är ett plugin mer bekvämt.

Manuellt skript, mysqldump eller plugin, vad du ska välja för din uppgift

Ett PHP-backup-skript ger det viktigaste, förståelse för exakt vad som händer med din databas under backup. Du litar inte på en svart låda, du kontrollerar varje fråga.

Om webbplatsen är i produktion och hastighet spelar roll, använd mysqldump. Ett kommando mysqldump -u user -p db_name | gzip > dump.sql.gz gör samma sak men många gånger snabbare, eftersom det arbetar på MySQL-motorns nivå, inte rad-för-rad SELECT. Ett PHP-skript är för inlärningsändamål, anpassade scenarier (säkerhetskopiering av inte hela databasen utan resultatet av en specifik fråga) och miljöer där mysqldump inte är tillgängligt.

Om webbplatsen är på WordPress och du inte vill dyka in i konsolen kommer vilket backup-plugin som helst att lösa uppgiften utan kod. UpdraftPlus, BackWPup, Duplicator tar både databas och webbplatsfiler.

Börja med ett manuellt skript, förstå hur en SQL-dump bildas. Sätt sedan upp Cron och komprimering. Sista steget, verifiera återställning på en testserver: en backup utan återställningsverifiering anses inte vara klar. Vilket verktyg för databasbackup använder du? Skriv i kommentarerna.