Deleting a file after user download it
PhpPhp Problem Overview
I am using this for sending file to user
header('Content-type: application/zip');
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename="file.zip"');
readfile($file);
I want to delete this file after user downloads it, how can i do this?
EDIT: My scenario is like that, when user hits download button, my script will create a temporary zip file and user download it then that temp zip file will be deleted.
EDIT2: OK best way seems running a cron job that will be cleaning temp files once an hour.
EDIT3: I tested my script with unlink
, it works unless user cancel the download. If user cancel the download, zip file stays on the server. So that is enough for now. :)
EDIT4: WOW! connection_aborted()
made the trick !
ignore_user_abort(true);
if (connection_aborted()) {
unlink($f);
}
This one will delete the file even if user cancel the download.
Php Solutions
Solution 1 - Php
unlink($filename);
This will delete the file.
It needs to be combined with ignore_user_abort()
Docs so that the unlink
is still executed even the user canceled the download.
ignore_user_abort(true);
...
unlink($f);
Solution 2 - Php
I always use the following solution, using register_shutdown_function:
register_shutdown_function('unlink', $file);
Solution 3 - Php
There is no any correct way to detect whether file was completely downloaded by user or not.
So the best way will be to delete file after some period of inactivity.
Solution 4 - Php
connection_aborted()
never worked for me.
Although ob_clean()
works exactly as it should. Hope this help others aswell
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $file . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
ob_clean();
flush();
if (readfile($file))
{
unlink($file);
}
Solution 5 - Php
I couldn't find something which worked for me, so I came up with this, which seems to work well for me:
header('Content-type: application/zip'); //this could be a different header
header('Content-Disposition: attachment; filename="'.$zipName.'"');
ignore_user_abort(true);
$context = stream_context_create();
$file = fopen($zipName, 'rb', FALSE, $context);
while(!feof($file))
{
echo stream_get_contents($file, 2014);
}
fclose($file);
flush();
if (file_exists($zipName)) {
unlink( $zipName );
}
I hope that helps someone
Solution 6 - Php
I too have very similar functionality in one of my website. It will be like deleting randomly created folder & zip file after/cancelling download. I try to explain it here, may be someone find it useful.
skin.php:
This page contains download link such as "http://mysite.com/downoload/bluetheme"
.htaccess:
I have following rule in htaccess file to redirect the download request to a php file. [download.php].
RewriteRule ^download/([A-Za-z0-9]+)$ download.php?file=$1 [L]
download.php:
include "class.snippets.php";
$sn=new snippets();
$theme=$_GET['file'];
$file=$sn->create_zip($theme);
$path="skins/tmp/$file/$file.zip";
$config_file="skins/tmp/$file/xconfig.php";
$dir="skins/tmp/$file";
$file.=".zip";
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$file");
header("Pragma: no-cache");
header("Expires: 0");
readfile($path);
//remove file after download
unlink($path);
unlink($config_file);
rmdir($dir);
so on request download.php will create directory with a random name using snippets class. Inside the directory it will create a zip file. after the download/cancelling the request all the files and the directory will be deleted.
Solution 7 - Php
For those who face the "extra bytes at the begining of file" issue, I would recommend to add buffer cleaning functions before readfile, as suggested in this post:
https://stackoverflow.com/a/51083411/16381972
@ob_start(''); //@ supresses a warning
//header entries
ob_end_clean();
ob_clean();
readfile($file);