2009-08-22 56 views
2

我在服务器端使用Paul Duncans php ZipStream(http://pablotron.org/software/zipstream-php/),用于在Flex/Air客户端实时创建zips以及Fzip(http://codeazur.com.br/lab/fzip/)。Php:如何计算Adler32校验和的zip?

在Air中正常工作,但在浏览器中运行Flex时,zip需要在标题中包含Adler32校验和以便读取FZip。

我该如何计算一个Adler32校验和在zip中的zip?

下面可以看到使用gzdeflate进行压缩的ZipStream核心函数。

问候/纳斯

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

谷歌倒了? – Gumbo 2009-08-22 19:56:18

回答

2

Tanslated从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); 
+0

Thanx,Gumbo! 我会测试它! 乔纳斯 – Cambiata 2009-08-23 06:33:56

2

对于PHP 5> = 5.1.2您可以使用返回crc的十六进制字符串表示的hash函数:

$dataStr = "abc"; 
$crcStr = hash('adler32', $dataStr); 

更新:有一个bug in hash until mid 2009字节顺序是错误的方式。该错误似乎在5.2.11和5.3.0之后得到修复。但对于早期版本,结果的字节顺序将需要交换。

更新2:这里是它可以用来解决这个bug的包装功能(和测试):

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

?> 
1

浓汤的解决方案几乎是完美的 - 但是,如果该参数是一个字符串,而不是一个数组的字节,您需要使用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; 
}