
💾 MySQL-tietokannan varmuuskopiointi ja palautus PHP:llä
Tietokannan menettäminen tarkoittaa tilausten, käyttäjien ja sisällön menettämistä sekunneissa. WordPress-sivuston omistajalle varmuuskopiointi ei ole "kiva lisä", vaan pakollinen. Mutta phpMyAdminiin kirjautuminen käsin joka päivä tuhlaa aikaa, ja kun sitä tarvitset, varmuuskopiota ei yksinkertaisesti ole.
PHP-skripti ratkaisee ongelman: annat sille tietokantayhteyden tiedot, ja se vie rakenteen ja datan SQL-tiedostoon. Viiden minuutin asennuksella saat toistettavan, ohjelmoitavan varmuuskopion, jota et unohda tehdä.
Seuraavaksi: valmiit skriptit MySQL-varmuuskopiointiin ja -palautukseen PHP:llä. Käymme läpi, miten ne toimivat, mistä saat tunnukset ja miten ajastat automaattisen varmuuskopioinnin, jotta tietokantasi ei koskaan jää suojaamatta.
💡 Pikaopas:
- Yhdistä MySQL:ään
mysqli:llä, hae taululista ja vie rakenne - Muodosta SQL-dump:
CREATE TABLEjaINSERTjokaiselle taululle, tallenna tiedostoon - Palauta: lue dump ja suorita kyselyt yhtenä eränä
mysqli_multi_query:lla - Automaatio Cronilla (Linux) tai Tehtävien ajoituksella (Windows) ajaa skriptin ilman osallistumistasi
- Pakkaus
.gz-muotoon ja vanhojen kopioiden kierrätys säästävät tilaa ja pitävät varmuuskopiohistorian
Vaihe 1: Tunnukset ja ympäristö, mitä tarvitset ennen ajoa
Ennen koodin kirjoittamista kerää kolme asiaa: MySQL-tunnukset, hakemisto varmuuskopioiden tallentamiseen ja käsitys siitä, missä skripti ajetaan.
Tietokantaan yhdistämiseen tarvitset palvelimen (yleensä localhost tai 127.0.0.1), käyttäjätunnuksen, salasanan ja tietokannan nimen. WordPress-sivustolla nämä tiedot ovat wp-config.php-tiedostossa: vakiot DB_HOST (palvelin), DB_USER (käyttäjätunnus), DB_PASSWORD (salasana) ja DB_NAME (tietokannan nimi).
Luo varmuuskopiohakemisto sivuston julkisen kansion ulkopuolelle. Sijoita backups/-kansio yhden tason public_html:n yläpuolelle, jotta SQL-tiedostot eivät ole selaimen kautta saatavilla. Kirjoitusoikeudet (chmod 755 tai chmod 775) ovat pakolliset: ilman niitä fopen() ja fwrite() epäonnistuvat virheeseen.
PHP-skripti ajetaan komentoriviltä: php backup.php. Verkkoajo (selaimen kautta) on myös mahdollinen, mutta komentorivi on turvallisempi, kukaan ei arvaa skriptin URL-osoitetta ja dumppaa tietokantaasi.
Vaihe 2: PHP-skripti tietokannan varmuuskopiointiin
Skripti tekee kolme läpikäyntiä: hakee taululistan, vie jokaisesta rakenteen (SHOW CREATE TABLE) ja sitten datan (SELECT *). Tulos kootaan yhdeksi merkkijonoksi ja kirjoitetaan .sql-tiedostoon. Tallenna koodi nimellä backup.php ja aja terminaalista.
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 ?>
Mitä tässä tapahtuu rivi riviltä. mysqli_connect() avaa yhteyden, jos pääsy evätään, skripti kuolee selkeään viestiin sen sijaan, että jatkaisi hiljaa. SHOW TABLES -silmukka kerää taulujen nimet taulukkoon.
Jokaiselle taululle SHOW CREATE TABLE palauttaa täsmälleen yhden rivin, jonka toinen kenttä on koko DDL-kysely. Lisäämme DROP TABLE IF EXISTS ennen sitä, jotta dump voidaan ajaa puhtaaseen tietokantaan ilman ristiriitoja.
SELECT * lukee kaikki rivit. Funktio mysqli_real_escape_string() suojaa lainausmerkit ja erikoismerkit arvojen sisällä, toisin kuin addslashes(), se kunnioittaa yhteyden merkistökoodausta eikä päästä läpi injektioita monitavuisten sekvenssien kautta. NULL-arvot lisätään NULL-arvoina, ei tyhjinä merkkijonoina.
Tiedostonimi sisältää ajon päivämäärän ja kellonajan, mikä on kätevää kierrätyksen kannalta. Tiedosto avataan w+-tilassa (luo tai korvaa) ja vastaanottaa koko dumpin yhdellä fwrite()-operaatiolla.
Vaihe 3: Skripti tietokannan palautukseen SQL-dumpista
Käänteinen skripti lukee .sql-tiedoston ja suorittaa kyselyt tietokantaa vasten. Käytännössä dumpit painavat usein kymmeniä megatavuja, joten file_get_contents() ja pilkkominen ;-merkillä ei ole paras vaihtoehto tuotantoon. Mutta oppimistarkoituksiin ja pienille tietokannoille lähestymistapa toimii.
Tallenna nimellä restore.php. Ennen ajoa ota täysi varmuuskopio nykyisestä tietokannasta, palautus korvaa taulut.
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 ?>
Keskeinen ero rivi riviltä mysqli_query()-kutsuun on mysqli_multi_query(). Se ottaa vastaan merkkijonon, jossa on useita SQL-kyselyjä, ja suorittaa ne peräkkäin yhdellä kutsulla. do...while-silmukka mysqli_next_result()-funktiolla on pakollinen: ilman sitä seuraavia kyselyjä ei suoriteta ja yhteys jumittuu.
mysqli_store_result() noutaa nykyisen kyselyn tuloksen, ja mysqli_free_result() vapauttaa muistin. Jos kysely on INSERT tai CREATE TABLE, tulos on false, ja se on normaalia: skripti vain siirtyy seuraavaan.
Huomaa: skripti ei tee DROP DATABASE-komentoa eikä luo itse tietokantaa uudelleen. Se odottaa, että test-tietokanta on jo olemassa. Turvallisuuden vuoksi dumpin ensimmäinen rivi voi sisältää CREATE DATABASE IF NOT EXISTS.
Vaihe 4: Varmuuskopioinnin automaatio Cronilla ja pakkaus
Manuaalinen ajo toimii kertaluonteisiin tehtäviin. Mutta elävällä sivustolla varmuuskopioinnin tulisi tapahtua ilman sinua, joka yö nukkuessasi.
Linux-palvelimella lisää tehtävä Croniin: crontab -e ja rivi 0 3 * * * php /path/to/backup.php ajaa skriptin joka päivä kello 3 aamulla. Windowsissa Tehtävien ajoitus, toiminnolla "käynnistä ohjelma" php.exe ja argumenttina polku skriptiin.
Kaksi parannusta, jotka muuttavat oppimisskriptin tuotantokelpoiseksi:
Pakkaus. .sql-tiedoston kirjoittamisen jälkeen lisää exec("gzip " . $filename);, dumpin koko kutistuu 5-10 kertaa. Palautusta varten gunzip purkaa tiedoston takaisin.
Kierrätys. Säilytä varmuuskopiot viimeiseltä 7 päivältä, poista loput. Yksinkertainen vaihtoehto, lisää N päivää vanhempien tiedostojen siivous skriptin alkuun:
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 }
Tuloksena sinulla on itsenäinen järjestelmä: skripti ajetaan aikataulun mukaan, luo pakatun varmuuskopion päivämäärällä tiedostonimessä ja siivoaa vanhat. Suorat kädet ja 20 minuutin asennus korvaavat maksullisen lisäosan.
Yllä oleva video näyttää koko automaattisen varmuuskopioinnin syklin: konfiguraatiotiedostosta pakatun .sql.gz-tiedoston tarkistamiseen backups/-kansiossa. Lähestymistapa on täsmälleen sama kuin tässä artikkelissa on kuvattu, lisättynä virhetarkistuksilla ja lokituksella.
⁉️🤔 UKK
Onko turvallista säilyttää MySQL-salasana PHP-skriptissä?
Tunnusten säilyttäminen selkokielisenä skriptin sisällä on hyväksyttävää vain, jos tiedosto sijaitsee sivuston julkisen hakemiston ulkopuolella eikä ole selaimen kautta saatavilla. Parempi on siirtää tunnukset erilliseen
config.php-tiedostoonpublic_html:n ulkopuolelle ja sisällyttäärequire-komennolla. Vielä luotettavampaa on välittää salasana ympäristömuuttujan kautta:getenv('DB_PASS').
Voinko varmuuskopioida vain tietyt taulut?
Kyllä. Korvaa
SHOW TABLESnimenomaisella nimitaulukolla:$tables = ['wp_posts', 'wp_postmeta', 'wp_options'];. Tai sulje pois merkityksettömät taulutif (!in_array($table, ['wp_litespeed_cache', 'wp_actionscheduler_logs']))-ehdolla. Käytännössä välimuisti- ja lokitaulut vievät merkittävän osan tietokannan koosta, eikä niitä tarvita palautukseen.
Kuinka paljon tilaa keskimääräisen WordPress-sivuston tietokannan varmuuskopio vie?
Pakkaamaton SQL-dump tietokannasta, jossa on 500 artikkelia ja 15 lisäosaa, painaa 15-40 Mt.
gzip-pakkauksen jälkeen 2-8 Mt. Kuukauden päivittäiset varmuuskopiot pakattuna kerryttävät 100-300 Mt, palvelimelle, jossa on 20 Gt levytilaa, tämä on merkityksetöntä. 7 päivän kierrätys pitää käytetyn tilan 50-100 Mt:ssa.
Mitä tehdä, jos varmuuskopiotiedosto on vioittunut?
Ennen palautusta tarkista eheys:
gunzip -t dump.sql.gzpakatulle,head -n 20 dump.sqlpakkaamattomalle, varmista, että tiedosto alkaa SQL-kommenteilla, ei binääriroskalla. Älä palauta vioittunutta dumpia, menetät dataa. Juuri siksi säilytät vähintään 2-3 uusinta kopiota.
Miten tämä lähestymistapa eroaa WordPress-varmuuskopiointilisäosista?
Lisäosa, kuten UpdraftPlus, tarjoaa verkkokäyttöliittymän, inkrementaaliset varmuuskopiot ja pilveen lähetyksen "suoraan paketista". PHP-skripti on täysi hallinta prosessista ilman ylimääräistä koodia hallintapaneelissa. Kehittäjälle, joka jo työskentelee palvelimen kanssa, skripti on nopeampi ja läpinäkyvämpi. Asiakkaalle, jolla ei ole konsoliyhteyttä, lisäosa on kätevämpi.
Manuaalinen skripti, mysqldump vai lisäosa, mitä valita tehtävääsi
PHP-varmuuskopiointiskripti antaa pääasian, ymmärryksen siitä, mitä tietokannallesi tarkalleen tapahtuu varmuuskopioinnin aikana. Et luota mustaan laatikkoon, hallitset jokaista kyselyä.
Jos sivusto on tuotannossa ja nopeudella on väliä, käytä mysqldump-komentoa. Yksi komento mysqldump -u user -p db_name | gzip > dump.sql.gz tekee saman asian mutta monin verroin nopeammin, koska se toimii MySQL-moottorin tasolla, ei rivi riviltä SELECT-kyselyillä. PHP-skripti on oppimistarkoituksiin, räätälöityihin skenaarioihin (ei koko tietokannan, vaan tietyn kyselyn tuloksen varmuuskopiointi) ja ympäristöihin, joissa mysqldump ei ole saatavilla.
Jos sivusto on WordPressissä etkä halua sukeltaa konsoliin, mikä tahansa varmuuskopiointilisäosa hoitaa tehtävän ilman koodia. UpdraftPlus, BackWPup, Duplicator nappaavat sekä tietokannan että sivuston tiedostot.
Aloita manuaalisella skriptillä, ymmärrä, miten SQL-dump muodostuu. Aseta sitten Cron ja pakkaus. Viimeinen vaihe, varmista palautus testipalvelimella: varmuuskopiointia ilman palautuksen varmistusta ei lasketa tehdyksi. Mitä työkalua käytät tietokannan varmuuskopiointiin? Kirjoita kommentteihin.



