Php: zip için Adler32 sağlama nasıl hesaplanır?

3 Cevap php

Ben Flex fermuarlar on-the-fly yaratılması için, sunucu tarafında Paul Duncans php ZipStream (http://pablotron.org/software/zipstream-php/) bir arada kullanarak ve Fzip (http://codeazur.com.br/lab/fzip/) değilim / Hava istemci tarafı.

Air iyi çalışır, ancak tarayıcıda Flex çalışırken, zip FZip okunacak için başlığında bir Adler32 sağlama dahil etmek gerekiyor.

Nasıl php zip için bir Adler32 sağlama hesaplayabilirsiniz?

Sıkıştırma için gzdeflate kullanarak ZipStream çekirdek fonksiyonları, aşağıda görülebilir.

Saygılar / 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);
}

3 Cevap

example implementation in the Wikipedia article dan Tanslated:

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

Ve bayt bu tamsayı değeri dönüştürmek için:

pack('H*', $checksum);

PHP 5 için> = Eğer ÇHS bir onaltılık dize temsilini döndürür hash işlevini kullanabilirsiniz 5.1.2:

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

GÜNCELLEME: Bir bug in hash until mid 2009 bayt sırası yanlış bir yol etrafında nerede oldu. Bug 5.2.11 sabit ve itibaren 5.3.0 görünüyor. Ama daha önceki sürümleri için sonuç bayt sırası takas gerekir.

GÜNCELLEME 2: İşte o hata bir çözüm için kullanılabilecek bir sarıcı işlevi (ve bir test) bulunuyor:

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

?>

Gumbo çözümü neredeyse mükemmel - ama parametre yerine bir bayt dizisi bir dize ise, işlemek karakterin ASCII kodu almak için) (ord kullanmanız gerekir. Bu gibi:

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