如何将 file_put_contents() 与 FILE_APPEND | 一起使用LOCK_EX 安全吗?

Posted

技术标签:

【中文标题】如何将 file_put_contents() 与 FILE_APPEND | 一起使用LOCK_EX 安全吗?【英文标题】:How can I use file_put_contents() with FILE_APPEND | LOCK_EX safety? 【发布时间】:2012-02-19 00:16:44 【问题描述】:

我正在使用:

file_put_contents("peopleList.txt", $person, FILE_APPEND | LOCK_EX);

写入文件末尾并确保没有其他人(或脚本)同时写入同一文件。

php manual 表示如果不成功,它将返回一个虚假值。

如果它无法获得对文件的锁定,它会失败还是继续尝试直到可以获得?如果在无法获得锁的情况下确实失败了,那么确保写入数据的最佳方法是什么?

也许在 while 循环中循环该函数,直到它不返回 false(畏缩)或只是为用户(网站访问者)提供某种 GUI 请求他们再试一次?

【问题讨论】:

Apache 生成一个执行 PHP 进程的线程。多个用户 = 多个 PHP 进程。获得锁的进程是唯一允许使用该文件的进程。所有其他进程将收到来自 file_put_contents 函数的错误,并且这些用户发出的 file_put_contents 不会向文件写入任何内容。这意味着当 1 个用户正在写入时,其他用户被拒绝并且该函数将返回布尔值 false LOCK_EX 存在的原因完全是另一个话题。如果您无论如何都想写入文件,只需删除 LOCK_EX 因为您不需要它,最后访问您的网站/脚本的人将是将数据写入文件的人。另外,既然你正在做追加 - 锁定文件的意义何在?只需将其删除。 我同时使用 LOCK_EX 和 FILE_APPEND 是因为其他脚本能够写入文件,而当数据被附加到文件时,我无法做到,反之亦然。 是否所有脚本都将数据附加到文件中? 不,有些会覆盖,有些只会读取。 【参考方案1】:

如果函数未能获得文件的锁,那么它将返回一个您可以使用的错误。

if ($result === false)  print "failed to lock"; 

现在,如果您想尝试多次获得锁,只需使用循环继续尝试写入文件。

【讨论】:

【参考方案2】:

其实我之前的回答有点过时了。 flock() 阻塞直到requested lock is acquired:

PHP 支持以建议方式锁定完整文件的可移植方式(这意味着所有访问程序都必须使用相同的锁定方式,否则将无法工作)。默认情况下,该函数将阻塞,直到获得请求的锁;这可以通过下面记录的 LOCK_NB 选项进行控制(在非 Windows 平台上)。

所以既然file_get_contents() 使用它,我会假设它是一样的。也就是说,请注意它因操作系统而异。

更重要的是,由于 N.B. 的原因,您不需要在您描述的场景中锁定文件。已经解释过了。除非您使用的是 CLI SAPI,否则我想不出您应该担心文件锁定的常见场景。

【讨论】:

@hozza 请不要猜测我在想什么,我只是在解释一些事情。如果你不理解它们,那是另一回事。简单地说,将循环与睡眠结合使用 - 愚蠢。您正在执行 FILE_APPEND,根本不需要使用 LOCK_EX。不要盲目复制php.net的例子,它会告诉你它是什么,它是做什么用的。 我提供的代码是一个例子。该场景只是许多脚本能够追加、截断写入或读取文件。我只希望一次发生其中一件事情,因此希望在使用 file_put_contents() 时使用 LOCK_EX 锁定文件; 然后@NB 说了什么。尝试运行并发脚本,看看会发生什么

以上是关于如何将 file_put_contents() 与 FILE_APPEND | 一起使用LOCK_EX 安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

file_put_contents 是不是与 NFS 同步

file_put_contents 将文件保存到哪里?

详解PHP file_put_contents() 函数用法示例

PHP file_put_contents() 函数

file_put_contents() ——将一个字符串写入文件

file_put_contents - 无法打开流:权限被拒绝