Робота з форматами стиснення RAR, LZF і Bz2 в PHP

Мітки: php, rar, zip, lzf, bzip2, архівація

Работа с форматами сжатия RAR, LZF и BZ2 в PHP Работа с форматами сжатия RAR, LZF и BZ2 в PHP
Working with RAR, LZF and BZ2 Compression Formats in PHP Working with RAR, LZF and BZ2 Compression Formats in PHP

Кінцевий набір інструментів
Коли справа доходить до роботи з різними форматами файлів, PHP складно збентежити. Документи XML, файли PDF, зображення JPEG, медіа Mp3… ви називаєте їх, і є всі шанси, що в PHP знайдуться розширення для роботи з ними. І така ж ситуація з такими форматами для стиснення, як RAR, LZF і Bzip2, хоча ці формати архівів не так поширені сьогодні, як повсюдні TAR і ZIP, вони все ще активно використовуються багатьма додатками і проектами, і продовжують підтримуватися в PHP через розширення PECL.
Ось про що ця стаття. На наступних сторінках я представлю вам деякі розширення PHP, які дозволять вам створювати, переглядати і маніпулювати стиснутими файлами в цих форматах. Читайте далі і готуйтеся дивуватися!

Установка розширень
Підтримка RAR прийшла в PHP через розширення PECL ext/rar, підтримуване Antony Dovgal і надає read-only API орієнтоване на функціях для лістингу і розпаковування файлів RAR-архівів. Розширення LZF, підтримуване Marcin Gibula, дозволяє стискати та розпаковувати LZF, тоді як розширення Bzip2 дозволяє робити архівацію і розархівування для Bzip2.
Найбільш простий спосіб установки цих пакетів це автоматизований установник PECL, який піклується про викачування і установку розширення як завантажувального модуля PHP. Ось приклад використання розширення RAR:
Прибрати підсвітку коду
1
2
3
4
5
6
shell# pecl install rar
shell# cd rar-1.0.0
shell# phpize
shell# ./configure 
shell# make    
shell# make install

Ця процедура повинна створити завантажувальний модуль PHP з ім'ям rar.so у вашому каталозі розширень PHP. Тепер вам потрібно включити розширення у файлі конфігурації php.ini, перезапустити веб-сервер і перевірити, чи доступне розширення, швидким викликом phpinfo():
Робота з форматами стиснення RAR, LZF і Bz2 в PHP

Щоб включити підтримку LZF, слідуйте даній інструкції: викачайте, скомпілюйте і встановіть розширення, використовуючи PECL або вручну, і все готово. Для включення підтримки Bzip2 вам буде потрібно зібрати PHP з опцією --with-bz2.
Користувачі Windows можуть зробити це швидше. Заздалегідь скомпільовані версії файлів php_rar.dll, php_lzf.dll і php_bz2.dll можна викачати на сайті http://pecl4win.php.net/. Як тільки ви отримали файли, помістіть їх в папку розширень PHP, активуйте їх через конфігураційний файл php.ini, перезапустіть ваш веб-сервер. Тепер ви можете бачити активований статус розширень в phpinfo(), як показано вище.

Погляд всередину
Припустимо, у вас є всі частини і вони працюють. Давайте задіємо їх в простому прикладі: читання існуючого файлу RAR через PHP, і виведення списку його вмісту:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// відкриття архіву
$rar = rar_open(realpath('.') . "/app-0.2.rar") or die('ERROR: Could not open archive!');
 
// отримання списку файлів архіву
$entries = rar_list($rar);
foreach ($entries as $entry) {
  printf("%s (%d bytes)", $entry->getName(), $entry->getUnpackedSize());
  print "\n";      
}
 
// закриття архіву
rar_close($rar);
?>

Цей скрипт починається з використання функції rar_open() для відкриття файлу RAR архіву. Якщо воно сталося, цей метод повертає хендл ресурсу, який представляє RAR архів. Цей хендл служить вхідною точкою для всіх RAR функцій. Потім використовується метод rar_list() для видачі масиву, який зберігає інформацію про вміст архіву. Кожен елемент цього масиву представляє окремий файл (або елемент) з архіву, який зберігається як об'єкт. Методи об'єкту, такі як getName() і getUnpackedSize() використовуються для отримання додаткової інформації по відповідному файлу. Як тільки весь масив оброблено, хендл ресурсу знищується викликом методу rar_close().
От як виглядає уривок виводу:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
TODO.txt (11590 bytes)
im3.txt (38736 bytes)
im5.txt (7902 bytes)
im6.txt (17387 bytes)
im7.txt (7766 bytes)
zend\Picture004.jpg (253525 bytes)
zend\scan0002a.jpg (2062719 bytes)
zend (0 bytes)

