2009-08-22 95 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; 
}