php gzcompress 生成损坏的 .zip 文件
Posted
技术标签:
【中文标题】php gzcompress 生成损坏的 .zip 文件【英文标题】:php gzcompress generates corrupted .zip file 【发布时间】:2017-02-02 08:53:24 【问题描述】:我必须重构一些旧的 php 代码才能将我们的 wiki 更新到 1.28。 我有一个导出插件,它将所选页面保存到字符串中。 此字符串添加到 zip 文件并由 gzcompress 压缩。
我可以下载文件,但是当我尝试打开它时,它说“文件已损坏”。如果我用 winrar 修复存档,我会得到预期的输出文件。我该如何解决才能首先获得正确的 .zip 文件
这可能与我们使用的旧ZipHelper有关,但我实际上不知道那里发生了什么,因为我对php很陌生:
class ZipWriter
function __construct()
var $datasec = array ();
var $ctrl_dir = array ();
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
var $old_offset = 0;
var $filename = "";
var $filepointer;
var $writtenSizeCtrlDir = 0;
var $writtenSizeData = 0;
var $writtenFiles = 0;
var $completeBuffer;
var $stream = false;
function addFile($data, $name, $time = 0)
$name = str_replace('\\', '/', $name);
$dtime = dechex($this->unix2DosTime($time));
$hexdtime = '\x' . $dtime[6] . $dtime[7]
. '\x' . $dtime[4] . $dtime[5]
. '\x' . $dtime[2] . $dtime[3]
. '\x' . $dtime[0] . $dtime[1];
eval('$hexdtime = "' . $hexdtime . '";');
$fr = "\x50\x4b\x03\x04";
$fr .= "\x14\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x08\x00"; // compression method
$fr .= $hexdtime; // last mod time and date
// "local file header" segment
$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzcompress($data);
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
$c_len = strlen($zdata);
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
$fr .= pack('v', strlen($name)); // length of filename
$fr .= pack('v', 0); // extra field length
$fr .= $name;
// "file data" segment
$fr .= $zdata;
// "data descriptor" segment (optional but necessary if archive is not
// served as file)
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
if ($this->stream)
array_push($this->completeBuffer, $fr);
else
// write the compressed data to the zipfile
fputs($this->filepointer, $fr);
// count up the already written data size
$this->writtenSizeData = $this->writtenSizeData + strlen($fr);
//$new_offset = strlen(implode('', $this->datasec));
$new_offset = $this->writtenSizeData;
// now add to central directory record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .= "\x00\x00"; // version made by
$cdrec .= "\x14\x00"; // version needed to extract
$cdrec .= "\x00\x00"; // gen purpose bit flag
$cdrec .= "\x08\x00"; // compression method
$cdrec .= $hexdtime; // last mod time & date
$cdrec .= pack('V', $crc); // crc32
$cdrec .= pack('V', $c_len); // compressed filesize
$cdrec .= pack('V', $unc_len); // uncompressed filesize
$cdrec .= pack('v', strlen($name)); // length of filename
$cdrec .= pack('v', 0); // extra field length
$cdrec .= pack('v', 0); // file comment length
$cdrec .= pack('v', 0); // disk number start
$cdrec .= pack('v', 0); // internal file attributes
$cdrec .= pack('V', 32); // external file attributes - 'archive' bit set
$cdrec .= pack('V', $this->old_offset); // relative offset of local header
$this->old_offset = $new_offset;
$cdrec .= $name;
// save to central directory
$this->ctrl_dir[] = $cdrec;
// count up written files
$this->writtenFiles++;
// end of the 'addFile()' method
【问题讨论】:
【参考方案1】:您混淆了不同的文件格式。 PHP 的 gzcompress
生成 zlib 格式,而您试图将其解释为 .zip 格式的文件,但事实并非如此。
顺便说一句,PHP 中这些函数的名称很糟糕且具有误导性,因为有人可能认为gzcompress
会生成 gzip 格式。 (顺便说一下,这也是 not zip 格式。)但是不,gzcompress
生成 zlib 格式。如果你想要gzip格式,你需要使用gzencode
。如果你想要原始的 deflate 格式,那么你需要使用gzdeflate
。所以三个函数以gz
开头,但只有一个产生gzip格式。
这些都不产生 zip 格式。为此,正如 symcbean 所述,您将使用 ZipArchive class。
【讨论】:
为了完整性....PHP 确实支持 ZIP 扩展名的 ZIP 文件:php.net/manual/en/book.zip.php以上是关于php gzcompress 生成损坏的 .zip 文件的主要内容,如果未能解决你的问题,请参考以下文章
我使用 PHP 的 ZipArchive 创建的 .zip 存档在 Windows 10 上已损坏/无效