PHP同时写入文件

23

我有两个不同的PHP文件,它们都写入同一个文件。每个PHP脚本都由两个不同HTML页面的用户动作调用。我知道这两个PHP文件可以被调用,但是它们会同时尝试写入该文件吗?如果是,会发生什么?此外,是否可以使其中一个PHP优雅地失败(文件写入将仅失败,并且另一个PHP可以写入该文件),因为一个PHP函数比另一个不重要。

5个回答

35
通常解决这个问题的方式是让两个脚本都使用 flock()来进行锁定:
$f = fopen('some_file', 'a');
flock($f, LOCK_EX);
fwrite($f, "some_line\n");
flock($f, LOCK_UN);
fclose($f);
这将使脚本在写入文件之前相互等待。如果您愿意,那些“不太重要”的脚本可以执行:
$f = fopen('some_file', 'a');
if(flock($f, LOCK_EX | LOCK_NB)) {
    fwrite($f, "some_line\n");
    flock($f, LOCK_UN);
}
fclose($f);

这样,如果它发现某个文件已被占用,它就不会执行任何操作。


正是我所需要的!这么简单,我应该更多地查看PHP文档。 - Amandeep Grewal
使用flock()函数时要小心,因为该函数不是原子的。 - arul
另一个防止文件内容在两个完全同时写入时变为空的提示。我在一张流行的页面上使用平面访问者计数器时经常遇到这个问题。解决方法:在fwrite()之前添加20-80毫秒的随机延迟,这解决了这个问题,即使在更高的访问量下也是如此。 - Juha Untinen

13
请注意,如果文件以追加方式打开,则posix状态具有原子访问。这意味着您可以使用多个线程向文件追加内容,而这些行不会损坏。
我使用了十几个线程和数十万行进行了测试。没有一行受到破坏。
这可能无法处理超过1kB的字符串,因为缓冲区大小可能会超出限制。
这在不符合posix标准的Windows上也可能无法正常工作。

10

请注意:

从PHP 5.3.2版本开始,当文件的资源句柄被关闭时,自动解锁已经被移除。 现在解锁必须手动完成。

更新后向兼容代码如下:

if (($fp = fopen('locked_file', 'ab')) !== FALSE) {
    if (flock($fp, LOCK_EX) === TRUE) {
        fwrite($fp, "Write something here\n");
        flock($fp, LOCK_UN);
    }

    fclose($fp);
}

也就是说,你必须显式调用 flock(.., LOCK_UN),因为 fclose() 现在不再这样做了。


1

-4

提示:flock仅适用于*nix系统,无法在Windows上使用。


2
从PHP文档中:“flock()允许您执行一个简单的读/写模型,可用于几乎所有平台(包括大多数Unix衍生产品甚至Windows)。” - cdmckay
1
虽然在Windows系统上没有实现 flock 系统调用,但在 flock PHP函数中已经将其抽象化处理。 - Piskvor left the building
1
是的,我说错了。这就是我在说 Windows 上没有可用时想到的错误:http://bugs.php.net/bug.php?id=39138(当我需要在 Windows 本地开发服务器上使用它时,我遇到了这个问题,从那以后就一直避免在 Windows 机器上使用它)。保持冷静并继续前进。 - xentek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接