RSS
Automatisch elke dag een backup

19 juni 2009

CodeIgniter, Programmeren

Automatisch elke dag een backup

Backups zijn vandaag belangrijker dan ooit. Je bestanden staan waarschijnlijk wel ergens op een server die dagelijks backups neemt in jouw plaats. Je denkt dan nogal snel: ‘als er iets fout gaat, hebben ze toch een backup’. Toch blijft het altijd een heel gedoe wanneer je wil beroep doen op deze backups.

Wanneer je aan een klein projectje werkt, is het makkelijk om zelf even elke dag na het programmeren snel even alle bestanden af te halen. Wanneer je echter aan grote projecten werkt, zoals ik nu aan Spacetarion, kan het afhalen van alle bestanden al snel 5 tot 10 minuten duren. Daarom had ik nood aan een automatische oplossing. Omdat ik deze best wel handig in gebruik vind, deel ik mijn opgedane kennis graag met jullie. Als fervente CodeIgniter fan, heb ik dit natuurlijk met behulp van dit framework gedaan.

Wat heb ik allemaal nodig?

Er zijn 2 dingen die nodig zijn om dit werkend te krijgen. Eerst en vooral moet je toegang hebben tot cronjobs. Dit hangt af van je webhost. De meeste fatsoenlijke hosts, zoals Futureweb en Combell, ondersteunen cronjobs. De cronjob zorgt ervoor dat het script automatisch elke 24 uur wordt uitgevoerd. Eigenlijk zal het script dus ook werken zonder cronjobs, maar dan moet je er zelf aan denken elke dag de controller een bezoekje te brengen.

Een andere voorwaarde is dat je je CodeIgniter system map niet buiten de web root hebt staan. CI buiten de web root installeren is veiliger omdat mensen geen toegang kunnen krijgen tot de bestanden in de installatie. Het nadeel is echter dat ook de ‘gebruiker’ die PHP uitvoert (Apache) ook geen rechten heeft om bestanden buiten de root te lezen. Aangezien het script dat we gaan gebruiken van elk bestand de inhoud moet kunnen lezen, zal dit enkel werken indien CI volledig in de web root staat. Meestal is deze root de map ‘www’ of ‘public_html’. Het kan zijn dat je bij jouw host enkel toegang hebt tot de web root. Indien je nergens een map ‘www’ of ‘public_html’ terugvind, is dit het geval en kan je het script gebruiken.

Noot: wanneer je je system map wel in de www map hebt staan, kan je deze nog altijd afschermen van het publiek door een klein .htaccess bestand in de system map te zetten. De inhoud van dit .htaccess bestand moet dan het volgende zijn:

order allow,deny
deny from any

Op die manier zal iedereen (behalve de Apache gebruiker) een 403 Forbidden error krijgen. Zo zijn je bestanden toch beschermd (wel minder goed dan gewoon alles buiten de www map te zetten natuurlijk) en kan je toch dit backup script gebruiken.

De controller

We maken in de map system/application/controllers een nieuw bestand aan met als naam backup.php. We voorzien in dit bestand 2 functies: 1 functie die elke dag een backup zal nemen en 1 functie die elke maandag (dit wordt bepaald in de cronjob) de laatste backup per e-mail zal versturen. De inhoud van Backup.php is als volgt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
class Backup extends Controller
{
	function __construct()
	{
		parent::__construct();
 
		define('PASSWORD', 'your_password');
		define('MAX_BACKUPS', 14);
		define('BACKUP_DIR', '/welke/map/je/wil/backuppen/');
	}
 
	function index($password = null)
	{
		if ($password !== PASSWORD)
		{
			die('Get out');
		}
 
		$this->load->library('zip');
 
		// Bestanden backuppen
		$this->zip->read_dir(BACKUP_DIR);
 
		// Database backuppen
		$this->load->dbutil();
		$backup = &$this->dbutil->backup(array('format' => 'txt'));
		$this->zip->add_data('database.txt', $backup);
 
		// Het zip bestand opslaan
		$this->zip->archive(BACKUP_DIR . 'backups/' . date('YmdHis') . ' - ' . $this->zip->get_file_num() . ' files.zip');
 
		// Overbodige backups verwijderen
		$this->load->helper('file');
		$files = get_filenames(BACKUP_DIR . 'backups/');
 
		// Controleren of er al backups zijn
		if (count($files) !== 0)
		{
			sort($files);
 
			$delete = count($files) - MAX_BACKUPS;
			for ($i = 0; $i < $delete; $i++)
			{
				unlink(BACKUP_DIR . 'backups/' . $files[$i]);
			}
		}
	}
 
