PHP

Backup Database MySQL in PHP

In questo tutorial costruiremo un semplice script PHP che esegue il backup di un database MySQL.

Lo script PHP consiste in un unico file molto corto (107 righe) facilmente configurabile impostando alcuni parametri da GET, in modo da poter rapidamente impostare se si vuole solo la struttura del database, struttura e dati eccetera.

Una volta eseguito lo script, esso restituirà al browser un file.
Il browser in questo modo avvierà il download del dump del database che andrà avanti durante le iterazioni e le varie query, cercando quindi di non fare andare in timeout la richiesta.

Questo vi consentirà di fare il backup di database MySQL consistenti.
Vediamo per prima cosa la testa dello script che contiene tutte le costanti che vi consentiranno di comandare l'applicazione.

Ajax Script

Introduzione

In questo tutorial costruiremo assieme uno script AJAX che ci consentirà di interrogare in modo semplice e veloce degli script lato server (o semplici pagine HTML).
Si tratta di uno script AJAX pronto ed efficace, che attraverso il concetto di ereditarietà, vi darà la possibilità di creare al volo una classe per comunicare con il vostro server.

Nel nostro caso costruiremo una pagina HTML che chiamerà uno script in PHP.
Questo restituirà a sua volta una lista di impiegati leggendola direttamente da un database MySQL.

Il cuore del tutorial consiste principalmente nella costruzione del modulo in JavaScript che dovrà occuparsi dell'invio e della ricezione dei dati.

Consiglio il tutorial a chi è già avvezzo con la programmazione ad oggetti in JavaScript, anche se non lo ritengo un requisito strettamente necessario per una comprensione utile.
Se utilizzate comunque l' ereditarietà in altri linguaggi, allora potrebbe essere il momento opportuno per imparare qualche chicca in JavaScript

Iniziamo con la creazione del foglio JS che ospiterà la nostra classe madre: AjaxModule.

5. Upload

In questo capitolo analizzeremo il codice ActionScript 3 che comporrà la classe di principale della nostra applicazione.

La classe documento in questione l'ho chiamata Upload, e ne riporto di seguito gli attributi :

  • browse (Button) - elemento dell'interfaccia che rappresenterà il bottone "Sfoglia";
  • status (TextField) - elemento dell'interfaccia che rappresenterà un campo di testo in cui verranno riportati gli stati dell'applicazione ed eventuali errori;
  • phpserv (PhpService) - istanza utilizzata per contattare gli script PHP una volta avvenuto l'invio del file;
  • fileRef (FileReference) - istanza utilizzata per inviare il file al server designato.

Procediamo ora analizzando il codice di tutti i metodi della classe :

  • Upload():void - costruttore della classe, inizializza l'attributo fileRef e il membro statico PhpService.scriptPath assegnandolo al percorso specificato nella classe Settings, inoltre richiama il metodo interfaccia() che vedremo subito dopo e infine aggiunge tutti i listener necessari al membro fileRef, per gestire le varie situazioni che possono verificarsi durante il tentativo di invio del file al server.
public function Upload():void
{
	PhpService.scriptPath = Settings.PHP_PATH;

	this.interfaccia();

	this.fileRef = new FileReference();
	this.fileRef.addEventListener(Event.SELECT, this.selectHandler);
	this.fileRef.addEventListener(Event.COMPLETE, this.completeHandler);
	this.fileRef.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
	this.fileRef.addEventListener(ProgressEvent.PROGRESS, this.progressHandler);
	this.fileRef.addEventListener(HTTPStatusEvent.HTTP_STATUS, this.httpStatusHandler);
	this.fileRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityHandler);
}

  • interfaccia():void - inizializza e configura i due membri browse e status dandogli la formattazione adeguata e li aggiunge infine al filmato contenitore attraverso il metodo addChild().