Кожен об'єкт йде з різними методами і властивостями, які можуть бути використані для здобуття детальної інформації про файл, який вони представляють. Попередній список був зроблений з використанням методів getName() і getUnpackedSize(), які повертають ім'я файлу і розмір незтиснутого файлу відповідно.
Для здобуття інформації про конкретний файл (а не про весь архів) використовуйте метод rar_entry_get() з ім'ям відповідного елементу. Ось приклад:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
<?php
// відкриття архіву
$rar = rar_open(realpath('.') . "/app-0.2.rar") or die('ERROR: Could not open archive!');
 
// отримання конкретного файл з архіву
$entry = rar_entry_get($rar, 'zend\Picture004.jpg') or die('ERROR: Could not get entry!');
printf("%s (%d bytes)", $entry->getName(), $entry->getUnpackedSize());
 
// закриття архіву
rar_close($rar);
?>

Все про методи
Вам також доступні й інші методи в ext/rar. Ось приклад, який демонструє деякі з них:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
  <head>
    <style type="text/css">
    td {
      border: solid 1px black;
      padding: 5px;
    }
    .head {
      font-weight: bold;  
    }
    </style>
  </head>
  <body>
    <table>
      <tr class="head">
        <td>File name</td>
        <td>Uncompressed size</td>
        <td>Compressed size</td>
        <td>Last modified</td>
        <td>CRC</td>
        <td>Pack method</td>
      </tr>
      <?php
      // відкриття архіву
      $rar = rar_open(realpath('.') . "/app-0.2.rar") or die("Could not open archive");
      
      // отримання списку файлів архіву
      $entries = rar_list($rar);
      
      // вивід детальної інформації про кожний з них
      // підрахунок степені стиснення
      foreach ($entries as $entry) {
      ?>
        <tr>
          <td><?php echo $entry->getName(); ?></td>
          <td><?php echo $entry->getUnpackedSize(); ?></td>
          <td><?php echo $entry->getPackedSize(); ?></td>
          <td><?php echo $entry->getFileTime(); ?></td>
          <td><?php echo $entry->getCRC(); ?></td>
          <td><?php echo $entry->getMethod(); ?></td>
        </tr>
      <?php
      }
      
      // закриття архіву
      rar_close($rar);
      ?>
    </table>
  </body>  
</html>

Цей скрипт представляє методи getPackedSize(), getFiletime(), getCRC() і getMethod(), які повертають розміри стиснутих файлів, час останньої зміни, контрольну суму CRC і спосіб стиснення, використовуваний для кожного елементу в архіві RAR. От як виглядає вивід:
Робота з форматами стиснення RAR, LZF і Bz2 в PHP

Місце розпаковування
Розширення RAR не дозволяє створювати нові архіви RAR, але воно дозволяє розпаковувати вже існуючі. Кожен об'єкт елементу rar_list() або rar_entry_get(), що повертається, йде з методом extract(), який приймає шлях до директорії як аргумент, виконуючи завдання розпаковування відповідного файлу в указану директорію.
Ось приклад, який розпаковує всі файли Rar-архіву в тимчасову директорію:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// відкриття архіву 
$rar = rar_open(realpath('.') . "/app-0.2.rar") or die("Could not open archive");
 
// отримання списку файлів архіву
$entries = rar_list($rar);
 
// перебір списку з розпаковкою кожного файлу
foreach ($entries as $entry) {
  if ($entry->extract(realpath('.') . "/out/")) {
    echo 'Extracted ' . $entry->getName() . "\n";
  }
}
 
// закриття архіву
rar_close($rar);
?>

Відмітьте, якщо вказаної директорії не існує, extract() створить її для вас. Проте, тоді як все відмінно працює під Windows, я зіткнувся з деякими проблемами при використанні під Linux.
Ви також можете вибірково розпаковувати конкретні файли з початкового архіву, використовуючи масив фільтру, що включає список файлів до розпаковування. Ось приклад:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// список файлів для розпаковки
$fileList = array(
  'zend\Picture004.jpg', 
  'im3.txt'
);
 
// відкриття архіву
$rar = rar_open(realpath('.') . "/app-0.2.rar") or die("Could not open archive");
 
// отримання списку файлів архіву 
$entries = rar_list($rar);
 
