ru en uk

  авторизація

(044) 362 48 16   (098) 294 41 60


   Ціни

У PHP Manual про flock () написано наступне:


"Warning! On most operation systems flock () is implemented at the process level. When using a multithreaded server API like ISAPI you cannot rely on flock () to protect files against other PHP scripts running in parallel threads of the same server instance! "


Тобто, буквально, якщо ви використовуєте мультітредний (тредов - вони і є тредов;) API, такий як ISAPI (наприклад, IIS замість Apache під Windows NT/2000), ви не можете використовувати flock () для захисту файлів від інших PHP скриптов, запущених у паралельних тредов одного й того-ж серверного процесу.
Якщо коротко, спосіб, про який піде мова, виглядає так: перед тим, як відкрити файл, доступний для запису, ми створюємо відповідний унікальний lock-файл, який видаляється після закриття "основного" файлу. Такним чином, інша копія процесу, перед відкриттям нашого файлу, перевіряє наявність відповідного йому блокувальні "прапора" і, якщо він присутній, процес очікує, коли цей "прапор" буде знищено, після чого сам створює такий файл-"прапор", блокуючи доступ до робочогофайлу для інших запущених копій скрипта.

Бажано використовувати блокування не тільки під час запису у файл, а й при читанні, так-як, теоретично, завжди є можливість одночасного відкриття файлу на читання і на запис різними копіями скрипту (в обох випадках я кажу тільки про файли,вміст яких буде змінюватися).
Звичайно, запис у файл відбувається одномоментно, при цьому або в кінець дописувати рядок / рядки (як в гостьовій книзі), або він обнуляється і записується заново (лічильники, системи голосування), теж можна сказати і про читання, тому час затримки загрузки сторінки, навіть при дуже великій кількості звернень до такого файлу, буде мінімальним. До речі, хоча мова йде про дійсно малому проміжку часу, тим не менш, при роботі з файлами великих розмірів, щоб звести до мінімуму затримку, раджу для читання використовувати тільки функцію file () (іЧи fileToArray () - див далі), якщо, звичайно, вам не потрібно прочитати 1-2 строчки, а, в разі запису, створювати тимчасовий буфер, заповнюючи його по мірі виконання скрипта, і в кінці скидати його в робочий файл. Ця загальна практика, яка використовується не тільки в PHP, реально прискорює роботу, особливо, еслі кожен рядок зчитує файлу піддається лексичному розбору (Парс) або кожен рядок записуваного - генерується окремо.
Тепер, власне, про блокування. Для початку, вибираємо каталог, в якому будуть зберігатися lock-файли. Можна, звичайно, використовувати поточний каталог, але тоді вОсь такі каталоги доведеться зробити доступними для запису всім користувачам, що небажано і не дуже зручно. Найкраще створимо його поза директорії з нашими HTML-документами. На UNIX-like машині (в подальшому це буде мається на увазі) це може бути $ HOME / lock (telnet-імся і набираємо в командноий рядок: mkdir $ HOME / lock; chmod 0777 $ HOME / lock) або, якщо доступу до домашнього каталогу нету, робимо його докорінно WWW-директорії за допомогою FTP-клієнта, не забуваючи поставити permissions 777 (rwxrwxrwx), і обов'язково створюємо в ньому файл. htaccess, забороняючи сюди доступ по HTTP, c такими рядками:

Order Deny, Allow
Deny from all


Створюємо файл lib.php - тут будуть зберігатися загальні функції і змінні, і кидає його, допустим, тоже в корінь вашого WWW-проекту (тоді не зайвим буде тут теж створити файл. Htaccess з рядками:

Order Deny, Allow
Deny from all

щоб заборонити доступ до нашого файлу-бібліотеку для браузерів. У lib.php пишемо:

<?
$ LOCK_DIR = "$ HOME / lock";
/ * Або $ LOCK_DIR = "[шлях файлової системи до вашого www-кореня] / lock"* /

/ *
* Внутрішня функція, блокуюча фото, безпосередньо ми до неї звертатися
не будемо
* /
function safeLock ($ file) (
global $ LOCK_DIR;
$ lck = "$ LOCK_DIR /". basename ($ file). ". LCK";
while (1) (
if (is_file ($ lck)) continue;
)
)
/ *
* Т.с., тільки для розблокування
* /
function safeUlock ($ file) (
global $ LOCK_DIR;
$ lck = "$ LOCK_DIR /". basename ($ file). ". LCK";
return unlink ($ lck);
)

/ *
* Безпечна заміна вбудованої функціі file ()
* /
function fileToArray ($ file) (
if (! is_readable ($ file)) return FALSE;
safeLock ($ file);
$ buf = file ($ file);
safeUlock ($ file);
return $ buf;
)

/ *
* А ця - замість системної fopen () - аргументи ті ж самі
* /
function safeOpen ($ file, $ mode) (
safeLock ($ file);
return fopen ($ file, $ mode);
)

/ *
* Заміна системного fclose ()
*! УВАГА! У цієї функції 2 аргументу, на відміну від fclose ():
* Першого $ fd - ідентичний fclose ();
* Другий $ file - рядок з ім'ям закриваємо файлу,
* /
function safeClose ($ fd, $ file) (
$ st = fclose ($ fd);
safeUlock ($ file);
return $ st;
)
?>


Тепер можна сміливо починати використовувати нашу альтернативну блокування: замість file () ми будемо використовувати fileToArray (), замість fopen () - safeOpen (), а замість fclose () - safeClose (), не забуваючи про другий аргумент з ім'ям файлу. І найголовніше - підключити наш lib.php:

<?
include ( "$ DOCUMENT_ROOT / lib.php");
/ *
* Якщо ваш адреса має вигляд/ / www.someisp.com/ ~ user5 "target =" _blank "> http://www.someisp.com/ ~ user5
* То замість $ DOCUMENT_ROOT треба прописати повний шлях файлової системи
* До кореня вашої сторінки, н.п.:
"/ usr/home/www-users/user5/.public_html/lib.php"
* /

/ * ... * /

$ gbfile= "$ HOME / wwwdata / guestbook.dat";

$ guestBook = fileToArray ($ gbfile);

while (list ($ key) = each ($ guestBook)) (
/ * ... * /
)

/ * ... * /

$ counter = "$ HOME / wwwdata / counter.txt";

$ fdCount = safeOpen ($ counter, 'w');


safeClose ($ fdCount, $ counter);

/ * ... * /
?>


Недоліки


1. Як видно з коду, є потенційна можливість конфлікту при одночасній блокування двох різних файлів з одинаковвимі іменами, тому що ім'я lock-файлу "не зовсім" унікально; в принципі, це легко вирішується додаванням до імені, скажімо, дати створення файлу-об'єкта, або MD5-суми, що генерується з рядка його повного шляху. Але, оскільки описаний випадок можливий хіба що в досить складному многопользовательском проект із загальною lock-директор, я не став цього робити.
2. Знову-ж, в теорії, залишається можливість для хакера обчислити місце знаходження каталогу для lock-файлів і їх імена і, запустивши на тому ж сервері свій PHP-скрипт з відповідним кодом, "залочіть", вашу сторінку на вікивічні, але, наскільки я розумію, це можливо тільки якщо у файлі конфігурації PHP не прописано "safe_mode = On".

 
Постранічний висновок результату
29.05.2007
Як надіслати пошту
29.05.2007
Як надіслати пошту
29.05.2007