我正在使用下面的函数来计算电影文件的opensubtitles.org哈希值.它主要工作,但有大文件我得到以下错误.
我真的不明白它,因为应该总是有数据可用.
任何人都可以指出我正确的方向吗?
PHP警告:unpack():输入v:输入不够,需要2,在第169行的file.php中有0
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]);
}
Run Code Online (Sandbox Code Playgroud)
如果你提供了一些额外的信息:版本的系统,PHP的版本,大文件大小,文件类型(简单文件,URL等) - 它会给出一个准确的答案更多的信息.
主要假设您使用的是32位系统,而且filsize文件超过2GB时会出现问题.来自docs:
注意:由于PHP的整数类型已签名且许多平台使用32位整数,因此某些文件系统函数可能会对大于2GB的文件返回意外结果.
您可能得到了错误的filesize值,因此无法准确读取尾随字节.此注释解释了如何获取较大文件的大小以及内部fseek使用的注释,int因此您无法在2GB阈值之后放置指针.你需要fread到这个位置.
还有其他假设可以检查:
fread 可以阅读的数据超过某些情况下的要求:
如果流被读缓冲并且它不表示普通文件,则最多读取一个等于块大小(通常为8192)的字节数; 取决于先前缓冲的数据,返回数据的大小可能大于块大小.
stat 缓存阻止您获得准确的文件大小值;小智 1
你永远不会检查你的 $handle 是否有任何资源,当你的 $handle 为 null 或 false 时,你会得到相同的错误
PHP Warning: unpack(): Type v: not enough input, need 2, have 0 in file.php on line 169
Run Code Online (Sandbox Code Playgroud)
因此,在使用 $handle 执行某些操作之前添加一个检查
if(!is_null($handle)){
// Do something..
}
Run Code Online (Sandbox Code Playgroud)