Efterhånden som jeg er begyndt at lege med og administrere flere og flere hjemmesider rundt omkring, er jeg kommet til at tænke på, hvor dumt det egentligt er, at jeg ikke har nogen form for backup af databaserne til nogen af siderne. Det ville altså sige at jeg, i tilfælde af et angreb eller en serverfejl, ville have nogle problemer.
Jeg besluttede mig derfor at kigge lidt på hvad der fandtes af muligheder for at tage backup af MySql databaser automatisk. Dette skulle dog vise sig at være et problem der er efterspurgt meget, men stort set uden løsninger. Det fik mig til at tænke, at jeg jo så bare selv måtte skrive noget kode til at tage de backups for mig, hvilket jeg gjorde, og her vil beskrive så andre kan få glæde af det.
Når det kommer til at skulle tage backup af en MySql database, vil lidt søgning på nettet højst sandsynligt blot give det samme svar: gør det manuelt via phpMyAdmin. Jeg tænkte dog, at der måtte findes lette løsning et eller andet sted på nettet. Jeg satte mig derfor til at søge efter forskellige muligheder, og kom da også frem til lidt af hvert. Måden at gøre det på i php er, at eksekvere et program på serveren. Dette kan gøres ved følgende kode:
exec("/usr/bin/mysqldump --opt --host=YOURHOST --user=USERNAME --password=PASSWORD DATABASENAME > EXPORTFILE");
Det fungere altså ved at eksekvere mysqldump med ovenstående parametre.
- –opt betyder at der bliver tilføjet en “opret table hvis det ikke allerede eksisterer” kode først i den ekspoterede fil
- –host er naturligvis MySql host’en – mange steder er denne blot localhost
- –user er brugernavnet til databasen
- –password er adgangskoden til databasen
- DATABASENAME skal udskiftes med navnet på den database man vil tage backup af
- EXPORTFILE er stien og navnet på den fil det hele skal eksporteres til.
Der findes en hel masse flere parametre man kan sende til programmet. Dem kan du læse mere om på mysql.com
Da jeg først fik dette til at virke, tænkte jeg at det nok var lettere at skrive et php script til at tage backup af alle mine databaser på en gang. Men i stedet for at skulle tilføje en hel masse kode for hver enkelt database, ville jeg da bare skrive en php klasse til at udføre arbejdet for mig.
Jeg begyndte altså at skrive en php klasse, med følgende mål i tankerne:
- Valg af mappe til backup direkte i konstruktøren
- Mulighed for at sætte backups i kø
- Mulighed for at udføre køen på én gang.
Denne del var egentligt simpel nok, indtil jeg kom til at tænke lidt videre. Hvad nu hvis det ikke kun var MySql databasen der gik ned, men hele serveren? Jeg har en gang tidligere oplevet at et hostingselskab jeg var hos gik konkurs, og jeg mistede derfor alle mine ting. Det hjælper mig jo ikke ret meget at have backup filerne liggende på serveren. Jeg tænkte derfor længe over forskellige muligheder for at få overført backup filerne til en anden server eller min egen computer for at have dem gemt sikkert. I første omgang tænkte jeg på at sende filerne vedhæftet til en e-mail, men så ville jeg stadig skulle bøvle med at tage filerne ud af de mails og smide dem i en mappe på computeren.
Pludseligt slog det mig, at jeg da selvfølgeligt bare skulle bruge Dropbox. Dropbox er en service til at gemme sine filer online automatisk. Det fungerer ved at man har et klient program på computeren, der sørger for at overføre ens filer til serveren når de gemmes på computeren. På den måde kan man holde alle sine filer synkroniserede over flere servere. Jeg fandt så ud af at der findes en API til Dropbox der gør det muligt at uploade filer til ens Dropbox direkte fra en webserver. Fra Dropbox’s egen side fandt jeg et link til en php klasse der allerede var lavet til at udføre dette arbejde (findes her).
Dette vil altså sige at jeg kunne inkludere Dropbox uploader klassen og derfor med følgende kode uploade filer til en mappe i Dropbox:
$dropbox = new DropboxUploader("BRUGERNAVN TIL DROPBOX", "PASSWORD TIL DROPBOX"); $dropbox->uploader->upload("FIL TIL BACKUP","MAPPE I DROPBOX");
På denne måde kunne jeg altså tage min backup af databasen, gemme den midlertidigt på serveren, overføre til Dropbox og slette den fra serveren igen. Selvfølgeligt også med mulighed for at lade filen forblive gemt på serveren.
Jeg havde altså nu fået på plads hvordan jeg ville lave hele mit script og min klasse, og gik derfor i gang med at skrive. Jeg fil til slut brygget følgende kode sammen:
<?php /** * Mysql Backup * * Dette script er udviklet af Simon Smith for Designature. * Koden kan frit benyttes af alle, men denne notits i toppen skal dog forblive intakt. * Rettigheder til Dropbox Uploader har intet med denne kode at gøre, og kan derfor læses på http://wiki.dropbox.com/DropboxAddons/PHPDropboxUploader * Hvis du finder kode brugbar, eller hvis du har ris/ros til mit arbejde, kan du skrive til mig på min blog www.simon-smith.dk * Hvis du har spørgsmål/forslag til ændringer kan du enten kommentere på min blog, eller kontakte mig direkte på simon@rosmi.dk * @author Simon Smith * @version 1.0 * @link www.simon-smith.dk */ require_once("DropboxUploader.php"); define('SERVER',1); define('DROPBOX',2); class DatabaseBackup{ private $uploadTo; private $uploader; private $dropboxDir; private $uploadDir; private $queue = array(); public function __construct($uploadDir,$uploadTo=SERVER,$dropboxUsername="",$dropboxPassword="",$dropboxDir="") { $this->uploadDir = dirname(__FILE__)."/".$uploadDir; if($uploadTo==DROPBOX&&$dropboxUsername!==""&&$dropboxPassword!==""&&$dropboxDir!=="") { $this->uploadTo = DROPBOX; $this->uploader = new DropboxUploader($dropboxUsername, $dropboxPassword); $this->dropboxDir = $dropboxDir; }else $this->uploadTo = SERVER; } public function addToQueue($host,$username,$password,$database) { if($host!==""&&$username!==""&&$password!==""&&$database!=="") $this->queue[] = array("host"=>$host,"user"=>$username,"pass"=>$password,"database"=>$database); else return false; } public function doBackup($deleteAfterBackup=true) { if(count($this->queue)>0) { switch($this->uploadTo){ default: case SERVER: foreach($this->queue as $i => $value) { $host = $this->queue[$i]["host"]; $user = $this->queue[$i]["user"]; $pass = $this->queue[$i]["pass"]; $database = $this->queue[$i]["database"]; $backupFile = $this->uploadDir."/".date("d.H.i.s")."-".$database.".sql"; $createBackup = exec("/usr/bin/mysqldump --opt --host=$host --user=$user --password=$pass $database > $backupFile"); } return true; break; case DROPBOX: foreach($this->queue as $i => $value) { $host = $this->queue[$i]["host"]; $user = $this->queue[$i]["user"]; $pass = $this->queue[$i]["pass"]; $database = $this->queue[$i]["database"]; $backupFile = $this->uploadDir."/".date("d.H.i.s")."-".$database.".sql"; $createBackup = exec("/usr/bin/mysqldump --opt --host=$host --user=$user --password=$pass $database > $backupFile"); $this->uploader->upload($backupFile,$this->dropboxDir."/".date("F")."/"); if($deleteAfterBackup) unlink($backupFile); } return true; break; } } else return false; } } ?>
For at kunne bruge koden, skal man naturligvis inkludere ovenstående kode til sin index.php (eller hvorfra man nu vil køre sin backup) og sørge for at DropboxUploader.php ligger i samme mappe som ovenstående kode.
For at bruge scriptet uden upload til Dropbox, skal man skrive følgende:
require_once("sti til ovenstående fil"); $backup = new DatabaseBackup("mappe til backup på serveren", 1); $backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //$backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //Tilføj flere linjer for at lave flere backups. $backup->doBackup(false);
Hvis man ønsker at tage backup til Dropbox, skal man i stedet bruge følgende kode:
require_once("sti til ovenstående fil"); $backup = new DatabaseBackup("mappe til backup på serveren", 2, "Dropbox username", "Dropbox password", "Sti til mappe på dropbox"); $backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //$backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //Tilføj flere linjer for at lave flere backups. $backup->doBackup();
Når man kalder “doBackup()” metoden, tager denne en parameter. Som standard er denne true, hvilket gør at filerne automatisk slettes fra serveren efter backup er udført. Det er altså derfor meget vigtigt at man husker at kalde denne som “doBackup(false)” hvis man ønsker at beholde backupfilerne på serveren.
Den aller sidste ting jeg ønskede med backup af mine databaser var, at det naturligvis skulle køre automatisk. Man kan jo enten lave dette script således det bare kører når man går ind på en bestemt URL, men det kræver igen at man lige husker at besøge denne en gang imellem. I stedet valgte jeg at sætte et cronjob op. Et cronjob er blot en server der besøger den backup URL’en på serveren på et bestemt tidspunkt. Der findes mange services på nettet til at udføre dette, men jeg kan godt lide at bruge cronjob.de. Det er en tysk side, så hvis man ikke er så stærk til tysk, må man lige smide den en tur forbi Google Translate.
Jeg håber min kode hjælper en masse af jer til at få tage backup af jeres MySql databaser rundt omkring. Smid gerne en kommentar og del denne artikel med andre hvis du synes den er god.Since I’ve started to play around with and administrate more and more websites I’ve started thinking how stupid it is not to have any kind of central backup of the databases on the different websites. This means that in case of some server error I would be in some serious trouble!
I decided to look around on the Internet to find out what kinds of solutions that were already available to backup MySql databases automatically. It turned out that a lot of people were having the same issue as myself but there weren’t a lot of solutions for the problem out there. This got me thinking that I had to write some sort of backup script myself which I then did. Because I finally got a working solution I decided to share this with everyone else on the internet for you to use as you please.
Når det kommer til at skulle tage backup af en MySql database, vil lidt søgning på nettet højst sandsynligt blot give det samme svar: gør det manuelt via phpMyAdmin. Jeg tænkte dog, at der måtte findes lette løsning et eller andet sted på nettet. Jeg satte mig derfor til at søge efter forskellige muligheder, og kom da også frem til lidt af hvert. Måden at gøre det på i php er, at eksekvere et program på serveren. Dette kan gøres ved følgende kode:
exec("/usr/bin/mysqldump --opt --host=YOURHOST --user=USERNAME --password=PASSWORD DATABASENAME > EXPORTFILE");
Det fungere altså ved at eksekvere mysqldump med ovenstående parametre.
- –opt betyder at der bliver tilføjet en “opret table hvis det ikke allerede eksisterer” kode først i den ekspoterede fil
- –host er naturligvis MySql host’en – mange steder er denne blot localhost
- –user er brugernavnet til databasen
- –password er adgangskoden til databasen
- DATABASENAME skal udskiftes med navnet på den database man vil tage backup af
- EXPORTFILE er stien og navnet på den fil det hele skal eksporteres til.
Der findes en hel masse flere parametre man kan sende til programmet. Dem kan du læse mere om på mysql.com
Da jeg først fik dette til at virke, tænkte jeg at det nok var lettere at skrive et php script til at tage backup af alle mine databaser på en gang. Men i stedet for at skulle tilføje en hel masse kode for hver enkelt database, ville jeg da bare skrive en php klasse til at udføre arbejdet for mig.
Jeg begyndte altså at skrive en php klasse, med følgende mål i tankerne:
- Valg af mappe til backup direkte i konstruktøren
- Mulighed for at sætte backups i kø
- Mulighed for at udføre køen på én gang.
Denne del var egentligt simpel nok, indtil jeg kom til at tænke lidt videre. Hvad nu hvis det ikke kun var MySql databasen der gik ned, men hele serveren? Jeg har en gang tidligere oplevet at et hostingselskab jeg var hos gik konkurs, og jeg mistede derfor alle mine ting. Det hjælper mig jo ikke ret meget at have backup filerne liggende på serveren. Jeg tænkte derfor længe over forskellige muligheder for at få overført backup filerne til en anden server eller min egen computer for at have dem gemt sikkert. I første omgang tænkte jeg på at sende filerne vedhæftet til en e-mail, men så ville jeg stadig skulle bøvle med at tage filerne ud af de mails og smide dem i en mappe på computeren.
Pludseligt slog det mig, at jeg da selvfølgeligt bare skulle bruge Dropbox. Dropbox er en service til at gemme sine filer online automatisk. Det fungerer ved at man har et klient program på computeren, der sørger for at overføre ens filer til serveren når de gemmes på computeren. På den måde kan man holde alle sine filer synkroniserede over flere servere. Jeg fandt så ud af at der findes en API til Dropbox der gør det muligt at uploade filer til ens Dropbox direkte fra en webserver. Fra Dropbox’s egen side fandt jeg et link til en php klasse der allerede var lavet til at udføre dette arbejde (findes her).
Dette vil altså sige at jeg kunne inkludere Dropbox uploader klassen og derfor med følgende kode uploade filer til en mappe i Dropbox:
$dropbox = new DropboxUploader("BRUGERNAVN TIL DROPBOX", "PASSWORD TIL DROPBOX"); $dropbox->uploader->upload("FIL TIL BACKUP","MAPPE I DROPBOX");
På denne måde kunne jeg altså tage min backup af databasen, gemme den midlertidigt på serveren, overføre til Dropbox og slette den fra serveren igen. Selvfølgeligt også med mulighed for at lade filen forblive gemt på serveren.
Jeg havde altså nu fået på plads hvordan jeg ville lave hele mit script og min klasse, og gik derfor i gang med at skrive. Jeg fil til slut brygget følgende kode sammen:
<?php /** * Mysql Backup * * Dette script er udviklet af Simon Smith for Designature. * Koden kan frit benyttes af alle, men denne notits i toppen skal dog forblive intakt. * Rettigheder til Dropbox Uploader har intet med denne kode at gøre, og kan derfor læses på http://wiki.dropbox.com/DropboxAddons/PHPDropboxUploader * Hvis du finder kode brugbar, eller hvis du har ris/ros til mit arbejde, kan du skrive til mig på min blog www.simon-smith.dk * Hvis du har spørgsmål/forslag til ændringer kan du enten kommentere på min blog, eller kontakte mig direkte på simon@rosmi.dk * @author Simon Smith * @version 1.0 * @link www.simon-smith.dk */ require_once("DropboxUploader.php"); define('SERVER',1); define('DROPBOX',2); class DatabaseBackup{ private $uploadTo; private $uploader; private $dropboxDir; private $uploadDir; private $queue = array(); public function __construct($uploadDir,$uploadTo=SERVER,$dropboxUsername="",$dropboxPassword="",$dropboxDir="") { $this->uploadDir = dirname(__FILE__)."/".$uploadDir; if($uploadTo==DROPBOX&&$dropboxUsername!==""&&$dropboxPassword!==""&&$dropboxDir!=="") { $this->uploadTo = DROPBOX; $this->uploader = new DropboxUploader($dropboxUsername, $dropboxPassword); $this->dropboxDir = $dropboxDir; }else $this->uploadTo = SERVER; } public function addToQueue($host,$username,$password,$database) { if($host!==""&&$username!==""&&$password!==""&&$database!=="") $this->queue[] = array("host"=>$host,"user"=>$username,"pass"=>$password,"database"=>$database); else return false; } public function doBackup($deleteAfterBackup=true) { if(count($this->queue)>0) { switch($this->uploadTo){ default: case SERVER: foreach($this->queue as $i => $value) { $host = $this->queue[$i]["host"]; $user = $this->queue[$i]["user"]; $pass = $this->queue[$i]["pass"]; $database = $this->queue[$i]["database"]; $backupFile = $this->uploadDir."/".date("d.H.i.s")."-".$database.".sql"; $createBackup = exec("/usr/bin/mysqldump --opt --host=$host --user=$user --password=$pass $database > $backupFile"); } return true; break; case DROPBOX: foreach($this->queue as $i => $value) { $host = $this->queue[$i]["host"]; $user = $this->queue[$i]["user"]; $pass = $this->queue[$i]["pass"]; $database = $this->queue[$i]["database"]; $backupFile = $this->uploadDir."/".date("d.H.i.s")."-".$database.".sql"; $createBackup = exec("/usr/bin/mysqldump --opt --host=$host --user=$user --password=$pass $database > $backupFile"); $this->uploader->upload($backupFile,$this->dropboxDir."/".date("F")."/"); if($deleteAfterBackup) unlink($backupFile); } return true; break; } } else return false; } } ?>
For at kunne bruge koden, skal man naturligvis inkludere ovenstående kode til sin index.php (eller hvorfra man nu vil køre sin backup) og sørge for at DropboxUploader.php ligger i samme mappe som ovenstående kode.
For at bruge scriptet uden upload til Dropbox, skal man skrive følgende:
require_once("sti til ovenstående fil"); $backup = new DatabaseBackup("mappe til backup på serveren", 1); $backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //$backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //Tilføj flere linjer for at lave flere backups. $backup->doBackup(false);
Hvis man ønsker at tage backup til Dropbox, skal man i stedet bruge følgende kode:
require_once("sti til ovenstående fil"); $backup = new DatabaseBackup("mappe til backup på serveren", 2, "Dropbox username", "Dropbox password", "Sti til mappe på dropbox"); $backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //$backup->addToQueue("database host","database brugernavn","database password","navn på databasen"); //Tilføj flere linjer for at lave flere backups. $backup->doBackup();
Når man kalder “doBackup()” metoden, tager denne en parameter. Som standard er denne true, hvilket gør at filerne automatisk slettes fra serveren efter backup er udført. Det er altså derfor meget vigtigt at man husker at kalde denne som “doBackup(false)” hvis man ønsker at beholde backupfilerne på serveren.
Den aller sidste ting jeg ønskede med backup af mine databaser var, at det naturligvis skulle køre automatisk. Man kan jo enten lave dette script således det bare kører når man går ind på en bestemt URL, men det kræver igen at man lige husker at besøge denne en gang imellem. I stedet valgte jeg at sætte et cronjob op. Et cronjob er blot en server der besøger den backup URL’en på serveren på et bestemt tidspunkt. Der findes mange services på nettet til at udføre dette, men jeg kan godt lide at bruge cronjob.de. Det er en tysk side, så hvis man ikke er så stærk til tysk, må man lige smide den en tur forbi Google Translate.
Jeg håber min kode hjælper en masse af jer til at få tage backup af jeres MySql databaser rundt omkring. Smid gerne en kommentar og del denne artikel med andre hvis du synes den er god.