如何在PHP中重命名()需要保持锁定状态的文件?

时间:2019-01-04 02:02:13

标签: php rename flock

我有一个文本文件,多个用户将同时编辑该文本文件(每个用户每次编辑都限于一行)。我已经在StackOverflow.com上找到了所需功能的“行编辑”部分的解决方案,特别是@Gnarf在以下问题中提供的第四个解决方案(用于大文件):

how to replace a particular line in a text file using php?

基本上,它将整个文件内容重写为新的临时文件(包括用户的编辑),然后在完成后将临时文件重命名为原始文件。太好了!

为了避免一个用户的编辑与另一个用户的编辑同时发生冲突,我引入了flock()功能,如我在下面代码中的变体所示:

$reading = fopen($file, 'r');
$writing = fopen($temp, 'w');

$replaced = false;

if ((flock($reading, LOCK_EX)) and (flock($writing, LOCK_EX))) {

    echo 'Lock acquired.<br>';

    while (!feof($reading)) {

        $line = fgets($reading);

        $values = explode("|",$line);

        if ($values[0] == $id) {

            $line = $id."|comment edited!".PHP_EOL;
            $replaced = true;
        }

        fputs($writing, $line);
    }

    flock($reading, LOCK_UN);
    flock($writing, LOCK_UN);

    fclose($reading);
    fclose($writing);

} else {

    echo 'Lock not acquired.<br>';
}

我已经确保$ temp文件始终具有唯一的文件名。此处的完整代码:https://pastebin.com/E31hR9Mz

我知道flock()会强制脚本的任何其他执行在队列中等待,直到第一次执行完成且flock()已释放。到目前为止,一切都很好。

但是,问题开始于脚本的末尾,这是时候到了要重命名()临时文件来替换原始文件的时候了。

if ($replaced) {

    rename($temp, $file);

} else {

    unlink($temp);
}

从我所看到的情况来看,如果原始文件仍然具有flock(),则rename()将失败,因此我需要在此之前释放flock()。但是,我还需要它保持锁定状态,否则,一旦释放了先前的flock(),运行同一脚本的另一个用户立即打开新的flock()时,rename()就会失败。发生这种情况时,它将返回:

Warning: rename(temporary.txt,original.txt): Access is denied. (code: 5)

tl; dr::我似乎有点赶上Catch-22了。看起来rename()在锁定的文件上不起作用,但是解锁文件将使另一个用户可以在rename()发生之前立即再次将其锁定。

有什么想法吗?

更新:在对flock()的工作方式进行了广泛的研究之后,(以外行的说法,不能保证另一个脚本会尊重“ lock”,因此,它实际上不是“锁定”一词,因为这个词的字面意思就是这样)。我选择了这种解决方案,它的工作原理就像一个魅力:

https://docstore.mik.ua/orelly/webprog/pcook/ch18_25.htm

锁定冒险中的“好锁”。

0 个答案:

没有答案