private function interfaccia():void
{
	// Bottone Sfoglia
	this.browse = new Button();
	this.browse.x = 10;
	this.browse.y = 30;
	this.browse.width = 50;
	this.browse.height = 20;
	this.browse.label = "Sfoglia";
	this.browse.addEventListener(MouseEvent.CLICK, this.browseClick);
	this.addChild(this.browse);

	// Campo di testo Status
	var format:TextFormat = new TextFormat("Verdana", 10, "0x000000");

	this.status = new TextField();
	this.status.x = 10;
	this.status.y = 10;
	this.status.width = 200;
	this.status.height = 16;
	this.status.border = true;
	this.status.defaultTextFormat = format;
	this.status.text = "Nessun file selezionato.";
	this.addChild(this.status);
}

  • browseClick(evt:MouseEvent):void - listener che gestisce i click sul bottone browse.
    Nel caso in cui l'etichetta del bottone sia impostata su "Sfoglia" tenta di aprire una finestra di dialogo per sfogliare i file sul disco rigido dell'utente attraverso il metodo browse() dell'istanza fileRef, se invece l'etichetta è impostata su "Invia" tenta di inviare il file precedentemente selezionato tramite il metodo upload() dell'istanza fileRef.
private function browseClick(evt:MouseEvent):void
{
	if (this.browse.label == "Sfoglia")
	{
		try
		{
			this.fileRef.browse(Settings.ALLOWED_TYPES);
		}
		catch (error:Error)
		{
			this.status.text = "Impossibile sfogliare il disco rigido.";
		}
	}
	else if (this.browse.label == "Invia")
	{
		this.browse.enabled = false;
		this.status.text = "Invio in corso ...";
		var request:URLRequest = new URLRequest(Settings.PHP_PATH + "upload.php");

		try
		{
			this.fileRef.upload(request);
		}
		catch (error:Error)
		{
			this.browse.enabled = true;
			this.status.text = "Impossibile inviare il file.";
		}
	}
}

  • checkUpload(evt:Event):void - più avanti vedremo il codice del listener completeHandler(), il cui compito sarà quello di utilizzare la classe PhpService per contattare il servizio php verify.php.
    Il risultato ottenuto da quest ultimo script verrà gestito appunto dal metodo checkUpload.
private function checkUpload(evt:Event):void
{
	this.browse.enabled = true;
	this.browse.label = "Sfoglia";

	if (Boolean(parseInt(this.phpserv.response.success)))
		this.status.text = "File inviato con successo.";
	else
		this.status.text = "Il file non è stato accettato.";

	trace(this.phpserv.response.log);
}

  • Di seguito riporto tutti gli altri metodi, ossia i listener che si limiteranno a riportare le informazioni raccolte attraverso il campo di testo status.

/* Gestori degli eventi */
private function selectHandler(evt:Event):void
{
	this.browse.label = "Invia";
	this.status.text = evt.target.name;
}

private function completeHandler(evt:Event):void
{
	this.status.text = "File \"" + evt.target.name + "\" inviato, verifica in corso ...";

	this.phpserv = new PhpService("verify.php");
	this.phpserv.addVar("filename", evt.target.name);
	this.phpserv.addEventListener(Event.COMPLETE, this.checkUpload);
	this.phpserv.request();
}

private function ioErrorHandler(evt:IOErrorEvent):void
{
	this.status.text = "Errore di Input/Output : " + evt;
}

private function progressHandler(evt:ProgressEvent):void
{
	var pc:uint = evt.bytesLoaded * 100 / evt.bytesTotal;
	this.status.text = "Invio in corso ... ";
	this.status.appendText(String(pc) + "%");
}

private function httpStatusHandler(evt:HTTPStatusEvent):void
{
	this.status.text = "Errore HTTP : " + evt;
}

private function securityHandler(evt:SecurityErrorEvent):void
{
	this.status.text = "Violazione della sicurezza : " + evt;
}

Si conclude qui questo tutorial, spero utile.
Potete scaricare l'intero codice d'esempio da qui.

Per far si che tutto funzioni correttamente, ricordatevi di modificare i permessi alle cartelle "php" per la scrittura del file di log e alla cartella "upload" per l'archiviazione dei file.


