Home » Php » php – How to read a single file inside a zip archive

php – How to read a single file inside a zip archive

Posted by: admin April 23, 2020 Leave a comment

Questions:

I need to read the content of a single file, “test.txt”, inside of a zip file. The whole zip file is a very large file (2gb) and contains a lot of files (10,000,000), and as such extracting the whole thing is not a viable solution for me. How can I read a single file?

How to&Answers:

Try using the zip:// wrapper:

$handle = fopen('zip://test.zip#test.txt', 'r'); 
$result = '';
while (!feof($handle)) {
  $result .= fread($handle, 8192);
}
fclose($handle);
echo $result;

You can use file_get_contents too:

$result = file_get_contents('zip://test.zip#test.txt'); 
echo $result;

Answer:

Please note @Rocket-Hazmat fopen solution may cause an infinite loop if a zip file is protected with a password, since fopen will fail and feof will always be true if an error occurs.

You may want to change it to

$handle = fopen('zip://file.zip#file.txt', 'r');
$result = '';
if ($handle) {
    while (!feof($handle)) {
        $result .= fread($handle, 8192);
    }
    fclose($handle);
}
echo $result;

This solves the infinite loop issue, but if your zip file is protected with a password then you may see something like

Warning: file_get_contents(zip://file.zip#file.txt): failed to open
stream: operation failed

There’s a solution however

As of PHP 7.2 support for encrypted archives was added.

So you can do it this way for both file_get_contents and fopen

$options = [
    'zip' => [
        'password' => '1234'
    ]
];

$context = stream_context_create($options);
echo file_get_contents('zip://file.zip#file.txt', false, $context);

A better solution however to check if a file exists or not before reading it without worrying about encrypted archives is using ZipArchive

$zip = new ZipArchive;
if ($zip->open('file.zip') !== TRUE) {
    exit('failed');
}
if ($zip->locateName('file.txt') !== false) {
    echo 'File exists';
} else {
    echo 'File does not exist';
}

This will work (no need to know the password)

Note: To locate a folder using locateName method you need to pass it like folder/ with a
forward slash at the end.