چگونه فایل ها را در PHP به صورت Zip یا Unzip درآوریم؟ — به زبان ساده

آخرین به‌روزرسانی: ۶ آبان ۱۳۹۷
زمان مطالعه: ۶ دقیقه

فشرده‌سازی فایل‌ها هنگام انتقال روی اینترنت مزیت‌های زیادی دارد. در اغلب موارد اندازه کلی مجموع همه فایل‌ها در قالب فشرده (zip) به میزان زیادی کاهش می‌یابد. این بدان معنی است که پهنای باند زیادی صرفه‌جویی می‌شود و کاربران نیز سرعت دانلودشان افزایش می‌یابد. زمانی که کاربران یک فایل را دانلود کردند، می‌توانند محتوای آن را در هر جا که می‌خواهند، از حالت فشرده خارج سازند. به طور خلاصه، فشرده‌سازی باعث می‌شود ارائه فایل‌ها روی اینترنت هم برای صاحبان وب‌سایت و هم بازدیدکنندگان تا حدود زیادی ساده‌تر شود.

یکی از عواملی که می‌تواند مانع فشرده‌سازی شود فرایند وقت‌گیر و خسته‌کننده آن در صورت اجرای دستی است. خوشبختانه PHP افزونه‌های زیادی دارد که به طور خاص برای فشرده‌سازی و استخراج فایل‌های فشرده طراحی شده‌اند. از کارکردهای ارائه شده در این افزونه‌ها می‌توان برای فشرده‌سازی خودکار فایل‌ها در PHP استفاده کرد. در این راهنما شیوه zip و unzip (فشرده‌سازی و استخراج فایل‌های فشرده) را در فایل‌های آرشیو zip در زبان برنامه‌نویسی PHP آموزش می‌دهیم. همچنین با چگونگی حذف و تغییر نام فایل‌ها در یک آرشیو بدون نیاز به استخراج فایل‌ها آشنا می‌شوید.

فشرده‌سازی فایل‌ها در PHP

کلاس ZipArchive در PHP مشخصات و متدهای زیادی دارد که به فشرده‌سازی و استخراج فایل‌ها کمک می‌کند.

فشرده‌سازی فایل‌های منفرد

