Php áëîêèðîâêà
Çàêàæèòå õîðîøèé ñâàðî÷íûé àïïàðàò Ñâàðîã PRO äëÿ êîìôîðòíîé è ë¸ãêîé ñâàðêè.
| Php-web-äèçàéí > Php
áëîêèðîâêà |
Ñóòü ïðîáëåìû òàêîâà: Åñòü áàçà äàííûõ,
èñïîëüçóåìàÿ íà ñàéòå (íàïðèìåð, áàçà äëÿ
ðåãèñòðàöèè ïîëüçîâàòåëåé, êóäà çàïèñûâàåòñÿ èõ èìÿ è
email), îíà ëåæèò â òåêñòîâîì ôàéëå ïîñòðî÷íî
(â äàëüíåéøåì, "file_base.dat".).
Äâà ïîëüçîâàòåëÿ àêòèâèçèðóþò ñåðâåð ÷åðåç êîìàíäíóþ ñòðîêó â
áðîóçåðå, äëÿ ââîäà ñâîõ èìåí è email. Ñåðâåð îòñûëàåò èõ ê
ñêðèïòó. Îáà ïîëüçîâàòåëÿ "íà÷èíàþò äâèæåíèå" ïî ñêðèïòîâîìó
ïîòîêó (òåêñòó php ôàéëà) ñâåðõó
âíèç, ïðè÷åì, Ïåðâûé "áåæèò" íà äîëþ ñåêóíäû áûñòðåå Âòîðîãî.
Êîãäà îíè äîñòèãàþò òîãî ìåñòà, ãäå ñêðèïò èñïîëíÿåò èõ
çàïðîñ, äâèæåíèå ïî ïîòîêó îñòàíàâëèâàåòñÿ, â èõ áðîóçåð
âûâîäèòñÿ ñãåíåðèðîâàííàÿ ñêðèïòîì ñòðàíèöà â âèäå html. ×òîáû
èç file_base.dat ïðî÷èòàòü äàííûå, ýòîò ôàéë íàäî îòêðûòü íà
÷òåíèå (ôóíêöèÿ - @file), ÷òîáû çàïèñàòü ÷òî-òî â
íåãî, íàäî îòêðûòü íà çàïèñü (ôóíêöèÿ - @fopen). Â ñêðèïòå ýòî âûãëÿäèò
òàê:
<? ……
// ÷èòàåì äàííûå èç ôàéëà-áàçû $f = @file
("file_base.dat", "r"); // çäåñü íàõîäèòñÿ 2 ïîëüçîâàòåëü //
çäåñü èäåò òåêñò ñêðèïòà // îòêðûâàåì ôàéë-áàçó íà çàïèñü
$fp = @fopen ("file_base.dat",
"w"); // çäåñü íàõîäèòñÿ 1
ïîëüçîâàòåëü // çàïèñûâàåì â ôàéë-áàçó äàííûå èç
âûøå // ïðî÷èòàííîãî file_base.dat - ïåðåìåííàÿ $f // è äîáàâëÿåì åùå îäíó ñòðîêó ñ
äàííûìè íîâîãî ïîëüçîâàòåëÿ // çàêðûâàåì ôàéë-áàçó
@fclose ($fp); …… ?>
Òî åñòü, ÷òîáû íîâûé
ïîëüçîâàòåëü ïîÿâèëñÿ â íàøåé file_base.dat, ìû ñ÷èòûâàåì
îòòóäà èíôîðìàöèþ, êîòîðóþ êëàäåì â ïåðåìåííóþ $f, çàòåì çàïèñûâàåì â ýòîò æå ôàéë ýòó
ïåðåìåííóþ $f (ïðè
ýòîì, file_base.dat ïåðåïèñûâàåì ïîëíîñòüþ) è
âíèçó äîïèñûâàåì åùå îäíó ñòðîêó ñ äàííûìè íàøåãî íîâîãî
ïîëüçîâàòåëÿ. Ìû âèäèì, ÷òî íà ÷òåíèå è íà çàïèñü
file_base.dat îòêðûâàåòñÿ â ðàçíûõ ìåñòàõ íàøåãî ñêðèïòà. Åñëè
îáà ïîëüçîâàòåëÿ, îäíîâðåìåííî, äîñòèãëè "ñâîåãî" ìåñòà â ýòîì
ñêðèïòå, íî îäèí èç file_base.dat òîëüêî íà÷àë ÷èòàòü äàííûå,
à äðóãîé óæå èõ ïðî÷èòàë, ïðîäâèíóëñÿ ÷óòü íèæå è, â ýòîò
ìîìåíò, íàõîäèòñÿ íà îòìåòêå çàïèñè â ôàéë file_base.dat ñâîèõ
äàííûõ. Òî, â ýòîì ñëó÷àå, îò íàøåãî ôàéëà file_base.dat
íè÷åãî íå îñòàíåòñÿ.  ñâÿçè ñ ýòèì, â Php áûëà ââåäåíà
ôóíêöèÿ ñîâìåñòíîãî äîñòóïà @flock,
êîòîðàÿ ïðèçâàíà íå äîïóñêàòü ñîâìåñòíûé äîñòóï ê ôàéëó íà
÷òåíèå è çàïèñü.
<? …… // ÷èòàåì äàííûå
èç ôàéëà ôàéëà-áàçû $f = @file ("file_base.dat",
"r"); // çäåñü íàõîäèòñÿ 2
ïîëüçîâàòåëü // çäåñü èäåò òåêñò ñêðèïòà //
îòêðûâàåì ôàéë-áàçó íà çàïèñü $fp = @fopen
("file_base.dat", "w"); // çäåñü íàõîäèòñÿ 1 ïîëüçîâàòåëü //
áëîêèðóåì ôàéë-áàçó íà ÷òåíèå @flock ($fp, LOCK_EX) //
çàïèñûâàåì â ôàéë-áàçó äàííûå èç âûøå // ïðî÷èòàííîãî
file_base.dat - ïåðåìåííàÿ $f //
è äîáàâëÿåì åùå îäíó ñòðîêó ñ äàííûìè íîâîãî ïîëüçîâàòåëÿ
// ñíèìàåì áëîêèðîâêó @flock
($fp,
LOCK_UN) // çàêðûâàåì ôàéë-áàçó @fclose ($fp); …… ?>
Òåïåðü, âðîäå áû âñå
íîðìàëüíî, ôàéë áëîêèðóåòñÿ íà ÷òåíèå, êîãäà â íåãî ÷òî-òî
ïèøóò. Íî, ÷òî ïðîèçîéäåò â íàøåì ñëó÷àå, êîãäà, 1
ïîëüçîâàòåëü ïðî÷èòàë äàííûå ôàéëà è ïðèøåë ê îòìåòêå îòêðûòèÿ
file_base.dat íà çàïèñü, îðêûë åãî è çàáëîêèðîâàë íà ÷òåíèå
ôóíêöèåé @flock, à 2 ïîëüçîâàòåëü,
èìåííî â ýòîò ìîìåíò ïðèøåë ê òî÷êå, ãäå äàííûå èç ôàéëà
ñ÷èòûâàþòñÿ ôóíêöèåé @file? 2
ïîëüçîâàòåëü íè÷åãî íå ïðî÷èòàåò èç ýòîãî ôàéëà, ïîòîìó ÷òî
file_base.dat áëîêèðîâàí 1 ïîëüçîâàòåëåì êîìàíäîé @flock íà ÷òåíèå. 2 ïîëüçîâàòåëü ïðîñòî
"ïðîáåæèò" äàëüøå ïî ïîòîêó ñêðèïòà íè÷åãî èç ôàéëà
file_base.dat íå ïðî÷èòàâ, òî åñòü íàøà ïåðåìåííàÿ $f áóäåò ïóñòîé. Íî, äàëüøå-òî îí áóäåò
çàïèñûâàòü â ýòîò ôàéë, òî ÷òî ðàíåå ñ íåãî ñ÷èòàë.  èòîãå, â
íàø file_base.dat çàïèøåòñÿ òîëüêî îäíà ñòðîêà ñ åãî èìåíåì è
email. Òî åñòü, file_base.dat áóäåò ïîòåðÿí. Â ñâÿçè ñ
÷åì, áûëà ïðèäóìàíà ôóíêöèÿ: read_file
function read_file($path) {
if(!is_file($path))
{return false;
} elseif(!filesize($path))
{return array();
} elseif($array=file($path))
{return $array; } else { while(!$array=file($path)){sleep(1);}
return $array; } }
Ñóòü åå òàêîâà: ïîêà ôàéë áëîêèðîâàí íà ÷òåíèå,
ïîëüçîâàòåëü, êîòîðûé õî÷åò ñ÷èòàòü èç íåãî èíôîðìàöèþ,
íàõîäèòñÿ â öèêëå, òî åñòü, êàê áû "ñòîèò" íà ìåñòå, íå
"áåæèò" äàëüøå ïî òåêñòó ñêðèïòà, îæèäàÿ, êîãäà ôàéë
ðàçáëîêèðóåòñÿ íà ÷òåíèå. Â èòîãå íàø ñêðèïò ïðèíèìàåò òàêîé
âèä:
<? function read_file($path) {
if(!is_file($path))
{return false;
} elseif(!filesize($path))
{return array();
} elseif($array=file($path))
{return $array; } else { while(!$array=file($path)){sleep(1);}
return $array; } }
…… // ïðîâåðÿåì çàáëîêèðîâàí ëè ôàéë íà ÷òåíèå, //
åñëè çàáëîêèðîâàí, íàçíà÷àåì öèêë ñ îñòàíîâêîé, // ïîêà
áëîêèðîâêà íå áóäåò ñíÿòà, ïîñëå ñíÿòèÿ áëîêèðîâêè, //
÷èòàåì äàííûå èç ôàéëà ôàéëà-áàçû $f = read_file
("file_base.dat", "r"); // çäåñü íàõîäèòñÿ 2 ïîëüçîâàòåëü //
çäåñü èäåò òåêñò ñêðèïòà // îòêðûâàåì ôàéë-áàçó íà çàïèñü
$fp = @fopen ("file_base.dat",
"w"); // çäåñü íàõîäèòñÿ 1
ïîëüçîâàòåëü // áëîêèðóåì ôàéë-áàçó íà ÷òåíèå
@flock ($fp, LOCK_EX) //
çàïèñûâàåì â ôàéë-áàçó äàííûå èç âûøå // ïðî÷èòàííîãî
file_base.dat - ïåðåìåííàÿ $f //
è äîáàâëÿåì åùå îäíó ñòðîêó ñ äàííûìè íîâîãî ïîëüçîâàòåëÿ
// ñíèìàåì áëîêèðîâêó @flock
($fp,
LOCK_UN) // çàêðûâàåì ôàéë-áàçó @fclose ($fp); …… ?>
Âðîäå áû âñå
íîðìàëüíî. Êîãäà 1 ïîëüçîâàòåëü íà÷àë çàïèñûâàòü ñâîè äàííûå â
file_base.dat, 2 "ñïèò" îäíó ñåêóíäó, îæèäàÿ ðàçáëîêèðîâêè
file_base.dat, êîãäà file_base.dat ðàçáëîêèðîâàí, îí ñ÷èòûâàåò
èç íåãî èíôîðìàöèþ è íà÷èíàåò äâèæåíèå äàëüøå. Íî, åñòü îäíî
"íî". Åñëè 2 ïîëüçîâàòåëü ÷óòü áûñòðåå 1 ïîëüçîâàòåëÿ
"äîáåæàë" äî "ñâîåãî" ìåñòà, ïðî÷èòàë ïîëîâèíó äàííûõ èç
íàøåãî file_base.dat, êîòîðûé åùå íå áûë áëîêèðîâàí, è,
èìåííî, â ýòîò ìîìåíò, 1 "äîáåæàë" ïî òåêñòó ñêðèïòà äî @flock ($fp, LOCK_EX), òî åñòü
çàáëîêèðîâàë íàø ôàéë, òî ïåðåìåííàÿ $fp áóäåò èìåòü òîëüêî ïîëîâèíó äàííûõ èç
íàøåãî file_base.dat, ïîòîìó ÷òî, èìåííî, â ýòîò ìîìåíò
file_base.dat áûë çàáëîêèðîâàí. Â èòîãå, â íàø file_base.dat
áóäåò çàïèñàíà ïîëîâèíà èíôîðìàöèè èç íàøåé áàçû + îäíà ñòîðêà
íîâîãî ïîëüçîâàòåëÿ. Òî åñòü, îïÿòü, file_base.dat ìû
ïîòåðÿëè.
Ñóòü ïîäõîäà, êîòîðûé ïðåäëàãàåì ìû äëÿ
ðåøåíèÿ ýòîé ïðîáëåìû òàêîé: Âî âðåìÿ ñ÷èòûâàíèÿ èç ôàéëà
èëè çàïèñè â íåãî äàííûõ, íà ñàéòå ïîÿâëÿåòñÿ òåêñòîâàÿ ñòðîêà
ñ íàçâàíèåì ýòîãî ôàéëà, êîãäà èç ôàéëà èíôîðìàöèÿ ïðî÷èòàëàñü
èëè çàïèñàëàñü, ýòà òåêñòîâàÿ ñòðîêà óäàëÿåòñÿ. Ïîêà îíà åñòü,
çíà÷èò êòî-òî óæå èñïîëüçóåò áàçó äàííûõ íà ÷òåíèå èëè çàïèñü,
ïîëüçîâàòåëü, êîòîðûé õî÷åò îáðàòèòüñÿ ê ýòîé áàçå íà ÷òåíèå
èëè çàïèñü, íàõîäèòñÿ â öèêëå, îæèäàÿ ïîêà òåêñòîâàÿ ñòðîêà
èñ÷åçíåò. Êàê òîëüêî îíà èñ÷åçàåò, îí ÷èòàåò èëè ïèøåò â áàçó
äàííûõ, ñàì ïðè ýòîì ñîçäàâàÿ òàêóþ æå òåêñòîâóþ ñòðîêó, òåì
ñàìûì ïðåïÿòñòâóÿ äîñòóïó äâóõ è áîëåå ïîëüçîâàòåëåé ê
áàçå.
Äëÿ ÷åãî, íà ñàéòå ñîçäàäèì ïàïêó äëÿ
õðàíåíèÿ òåêñòîâûõ ñòðîê. Íàïðèìåð, lock. Íàø ôàéë íà ñàéòå
ëåæèò â ïàïêå basedir, çíà÷èò â ïàïêå lock íàäî ñîçäàòü ïàïêó
basedir. Òåïåðü, êîãäà ïîëüçîâàòåëü îáðàùàåòñÿ ê
file_base.dat, äëÿ ÷òåíèÿ èëè çàïèñè â íåãî, àáñîëþòíûé ïóòü
https://íàø_ñàéò.ru/basedir/file_base.dat, â ïàïêå
https://íàø_ñàéò.ru/lock/basedir/ ïîÿâëÿåòñÿ ôàéë-ñòðîêà
file_base.dat.tmp, àáñîëþòíûé ïóòü -
https://íàø_ñàéò.ru/lock/basedir/file_base.dat.tmp, çàêðûâàÿ
äîñòóï ê file_base.dat, êàê òîëüêî ïîëüçîâàòåëü ñ÷èòàë èëè
çàïèñàë èíôîðìàöèþ â íàø ôàéë-áàçó, òåêñòîâàÿ ñòðîêà
file_base.dat.tmp óäàëÿåòñÿ, îòêðûâàÿ äîñòóï äðóãèì
ïîëüçîâàòåëÿì ê file_base.dat.
<? // îáúÿâëÿåì äèðåêòîðèþ
äëÿ âðåìåííûõ ôàéëîâ $Lock_dir =
"lock"; // ôóíêöèÿ äëÿ ñîçäàíèÿ âðåìåííûõ òåêñòîâûõ ôàéëîâ
function
touchString($file) {
global $Lock_dir; $tmp = "$Lock_dir/".$file.".tmp"; while(1)
{ if
(is_file($tmp))
{ while(file_exists($tmp))
{ $file_exist++; if($file_exist >
10){break;} clearstatcache();
sleep(1);
} } return touch($tmp); }
} // ôóíêöèÿ óäàëÿþùàÿ âðåìåííûå
òåêñòîâûå ôàéëû function
delString($file) {
global $Lock_dir; $tmp = "$Lock_dir/".$file.".tmp"; return unlink($tmp); }
// àëüòåðíàòèâà ôóíêöè @file
function
FileArray($file) {
if (!is_readable($file)) return FALSE;
touchString($file); $bufer = file($file);
delString($file); return $bufer;
} // àëüòåðíàòèâà ôóíêöè @fopen function
OpenFile($file, $mode) {
touchString($file); return fopen($file, $mode); }
// àëüòåðíàòèâà ôóíêöè @fclose
function
CloseFile($fido, $file) {
$sito = fclose($fido);
delString($file); return $sito;
} …… // ïðîâåðÿåì åñòü ëè âðåìåííûé
ôàéë, çàïðåùàþùèé // ÷òåíèå è çàïèñü â ôàéë-áàçó, åñëè îí
åñòü, îñòàíàâëèâàåì // ïîëüçîâàòåëÿ â öèêëå, ãäå îí
îæèäàåò ïîêà âðåìåííûé ôàéë // èñ÷åçíåò, êàê òîëêî îí
èñ÷åçàåò, ñàìè ñîçäàåì òàêîé æå âðåìåííûé // ôàéë,
çàïðåùàÿ äîñòóï ê ôàéëó-áàçå, òîëüêî ïîñëå ýòîãî ÷èòàåì äàííûå
èç // ôàéëà-áàçû, óäàëÿåì âðåìåííûé ôàéë, îòêðûâàÿ äîñòóï
ê áàçå // äðóãèì ïîëüçîâàòåëÿì $f = FileArray
("basedir/file_base.dat"); // çäåñü íàõîäèòñÿ 2 ïîëüçîâàòåëü //
çäåñü èäåò òåêñò ñêðèïòà // ïðîâåðÿåì åñòü ëè âðåìåííûé
ôàéë, çàïðåùàþùèé // ÷òåíèå è çàïèñü â ôàéë-áàçó, åñëè îí
åñòü, îñòàíàâëèâàåì // ïîëüçîâàòåëÿ â öèêëå, ãäå îí
îæèäàåò ïîêà âðåìåííûé ôàéë // èñ÷åçíåò, êàê òîëêî îí
èñ÷åçàåò, ñàìè ñîçäàåì òàêîé æå âðåìåííûé // ôàéë,
çàïðåùàÿ äîñòóï ê ôàéëó-áàçå, òîëüêî ïîñëå ýòîãî îòêðûâàåì
// ôàéë-áàçó íà çàïèñü, âðåìåííûé ôàéë íå óäàëÿåòñÿ,
çàêðûâàÿ äîñòóï ê áàçå // äðóãèì ïîëüçîâàòåëÿì $fp = OpenFile
("basedir/file_base.dat", "w");
// çäåñü íàõîäèòñÿ 1 ïîëüçîâàòåëü
// çàïèñûâàåì â ôàéë-áàçó äàííûå èç âûøå //
ïðî÷èòàííîãî basedir/file_base.dat - ïåðåìåííàÿ $f // è äîáàâëÿåì åùå îäíó ñòðîêó ñ
äàííûìè íîâîãî ïîëüçîâàòåëÿ // çàêðûâàåì ôàéë-áàçó,
óäàëÿåì âðåìåííûé ôàéë, îòêðûâàÿ äîñòóï ê áàçå // äðóãèì
ïîëüçîâàòåëÿì CloseFile ($fp,
"basedir/file_base.dat"); // îáðàòèòå
âíèìàíèå, ÷òî â CloseFile äâà àðãóìåíòà: $fp è // basedir/file_base.dat ……
?>
 ýòîé
