2009-08-22 15 views
2

Ich benutze eine Kombination von Paul Duncans PHP ZipStream (http://pablotron.org/software/zipstream-php/) auf der Server-Seite, für die direkte Erstellung von Zips und Fzip (http://codeazur.com.br/lab/fzip/) auf der Flex/Air-Client-Seite.Php: Wie berechnet man Adler32 Prüfsumme für zip?

Funktioniert gut in Air, aber wenn Sie Flex im Browser ausführen, muss die Zip-Datei eine Adler32-Prüfsumme in der Kopfzeile enthalten, damit FZip gelesen werden kann.

Wie kann ich eine Adler32 Prüfsumme für die ZIP in PHP berechnen?

Die ZipStream-Kernfunktionen, die gzdeflate zur Komprimierung verwenden, sind unten zu sehen.

Grüße/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

Ist Google down? – Gumbo

Antwort

2

Tanslated vom 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; 
} 

Und das Integer-Wert zu Bytes konvertieren:

pack('H*', $checksum); 
+0

Danke, Gumbo! Ich werde es testen! Jonas – Cambiata

2

Für PHP 5> = 5.1.2 Sie können die hash-Funktion verwenden, die eine hexadezimale Zeichenfolgendarstellung des crc zurückgibt:

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

UPDATE: Es gab eine bug in hash until mid 2009 wo die Byte-Reihenfolge um den falschen Weg war. Der Fehler scheint in 5.2.11 und 5.3.0 behoben zu sein. Aber für frühere Versionen muss die Byte-Reihenfolge des Ergebnisses getauscht werden.

UPDATE 2: Hier ist eine Wrapper-Funktion (und ein Test), die um diesen Fehler zu arbeiten, verwendet werden könnten:

<?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

Gumbo-Lösung ist fast perfekt - aber wenn der Parameter ist eine Zeichenfolge anstelle eines Arrays von Bytes müssen Sie ord() verwenden, um den ASCII-Code des zu verarbeitenden Zeichens zu erhalten. Gefällt mir:

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; 
} 
Verwandte Themen