Открытие изображения в формате JPEG с помощью imagecreatefromjpeg
может привести к фатальным ошибкам, потому что память должна извлекать memory_limit
.
Файл .jpg
размером менее 100 Кбайт может легко превышать 2000х2000 пикселей – при открытии займет около 20-25 МБ памяти. «То же самое изображение 2000x2000px может занимать до 5 МБ на диске с использованием другого уровня сжатия.
Поэтому я, очевидно, не могу использовать размер файла, чтобы определить, можно ли его безопасно открыть.
Как определить, будет ли файл помещаться в памяти перед его открытием, поэтому я могу избежать фатальных ошибок?
Согласно нескольким источникам, требуемая память составляет до 5 байт на пиксель в зависимости от нескольких разных факторов, таких как бит-глубина. Мои собственные тесты подтверждают это примерно так.
Кроме того, есть некоторые накладные расходы, которые необходимо учитывать.
Но, исследуя размеры изображения, которые можно легко сделать без загрузки изображения, мы можем грубо оценить нужную память и сравнить ее с (оценкой) памяти, доступной следующим образом:
$filename = 'black.jpg'; //Get image dimensions $info = getimagesize($filename); //Each pixel needs 5 bytes, and there will obviously be some overhead - In a //real implementation I'd probably reserve at least 10B/px just in case. $mem_needed = $info[0] * $info[1] * 6; //Find out (roughly!) how much is available // - this can easily be refined, but that's not really the point here $mem_total = intval(str_replace(array('G', 'M', 'K'), array('000000000', '000000', '000'), ini_get('memory_limit'))); //Find current usage - AFAIK this is _not_ directly related to //the memory_limit... but it's the best we have! $mem_available = $mem_total - memory_get_usage(); if ($mem_needed > $mem_available) { die('That image is too large!'); } //Do your thing $img = imagecreatefromjpeg('black.jpg');
Это проверяется только поверхностно, поэтому я предлагаю провести дополнительное тестирование с большим количеством разных изображений и использовать эти функции, чтобы проверить правильность расчетов в вашей конкретной среде:
//Set some low limit to make sure you will run out ini_set('memory_limit', '10M'); //Use this to check the peak memory at different points during execution $mem_1 = memory_get_peak_usage(true);