diff --git a/index.php b/index.php index 7ef14e9..a954d92 100644 --- a/index.php +++ b/index.php @@ -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'); } + + } diff --git a/resources/DirectoryLister.php b/resources/DirectoryLister.php index 9667e68..2200f2b 100644 --- a/resources/DirectoryLister.php +++ b/resources/DirectoryLister.php @@ -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; + + } /** diff --git a/resources/default.config.php b/resources/default.config.php index 7ceb32e..b6240cf 100644 --- a/resources/default.config.php +++ b/resources/default.config.php @@ -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' + ), ); diff --git a/resources/themes/bootstrap/index.php b/resources/themes/bootstrap/index.php index 5285569..d7df61e 100644 --- a/resources/themes/bootstrap/index.php +++ b/resources/themes/bootstrap/index.php @@ -47,6 +47,11 @@