Php Lock файлы при записи

Я тестирую свой код, используя небольшую базу данных в текстовых файлах. Самая важная проблема, которую я обнаружил: когда пользователи одновременно пишут в один файл. Для решения этой проблемы я использую flock, ОС моего компьютера - Windows с установленным xampp (прокомментируйте это, потому что я понимаю, что flocks отлично работает над Linux без Windows). Однако мне нужно сделать этот тест на сервере Linux.

На самом деле я проверил свой код, загрузив один и тот же скрипт в 20 окон одновременно. Первые результаты работают нормально, но после теста файл базы данных кажется пустым.

Мой код:

$file_db=file("test.db");
$fd=fopen("".$db_name."","w");

if (flock($fd, LOCK_EX)) 
    { 
    ftruncate($fd,0); 
    for ($i=0;$i<sizeof($file_db);$i++)
        {
        fputs($fd,"$file_db[$i]"."\n");
        }
    fflush($fd); 
    flock($fd, LOCK_UN);
    fclose($fd);
    }
else
    {
    print "Db Busy";
    }

Как это возможно, что скрипт удаляет содержимое файла базы данных. Как правильно: использовать flock с исправлением существующего кода или использовать другую альтернативную технику flock?

2 ответа

ftruncate после fopen с "ш" бесполезно.

file функция

Возвращает файл в массиве. Каждый элемент массива соответствует строке в файле с новой строкой, все еще прикрепленной. В случае неудачи file() возвращает FALSE.

Вам не нужно добавлять дополнительный символ конца строки.

flock функция

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

Это означает, что file функция не зависит от блокировки. Это означает, что $file_db=file("test.db"); мог читать файл, в то время как другой процесс где-то между ftruncate($fd,0); а также fflush($fd);, Итак, вам нужно прочитать содержимое файла внутри блокировки.

$db_name = "file.db";
$fd = fopen($db_name, "r+"); // w changed to r+ for getting file resource but not truncate it

if (flock($fd, LOCK_EX))
    {
    $file_db = file($db_name); // read file contents while lock obtained
    ftruncate($fd, 0);
    for ($i = 0; $i < sizeof($file_db); $i++)
        {
        fputs($fd, "$file_db[$i]");
        }
    fflush($fd);
    flock($fd, LOCK_UN);
    }
else
    {
    print "Db Busy";
    }
fclose($fd); // fclose should be called anyway

PS вы можете протестировать этот скрипт с помощью консоли

$  for i in {1..20}; do php 'file.php' >> file.log 2>&1 & done

Я переписал сценарий, используя ответ @lolka_bolka, и он работает. Итак, в ответ на ваш вопрос, файл $db_name может быть пустым, если файл test.db пустой.

Другие вопросы по тегам