我在服务器端使用Paul Duncans php ZipStream(http://pablotron.org/software/zipstream-php/)的组合,用于动态创建拉链,并在Flex / Air上使用Fzip(http://codeazur.com.br/lab/fzip/)客户方。
在Air中运行良好,但在浏览器中运行Flex时,zip需要在标题中包含Adler32校验和,以便读取FZip。
如何计算php中zip的Adler32校验和?
使用gzdeflate进行压缩的ZipStream核心功能如下所示。
问候/ Jonas
function add_file($name, $data, $opt = array(), $deflateLevel=0) {
# compress data
$zdata = gzdeflate($data, $deflateLevel);
# calculate header attributes
$crc = crc32($data);
$zlen = strlen($zdata);
$len = strlen($data);
$meth = 0x08;
# send file header
$this->add_file_header($name, $opt, $meth, $crc, $zlen, $len);
# print data
$this->send($zdata);
}
private function add_file_header($name, $opt, $meth, $crc, $zlen, $len) {
# strip leading slashes from file name
# (fixes bug in windows archive viewer)
$name = preg_replace('/^\\/+/', '', $name);
# calculate name length
$nlen = strlen($name);
# create dos timestamp
$opt['time'] = $opt['time'] ? $opt['time'] : time();
$dts = $this->dostime($opt['time']);
# build file header
$fields = array( # (from V.A of APPNOTE.TXT)
array('V', 0x04034b50), # local file header signature
array('v', (6 << 8) + 3), # version needed to extract
array('v', 0x00), # general purpose bit flag
array('v', $meth), # compresion method (deflate or store)
array('V', $dts), # dos timestamp
array('V', $crc), # crc32 of data
array('V', $zlen), # compressed data length
array('V', $len), # uncompressed data length
array('v', $nlen), # filename length
array('v', 0), # extra data len
);
# pack fields and calculate "total" length
$ret = $this->pack_fields($fields);
$cdr_len = strlen($ret) + $nlen + $zlen;
# print header and filename
$this->send($ret . $name);
# add to central directory record and increment offset
$this->add_to_cdr($name, $opt, $meth, $crc, $zlen, $len, $cdr_len);
}
答案 0 :(得分:2)
来自example implementation in the Wikipedia article:
的翻译define('MOD_ADLER', 65521);
function adler32($data) {
$a = 1; $b = 0; $len = strlen($data);
for ($index = 0; $index < $len; ++$index) {
$a = ($a + $data[$index]) % MOD_ADLER;
$b = ($b + $a) % MOD_ADLER;
}
return ($b << 16) | $a;
}
并将该整数值转换为字节:
pack('H*', $checksum);
答案 1 :(得分:2)
对于PHP 5&gt; = 5.1.2,您可以使用hash函数返回crc的十六进制字符串表示形式:
$dataStr = "abc";
$crcStr = hash('adler32', $dataStr);
更新:有bug in hash until mid 2009字节顺序错误的方式。该错误似乎在5.2.11和5.3.0之后修复。但是对于早期版本,需要交换结果的字节顺序。
更新2:这是一个包装函数(和测试),可用于解决该错误:
<?php
error_reporting(E_ALL);
function hash_adler32_wrapper($data) {
$digHexStr = hash("adler32", $data);
// If version is better than 5.2.11 no further action necessary
if (version_compare(PHP_VERSION, '5.2.11', '>=')) {
return $digHexStr;
}
// Workaround #48284 by swapping byte order
$boFixed = array();
$boFixed[0] = $digHexStr[6];
$boFixed[1] = $digHexStr[7];
$boFixed[2] = $digHexStr[4];
$boFixed[3] = $digHexStr[5];
$boFixed[4] = $digHexStr[2];
$boFixed[5] = $digHexStr[3];
$boFixed[6] = $digHexStr[0];
$boFixed[7] = $digHexStr[1];
return implode("", $boFixed);
}
// Test fixture, plus expected output generated using the adler32 from zlib
$data_in = "abc";
$expected_out = 0x024d0127;
// PHP's hash function returns a hex hash value as a string so hexdec used to
// convert to number
$hash_out = hexdec(hash("adler32", $data_in));
// Get value via the wrapper function
$wrapper_out = hexdec(hash_adler32_wrapper($data_in));
printf("data_in: %s\n", $data_in);
printf("expected_out: 0x%08x\n", $expected_out);
printf("builtin hash out: 0x%08x, %s\n", $hash_out,
($hash_out == $expected_out)? "OK" : "NOT OK");
printf("wrapper func out: 0x%08x, %s\n", $wrapper_out,
($wrapper_out == $expected_out)? "OK" : "NOT OK");
?>
答案 2 :(得分:1)
Gumbo的解决方案几乎是完美的 - 但如果参数是字符串而不是字节数组,则需要使用ord()来获取要处理的字符的ascii代码。像这样:
function adler32($data) {
$a = 1; $b = 0; $len = strlen($data);
for ($index = 0; $index < $len; ++$index) {
$a = ($a + ord($data[$index])) % 65521;
$b = ($b + $a) % 65521;
}
return ($b << 16) | $a;
}