Current Location: Home> Latest Articles> How to Efficiently Use the zip_read() Function to Handle ZIP Archives with Multi-level Nested Directories?

How to Efficiently Use the zip_read() Function to Handle ZIP Archives with Multi-level Nested Directories?

M66 2025-06-15

Handling ZIP files in PHP is a common task, especially when you need to extract contents or read the file structure from an archive. The zip_read() function offers an alternative to the ZipArchive class for processing ZIP files. It is often used alongside functions like zip_open() and zip_entry_read(). Although these functions operate at a lower level, they remain valuable for developers who want deeper control over ZIP file structures, particularly when dealing with ZIP files containing multiple levels of nested directories.

Basic Usage

First, you need to open the ZIP file with zip_open() and iterate through each entry using zip_read(). The basic structure looks like this:

$zip = zip_open("nested_directories.zip");
<p>if (is_resource($zip)) {<br>
while ($entry = zip_read($zip)) {<br>
$entryName = zip_entry_name($entry);<br>
echo "Entry: $entryName\n";<br>
}<br>
zip_close($zip);<br>
}<br>

This code snippet lists all entries within the ZIP file (including both directories and files), but simply listing them is not enough; we need to delve deeper into handling nested structures.

Recognizing Nested Directory Structures

Nested directories in ZIP files do not possess a “tree-like” structure as real file systems do. Each directory or file is represented as a path string, for example:

photos/
photos/vacation/
photos/vacation/beach.jpg
documents/report.docx

Therefore, we determine the depth of a file path by counting the number of / characters. Using a simple explode() function, we can analyze each layer:

$depth = substr_count($entryName, '/');

This is especially useful when you want to perform specific operations based on directory levels.

Extracting Files While Preserving Directory Structure

To extract contents from a ZIP file into a target directory while preserving the directory hierarchy, you can combine zip_entry_read() with file_put_contents() as shown below:

$zip = zip_open("nested_directories.zip");
<p>$extractPath = "extracted/";</p>
<p>if (is_resource($zip)) {<br>
while ($entry = zip_read($zip)) {<br>
if (zip_entry_open($zip, $entry, "r")) {<br>
$entryName = zip_entry_name($entry);<br>
$fullPath = $extractPath . $entryName;</p>
        if (substr($entryName, -1) === '/') {
            if (!is_dir($fullPath)) {
                mkdir($fullPath, 0755, true);
            }
        } else {
            // If it's a file, make sure the parent directory exists
            $dir = dirname($fullPath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }

            $content = zip_entry_read($entry, zip_entry_filesize($entry));
            file_put_contents($fullPath, $content);
        }

        zip_entry_close($entry);
    }
}
zip_close($zip);

}

The above code fully implements nested extraction, handling directory creation and file writing while preserving the original structure.

Practical Application Example

Imagine you have developed a website (such as https://m66.net/upload) that offers ZIP upload functionality. Users might upload ZIP files with complex multi-level nested directories. To safely unzip these files into a temporary directory for further processing, you can first extract the contents using the above code, then iterate through the target folder to handle files.

To prevent path traversal vulnerabilities (e.g., a malicious ZIP containing ../../etc/passwd), you should perform security checks after constructing paths:

$realBase = realpath($extractPath);
$realUserPath = realpath($fullPath);
<p>if (strpos($realUserPath, $realBase) !== 0) {<br>
// Illegal path, skip<br>
continue;<br>
}<br>

Performance Optimization Tips

  1. Avoid unnecessary file reads: Process only required directories or files with specific extensions.

  2. Load on demand: For large files, avoid loading the entire content at once with zip_entry_read($entry, zip_entry_filesize($entry)). Instead, use streaming reads.

  3. Batch operations: If final steps involve databases or external services, consider buffering results and submitting them in batches.

Conclusion

Although using zip_read() to handle ZIP files is less intuitive than the ZipArchive class, it remains highly practical in scenarios requiring fine-grained control over structure. By analyzing path strings, we can efficiently manage multi-level nested directories and safely extract contents to server paths. Coupled with appropriate security and performance measures, this method is a powerful tool for building complex ZIP file handling logic.