Я пытаюсь зашифровать загруженный файл с помощью PHP-скрипта, подобного этому. Он отлично работает с меньшими файлами, но когда я пытаюсь загрузить тестовый файл размером 49,2 МБ (что не так уж важно по сегодняшним стандартам), следующая причина: моя страница 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
Что я и сделал, но это все равно привело к тому же результату.
Поэтому у меня есть вопрос из двух частей:
Очевидно, как предотвратить исключение этого исключения из моего сценария?
Есть ли способ заставить эту функцию возвращать ошибку или вызывать исключение, которое я могу уловить, а не просто завершать (и в результате получается белая/пустая страница, отображаемая пользователю?)
Мне нужно также разрешить пункт 2 выше, чтобы удалить незашифрованный файл с сервера, если сбой шифрования (что я, очевидно, не могу сделать, если mcrypt_encrypt
просто завершает мой скрипт.
PS. Мне нужно сказать, что я запускаю этот скрипт в общей учетной записи, размещенной в BlueHost.
использование
ini_set("memory_limit","640M");
Чтобы установить предел памяти на более высокий предел. Приведенное выше увеличивает лимит с вашего 128MB до 640Mb.
Если вы все еще сталкиваетесь с проблемами, используйте
realpath_cache_size = 16k
realpath_cache_ttl = 120
Обратите внимание, что в php 5.3 и после того, как вы можете просто поместить файл user.ini (с линией памяти_limit = 640M) в каталог public_html, но это не разрешено всеми cpanels.
ini_set
имеет эффект, а его изменение через php.ini
- нет?
Одним из возможных способов решения проблемы было бы зашифровать файл небольшими кусками (например, 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 байта), я определил LCM между этими номерами (это 96), а затем я выбрал любой размер блока (около 4K), который кратен 96 Случилось так, что 4128 соответствовали критериям.
Почему размер куска важен? Поскольку MCrypt делит ваш входной текст на фиксированные блоки длины вашего блока и, если есть напоминание, он заполняет это пространство нулями до тех пор, пока длина блока не разделится точно. Поэтому мы не хотим, чтобы MCrypt мог это сделать, правильно? Во всяком случае, имейте в виду, что он сделает это для последнего блока вашего файла (если вам не повезет, так что он уже кратен вашему размеру блока.
Я надеюсь, что это помогает...
mcrypt_get_iv_size
, например: $cipher_block_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
mcrypt_encrypt
бесполезна, не так ли? Кроме того, мне любопытно, поскольку загрузка всего файла в ОЗУ и его шифрование может быть плохой идеей, есть ли способ сделать это блок за блоком? Или, другими словами, путем чтения, шифрования и записи небольших фрагментов файла, по одному за раз.