Блокировка файла в PHP. Как контролировать доступ во время выполнения?

блокировка файла в php. как контролировать доступ во время выполнения?

Блокировка файлов с ожиданием

При осуществлении файловых операций нужно учитывать возможность их параллельного выполнения. С одним и тем же файлом могут взаимодействовать различные процессы. Одни выполняют чтение, а другие записывают данные. Некоторые задачи, решаемые в PHP, требуют явного контроля над таким поведением. Например, если в настоящий момент происходит запись в файл, нужно подождать его завершения перед началом чтения. Таким образом, пользователь будет получать актуальную информацию о содержимом.

PHP имеет встроенный механизм блокировки доступа к файлам. Он реализует консультативную модель (англ. advisory locking). Это означает, что все программы, работающие с файлом, должны реализовывать один и тот же способ проверки и использования блокировок. Иначе они не будут работать.

Блокировки доступа бывают двух типов: монопольная — другие процессы не могут записывать и читать данные пока не будет снята блокировка, совместная — все процессы могут читать, но не записывать.

Для блокировки файла используйте функцию flock(). В первом параметре она принимает дескриптор файла, а во втором указывается тип блокировки. Тип можно задать с помощью встроенных констант LOCK_SH (совместная) или LOCK_EX (монопольная). Функция возвращает true в случае захвата файла или false, если произошла ошибка. flock() также отвечает и за снятие блокировки. Для этого передайте ей дескриптор файла, а во втором параметре укажите константу LOCK_UN.

//если файл не существует создадим его в корне сайта
$filename = $_SERVER['DOCUMENT_ROOT']. '/test-file.txt';
if (!file_exists($filename)) {
    touch($filename);
}

//пытаемся получить контролируемый доступ к файлу
$descriptor = fopen($filename, 'w');
if (flock($descriptor, LOCK_EX)) {
    //формируем задержку разблокировки в 10 секунд
    sleep(10);
    flock($descriptor, LOCK_UN);
    echo 'Блокировка успешно снята!';
}

Проверка блокировки без задержки

Обратите внимание на пример, приведенный выше. Откройте два разных окна браузера и запустите PHP-скрипт на выполнение в каждом из них. В первом окне сразу появится надпись «Блокировка установлена!», а во втором – пройдет 15 секунд перед выводом аналогичного текста. Это происходит потому что flock() блокирует дальнейшее выполнение скрипта до момента получения контроля над файлом.

Если вы хотите продолжить выполнение без ожидания и вывести текст ошибки, ко второму параметру функции нужно подставить константу LOCK_NB с помощью битовой маски. Тогда flock() вернет результат сразу.

//если файл не существует создадим его в корне сайта
$filename = $_SERVER['DOCUMENT_ROOT']. '/test-file.txt';
if (!file_exists($filename)) {
    touch($filename);
}

//пытаемся получить контролируемый доступ к файлу
$descriptor = fopen($filename, 'w+');
if (flock($descriptor, LOCK_EX | LOCK_NB)) {
    //формируем задержку разблокировки в 10 секунд
    sleep(10);
    flock($descriptor, LOCK_UN);
    echo "Блокировка успешно снята!";

} else {
    echo 'Невозможно установить блокировку';
}

Отметим, что PHP реализует встроенные механизмы буферизации данных, предназначенных для записи в файл. Это необходимо для уменьшения количества операций с диском. Может случится так, что блокировка будет снята до того, как данные будут реально записаны в файл. Этот процесс контролируется вызовом функции fflush(), которая сбрасывает буфер файла и применяет все его изменения. Функция принимает всего один параметр — дескриптор файла, а возвращает результат логического типа.

Заметка
В PHP блокировка файлов средствами вышеописанной функции не будет работать на старых файловых системах, сетевых дисках и в старых операционных системах Windows. На самом деле потребность блокировки файла может указывать на ошибки архитектуры приложения.

Возможно данные, к которым вы пытаетесь организовать контролируемый доступ, должны храниться с помощью систем управления базами данных: MySQL, PostgreSQL, SQLite и т.д.

Последние публикации