Blocarea fișierului - Funcția flock
Dacă site-ul nostru este vizitat de mulți utilizatori care accesează simultan același fișier, putem întâmpina unele probleme. În special, la încercarea simultană de scriere a mai multor utilizatori, fișierul poate fi corupt sau poate returna rezultate neașteptate dacă o persoană citește fișierul în timp ce alta îl scrie simultan. Apare problema sincronizării accesului utilizatorilor.
Pentru a limita accesul la fișier, în PHP se folosește funcția flock(). Această funcție blochează accesul la fișier când acesta este deja utilizat de un utilizator, iar toate celelalte cereri sunt puse în așteptare. La eliberarea fișierului, acesta se deblochează, se transmite primului utilizator din coadă și se blochează din nou.
Funcția are următoarea definiție:
bool flock (resource $handle , int $operation [, int &$wouldblock ])
Primul parametru este descriptorul fișierului, returnat de funcția fopen().
Al doilea parametru indică tipul blocării. Acesta poate avea următoarele valori:
- LOCK_SH (sau numărul 1): blocare partajată (citirea fișierului)
- LOCK_EX (sau numărul 2): blocare exclusivă (scrierea fișierului)
- LOCK_UN (sau numărul 3): pentru deblocare
- LOCK_NB (sau numărul 4): această constantă se folosește doar împreună cu una dintre cele precedente într-o mască de biți (LOCK_EX | LOCK_NB), dacă nu trebuie să așteptăm până când flock() obține blocarea
Al treilea parametru opțional $wouldblock va conține true dacă blocarea va fi una blocantă.
La execuția cu succes, funcția flock va returna valoarea true, iar în caz de eroare - false.
Folosim flock pentru a limita accesul la fișier:
<?php
$fd = fopen("hello.txt", 'r+') or die("Eroare la deschiderea fișierului");
$str = "Hello World!";
if (flock($fd, LOCK_EX)) // setarea blocării exclusive pentru scriere
{
fseek($fd, 0, SEEK_END); // plasarea indicatorului la sfârșitul fișierului
fwrite($fd, "$str") or die("Eroare la scriere"); // scrierea
flock($fd, LOCK_UN); // deblocarea fișierului
}
fclose($fd);
?>
La modificarea fișierului, blocarea este plasată chiar înainte de a face modificările și se elimină imediat după efectuarea acestora. În caz contrar, programul poate încetini.
De aceea, apelul care blochează fișierul: flock($fd, LOCK_EX) este plasat chiar înainte de apelul funcției fwrite($fd, "$str"). Iar deblocarea cu ajutorul constantei LOCK_UN are loc imediat după scriere.
Rețineți că la deschiderea fișierului s-a folosit modul 'r+', nu 'w' sau 'w+', deoarece 'w' și 'w+' implică deja modificarea fișierului. Prin urmare, la blocare, chiar dacă trebuie făcută scrierea, nu este recomandată utilizarea 'w' și 'w+'.
Dacă trebuie să ștergem tot conținutul fișierului și să-l rescriem, putem folosi funcția ftruncate:
<?php
$fd = fopen("hello.txt", 'r+') or die("Eroare la deschiderea fișierului");
$str = "Hello World!";
if (flock($fd, LOCK_EX)) // setarea blocării exclusive pentru scriere
{
ftruncate($fd, 0); // ștergerea conținutului fișierului
fwrite($fd, "$str") or die("Eroare la scriere"); // scrierea
flock($fd, LOCK_UN); // deblocarea fișierului
}
fclose($fd);
?>
Astfel, ne asigurăm că fișierul este blocat în mod exclusiv înainte de ștergere și scriere, și deblocat imediat după.