2013-05-12 12 views
5

Voglio comprimere (al volo) una directory nel formato tar.gz usando PHP. So che può essere fatto con exec o usando this code (utilizzando il formato ZIP), ma il mio host non supporta exec e non ha installato l'estensione zip di PHP.Comprimi al volo una directory in formato tar.gz usando PHP

Dopo una ricerca su internet mi sono imbattuto this PHP code:

<?php 
// Computes the unsigned Checksum of a file’s header 
// to try to ensure valid file 
// PRIVATE ACCESS FUNCTION 
function __computeUnsignedChecksum($bytestring) { 
    for($i=0; $i<512; $i++) 
    $unsigned_chksum += ord($bytestring[$i]); 
    for($i=0; $i<8; $i++) 
    $unsigned_chksum -= ord($bytestring[148 + $i]); 
    $unsigned_chksum += ord(" ") * 8; 

    return $unsigned_chksum; 
} 

// Generates a TAR file from the processed data 
// PRIVATE ACCESS FUNCTION 
function tarSection($Name, $Data, $information=NULL) { 
    // Generate the TAR header for this file 

    $header .= str_pad($Name,100,chr(0)); 
    $header .= str_pad("777",7,"0",STR_PAD_LEFT) . chr(0); 
    $header .= str_pad(decoct($information["user_id"]),7,"0",STR_PAD_LEFT) . chr(0); 
    $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0); 
    $header .= str_pad(decoct(strlen($Data)),11,"0",STR_PAD_LEFT) . chr(0); 
    $header .= str_pad(decoct(time(0)),11,"0",STR_PAD_LEFT) . chr(0); 
    $header .= str_repeat(" ",8); 
    $header .= "0"; 
    $header .= str_repeat(chr(0),100); 
    $header .= str_pad("ustar",6,chr(32)); 
    $header .= chr(32) . chr(0); 
    $header .= str_pad($information["user_name"],32,chr(0)); 
    $header .= str_pad($information["group_name"],32,chr(0)); 
    $header .= str_repeat(chr(0),8); 
    $header .= str_repeat(chr(0),8); 
    $header .= str_repeat(chr(0),155); 
    $header .= str_repeat(chr(0),12); 

    // Compute header checksum 
    $checksum = str_pad(decoct(__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT); 
    for($i=0; $i<6; $i++) { 
    $header[(148 + $i)] = substr($checksum,$i,1); 
    } 
    $header[154] = chr(0); 
    $header[155] = chr(32); 

    // Pad file contents to byte count divisible by 512 
    $file_contents = str_pad($Data,(ceil(strlen($Data)/512) * 512),chr(0)); 

    // Add new tar formatted data to tar file contents 
    $tar_file = $header . $file_contents; 

    return $tar_file; 
} 

function targz($Name, $Data) { 
    return gzencode(tarSection($Name,$Data),9); 
} 

header("Content-Disposition: attachment; filename=backup.tar.gz"); 
header("Content-type: application/x-gzip"); 

$getfile = file_get_contents("test.txt"); 

echo targz('test.txt', $getfile); 
?> 

Questo funziona per più file che utilizzano questo:

header("Content-Disposition: attachment; filename=backup.tar.gz"); 
header("Content-type: application/x-gzip"); 

$getfile = file_get_contents("test.txt"); 

echo targz('test.txt', $getfile); 

$getfile2 = file_get_contents("test2.txt"); 

echo targz('test2.txt', $getfile2); 

Nel backup.tar.gz sono ora 2 file (test.txt e test2.txt).

Ma come posso utilizzarlo per scaricare una directory (e le sottodirectory)?

mia directory è qualcosa di simile:

home/ 
    file1.html 
    file2.html 
Another_Dir/ 
    file8.html 
    Sub_Dir/ 
     file19.html 

risposta

5

È necessario anche elencare tutti i file e le directory all'interno della directory che si desidera comprimere. C'è una funzione di elenco di directory ricorsiva here. Penso che combinando il tuo codice con il suo codice faccia il lavoro. qualcosa di simile:

header("Content-Disposition: attachment; filename=backup.tar.gz"); 
header("Content-type: application/x-gzip"); 

// Your other tar.gz functions... 

function compress($path = '.', $level = 0){ 
    $ignore = array('cgi-bin', '.', '..'); 
    $dh = @opendir($path); 

    while(false !== ($file = readdir($dh))){         
     if(!in_array($file, $ignore)){ 
      if(is_dir("$path/$file")){ 
       // Go to the subdirs to compress files inside the subdirs 
       compress("$path/$file", ($level+1));           
      } else { 
       $getfile = file_get_contents($path. '/' .$file); 
       // get the last dir in the $path 
       $dirs = array_filter(explode('/', $path)); 
       $dir = array_pop($dirs); 

       // if we're not in a sub dir just compress the file in root otherwise add it on the subdir... 
       if ($level < 1) { 
        echo targz($file, $getfile); 
       } else { 
        // add all top level subdirs when $level is > 2 
        for ($i = 0; $i < $level - 1; $i++) { 
         $temp = array_pop($dirs); 
         $dir = $temp.'/'.$dir; 
        } 
        echo targz($dir. '/' .$file, $getfile); 
       } 
      }           
     }          
    } 

    closedir($dh); 
} 

$dir = 'dir/to/compress'; 
if (is_file($dir)) { 
    // If it's a file path just compress it & push it to output 
    $getfile = file_get_contents($dir); 
    echo targz(basename($dir), $getfile); 
} elseif(is_dir($dir)) { 
    return compress($dir); 
} 

Funziona bene per me. È il mio primo contributo, spero che sia d'aiuto ..

+0

Stavo usando un framework php per testare, in modo che 'return' nell'ultima riga fosse inutile .. –

+0

Grazie! Ma quando c'è una sottodirectory ('home/Another_Dir/Sub_Dir /') sposta la cartella in ('home/Sub_Dir /') nel file 'backup.tar.gz' e non mantiene il normale formato di directory ('home/Another_Dir/Sub_Dir /'). Può essere risolto? – user1480019

+1

@GerritHoekstra Ho modificato il codice in modo che dovrebbe essere risolto ora. –