I am trying to download files from server and it works fine for pdf files, I am wondering is there a way to download any type of files such as doc, zip,.. etc.
My code:
<?php
$doc = $sqlite->readDoc($documentId);
if ($doc != null) {
header("Content-Type:" . $doc['mime_type']);
header('Content-disposition: attachment; filename="something"');
print $doc['doc'];
} else {
echo 'Error occured while downloading the file';
}
?>
You'll want to identify the file - maybe using this function:
http://php.net/manual/en/function.mime-content-type.php
and then you can create a switch to indicate the content-type and appropriate disposition. There's a decent example here: PHP - send file to user
A simple function that can be used to download any file formate form path.
function DownloadFile($strFilePath)
{
$strContents = file_get_contents(realpath($strFilePath));
if (strpos($strFilePath,"\\") > -1 )
$strFileName = substr($strFilePath,strrpos($strFilePath,"\\")+1);
else
$strFileName = substr($strFilePath,strrpos($strFilePath,"/")+1);
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=\"${strFileName}\"");
echo $strContents;
}
Usage Example
$file = $_GET['file_id'];
$path = "../uploads/".$file; // change the path to fit your websites document structure
DownloadFile($path);
I have a folder in my root dir called files.
This folder contains files ranging from 1 Kb-1 GB.
I want a php script that can simply download a file asynchronously using AJAX.
This codes initiates download scripts when a file is clicked:
JQUERY
$('.download').click(function(){
var src =$(this).attr('src');
$.post('download.php',{
src : src //contains name of file
},function(data){
alert('Downloaded!');
});
});
PHP
<?php
$path = 'files/'.$_POST['src'];
//here the download script must go!
?>
Which would be the best, fastest and secure way to download a file?
<?php
/**
* download.php
*/
if (!empty($_GET['file'])) {
// Security, down allow to pass ANY PATH in your server
$fileName = basename($_GET['file']);
} else {
return;
}
$filePath = '???/files/' . $fileName;
if (!file_exists($filePath)) {
return;
}
header("Content-disposition: attachment; filename=" . $fileName);
header("Content-type: application/pdf");
readfile($filePath);
And actually AJAX request is unnecessary, when using Content-disposition: attachment:
File1
To continue on the original answer, I've added a few php functions to make it a bit more programmatic:
$filePath = $_GET['path'];
$fileName = basename($filePath);
if (empty($filePath)) {
echo "'path' cannot be empty";
exit;
}
if (!file_exists($filePath)) {
echo "'$filePath' does not exist";
exit;
}
header("Content-disposition: attachment; filename=" . $fileName);
header("Content-type: " . mime_content_type($filePath));
readfile($filePath);
If your sever requires strong security, do not use this function without pre-validating the user in the same script. Or use the security measures posted by the original answer. This script will allow any file on your server to be downloaded by a user.
This is a code i found over internet, intended to create a .zip of the entire folder and download it.
I want to do a few changes, but everything I tried doesn't work. What I want:
Make it generic (i.e. I want to have that makezip.php in root folder. I've a file manager, and everytime I call this script from some location (ex. www.domain.com/files/media/images/ it gets that folder).
Delete the zip after the download (I think I did it well, using the comand unlinkbut I'm not sure that's the right way.
Remove that . and .. folder that the zip gets too.
Export the zip with the name date.hour.directory.zip (ex 18Sep2013_13-26-02_images.zip). I tried to do this
$fd = getcwd();
$filename = date("dMY_H:i:s").'_'.$fd.'.zip';
but it didn't worked, it only gets the $fd variable.
I know it isn't supposed to give you all the code and expect that you will look on it nor debug it, but I've tried everything and nothing of it works. I'm learning by myself and I'm a bit newbie on php.
Best regards
<?php
function download($file) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
unlink($file);
exit;
}
$directory = '.';
$files = scandir($directory);
if(empty($files))
{
echo("You haven't selected any file to download.");
}
else
{
$zip = new ZipArchive();
$filename = date("dMY_H:i:s").'_arquivo.zip'; //adds timestamp to zip archive so every file has unique filename
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { // creates new zip archive
exit("Cannot open <$filename>\n");
}
$N = count($files);
for($i=0; $i < $N; $i++)
{
$zip->addFile($files[$i], $files[$i]); //add files to archive
}
$numFiles = $zip->numFiles;
$zip->close();
$time = 8; //how long in seconds do we wait for files to be archived.
$found = false;
for($i=0; $i<$time; $i++){
if($numFiles == $N){ // check if number of files in zip archive equals number of checked files
download($filename);
$found = true;
break;
}
sleep(1); // if not found wait one second before continue looping
}
if($found) { }
else echo "Sorry, this is taking too long";
}
?>
Ok, I've figured out my problems by myself, and I'm sharing the solution for those who want.
Make it generic (i.e. I want to have that makezip.php in root folder. I've a file manager, and everytime I call this script from some location (ex. www.domain.com/files/media/images/ it gets that folder).
I modified the code on index.php, and made a few changes on zip.php (the file which is handling the zipping process. Simples solution.. Dumb!
1 - index.php - just put a simple link
Download folder as a .zip
2 - zip.php
$directory = $_REQUEST['dirz'];
Delete the zip after the download (I think I did it well, using the comand unlinkbut I'm not sure that's the right way.
Yes, it's correct. (on zip.php)
unlink($ZIPNAME);
Remove that . and .. folder that the zip gets too.
$direct = array_diff(scandir($directory), array(".","..","error_log"));
foreach($direct as $file){
if(is_file($directory.'/'.$file)){
$zip->addFile($directory.'/'.$file, $file);
}
}
Export the zip with the name date.hour.directory.zip (ex 18Sep2013_13-26-02_images.zip). I tried to do this $fd = getcwd(); $filename = date("dMY_H:i:s").'_'.$fd.'.zip'; but it didn't worked, it only gets the $fd variable.
Simple as:
$zipname = date("dMY_H-i-s").'_'.basename($directory).'.zip';
Best regards
I need to download images from other websites to my server. Create a ZIP file with those images. automatically start download of created ZIP file. once download is complete the ZIP file and images should be deleted from my server.
Instead of automatic download, a download link is also fine. but other logic remains same.
Well, you'll have to first create the zipfile, using the ZipArchive class.
Then, send :
The right headers, indicating to the browser it should download something as a zip -- see header() -- there is an example on that manual's page that should help
The content of the zip file, using readfile()
And, finally, delete the zip file from your server, using unlink().
Note : as a security precaution, it might be wise to have a PHP script running automatically (by crontab, typically), that would delete the old zip files in your temporary directory.
This just in case your normal PHP script is, sometimes, interrupted, and doesn't delete the temporary file.
<?php
Zip('some_directory/','test.zip');
if(file_exists('test.zip')){
//Set Headers:
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime('test.zip')) . ' GMT');
header('Content-Type: application/force-download');
header('Content-Disposition: inline; filename="test.zip"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize('test.zip'));
header('Connection: close');
readfile('test.zip');
exit();
}
if(file_exists('test.zip')){
unlink('test.zip');
}
function Zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
{
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file)
{
$file = str_replace('\\', '/', realpath($file));
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
?>
Any idea how many zip file downloads get interrupted and need to be continued?
If continued downloads are a small percentage of your downloads, you can delete the zip file immediately; as long as your server is still sending the file to the client, it'll remain on disk.
Once the server closes the file descriptor, the file's reference count will drop to zero, and finally its blocks on disk will be released.
But, you might spent a fair amount of time re-creating zip files if many downloads get interrupted though. Nice cheap optimization if you can get away with it.
Here's how I've been able to do it in the past. This code assumes you've written the files to a path specified by the $path variable. You might have to deal with some permissions issues on your server configuration with using php's exec
// write the files you want to zip up
file_put_contents($path . "/file", $output);
// zip up the contents
chdir($path);
exec("zip -r {$name} ./");
$filename = "{$name}.zip";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.urlencode($filename));
header('Content-Transfer-Encoding: binary');
readfile($filename);
Other solution: Delete past files before creation new zip file:
// Delete past zip files script
$files = glob('*.zip'); //get all file names in array
$currentTime = time(); // get current time
foreach($files as $file){ // get file from array
$lastModifiedTime = filemtime($file); // get file creation time
// get how old is file in hours:
$timeDiff = abs($currentTime - $lastModifiedTime)/(60*60);
//check if file was modified before 1 hour:
if(is_file($file) && $timeDiff > 1)
unlink($file); //delete file
}
Enable your php_curl extension; (php.ini),Then use the below code to create the zip.
create a folder class and use the code given below:
<?php
include("class/create_zip.php");
$create_zip = new create_zip();
//$url_path,$url_path2 you can use your directory path
$urls = array(
'$url_path/file1.pdf',
'$url_path2/files/files2.pdf'
); // file paths
$file_name = "vin.zip"; // zip file default name
$file_folder = rand(1,1000000000); // folder with random name
$create_zip->create_zip($urls,$file_folder,$file_name);
$create_zip->delete_directory($file_folder); //delete random folder
if(file_exists($file_name)){
$temp = file_get_contents($file_name);
unlink($file_name);
}
echo $temp;
?>
create a folder class and use the code given below:
<?php
class create_zip{
function create_zip($urls,$file_folder,$file_name){
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file_name);
header('Content-Transfer-Encoding: binary');
$mkdir = mkdir($file_folder);
$zip = new ZipArchive;
$zip->open($file_name, ZipArchive::CREATE);
foreach ($urls as $url)
{
$path=pathinfo($url);
$path = $file_folder.'/'.$path['basename'];
$zip->addFile($path);
$fileopen = fopen($path, 'w');
$init = curl_init($url);
curl_setopt($init, CURLOPT_FILE, $fileopen);
$data = curl_exec($init);
curl_close($init);
fclose($fileopen);
}
$zip->close();
}
function delete_directory($dirname)
{
if (is_dir($dirname))
$dir_handle = opendir($dirname);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle))
{
if ($file != "." && $file != "..")
{
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($dirname.'/'.$file);
}
}
closedir($dir_handle);
rmdir($dirname);
return true;
}
}
?>
I went there looking for a similar solution, and after reading the comments found this turnover : before creating your zip file in a dedicated folder (here called 'zip_files', delete all zip you estimate being older than a reasonable time (I took 24h) :
$dossier_zip='zip_files';
if(is_dir($dossier_zip))
{
$t_zip=$dossier_zip.'/*.zip'; #this allow you to let index.php, .htaccess and other stuffs...
foreach(glob($t_zip) as $old_zip)
{
if(is_file($old_zip) and filemtime($old_zip)<time()-86400)
{
unlink($old_zip);
}
}
$zipname=$dossier_zip.'/whatever_you_want_but_dedicated_to_your_user.zip';
if(is_file($zipname))
{
unlink($zipname); #to avoid mixing 2 archives
}
$zip=new ZipArchive;
#then do your zip job
By doing so, after 24h you only have the last zips created, user by user. Nothing prevents you for doing a clean by cron task sometimes, but the problem with the cron task is if someone is using the zip archive when the cron is executed it will lead to an error. Here the only possible error is if someone waits 24h to DL the archive.
Firstly, you download images from webiste
then, with the files you have downloaded you creatae zipfile (great tute)
finally you sent this zip file to browser using readfile and headers (see Example 1)
I tried a php solution but was told in my last question I "can't read/list a directory over HTTP. You'll need to use a different protocol to list a directory over the internet: FTP, SSH, etc. You'll need access to the remote server to do this. If the only thing you can use is HTTP, you'll need to retrieve the webpage (= the HTML document) and parse it yourself." ( How to get a php script to print/work )
I would like it to be simple - I can do HTML, I am learning Java, and I am just floundering around with PHP.
Update: an example. file.txt, file2.txt, & file3.txt are in /some/directory - I want a PHP script to grab one RANDOMLY & give it to me in a way I can put it in the href of an element. If not PHP, something else? thanks.
I haven't tested this.
$filenames=glob("files/*.txt");
$count=count($filenames);
if($count>0)
{
$rndfile=$filenames[rand(0,$count-1)];
echo '<a href="' . $rndfile . "'>Random file</a>";
}
First you need the files:
<?php
[...]
$files = scandir(dirname(__FILE__));
$links = array();
foreach($files as $file)
{
links[] = '<a href="http://localhost/url_decoder?file="'.md5_file($filepath.$file).'"> $file';
}
<table>
foreach ($links as $link){ echo "<tr><td>$link</td></tr>";}
<table>
?>
This little script scans the filepath of the current php script and creates one link per file in that directory to another php script that uses the file md5 hashed value as a parameter. Then the decoder should fo the following:
<?php
[...]
$file_search = $_GET['file'];
$files = scandir(dirname(__FILE__));//coder and decored located in same folder
foreach($files as $file)
{
if (md5_file(dirname(__FILE__).DIRECTORY_SEPARATOR.$file) == $file)
{
$fd = fopen (dirname(__FILE__).DIRECTORY_SEPARATOR.$file, "r")) {
$fsize = filesize(dirname(__FILE__).DIRECTORY_SEPARATOR.$file);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
switch ($ext) {
case "pdf":
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\""); // use 'attachment' to force a download
break;
default;
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
while(!feof($fd)) {
$buffer = fread($fd, 2048);
echo $buffer;
}
fclose ($fd);
exit;
}
}
?>
This is not perfect, and some of the code was taken from this page but at least gives you an idea how to operate. Hope this helps!