Implementing ZIP Packaging and Large File Download in PHP
This article demonstrates how to use PHP's ZipArchive class to create ZIP packages, stream large files for download, and encapsulate these operations within a reusable class, providing complete code examples and detailed explanations for backend developers.
This guide shows three PHP implementations related to file compression and download.
1. PHP ZIP Packaging and Download
The script creates an empty ZIP file, adds images to it, and streams the ZIP to the browser with appropriate headers, finally deleting the temporary file.
// Ensure an empty zip exists
$file_template = FCPATH.'canddata/cand_picture.zip';
$downname = $card.'.zip';
$file_name = FCPATH.'canddata/'.$card.'.zip';
$result = copy($file_template, $file_name);
$zip = new ZipArchive();
if ($zip->open($file_name, ZipArchive::CREATE) === TRUE) {
$zip->addEmptyDir($card);
$i = 1;
foreach ($cand_photo as $key3 => $value3) {
$file_ext = explode('.', $value3['cand_face']);
$zip->addFromString($card.'/'.$card.'_'.$i.'.'.$file_ext[3], file_get_contents($value3['cand_face']));
$i++;
}
$zip->close();
$fp = fopen($file_name, "r");
$file_size = filesize($file_name);
Header("Content-type: application/octet-stream");
Header("Accept-Ranges: bytes");
Header("Accept-Length:".$file_size);
Header("Content-Disposition: attachment; filename=$downname");
$buffer = 1024;
$file_count = 0;
while (!feof($fp) && $file_count < $file_size) {
$file_con = fread($fp, $buffer);
$file_count += $buffer;
echo $file_con;
}
fclose($fp);
if ($file_count >= $file_size) {
unlink($file_name);
}
}2. PHP Large File Download
This function streams very large files (even several gigabytes) by reading and outputting fixed-size buffers, setting unlimited execution time, and sending proper HTTP headers.
function downloadFile($filename) {
$allowDownExt = array('rar','zip','png','txt','mp4','html');
$fileext = pathinfo($filename);
if (!in_array($fileext['extension'], $allowDownExt)) {
return false;
}
set_time_limit(0);
ini_set('max_execution_time', '0');
header('content-type:application/octet-stream');
header('Accept-Ranges:bytes');
$header_array = get_headers($filename, true);
$filesize = $header_array['Content-Length'];
header('Accept-Length:'.$filesize);
header('content-disposition:attachment;filename='.basename($filename));
$read_buffer = 4096;
$handle = fopen($filename, 'rb');
$sum_buffer = 0;
while (!feof($handle) && $sum_buffer < $filesize) {
echo fread($handle, $read_buffer);
$sum_buffer += $read_buffer;
}
fclose($handle);
exit;
}3. PHP ZipArchive Wrapper Class for Packaging and Download
The zip_down class encapsulates ZIP creation, file addition, and download logic, providing methods to add files, delete temporary directories, and clean up after the download.
<?php
class zip_down {
protected $file_path;
/**
* Constructor
* @param string $path Path to the directory to be zipped
*/
public function __construct($path) {
$this->file_path = $path;
}
/**
* Entry point for creating and downloading the ZIP
*/
public function index() {
$zip = new ZipArchive();
$end_dir = $this->file_path . date('Ymd', time()) . '.zip';
$dir = $this->file_path;
if (!is_dir($dir)) {
mkdir($dir);
}
if ($zip->open($end_dir, ZipArchive::OVERWRITE) === TRUE) {
$this->addFileToZip($dir, $zip);
$zip->close();
}
if (!file_exists($end_dir)) {
exit("Unable to find file");
}
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/zip");
header('Content-disposition: attachment; filename=' . basename($end_dir));
header("Content-Transfer-Encoding: binary");
header('Content-Length:' . filesize($end_dir));
@readfile($end_dir);
$this->delDirAndFile($dir, true);
unlink($end_dir);
}
/**
* Recursively add files to the ZIP archive
*/
protected function addFileToZip($path, $zip) {
$handler = opendir($path);
while (($filename = readdir($handler)) !== false) {
if ($filename != "." && $filename != "..") {
if (!is_dir($filename)) {
$zip->addFile($path . "/" . $filename, $filename);
}
}
}
@closedir($path);
}
/**
* Delete files and optionally directories
*/
protected function delDirAndFile($path, $delDir = true) {
$handle = opendir($path);
if ($handle) {
while (false !== ($item = readdir($handle))) {
if ($item != "." && $item != "..") {
if (is_dir($path . '/' . $item)) {
$this->delDirAndFile($path . '/' . $item, $delDir);
} else {
unlink($path . '/' . $item);
}
}
}
@closedir($handle);
if ($delDir) {
return rmdir($path);
}
} else {
if (file_exists($path)) {
return unlink($path);
} else {
return FALSE;
}
}
}
}
?>The article concludes with a call to action encouraging readers to like and share.
Laravel Tech Community
Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.