I'm struggling with a simple php script that combine files into a single .zip and then start downloading it.
My script is called through AJAX with Wordpress.
The response header seems fine but the response is a large amount of weird characters (see below).
Probably a problem with the zip file encoding but I can't figure it out.
Note that I can find the zip on my server.
The response headers
The php function
function zipFilesAndDownload($file_names,$archive_file_name) {
ob_start();
$zip = new ZipArchive();
$archive_link = WP_CONTENT_DIR . '/uploads/' . $archive_file_name;
// Create the zip file and throw error if problem
if ($zip->open($archive_link , ZIPARCHIVE::CREATE )!==TRUE) {
exit("Cannot create <$archive_file_name>\n");
}
foreach($file_names as $files)
{
// Create the absolute path for the files
$file_full_path = WP_CONTENT_DIR . '/uploads/' . $files;
// Clean the file name to remove date path created by WP (/2014/05/file -> file)
$file = end((explode('/', $files)));
// Check if the file exists
if ( file_exists( $file_full_path ) ){
// Add the file to the zip with the new $file name
$zip->addFile( $file_full_path, $file );
} else {
exit("ERROR file doesn't exist : $file\n");
}
}
$zip->close();
if(file_exists($archive_link)){
// Send the proper header to download the zip
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($archive_link).'"');
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($archive_link));
ob_end_clean();
flush();
readfile($archive_link);
//unlink($archive_link);
exit;
} else {
exit("ERROR can't find <$archive_file_name>\n");
}
}
The weird characters
I just echoed an array containing the download link :
echo json_encode(array("link"=>$downloadLink));
and within my ajax success callback function :
$.post(ajax_object.ajax_url, data, function (response) {
$("body").append("<iframe src='" + response.link + "' style='display: none;' ></iframe>");
}, "json");
This post helps me : https://stackoverflow.com/a/8394118/345901
Related
I have the following file hierarchy :
downloader.php (to download the files only through the php page for logged in users and block direct access through .htaccess file )
10-C-Language (a directory containing some pdf files )
C Language 2019 First + notes.pdf (a pdf file contained in "10-C-Language" directory)
The link sent to the downloader.php is as follows:
downloader.php?file=10-C-Language/C%20Language%202017%20First%20%20+%notes.pdf
but it returns
File does not exist.
although the file does exist !
here is the php code for the downloader:
<?php
include('session.php');
if (isset($_GET['file'])) {
//Read the filename
$filename = $_GET['file'];
//Check the file exists or not
$extension = pathinfo($filename, PATHINFO_EXTENSION);
$allowed = array('pdf', 'txt', 'docx', 'rar', 'zip', 'jar');
if (!in_array($extension, $allowed)) {
echo 'You don't have permission to download this type of files.';
} else {
if (file_exists($filename)) {
//Define header information
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: 0");
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . filesize($filename));
header('Pragma: public');
ob_clean();
//Clear system output buffer
flush();
//Read the size of the file
readfile($filename);
//Terminate from the script
die();
} else {
echo "File does not exist.";
}
}
} else
echo "Filename is not defined."
?>
Some files are containing spaces ,but they are downloaded fine ,but for other cases like the ond described above it doesn't work !
So what is the problem here ?!
Regards
I am having an issue with the below code (it works fine on local).
I am using this for an image gallery to download a selection of images using a checkbox. Anyways, this is working fine on my localhost but when I execute this code on my live site it downloads a zip file with the correct file names but the the files are blank.
Any suggestions to why this may be happening?
<?php
function zipFilesAndDownload($file_names, $archive_file_name, $file_path)
{
$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");
}
foreach ($file_names as $files) {
# download file
$download_file = file_get_contents($files);
#add it to the zip
$zip->addFromString(basename($files), $download_file);
}
$zip->close();
$zipped_size = filesize($archive_file_name);
header("Content-Description: File Transfer");
header("Content-type: application/zip");
header("Content-Type: application/force-download");// some browsers need this
header("Content-Disposition: attachment; filename=$archive_file_name");
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-Length:" . " $zipped_size");
ob_clean();
flush();
readfile("$archive_file_name");
unlink("$archive_file_name"); // Now delete the temp file on the server
exit;
}
if (isset($_POST['formSubmit'])) {
//$file_names=$_POST['files'];//
//$file_names = filter_var_array($_POST['files']);//works but it's the wrong method
$filter = filter_input_array(INPUT_POST, FILTER_SANITIZE_SPECIAL_CHARS); //sanitise files
$file_names = $filter['files'];
//Archive name
$archive_file_name = 'product-images.zip';
//Download Files path
$file_path = getcwd() . '';
//cal the function
zipFilesAndDownload($file_names, $archive_file_name, $file_path);
} else {
header("Refresh: 5; url= ./index.php ");
print '<h1 style="text-align:center">You you shouldn\'t be here ......</pre>
<p style="color: red;"><strong>redirection in 5 seconds</strong></p>
<pre>';
exit;
}
?>
edit: i see this in my php error log:
PHP message: PHP Warning: ZipArchive::close(): Failure to create temporary file: Permission denied in /var/www/html/wp-content/plugins/jig/download-product-images.php on line 19
I have text file contains Sample of CSV file format, I want my users can download that file on a link click.
This file resides in this folder stucture:
assets->csv->Sample-CSV-Format.txt
This is the code that I have tried to far:
<?php
$file_name = "Sample-CSV-Format.txt";
// extracting the extension:
$ext = substr($file_name, strpos($file_name,'.') + 1);
header('Content-disposition: attachment; filename=' . $file_name);
if (strtolower($ext) == "txt") {
// works for txt only
header('Content-type: text/plain');
} else {
// works for all
header('Content-type: application/' . $ext);extensions except txt
}
readfile($decrypted_file_path);
?>
<p class="text-center">Download the Sample file HERE It has a sample of one entry</p>
This code is downloading the file on page load instead of link click. Also, it is downloading the whole html structure of the page I want only the text what I have written in text file.
Please guide where is the issue?
You can do this simply in by HTML5 download atrribute . Just add this line in your downloading link .
HERE
You can do it like this, it won't redirect you and also works good for larger files.
In your controller "Controller.php"
function downloadFile(){
$yourFile = "Sample-CSV-Format.txt";
$file = #fopen($yourFile, "rb");
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=TheNameYouWant.txt');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($yourFile));
while (!feof($file)) {
print(#fread($file, 1024 * 8));
ob_flush();
flush();
}
}
In your view "view.php"
Download
make it like this
someother_file.php
<?php
$file_name = "Sample-CSV-Format.txt";
// extracting the extension:
$ext = substr($file_name, strpos($file_name,'.')+1);
header('Content-disposition: attachment; filename='.$file_name);
if(strtolower($ext) == "txt")
{
header('Content-type: text/plain'); // works for txt only
}
else
{
header('Content-type: application/'.$ext); // works for all extensions except txt
}
readfile($decrypted_file_path);
?>
some_html_page.html
<p class="text-center">Download the Sample file HERE It has a sample of one entry</p>
To my view its better to have the download code to the client side, than to have a controller-method written for this.
you can use this ref
public function getTxt()
{
$this->load->helper('download');
$dataFile = "NOTE87";
$dataContent = array();
$dt = "Date :23/07/2021";
$dataContent= array(
"\n",
"\t\t\tUTI AMC Limited\n",
"\t\tDepartment of Fund Accounts\n",
"\n",
"\tReissue of Non Sale Remittance - Axis Bank Cases\n",
"\n",
"\t\t\t\tDate :".$dt."\n",
"\n",
);
force_download($dataFile,implode($dataContent));
}
I'm working on a CodeIgniter-based web app, and I'm implementing the functionality to download a zip file of the vehicle images in the admin for passing to third parties.
I'm able to create the zip archive without problem - if I comment out the later parts, I can see that the zip file gets created and contains the correct files, and it can be extracted as normal.
However, allowing the user to download the file once it's created is proving tricky. What I've implemented allows a file with the correct name to be downloaded, but it errors when unzipped with the following message:
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
Any idea where I've gone wrong? I checked multiple tutorials on the web and couldn't find where the issue was.
public function downloadvehicleimages()
{
// If logged in...
if ($this->adminuser)
{
// Get data
$usedcars = $this->adminmodel->getUsedCarsWithLimit();
// Get the registrations for these vehicles
$registrations = array();
foreach($usedcars->result_array() as $usedcar)
{
array_push($registrations, $usedcar['Registration']);
}
// Get all the images for these registrations
$images = array();
$original_dir = getcwd();
chdir('../used-cars/static/images/custom/');
foreach($registrations as $registration)
{
$vehicle_images = glob(strtoupper($registration) . '_*.jpg');
sort($vehicle_images);
foreach($vehicle_images as $vehicle_image)
{
array_push($images, $vehicle_image);
}
}
// Zip them up
$zipname = 'images.zip';
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach($images as $image)
{
$zip->addFile($image);
}
$zip->close();
// Let user download the file
$this->output->set_header('Content-Type: application/zip');
$this->output->set_header('Pragma: no-cache');
$this->output->set_header('Expires: 0');
$this->output->set_header("Content-Disposition: attachment;filename='$zipname'");
$this->output->set_header('Content:Length: ' . filesize($zipname));
unlink($zipname);
chdir($original_dir);
}
}
You need to use fopen() to read the content of the zipfile, and readfile() to pass the file content to the visitor. And also, provide the full system directory uri to the files location:
$filename = 'images.zip';
$path = /var/www/yourdomain.com/images.zip';
if(!file_exists($path))
{
die('Error: file not found');
}
else {
$handle = fopen($path, "r");
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename='.$filename);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
flush();
readfile($path);
fclose($handle);
<?PHP
function zipFilesAndDownload($file_names,$archive_file_name,$file_path){
$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.$files,$files);
}
$zip->close();
$zipped_size = filesize($archive_file_name);
header("Content-Description: File Transfer");
header("Content-type: application/zip");
header("Content-Type: application/force-download");// some browsers need this
header("Content-Disposition: attachment; filename=$archive_file_name");
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-Length:". " $zipped_size");
ob_clean();
flush();
readfile("$archive_file_name");
unlink("$archive_file_name"); // Now delete the temp file (some servers need this option)
exit;
}
if(($_POST['formSubmit'])) {
//$file_names=$_POST['items'];// Always sanitize your submitted data!!!!!!
//$file_names = filter_var_array($_POST['items']);//works but it's the wrong method
$filter = filter_input_array(INPUT_POST, FILTER_SANITIZE_SPECIAL_CHARS) ;
$file_names = $filter['items'] ;
//Archive name
$archive_file_name= "zip.zip";
//Download Files path
$file_path= $leadon;
//cal the function
zipFilesAndDownload($file_names,$archive_file_name,$leadon);
}
?>
I have a working code here.
The main problem is
//Download Files path
$file_path= $leadon;
//cal the function
zipFilesAndDownload($file_names,$archive_file_name,$leadon);
This code
echo $leadon;
returns string images2/User/
And it doesn't create me the zip file ( well it creates a blank ) but if I manually type in the path
"images2/User/"
into
$file_path= and then I just change
zipFilesAndDownload($file_names,$archive_file_name,$file_path);
everything works fine can you tell me why is it so? And how can I change it:s