多个用户使用 PHP 同时写入同一个文件

Multiple users write to the same file at the same time using PHP

我有一个网站,在同一时刻,可以有多个用户同时写入同一个文件。下面是我的代码示例。

PHP 5.6.20

<?php
$root=realpath($_SERVER["DOCUMENT_ROOT"]);
$var=time()."|";
echo $var."<br/>";
$filename=$root."/Testing/Testing/test1.txt";

$myfile=fopen($filename,"a");
fwrite($myfile,$var);
fclose($myfile);

$myfile=fopen($filename,"r");
$contents = fread($myfile, filesize($filename));
echo $contents;
fclose($myfile);
?>

我在 PHP 中读到,如果多个用户试图在同一个文件中写入同一个文件,则有可能发生数据损坏,我当然不希望有这样的代码可能会导致长时间 运行.

中的一些数据损坏

我尝试在我的浏览器上几乎同时 运行 上面的代码来模拟多个用户同时写入同一个文件,它没有产生任何错误或文件数据损坏正在写入,但我仍然不确定未来的数据损坏。

我读到我可以使用 flock 来确保 2 个用户不能同时写入文件,但是由于我测试了上面的代码并且它没有产生数据损坏,我不确定我是否应该用 flock 更新我的代码,或者保持原样。

我的问题是:

1) 上面的代码是否有可能破坏它正在写入的文件?

2) 如果是,使用 flock 是否可以解决这个问题?如果是,我应该如何在上面的代码中实现 flock ?

编辑:

我知道这个不确定性可以通过数据库来解决,但是对于这种情况,还是用纯文本比较好,所以请不要建议我使用数据库。

提前致谢。

您需要将保存机制从简单文件更改为任何具有事务的数据库。

如果两个脚本试图同时写入一个文件。 fopen() 函数在文件上调用时,不会阻止同一文件被另一个脚本打开,这意味着您可能会发现一个脚本在读取文件的同时另一个正在写入文件,或者更糟的是,两个脚本正在写入同一个文件同时。所以最好使用 flock() 。 您可以在 http://www.hackingwithphp.com/8/11/0/locking-files-with-flock 上获得更多帮助。 对于您的代码,您可以使用 flock() as

<?php
$root=realpath($_SERVER["DOCUMENT_ROOT"]);
$var=time()."|";
echo $var."<br/>";
$filename=$root."/Testing/Testing/test1.txt";

$myfile=fopen($filename,"a");
if (flock($myfile, LOCK_EX)) {        
    fwrite($myfile,$var);
    flock($myfile, LOCK_UN); // unlock the file
} else {
    // flock() returned false, no lock obtained
    print "Could not lock $filename!\n";
}

fclose($myfile);

$myfile=fopen($filename,"r");
if (flock($myfile, LOCK_EX)) {        

    $contents = fread($myfile, filesize($filename));
    echo $contents;
    flock($myfile, LOCK_UN); // unlock the file
} else {
    // flock() returned false, no lock obtained
    print "Could not lock $filename!\n";
}
fclose($myfile);
?>

我对flock不熟悉,但我的第一个想法是锁定或排队机制。如果写入的数据不需要被使用或返回给用户,那么工作队列将是最好的选择。将数据写入基于 redis 或 memcached 的系统,sql 或其他类型的队列系统,或者只是将带有有趣内容的唯一时间戳文件转储到一个目录中,工作人员可以按升序将其聚合到 master 文件中。

对于写入数据触发用户需要获取报告或结果、响应或其他反馈的用例,如果您无法重新构建异步架构,那么锁定可能是一种方式最终一致性堆栈。如果不知道并发用户的负载和数量、服务器数量等,也很难知道。

这是许多编程语言中的许多 Web 应用程序的常见理论问题。

答案是肯定的,它会引起麻烦。然而,这是一个非常理论上的问题,如果您添加到文件中的内容不是很大并且您的流量不是很大。今天的操作系统和文件系统优化得很好(缓存、惰性写入等),当您在使用它们后立即关闭文件句柄时,这种情况不太可能发生。

如果您 运行 出错(在使用其他语言写入 PHP/catch 异常之前检查访问权限),您可以添加缓冲区之类的东西,并在延迟一段时间后重试或写入您的缓冲区到临时文件并将其与另一个进程合并 - 您有几种可能性。

是的,flock() 是一个可以很好地用于这些目的的函数,但我认为,它已经被过度设计了。