	function mail_backup($password = null)
	{
		if ($password !== PASSWORD)
		{
			die('Get out');
		}
 
		$this->load->helper('file');
		$files = get_filenames(BACKUP_DIR . 'backups/');
 
		// Controleren of er al backups zijn
		if (count($files) !== 0)
		{
			rsort($files);
 
			// De laatste backup mailen
			$this->load->library('email');
			$this->email->from('no-reply@example.com', 'Backup system');
			$this->email->to('you@example.com');
			$this->email->subject('Your backup');
			$this->email->message('Your backup');
			$this->email->attach(BACKUP_DIR . 'backups/' . $files[0]);
			$this->email->send();
		}
	}
}

De cronjob

De cronjob zal ervoor zorgen dat de Backup controller elke 24 uur opgeroepen wordt. Deze controller zal dan een backup nemen en het bestand opslaan op de server. De manier om cronjobs in te stellen is bij elke host meestal anders. Ik kan dus niet stap voor stap uitleggen hoe je dit moet doen. Het commando dat moet worden uitgevoerd is echter altijd hetzelfde, en ziet er als volgt uit:

1
0 0 * * * wget http://www.jouwsite.be/backup/index/your_password/ -O /dev/null

Deze cronjob zal elke dag om 0:00 worden uitgevoerd. Dit tijdstip kan je zelf aanpassen. De structuur van de argumenten is ‘minuut’, ‘uur’, ‘dag van de maand’, ‘maand’, ‘dag van de week’. Indien je 12 0 * * 1 gebruikt, zal er elke maandag om 12 uur ’s middags een backup worden genomen.

Je moet natuurlijk ook de ‘jouwsite.be’ vervangen door het domein waarop jouw site staat. De ‘your_password’ op het einde is het wachtwoord dat je hebt gedefiniëerd in de controller. De ‘-O /dev/null’ zorgt ervoor dat de cronjob geen logfile zal schrijven naar de website. Indien je dit weglaat zal er elke keer de cronjob wordt uitgevoerd een bestand in de root van je website bijkomen. Na verloop van tijd kan dit aantal flink oplopen. Het is dus een goed idee om deze logfiles weg te laten.

Je kan ook een aparte cronjob aanmaken om de laatste backup per e-mail te ontvangen. Persoonlijk neem ik elke dag een backup, en krijg ik elke maandag om 6 uur ’s morgens graag de laatste backup in mijn inbox. Deze cronjob ziet er als volgt uit:

0 6 * * 1 wget http://www.jouwsite.be/backup/mail_backup/your_password -O /dev/null

Het resultaat

Het resultaat is best wel duidelijk. Je webserver zal nu elke dag een backup nemen van alle bestanden EN de volledige database. Ook zal je elke maandag een e-mail krijgen waarin de laatst genomen backup zal zitten. Ook zullen op de server maximaal 14 backups worden bijhouden, zo heb je iets of wat controle over hoeveel plaats de verschillende backups innemen.

Zoals je misschien al gemerkt hebt, zijn alle werken op deze website gelicenseerd onder een Creative Commons licentie. Wanneer je mijn werk wil gebruiken kan je dat vrij doen, zolang je mijn naam bij het werk zet en het niet dient voor commerciële doeleinden. Wanneer je mijn naam liever niet bij het werk wil zetten of de scripts toch wil gebruiken voor commerciële doeleinden, dien je eerst een schriftelijke toestemming aan mij te vragen.

Delen

Facebook Facebook     Twitter Twitter     TinyUrl: http://tinyurl.com/lofn4j

4 reacties op deze post

  1. Michael zei op 20 juni :

    Je kan je script ook gewoon gebruiken om alles bestanden in een zip te zetten samen met een database backup om daarna de zip te kunnen downloaden. Het gaat veel sneller om die zip te downloaden, die er trouwens maar 6 seconden over doet 3000 bestanden te zippen.

    In plaats van lijn 31 in backup.php van jouw script die de zip wegschrijft, kan je het ook rechtstreeks aanbieden om het te downloaden bij het manueel bezoeken van de controller (gaat niet bij cronjobs):

    $this->zip->download(‘laatstebackup.zip’);

  2. Michael zei op 20 juni :

    Wat is nog vergeten ben :p

    Mooi script dat eigenlijk nogmaals het nut van CodeIgniter benadrukt.
    Een databasebackup in enkele lijnen code, de zip maken in enkele lijnen, … echt waaw. Chapeau voor uw script, zeer handig trouwens ;)

  3. TheEvilDuckie zei op 21 juni :

    handig! dit kan ik ook gebruiken!

  4. FinalFrag zei op 21 juni :

    @TheEvilDuckie Daar doen we het voor :P

Reageer zelf!