4. Client Side

Come già accennato nell'introduzione di questo tutorial, anche per ActionScript 3 ci serviremo di una classe costruita in precedenza nella mia Guida ad ActionScript 3.

La classe in questione è PhpService.
Non ho apportato alcuna modifica a questa classe, quindi se volete ricostruirne il codice e studiarne il funzionamento vi rimando al capitolo dedicato : Classi per interrogare PHP.

Anche per ActionScript 3 ho creato un'enumerazione, ossia una classe usata come collezione di valori (costanti) che useremo per impostare rapidamente alcuni parametri standard che detteranno il funzionamento della nostra applicazione.

Questa classe prende il nome di Settings :

Settings.as
package script.as3
{
	import flash.net.FileFilter;

	public final class Settings
	{
		public static const PHP_PATH:String = "http://10.0.0.8/realizzazionesito/articoli/as3 files/script/php/";
		public static const ALLOWED_TYPES:Array = new Array
		(
			new FileFilter("Immagini", "*.jpg; *.jpeg; *.bmp; *.gif; *.png"),
			new FileFilter("Archivi", "*.zip; *.rar; *.ace; *.7z")
		);
	}
}

La costante PHP_PATH è assegnata al percorso HTTP che conterrà gli script PHP responsabili della gestione dei files inviati.

L'indirizzo del server in questo caso è impostato a 10.0.0.8 semplicemente perchè ho testato l'applicazione sul mio computer, che essende sotto rete NAT (utilizzo un Router ADSL) ha un indirizzo interno proprio.

Se lo testate sul vostro server locale probabilmente dovrete utilizzare localhost (127.0.0.1).
Una volta effettuati i test e le personalizzazioni al codice, utilizzerete direttamente l'indirizzo remoto del server come mostrato nel percorso di esempio che segue :

// ...
public static const PHP_PATH:String = "http://www.realizzazione-sito.info/script/php/";
// ...

La costante ALLOWED_TYPES è un array di istanze della classe FileFilter.
Attraverso l'impostazione di questa costante possiamo personalizzare la finestra di dialogo che l'utente utilizzerà per selezionare il file da inviare dal suo disco rigido.

Aggiungendo o rimuovendo nuovi elementi dell'array o modificando quelli da me impostati, è possibile impostare dei filtri che il browser dell'utente sfrutterà per rendere possibile solo l'invio di determinati file, servendosi delle estensioni specificate.

Nel prossimo capitolo vedremo il codice dell'ultima classe, che sarà il cuore della nostra applicazione.


3. Script PHP

In questa lezione vedremo come utilizzare le classi viste nel capitolo precedente e che compongono la nostra libreria PHP 5.

Innanzitutto mettiamo i tre file PHP che seguono in una cartella nominata classi :

  • UploadSettings.php
  • ErroreFile.php
  • File.php

Nel percorso in cui risiede la cartella classi, andremo a creare lo script PHP che verrà contattato per primo dal filmato Flash.
Lo script in questione avrà il nome "upload.php", e sarà lo script che riceverà il file inviato vero e proprio.

upload.php
<?php

	require_once("classi/File.php");

	try
	{
		$file = new File(UploadSettings::NAME, UploadSettings::FILE_PATH);
		$file->tipo(GIF, PNG, JPEG, GENERIC);
		$file->dimensione(UploadSettings::MAX_SIZE, "kb");
		$file->sposta();
	}
	catch (ErroreFile $e)
	{
		if (UploadSettings::LOG_ME)
			fwrite($file->log, "exception:'" . $e->messaggio() . "'");
	}
	catch (Exception $e)
	{
		if (UploadSettings::LOG_ME)
			fwrite($file->log, "exception:'" . $e->getMessage() . "'");
	}

?>

Il sorgente è molto breve, in quanto i controlli vengono effettuati tutti dalla classe File.
Il resto dello script non fa altro che loggare eventuali eccezioni nel caso in cui la costante LOG_ME sia impostata sul valore true.

