【问题标题】:Compress on the fly a directory in tar.gz format using PHP使用 PHP 动态压缩 tar.gz 格式的目录
【发布时间】:2013-05-06 14:09:49
【问题描述】:

我想使用 PHP 压缩(即时)tar.gz 格式的目录。我知道可以使用execthis code(使用ZIP 格式)来完成,但是我的主机不支持exec 并且没有安装PHP 的zip 扩展。

在网上搜索后发现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);
?>

这确实适用于使用这个的多个文件:

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);

backup.tar.gz 现在有 2 个文件(test.txttest2.txt)。

但是如何使用它来下载目录(和子目录)?

我的目录是这样的:

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

【问题讨论】:

    标签: php directory gzip tar


    【解决方案1】:

    您还需要列出要压缩的目录中的所有文件和目录。有一个递归目录列表函数here。我认为将您的代码与他的代码结合起来即可完成工作。像这样:

    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);
    }
    

    它对我来说很好用。这是我的第一个贡献,希望对您有所帮助..

    【讨论】:

    • 我使用的是php框架来测试,所以最后一行的return可能是不必要的..
    • 谢谢!但是当有一个子目录(home/Another_Dir/Sub_Dir/)时,他将文件夹移动到backup.tar.gz文件中的(home/Sub_Dir/),并且他不保持正常的目录格式(home/Another_Dir/Sub_Dir/)。可以解决吗?
    • @GerritHoekstra 我编辑了代码,现在应该修复了。
    • 谢谢,它现在工作得很好! +1 但是当我尝试做一个文件home/file2.html 而不是一个目录时,我得到了这些错误:pastebin.com/scuNLbSv 当检测到文件将其作为文件处理时,是否可以在脚本中进行更改?
    • @GerritHoekstra 刚刚编辑了代码的最后一部分来处理它
    猜你喜欢
    • 2012-11-07
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多