1

如果多个页面有多个连接,则删除文件时出错。错误:Warning: unlink(folder/1.txt.txt) [function.unlink]: Permission denied in C:\htdocs\fopen.php on line 7

Note:如果只有一个连接访问一切正常发生(没有错误发生)。

PHP代码fopen.php

<?php
function fastWrite($a){
    echo 'Coping file: "',$a,'" to "',$a,'.txt"<br>';
    copy($a,$a.'.txt');

    echo 'Delete file: "',$a,'.txt"<br>';
    unlink($a.'.txt');
}

for($i=0;$i<10;$i++){
    fastWrite('folder/1.txt');
    echo '<hr>';
}
?>

html/javascript 代码(模拟多个连接):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<title>my test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
function myTest(z){
    $.ajax("fopen.php?time="+(new Date().getTime()),{"success":function(data){
        $("<div></div>").addClass("sty").html(data).appendTo("body");
    },"error":function(a,b,c){
        $("<div></div>").addClass("sty").html([a,b,c]).appendTo("body");
    }});
}
</script>
<style>
.sty{
border:1px #000 solid;
overflow:auto;
margin:5px 0 0 5px;
}
</style>
</head>
<body>
<p><a href="teste.html">New test</a></p>
<script type="text/javascript">
var dd = "";
for(var i=0;i<10;i++){
    dd += "myTest(\"#a"+(i+1)+"\");\n";
}
eval(dd);
</script>
</body>
</html>

我做错什么了?

谢谢。


解决方案: clearstatcache

4

2 回答 2

3

您遇到了问题,因为两个进程试图同时复制和删除同一个文件。因为它们是独立的进程,所以你不能轻易控制它们做事的顺序。

想象一下同时运行的两个进程fastWrite()

  • t1 将“a”复制到“a.txt”
  • t2 将“a”复制到“a.txt”
  • t2 删除'a.txt'
  • t1 尝试删除“a.txt”,但由于它不存在而失败

这被称为“竞争条件”。

如果您不介意unlink调用有时会失败,您可以通过在命令前面使用“@”符号来忽略该错误:

@unlink("$a.txt");

我很确定将用户生成的数据一遍又一遍地保存到同一个文件中并不是您的最终目标。你显然在追求更大的东西时遇到了这个问题。也许您应该开始一个新问题,更关注问题。

如果您只需要在连接期间使用临时文件,请不要总是将文件命名为相同。相反,您可以:

function doStuffToFile($fname) {
    $tempName = $fname . "." . getmypid() . "." . rand();
    copy($fname, $tempName);
    // do stuff to your temporary file
    unlink($tempName);
}
于 2012-11-10T17:06:46.500 回答
1

问题是您有两个或更多脚本写入和删除1.txt.txt。这称为竞争条件。Script1.php无法直接知道Script2.php是否正在使用文件,您需要自己实现此机制。

一个简单的解决方案是在使用共享文件之前创建一个锁定文件,并在完成后删除锁定文件。

那么有一个新问题:如何确保两个脚本不会同时创建锁定文件?Script1.php可能会发现锁定文件不存在,但在它实际创建文件之前,处理器切换到Script2.php,它也发现锁定文件丢失。然后怎样呢?

PHP 提供了一个有用的flock功能。我不知道血淋淋的细节,但我相信它应该至少在某些平台上在某种程度上解决你的问题。

<?php
function fastWrite($a)
{
    # //// LOCK \\\\
    $fp = fopen("fastwrite.lock", "w");
    if (flock($fp, LOCK_EX) === false) { # PHP will stop at this line until the lock is acquired
        die("flock failed");
    }
    # \\\\ LOCK ////

    echo 'Coping file: "', $a, '" to "', $a, '.txt"<br>';
    copy($a, $a . '.txt');

    echo 'Delete file: "', $a, '.txt"<br>';
    unlink($a . '.txt');

    # //// UNLOCK \\\\
    if (flock($fp, LOCK_UN) === false) {
        die("flock failed");
    }
    fclose($fp);
    # \\\\ UNLOCK ////

}
for ($i = 0; $i < 10; $i++) {
    fastWrite('1.txt');
    echo '<hr>';
}

PS:我无法在我的系统上重现比赛条件。

于 2012-11-10T17:37:18.673 回答