Backend Development 7 min read

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.

Laravel Tech Community
Laravel Tech Community
Laravel Tech Community
Implementing ZIP Packaging and Large File Download in PHP

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.

backendPHPfile downloadfile handlingzipZipArchive
Laravel Tech Community
Written by

Laravel Tech Community

Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.