在取消链接

时间:2017-05-16 18:11:12

标签: php concurrency filesystems locking unlink

我想等待所有进程在PHP中读取某个文件,方法是获取该文件的独占锁,然后删除(取消链接)该文件。这涉及用户可以删除或更改的个人资料图片等文件。该文件的名称将类似于用户ID。

我的代码:

//Obtain lock
$file = fopen("path/to/file", "r"); //(I'm not sure which mode to use here btw)
flock($file, LOCK_EX);

//Delete file
unlink("path/to/file");

第3行等待释放所有锁定,这很好,但unlink函数会抛出错误:Warning: unlink(path/to/file): Resource temporarily unavailable in path/to/script on line xx

为了防止这种情况,我可以在调用unlink之前解除锁定,但这意味着另一个进程可能会再次锁定文件,这会导致同样的错误。

我的问题是:

  1. 是否可以在不释放锁的情况下删除PHP中的文件?也就是说,没有其他进程同时尝试使用该文件的风险。
  2. 如果不是:

    1. 这在Windows中是否可行? Unix怎么样?
    2. 我是否应该让我的数据库参与此事并锁定数据库中的行,或者有更好的方法吗?
    3. 我能看到的另一个选项是重复这段代码,包括在调用unlink之前释放锁,直到unlink成功,但这看起来有点乱,对吧?

1 个答案:

答案 0 :(得分:0)

嘿,两年后,我也在为此而苦苦挣扎。似乎有些愚蠢,您在尝试重命名或取消链接文件时无法获得文件的排他锁,或者至少没有文档来执行此操作。

一种解决方案是打开文件进行写入,获取排他锁,使用ftruncate清除文件内容,将其关闭,然后取消链接。从文件中读取文件时,可以检查文件大小以确保文件中包含内容。

删除时(未经验证的代码):

$fh = fopen('yourfile.txt', 'c'); // 'w' mode truncates file, you don't want to do that yet!
flock($fh, LOCK_EX); // blocking, but you can use LOCK_EX | LOCK_NB for nonblocking and a loop + sleep(1) for a timeout
ftruncate($fh, 0); // truncate file to 0 length
fclose($fh);
unlink('yourfile.txt');

阅读时(未经测试的代码):

if (!file_exists('yourfile.txt') || filesize('yourfile.txt') <= 0) {
  print 'nah.jpg, must be dELeTeD :O';
}