Manipolare i file
Tecniche che devi affinare
- Come aprire un file
- Come leggere da un file
- Come scrivere su un file
- Come chiudere un file
- Come interagire con il file system
- Come bloccare i file
- Miscellanea sui file
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:
| Mode | Descrizione |
|---|
| r | Apre il file solamente per leggere; posizionamento all'inizio del file |
| r+ | Apre il file per leggere e per scrivere; posizionamento all'inizio del file |
| w | Apre 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 |
| a | Apre 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 |
| x | Crea 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_SH | Cerca di acquisire un lock shared |
| LOCK_EX | Cerca di acquisire un lock esclusivo |
| LOCK_UN | Rilascia 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 ^