If your server allows execution of shell commands from PHP, and zip
is installed, you could generate a zip on the fly with passthru( "zip - directory" )
. The -
says to write to stdout, which saves you from having to deal with temporary file cleanup.
Here's an outline of such a script:
<?php
if ( ! $dir = get_my_directory() )
die("Illegal call.");
header( 'Content-Type: application/zip' );
header( 'Content-Disposition: attachment; filename=\"your.zip\"' );
passthru( 'zip -r - ' . escapeshellarg( $dir ) );
/**
* @return false/null or the directory to zip.
*/
function get_my_directory() {
....
return ....;
}
However you implement get_my_directory()
, make sure that it isn't possible for anyone to specify any path on your server!
Also, do not generate any output (no echo
/print
or warnings), because then either the headers won't be set, or the zip binary data will be corrupt.
Other than that, there are code samples and documentation on PHP's ZipArchive page.
UPDATE
(@ OP: I'm not really sure what you're doing implementing PHP solutions if you don't know any PHP. But, let's assume that you want to learn. )
Lets say that you have 3 public directories you would like to offer for download, and that anyone can download them. You would implement as follows:
function get_my_directory() {
// list of the directories you want anyone to be able to download.
// These are key-value pairs, so we can use the key in our URLs
// without revealing the real directories.
$my_directories = array(
'dir1' => 'path/to/dir1/',
'dir2' => 'path/to/dir2/',
'dir3' => 'path/to/dir3/'
);
// check if the 'directory' HTTP GET parameter is given:
if ( ! isset( $_GET['directory'] ) )
return null; // it's not set: return nothing
else
$dir = $_GET['directory']; // it's set: save it so we don't have
// to type $_GET['directory'] all the time.
// validate the directory: only pre-approved directories can be downloaded
if ( ! in_array( $dir, array_keys( $my_directories ) ) )
return null; // we don't know about this directory
else
return $my_directories[ $dir ]; // the directory: is 'safe'.
}
And yes, you paste the first and second code sample in one .php file (be sure to replace the first get_my_directory
function with the second one), somewhere on your server where it is accessible.
If you call the file 'download-archive.php', and place it in the DocumentRoot,
you would access it as http://your-site/download-archive.php?directory=dir1
etc.
Here are some references:
Update 2
Here's a complete script using ZipArchive. It only adds files in the directory; no subdirectories.
<?php
if ( ! $dir = get_my_directory() )
die("Illegal call.");
$zipfile = make_zip( $dir );
register_shutdown_function( function() use ($zipfile) {
unlink( $zipfile ); // delete the temporary zip file
} );
header( "Content-Type: application/zip" );
header( "Content-Disposition: attachment; filename=\"$zipfile\"" );
readfile( $zipfile );
function make_zip( $dir )
{
$zip = new ZipArchive();
$zipname = 'tmp_'.basename( $dir ).'.zip'; // construct filename
if ($zip->open($zipname, ZIPARCHIVE::CREATE) !== true)
die("Could not create archive");
// open directory and add files in the directory
if ( !( $handle = opendir( $dir ) ) )
die("Could not open directory");
$dir = rtrim( $dir, '/' ); // strip trailing /
while ($filename = readdir($handle))
if ( is_file( $f = "$dir/$filename" ) )
if ( ! $zip->addFile( $f, $filename ) )
die("Error adding file $f to zip as $filename");
closedir($handle);
$zip->close();
return $zipname;
}
/**
* @return false/null or the directory to zip.
*/
function get_my_directory() {
// list of the directories you want anyone to be able to download.
// These are key-value pairs, so we can use the key in our URLs
// without revealing the real directories.
$my_directories = array(
'dir1' => 'path/to/dir1/',
'dir2' => 'path/to/dir2/',
'dir3' => 'path/to/dir3/'
);
// check if the 'directory' HTTP GET parameter is given:
if ( ! isset( $_GET['directory'] ) )
return null; // it's not set: return nothing
else
$dir = $_GET['directory']; // it's set: save it so we don't have
// to type $_GET['directory'] all the time.
// validate the directory: only pre-approved directories can be downloaded
if ( ! in_array( $dir, array_keys( $my_directories ) ) )
return null; // we don't know about this directory
else
return $my_directories[ $dir ]; // the directory: is 'safe'.
}