In pratica il costruttore della classe File inizializza il file di log e lo script procede tentando di archiviare il file.
Se si verifica un'eccezione, i due blocchi catch la memorizzano nel file di log. A questo punto lo script termina e vengono quindi richiamati tutti i distruttori delle varie classi, quindi anche quello della classe File che come abbiamo visto nel capitolo precedente, scriverà una linea di formattazione nel file di log e poi lo chiuderà con fclose().

Una volta inviato il file, il filmato Flash contatterà un secondo script PHP per verificare che il file sia stato accettato e correttamente archiviato sul server.

Il secondo script prenderà il nome di "verify.php" :

verify.php
<?php

	require_once("classi/UploadSettings.php");

	$filename = UploadSettings::FILE_PATH . $_POST["filename"];

	if (file_exists($filename)) echo "success=1";
	else echo "success=0";

	if (UploadSettings::LOG_ME)
	{
		$file = fopen(UploadSettings::LOG_FILE, "r");
		$log = fread($file, filesize(UploadSettings::LOG_FILE));
		echo "&log=$log";
	}

?>

Lo script soprastante non fa altro che verificare la corretta archiviazione del file inviato ad upload.php, tramite la funzione nativa file_exists().

Una volta chiamata la funzione, restituirà il risultato al filmato Flash inviando le variabili in codifica URL tramite il costrutto echo.

Per motivi di debug, ho impostato lo script in modo che restituisca a Flash anche il contenuto del file di log, in modo da non obbligarci a scaricarlo via FTP per effettuarne la lettura.

Nel prossimo capitolo inizieremo a vedere il codice Client Side in ActionScript 3, che fornirà l'interfaccia per l'invio dei file ai nostri utenti.

2. Server Side

In questo capitolo vedremo il codice Server Side in PHP 5, responsabile della gestione e della memorizzazione del file inviato tramite l'applicazione in ActionScript 3, che studieremo invece nei capitoli successivi.

Come già anticipato nei capitoli precedenti, le classi in questione le abbiamo già viste nella Guida a PHP 5, più esattamente nel capitolo Classi per l'upload di file.

Il codice della classe ErroreFile è rimasto invariato, mentre per la classe File ho definito un distruttore e ho effettuato qualche modifica al costruttore, ma prima di introdurre queste modifiche è necessaria una premessa.

La classe FileReference non ci consente di ricevere una risposta personalizzata dallo script PHP che si occuperà dell'archiviazione del file inviato, ma ci consente solo di gestire delle determinate eccezioni tramite i blocchi try e catch.

Questo fattore ci obbliga a interrogare un secondo script PHP una volta che il file è stato inviato,per verificarne l'effettiva archiviazione sul server.
Inoltre, nel caso in cui l'archiviazione non fosse andata a buon fine, ho ampliato la classe File come ho accennato prima, inserendo nel costruttore e nel distruttore del codice che creerà un file di log sul server, in modo da poter risalire con maggior precisione al motivo per cui il file non è stato accettato.

Per prima cosa vediamo il codice PHP della nuova classe UploadSettings, una collezione di costanti che ci consentirà di configurare rapidamente il nostro script :

UploadSettings.php
<?php

	final class UploadSettings
	{
		const NAME = "Filedata";
		const MAX_SIZE = 1024; // Espresso in KiloByte
		const FILE_PATH = "C:/Appserv/www/RealizzazioneSito/articoli/as3 files/upload/";

		const LOG_ME = true;
		const LOG_FILE = "upload.log";
	}

?>

Di default la classe ActionScript FileReference, invierà il file al server con il nome Filedata, accessibile quindi da PHP tramite l'array globale $_FILES["Filedata"].
Dal momento che è possibile assegnare un nome personalizzato al file, ho creato la costante NAME nella classe PHP UploadSettings, in modo da poter riconoscere immediatamente il file inviato.

