Unable to Download ZIP File from jQuery-AJAX on Button Click event - php

My problem is: I am using a PHP script for zipping a folder and downloading it. But I am doing it by AJAX-jQuery code. So when I click on a button to generate a ZIP package, it won't work. But when I enabled IDM (Internet Download Manager), then it is downloaded. But after disabling the IDM ZIP file created but can not be downloaded. I have attached the AJAX response recorded on Chrome console.
This is my PHP function:
public function createZip($files, $zip_file_name) {
$valid_files = array();
if(is_array($files)) {
foreach($files as $file) {
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
if(count($valid_files > 0)){
$zip = new ZipArchive();
$zip_name = $zip_file_name.".zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "* Sorry ZIP creation failed at this time";
}
foreach($valid_files as $file){
$zip->addFile($file);
}
$zip->close();
if(file_exists($zip_name)){
// force to download the zip
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_name);
// remove zip file from temp path
unlink($zip_name);
return "Files are successfully Archived !";
}
else{
return "ERROR in ZIP FIle Archive!";
}
} else {
return "No valid files to zip";
exit;
}
}
And this is my jQuery / AJAX code:
$(document).on('click', '.zip_dl', function(){
var click_id = $(this).attr('id');
//alert(click_id);
$.ajax({
url: 'includes/AjaxResponses.php',
data: {
folder_name : click_id,
action_type : "zip_file_download"
},
error: function() {
//$('#info').html('<p>An error has occurred</p>');
},
dataType: 'JSON',
success: function(response) {
},
type: 'GET'
});
});

Related

Unable To Create zip for multiple large files and unlink the zip

I am trying to download some files from server using a php script but when I execute the script it works fine with smaller number of file with lesser number of files to zip however when I try execution with larger no of files the server times out and also the zip generated as the result is not deleted and occupies the space on server. the php script is as follows
if(isset($_POST['download_all']))
{
$errmsg = '';
$sql = mysqli_query($conn, "select * from img WHERE gal_id = '".base64_decode($_REQUEST['Gal'])."' And uid='".$_SESSION['uid']."' order by image1 asc");
$url = "dataroot/Gallery/".base64_decode($_REQUEST['Gal'])."_".$_SESSION['uid']."/";
while($res = mysqli_fetch_array($sql)){
$filess[] = $url.$res['image1'];
echo $url.$res['image1'];
}
$files = json_encode($filess);
$files = json_decode($files);
if(is_array($files)) {
foreach($files as $file) {
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
if(count($valid_files > 0)){
$zip = new ZipArchive();
$zip_name = "total.zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "* Sorry ZIP creation failed at this time";
}
foreach($valid_files as $file){
$zip->addFile($file);
}
$zip->close();
if(file_exists($zip_name)){
// force to download the zip
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Transfer-Encoding: binary");
header("Content-length: $ size");
header("Cache-Control: private",false);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
ob_clean();
flush();
readfile($zip_name);
ignore_user_abort(true);
//remove zip file from temp path
unlink($zip_name);
}
} else {
echo "No valid files to zip";
exit;
}
}
I have updated the memory and timeout setting on the server. The issue persists. Also the zip thus formed as the result is not unlinked and consumes memory on server.
already referred to
Reading very large files in PHP
and
How to download multiple large files with php?
but unable to resolve the issue.

AJAX/PHP force file download display contents of zip file in the browser

Hi i'm trying to force download a zip file created from ZipArchive() but the file is not being downloaded instead is displayed/read in the browser.check my code below.
function search(item){
var search = new XMLHttpRequest();
search.open("POST","download.php");
search.onreadystatechange = function(){
if(search.readyState === 4 && search.status === 200){
// document.getElementById('tes').innerHTML = search.responseText;
}
}
search.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
search.send("searchItem="+item);
}
download button, calls search function.
<button value="<?php echo "$name"; ?>" onclick="search(this.value)">Download File</button>
PHP code in the download.php file
<?php
$name = trim($_POST['searchItem']);
if(!file_exists("images/$name/$name.zip")){
//creating a zip file
$zip = new ZipArchive();
$zip_file = "$name".'.zip';
$zip->open("images/$name/".$zip_file, ZipArchive::CREATE);
$files = scandir("images/$name/");
for ($i=2; $i < count($files) ; $i++) {
$fi = $files[$i];
if(file_exists("images/$name/$fi")){
$zip->addFile("images/$name/$fi", $fi);
}
}
$zip->close();
//force to download the zip
$file = "images/$name/$zip_file";
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
readfile($file);
// remove zip file from temp path
unlink($file);
}
?>
Here is what I use to get zip file
header('Content-Type: application/zip'); // ZIP file
header('Content-Disposition: attachment; filename="downloadpackage.zip"');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
header('Content-Description: File Transfer');
echo($file);
Hope that helps
You cannot download a file with javascript/ajax. You're making this way more difficult than it needs to be. Forget about AJAX and just create a form or an anchor tag that links to the script that generates the ZIP file. Your page will not be redirected so there is no reason to do an XHR.
Javascript, for security reasons, does not have access to your filesystem, therefore you cannot use it to download files. What if every web site you went to was capable of adding files to your computer. That'd be bad. That's why you can't.
Since you can't download files using AJAX, The simplest solution is to return the file name to Javascript and use location.href and force file download.
<?php
$name = trim($_POST['searchItem']);
if (!file_exists("images/$name/$name.zip")) {
//creating a zip file
$zip = new ZipArchive();
$zip_file = "$name" . '.zip';
$zip->open("images/$name/" . $zip_file, ZipArchive::CREATE);
$files = scandir("images/$name/");
for ($i = 2; $i < count($files); $i++) {
$fi = $files[$i];
if (file_exists("images/$name/$fi")) {
$zip->addFile("images/$name/$fi", $fi);
}
}
$zip->close();
//force to download the zip
$file = "images/$name/$zip_file";
echo json_encode(['filename' => $file]); // return file name to Javascript
}
?>
Then in Javascript I use location.href to force file download
function search(item){
var search = new XMLHttpRequest();
search.open("POST","check.php");
search.onreadystatechange = function(){
if(search.readyState === 4 && search.status === 200){
var data = JSON.parse(search.responseText);
window.location.href = data.filename; // force file download
}
};
search.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
search.send("searchItem="+item);
}

Add files to zip with php

my php code for create zip file is:
function zipFilesDownload($file_names,$archive_file_name,$file_path)
{
$zip = new ZipArchive();
if ($zip->open($archive_file_name, ZIPARCHIVE::CREATE )!==TRUE) {
exit("cannot open <$archive_file_name>\n");
}
foreach($file_names as $files)
{
if (!file_exists($files)) { die($files.' does not exist'); }
if (!is_readable($files)) { die($files.' not readable'); }
$zip->addFile($file_path.$files,$files);
}
$zip->close();
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;
}
if ($act=="backup") {
$fileNames=array('us/man.txt');
$zip_file_name='myFile.zip';
$file_path=dirname(__FILE__).'/';
zipFilesDownload($fileNames,$zip_file_name,$file_path);
}
i add this code in my php, page show this code instead download:
PK0�~E1x��us/man.txtKIPK0�~E1x��users/mohammad-ali/mamad.txtPKJ>
but if i add it in another php, zip file downloaded correctly.

PHP readfile return weird characters

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

Security issues. PHP window.location

i have created this application which creates a csv file from given list from DB and than allows user to download it! When i finished the job i came to realise that there is a security issues!
Here is the ajas i am using to make a request:
$.ajax({
type: "POST",
url:HTTPS + '/lib/model/data/ctlRates.php?export=1',
data: {
ext: ext,
filter: filter,
fileName: fileName
},
dataType: 'json',
success: function(data){
if(data['results'] == "success"){
console.log(data['results']);
var filename = data['filename'];
var extension = data['ext'];
window.location = HTTPS + '/lib/model/data/ctlRates.php download=1&filename='+filename+'&ext='+extension;
} else {
console.log(data['results']);
}
}
});
} else {
alert("Error: File name and extension must be provided");
}
});
And i imagine that most of you already sees the problem!
but here is the controller to which window.location is pointing:
if(isset($_GET['download']) && $_GET['download'] == 1){
$filePath = "/path/to/file/dir";
$name = $_GET['filename'];
$extension = $_GET['ext'];
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header('Content-Description: File Transfer');
header('Content-type: text/'.$extension.'');
header('Content-Disposition: attachment; filename="'.$name.".".$extension.'');
header("Content-Transfer-Encoding: binary");
header("Pragma: public");
ob_clean();
flush();
readfile($filePath.$name.".".$extension);
}
Started testing and came to realize that everyone can ender filename and extension they pleases and get files from that directory....Any ideas how to burry this hole?
And i imagine that most of you already sees the problem!
Not really - there are very few security issues i javascript - and this does not exhibit any of them - the problem is how you are procesing your data server-side. Do not attempt to server security holes with javascript changes.
If you want to restrict access to a specific directory tree...
if(isset($_GET['download']) && $_GET['download'] == 1){
$filePath = "/path/to/file/dir";
$fetchfrom = realpath($filepath . '/'
. /* basename( */ $name /* ) */
. "." . $extension);
if (substr($fetchfrom, 0, strlen($filepath))!=$filepath) {
header("HTTP/1.0 404 Not Found");
print "Directory traversal not allowed";
exit;
}

Categories