Opensubtitles哈希函数对于大文件失败

时间:2017-12-25 12:29:50

标签: php hash

我正在使用下面的函数来计算电影文件的opensubtitles.org哈希值。它主要工作,但有大文件我得到以下错误。

我真的不明白,因为应该总是有数据可用。

任何人都可以指出我正确的方向吗?

  

PHP警告:unpack():输入v:输入不够,需要2,输入0   第169行的file.php

function OpenSubtitlesHash($file)
{
    $handle = fopen($file, "rb");
    $fsize = filesize($file);

    $hash = array(3 => 0, 
                  2 => 0, 
                  1 => ($fsize >> 16) & 0xFFFF, 
                  0 => $fsize & 0xFFFF);

    for ($i = 0; $i < 8192; $i++)
    {
        $tmp = ReadUINT64($handle);
        $hash = AddUINT64($hash, $tmp);
    }

    $offset = $fsize - 65536;
    fseek($handle, $offset > 0 ? $offset : 0, SEEK_SET);

    for ($i = 0; $i < 8192; $i++)
    {
        $tmp = ReadUINT64($handle);
        $hash = AddUINT64($hash, $tmp);         
    }

    fclose($handle);
        return UINT64FormatHex($hash);
}

function ReadUINT64($handle)
{
    $u = unpack("va/vb/vc/vd", fread($handle, 8));
    return array(0 => $u["a"], 1 => $u["b"], 2 => $u["c"], 3 => $u["d"]);
}

function AddUINT64($a, $b)
{
    $o = array(0 => 0, 1 => 0, 2 => 0, 3 => 0);

    $carry = 0;
    for ($i = 0; $i < 4; $i++) 
    {
        if (($a[$i] + $b[$i] + $carry) > 0xffff ) 
        {
            $o[$i] += ($a[$i] + $b[$i] + $carry) & 0xffff;
            $carry = 1;
        }
        else 
        {
            $o[$i] += ($a[$i] + $b[$i] + $carry);
            $carry = 0;
        }
    }

    return $o;   
}

function UINT64FormatHex($n)
{   
    return sprintf("%04x%04x%04x%04x", $n[3], $n[2], $n[1], $n[0]);
}

3 个答案:

答案 0 :(得分:5)

如果您提供了一些额外的信息:系统版本,php版本,大文件大小,文件类型(简单文件,网址等) - 它会提供更多信息以获得准确答案。

主要假设您使用的是32位系统,并且filsize的文件超过2GB时出现问题。来自docs:

  

注意:由于PHP的整数类型已签名且许多平台使用32位整数,因此某些文件系统函数可能会为大于2GB的文件返回意外结果。

您可能得到错误的filesize值,因此无法准确读取尾随字节。 This comment解释了如何获取较大文件的大小,并注意到fseek在内部使用int,因此您无法在2GB阈值之后放置指针。您需要fread到这个位置。

还有其他假设可以检查:

  • fread可以阅读的数据超过某些情况下的要求:
      

    如果流被读缓冲并且它不表示普通文件,则最多读取一个等于块大小(通常为8192)的字节数;根据先前缓冲的数据,返回数据的大小可能大于块大小。

  • stat缓存会阻止您获取准确的文件大小值;

答案 1 :(得分:1)

你永远不会检查你的$ handle是否有任何resoure,当你的$ handle为null或false时你会得到同样的错误

PHP Warning: unpack(): Type v: not enough input, need 2, have 0 in file.php on line 169

因此,在使用$ handle

执行操作之前添加一个检查
if(!is_null($handle)){
  // Do something..
}

答案 2 :(得分:0)

您不需要也不应该计算总文件大小。如果文件大小超过PHP_INT_MAX,那么结果将不准确,

更好的解决方案是使用文件末尾的fseek()

fseek($handle, -65536, SEEK_END);