Preparing a custom made download - php

I would like to create a form that will allow for custom download assembling, just like the one on jQuery UI download page. The user selects the components s/he needs and a custom download is assembled, (g)zipped and sent out. How does this work? How do I write something similar?
Optionally: since I'd like to implement this on a Drupal 7 site, suggestions for helpful modules are also welcome.

jnpcl's answer works. However, if you want to download the file without requiring a redirect, just do the following:
// Once you created your zip file as say $zipFile, you can output it directly
// like the following
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename='.basename($zipFile));
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($zipFile));
ob_clean();
flush();
readfile($zipFile);
http://php.net/manual/en/function.readfile.php

Simple implementation:
<?php
// base directory containing files that we're adding
$dir = 'images/';
// name of our zip file. best to use a unique name here
$zipfile = "test.zip";
// get a directory listing, remove self/parent directories, and reindex array
$files = array_values(array_diff(scandir($dir), array('.', '..')));
// form has been submitted
if (isset($_POST['submit'])) {
// initialize the zip file
$output = new ZipArchive();
$output->open($zipfile, ZIPARCHIVE::CREATE);
// add files to archive
foreach ($_POST['file'] as $num=>$file) {
// make sure the files are valid
if (is_file($dir . $file) && is_readable($dir . $file)) {
// add it to our zip file
$output->addFile($dir . $file);
}
}
// write zip file to filesystem
$output->close();
// direct user's browser to the zip file
header("Location: " . $zipfile);
exit();
} else {
// display filenames with checkboxes
echo '<form method="POST">' . PHP_EOL;
for ($x=0; $x<count($files); $x++) {
echo ' <input type="checkbox" name="file[' . $x . ']" value="' . $files[$x] . '">' . $files[$x] . '<br>' . PHP_EOL;
}
echo ' <input type="submit" name="submit" value="Submit">' . PHP_EOL;
echo '</form>' . PHP_EOL;
}
?>
Known bug: Doesn't check if $zipfile exists beforehand. If it does, it will be appended to.

i dont know anything about that drupal but probably is some help editor for php or similar... however this may help you... PHP ZIP
never used it but it dont seams hard!
hope it helps

Related

Downloading a CSV from tmp folder of PHP project

I currently am working on a PHP project that uses the Zend Framework. I am making a CSV without any issues in the controller, but then want the user to be able to download the file by clicking a button in the view.
In my .phtml I have:
<a class="btn" href="<?php echo $this->download;?>" download>Export to CSV</a>
$this->download is being set in the controller:
$view["download"] = $this->_createCSV($bqc_jobs, $startDate, $endDate, $processor_id, $defaultTime);
The _createCSV function creates the CSV and stores it in the temporary directory that the site uses. It then returns the filepath.
private function _createCSV($jobs, $start, $end, $user=null, $minutes){
$format = "Ymd_His";
if(!$start && !$user){
$start = date($format, strtoTime("-" . $minutes . " minutes"));
}
if(!$end){
$end = \DateTime::createFromFormat($format, date($format))->format($format);
}
$directory = Config::$tempDir;
$fileName = $directory . "/" . ($user ? $user . "_" : "") . ($start ? $start . "_" : "") . $end . "_report.csv";
$file = fopen($fileName, 'w');
foreach ($jobs as $job){
fputcsv($file, $job);
}
fclose($file);
return $fileName;
}
When the button is clicked, the browser tries to download the file, but errors because it cannot find the file. This makes sense, since the browser should not have access to the temporary folder, but I'm not entirely sure how to get around this.
If you are unable to see the folder due to the UNIX file permissions, then your only options will be to:
Change the file permissions on the tmp folder so that your web server can read/write there using chmod/chown (I assume it is a linux system?)
Use a different folder with sufficient permissions
Don't store the file on disk - store it in a database instead (not optimal).
Once you are sure your file permissions are in order and that the file can be read by apache, it appears that you should be able to use php's readfile function to actually transmit the file back to the browser:
<?php
$file = '/tmp/monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>

PHP Create ZIP file in background

