Zip entry read: примеры (PHP)
zip_entry_read(resource zip_entry, int length): string|falseОписание функции zip_entry_read
Функция zip_entry_read() используется для чтения содержимого конкретной записи (файла) внутри открытого ZIP-архива. Она является частью старого, основанного на ресурсах расширения Zip (до PHP 8.0.0) и сейчас считается устаревшей.
- zip_entry (resource) - обязательный. Ресурс записи ZIP, полученный с помощью
zip_read()илиzip_entry_open(). - length (int) - необязательный. Количество байтов для чтения из записи. Если параметр не указан или равен 0, функция пытается прочитать 1024 байта. Фактическое количество прочитанных байтов может быть меньше запрошенного, особенно в конце файла.
Функция возвращает прочитанные данные в виде строки. Возвращается пустая строка ('') при достижении конца файла (EOF). В случае возникновения ошибки возвращается false.
Базовые примеры использования
<?
$zip = zip_open('archive.zip');
if ($zip) {
while ($entry = zip_read($zip)) {
if (zip_entry_open($zip, $entry, 'r')) {
echo 'Чтение: ' . zip_entry_name($entry) . '\n';
$content = '';
while ($data = zip_entry_read($entry, 2048)) {
$content .= $data;
}
echo 'Размер содержимого: ' . strlen($content) . ' байт\n';
zip_entry_close($entry);
}
}
zip_close($zip);
}
?>Чтение: documents/report.txt Размер содержимого: 1256 байт Чтение: images/photo.jpg Размер содержимого: 54321 байт
<?
$zip = zip_open('data.zip');
$entry = zip_read($zip);
zip_entry_open($zip, $entry, 'r');
// Чтение первых 100 байт
$firstChunk = zip_entry_read($entry, 100);
echo 'Первые 100 байт (длина): ' . strlen($firstChunk) . '\n';
// Чтение следующих 500 байт
$secondChunk = zip_entry_read($entry, 500);
echo 'Следующие 500 байт (длина): ' . strlen($secondChunk) . '\n';
zip_entry_close($entry);
zip_close($zip);
?>Первые 100 байт (длина): 100 Следующие 500 байт (длина): 500
Альтернативы в современном PHP
Класс ZipArchive (расширение ext-zip) является объектно-ориентированной и более мощной альтернативой. Он предоставляет методы getFromName() и getFromIndex() для чтения всего содержимого файла целиком, а также возможность работы с потоковым чтением через fopen() и fread() с использованием оберток zip://.
$zip = new ZipArchive;
if ($zip->open('archive.zip') === TRUE) {
$content = $zip->getFromName('file.txt'); // Прочитать весь файл
$stream = $zip->getStream('file.txt'); // Получить поток для чтения
fread($stream, 1024); // Читать из потока
fclose($stream);
$zip->close();
}Позволяют работать с файлами внутри архива как с обычными файлами, используя стандартные функции вроде fopen(), fgets(), stream_get_contents().
$handle = fopen('zip://archive.zip#file.txt', 'r');
$content = stream_get_contents($handle);
fclose($handle);Предпочтения: Для нового кода всегда следует использовать ZipArchive или потоковые обертки. Старые функции на основе ресурсов (zip_open, zip_entry_read) устарели в PHP 8.0.0 и удалены в PHP 8.1.0.
Аналоги в других языках программирования
Класс ZipFile предоставляет метод read() для получения байтового содержимого файла по имени.
import zipfile
with zipfile.ZipFile('archive.zip', 'r') as zf:
content = zf.read('file.txt') # Возвращает bytes
print(content.decode('utf-8'))Сторонний модуль adm-zip позволяет читать содержимое записей.
const AdmZip = require('adm-zip');
const zip = new AdmZip('archive.zip');
const entry = zip.getEntry('file.txt');
const content = entry.getData().toString('utf8');
console.log(content);Утилита командной строки unzip может извлекать конкретный файл в стандартный вывод.
unzip -p archive.zip file.txtОтличия: В отличие от итеративного чтения в zip_entry_read(), аналоги в Python и JS часто читают файл целиком в память. Подход, основанный на потоках, в Node.js (yauzl) более схож с поэтапным чтением.
Типичные ошибки и их решение
<?
$zip = zip_open('archive.zip');
$entry = zip_read($zip);
// Забыли вызвать zip_entry_open
$data = zip_entry_read($entry); // Предупреждение и false
?>Warning: zip_entry_read(): supplied resource is not a valid Zip Entry resource
Решение: Всегда открывать запись с помощью zip_entry_open() перед чтением.
while ($data = zip_entry_read($entry, 1024)) {
// Обработка данных
}
// Цикл завершился, потому что $data стала false или пустой строкой
$extraRead = zip_entry_read($entry, 1024); // false
if ($extraRead === false) {
echo 'Достигнут конец файла или ошибка';
}Решение: Проверять возвращаемое значение. Пустая строка означает EOF, false - ошибку. После EOF дальнейшие вызовы возвращают пустую строку.
// Если файл содержит бинарные данные (например, изображение),
// его нельзя выводить как текст или использовать в строковых операциях
// без специальной обработки (например, кодирования в base64).
$imageData = '';
while ($chunk = zip_entry_read($entry)) {
$imageData .= $chunk;
}
// $imageData содержит бинарную строку
header('Content-Type: image/jpeg');
echo $imageData; // Корректный вывод изображенияИстория изменений функции
- В PHP 8.0.0 все функции модуля Zip, основанные на ресурсах (включая
zip_entry_read), были переведены в разряд устаревших (deprecated). При их использовании генерировалось уведомление об устаревании (E_DEPRECATED). - В PHP 8.1.0 эти устаревшие функции были полностью удалены из ядра языка. Любые попытки их вызова приводят к фатальной ошибке.
Таким образом, в актуальных версиях PHP (8.1 и выше) функция zip_entry_read() не существует. Для работы с ZIP-архивами требуется использование класса ZipArchive.
Расширенные и специфические примеры
Чтение файла построчно, предполагая, что строка помещается в один блок чтения. В реальности это ненадежно для длинных строк.
<?
$zip = zip_open('logs.zip');
if ($zip) {
while ($entry = zip_read($zip)) {
if (zip_entry_open($zip, $entry) && strpos(zip_entry_name($entry), '.log')) {
echo '--- ' . zip_entry_name($entry) . ' ---\n';
$buffer = '';
while (($data = zip_entry_read($entry, 1024)) !== '') {
$buffer .= $data;
$lines = explode("\n", $buffer);
// Обрабатываем все, кроме последней, возможно неполной строки
$buffer = array_pop($lines);
foreach ($lines as $line) {
echo 'Строка: ' . htmlspecialchars($line) . '\n';
}
}
// Вывод последней строки из буфера
if ($buffer !== '') {
echo 'Строка: ' . htmlspecialchars($buffer) . '\n';
}
zip_entry_close($entry);
}
}
zip_close($zip);
}
?><?
function readWithChunkSize($zipName, $chunkSize) {
$start = microtime(true);
$zip = zip_open($zipName);
$entry = zip_read($zip);
zip_entry_open($zip, $entry);
$totalBytes = 0;
while ($data = zip_entry_read($entry, $chunkSize)) {
$totalBytes += strlen($data);
}
zip_entry_close($entry);
zip_close($zip);
$time = microtime(true) - $start;
return ['size' => $chunkSize, 'time' => $time, 'bytes' => $totalBytes];
}
$sizes = [128, 1024, 8192, 65536];
foreach ($sizes as $size) {
$res = readWithChunkSize('largefile.zip', $size);
printf("Блок %6d байт: прочитано %d байт за %.4f сек\n",
$res['size'], $res['bytes'], $res['time']);
}
?>Блок 128 байт: прочитано 1048576 байт за 0.1234 сек Блок 1024 байт: прочитано 1048576 байт за 0.0456 сек Блок 8192 байт: прочитано 1048576 байт за 0.0234 сек Блок 65536 байт: прочитано 1048576 байт за 0.0189 сек
Полезно для отправки больших файлов из архива непосредственно в браузер или другому клиенту без сохранения в памяти.
<?
$zip = zip_open('huge_video.zip');
$entry = zip_read($zip);
zip_entry_open($zip, $entry);
header('Content-Type: video/mp4');
header('Content-Disposition: attachment; filename="video.mp4"');
while ($chunk = zip_entry_read($entry, 65536)) {
echo $chunk;
flush(); // Сброс буфера вывода
if (ob_get_level()) ob_flush();
}
zip_entry_close($entry);
zip_close($zip);
?>Чтение ZIP-файла, который находится внутри другого ZIP-архива, и обработка его содержимого без извлечения на диск.
<?
// Открываем внешний архив
$outerZip = zip_open('nested.zip');
$outerEntry = zip_read($outerZip);
zip_entry_open($outerZip, $outerEntry);
// Читаем весь вложенный архив в строку
$innerZipData = '';
while ($data = zip_entry_read($outerEntry)) {
$innerZipData .= $data;
}
zip_entry_close($outerEntry);
zip_close($outerZip);
// Сохраняем данные вложенного архива во временный файл
$tempFile = tempnam(sys_get_temp_dir(), 'inner');
file_put_contents($tempFile, $innerZipData);
// Открываем вложенный архив как новый
$innerZip = zip_open($tempFile);
// ... работа с содержимым $innerZip ...
zip_close($innerZip);
unlink($tempFile);
?>