[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico] [volume] [parte]


Capitolo 218.   La gestione del file system

Il file system è ben gestito dal PHP, le funzioni a disposizione degli sviluppatori sono innumerevoli, inoltre sono ben integrate con il sistema operativo in modo particolare GNU/Linux.

Ad esempio è possibile ottenere e cambiare i permessi, il proprietario e il gruppo di un file, creare collegamenti simbolici, copiare, spostare, eliminare directory e file. Dunque gli strumenti a disposizione non mancano e molti di essi verranno trattati nelle pagine seguenti.

Prima di entrare nello specifico è bene precisare ancora una volta che il file system su cui il PHP opera è quello dell'elaboratore servente, quindi se si crea un file esso viene creato sul disco del servente e non su quello del cliente.

Tramite il protocollo HTTP il PHP può gestire anche il trasferimento di file dall'elaboratore cliente a quello servente, questo però verrà trattato nella sezione dedicata alla programmazione avanzata.

218.1   Concetto di file

Un file può essere visto come un contenitore nel quale immagazzinare informazioni. La gestione fisica del file su disco viene effettuata dal sistema operativo a cui si interfaccia il PHP.

Per poter accedere alle informazioni contenute in un file è necessario aprirlo, leggerne il contenuto, eventualmente modificarlo e infine chiuderlo.

I dati vengono salvati nel file sotto forma di righe, per indicare il fine riga nei file di testo viene utilizzato \n, mentre la fine del file è ottenuta tramite la funzione feof() che restituisce un valore booleano vero se ci si trova alla fine del file.

La particolarità fondamentale di questa struttura è il suo accesso, a differenza degli array non è possibile puntare direttamente ad una riga ben precisa del file è dunque necessario scorrere il suo contenuto fino ad arrivare alla riga desiderata. Questo tipo di accesso viene detto "accesso sequenziale".

Non ci sono, inoltre, limiti massimi o minimi per le dimensioni del file, esse dipendono dalla disponibilità di spazio su disco.

218.2   Apertura di un file

Se un file è un contenitore per poter accedere al suo contenuto è necessario aprirlo, per farlo si utilizza la funzione fopen() a cui va fornito il file con il percorso, se diverso da quello dello script, e il tipo di apertura. Dunque al momento dell'apertura del file bisogna dichiarare il tipo di operazione che si desidera eseguire su di esso, ad esempio se si vuole solo leggere, scrivere o semplicemente aggiungere dati alla fine. Ecco l'elenco dei possibili modi di accedere ad un file in PHP:

Il PHP permette anche di aprire file remoti tramite i protocolli più diffusi come HTTP e FTP, ovviamente il file deve essere raggiungibile almeno in lettura.

Ecco qualche esempio di apertura di file:

0  $f = fopen ("dati.txt", "w");
1  $f = fopen ("/home/qualche_percorso/dati.txt", "a");
2  $f = fopen ("http://www.php.net/", "r");
3  $f = fopen ("ftp://nome_utente:password@indirizzo_del_sito_ftp.com/", "w"); 

Va notato che la funzione ritorna un intero. La variabile $f contiene i riferimenti al file aperto, viene anche detto "puntatore al file" anche se non ha nulla a che vedere con la "struttura puntatore". Tutte le operazione sarnno eseguite sul puntatore al file.

Nella riga 0 il file viene aperto in sola scrittura un file che si trova nella stessa directory dello script, se non esistere viene creato. Nella riga 1 il file viene aperto in un ben preciso punto del del disco del servente. Negli ultimi due esempi i file aperti risiedono in remoto e sono aperti tramite i due protocolli HTTP ed FTP

Fare molta attenzione ai permessi dei file che si intende manipolare e delle directory in cui sono contenuti. Ricordare che l'utente che accede al file è quello che lancia il servente HTTP e di conseguenza l'interprete PHP in esso caricato come modulo. Tale utente viene specificato nel file di configurazione del servente.

218.3   Lettura di un file di testo

Il primo passo sarà quello di leggere un semplice file di testo esistente e contenuto nella stessa directory dello script. Verrà utilizzato il metodo di sola lettura con l'indispensabile controllo di errore e ancora prima di esistenza del file da leggere. Se si salvano informazioni riservate in file di testo è bene farlo in una directory che non faccia parte dei documenti WEB altrimenti potrebbe essere richiamato e letto direttamente dal navigatore. Inoltre è importante nascondere eventuali errori mediante una corretta gestione degli stessi al fine di evitare la visualizzazione di informazioni importanti come il percorso e il nome del file che si tenta di aprire. Prima di scrivere il codice è bene creare il file da leggere, nominarlo come dati_1.txt e riempirlo con del semplice testo.

Un esempio di dati_1.txt:

Salve a tutti,
scrivo nel file per poi leggere con php.
di seguito una riga vuota

e poi il file finisce!

Ecco il programma che legge il file appena creato:

0  <html><body>
1  
2  <?
3  if (file_exists("dati_1.txt")){
4    echo "Il file dati_1.txt esiste. Ecco il suo contenuto:<br>";
5  
6    $f = @fopen("dati_1.txt", "r");  // apre il file in sola lettura
7    if($f){
8      while(!feof($f)){  // un semplice while fino alla fine del file
9        $riga = fgets($f,4096);  // legge la riga
10       echo "<br>".$riga;  // visualizza la riga
11     }
12     @fclose($f);  // è importante chiudere il file 
13   }else{
14     echo "Errore durante l'apertura del file!";
16   }
17
18 }else{
19    echo "Il file dati_1.txt NON esiste!";
20 }
21 ?>
22
23 </body></html>

Nella riga 3 viene controllata l'esistenza del file di testo tramite la funzione file_exists() che come riportato nel manuale ufficiale alla sezione "XXVI. Filesystem functions" ritorna un valore booleano vero se il file esiste falso negli altri casi. Questa sezione del manuale è ricca di funzioni per la gestione dei file si consiglia vivamente di approfondirne la lettura.

Alla riga 6 il file viene aperto in sola lettura è bene fare attenzione alla gestione dell'errore. Se l'apertura va a buon fine tramite una struttura ciclica ne viene visualizzato il contenuto. La lettura viene interrotta nel momento in cui la funzione feof() resituisce valore vero, questo accade quando si arriva alla fine del file.

Per la lettura delle singole righe del file è stata utilizzata la funzione fgets() che restituisce una stringa o un valore falso in caso di errore.

Molto importante è l'istruzione della riga 12 con la quale viene chiuso il puntatore al file definito nella fase di apertura. È bene liberare un file prima possibile per evitare problemi di scrittura concorrenziale. Anche questa funzione ritorna un valore booleano vero se l'operazione va a buon fine, falso altrimenti.

Se il file di testo da leggere è piccolo si può utilizzare la funzione file("nome_del_file"), ovviamente oltre al nome del file può essere specificato un particolare percorso e il tutto può essere contenuto in una variabile da passare come parametro. La funzione file() resituisce un array formato da tanti elementi quante sono le righe del file di testo, ogni elemento conterrà il testo della riga relativa. Ad esempio nel caso del precedente file dati_1.txt:

0  <html><body>
1  
2  <?
3   $appo = @file("dati_1.txt");
4   if ($appo){
5     echo "Operazione riuscita il contenuto del file dati_1.txt 
6           è nell'array <b>\$appo</b><br>";
7       $i=0;
8       foreach($appo as $valore)  // visualizzo il contenuto dell'array
9         echo "<br>".$valore; 
10      
11  }else{
12    echo "Errore nella lettura del file! Accertarsi che 
13          esista e che i permessi siano corretti";
14  }
15  
16 ?>
17
18 </body></html>

Questa funzione risulta molto comoda e rapida inquanto non necessita di istruzioni per l'apertura e la chiusura del file. È evidente che in questo modo il contenuto può essere soltanto letto e non modificato. In caso di file di dimensioni medio grandi è preferibile utilizzare le funzioni classiche viste in precedenza che benchè più macchinose garantiscono una migliore gestione del file e della memoria.

