IMC!


Contenuti


Foto

 







Curiosando...
Novita  Novità Link  Link Blog  Blog English  Español 
Accesso contemporaneo ai file e lock in PHP


Non � raro che una pagina di un sito internet scritta in PHP debba accedere in lettura o in scrittura a dei file, come un database SQLite, un'immagine generata o modificata dinamicamente con librerie GD, un documento pdf aggiornato con FPDF, un file compresso generato al volo per il download da parte dell'utente.

Immaginiamo che tale pagina PHP del nostro sito internet venga richiesta contemporaneamente da due utenti nella rete. Di conseguenza, avremo due esecuzioni quasi contemporanee dello script, che chiameremo, in ordine cronologico, Processo A e Processo B. In realt�, non � sempre vero che ogni esecuzione di uno script generi un processo separato, ma per semplicit� assumeremo che sia cos�. I due processi cercheranno di leggere o scrivere contemporaneamente sul file pippo.txt, generando dei problemi. In particolare, per un server Windows:
  1. Se il processo B, lanciato per secondo, cerca di aprire il file in scrittura col comando fopen('pippo.txt', 'w'), l'operazione viene completata correttamente anche se il file era gi� aperto in scrittura dal Processo A;
  2. Se entrambi i processi cercano di scrivere sul file, ad esempio con fwrite($fp, 'blablabla'), le due operazioni vanno a buon fine, ma i dati saranno un misto di quelli scritti da A e da B, facendo s� che il file venga corrotto.


  123456
  123456
  123456
  123456
+
  abcdef  
  abcdef
  abcdef
  abcdef
  abcdef
=
  123456
  f4902jd922r

  abcdef
  abcdef
  34
  123456
    
Dati scritti dal Processo A   Dati scritti dal Processo B   Dati risultanti sul pippo.txt


Possibili soluzioni
Non esiste una soluzione univoca alla questione; l'accesso condiviso alle risorse � un problema molto importante per i sistemi operativi multithreading, ovvero per tutti i moderni sistemi Windows, Linux e MacOS. In particolare:
  • Windows: non esiste un modo semplice per verificare se un file � aperto; ci sono soluzioni basate su strumenti sviluppati da SysInternals di Mark Russinovich. Tuttavia tali soluzioni richiedono l'uso di eseguibili EXE, quasi mai possibile su server remoti.
  • Linux: esiste il comando lsof, che permette di sapere se un file � utilizzato da un processo. Tuttavia, anche in questo caso � necessario che lo script PHP possa eseguire dei comandi della shell, ad esempio con shell_exec; tale opzione non � sempre disponibile, per motivi di sicurezza. Inoltre, con questo metodo � possibile sapere se un file � aperto in un dato istante, ma non � possibile mantenerne il controllo per tutta la durata dello script.
Il file lock
I file lock sono una soluzione completa e supportata da tutti i moderni sistemi operativi per risolvere il problema dell'accesso condiviso a un file. Possono essere interpretati come un attibuto temporaneo del file, leggibile da qualsiasi processo (incluso uno script PHP), che permette a tale processo di bloccare il file per scriverci, o di segnalare a altri processi che lo sta utilizzando. In particolare, esistono due tipi di blocco:
  1. Blocco condiviso (shared lock): il file � bloccato, ma altri processi possono ottenere ugualmente uno shared lock; uno exclusive lock non pu� essere invece ottenuto. Lo shared lock viene utilizzato da un processo che sta leggendo un file: permette a altri processi di leggerlo (visto che nessuna modifica � un corso), ma non di scriverlo.
  2. Blocco esclusivo (exclusive lock): il file � bloccato dal processo, e nessun altro processo pu� leggerlo, scriverlo o ottenere uno shared lock o un exclusive lock. E' il caso in cui il processo sta scrivendo sul file.
Il processo A possiede uno Shared lock sul file Il processo A possiede un Exclusive lock sul file
Il processo B pu� acquisire uno Shared Lock S� No
Il processo B pu� acquisire un Exclusive Lock No No
Il processo B pu� leggere il file S� No
Il processo B pu� scrivere il file No No


Come interpretare i file lock
I lock sono solo un attributo del file, come il nome, la dimensione, la data di modifica, ecc. E' compito del processo che accede al file o del sistema operativo interpretare l'informazione che il lock fornisce riguardo alla condizione del file, e farne buon uso. In base all'uso che se ne pu� fare, esistono due tipi di lock:
  • Advisory lock: il sistema operativo informa (consiglia, ovver advise) solamente i processi dei lock, ma non impedisce che tali processi agiscano sul file; � compito dei processi controllare il lock e eseguire o meno delle operazioni di scrittura / lettura. Dunque, affinch� l'uso dei lock permetta di gestire correttamente l'uso condiviso del file, � necessario che tutti i processi ne facciano uso; in altri termini, i processi devono cooperare. Windows implementa l'advisory lock.
    Per fare un esempio: se state scaricando un file da internet, potete selezionarlo e copiarlo, nonostante questa operazione non dovrebbe essere permessa, visto che il file � ancora incompleto e in corso di scrittura. Tuttavia tale libert� pu� risultare comoda.
  • Mandatory lock: il sistema operativo blocca un file sul quale un processo ha acquisito un lock, e non permette a altri processi di scrivervi (shared lock e exclusive lock) e eventualmente leggerne il contenuto (exclusive lock del file). In altri termini: i vari processi concorrenti non devono preoccuparsi di verificare i lock prima di interagire col file, ovvero non devono cooperare; il sistema operativo si incarica infatti di concedere o negare i permessi di lettura e scrittura del file al processo. Linux implementa il mandatory lock.
Uso del file lock in PHP
In PHP � possibile controllare il lock di un file tramite il comando flock():

flock($file_pointer, LOCK_SH | LOCK_EX | LOCK_UN)

La funzione ritorna TRUE nel caso in cui abbia avuto successo, oppure FALSE nel caso in cui fallisca. Grazie a questo comportamento, � possibile verificare se un file ha gi� un lock con il seguente codice:

if (!flock($fp, LOCK_SH | LOCK_NB))
{
  fai qualcosa...
}

Gli attributi sono:
  • LOCK_SH: ottiene uno shared lock;
  • LOCK_EX: ottiene un exclusive lock;
  • LOCK_UN: rilascia (cancella) il lock.
Ulteriori link






Inserire la password di amministratore:



Password:

Riga:


Fatal error: Call to undefined function sqlite_open() in /membri/giacobbe85/include/commenti.inc.php on line 324