PHP flock()在Windows和Linux上的行为差异

3

我在Windows和Linux机器上都执行了相同的代码片段,两者都运行PHP 5.4:

$file = "lock.txt";
$fp = fopen($file, "w+");
flock($fp, LOCK_EX);
var_dump(@file_put_contents($file, 'hello' . rand()));
flock($fp, LOCK_UN);
fclose($fp);

在Windows机器上,file_put_contents()操作失败并返回false,在Linux机器上则成功。
我正在尝试弄清楚这两种行为中哪一个才是正确的,并且我该如何将这两个系统的行为标准化(记录一下,我的目标是使file_put_contents()操作失败。我不需要它具有鲁棒性或原子性,我只想让它失败)。
我看到很多其他关于此主题的问题,但它们似乎都与多个脚本访问同一文件有关,而这不是这里的情况。

两种行为都是正确的,只是不同而已。Windows支持文件共享模式,默认情况下打开文件时会被赋予独占访问权。而Linux并不是这样的。(请注意,flock()函数创建咨询锁定,因此仅在file_put_contents调用flock()时才有效,这可能不是这样的情况。) - Harry Johnston
我建议您重新措辞您的问题(或发布一个新问题),侧重于您实际想要做的事情:在Linux上锁定文件,以使file_put_contents失败。Windows默认执行您想要的操作并不是真正与问题相关的。 (在“linux文件锁定”上进行谷歌搜索表明您可能没有希望,但最好获取专业建议。) - Harry Johnston
最终目标对我来说其实不如弄清楚发生了什么重要,这就是为什么我这样表达问题的原因!无论如何,我现在认为我理解了。 - Swiftheart
2个回答

3
flock() 的文档确实回答了这个问题,虽然不是非常详细。文档确实说明了:

flock() 在 Windows 上使用强制锁定而不是建议性锁定。

这已经足够清楚了,但是我被第一条评论所迷惑,其中写道:

Flock 仅使用建议性锁定,也就是说,其他进程 可能会完全忽略该锁定。

我曾理解为我的进程将默认尊重锁定;实际上它似乎意味着类似于“我们假设——当您首次使用 flock() 后——在任何编写之前,您将记得检查锁定的状态,但请记住其他程序可能不会这样做”。

1
这是从手册中引用的内容:“...以咨询方式进行(这意味着所有访问程序必须使用相同的锁定方式,否则它将无法工作)”。 - Accountant م

0
我曾经在Windows 10上使用SimpleXMLElement:asXML()将XML写入文件时遇到了相同的问题。在使用fopen()打开文件并使用flock()锁定后,我的Linux机器可以正常工作并留下XML文档文件,但是在Windows机器上文件会被留空。我尝试在Windows机器上只使用一个单独的“锁文件”,以读取它来获取文件描述符,然后使用排他或共享锁进行锁定,然后在实际文件上使用PHP file_get_contents()、asXML()、simpleXML_load_file()等函数,最后使用flock()解锁锁文件并使用fclose()关闭它。这样做效果更好,因为在Windows上使用fopen()打开文件进行写入似乎会干扰这些PHP函数的操作。所以,你需要...
   $fd=fopen("lockfile.txt", "r");
   flock($fd, LOCK_EX);
   $text=file_get_contents("myFile");
   $text .= "Add some text.\n";
   file_put_contents("myFile", $text);
   flock($fd, LOCK_UN);
   fclose($fd);

   $fd=fopen("lockfile.txt", "r");
   flock($fd, LOCK_SH);
   $text = file_get_contents("myFile");
   echo $text;
   flock($fd, LOCK_UN);
   fclose($fd);

“锁定文件”只是一个交通信号灯,用于保护程序中重要的实际文件。在Windows中,您需要以这种方式进行操作,因为理论上那些PHP函数不会对已被fopen()打开的文件进行操作,而您仍需要将文件描述符作为flock()的参数。
请确保“lockfile.txt”或您命名的任何文件都存在!
   if (!file_exists("lockfile.txt")){
          $fd = fopen("lockfile.txt", "w");
          fwrite("lockfile.txt", "This lockfile now exists!\n");
          fclose($fd);
   }

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