I tried to create a zip file using zip archive, it works fine although the zip file is downloaded twice in two different folders at same time, the htdocs folder where the source code is and the default download folder from browser setting. Is there any way that I could prevent this? I only want it to be downloaded once into download folder...
$file_names = explode(',', $_REQUEST['files']);
$dir = $_REQUEST['currentdir'];
//Archive name
$archive_file_name="Downloaded_".date("Y-m-d_G-i-s").".zip";
//Download Files path
$file_path=$dir;
//cal the function
zipFilesAndDownload($file_names,$archive_file_name,$file_path);
function zipFilesAndDownload($file_names,$archive_file_name,$file_path)
{
$zip = new ZipArchive();
$res = $zip->open($archive_file_name, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE );
if ($res===TRUE) {
//add each files of $file_name array to archive
foreach($file_names as $files)
{
$tt=$file_path."/".$files;
if (file_exists($tt)){
$zip->addFile($tt,$files);
}
else{
return false;
exit;
}
}
$zip->close();
//then send the headers to force download the zip file
header('Content-type: application/zip');
header("Content-Disposition: attachment; filename=\"".basename($archive_file_name)."\"");
header('Pragma: no-cache');
header('Expires: 0');
//header('Content-Length: ' . filesize($archive_file_name));
ob_end_clean();
//flush();
readfile($archive_file_name);
exit;
}
else{
return false;
exit;
}
}
Your PHP script creates the zip in the local directory, which is your htdocs directory.
You have a few options now:
Delete the zip archive after reading the archive with php (readfile)
Create the zip archive in a subdirectory, if you need to save it for later (archiving)
Create the zip in the temporary folder and delete the zip after use
I would go with option 3, as it will ensure that the zip gets ever deleted if the script dies before being able to delete it.
You can delete a file with the unlink() command. You just pass the filename or filepath to it and it does it (if the file exists). If you want to save it in a subdirectory, you just prepend the directory name with the directory separator to the filename. If you want to save it e.g. in the subdirectory 'downloads', you just add downloads/ before the filename. $archive_file_name="downloads/Downloaded_".date("Y-m-d_G-i-s").".zip";
The better option here is to create the zip in the server's temporary directory and manually delete it, so the zip gets cleaned up as soon as it's done. You will get the server's temporary directory with sys_get_temp_dir(), which you can prepend to the filename. After you're done with your business you can just delete the file with unlink().
$archive_file_name=sys_get_temp_dir()."Downloaded_".date("Y-m-d_G-i-s").".zip";
After you're done and want to delete the file you just do unlink($archive_file_name);.
Function reference:
http://php.net/unlink
http://php.net/sys_get_temp_dir
After download, you can delete the file on server:
(...)
ob_end_clean();
//flush();
readfile( $archive_file_name );
unlink( $archive_file_name );
(...)
Related
guys! I saw a lot of posts talking about using ZipArchive and how to get rid of the path structure inside the zip.
So, here's my code:
$zipname = $post->post_title.".zip";
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach($gallery as $img) {
$attachment = get_attached_file($img['id']);
$zip->addFile($attachment, pathinfo($attachment,PATHINFO_BASENAME));
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
exit;
The problem is, that the zip file contains an image without path, f.e. /image.jpg and the same image in a multiple directories as it appears on the server /path/to/the/file/image.jpg.
So, I'm not sure why this is happening. Can somebody help on this?
Looking at the documentation of addFile:
$zip->addFile($attachment, pathinfo($attachment,PATHINFO_BASENAME));
pathinfo($attachment,PATHINFO_BASENAME) is returning you the "base name", that is to say the file name (without the path). The second parameter is the name (with path) of the file IN the zip.
If you want to keep the complete path structure in your zip, you should remove this parameter:
$zip->addFile($attachment)
I have zip files in my website and I made a log in system so only users with valid passwords can download the zip files ONCE.
But there is always a possibility that they can download the zip files directly by entering the file path in the browser address bar.
You can get the link of the zip file by viewing the source code.
How can I deny people from downloading zip files by simply posting the file link in the browser address bar? is possible?
Instead of placing the file in a web accessible folder (/var/www/ for example), place it above it so users can't browse to it (like /var/files). Then to serve it to your users, after they type the password, with a php script, have the script set the headers as they would if it were a file, and use readfile to output the contents of the file to the user.
Firstly, create a folder in your root (~/) called secure_zip or something. This should sit alongside your public_html folder (meaning they cannot be accessed by typing in a URL).
Next, create a new php script, called file.php or something:-
<?php
public function sendFile() {
$filename = "sample.zip";
$attachment_location = $_SERVER["DOCUMENT_ROOT"]
. "../secure_zip/" . $filename;
if (file_exists($attachment_location)) {
header('Cache-Control: public'); // needed for i.e.
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $filename . '"');
readfile($attachment_location);
die();
} else {
die('Error: File not found.');
}
}
And call sendFile() if you authenticate the user using whatever logic you like, eg:
if (true) { sendFile(); }
Just to start, I'm a PHP noob.
I have an Apache server which hosts my files. I have a device which can only point to one PHP file. What I need it to do is have my PHP file read in the name of the file I want to download, and point it towards the directory it is stored. Currently, I have it pointing to one file, but I need it to be able to point to multiple. Is this possible in PHP?
Here's what I have so far:
<?php
$file_name = 'file.img';
$size = filesize($file_name);
$file_url = 'http://192.168.0.5/' . $file_name;
header("Content-length: $size");
header("Content-Type: text/plain");
header("Content-Transfer-Encoding: binary");
header("Content-disposition: attachment; filename=\"".$file_name."\"");
readfile($file_url);?>
Edit:
The commands I want to input in order to download the file are close enough to as follows:
cmd=download+-a+$$.img+altimage
cmd=download+-a+$$.conf+altconfig
and the download directory is the .php file. I am open to other suggestions in how to do this.
Edit2:
Here's what an exact sample URL is:
myserver.com/cgi-bin/va/cmd?hdl+fullconfig.ini+altconfig
the hdl is a predefined function which points to the download directory, in order to download the file from the server, so the layout of what you mean isn't exactly the same.
I have trouble understanding what exactly you're trying to do, but I guess that you want a user to be able to download multiple files. If that is correct, here is one way to achieve this:
You can let PHP create a ZIP archive using the ZIP extension. For it to work, you have to load the extension php_zip.dll inside your php.ini.
$ZIP = new ZipArchive();
// Use the current time as the filename to prevent two users to use the same file
$ZIPName = microtime().".zip";
// Create a new ZIP file
$ZIP->open($ZIPName, ZIPARCHIVE::CREATE);
// Loop through all files - $Files needs to be an array with the names of the files you want to add, including the paths
// basename() will prevent the creation of folders inside the ZIP
foreach ($Files as $File) {
$ZIP->addFile($File, basename($File));
}
// Close the archive
$ZIP->close();
// Send the archive to the browser
readfile($ZIPName);
I hope this is what you were looking for.
I have a function for export one csv file include all answers of each survey. I need one function for export all answers of all surveys (one survey per one csv file) into menory and zip it before download to computer
Not save all csv file into server or local storage, I need storage it into memory and zip it before download to computer
I had use this code:
function exportAllAnswer() {
allTokenId = getAllTokenId();
foreach(allTokend as $key->$value) {
exportAnswer($value->id, false);
}
$path = 'exportAllCsv';
// we deliver a zip file
header("Content-Type: archive/zip");
// filename for the browser to save the zip file
header("Content-Disposition: attachment; filename=allCsvs.zip");
// get a tmp name for the .zip
$tmp_zip = tempnam ("tmp", "tempname") . ".zip";
//change directory so the zip file doesnt have a tree structure in it.
chdir($path);
// zip the stuff (dir and all in there) into the tmp_zip file
exec('zip '.$tmp_zip.' *');
// deliver the zip file
$fp = fopen("$tmp_zip","r");
echo fpassthru($fp);
// clean up the tmp zip file
unlink($tmp_zip);
// delete folder csv
rmdir($path);
}
I have the following code running on my site. The only problem I have with it is that it makes a zip file on the server and then user downloads.
I would like to know what should I do in order for the zip file to be generated "on the fly" without being dumped on the server disk first. I would also like to make possible for the user to pause/resume the download.
//function for zip
function zipFilesAndDownload($file_names,$archive_file_name,$file_path)
{
//create the object
$zip = new ZipArchive();
//create the file and throw the error if unsuccessful
if ($zip->open($archive_file_name, ZIPARCHIVE::CREATE )!==TRUE) {
exit("cannot open <$archive_file_name>\n");
}
//add each files of $file_name array to archive
foreach($file_names as $files)
{
$zip->addFile($file_path.str_replace('./','',$files),translit($files).".mp3");
}
$zip->close();
//then send the headers to foce download the zip file
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$archive_file_name");
header("Pragma: no-cache");
header("Expires: 0");
readfile("$archive_file_name");
exit;
}
There are three requirements you mention:
zip is available for download on fly - I presume that by this, you mean "zip file is created on the fly". This is already happening. Indeed, it is what your script does, it's raison d'etre, if you will.
zip file should not be created on server - You have to create a file on the server, even if it's only temporarily, because that is how the Zip extension works. You can delete it after the user has downloaded it (just add unlink($archive_file_name); on the line before exit;).
user can also resume it if paused - This requirement is (mostly) incompatible with zip file should not be created on server. Resumable downloads are implementable in PHP, but it is quite difficult to do and requires access to the Range: header of the request - which not every server will allow you to have. Also, you would have to generate the whole file for even a partial request, because you have deleted it from the server. Apache has an implementation of resumable downloads, but it requires (AFAIK) that the file be static on the hard drive, and requested directly. This would mean that deleting the file after it was downloaded (at the end of the PHP script) would break the resumability.
Reading between the lines, I suspect the problem you are having is that your server's hard drive space is getting used up by all the Zip archives you are creating and not deleting. The solution to this (while still allowing resumable downloads) is to implement some form of TTL checker on the server and periodically deleting files that are older than, for example, 1 day. You could do this with a cron job, or by running the check when you go to create a new arhive.
At the moment, your code does not specify where the zip files will be created, and this is something you would need to do. Here is an example that assumes your script is in the root directory of your site, and that there is a directory called zips in the root directory of your site.
The basic flow is:
Loop through the /zips directory, and delete all files that are older than 1 day.
Create a new archive in the /zips directory
Redirect the user to the path of that static file.
function zipFilesAndDownload($file_names, $archive_file_name, $file_path) {
// Archive directory
$archiveDir = 'zips';
// Time-to-live
$archiveTTL = 86400; // 1 day
// Files to ignore
$ignoreFiles = array('.', '..');
// Loop the storage directory and delete old files
if ($dp = opendir($archiveDir)) {
while ($file = readdir($dp)) {
if (!in_array($file, $ignoreFiles) && filectime("$archiveDir/$file") < (time() - $archiveTTL)) {
unlink("$archiveDir/$file");
}
}
}
// Re-format the file name
$archive_file_name = "$archiveDir/".basename($archive_file_name);
// Create the object
$zip = new ZipArchive();
// Create the file and throw the error if unsuccessful
if ($zip->open($archive_file_name, ZIPARCHIVE::CREATE) !== TRUE) {
exit("Cannot open '$archive_file_name'\n");
}
// Add each file of $file_name array to archive
foreach($file_names as $file) {
$zip->addFile($file_path.str_replace('./', '', $file), translit($files).".mp3");
}
$zip->close();
// Then send the headers to redirect to the ZIP file
header("HTTP/1.1 303 See Other"); // 303 is technically correct for this type of redirect
header("Location: http://{$_SERVER['HTTP_HOST']}/$archive_file_name");
exit;
}