bool flock ( resource handle, int operation [, int &wouldblock])
文件系统操作的关键问题是,如果两个脚本试图同时写入文件,您将处于不稳定状态。fopen()在文件上调用该函数时,该函数不会阻止该文件被另一个脚本打开,这意味着您可能会发现一个脚本正在读取文件,而另一个脚本正在写入,或者更糟的是,两个脚本同时写入同一文件。
解决此问题的方法是使用文件锁定,该锁定在PHP中使用flock()函数实现。锁定文件时,可以选择将其标记为只读锁,从而与其他进程或独占锁共享对文件的访问权限,从而可以更改文件。在Unix上,flock()是advisory,表示操作系统可以随意忽略它。在Windows上,这flock()是强制性的,这意味着无论您是否要求文件都被操作系统锁定!
该flock()函数将文件句柄作为其第一个参数,并将锁定操作作为其第二个参数。您已经知道文件句柄,并且操作很简单:LOCK_SH请求共享锁,LOCK_EX请求排他锁,而LOCK_UN释放锁。如果成功检索到文件锁,则调用flock()将返回true;如果失败,则调用false。因此,例如,可以像这样使用flock():
<?php $fp = fopen( $filename,"w"); // open it for WRITING ("w") if (flock($fp, LOCK_EX)) { // 你的文件写在这里吗 flock($fp, LOCK_UN); // 解锁文件 } else { // flock()返回false,未获得锁定 print "Could not lock $filename!\n"; } ?>
文件锁定需要相当现代的文件系统,例如NTFS(Windows),ext3 / ext4(Linux)和HFS +(Mac)。此外,通常用于在Unix机器之间提供文件共享的网络文件系统(NFS)不适合与flock()一起使用。
PHP中的文件锁定机制默认使进程自动排队等待其锁定。例如,将下面的脚本另存为flock.php:
<?php $fp = fopen("foo.txt", "w"); if (flock($fp, LOCK_EX)) { print "Got lock!\n"; sleep(10); flock($fp, LOCK_UN); } ?>
该脚本尝试锁定文件foo.txt,因此您需要创建该文件。该脚本使用LOCK_EX锁定它,这意味着没有其他程序可以锁定该文件。获得锁定后,脚本将休眠十秒钟,然后解锁文件并退出。如果由于另一个应用程序具有锁定而无法获得锁定,则脚本将等待flock()调用释放,然后将其自身锁定并继续。
要对此进行测试,请打开两个命令提示符并运行两次脚本。第一次运行脚本将立即获得一个锁,并显示“ Got lock!”,然后睡眠十秒钟。如果在第一个脚本处于休眠状态时启动了第二个脚本,它将在flock()调用中等待(“阻止”)并等待第一个脚本完成。当第一个脚本完成时,第二个脚本将成功获得其锁定,并打印出“ Got lock!”。然后再睡十秒钟,直到它最终终止。
有时不希望脚本等待文件被解锁,在这种情况下,您可以使用按位OR运算符|向第二个参数添加一个额外的选项。如果您使用常规的第二个参数传递LOCK_NB ORed,则PHP在请求文件锁定时将不会阻塞。这意味着,如果文件锁不可用,flock()将立即以false返回,而不是在等待锁可用之前徘徊。
这是代码中的样子:
<?php $fp = fopen("foo.txt", "w"); if (flock($fp, LOCK_EX | LOCK_NB)) { echo "Got lock!\n"; sleep(10); flock($fp, LOCK_UN); } else { print "Could not get lock!\n"; } ?>
这次,第一个脚本将获得锁定并显示“ Got lock!”,而第二个脚本将无法获得锁定,立即返回并显示“无法获得锁定!”。