Я часто использую небольшой класс ... который является безопасным и быстрым, в основном вы должны писать только тогда, когда получите эксклюзивную блокировку файла, в противном случае вам следует подождать, пока блокировка не будет ...
lock_file.php
<?php
/*
Reference Material
http://en.wikipedia.org/wiki/ACID
*/
class Exclusive_Lock {
/* Private variables */
public $filename; // The file to be locked
public $timeout = 30; // The timeout value of the lock
public $permission = 0755; // The permission value of the locked file
/* Constructor */
public function __construct($filename, $timeout = 1, $permission = null, $override = false) {
// Append '.lck' extension to filename for the locking mechanism
$this->filename = $filename . '.lck';
// Timeout should be some factor greater than the maximum script execution time
$temp = @get_cfg_var('max_execution_time');
if ($temp === false || $override === true) {
if ($timeout >= 1) $this->timeout = $timeout;
set_time_limit($this->timeout);
} else {
if ($timeout < 1) $this->timeout = $temp;
else $this->timeout = $timeout * $temp;
}
// Should some other permission value be necessary
if (isset($permission)) $this->permission = $permission;
}
/* Methods */
public function acquireLock() {
// Create the locked file, the 'x' parameter is used to detect a preexisting lock
$fp = @fopen($this->filename, 'x');
// If an error occurs fail lock
if ($fp === false) return false;
// If the permission set is unsuccessful fail lock
if (!@chmod($this->filename, $this->permission)) return false;
// If unable to write the timeout value fail lock
if (false === @fwrite($fp, time() + intval($this->timeout))) return false;
// If lock is successfully closed validate lock
return fclose($fp);
}
public function releaseLock() {
// Delete the file with the extension '.lck'
return @unlink($this->filename);
}
public function timeLock() {
// Retrieve the contents of the lock file
$timeout = @file_get_contents($this->filename);
// If no contents retrieved return error
if ($timeout === false) return false;
// Return the timeout value
return intval($timeout);
}
}
?>
Простое использование следующим образом:
include("lock_file.php");
$file = new Exclusive_Lock("my_file.dat", 2);
if ($file->acquireLock()) {
$data = fopen("my_file.dat", "w+");
$read = "READ: YES";
fwrite($data, $read);
fclose($data);
$file->releaseLock();
chmod("my_file.dat", 0755);
unset($data);
unset($read);
}
Если вы хотите добавить более сложный уровень, вы можете использовать другой прием ... используйте while (1)
, чтобы инициализировать бесконечный цикл, который прерывается только при получении эксклюзивной блокировки, не рекомендуется, поскольку может блокировать ваш сервер на неопределенное время. .
include("lock_file.php");
$file = new Exclusive_Lock("my_file.dat", 2);
while (1) {
if ($file->acquireLock()) {
$data = fopen("my_file.dat", "w+");
$read = "READ: YES";
fwrite($data, $read);
fclose($data);
$file->releaseLock();
chmod("my_file.dat", 0755);
unset($data);
unset($read);
break;
}
}
file_put_contents()
очень быстрый и записывает непосредственно в файл, но, как вы говорите, имеет ограничение ... условие гонки существует и может произойти, даже если вы попытаетесь использовать LOCK_EX
. Я думаю, что класс php более гибкий и удобный ...
Увидимся в этой теме, которая рассматривает похожий вопрос: php flock, когда файл заблокирован одним процессом