I am using the following script to create zip files: http://davidwalsh.name/create-zip-php
It's working just fine and does exactly what I need. Sometimes though I have large files and zipping those takes up to 30 seconds.
I want to let the user know that their download is being packed and tell them whenever the download is ready.
How would I do that? I have a script which is called download.php which basically just calls this create_zip method from above and then forces a download like this:
$files = explode(":", $file_decrypted);
array_pop($files);
$zipname = 'uploads/download_' . $username . '.zip';
foreach ($files as &$value) {
$value = "uploads/" . $username_d . "/" . $value;
}
$resultat = create_zip($files, $zipname, 'uploads/' . $username . '/');
ob_clean();
ob_end_flush();
// Start the download for the user
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $zipname);
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
exit();
So basically I want to show a text to the user (For example: Preparing download...) and at the same time call all the above php stuff in the background somehow.

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

Need help getting this auto-download header to show the right path

I have a page with mp3s that are playable from a player, and there are also links to download the songs. When the user clicks on the download link, it needs to open the download dialog instead of opening a media player, so it was recommended to me to use this header script:
includes/auto-download.php:
<?php
$path = $_GET['path'];
header('Content-Disposition: attachment; filename=' . basename($path));
readfile($path);
?>
And then on my main page, the link looks like this:
Song Name
I seem to be doing something wrong with my paths, as when I click the link, the download box opens, and I can download a file with the correct name, but it doesn't contain any information.
To elaborate on my file structure, I've got this:
/Patrons (where my main index.php page is with my link
/Patrons/includes (where my auto-download.php script is)
/Patrons/Media/Audio/Date/ (this is where all the songs are)
Any help would be greatly appreciated!
Either change HTML code to this:
Song Name
OR change PHP code to this:
readfile('../'.$path);
$path needs to be the relative path to the file from the web root. with no leading slash. If the files are outside the web root you should use a fullpath (/home/webuser/song_files/song.mp3).
For example $path = 'song_files/'. $_GET['name_of_the_file'];
You should also check if the file does not exist and exit with an error.
Here is an example I made in codeigniter.
function _begin_download($document_data) {
basepath = 'uploads/';
$filepath = basepath . $document_data->filename;
if (file_exists($filepath)) {
header("Content-type: " . $document_data->mimetype);
header("Content-length: " . filesize($filepath));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-disposition: attachment; filename="' . $document_data->filename . '"');
readfile($filepath);
exit();
} else {
exit('File not found.');
}
}

How do I put a download button on a site to get a CSV of a table Query?

How do I put a download button on a site to get a CSV of a table Query?
Currently I am using SELECT * INTO OUTFILE to make the CSV file on the server HD and is fine except...
I want to create the CSV like I am now, but I want the "OUTFILE" to be saved on the clients computer when they click Download.
<?php
// Create new file name for file to be created
$csvfilename = "/dropbox/consolodated-" . date("Y-M-d_H-i-s") . ".csv";
mysql_query ("SELECT * INTO OUTFILE '$csvfilename' FIELDS TERMINATED BY ',' FROM people ");
?>
<H2>Done - File created - Now download it from FTP site.</H2>
The solution to this can be that:
First you save the csv file on to server.
then get it's path
and finally create an anchor tag with its path for download eg:
_
Download
Here are a couple of similar posts:
Generating CSV file and then forcing the file to download.
PHP code to convert a MySQL query to CSV
Add a POST form at the end which includes a hidden field containing the filename (but NOT the path!) of the file to download. Then have the page it POSTs to read the variable and offer the file for download. Don't forget to enable output buffering and to occasionally flush so that the form is not visible until the query has completed.
Simple, here is a sample snippet:
$csv_filename = "/dropbox/consolodated-" . date("Y-M-d_H-i-s") . ".csv";
Download($csv_filename);
And here is the download function:
function Download($path, $speed = null)
{
if (is_file($path) === true)
{
set_time_limit(0);
while (ob_get_level() > 0)
{
ob_end_clean();
}
$size = sprintf('%u', filesize($path));
$speed = (is_null($speed) === true) ? $size : intval($speed) * 1024;
header('Expires: 0');
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . $size);
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
for ($i = 0; $i <= $size; $i = $i + $speed)
{
echo file_get_contents($path, false, null, $i, $speed);
flush();
sleep(1);
}
exit();
}
return false;
}
Merry Xmas to you too! =)

Categories