Manipolare i file
Tecniche che devi affinare
Interagire con i file è un aspetto comune della programmazine. Comunque si lavori con file cache, di informazioni o di impostazioni, la capacità di elaborare i file è un'abilità fondamentale del programmatore PHP. In questo capitolo, imparerai ad aprire file per leggere e scrivere e anche funzioni del filesystem per manipolare gli attributi dei file stessi.
Aprire file
Quando si interagisce con i file, in PHP, per prima cosa bisogna aprirli. Quando si apre un file, questo crea un "risorsa" che devi obbligatoriamente passare alle funzioni per leggere, scrivere e alle funzioni lock. Per aprire un file basta usare la funzione fopen().
fopen() riceve come primo argomento il nome del file da aprire, e come secondo le modalità di apertura del file. Il file può essere sia locale che su rete. In questo capitolo considereremo solamente quelli in locale. La modalità determina ciò che è possibile fare con il file: leggere, scrivere, leggere + scrivere, scrivere dall'inizio, scrivere della fine. La lista completa è presentata nella tabella sottostante:
ModeDescrizione
rApre il file solamente per leggere; posizionamento all'inizio del file
r+Apre il file per leggere e per scrivere; posizionamento all'inizio del file
wApre il file solamente per scrivere; posizionamento all'inizio del file; se il file non esiste verrà creato
w+Apre il file per leggere e scrivere; posizionamento all'inizio del file; se il file non esiste verrà creato
aApre il file solamente per scrivere; posizionamento alla fine del file; se il file non esiste verrà creato
a+Apre il file per leggere e scrivere; posizionamento alla fine del file; se il file non esiste verrà creato
xCrea e apre il file solamente per scrivere; posizionamento all'inizio del file; se il file esiste verrà dato errore
x+Crea e apre il file per leggere e scrivere; posizionamento all'inizio del file; se il file esiste verrà dato errore
Sui sistemi operativi Windows, puoi anche specificare se il file in questione è di testo o binario appendendo al mode una b o una t se il file in questione è, rispettivamente, binario o testuale. Nel caso di file binari, se non viene specificato il "b", questo potrebbe risultare corrotto.
Se fopen() fallisce per qualche motivo, ritornerà false e emetterà un E_WARNING altrimenti ritornerà un puntatore al file. Ecco un esempio per appendere del testo ad un file:
if(($fp = fopen( "file.txt", "a") == false) {
	//chiamata andata male
}
//la chiamata è andata bene
Una chiamata alla funzione fopen() può fallire per svariati motivi tra i quali possono esseci la non esistenza del file o i permessi dell'utente insufficienti.
Chiudere i file
Dopo aver usato e scritto il file, dovresti chiuderlo. File non chiusi verranno automaticamente chiusi da PHP alla fine della sessione automaticamente. Tu puoi usare la funzione fclose().
Leggere da un file
Quando haiun file aperto per leggere, puoi utilizzare vari modi per leggere.Prima però di leggere devi controllare che la risors indicata abbia ancora qualcosa da offrire, ovvero bytes da leggere. Puoi effettuare questo controllo con la funzione feof(). feof() ritorna true se incontra EOF (End Of File) altrimenti ritornerà false.
La funzione base per leggere è fread(). fread() prende due parametri: il primo è il puntatore al file mentre il secondo è la lunghezza in bytes da leggere.
Il seguente è un esempio che legge 1024 bytes da un file:
if(($fp = fopen($filename, "r")) === false) {
	return;
}
while( !feof($fp)) {
	$buffer = fread($fp, 1024);
	//altro
}
Se vuoi leggere dal puntatore riga per riga, puoi usare fgets(). fgets() legge 1024 byte alla volta e quando trova il newline ritorna. Se trova un errore ritrna false altrimenti ritorna la stringa appena letta.
Immaginiamo che esista un file contenente foo=bar e noi volessimo costruirci un array. Ecco il codice:
$arr = array();
if(( $fp = fopen( "$filename,"r")) === false) {
	return;
}
while(!feof($fp)) {
	$line = fgets($fp);
	list($k,$v) = explode('=', rtrim($line));
	$arr[$k] = $v;
}
La funzione fpassthru() permette di fare l'output di tutto il file rimanente. Il codice seguente controlla se i primi quattro byte per verificare che il file sia jpg; se così, imposta la posizione al file all'inizio con la funzione fseek() e poi ne fa l'output con la funzione fpassthru():
function outputjpg( $filename ) {
	if(($fp = fopen( $filename, "r")) === false) {
		return;
	}

	$line = fread( $fp, 4);
	if( $line === "\x77\x30\x77\x40") {
		fseek( $fp, 0 );
		fpassthru( $fp );
	}
	fclose($fp);
}
Scrivere su un file
Se hai un puntatore a file aperto in scrittura, il modo per scrivere è fwrite() (inverso a fread());
fwrite() prende come primo argomento il puntatore al file, come secondo argomento la stringa da scrivere sul file. Opzionale, puoi passare un terzo argomento: la massima lunghezza di scrittura del file. fwrite() ritorna il numero di bytes scritti al puntatore del file (e quindi al file stesso). fputs() è un alias di fwrite().
Ecco un esempio di funzione che appende il time in un logfile assieme ad un messaggio:
function append_to_log( $logline ) {
	if(($fp = fopen( 'debug.log', 'a' )) === false) {
		die("Non riesco ad aprire debug.log");
	}
	fwrite( $fp , time() . " " . $logline . "\n");
	fclose($fp);
}
Determinare informazioni su un file
Per avere informazioni su un file, puoi utilizzare due tipi di funzioni a seconda che tu abbia il file aperto o meno. Nel primo caso puoi usare fstat(). Chiamando fstat() su un puntatore a file avremo a disposizione un array con le seguenti chiavi
"dev"Il numero di dispositivo su cui il file si trova
"ino"Il numero di inode del file
"mode"I mode del file
"nlink"Il numero di hard link a quel file
"uid"Lo user id dell'owner del file
"gid"L'id del gruppo di appartenenza del file
"size"La grandezza del file in bytes
"atime"Il timestamp unix dell'ultimo accesso
"mtime"Il timestamp unix dell'ultima modifica
"ctime"Il timestamp unix dell'ultimo cambiamento (di solito identica a mtime)
Se non hai una risorsa ad un file aperto, puoi generare lo stesso array con la funzione stat(), che prende il nome del file piuttosto che il puntatore. Se il file non esiste la funzione stat() ritorna false.
Php fornisce anche una serie di shortcuts per accedere alle informazioni. Queste funzioni sono elencate nella tabella sottostante:
file_exists()Ritorna true se il file esiste
fileatime()Ritorna l'ultimo accesso al file
filectime()Ritorna la data dell'ultimo cambiamento
filemtime()Ritorna la data dell'ultima modifica
filegroup()Ritorna il gruppo di appartenenza del file
fileinode()Ritorna l'inode del file
fileowner()Ritorna l'id dell'owner del file
fileperms()Ritorna i permessi del file (mode)
filesize()Ritorna la grandezza del file in bytes
filetype()Ritorna il tipo di file
is_dir()Ritorna true se il file è una directory
is_executable()Ritorna true se il file è eseguibile
is_file()Ritorna true se il file è effettivamente un file
is_readble()Ritorna true se il file ha permesso di lettura
is_uploaded_file()Ritorna true se il file è appena stato uploadato sul server
is_writable()Ritorna true se il file ha il permesso di scrittura
Queste funzioni servono anche per prevenire errori, oltre che per ottenere informazioni in generale. Per esempio, questo codice controlla se il file è leggibile e se ha grandezza diversa da zero:
if(!is_file($filename) ||
   !is_readable($filename) ||
   !filesize($filename)) {
   die("$filename non è un buon file!");
}
if(($fp = fopen( "file.txt", "r" ) === false) {
	die("Erroe in apertura $filename");
}
Manipolare file sui filesystem
PHP ti permette di manipolare i file che si trovano sul file system, cancellandoli, copiandoli, cambiando i loro permessi e altro.
Copiare, cancellare e muovere file
Per copiare un file puoi usare la funzione copy() che funziona come segue:
copy( $src_file, $dst_file );
Per cancellare un file si può usare unlink():
unlink( $filename );
Per muovere un file rename():
rename( $old_file, $new_file );
Se il path della sorgente e della destinazione si trovano sullo stesso file system, rename() è atomic, il che significa che esegue istantaneamente. Se invece i filesystem sono diversi, rename() prima copia il vecchio file al nuovo file e poi rimuove il vecchio file. Per copiare il file, se la grandezza del file è significativa ci vorrà un pò di tempo.
Cambiare proprietario e permessi
Per cambiare il proprietario di un file (owner), si usa la funzione chown(). chown() prende come primo argomento il nome del file e sia uno username o un uid come secondo argomento. Solo il superuser può cambiare il proprietario ad un file.
Per cambiare il gruppo di un file, esiste chgrp(). chgrp() come primo argomento ha il nome del file e il gid o il groupname come secondo argomento. Solo il proprietario o il superuser possono cambiare il gruppo del file. Il proprietario deve essere appartenente a tutti e due i gruppi.
Per cambiare i mode di un file: chmod(). chmod(), come è intuibile, prende il nome del file come primo argomento e i nuovi mode in ottale del file come secondo argomento. Bisogna fare attenzione che i numeri siano scritti in forma ottale affinchè i mode vengano interpretati correttamente.
Locking files
Per allontanare definitivamente la possibilità di corrompere i file bisogna per forza di cose usare un lucchetto per moderare l'accesso ai file. PHP supporta questo tramite la funzione flock(). Le funzioni flock() sono a discrezione dell'utente. Ciò siginifica che se il controllo sul lock non viene fatto un qualsiasi utente può aprire il file liberamente. Questo significa il tuo uso di flock deve essere consistente affinchè abbia effetto.Per usare flock(), primo devi avere un file aperto sul quale applicare il lock. Potrai quindi chiamare flock() con il puntatore al file come primo argomento e una costante come secondo argomento.
LOCK_SHCerca di acquisire un lock shared
LOCK_EXCerca di acquisire un lock esclusivo
LOCK_UNRilascia i lock
Di default, queste operazioni bloccano tutto. Significa che se tu stai provando ad ottenere un LOCK_EX mentre un altro processo ha un LOCK_SH il processo tuo si blocca in attesa che il LOCK_SH venga rilasciato.
Un uso comune dei lock puì essere utilizzato, per esempio per scrivere delle informazioni su un file -- per esempio un file di log. Una funzione del genere richiede due componenti: un writer e un reader. Il writer necessiterà di un LOCK_EX per poter scrivere mentre il reader necessiterà solamente di un LOCK_SH cosicchè possa leggere concorrentemente con altri reader.
function retireve_guestbook_data() {
	if(($fp = fopen( "guestbook.log", "r" ) === false) {
		die("Fallito");
	}

	flock( $fp, LOCK_SH );
	$data = fread( $fp, filesize( 'guestbook.log' ));
	flock( $fp, LOCK_UN );
	flocse( $fp );

	return $data;
}
Miscellanea
Oltre le funzioni base, PHP offre una collezione di shortcuts che ti permettono di eseguire task comuni in pochi passi.
file()
Spesso vorrai convertire un file in array contenti le sue righe. La funzione file() provvede a fare quesyto.
Per fil di dimensioni importanti sarà meglio iterare e utilizzare fgets()
readfile()
Similare a fpassthru(), readfile() fa l'output del file direttamente. readfile($filename) è uguale al seguente codice:
if(( $fp = fopen( $filename, 'r' )) {
	fpassthru( $fp );
	fclose( $fp );
}
file_get_contents()
È possibile leggere tutto un file in una stringa con il seguente codice:
if(( $fp = fopen( $filename, 'r' ) === false) {
	$file = false;
} else {
	$file = fread( $fp, filesiaze( $filename ));
}

fclose( $fp );
è molto più efficiente utilizzare la funzione built-in file_get_contents che può rimpiazzare il codice di prima con il seguente:
$file = file_get_contents( $filename );


Torna su ^
P H P

D E V E L O P M E N T