// перебір списку файлів з розпаковкою тільки тих файлів, що вказані в масиві
foreach ($entries as $entry) {
  if (in_array($entry->getName(), $fileList)) {
    if ($entry->extract(realpath('.') . "/out/")) {
      echo 'Extracted ' . $entry->getName() . "\n";
    }
  }
}
 
// закриття архіву
rar_close($rar);
?>

Рентгенівський зір
Тепер, коли ви маєте чітке уявлення про можливості ext/rar, давайте візьмемо те, що ми вивчили і напишемо маленький додаток. Скрипт приймає Rar-архів для завантаження на сервер і виводить його вміст методом rar_list():
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<html>
  <head>
    <style type="text/css">
    td {
      border: solid 1px black;
      padding: 5px;
    }
    .head {
      font-weight: bold;  
    }
    </style>
  </head>
  <body>
 
<?php
if (!isset($_POST['submit'])) {
?>
    <form action="<?=htmlentities($_SERVER['PHP_SELF']); ?>"
 method="POST" enctype="multipart/form-data">
     Select a file:
     <input type="file" name="file">
     <p>
     <input type="Submit" name="submit" value="Send File">
    </form>
<?php
} else {
 
  // додамо трохи перевірок на безпеку файлу
  // наприклад: file size > 0
  
  if (is_uploaded_file($_FILES['file']['tmp_name'])) {        
?>        
    <table>
      <tr>
          <td><b>Filename</b></td>
          <td><b>Uncompressed size</b></td>
          <td><b>Compressed size</b></td>
          <td><b>Pack ratio</b></td>
          <td><b>Last modified</b></td>
      </tr>   
<?php
    $filename = $_FILES['file']['tmp_name'];
    
    // відкриваємо завантажений файл
    $rar = rar_open($filename) or die("Could not open archive");
    $entries = rar_list($rar);
    
    // перебір всього списку файлів
    // вивід подробиць про кожний файл
    foreach ($entries as $entry) {
?>
      <tr>
        <td><?php echo $entry->getName(); ?></td>
        <td><?php echo $up = $entry->getUnpackedSize(); ?></td>
        <td><?php echo $p = $entry->getPackedSize(); ?></td>
        <td><?php echo ($up > 0) ? sprintf('%0.2f', $p/$up) : '-'; ?></td>
        <td><?php echo $entry->getFileTime(); ?></td>
      </tr>
<?php
    }
    
    // закриття архіву
    rar_close($rar);  
?>    
    </table>
<?php
  } else {
    die ('ERROR: Invalid file!');
  }
}
?>
 </body>
</html>

Цей скрипт поділений на дві основні частини, відокремлені умовою if():
1. У першій частині скрипта ми перевіряємо чи дані форми були відправлені, якщо ні, то показуємо форму з вибором файлу для завантаження. Відмітьте, що для того, щоб ми могли передавати файли за допомогою форми, тип encoding має бути встановлений як multipart/form-data.
2. Коли файл був завантажений, друга частина скрипта перевіряє масив $_FILES і дивиться щоб файл був завантажений вірно. Переконавшись в цьому, використовується функція rar_open() для відкриття архіву, потім використовується функція rar_list() у комбінації з різними методами get*() у циклі, для відображення вмісту архіву як акуратно відформатовану HTML-таблицю. Відмітьте, що скрипт підраховує рівень стиснення для кожного файлу, діленням розміру стиснутого файлу на розмір файлу до запаковування; чим менше число, тим краще компресія.
Ось приклад того, що виводиться на екран:
Робота з форматами стиснення RAR, LZF і Bz2 в PHP
Відмітьте, що даний скрипт всього лише демонстраційний – дозвіл для користувачів на завантаження файлів у веб-додатках є дуже небезпечним і може відкривати певні дірки в безпеці. Якщо ви плануєте використовувати цей приклад в реальному середовищі, ви повинні підсилити перевірку безпеки в коді щоб уникнути небажаних завантажень.

Спрощуємо собі життя
Що варто зробити далі, так це архівація окремих файлів (замість створення стиснутих архівів, що містять безліч файлів), розширень PHP LZF і Bzip2, які ми розглянули.
PHP розширення LZF управляється через дві функції: lzf_compress() і lzf_decompress() – не складно здогадатися, що вони роблять. Ось простий приклад використання lzf_compress(), функція стиснення таблиць Excel:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// вказуємо вхідний і вихідний файли
$in = 'info.xls';
$out = 'compressed.lzf';
 
