Работа с форматами сжатия 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
   Обфускаторы кода для PHP
   Полнотекстовый поиск с Xapian и PHP


Обсуждение статьи:

 
Семен [2010-03-01]
допишите еще пожалуйста, как можно запаковывать RAR'ом ))))


Вася [2010-03-11]
Никак, Семен, только если делать exec программы с нужными параметрами, потому что раровая сжималка - платная


 

Оставить комментарий:

Имя


E-mail


Сообщение