218.4   Scrittura in un file di testo

Come al solito prima di poter operare sul contenuto del file bisogna aprirlo, ovviamente per poter inserire dei dati nel contenitore bisogna aprirlo in modalità di scrittura. Come visto in precedenza esistono varie modalità e per ogni situazione va scelta quella ottimale. Di seguito esamineremo alcuni metodi di scrittura nel file.

Il tipo r+ permette di leggere e scrivere nel file che si sta aprendo e posiziona il puntatore all'inizio del contenitore senza alterarne a priori il contenuto. È utile quando bisogna posizionare una riga in una ben precisa posizione del file.

Nel caso di w e w+ il file viene aperto in scrittura o scrittura e lettura e viene immediatamente svuotato. Può essere comodo nel caso di file di appoggio che possono essere sovrascritti senza doverne controllare il contenuto.

Il metodo di apertura a e a+, che serve ad accodare righe al file, verrà trattato in dettaglio nel paragrafo 218.5.

Nell'esempio seguente si salva nel file dati_3.txt l'indirizzo IP dell'ultimo visitatore che ha caricato la pagina 3.php. Anche questo come tutti gli esempi di questo capitolo è raggiungibile al solito indirizzo: <http://www.urcanet.it/brdp/php_manual/esempi/> nel caso specifico: <http://www.urcanet.it/brdp/php_manual/esempi/cap_5/3.php>

0  <html><body>
1  
2   <?
3     $f = @fopen("dati_3.txt", "w");   // lo apre e lo svuota. se non esiste lo crea
4     if($f){
5       echo "<br><br>file <a href=\"dati_3.txt\">dati_3.txt</a> Aperto correttamente.";
6       echo "<br><br>Sto salvando i tuoi dati nel file";
7
8       $frase = "Ultimo visitatore ad aver eseguito lo script 3.php \n\n";
9       $frase = $frase."il suo IP:".$REMOTE_ADDR." \n";
10
11      @fputs($f,$frase);    // scrive la frase nel file tramite $f
12      @fclose($f);          // è importante chiudere il file 
13     
14      echo "...... Fatto!";
15
16    }else{
17      echo "<br>Errore durante l'apertura del file dati_3.txt";
18    }
19  ?>
20
21 </body></html>

Nella riga 3 il file viene aperto in sola scrittura e come più volte ripetuto il suo contenuto viene cancellato. Dunque questo codice sarà in grado di mantenere traccia soltanto dell'ultimo visitatore. Sarebbe più interessante memorizzare più visite ma bisogna fare i conti con la crescita del file, se la pagina è molto frequentata le dimensioni del file di log potrebbero crescere a dismisura fino a saturare lo spazio su disco. Un buon esercizio potrebbe essere la realizzazione di uno script che tenga traccia degli ultimi $n visitatori, dove $n è un parametro che può essere impostato a seconda delle esigenze.

Di seguito una possibile soluzione:

0  <html><body>
1  <? 
2   $n = 4;  // numero di visite da mantenere
3   $f = @fopen("dati_4.txt", "r");
4
5   if($f){
6
7     echo "<br>file dati_4.txt esistente ed aperto correttamente <br>";
8     $i=0;
9     while( !feof($f) && $i<$n-1 ){   // finchè fine del file o il $i< $n-1
10      $righe[$i] = @fgets($f,4096);  // file piccolo! utilizzo array sacmbio
11      $i++;
12    }
13    @fclose($f);   // è importante chiudere il file 
14
15    $f = @fopen("dati_4.txt", "w");  // adesso lo riempio con i nuovi dati.   
16    if($f){
17      echo "<br><br>file <a href=\"dati_4.txt\">dati_4.txt</a> Aperto 
18            correttamente. Sto salvando i tuoi dati";
19
20      $frase = "visitatore di 4.php - ";
21      $frase = $frase."il suo IP:".$REMOTE_ADDR." alle ore: ".date("d-m-Y G:i:s")." \n";
22      @fputs($f,$frase);     // scrive la frase nel file tramite $f
23
24      for ($i=0; $i<count($righe); $i++)
25        @fputs($f,$righe[$i]);
26
27      @fclose($f);   // è importante chiudere il file 
28      echo ".......Fatto!";
29    }
30
31  }else{
32
33    echo "<br>Il file dati_4.txt non esiste. Lo creo.";
34
35    $f = @fopen("dati_4.txt", "w");
36
37    if($f){
38    
39      echo "<br><br>file <a href=\"dati_4.txt\">dati_4.txt</a> Aperto 
40            correttamente. Sto salvando i tuoi dati";
41
42      $frase = "visitatore di 4.php - ";
43      $frase = $frase."il suo IP:".$REMOTE_ADDR." alle ore: ".date("d-m-Y G:i:s")." \n";
44
45      @fputs($f,$frase);     // scrive la frase nel file tramite $f
46      @fclose($f);           // è importante chiudere il file 
47
48      echo ".......Fatto!";
49
50    }else{
51      echo "<br><br>Non posso creare il file dati_4.txt";
52    }
53  }
54 ?>
55 </body></html>

Ci sono vari modi per risolvere il problema, quello usato per questo esempio è volutamente prolisso al fine di utilizzare più volte le funzioni sotto esame così da rendere più semplice l'apprendimento.

Concettualmente si è ragionato in questi termini:

 se il file esiste 
 {
    - leggo le prime $n-1 righe del file
    - le salvo in un array di appoggio
    - chiudo il file 
    - apro il file in scrittura cancellandone il contenuto
    - salvo i dati relativi alla connessione attuale nel file
    - salvo tutte le righe dell'array di appoggio
    - chiudo il file
 }
 altrimenti
 {
    - apro il file in scrittura e viene creato
    - salvo i dati relativi alla connessione attuale nel file
    - chiudo il file 
 }

in realtà non viene fatto un controllo sull'esistenza del file ma si è considerato che se non si riesce ad aprire in sola lettura con il metodo r il file o non esiste o non è leggibile.

Nel ciclo di riga 9 vengono prese le prime $n-1 righe del file o tutto il file se ha meno di $n righe, la condizione che per prima non viene soddisfatta fa abbandonare il ciclo.

Nelle righe 21 e 43 è stata usata la variabile predefinita $REMOTE_ADDR che contiene l'indirizzo IP del visitatore e di seguito la funzione date() già incontrata nalla sezione 214.1 che in questo caso ritorna la data nella forma del tipo: 31-10-2002 15:13:13. Maggiori informazioni in merito possono essere trovate nella sezione "XVI. Date and Time functions" del manuale ufficiale.

In fine nella righa 24 al posto della solita struttura foreach è stata utilizzata volutamente la funzione count() che restituisce il numero di elementi dell'array che gli viene passato come parametro.

In conclusione va notato che l'ultima visita verrà registrata in testa al file mentre le più vecchie verranno scartate mano a mano che ne entreranno delle nuove. Il risultato ottenuto nel file dati_4.txt è simile a:

visitatore di 4.php - il suo IP:192.168.1.153 alle ore: 31-10-2002 15:13:24 
visitatore di 4.php - il suo IP:192.168.1.153 alle ore: 31-10-2002 15:13:17 
visitatore di 4.php - il suo IP:192.168.1.153 alle ore: 31-10-2002 15:13:12 
visitatore di 4.php - il suo IP:192.168.1.153 alle ore: 31-10-2002 15:10:21 

Come conclusione viene proposto un esempio riepilogativo in merito al quale non verranno fornite spiegazioni, sarà compito del lettore capirne il comportamento. Per testarne il funzionamento è tuttavia possibile collegarsi all'indirizzo: <http://www.urcanet.it/brdp/php_manual/esempi/cap_5/5.php>