ñèòóàöèè ìû âèäèì, ÷òî êîãäà îäèí ïîëüçîâàòåëü äîñòèã òî÷êè
ñ÷èòûâàíèÿ ñ file_base.dat èëè, íàîáîðîò, äðóãîé ïûòàåòñÿ
çàïèñàòü â file_base.dat èíôîðìàöèþ, íàì íè÷åãî íå ñòðàøíî.
Ïîòîìó ÷òî, êàê â îäíîì, òàê è â äðóãîì ñëó÷àå, ïîÿâèëñÿ
ìàëåíüêèé òåêñòîâûé ôàéë file_base.dat.tmp, êîòîðûé íå äàåò íè
îäíîìó íè äðóãîìó ñîâìåñòíî ÷èòàòü èëè ïèñàòü â file_base.dat.
 íàøåì âàðèàíòå åñòü îäíà "äûðà", åñëè âäðóã
ïîëüçîâàòåëü îáðàòèëñÿ ê áàçå äàííûõ, ñîçäàâ òåêñòîâóþ ñòðîêó
áëîêèðîâêè, íåçàêîí÷èë êàê-áû öèêë (ñâåò ïîãàñ è
êîìïüþòåð âûêëþ÷èëñÿ), è ýòà òåêñòîâàÿ
áëîêèðóþùàÿ ñòðîêà îñòàëàñü ëåæàòü â ïàïêå Lock, òî íàøà
ïðîãðàììà "ïîäâèñíåò", íå äàâàÿ íèêîìó ïðîéòè, èç-çà ýòîãî
îñòàâøåãîñÿ ôëàãà. Ìû íå ñòàëè óñëîæíÿòü ôóíêöèè ïðîâåðêîé íà
óäàëåíèå ýòîãî ôàéëà-ôëàãà, à, ïðîñòî ââåëè â ôóíêöèè åãî
ñîçäàþùåé, ïðåäåë "ïîäâèñàíèÿ" êîìïüþòåðà 10 ñåêóíä
($file_exist++; if($file_exist >
10){break;}), ÷åðåç
10 ñåêóíä îí àâòîìàòè÷åñêè âûéäåò èç öèêëà è ñîòðåò âðåìåííûé
ôàéë. Â ýòîì êðîåòñÿ îïàñíîñòü, íî îíà íè÷òîæíà ìàëà ïî
ñðàâíåíèþ ñ òåìè, êîòîðûå áûëè îïèñàíû âûøå. Ñ÷èòàåì, ÷òî
ïîäõîä îïèñàííûé âûøå, çàùèòèò îò îáâàëà áàçû äàííûõ, êîòîðàÿ
ëåæèò â òåêñòîâîì ôàéëå è íå áóäåò îñîáî çàìåòíî ôëàãîâ
áëîêèðîâêè, êîãäà íà ñàéòå åå, îäíîâðåìåííî èñïîëüçóåò äî 10
÷åëîâåê. Ìû çíàåì, ÷òî íàø ñêðèïò ñåðâåðîì èñïîëíÿåòñÿ 0,5
ñåê, â ýòîì ñëó÷àå åãî ïðîïóñêíàÿ ñïîñîáíîñòü â ÷àñ ñîñòàâèò
äî 1800 ÷åëîâåê. Óìåíüøèì åå âäâîå, 900 ÷åëîâåê, çà ñóòêè
21600 ÷åëîâåê. Ñîãëàñèòåñü, è áåç MySql ìîæíî îáîéòèñü.
Äëÿ ïðîâåðêè ðàáîòîñïîñîáíîñòè ýòèõ ôóíêöèé çàïèøèòå
âðó÷íóþ â ïàïêó Lock ýòîò ñàìûé áëîêèðóþùèé ôàéë file_base.dat.tmp, â íàøåì ñëó÷àå, ýòî:
https://íàø_ñàéò.ru/lock/basedir/file_base.dat.tmp,
òåì ñàìûì, áëîêèðóÿ äîñòóï ê áàçå https://íàø_ñàéò.ru/basedir/file_base.dat,
çàïóñòèòå ïðîãðàììó, îáðàòèòåñü ê áàçå, âû óâèäèòå, ÷òî ôëàã
ðàáîòàåò è áðîóçåð "ñòîèò" íà ìåñòå, óäàëèòå file_base.dat.tmp ôàéë
(ðàçáëîêèðóÿ) è ïîäâèñàíèå
çàêîí÷èòñÿ.
Òåïåðü ó íàñ åñòü ôóíêöèè: 1. FileArray , çàìåíÿþùàÿ @file 2. OpenFile
, çàìåíÿþùàÿ @fopen 3.
CloseFile , çàìåíÿþùàÿ @fclose
|