Allow to download directories as zip files

The feature adds a button to download all files in current directory as zip archive.
For this function to work it is required to have 'zip' utility available on the server.
To enable this function set the 'zip_dirs' option to 'true' in configuration file (it is disabled by default).

By default the zip is created 'on-the-fly' and streamed to client, without any temporary file. This behaviour can be changed by setting 'zip_stream' configuration option to false.

It is also possible to choose compression level for zip files - see 'zip_compression_level' configuration option. The default value is zero for perfomance reasons.
The 'zip_disable' option allows to disable zip downloading for particular set of directories. It is works much the same as 'hidden_files' option.

TODO: When zip is created the script tries to exclude files with respect to 'hidden files' option. But it doesn't do it very well - for example, if 'hidden_files' have 'resources/*' entry, then it will exclude the contents of 'resources' directory on any subdirectory, not just at the root level.
This commit is contained in:
Konstantin Dmitriev
2015-08-14 21:58:13 +06:00
parent bab26baa45
commit 63788345a8
4 changed files with 111 additions and 1 deletions

View File

@@ -20,6 +20,12 @@
die($data);
}
if (isset($_GET['zip'])) {
$dirArray = $lister->zipDirectory($_GET['zip']);
} else {
// Initialize the directory array
if (isset($_GET['dir'])) {
@@ -42,3 +48,5 @@
} else {
die('ERROR: Failed to initialize theme');
}
}

View File

@@ -61,6 +61,81 @@ class DirectoryLister {
$this->_themeName = $this->_config['theme_name'];
}
/**
* If it is allowed to zip whole directories
*
* @param string $directory Relative path of directory to list
* @return true or false
* @access public
*/
public function isZipEnabled() {
foreach ($this->_config['zip_disable'] as $disabledPath) {
if (fnmatch($disabledPath, $this->_directory)) {
return false;
}
}
return $this->_config['zip_dirs'];
}
/**
* Creates zipfile of directory
*
* @param string $directory Relative path of directory to list
* @access public
*/
public function zipDirectory($directory) {
if ($this->_config['zip_dirs'])
{
// Cleanup directory path
$directory = $this->setDirectoryPath($directory);
if ($directory != '.' && $this->_isHidden($directory)){
echo "Access denied.";
}
$filename_no_ext = basename("$directory");
if ( $directory == '.' )
{
$filename_no_ext = "Home";
}
// We deliver a zip file
header("Content-Type: archive/zip");
// Filename for the browser to save the zip file
header("Content-Disposition: attachment; filename=\"$filename_no_ext".".zip\"");
//change directory so the zip file doesnt have a tree structure in it.
chdir($directory);
// TODO: Probably we have to parse exclude list more carefully
$exclude_list = implode(" ", array_merge($this->_config['hidden_files'],array('index.php')));
$exclude_list = str_replace("*", "\*", $exclude_list);
if ($this->_config['zip_stream'])
{
// zip the stuff (dir and all in there) into the streamed zip file
$stream = popen( "/usr/bin/zip -".$this->_config['zip_compression_level']." -r -q - * -x ".$exclude_list, "r" );
if( $stream )
{
fpassthru( $stream );
fclose( $stream );
}
} else {
// zip the stuff (dir and all in there) into the tmp_zip file
exec('zip -'.$this->_config['zip_compression_level'].' -r '.$tmp_zip.' * -x '.$exclude_list);
// get a tmp name for the .zip
$tmp_zip = tempnam ("tmp", "tempzip") . ".zip";
// calc the length of the zip. it is needed for the progress bar of the browser
$filesize = filesize($tmp_zip);
header("Content-Length: $filesize");
// deliver the zip file
$fp = fopen("$tmp_zip","r");
echo fpassthru($fp);
// clean up the tmp zip file
unlink($tmp_zip);
}
}
}
/**
@@ -341,6 +416,17 @@ class DirectoryLister {
return $this->_directory;
}
/**
* Get directory path variable
*
* @return string Sanitizd path to directory
* @access public
*/
public function getDirectoryPath() {
return $this->_directory;
}
/**

View File

@@ -34,6 +34,17 @@ return array(
// Custom sort order
'reverse_sort' => array(
// 'path/to/folder'
)
),
// Allow to download directories as zip files
'zip_dirs' => false,
// Stream zip file content directly to the client, without any temporary file
'zip_stream' => true,
'zip_compression_level' => 0,
// Disable zip downloads for particular directories
'zip_disable' => array(
'.' // - disable for root directory by default
// 'path/to/folder'
),
);

View File

@@ -47,6 +47,11 @@
</p>
<div class="navbar-right">
<?php if ($lister->isZipEnabled()): ?>
<ul id="page-top-download-all" class="nav navbar-nav">
<li><a href="?zip=<?php echo $lister->getDirectoryPath() ?>" id="download-all-link"><i class="fa fa-download fa-lg"></i></a></li>
</ul>
<?php endif; ?>
<ul id="page-top-nav" class="nav navbar-nav">
<li><a href="javascript:void(0)" id="page-top-link"><i class="fa fa-arrow-circle-up fa-lg"></i></a></li>
</ul>