0 <html><body>
1 <? 
2 /* 
3 Primo tentativo di apertura del file inesistente dati_5.txt in sola lettura
4 il tentativo di apertura fallisce perchè la modalità 'r' non 
5 crea il file in caso di inesistenza, a differenza delle modalità
6 'w' e 'a' che se non esiste lo creano. Quindi il controllo seguente
7 restituirà il messaggio di errore...
8 */
9
10 $f = @fopen("dati_5.txt", "r");
11
12 if($f){
13   echo "<br>1) file dati_5.txt Aperto. Ecco il contenuto: <br>";
14   //Se apre il file facciamo scrivere il contenuto
15   while(!feof($f)){    // finchè non raggiungo la fine del file
16     $riga = @fgets($f,4096);
17     echo "<br>".$riga;
18   }
19   @fclose($f);   // è importante chiudere il file 
20 }else{
21   echo "<br>1) Apertura del file dati_5.txt FALLITA! Ora lo creo e lo riempio.";
22 }
23 
24 /* 
25 Secondo tentativo apro in sola scrittura il file
26 il tentativo di apertura riesce perchè la modalità 'w' 
27 crea il file in caso di inesistenza. Il controllo seguente
28 restituirà messaggio positivo. 
29 ATTENZIONE in questo caso il file viene svuotato al momento 
30 dell'apertura, il contenuto viene perso.
31 */
32 
33 if (!file_exists("dati_5.txt")){
34
35   $f = @fopen("dati_5.txt", "w");
36   if($f){
37 
38     echo "<br><br>2) file dati_5.txt Aperto correttamente. Lo riempio";
39 
40     // sappiamo che va a buon fine e quindi scriviamoci qualcosa dentro.
41     // notare che \n inserisce un fine riga!!!
42     $frase = "Ciao Popolo. \n";
43     $frase = $frase."Scrivo nel mio primo file in PHP \n";
44     $frase = $frase."Speriamo bene! \n";
45     $frase = $frase."CIAO";
46
47     @fputs($f,$frase);    // scrive la frase nel file tramite $f
48     @fclose($f);          // è importante chiudere il file 
49
50   }else{
51     echo "<br><br>2) Apertura del file dati_5.txt <strong>FALLITA!</strong>";
52   }
53
54 }else{
55 
56   echo "<br><br>2) Il file dati_5.txt esiste già. Allora lo RIMUOVO!";
57   if(@unlink ("dati_5.txt")){
58     echo "<br><br> FILE dati_5.txt RIMOSSO CORRETTAMENTE";
59   }else{
60     echo "<br><br> ERRORE durante la rimozione di dati_5.txt";
61   }
62 }
63 ?>
64 </body></html>

In questo ultimo esempio viene utilizzata per la prima volta la funzione unlink() che serve ad eliminare il file che riceve come parametro, essa restituisce un intero che assume valore pari a 0 o falso se l'operazione di cancellazione non va a buon fine.

218.5   Accodare testo in un file

Ovviamente esistono metodi più semplici, immediati e dunque migliori per tenere traccia di qualunque evento. Prima di continuare è bene ricordare che il servente HTTP memorizza in file di log le informazioni relative alle connessioni quindi se non si hanno particolari esigenze tracciare le visite degli utenti potrebbe essere un'operazione ridondante.

Il PHP come visto nella sezione 218.2 permette di aprire un file in modalità "append", ovvero in modo che le righe inserite vengano appese alla fine del file. questo metodo è utilizzabile passando alla funzione fopen() il parametro a o a+, nel primo caso il file viene aperto in sola scrittura mentre nel secondo in scrittura e lettura, il puntatore viene posizionato alla fine del file e se non esiste il file specificato viene creato.

Se si pensa al problema affrontato precedentemente (sezione 218.4) ci si rende immediatamente conto che utilizzando questo metodo di scrittura nel file si possono accodare le informazioni utilizzando poche righe di codice. Ad esmpio:

