Частенько ли приходилось встречать ошибку рода
Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 544328 bytes) in …
Давайте устраним ее раз и навсегда...
При загрузке изображений? Это общая ошибка переполнения памяти, когда скрипт пытается отхватить больше памяти, чем ему положено. Согласитесь – когда такую ошибку видит пользователь – у него останется много вопросов относительно того, что же произошло и что делать теперь. Что и как нужно сделать, чтобы избежать ошибки в дальнейшем? Здесь проблема не столько – почему оно не отработало, сколько – почему программа не могла оповестить об возможном переполнении памяти и не ывзвать исключение. Чтобы если уж не отработало – так дало возможность разработчику написать инструкцию как обойти данную ошибку. А также отменить совершенные операции скриптом,
Решить проблему с обработкой изображений можно просто, если у вас много ресурсов в запасе, просто увеличив ресурсы. Просто даем больше ресурсов.
Пишите
memory_limit = 256M ; в PHP.ini
php_value memory_limit 256M в .HTACCESS
ini_set('memory_limit', '256M');
в исполняемом PHP файле
И память будет выделена скрипту в этих пределах. И все будет хорошо, пока в моду не придут фотоаппараты с 30+ мегаписелями.
Проблема кроится в больших пикселях. Если скопировать заливаемое изображение – скрипт может без проблем, то сжать его – он уже не сможет. На сегодняшний момент не все браузеры умеют сжимать изображения на стороне клиента.
Браузеры аля IE9 – будут еще долго препятствовать этой возможности. (Про мобильный мир пока тоже ничего не скажу)
Но что делать, если ресурсы очень ограничены и хостинг не позволяет управлять выделяемой памятью, давая всего 32…64…128 мб. Обработать изображение мы уже не сможем. Мы можем хотя бы оповестить пользователя, чтобы он сжал изображение у себя на компьютере или через сторонние сервисы и повторил попытку
Если вы думаете, что можно использовать перехватчик ошибок set_error_handler('myErrorHandler');
То вы ошибаетесь, данные ошибки перехватчик не ловит. Давайте поговорим о реальных способах решения.
Мы можем реально отправлять файлы через IFRAME или при помощи AJAX, считывая сообщение об ошибке и переводя его на читаемый для пользователя вид. Метод громоздкий и не универсальный
Мы также можем перед тем, как вгрузить в себя изображение – проверить, а хватит ли памяти на его обработку. Но как? Давайте копать)
Мы знаем сколько памяти выделено на процесс? Конечно. Мы знаем, сколько памяти израсходовано сейчас? Конечно. Мы также опытным путем можем получить число памяти, которое будет использовано после загрузки изображений. Конечно. Вот сколько памяти у нас есть всего:
$limit=return_bytes(ini_get('memory_limit'));
function return_bytes($val) {
$val = trim($val);
$last = $val[strlen($val)-1];
switch($last){
case 'G':
$val *= 1024;
case 'M':
$val *= 1024;
case 'K':
$val *= 1024;
}
return $val;
}
А вот сколько памяти используется сейчас
$m=memory_get_usage();
Опытным путем – для получения количества занимаемым изображением памяти – была получена следующая формула
$usage=($x*$y*5.07)+7900+($y*112);
Сложим все вместе и получим. Искомое число. Можете добавить это во все классы работы с изображением и с легкостью выводить и не брать такого рода изображение. Можно также воспользоваться сторонним сервисом по сжатия без уведомления пользователя. Главное – научить систему разбираться в своей памяти.
Формула была получена опытным путем и является приблизительной, т.к. память в PHPвыделяется большими порциями. Формула может отличаться для очень широких изображений, какие достаточно редки. Но и для них просто запас будет меньше и предупреждение высвечено заранее. В общем пользуйтесь
function memory_test($x,$y){
$val=trim(ini_get('memory_limit'));
$last = $val[strlen($val)-1];
switch($last){
case 'G':
$val *= 1024;
case 'M':
$val *= 1024;
case 'K':
$val *= 1024;
}
$limit=$val;
$m=memory_get_usage();
$usage=($x*$y*5.07)+7900+($y*112)+$m;
return $usage<=$limit;
}
Функция потребляет мало ресурсов и понадобится всегда и везде. Успехов в создании лучших сервисов