// стиснення файлу за допомогою LZF
if (file_exists($in)) {
  $data = file_get_contents($in) or die('ERROR: Cannot read from input file!');
  if (file_put_contents($out, lzf_compress($data))) {
    echo 'Compressed file created.';
  } else {
   die('ERROR: Cannot write to output file!'); 
  }
}
?>

Для відновлення оригінального файлу, просто проведіть стиснутий файл через lzf_decompress() як рядок, і запишіть результат в новий файл. Ось код:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// вказуємо вхідний і вихідний файли
$out = 'out-lzf.xls';
$in = 'compressed.lzf';
 
// розпаковка файлу
if (file_exists($in)) {
  $data = file_get_contents($in) or die('ERROR: Cannot read input file!');
  if (file_put_contents($out, lzf_decompress($data))) {
    echo 'Decompression complete.';  
  } else {
    die('ERROR: Cannot write to output file!');  
  }
}
?>

Тут немає нічого складного – функції інтуїтивні, все просто і легко у використанні, що робить це ідеальним для ситуацій де потрібне швидке стиснення і розпаковування пакетів бінарних даних.

Zip, Zap, Zoom
Якщо ви шукаєте кращий ступінь стиснення (і не турбуєтеся про низьку швидкодію) ext/bz2 може підійти вам більше, ніж ext/lzf. Стиснуті дані, які робляться цим розширенням, часто виявляються менші, ніж у конкурента, але це приводить до нижчої продуктивності. Ось приклад використання:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// вказуємо вхідний і вихідний файли
$in = 'info.xls';
$out = 'compressed.bz2';
 
// стиснення файлу за допомогою BZIP2
if (file_exists($in)) {
  $data = file_get_contents($in) or die('ERROR: Cannot read input file');
  $bz = bzopen($out, 'w') or die('ERROR: Cannot open output file!');
  bzwrite($bz, $data) or die('ERROR: Cannot write to output file!');
  bzclose($bz);
  echo 'Compressed file created.';
}
?>

Функції bzopen(), bzwrite() і bzclose() працює за таким же принципом як функції PHP fopen(), fwrite() і fclose(), за винятком того, що вони призначені для роботи із стиснутими файлами Bzip2. Вказаний скрипт демонструє їх у дії: насамперед відкривається управління виведення файлу (у режимі запису) і використовується функція bzwrite() для стиснення і запису даних, що вводяться, в цей хендл файлу. Коли всі дані було стиснуто, управління файлом закривається і стиснуті дані зберігаються на диск функцією bzclose().

Зворотний процес настільки ж простий. Все що потрібне, це відкрити управління стиснутим файлом, прочитати і розпакувати його вміст, використовуючи функцію bzread(). Ці розпаковані дані можуть бути збережені в окремий файл для подальшого перегляду або маніпуляцій. Ось приклад:
Прибрати підсвітку коду
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// вказуємо вхідний і вихідний файли
$out = 'out-bz2.xls';
$in = 'compressed.bz2';
 
// розпаковка файлу за допомогою BZIP2
if (file_exists($in)) {
  $data = '';
  $bz = bzopen($in, 'r') or die('ERROR: Cannot open input file!');
  while (!feof($bz)) {
    $data .= bzread($bz, 4096) or die('ERROR: Cannot read from input file');;
  }
  bzclose($bz);  
  file_put_contents($out, $data) or die('ERROR: Cannot write to output file!');
  echo 'Decompression complete.';  
}
?>

І якщо ви порівняєте стиснутий вивід розширень LZF і Bzip2, ви побачите, що версія Bzip2 зазвичай менше, ніж версія LZF.
Останні декілька сторінок, я зробив вам швидкий екскурс по трьом розширеннях PECL, розроблених для роботи з форматами стиснутих файлів: розширень RAR, LZF і Bzip2. Як показують приклади в даному керівництві, ці три розширення можуть принести значиму допомогу у вашій повсякденній розробці, також дозволяючи вам програмно переглядати і розпаковувати файли архівів, або зменшити простір додатку, що використовується, за допомогою динамічної архівації/розархівації бінарних даних.

Оригінал: Working with RAR, LZF and BZ2 Compression Formats in PHP

Рейтинг: 12345   << Ви можете поставити оцінку цій статті


Подібні статті:
   Паттерн кешування для моделей
   Паттерн Спостерігач (Observer) в PHP


 
 

Залишити коментар:

Ім'я


E-mail


Повідомлення