2010-06-05 5 views
4

PHP의 crc32 지원 문자열은 input.And로, 파일의 경우 아래 코드는 OFC를 사용합니다.큰 파일의 crc32 찾는 법?

crc32(file_get_contents("myfile.CSV")); 

파일이 커지면 (2GB) 메모리 부족이 발생할 수 있습니다. 치명적인 오류입니다.

거대한 파일의 체크섬을 찾는 방법은 무엇입니까? 를 계산하기

사용자 공헌 노트에
$hash = hash_file('crc32b',"myfile.CSV"); 

답변

0

This functioncrc32()에 대한 주장 :

+0

crc32를 계산할 외부 도구를 알고 있습니까? 나는 리눅스에있다. (Debian Flavor.) – Arshdeep

+3

여기에 대한 소스 코드 : http://www.csbruce.com/~csbruce/software/crc32.c – zaf

+3

@zaf - 멋지게 일했다 ** 별 ** – Arshdeep

5

PHP 2 기가 바이트 (32 비트 제한)

그리고 파일의 CRC32를 계산하는보다 효율적인 방법보다 더 큰 파일을 지원하지 않습니다 값을 전체 파일을로드하지 않고. 제대로 작동하면 메모리 문제가 없어야합니다.

2GB보다 큰 파일의 경우 지금 당장 발생하는 32 비트 제한으로 중단 될 가능성이 있습니다.

가능한 경우 파일 크기가 가장 큰 파일의 체크섬을 계산할 수있는 외부 도구를 호출합니다.

+0

오 좋아하면 편집이 친구 :) – Arshdeep

+0

주셔서 감사합니다 한번 더 편집 -'crc32b'은 대부분의 경우 올바른 해시 알고리즘입니다. –

0

dev-null-dweller 님의 답변은 갈 길입니다.

  • 그것은 지금 정확히 hash_file()
  • 보다 동일한 결과를 제공합니다

    그러나 hash_file('crc32b', $filename);의 메모리 효율적인 PHP4의 백 포트를 찾고있는 사람들을 위해, 여기에 몇 가지 개선과 this PHP manual comment 기반으로하는 솔루션이며,

  • 32 비트 & 64 비트 아키텍처를 지원합니다.

경고 : 개는 추합니다. 개선하려고 노력 중입니다.

참고 : 저는 zaf의 주석에서 C 소스 코드를 기반으로 한 솔루션을 시도했지만 PHP로 이식하기에 충분히 신속하게 성공하지 못했습니다.

if (!function_exists('hash_file')) 
{ 
    define('CRC_BUFFER_SIZE', 8192); 

    function hash_file($algo, $filename, $rawOutput = false) 
    { 
     $mask32bit = 0xffffffff; 

     if ($algo !== 'crc32b') 
     { 
      trigger_error("Unsupported hashing algorightm '".$algo."'", E_USER_ERROR); 
      exit; 
     } 

     $fp = fopen($filename, 'rb'); 

     if ($fp === false) 
     { 
      trigger_error("Could not open file '".$filename."' for reading.", E_USER_ERROR); 
      exit; 
     } 

     static $CRC32Table, $Reflect8Table; 
     if (!isset($CRC32Table)) 
     { 
      $Polynomial = 0x04c11db7; 
      $topBit = 1 << 31; 

      for($i = 0; $i < 256; $i++) 
      { 
       $remainder = $i << 24; 
       for ($j = 0; $j < 8; $j++) 
       { 
        if ($remainder & $topBit) 
         $remainder = ($remainder << 1)^$Polynomial; 
        else 
         $remainder = $remainder << 1; 

        $remainder &= $mask32bit; 
       } 

       $CRC32Table[$i] = $remainder; 

       if (isset($Reflect8Table[$i])) 
        continue; 
       $str = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); 
       $num = bindec(strrev($str)); 
       $Reflect8Table[$i] = $num; 
       $Reflect8Table[$num] = $i; 
      } 
     } 

     $remainder = 0xffffffff; 
     while (!feof($fp)) 
     { 
      $data = fread($fp, CRC_BUFFER_SIZE); 
      $len = strlen($data); 
      for ($i = 0; $i < $len; $i++) 
      { 
       $byte = $Reflect8Table[ord($data[$i])]; 
       $index = (($remainder >> 24) & 0xff)^$byte; 
       $crc = $CRC32Table[$index]; 
       $remainder = (($remainder << 8)^$crc) & $mask32bit; 
      } 
     } 

     $str = decbin($remainder); 
     $str = str_pad($str, 32, '0', STR_PAD_LEFT); 
     $remainder = bindec(strrev($str)); 
     $result = $remainder^0xffffffff; 
     return $rawOutput ? strrev(pack('V', $result)) : dechex($result); 
    } 
} 
+0

이것은 흥미 롭습니다. 파일 블록을 네이티브 crc32() 메서드를 사용하여 블록 해시하는 방법이 있어야합니다. crc16 함수 (오래 전), crc16 (data.crc16 (data)) == 0x0000을 구현 한 것을 기억합니다. 마지막 블록의 crc32를 얻기 위해 다음 블록 앞에 어떤 데이터를 넣을지 추측 할 수 있다면 잘 할 수 있습니다. 즉, crc32 (x) = crc32 (block1), 그런 다음 crc32 (block1.block2) = crc32 (x.block2)와 같이 crc32 (block1)에서 32 비트 값 x를 효율적으로 계산할 수 있습니다. 이것이 가능할 수 있는지 누구나 알고 있습니까? –

+0

더 나은 점은 crc32_combine()과 같은 crc32_combine() 함수를 생각해 볼 수 있다고 생각하는 [this post] (http://php.net/manual/en/function.crc32.php#100060)입니다. crc32_combine (crc32 (block1), crc32 (block2)) = crc32 (block1.block2). 불행하게도 원래의 게시물은 사라졌습니다.오픈 소스 Zlib에는 crc32_combine()이 구현되어 있습니다. 나는 이것을 파헤 치려고 노력할 것이다. –