在使用PHP下载文件后,如何从服务器上删除文件?

13

我正在使用PHP下载文件,并且希望文件在成功下载完成后从服务器上自动删除。我正在使用以下PHP代码:

$fullPath = 'folder_name/download.txt';

if ($fd = fopen ($fullPath, "r")) {
    $fsize = filesize($fullPath);
    $path_parts = pathinfo($fullPath);
    $ext = strtolower($path_parts["extension"]);

    header("Content-type: application/octet-stream");
    header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
    header("Content-length: $fsize");
    header("Cache-control: private"); //use this to open files directly
    $fd = fopen ($fullPath, "r");
    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
    fclose ($fd);

}

unlink($fullPath);

在下载后的代码中,您可以看到我正在取消链接该文件。但是,如果这样做,可能会下载损坏的文件。因为有时文件在完全下载之前就被删除了。在PHP中有没有办法知道客户端成功下载了文件,然后我才能删除它?任何想法都将不胜感激。


你无法确定下载是否完成。如果你要下载的文件不是很大,那么最好的方法就是通过电子邮件发送并立即删除它们。 - php_nub_qq
你能进行文件大小检查并比较它们的大小吗?如果它们相同,那就完成了。 - Panama Jack
文件删除比文件下载更快。 - Jay Harris
7个回答

6
据我所知,您不能使用服务器端的PHP来检测客户端是否已经完成了下载。似乎ignore_user_abort()是您问题的答案(请参见下文),否则您可以在一定时间后删除文件。
ignore_user_abort(true);
if (connection_aborted()) {
  unlink($f);
} 

在Stackoverflow上相关/重复的问题:


2
如果你确实是在下载(而不是像你的帖子中的代码那样上传),那么你可能会对tmpfile函数感兴趣,该函数专门设计用于创建文件,在其描述符关闭后将立即被删除。

这很简单,因为他可以打开两个文件 - 然后使用stream_copy_to_stream - 删除旧文件并只读取tmp文件 - 但这将破坏部分下载 :) - Bartosz Grzybowski

1

1

无法通过PHP知道用户何时完成文件下载,我会使用队列系统在请求后n秒钟删除文件:

如何构建PHP队列系统


这似乎不是真的。为什么 PHP 不能读取服务器日志并记录文件传输的时间呢?只需总结所有 2xx 请求的传输大小,如果等于或大于(HTTP 标头开销),则表示文件已被下载。 - Brian Klug

0

对于大文件可能会有一些bug,但是对于小文件和快速连接,我使用这个没有问题。

<?php
 ### Check the CREATE FILE has been set and the file exists
if(isset($_POST['create_file']) && file_exists($file_name)):
### Download Speed (in KB)
$dls = 50;
### Delay time (in seconds) added to download time 
$delay = 5; 
## calculates estimated download time
$timer = round(filesize($file_name) / 1024 / $dls + $delay); 
###Calculates file size in kb divides by download speed + 5 ?>

<iframe width="0" height="0" frameborder="0" src="<?php echo $file_name;?>"></iframe>
<h2>Please Wait, Your Download will complete in: <span id="logout-timer"></span></h2> 

通过文件值? f = $file_name重定向到自身

<script>setTimeout(function(){ window.location = "<?php echo $_SERVER['PHP_SELF']?>?f=<?php echo $file_name;?>";},<?php echo $timer;?>000);</script>

删除文件

     <?php 
 endif;
if (isset($_GET['f'])):
    unlink($_GET['f']);
    ### removes GET value and returns to page's original url
    echo "<script> location.replace('".$_SERVER['PHP_SELF']."')</script>"; 
    endif;?>

每个文件的下载定时器设置为var秒

<script>
var seconds=<?php echo $timer;?>;function secondPassed(){var a=Math.round((seconds-30)/60);var b=seconds%60;if(b<10){b="0"+b}document.getElementById('logout-timer').innerHTML=a+":"+b;if(seconds==0){clearInterval(countdownTimer);document.getElementById('logout-timer').innerHTML="Timer"}else{seconds--}}var countdownTimer=setInterval('secondPassed()',1000);
</script>

0

检查请求,如果设置了Range HTTP头,则客户端正在分段下载文件,它只想一次下载一小部分数据(例如:Range: bytes=500-999)。通常这由Web服务器自动处理,但在这种情况下,您必须处理它并仅发送请求的范围。将进度存储在会话中,仅在客户端下载所有片段时拒绝访问。


-1

不确定在几乎所有情况下都能起作用,但尝试使用sleep(10);来延迟删除文件的特定时间。


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