Seguono altre costanti come MAX_SIZE che definisce la dimenzione massima in kilobyte che il file potrà avere.
FILE_PATH indica la cartella del server dove dovranno essere salvati i file inviati.
Infine le costanti LOG_ME e LOG_FILE indicano rispettivamente se lo script dovrà loggare le attività di upload, e il nome del file di log.

A questo punto non ci resta che dare un'occhiata alle modifiche effettuate alla classe File.
Oltre alle modifiche a costruttore e distruttore, ho definito una nuova costante che consentirà allo script di accettare anche file di tipo generico, rappresentando il tipo MIME corrispondente alla stringa "application/octet-stream".

File.php
<?php

	require_once("ErroreFile.php");
	require_once("UploadSettings.php");

	// MIME Types
	define("GIF", "image/gif");
	define("JPEG", "image/jpeg");
	define("PNG", "image/png");
	define("PSD", "image/psd");
	define("BMP", "image/bmp");
	define("TIFF", "image/tiff");
	define("GENERIC", "application/octet-stream"); // Nuova costante
	define("FLASH", "application/x-shockwave-flash"); // Filmato Adobe Flash

	class File
	{
		public $log;
		private $file;
		private $cartella;

		public function File($nome, $cartella = "/upload/")
		{
			// Inizio frammento di nuovo codice per il log
			if (UploadSettings::LOG_ME)
			{
				$this->log = fopen(UploadSettings::LOG_FILE, "a ");
				$content = "########## " . date("d/m/Y - H:i:s", time()) . "\n";
	
				foreach ($_FILES[$nome] as $chiave => $valore)
					$content .= "$chiave:'$valore'\n";
	
				fwrite($this->log, $content);
			}
			// Fine frammento di nuovo codice per il log

			if (isset($_FILES[$nome]))
			{
				$this->file = $_FILES[$nome];
				$this->cartella = $cartella;
			}
			else
				throw new ErroreFile(UPLOAD_ERR_NO_FORM);
		}

		public function tipo()
		{
			if (!func_num_args()) throw new ErroreFile(UPLOAD_ERR_NO_TYPE);

			$tipi = func_get_args();

			foreach ($tipi as $chiave => $valore)
				if ($this->file["type"] == $valore)
					return true;

			throw new ErroreFile(UPLOAD_ERR_NO_TYPE);
		}

		public function dimensione($dim, $unita = "byte")
		{
			if (strcasecmp($unita, "byte") == 0) $dim = (int) $dim;
			else if (strcasecmp($unita, "kb") == 0) $dim = (int) $dim * 1024;
			else if (strcasecmp($unita, "mb") == 0) $dim = (int) $dim * 1024 * 1024;
			else $dim = 0;

			if ($this->file["size"] > $dim) throw new ErroreFile(UPLOAD_ERR_FORM_SIZE);
		}

		public function sposta()
		{
			$ok = @move_uploaded_file($this->file["tmp_name"], $this->cartella . $this->file["name"]);

			if (!$ok) throw new ErroreFile(UPLOAD_ERR_MOVE);
		}

		public function immagine($dir, $alt = NULL)
		{
			$dimensioni = getimagesize($dir . $this->file["name"]);
			$dimensioni = $dimensioni[3]; // height="yyy" width="xxx"

			
			$imgtag = "<img src=\"$dir" . $this->file["name"] . "\" ";
			$imgtag .= "$dimensioni ";
			$imgtag .= (strlen($alt) ? "alt=\"$alt\"" : "") . " />";

			return $imgtag;
		}

		public function __get($attributo)
		{
			if (array_key_exists($attributo, $this->file))
				return $this->file[$attributo];

			return false;
		}

		public function __toString()
		{ return $this->file["name"]; }

		// Nuovo distruttore
		// Scrive una linea di chiusura nel file di log e lo chiude
		function __destruct()
		{
			fwrite($this->log, "\n##########\n\n");
			fclose($this->log);
		}
	}

?>

Ora che la nostra libreria PHP è al completo, possiamo proseguire nel prossimo capitolo dove verranno illustrati i due script PHP che avranno il compito di comunicare direttamente con il filmato Flash.

Condividi contenuti