понедельник, 18 февраля 2013 г.

Распаковщик zip-ов на php

Пригодится тем у кого php без --with-zip
Поддерживает только методы сжатия deflate и no_compression.
Большинство зипов по умолчанию зажаты именно deflate, так что 95% архивов открывает без проблем. Запароленные не распаковывает.
Распаковывает также и вордовский docx (для чего, собственно, и был сделан, т.к. популярная либа PclZip, спотыкалась на куче нулей, которые ворд щедро пихает в свои файлы, видимо для того, чтобы размер файла не казался подозрительно маленьким :))


 <?php 
// Radchand (C) radchand(a)mail.ru 

$GLOBALS['unzip_error'] = 'Ok'; // Строка с описанием ошибки 

/** Главная (и единственная) низкоуровняя ф-я для распаковки архива 
// @desc Распаковывает текущий файл в архиве. 
// Предназначана для работы в цикле. 
// Если $target не задан, то просто перемещает указатель на следующий файл в архиве не распаковывая. 
// Чтобы распаковать все файлы в архиве нужно вызывать эту ф-ю с одним и тем же handle до тех пор пока она не вернет false 
// Аргументы: 
// @param $file - имя файла или handle (возвращает fopen) 
// @param $target - имя файла для распаковки, если не совпадает, то просто перемещает указатель в архиве на следующий файл, но возващает имя файла, его размер и пр. 
//      true - распаковывает любой файл 
// @return Возвращает ассоциативный массив: 
//   FName - имя файла, 
//   Date, Time - дата и время в 2-х байтном MS-DOS формате, 
//   ExtractedLen - размер, 
//   Data - содержимое файла, 
//   Extra - дополн. данные 
// если произошла какая-то ошибка, то возвращает false, скорее всего, последующие вызовы тоже вернут false, т.к. наверняка указатель сползет 
// в случае ошибки из-за неподдерживаемого алгоритма распаковки, все же можно прочитать список файлов ($target=false) 
*/   
function Unzip($file, $target=false) 
{ 
    $h = is_string($file) ? fopen($file, 'rb') : $file; 
    if($h===false) 
        { $GLOBALS['unzip_error'] = "Can't open file"; return FALSE; } 
    $offset = ftell($h); 
    // ReadLocalFileHeader 
    $hdr = unpack('V1Sign/v1Ver/v1Flags/v1Method/v1Time/v1Date/V1CRC/V1DataLen/V1ExtractedLen/v1FNameLen/v1ExtraLen', fread($h, 30)); 
    if($hdr['Sign'] == 0x02014b50) 
        { $GLOBALS['unzip_error'] = 'End of file'; return FALSE; } 
    if($hdr['Sign'] != 0x04034b50) 
        { $GLOBALS['unzip_error'] = 'Invalid sign!'; return FALSE; } 
    if($hdr['Flags'] & 0x0008) // Descriptor after data. Need read directory at first. 
        { $GLOBALS['unzip_error'] = 'Descriptor after data'; return FALSE; } 

    $hdr['Offset'] = $offset; 
    $hdr['FName'] = fread($h, $hdr['FNameLen']); 
    if($target == $hdr['FName'] || $target === true) 
    { 
        if($hdr['Method']!=8 && $hdr['Method']!=0) // only deflate & no_compression method implemented 
            { $GLOBALS['unzip_error'] = 'Only deflate & no_compression method implemented'; return FALSE; } 
        if($hdr['ExtraLen']>0) 
            $hdr['Extra'] = fread($h, $hdr['ExtraLen']); 
        if($hdr['DataLen']>0) 
        { 
            $hdr['Data']  = fread($h, $hdr['DataLen']); 
            if($hdr['Flags'] & 0x0001) 
                { $GLOBALS['unzip_error'] = 'Encrypted';  return FALSE; } 
            if($hdr['Method'] == 8) 
                $hdr['Data'] = gzinflate($hdr['Data']); // deflate 
        } 
        if(strlen($hdr['Data']) != $hdr['ExtractedLen']) // bad length 
            { $GLOBALS['unzip_error'] = 'Bad length'; return FALSE; } 
        if(crc32($hdr['Data'])  != $hdr['CRC']) 
            { $GLOBALS['unzip_error'] = 'Bad CRC'; return FALSE; } 
    } 
    else 
        fseek($h, $hdr['ExtraLen']+$hdr['DataLen'], SEEK_CUR); 
    if(is_string($file)) fclose($h); 
    return $hdr; 
} 

// Пара утилиток 

/** @desc возвращает список файлов в архиве 
*  @param путь к архиву */ 
function ZipList($file) 
{ 
    $ret = array(); 
    $h = fopen($file,'rb'); 
    do { 
        $data = Unzip($h); 
        if(isset($data['FName'])) 
                $ret[] = $data['FName']; 
    } while($data && !feof($h)); 
    fclose($h); 
    return $ret; 
} 

/** @desc возвращает содержимое заданного файла из архива 
*  @param путь к архиву 
*  @param путь (имя файла) в архиве 
*/ 
function UnzipFile($arcfile, $file) 
{ 
    $h = fopen($arcfile, 'rb'); 
    do { 
        $data = Unzip($h, $file); 
        if(isset($data['Data'])) 
        { 
            fclose($h); 
            return $data['Data']; 
        } 
    } while($data && !feof($h)); 
    fclose($h); 
    return false; 
} 

/** @desc возвращает ассоц. массив [имяфайла]=содержимое со всеми файлами из архива 
*  @param путь к архиву */ 
function UnzipAll($arcfile) 
{ 
    $ret = array(); 
    $h = fopen($arcfile, 'rb'); 
    do { 
        $data = Unzip($h, $file); 
        if($data && isset($data['FName'], $data['Data'])) 
            $ret[$data['FName']] = $data['Data']; 
    } while($data && !feof($h)); 
    fclose($h); 
    return $ret; 
} 
?> 

Комментариев нет:

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