شما می‌توانید فایل‌ها را به صورت یک به یک و یا به صورت کل دایرکتوری به آرشیوهای zip اضافه کنید. در هر حالت، نخستین گام ایجاد یک وهله جدید از کلاس ZipArchive و سپس فراخوانی متد ([open($filename, [$flags است. این متد یک آرشیو zip جدید برای خواندن، نوشتن یا دیگر تغییرات باز می‌کند. چهار مقدار معتبر برای پارامتر flag$ وجود دارند که شبیه مدیریت موقعیت‌های مختلف را تعیین می‌کنند:

  • ZipArchive::OVERWRITE – این فلگ در صورتی که یک آرشیو خاص از قبل محتوایی داشته باشد، بازنویسی می‌کند.
  • ZipArchive::CREATE – این فلگ در صورتی که آرشیوی از قبل وجود نداشته باشد، یک آرشیو جدید ایجاد می‌کند.
  • ZipArchive::EXCL این فلگ در صورتی که آرشیو از قبل وجود داشته باشد خطایی صادر می‌کند.
  • ZipArchive::CHECKCONS – این فلگ به PHP می‌گوید که بررسی‌های سازگاری بیشتری را روی آرشیو انجام داده و در صورت شکست خطایی صادر کند.

برای یادگیری موارد بیشتر در مورد خطاهایی که این متد در صورت عدم توانایی باز کردن فایل صادر می‌کند، می‌توانید از مستندات آن استفاده کنید. اگر فایل‌های zip به طور موفقیت‌آمیزی باز یا ایجاد شوند، این متد مقدار true بازمی‌گرداند.

زمانی که آرشیو با موفقیت باز شد، می‌توانید از متد addFile($filename, $localname, $start, $length) برای افزودن هر فایلی از یک مسیر مفروض به آرشیو استفاده کنید. پارامتر filename$ مسیر یک فایل است که می‌خواهد به آرشیو اضافه کنید. پارامتر localname$ برای انتساب یک نام به فایل جهت ذخیره‌سازی درون آرشیو استفاده می‌شود. شما می‌توانید متد ()addFile را هر بار که می‌خواهید یک فایل جدید به آرشیو اضافه کنید، فراخوانی نمایید.

پس از افزودن همه فایل‌های ضروری به آرشیو می‌توانید به سادگی متد ()close را فراخوانی کنید تا فایل بسته شده و تغییرات ذخیره شوند.

فرض کنید وب‌سایتی دارید که می‌خواهید کاربران بتوانند فایل‌های فونت را برای فونت‌های مختلف همراه با اطلاعات لایسنس استفاده از هر کدام دانلود کنند. فایل‌هایی مانند این نمونه‌های خوبی برای فشرده‌سازی خودکار با استفاده از PHP محسوب می‌شوند. کد زیر شیوه دقیق انجام این کار را نمایش می‌دهد:

<?php
 
$zip = new ZipArchive();
$zip->open('compressed/font_files.zip', ZipArchive::CREATE);
  
$zip->addFile('fonts/Monoton/Monoton-Regular.ttf', 'Monoton-Regular.ttf');
$zip->addFile('fonts/Monoton/OFL.txt', 'license.txt');
  
$zip->close();
 
?>

در ابتدا یک وهله از کلاس ZipArchive ایجاد می‌کنیم و سپس با استفاده از متد ()open آرشیو خود را می‌سازیم. متد ()addFile فایل فونت واقعی ttf. و فایل لایسنس txt. را به آرشیو اضافه می‌کند.

دقت کنید که فایل‌های اصلی درون دایرکتوری fonts/Monoton هستند. با این وجود، کد PHP آن را مستقیماً درون ریشه آرشیو ما قرار می‌دهد. می‌توانید ساختار دایرکتوری و همچنین نام‌های فایل‌هایی که در آرشیو قرار می‌گیرند را تغییر دهید.

فشرده‌سازی چندین فایل از یک دایرکتوری

افزودن فایل‌های منفرد به آرشیو در صورت وجود فایل‌های زیاد، پس از مدتی می‌تواند کاری خسته‌کننده باشد. برای نمونه اگر بخواهید آرشیوی از همه فایل‌های png. یا pdf. در یک دایرکتوری ایجاد کنید، می‌توانید از فرایند متفاوتی استفاده کنید. متد (addGlob($pattern, $flags, $options در چنین مواردی کاملاً مفید است. تنها عیب این متد آن است که کنترلمان را روی مکان فایل‌های منفرد در آرشیو از دست می‌دهیم. با این وجود می‌توان ساختار دایرکتوری درون آرشیو را با استفاده از پارامتر $options تعیین کرد. این گزینه‌ها را می‌توان به صورت یک آرایه انجمنی (associative array) ارسال کرد.

  • add_path – مقدار انتساب یافته به add_path، در واقع پیشوندی برای مسیر محلی فایل‌های درون آرشیو است.
  • remove_path – مقدار انتساب یافته به remove_path برای حذف پیشوند منطبق از مسیر فایل‌های مختلفی است که به آرشیو افزوده شده‌اند.
  • remove_all_path – تعیین مقدار remove_all_path به صورت true باعث می‌شود، همه چیز به جز نام فایل از مسیر آن حذف شود. در این حالت فایل‌ها به ریشه آرشیو اضافه می‌شوند.

به خاطر داشته باشید که حذف مسیر، پیش از ارائه پیشوند مقدار ذکر شده در add_path صورت می‌گیرد.

در قطعه کد زیر از متد ()addGlob و همه گزینه‌های مطرح شده استفاده شده است.

$zip = new ZipArchive();
$zip->open('compressed/user_archive.zip', ZipArchive::CREATE);
  
$options = array('add_path' => 'light_wallpapers/', 'remove_all_path' => TRUE);
$zip->addGlob('lights/*.jpg', 0, $options);
 
$options = array('add_path' => 'font_files/', 'remove_all_path' => TRUE);
$zip->addGlob('documents/*.ttf', 0, $options);
 
$options = array('add_path' => 'pdf_books/', 'remove_all_path' => TRUE);
$zip->addGlob('documents/*.pdf', 0, $options);
 
$options = array('add_path' => 'images/', 'remove_all_path' => TRUE);
$zip->addGlob('documents/*.{jpg, png}', GLOB_BRACE, $options);
  
$zip->close();

به طور معمول کار خود را با ایجاد وهله جدیدی از کلاس ZipArchive آغاز می‌کنیم و سپس از متد ()open برای ایجاد آرشیو خود استفاده می‌کنیم. همچنین پیش از هر فراخوانی متد ()addGlob مقادیر مختلفی برای کلید add_path در آرایه options$ تعیین می‌کنیم. بدین ترتیب می‌توانیم هر بار با مجموعه خاصی از فایل‌ها کار کنیم و بر همین اساس گزینه‌های آرشیو کردن را تعیین نماییم.

در حالت نخست این متد همه فایل‌های jpg. را در دایرکتوری lights انتخاب می‌کند و آن‌ها را در دایرکتوری light_wallpapers در آرشیو قرار می‌دهد. به طور مشابه، همه فایل‌های ttf. را در دایرکتوری documents انتخاب می‌کنیم و سپس آن‌ها را درون دایرکتوری font_files در آرشیو قرار می‌دهد. در نهایت همه فایل‌های jpg. و png. را از میان اسناد خود انتخاب می‌کنیم و آن‌ها را به همراه یکدیگر در دایرکتوری images قرار می‌دهیم.

همان طور که مشاهده می‌کنید مقادیر options$ در سازماندهی محتوای درون آرشیو مفید هستند.

استخراج محتوا از یک آرشیو

کلاس ZipArchive متدی به نام xtractTo($destination, $entries) دارد که محتوای یک آرشیو را استخراج می‌کند. می‌توان از آن برای استخراج همه چیز از درون آرشیو یا برخی فایل‌های خاص استفاده کرد. پارامتر entries$ نیز می‌تواند برای تعیین نام فایل منفرد که باید استخراج شود مورد استفاده قرار گیرد. همچنین از آن می‌توان برای ارسال آرایه‌ای از فایل‌ها استفاده کرد.

نکته مهمی که باید به خاطر داشت این است که باید مسیر صحیح فایل درون آرشیو را برای استخراج آن تعیین نمود. برای نمونه یک فایل فونت به نام AlegreyaSans-Light.ttf را در مرحله قبلی آرشیو کردیم. این فایل درون آرشیو در دایرکتوری font_files ذخیره شده است. این بدان معنی است که مسیر مورد نیاز برای پارامتر entries$ به صورت font_files/AlegreyaSans-Light.ttf خواهد بود و نه به صورت AlegreyaSans-Light.ttf.

این دایرکتوری و ساختار فایل در طی فرایند استخراج حفظ می‌شود و فایل‌ها در دایرکتوری‌های مربوطه استخراج می‌شوند.

<?php
 
$zip = new ZipArchive();
$zip->open('compressed/user_archive.zip', ZipArchive::CREATE);
$zip->extractTo('uncompressed/', 'font_files/AlegreyaSans-Light.ttf');
$zip->close();
  
?>

اگر پارامتر دوم فراموش شود، این متد همه فایل‌های درون آرشیو را استخراج خواهد کرد.

کنترل بیشتر روی آرشیوها

کلاس ZipArchive متدها و مشخصات زیاد دیگری نیز دارد که در هنگام کسب اطاعات در مورد آرشیو، پیش از استخراج همه محتوای آن به کمک می‌آیند.

با استفاده از متد ()count می‌توان تعداد فایل‌های درون آرشیو را شمارش کرد. گزینه دیگر استفاده از خصوصیت numFiles است. از این گزینه‌ها می‌توان برای شمارش همه فایل‌ها درون آرشیو استفاده کرد و سپس تنها فایل‌هایی که مورد نیاز هستند را استخراج کرد. همچنین می‌توان کارهای دیگری با آن‌ها کرد، مثلاً برخی از فایل‌ها را از آرشیو حذف کرد.

در نمونه کد زیر ما همه فایل‌های درون آرشیو را که شامل کلمه italic هستند حذف می‌کنیم. کد مشابهی را می‌توان برای حذف همه فایل‌هایی که شامل واژه‌ای خاص نیستند تعریف کرد. همچنین می‌توان همه فایل‌ها را بررسی کرد و واژه خاصی را با کلمه دیگری جایگزین نمود.

<?php
 
$zip = new ZipArchive();
$zip->open('compressed/user_archive.zip', ZipArchive::CREATE);
 
$file_count = $zip->count();
 
for($i = 0; $i < $file_count; $i++) {
    $file_name = $zip->getNameIndex($i);
 
    if(stripos($file_name, 'Italic') !== false) {
        $zip->deleteName($file_name);
    }
}
  
$zip->close();
 
?>

در کد فوق از متد ()deleteName برای حذف یک فایل منفرد استفاده شده است. با این وجود، می‌توان از آن برای حذف کل دایرکتوری نیز استفاده کرد.

می‌توان از تابع مشابه (renameName($oldname, $newname برای تغییر نام هر فایل در آرشیو استفاده کرد. در این صورت اگر فایل با عنوان newname$ از قبل وجود داشته باشد با خطایی مواجه می‌شوید.

سخن پایانی

دز این مقاله برخی از متدهای مفید کلاس ZipArchive را که فرایند فشرده‌سازی و استخراج خودکار فایل‌ها در PHP نقش دارند معرفی کردیم. اینک شما می‌توانید فایل‌های منفرد یا گروهی از آن‌ها را بر اساسی معیار خاص به یک باره فشرده کنید. به طور مشابه قادر هستید هر فایل خاصی را از یک آرشیو بدون تأثیر گذاشتن روی محتوای دیگر استخراج کنید.

به کمک متدهای ()count و numFiles می‌توانید کنترل بیشتری روی فایل‌های منفرد داشته باشد و آن‌ها را به روشی کاملاً ساده تغییر نام داده یا حذف کنید. اگر می‌خواهید در این موارد اطلاعات بیشتری کسب کنید می‌توانید به مستندات این کلاس مراجعه کنید.

اگر به این نوشته علاقه‌مند بودید، شاید موارد زیر نیز مورد توجه شما قرار گیرند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
شما قبلا رای داده‌اید!
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
tutsplus

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *