Im using Php (Zend Framework) to download a datagrid as CSV..the csv generation works fine.I just want to know is it possible to download the csv file within a zip file
My current code
public function downloadCsvAction(){
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=answers_csv.csv");
header("Pragma: no-cache");
header("Expires: 0");
echo "stuff1" . ",";
echo "stuff2".",";
//----bla bla
exit;
}
By calling the url controller/downloadCsv im getting a popup to save the csv.I want the csv to be in a zip file
Here is a simple code to zip and output csv as a zip file
//here is your csv file
$csvFile = "test.csv";
//location for php to create zip file.
$zipPath = "/tmp/$csvFile.zip";
$zip = new ZipArchive();
if ($zip->open($zipPath,ZipArchive::CREATE)) {
$zip->addFile($csvFile, $csvFile);
$zip->close();
//Make sure the zip file created and output it.
if(is_file($zipPath)){
header('Content-type: application/octet-stream; charset=utf-8');
header('Content-Disposition: attachment; filename="'.$csvFile.'.zip"');
header('Content-Length: ' . filesize($zipPath));
readfile($zipPath,false);
}
}
I just want to know is it possible to download the csv file within a zip file
Yes it is possible. Just create a ZIP-file and put the CSV-file in there. Then deliver the ZIP-file.
If you're looking for more technical info, please read into the related Q&A material as the concrete code differs highly on what you need to achieve:
Generating ZIP files with PHP + Apache on-the-fly in high speed?
Related
I'm using PHPWord to generate Word documents, and I'm hoping someone can help on this. The way its set up now, an ajax request is sent to my server from the browser requesting the PHPWord document to be built. The document is built, and stored in a file on the server with this code:
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$fileName = $picklistDetails['file_name'] . ".docx";
$filePath = '../users/' . $userId . "_word_" . $fileName;
$objWriter->save($filePath);
To allow the user to download the file, once the ajax request succeeds i use window.location to send the user to a page that puts the word document together with this (allowing the download to commence):
$fileName = $this->session->word_file_name;
$filePath = $this->session->word_file_path;
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . $fileName);
header("Content-Transfer-Encoding: binary");
readfile($filePath);
This all works great, the only problem is i would really rather the file not have to be saved to the server before the download. I've been researching PHPWord and as per this post (Auto download the file attachment using PHPWord) theres some discussion of how you can send the file to php's output stream instead of writing it to disk, but because building the word document is done in ajax and then a separate page is used to download it, i don't think this would work. Am i wrong?
Also in this post (Save Generated File to database PHPWORD) there is a description of how to store it to a DB, but there's still the intermediate step of a file on the server, which i need to avoid.
Is there some way I can modify
$objWriter->save($filePath);
to not write it to disk and instead save it to a variable or something? Then I could maybe store in a database where I could encrypt it.
Any help would be appreciated. I'm kind of a beginner php programmer so detailed help would be much appreciated. have a good day.
Should be as simple as doing $objWriter->save("php://output");:
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$fileName = $picklistDetails['file_name'] . ".docx";
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . $fileName);
header("Content-Transfer-Encoding: binary");
$objWriter->save("php://output");
Skip the redirect entirely. Just window.location directly to the above code ^ and the file should download once it's done building.
The end goal is for the user to download a .csv file. Right now I'm just testing trying to download a simple text file: test.txt. The only thing in this file is the word "test".
Here is the HTML code for files_to_download.php
Test file: <a href='test.php?file=test.txt'>Test.txt</a>
Code for test.php:
if(!(empty($_GET["file"])))
{
$file_name = $_GET["file"];
$path = "path/to/file";
$fullPath = $path . $file_name;
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: inline; attachment; filename=\"$file_name\"");
header("Content-Type: text/plain");
header("Content-Transfer-Encoding: binary");
readfile($fullPath);
}
I've tried variations of the headers above, adding more and removing others. The above seem to be the most common recommended on this site.
I've also tried changing
header("Content-Type: text/plain");
to
header("Content-Type: text/csv");
and get same results: empty .txt or .csv file.
The files are not empty when I open them directly (file browser) from the server. I've checked the permissions of the files and they're both 644, so the entire world can at least read the files. The directory is 777.
Is there a configuration on the Apache server I need to specify that may not be or am I missing something above.
Thanks for looking!
In most cases the path is wrong
Read the text file, then echo the text out after your header() calls.
Here's how I have my csv download set up:
//downloads an export of the user DB
$csv = User::exportUsers();
header('Content-disposition: attachment; filename=userdb.csv');
header('Content-type: text/csv');
echo $csv;
Where exportUsers() creates the csv data. You can easily just replace $csv with the contents of your text file, then echo it out.
And as far as your text file, you can use file_get_contents() to get the contents of your file into a string. Then echo that string.
Try setting the content length of the file:
header('Content-Length: ' . filesize($file));
Also, please have this in mind: file inclusion
In my case, the path was correct. And the download-forcing was working on windows, but not mac.
I figured out after few tests that the header Content-Length was failing. I was using the function filesize on a full url, like :
$url_my_file = "http://my-website.com/folders/file.ext";
header('Content-Length: '.(filesize($url_my_file)));
I replace it by
$url_my_file = "http://my-website.com/folders/file.ext";
$headers = get_headers($url_my_file, 1);
header('Content-Length: '.($headers['Content-Length']));
And ... It's working now :)
I have following PHP Script for downloading the zip files:
header("Content-length:".filesize($archive_file_name));
header('Content-Type: application/zip'); // ZIP file
header('Content-Disposition: attachment; filename="downloadpackage.zip"');
header('Content-Transfer-Encoding: binary');
readfile($archive_file_name);
exit();
But it doesn't force the download the zip file instead, it shows the lots of unusual characters like below:
PK[�FA����#�X$D:\voice_06101243342pm014771957.wav�|�s]�y���b�CI\��{2m��M'�Eibu2\#B��܋{� 6b# $H,\#��:��Z�(q�����ә���Y��q�����,� ���� d��y��O�tp$PĽg��w}��}�r֯[7�u�"w���|o�7/Z��ˋ^Z������Ң�ZTZ\S|N����c�X8��c�X8��c�X8��c�X8��c�X8���۲,��a�oA*=ە���do:��|ˉ'rb�|�L2�*^�:q}/��\�s�Z?��G�[��=ϗ?
I have also placed the below code before the headers function :
if (headers_sent())
{
// HTTP header has already been sent
return false;
}
// clean buffer(s)
while (ob_get_level() > 0)
{
ob_end_clean();
}
This ignore to display those character and zip is also not force to download. I couldn't figure out the problem, please help me, it will be greatly appreciated.
PK[�FA����#�X$D:\voice_06101243342pm014771957.wav�|
�s]�y���b�CI\��{2m��M'�Eibu2\#B��܋{� 6b#
$H,\#��:��Z�(q�����ә���Y��q�����,� ���� d��y��O�tp$PĽg��w}��}
�r֯[7�u�"w���|o�7/Z��ˋ^Z������Ң�ZTZ\S|N����c�X8��c�X8��c�X8��c�X8��c�X8���۲,��a�oA*
=ە���do:��|ˉ'rb�|�L2�*^�:q}/��\�s�Z?��G�[��=ϗ?
This is your zip file.
You are a receiving a zip file and there's nothing wrong, you just need to correct your php processing script because apparently it is processing it as plain text/string.
Note the PK at the start, zip files start with 'PK` data. Test yourself by opening any zip file with a hex editor.
Try to add this to your header:
header('Content-Description: File Transfer');
Here is the simple function I use to download files:
function _download ($file_name) {
$src = fopen($this->download_path . $file_name,'r') or die("\n\n ========= Could not download $file_name\n");
$dest = fopen($file_name,'w');
stream_copy_to_stream($src, $dest);
}
I am trying to download a 2 files by creating the zip file on local-server.the file is downloaded in zip format but when i try to extract it.it gives error:
End-of-central-directory signature not found. Either this file is not
a zip file, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zip file comment will be found on
the last disk(s) of this archive.
the following code i am using for this:
<?php
$file_names = array('iMUST Operating Manual V1.3a.pdf','iMUST Product Information Sheet.pdf');
//Archive name
$archive_file_name=$name.'iMUST_Products.zip';
//Download Files path
$file_path=$_SERVER['DOCUMENT_ROOT'].'/Harshal/files/';
zipFilesAndDownload($file_names,$archive_file_name,$file_path);
function zipFilesAndDownload($file_names,$archive_file_name,$file_path)
{
//echo $file_path;die;
$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);
//echo $file_path.$files,$files."
}
$zip->close();
//then send the headers to force 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;
}
?>
i checked the values of all variables which are passing into the function,all are fine.so please look this.Thanks in advance.
Add Content-length header describing size of zip file in bytes.
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$archive_file_name");
header("Content-length: " . filesize($archive_file_name));
header("Pragma: no-cache");
header("Expires: 0");
readfile("$archive_file_name");
Also make sure that there is absolutely no white space before <? and after ?>. I see a space here:
↓
<?php
$file_names = array('iMUST Operating Manual V1.3a.pdf','iMUST Product Information Sheet.pdf');
$zip = new ZipArchive;
$tmp_file = 'assets/myzip.zip';
if ($zip->open($tmp_file, ZipArchive::CREATE)) {
$zip->addFile('folder/bootstrap.js', 'bootstrap.js');
$zip->addFile('folder/bootstrap.min.js', 'bootstrap.min.js');
$zip->close();
echo 'Archive created!';
header('Content-disposition: attachment; filename=files.zip');
header('Content-type: application/zip');
readfile($tmp_file);
} else {
echo 'Failed!';
}
// http headers for zip downloads
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filepath.$filename));
ob_end_flush();
#readfile($filepath.$filename);
I found this soludtion here and it work for me
One of the error could be that the file is not read as 'archive' format. check out ZipArchive not opening file - Error Code: 19. Open the downloaded file in text editor, if you have any html tags or debug statements at the starting, clear the buffer before reading the file.
ob_clean();
flush();
readfile("$archive_file_name");
I just ran into this problem. For me the issue was with:
readfile("$archive_file_name");
It was resulting in a out of memory error.
Allowed memory size of 134217728 bytes exhausted (tried to allocate 292982784 bytes)
I was able to correct the problem by replacing readfile() with the following:
$handle = fopen($zipPath, "rb");
while (!feof($handle)){
echo fread($handle, 8192);
}
fclose($handle);
Not sure if this is your same issue or not seeing that your file is only 1.2 MB. Maybe this will help someone else with a similar problem.
I have experienced exactly the same problem. In my case, the source of it was the permissions of the folder in which I wanted to create the zip file that were all set to read only. I changed it to read and write and it worked.
If the file is not created on your local-server when you run the script, you most probably have the same problem as I did.
but the file i am getting from server after download it gives the size
of 226 bytes
This is the size of a ZIP header. Apparently there is no data in the downloaded ZIP file. So, can you verify that the files to be added into the ZIP file are, indeed, there (relative to the path of the download PHP script)?
Consider adding a check on addFile too:
foreach($file_names as $file)
{
$inputFile = $file_path . $file;
if (!file_exists($inputFile))
trigger_error("The input file $inputFile does not exist", E_USER_ERROR);
if (!is_readable($inputFile))
trigger_error("The input file $inputFile exists, but has wrong permissions or ownership", E_USER_ERROR);
if (!$zip->addFile($inputFile, $file))
trigger_error("Could not add $inputFile to ZIP file", E_USER_ERROR);
}
The observed behaviour is consistent with some problem (path error, permission problems, ...) preventing the files from being added to the ZIP file. On receiving an "empty" ZIP file, the client issues an error referring to the ZIP central directory missing (the actual error being that there is no directory, and no files).
Make sure that the path inside $archive_file_name is correct and does exist. In your code, you updated the $archive_file_name variable by putting an undeclared prefix variable - $name.
$archive_file_name = $name.'iMUST_Products.zip';
If the path is not correct and cannot be found, the created zipped file have nowhere to go to and the two files have nowhere to store to to begin with. The path to the files to be stored should also exist.
Let's assume that you just want to customize the name of the zipped folder to be downloaded that is why there is a $name variable to prevent redundant file name. But you have to consider the URI where you run your script.
For example, you're using URI routing, and you load the script at https://sample.co/file-management/download-zipped-111. With your current script, the zipped folder will be stored at file-management folder. If it does not exist, you will mostly encounter the error you are experiencing right now.
The solution is to explicitly declare the path to the folder where the zipped file will be stored.
For example, you want to store the zipped file at Harshal/files/zipped/. Make sure that this folder exist by creating a folder named zipped inside files folder and that you have access to write on this folder.
$file_names = array('iMUST Operating Manual V1.3a.pdf', 'iMUST Product Information Sheet.pdf');
// $name should be declared before this line
$archive_file_name = $name.'iMUST_Products.zip';
//Download Files path
$file_path = $_SERVER['DOCUMENT_ROOT'].'/Harshal/files/';
zipFilesAndDownload($file_names, $archive_file_name, $file_path);
function zipFilesAndDownload($file_names, $archive_file_name, $file_path)
{
$zip = new ZipArchive();
// WE REUSED THE $file_path VARIABLE HERE THEN ADDED zipped FOLDER
if ($zip->open($file_path.'zipped/'.$archive_file_name, ZIPARCHIVE::CREATE )!==TRUE) {
exit('cannot open <'.$archive_file_name.'>');
}
//add each files of $file_name array to archive
foreach($file_names as $files)
{
$zip->addFile($file_path.$files, $files);
}
$zip->close();
//then send the headers to force download the zip file
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$archive_file_name");
header('Content-length: '.filesize($file_path.'zipped/'.$archive_file_name));
header("Pragma: no-cache");
header("Expires: 0");
readfile("$archive_file_name");
exit;
}
People may suggest - "Why not directly put the full path to the $archive_file_name variable?
$archive_file_name = $file_path.'zipped/'.$name.'iMUST_Products.zip';
If we put it directly to $archive_file_name variable, the file that will be downloaded will mostly likely be named /var/www/Harshal/files/zipped/xxx-iMUST_Products.zip.
This question already has an answer here:
Closed 12 years ago.
Possible Duplicate:
Open file, write to file, save file as a zip and stream to user for download
I have a txt file in uploads folder where i need to add this file and create a ZIP on fly and prompt the user to download the Zip file which should contain the text file .How do i do this and moreover what are the headers needed for prompting the user for download .can any one Help me out. I have used the same constucts from PHP Manual.Iam Using the same function to zip the file "http://davidwalsh.name/create-zip-php" and iam writing this code and iam getting prompted for zip download but iam getting the caution message when i extarct the file
$zip_file = "my-archive.zip";
$file_path="../../../downloads/";
$files_to_zip = array($file_path."test_testing.txt");
$result = create_zip($files_to_zip,'my-archive.zip');
header('Content-Description: File Transfer');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=".$zip_file);
header("Pragma: no-cache");
header("Expires: 0");
readfile($zip_file);
The Caution error message is "one or more files in this archive uses ".."(parent folder) as part of its folder information "
In the create_zip() function,
change
foreach($valid_files as $file) {
$zip->addFile($file,$file);
}
to
foreach($valid_files as $file) {
$zip->addFile($file,pathinfo($file,PATHINFO_BASENAME));
}
This will work as long as you don't have files with duplicate names but different directories in your array of files