ویژگی تصویر

تابع zip_read() در PHP

  /  PHP   /  تابع zip_read() در PHP
بنر تبلیغاتی الف
آموزش PHP

تابع zip_read() یکی از توابع قدیمی و کاربردی PHP برای خواندن محتویات فایل‌های ZIP است. این تابع همراه با zip_open() و zip_entry_*() استفاده می‌شود و برای مرور و خواندن اعضای یک آرشیو ZIP مناسب است. در این مقاله عملکرد، مثال‌های واقعی، نکات بهینه‌سازی و مقایسه با ZipArchive بررسی خواهد شد.

پیش‌نیازها و فعال‌سازی

برای استفاده از zip_read باید اکستنشن zip در PHP فعال باشد. معمولاً در PHPهای مدرن این اکستنشن نصب و فعال است، اما می‌توانید با تابع extension_loaded('zip') وضعیت را بررسی کنید.

  • تابع اصلی: zip_read(resource $zip) — یک ورودی (resource) از zip_open می‌گیرد و یک zip_entry resource یا false باز می‌گرداند.
  • توابع مکمل: zip_open, zip_close, zip_entry_name, zip_entry_open, zip_entry_read, zip_entry_filesize, zip_entry_close.

نحوه کارکرد کلی

روند عمومی کار به این شکل است:

  • با zip_open() فایل ZIP را باز می‌کنید.
  • با حلقه و zip_read() هر عضو را دریافت می‌کنید.
  • برای هر عضو با zip_entry_name() نام را می‌خوانید.
  • با zip_entry_open() عضو را باز و با zip_entry_read() محتوا را می‌خوانید.
  • در پایان منابع را با zip_entry_close() و zip_close() آزاد می‌کنید.

نمونه پایه — خواندن نام فایل‌ها و اندازه‌ها

$zip = zip_open('archive.zip');
if (!is_resource($zip)) {
    throw new Exception('Cannot open zip archive');
}

while ($entry = zip_read($zip)) {
    $name = zip_entry_name($entry);
    $size = zip_entry_filesize($entry);
    echo "Entry: $name (size: $size)n";
}

zip_close($zip);

این کد فایل archive.zip را باز کرده، در هر بار اجرای حلقه یک entry برمی‌دارد و نام و اندازه آن را چاپ می‌کند. اگر فایل قابل باز شدن نباشد، استثنا پرتاب می‌شود.

خواندن محتوای یک عضو ZIP

$zip = zip_open('archive.zip');
if (!is_resource($zip)) exit('Cannot open zip');

while ($entry = zip_read($zip)) {
    $name = zip_entry_name($entry);
    if (zip_entry_open($zip, $entry)) {
        $contents = zip_entry_read($entry, zip_entry_filesize($entry));
        echo "File: $namen";
        echo $contents;
        zip_entry_close($entry);
    }
}

zip_close($zip);

در این مثال ابتدا عضو با zip_entry_open باز می‌شود سپس با zip_entry_read کل محتوا (با استفاده از سایز فایل) خوانده می‌شود و در نهایت با zip_entry_close بسته می‌شود. این روش برای فایل‌های کوچک مناسب است؛ برای فایل‌های بزرگ باید خواندن در بلوک‌های کوچک انجام شود تا حافظه مصرفی کنترل شود.

خواندن در بلوک (برای فایل‌های بزرگ)

$zip = zip_open('large.zip');
while ($entry = zip_read($zip)) {
    $name = zip_entry_name($entry);
    if (!zip_entry_open($zip, $entry)) continue;

    $bufferSize = 8192;
    while (!feof($entry) && ($data = zip_entry_read($entry, $bufferSize))) {
        // پردازش بلوکی، مثلاً نوشتن در فایل خروجی
        echo $data;
    }

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

در این قطعه از خواندن بلوکی با سایز 8192 بایت استفاده شده تا از حافظه بیش از حد جلوگیری شود. توجه کنید که تابع zip_entry_read تا زمانی که داده موجود باشد مقدار بازمی‌گرداند و باید حلقه تا پایان داده ادامه یابد.

اشکال‌زدایی، مدیریت خطا و نکات ایمنی

  • همیشه وجود اکستنشن zip را قبل از استفاده چک کنید: extension_loaded('zip').
  • منابع را ببندید: فراموش نکنید zip_entry_close و zip_close را صدا بزنید تا نشت منابع رخ ندهد.
  • برای فایل‌هایی که ممکن است حاوی مسیرهای مخرب باشند (مثلاً ../../) قبل از استخراج مسیر را sanitize کنید تا از Directory Traversal جلوگیری کنید.
  • برای بارگزاری روی وب‌سرور، محدودیت‌های حافظه و زمان اجرا را در نظر بگیرید و از خواندن بلوکی استفاده کنید.

مقایسه با ZipArchive (توصیه‌شده)

تابع‌های مبتنی بر zip_open/zip_read قدیمی‌تر و مبتنی بر منابع هستند. کلاس ZipArchive مدرن‌تر، شیءگرا و امن‌تر است و امکانات بیشتری مثل استخراج مستقیم (extractTo) دارد. در پروژه‌های جدید توصیه می‌شود از ZipArchive استفاده کنید مگر اینکه دلایل خاصی برای استفاده از API قدیمی وجود داشته باشد.

$zip = new ZipArchive();
if ($zip->open('archive.zip') === TRUE) {
    for ($i = 0; $i numFiles; $i++) {
        $stat = $zip->statIndex($i);
        echo $stat['name'] . " (" . $stat['size'] . ")n";
    }
    $zip->close();
} else {
    echo "Failed to open archiven";
}

این کد نشان می‌دهد که با ZipArchive می‌توانید به صورت شیءگرا به اعضا دسترسی پیدا کنید و متدهایی مثل statIndex برای اطلاعات فایل وجود دارد. خوانایی و قابلیت نگهداری این روش بهتر است.

جدول توابع مرتبط

تابعکاربری
zip_openباز کردن فایل ZIP و بازگرداندن resource
zip_readخواندن عضو بعدی (zip_entry resource)
zip_entry_nameدریافت نام عضو جاری
zip_entry_openباز کردن عضو برای خواندن
zip_entry_readخواندن محتوای عضو
zip_entry_filesizeدریافت اندازه عضو
zip_entry_close / zip_closeبستن منابع

نتیجه‌گیری و توصیه‌ها

تابع zip_read() برای مرور و خواندن اعضای یک ZIP مناسب است، اما برای پروژه‌های جدید بهتر است از ZipArchive استفاده کنید. اگر به هر دلیلی از API قدیمی استفاده می‌کنید، به مدیریت منابع، خواندن بلوکی برای فایل‌های بزرگ و ایمن‌سازی مسیرها توجه داشته باشید. در نهایت تست روی نمونه‌های بزرگ و بررسی مصرف حافظه قبل از تولید ضروری است.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: