Blokowanie plików jest jednym z ważniejszych zagadanień przy
używaniu plików do przechowywania danych. W zastosowaniach
internetowych może dojść do takiej sytuacji, że dwie lub więcej
osób jednocześnie wejdzie na stronę czy po prostu uruchomi
skrypt. Jeśli będzie to na przykład licznik odwiedzin
przechowujący ilość odwiedzin w pliku, to te kilka osób będzie
chciało zapisać dane do tego pliku jednocześnie. Może to
doprowadzić do utraty danych z tego licznika. Wystarczy jednak
zastosować mechanizm blokad aby zapobiec takiej sytuacji.
Funkcja flock( int wskaźnik, int operacja )
zakłada blokadę lub ją zdejmuje, zależnie od wartości drugiego
parametru. Są 2 typy blokad: blokada dzielona, używana jeśli
plik ma być odczytywany (dzielona, ponieważ więcej niż jeden
skrypt może utrzymywać taką blokade na pliku) , i blokada
wyłączna, zakładana jeśli plik ma być zapisywany. Drugi parametr
funkcji może mieć takie wartości:
-
LOCK_SH
aby założyć blokadę dzieloną
-
LOCK_EX
aby założyć blokadę wyłączną
-
LOCK_UN
aby zdjąć blokadę, wszystko jedno jaką
Teraz wiadomo jak założyć i zdjąć blokadę. Ale jak wykorzystać
to w praktyce? Otóż funkcja flock() zwraca wartość true lub
false w zależności od tego, czy udało się założyć blokadę czy
nie. Przykładowo, jeśli na pliku założona jest blokada dzielona,
to można ten plik jeszcze raz zablokować do odczytu, ale do
zapisu już nie. Jeśli natomiast założona jest blokada wyłączna,
to żaden inny skrypt nie może już założyć blokady do czasu aż ta
blokada zostanie zdjęta.
Zależnie od zastosowania, można różnie reagować na niemożność
założenia blokady. Można albo przerwać skrypt albo czekać na
zdjęcie blokady. W przypadku licznika jedne odwiedziny w tą czy
tamtą nie mają znaczenia w obliczu konieczności czekania na
zakończenie działania innego skryptu - pewnie będą to ułamki
sekund, ale bywa z tym różnie (zwłaszcza, jeśli takich
czekających jest więcej). Natomiast jeśli chodzi o blokadę bazy
danych, to czekanie na zdjęcie blokady jest koniecznością.
Przykład 11.6. Licznik odwiedzin z blokowaniem bazy
<?php // Konfiguracja
// Nazwa pliku zawierającego licznik - względna do katalogu, w którym // jest strona na której ma być licznik
$df = "lib/count.dat";
// Próba otwarcia pliku do odczytu
if(!($fp=@fopen($df, "r"))){ // Jeśli plik jeszcze nie istnieje, to jest inicjowany wartością 0 $count=0; } else { // jeśli istnieje, to jego wartość jest odczytywana a plik zamykany $count = fgets($fp, 100); fclose($fp); }
// Zwiększenie licznika o 1
$count+=1;
// Otwarcie pliku do zapisu
$fp = fopen($df, "w");
// Blokada - jeśli plik już jest zablokowany, to skrypt go zamyka i kończy // działanie
if(!flock($fp, LOCK_EX)){ fclose($fp); return; } else{ // Jeśli nie jest zablokowany, to następuje blokada i zapis danych fputs($fp, $count); flock($fp, LOCK_UN); fclose($fp); }
// Wyświetlenie stanu licznika
echo $count; ?>
|
Ten plik możemy zapisać np. jako count.php i w odpowiednim
miejscu na stronie, gdzie ma się pojawić licznik, należy wpisać
<?include "count.php"?>
. Jeśli pojawią
się błedy w stylu "Permission denied" oznacza to, że coś jest
nie tak z prawami dostępu do pliku z danymi, a jeśli jeszcze on
nie istnieje, to z prawami do katalogu gdzie ma być ten licznik.
Serwer WWW powinien mieć prawa zapisu do tego pliku/katalogu.