如何防止 mcrypt_encrypt() 无法加密较大的文件


How to prevent mcrypt_encrypt() from failing to encrypt larger file?

我正在尝试使用与此类似的PHP脚本加密上传的文件。它适用于较小的文件,但是当我尝试上传大小为 49.2 MB 的测试文件(按照今天的标准并不大)时,以下导致我的 php 页面通过终止脚本来显示空白页:

$binaryFileData = file_get_contents($serverFilePath);
$binaryEncFile = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $binaryKey, $binaryFileData, MCRYPT_MODE_CBC, $binaryIV);

我在error_log文件中得到一行,上面写着:

PHP 致命错误:允许的内存大小 134217728 字节已耗尽 (尝试分配 51694736 字节) /home2/myaccount/public_html/myfldr/myfile.inc 在第 620 行

在上面的示例中,第 620 行指向mcrypt_encrypt

所以我做了一些研究,人们建议在php.ini文件中添加以下内容:

memory_limit = -1

我做到了,但它仍然导致了相同的结果。

所以我有一个由两部分组成的问题:

  1. 显然,如何防止该异常终止我的脚本?

  2. 有没有办法让该函数返回错误,或者抛出我可以捕获的异常,而不仅仅是终止(并导致向用户显示白/空白页?

我还需要解决上面的第 2 项,以便在加密失败时能够从服务器上删除未加密的文件(如果mcrypt_encrypt简单地终止我的脚本,我显然无法做到这一点。

附言。我需要说我在用BlueHost托管的共享帐户上运行此脚本。

使用

ini_set(“memory_limit”,”640M“);

将内存限制设置为更高的限制。上述内容将限制从128MB增加到640Mb。

如果仍然遇到问题,请使用

realpath_cache_size = 16k
realpath_cache_ttl = 120

请注意,在 php 5.3 及之后,您可以简单地将用户.ini文件(行 memory_limit = 640M)放在 public_html 目录中,但并非所有 cpanel 都允许这样做。

一种可能的解决方法是将文件加密为小块(一次 4128 字节)。

示例代码:

$fr=fopen('input.file','r');
$fw=fopen('output.file','w');
while(!feof($fr))
{
    $buffer=fread($fr,4128);
    $result=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $binaryKey, $buffer, MCRYPT_MODE_CBC, $binaryIV);
    false!==$result && fwrite($fw,$result);
}
fclose($fw);
fclose($fr);

这样,您最终会得到一个加密文件,稍后可以通过反向执行这些步骤来解密该文件。

请注意,块大小 4128 它不是随机选择的。知道 RIJNDAEL 支持 128/192/256 位(即 16/24/32 字节)的块,我确定了这些数字(即 96)之间的 LCM,然后选择了 96 倍的任何块大小(大约 4K)。碰巧4128符合标准。

为什么区块大小很重要?因为 MCrypt 将您的输入文本划分为块大小长度的固定块,如果有提醒,它会用零填充该空间,直到块长度完全除以。所以我们不想让MCrypt这样做,对吧?无论如何,请记住,它会对文件的最后一个块执行此操作(除非您足够幸运,以至于它已经是块大小的倍数。

我希望它有帮助...