4D e 4E SIA: lezione sui file di testo in Php

4D e 4E SIA: lezione sui file di testo in Php



Gli americani definiscono "file" tutto ciò che viene salvato sulle memorie permanenti (dischi fissi, memorie flash, ecc) ma c'è una sostanziale differenza tra un archivio e un programma.
L'archivio si divide in archivio strutturato e non strutturato.

Dati strutturati:
sono i dati conservati in un archivio di testo ed ogni righa contiene informazioni divise in campi (l'insieme dei campi si definisce record).
I dati possono essere anche memorizzati in un database, organizzati secondo schemi e tabelle rigide. Questa è la tipologia di dati più indicata per i modelli di gestione relazionale delle informazioni.

Dati non strutturati:
sono i dati conservati senza alcuno schema. Un esempio possono essere i file contenenti testi a carattere narrativo prodotti per mezzo di uno dei più diffusi software di editing testuale o un file multimediale.

Il programma invece è un software che può essere eseguito da un elaboratore per ricevere in input determinati dati di un problema automatizzabile e restituirne in output le (eventuali) soluzioni.

Un programma è un insieme di linee di codice a loro volta costituite da un insieme di istruzioni. Il problema deve essere risolvibile attraverso un algoritmo affinché un programmatore possa codificarlo in istruzioni in un linguaggio di programmazione; in questa fase - detta programmazione - viene realizzato il codice sorgente del programma che definisce il suo flusso di esecuzione.

Il termine indica una sequenza logicamente ordinata di comandi, istruzioni e operazioni e differisce dal termine - più generico - di software in quanto un programma è un software che può essere caricato nella memoria RAM per essere eseguito sotto forma di processo, includendo quindi anche quei programmi che girano in background come a esempio in un sistema operativo in esecuzione come a es. le librerie. Analogamente differisce dal termine "applicazione" il quale viene usato normalmente nella prospettiva dell'utente finale per intendere un servizio di cui questi può usufruire, a prescindere dal fatto che questo sia realizzato da un solo programma o da un insieme di programmi - e infatti i programmi operanti su sistemi embedded non sono dunque applicazioni per l'utente ma consentono comunque la funzionalità del dispositivo. In questo caso l'applicazione si compone di un'interfaccia utente e di un nucleo elaborativo.[non chiaro] L'espressione "sistema software" è usata poi, di norma, per indicare esplicitamente una collezione di componenti software come programmi, librerie, file e altro, interagenti fra loro.

In questa lezione tratteremo degli archivi di testo strutturati che conterranno record sequenziali.

In informatica un record (in italiano anche registrazione), è un oggetto o una struttura di dati eterogenei fatta da dati compositi, contenente cioè un insieme di campi o elementi, ciascuno dei quali identificato da un nome univoco e da un tipo di dato, il cui valore è detto attributo (ad esempio: un numero intero, un numero in virgola mobile o una sequenza - stringa - di caratteri alfabetici). Il numero complessivo di caratteri che si possono registrare in un record ("lunghezza del record") è fisso.

Gli archivi testuali sono dei semplici documenti di testo (.txt) in cui vengono salvati dei dati per poi essere letti tramite script php.

In particolare php offre una gamma di funzioni atte alla scrittura e lettura dei file in cui potranno essere salvati dei dati e letti all'occorrenza.


LIMITI DEI FILE DI TESTO
Occorre fin da subito chiarire un punto: i FILE DI TESTO sono utilizzabili solo nel caso in cui la mole di dati in esso contenuta è relativamente piccola e soggetti a sporadiche modifiche.

Infatti avranno una gestibilità decisamente molto più complessa e limitata rispetto a quella ottenibile con un database MySql dato che non sarà possibile formulare le query.
Inoltre, risulta quasi del tutto impossibile istaurare relazioni fra i dati.


IL FUNZIONAMENTO
Al fine di gestire i dati contenuti in un file .txt occorrerà:
"scrivere" il file con una idonea formattazione;
eseguire operazioni su di esso ricorrendo ad alcune funzioni; fra le tante, ve ne sono alcune che assumono particolare rilievo: fopen(), fread(), fwrite(), fclose(), file() ed explode().

Chiariamo i due concetti esaminandoli separatamente.

LA FORMATTAZIONE DI UN FILE DI TESTO
Un file .txt si articola in più righe: ognuno di esse potrà rappresentare un set di dati.

Ad esempio poniamo di voler costruire un archivio in cui salvare i dati riguardanti dei prodotti su un file di testo: ogni riga potrà rappresentare un prodotto.
Tuttavia, per ogni prodotto inserito occorrerà salvare più di una informazione: poniamo, ad esempio, di voler salvare il nome, la taglia e il prezzo.
Affinche più dati siano scritti su un'unica riga occorrerà strutturare una formattazione adeguata. Vediamone un esempio:

capo|taglia|prezzo

Pertanto il file di testo che possiamo chiamare prodotti.txt avrà una struttura di questo genere:

camicia|S|150
felpa|XXL|220
t-shirt|M|250

In pratica i tre dati (nome, taglia e prezzo) che desideriamo salvare su un'unica riga del file .txt saranno separati gli uni dagli altri da un carattere separatore (poco comune) a nostra scelta, nell'esempio "|".

Quindi, un archivio testuale è un file .txt in cui ciascuna riga contiene uno o più dati e all'interno della riga e i singoli dati sono separati da una carattere separatore.
Ciò sarà rilevante sia in fase di lettura, sia in fase di scrittura del file.


LA LETTURA
In fase di "lettura" è possibile far ricorso a diverse funzioni che tuttavia presentano ognuna delle specifiche particolarità.
Quella che in caso di database testuali risulta essere maggiormente utile è file().

La funzione file() accetta come unico parametro il percorso al file che si desidera leggere ed esegue una lettura del file riga per riga restituendo un array in cui ciascun elemento è costituito da un rigo.
Ovviamente, avendo ottenuto un array, questo potrà essere letto con un classico ciclo foreach.

Scorrendo il nostro array otterremo una singola riga per ogni ciclo; per isolare i singoli dati presenti all'interno di tale riga si farà ricorso alla funzione explode().

La funzione explode() riceve due parametri obbligatori: il primo è il carattere separatore; il secondo è una stringa da trasformare in un array.

Vediamo cosa avremo:

<?php  
$my_database_txt = 'prodotti.txt';  
$array_righi = file($my_database_txt);  
foreach($array_righi as $key => $capi){  
    list($capo, $taglia, $prezzo) = explode("|", $capi);  
    echo '  
        <p>  
        Capo: ' .$capo. '<br />  
        Taglia: ' .$taglia. '<br />  
        Prezzo: ' .$prezzo. '<br />  
        <a href="action.php?delete=' .$key. '">Elimina</a> - <a href="form_update.php?row=' .$key. '">Modifica</a>  
        </p>  
        <hr />';  
    }  
?>  

Si ponga attenzione ai link per eseguire l'eliminazione e la modifica di un prodotto il cui funzionamento sarà di seguito illustrato.


LA SCRITTURA
Per poter scrivere su un file di testo occorre anzitutto assicurarsi che questo abbia i permessi di scrittura: a questo scopo può essere utile la funzione is_writable(). Essa prende come parametro il percorso al file e restituisce un valore boleano, TRUE se il file può essere scritto.

La scrittura del file avverrà con le funzioni fopen(), fwrite() e fclose().

La funzione fopen() serve per apire il collegamento con la risorsa (il file da scrivere). Essa prevede due parametri obbligatori: il percorso al file e una stringa che ci indicherà modalità con la quale si vorrà operare sul file (si rimanda al manuale per maggiori dettagli).
La funzione fwrite() esegue la scrittura sul file e prevede due parametri: la risorsa e la stringa da scrivere.
Infine, la funzione fclose() esegue la chiusura del file e prevede come unico parametro la risorsa.

Avremo una pagina con un banale form:

<form action="action.php" method="post">  
<label for="capo">Capo</label>  
    <input type="text" id="capo" name="capo" />  
<label for="taglia">Taglia</label>  
    <input type="text" id="taglia" name="taglia" />  
<label for="prezzo">Prezzo</label>  
    <input type="text" id="prezzo" name="prezzo" />  
      
    <input type="submit" name="scrivi" value="scrivi" />  
</form> 

E poi avremo una pagina (action.php) che eseguirà la scrittura sul un file prodotti.txt:

<?php  
$my_database_txt = 'prodotti.txt';  
if(isset($_POST['scrivi']))  
    {  
    if(!is_writable($my_database_txt)){  
        exit("il file non ha i permessi di scrittura!");  
        }  
    // riceviamo i dati e li filtriamo  
    $bad_char = array("|", "rn", "r", "n");  
    $capo = str_replace($bad_char, "", $_POST['capo']);  
    $taglia = str_replace($bad_char, "", $_POST['taglia']);  
    $prezzo = str_replace($bad_char, "", $_POST['prezzo']);  
    // apriamo il file  
    $open = fopen($my_database_txt, "a+");  
    // scriviamo i dati separati dal carattere separatore  
    fwrite($open, $capo."|".$taglia."|".$prezzo."rn");   
    // chiudiamo il file     
    fclose($open);  
      
    // ritorniamo nella pagina di visualizzazione  
    header("location: lettura.php");  
    exit;  
    }  
?>  

ELIMINARE UNA RIGA DAL FILE .TXT
Eliminare un rigo sta a significare, nel caso del nostro archivio basato su file di testo, eliminare un prodotto. Abbiamo precedentemente visto che ciascun prodotto avrà un link per l'eliminazione scritto attaverso un ciclo foreach di questo tipo (si veda il codice per eseguire la lettura):


<a href="action.php?delete=' .$key. '">Elimina</a>  

La variabile $key all'interno del ciclo individua la chiave dell'array ottenuto con la funzione file() e, quindi, ci consente di individuare il rigo specifico che vogliamo eliminare. Nel file action.php pertanto avremo:


if(isset($_GET['delete']))  
    {  
    // creiamo l'array con tutti i righi  
    $array_righi = file($my_database_txt);  
    // eliminiamo dall'array il rigo la chiave inviata via get  
    unset($array_righi[$_GET['delete']]);  
    // apriamo il file resettando il contenuto  
    $open = fopen($my_database_txt, "w");  
    foreach($array_righi as $key => $value){  
        // ri-scriviamo tutti i righi (rimanenti)  
        fwrite($open, $value);  
        }  
    fclose($open);  
    // ritorniamo nella pagina di visualizzazione  
    header("location: lettura.php");  
    exit;  
    }  

Occorre notare che con la funzione unset() eliminiamo l'elemento dall'array; inoltre la funzione fopen, a differenza di quando fatto in precedenza, avrà come secondo parametro w e quindi verrà cancellato l'intero file e riscritto di nuovo ma senza il rigo eliminato.
Il codice proposto necessiterebbe di ulteriori e più rigidi controlli (quantomeno con array_key_exists) ma ho voluto ridurre al minimo lo script.


LA MODIFICA DI UNA RIGA DI UN FILE .TXT
La modifica della singola riga segue una logica per molti aspetti simile a quella vista per l'eliminazione. Tuttavia in questo caso avremo uno step ulteriore: dovremo precompilare un form con i dati correnti della riga che desideriamo modificare e poi, al submit di tale form, eseguire la modifica.

Anzitutto esaminiamo il link che rimanda alla pagina di modifica che, ricordo, viene prodotto all'interno del ciclo foreach (si veda il codice per eseguire la lettura):

<a href="form_update.php?row=' .$key. '">Modifica</a>  


Come detto in precedenza per l'eliminazione, $key ci permetterà di individuare la riga che desideriamo modificare. In questo caso dovremo estrarre i dati contenuti in tale riga e compilare i value del form:

<?php  
$my_database_txt = 'prodotti.txt';  
if(!isset($_GET['row'])){  
    header("location: lettura.php");  
    exit;  
    }  
$array_righi = file($my_database_txt);  
if(!isset($array_righi[$_GET['row']])){  
    exit('errore nella chiave');  
    }  
list($capo, $taglia, $prezzo) = explode("|", $array_righi[$_GET['row']]);  
?>  
<html>  
<head>  
</head>  
<body>  
<h2><a href="lettura.php">Torna alla lista degli articoli</a></h2>  
<form action="action.php" method="post">  
<label for="capo">Capo</label>  
    <input type="text" id="capo" name="capo" value="<?php echo htmlentities($capo, ENT_QUOTES); ?>" />  
<label for="taglia">Taglia</label>  
    <input type="text" id="taglia" name="taglia" value="<?php echo htmlentities($taglia, ENT_QUOTES); ?>" />  
<label for="prezzo">Prezzo</label>  
    <input type="text" id="prezzo" name="prezzo" value="<?php echo htmlentities($prezzo, ENT_QUOTES); ?>" />  
    <input type="hidden" name="row_update" value="<?php echo $_GET['row']; ?>" />  
    <input type="submit" name="modifica" value="modifica" />  
</form>  
</body>  
</html>  

Si noti il campo name="row_update" di tipo hidden che avrà come value la chiave inviata via get. All'invio del form andremo a recuperare i dati inviati: i nuovi valori che dovrà assumere la riga e la riga da modificare (presente nel campo hidden). Pertanto avremo:


$my_database_txt = 'prodotti.txt';  
if(isset($_POST['modifica']) AND isset($_POST['row_update']))  
    {  
    // creiamo l'array con tutti i righi  
    $array_righi = file($my_database_txt);  
    // riceviamo i dati e li filtriamo  
    $bad_char = array("|", "rn", "r", "n");  
    $capo = str_replace($bad_char, "", $_POST['capo']);  
    $taglia = str_replace($bad_char, "", $_POST['taglia']);  
    $prezzo = str_replace($bad_char, "", $_POST['prezzo']);  
    // ri-scriviamo il rigo (che sostituirà il precedente)  
    $array_righi[$_POST['row_update']] = $capo."|".$taglia."|".$prezzo."rn";  
    // apriamo il file resettando il contenuto  
    $open = fopen($my_database_txt, "w");  
    foreach($array_righi as $key => $value){  
        // ri-scriviamo tutti i righi  
        fwrite($open, $value);  
        }  
    fclose($open);  
    // ritorniamo nella pagina di visualizzazione  
    header("location: lettura.php");  
    exit;     
    }  

Come possiamo notare lo script segue una logica analoga a quella vista per l'eliminazione con l'unica differenza che anziché eliminare l'elemento dall'array $array_righi con unset lo andremo a valorizzare con i nuovi valori (opportunamente filtrati) provenienti dal form, semparando i valori con il carattere separatore | e aggiungendo a fine stringa il ritorno a capo.

Di seguito il link al download dei file in cui è presente lo script completo.
http://www.miniscript.it/application/download/download.php?id=13

Lezioni sui file di testo degli anni precedenti:
https://paololatella.blogspot.com/2016/09/la-gestione-dei-file-di-testo-in-php.html

Approfondimenti sul mio libro scaricabile gratuitamente in formato pdf: 
http://laboratoriosia.altervista.org/3DSIA/informatica/eserciziphp/filemanager_didattico2/fileman/uploads/ebook_php_paololatella.pdf

Commenti

Post popolari in questo blog

Simulazioni di reti (con Cisco Packet Tracer)

Esercizi sulla rappresentazione della virgola mobile IEEE 754 (Floating Point)