0  <html><body>
1  
2   <?
3     $f = @fopen("dati_6.txt", "a");   //apre in scrittura. se non esiste lo crea
4     if($f){
5       echo "<br><br>file <a href=\"dati_6.txt\">dati_6.txt</a> Aperto.";
6       echo "<br><br>Sto salvando i tuoi dati nel file";
7
8       $frase = "visitatore di 6.php - ";
9       $frase = $frase."il suo IP:".$REMOTE_ADDR." alle ore: ".date("d-m-Y G:i:s")." \n";
10
11      @fputs($f,$frase);    // scrive la frase nel file tramite $f
12      @fclose($f);          // è importante chiudere il file 
13     
14      echo "...... Fatto!";
15
16    }else{
17      echo "<br>Errore durante l'apertura del file dati_6.txt";
18    }
19  ?>
20
21 </body></html>

È bene sottolineare che in questo caso non ci sono controlli sulle dimensioni del file di testo generato. Ogni volta che lo script viene eseguito il file dati_6.txt aumenta di dimensioni. Se la pagina è molto visitata a lungo andare potrebbe addirittura saturare il disco. Visto che questo è un semplice esercizio e non si ha alcun bisogno dei dati contenuti nel file verrà aggiunto un controllo che elimina il file sele sue dimensioni superano un determinato valore. Ecco una soluzione:

0  <html><body>
1  
2   <?
3     $max_file_size = 4000;  // dimensione massima in byte
4
5     if(filesize("dati_6.txt") > $max_file_size ){
6       echo "<br><br><b>Vuoto il file! ha superato il limite</b><br><br>";
7       $f = @fopen("dati_6.txt", "w");   //lo apre scrittura e lo svuota
8     }else{
9       $f = @fopen("dati_6.txt", "a");   //lo apre scrittura e appende i dati 
10    }
11    if($f){
12      echo "<br><br>file <a href=\"dati_6.txt\">dati_6.txt</a> Aperto.";
13      echo "<br><br>Sto salvando i tuoi dati nel file";
14
15      $frase = "visitatore di 6.php - ";
16      $frase = $frase."il suo IP:".$REMOTE_ADDR." alle ore: ".date("d-m-Y G:i:s")." \n";
17
18      @fputs($f,$frase);    // scrive la frase nel file tramite $f
19      @fclose($f);          // è importante chiudere il file 
20     
21      echo "...... Fatto!";
22
23    }else{
24      echo "<br>Errore durante l'apertura del file dati_6.txt";
25    }
26  ?>
27
28 </body></html>

Le modifiche sono semplici, è stato aggiunto un if che controlla la dimensione del file dati_6.txt se è maggiore del valore impostato nella variabile $max_file_size apre il file in modalità w e quindi ne cancella il contenuto, altrimenti lo apre in modalità a. In entrambi i casi se il file non esiste viene creato.

218.6   Conclusioni

Il file system, come appena visto, permette di immagazzinare informazioni su disco dando la possibilità di aggiornarle modificandole o cancellandole. Tuttavia è bene tenere presente che esistono tecnologie relazionali apposite per la gestione di grandi moli di dati che garantiscono maggiori prestazioni e una migliore gestione dello spazio su disco. Tali tecnologie sono le basi di dati alle quali si accede tramite un linguaggio di interrogazione standard noto come SQL(1).

Il file rimane comunque uno strumento utile, semplice e immediato, e nel caso di piccole quantità di dati o nel caso in cui non si abbia accesso ad un DBMS(2), può essere preso in considerazione come alternativa alle basi di dati.

Programmare in PHP --- Copyright © 2001-2002 Gianluca Giusti --  brdp @ urcanet.it

1) Acronimo di "Structured Query Language" ovvero "linguaggio di interrogazione strutturato".

2) Acronimo di "Data Base Management System " ovvero "Sistema di Gestione di Basi di Dati", è il software che si occupa di rispondere alle istruzioni SQL.


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome la_gestione_del_file_system.html

[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico]