«Знание — могущество».

14 мая 2009

2 PHP-функции для работы с изображениями

написал Figaroo в рубрике Web-разработка @ 12:44

Представляю Вашему вниманию 2 полезных PHP-функции для работы с картинками.
Одна из них позволяет пропорционально уменьшать размеры картинки, вторая — проверять картинку на валидность (защита от XSS-атак).

Исходники под катом.

Пропорциональное уменьшение размеров изображения:

<?php

/** Универсальный ресайз картинок
  *
  * Функция позволяет копировать изображение,
  * оставляя его исходные характеристики или
  * изменяя его размер и/или качество.
  * При изменении размера сохраняются пропорции.
  *
  * Функция умеет работать с изображениями
  * следующих форматов: JPG, PNG, GIF.
  *
  * Параметры:
  * @ $from		- путь к изображению, над которым будут выполняться операции
  * @ $to		- путь к результирующему изображению
  * @ $maxwidth	- максимальная ширина изображения
  * @ $maxheight	- максимальная высота изображения
  * @ $quality	- качество картинки (0..100) (для JPG и PNG)
  *
  * Возвращаемые значения:
  * false	- во время выполнения произошла ошибка
  * true	- функция выполнилась успешно и без ошибок
  *
  * Автор:
  * @name	Валерий 'Figaroo' Киркиж
  * @url	http://blogfigaroo.ru/
  * @email	mail@figaroo.ru
*/
function figaroo_resize_image ($from, $to, $maxwidth, $maxheight, $quality = 80) {
		// защита от Null-байт уязвимости PHP
		$from = preg_replace('/\0/uis', '', $from);
		$to = preg_replace('/\0/uis', '', $to);

		// информация об изображении
		$imageinfo = @getimagesize($from);
		// если получить информацию не удалось - ошибка
		if (!$imageinfo) return false;
		// получаем параметры изображения
		$width = $imageinfo[0];		// ширина
		$height = $imageinfo[1];	// высота
		$format = $imageinfo[2];	// ID формата (число)
		$mime = $imageinfo['mime'];	// mime-тип

		// определяем формат и создаём изображения
		switch ($format) {
			case 2: $img = imagecreatefromjpeg($from); break;	// jpg
			case 3: $img = imagecreatefrompng($from); break;	// png
			case 1: $img = imagecreatefromgif($from); break;	// gif
			default: return false; break;
		}
		// если создать изображение не удалось - ошибка
		if (!$img) return false;

		// меняем размеры изображения
		$newwidth = $newheight = 0;
		// требуется квадратная картинка
		if ($maxwidth == $maxheight) {
			// размеры картинки больше по X и по Y
			if ($width > $maxwidth && $height > $maxheight) {
				// пропорции картинки одинаковы
				if ($width == $height) {
					$newwidth = $maxwidth;
					$newheight = $maxheight;
				}
				// ширина больше
				elseif ($width > $height) {
					$newwidth = $maxwidth;
					$newheight = intval(((float)$newwidth / (float)$width) * $height);
				}
				// высота больше
				else {
					$newheight = $maxheight;
					$newwidth = intval(((float)$newheight / (float)$height) * $width);
				}
			}
			// размеры картинки больше только по X
			elseif ($width > $maxwidth) {
				$newwidth = $maxwidth;
				$newheight = intval(((float)$newwidth / (float)$width) * $height);
			}
			// размеры картинки больше только по Y
			elseif ($height > $maxheight) {
				$newheight = $maxheight;
				$newwidth = intval(((float)$newheight / (float)$height) * $width);
			}
			// в остальных случаях ничего менять не надо
			else {
				$newwidth = $width;
				$newheight = $height;
			}
		}
		// требуется горизонтальная картинка
		elseif ($maxwidth > $maxheight) {
			// размеры картинки больше по X и по Y
			if ($width > $maxwidth && $height > $maxheight) {
				// ширина больше
				if ($width > $height) {
					$newwidth = $maxwidth;
					$newheight = intval(((float)$newwidth / (float)$width) * $height);
				}
				// высота больше или равна ширине
				else {
					$newheight = $maxheight;
					$newwidth = intval(((float)$newheight / (float)$height) * $width);
				}
			}
			// размеры картинки больше только по X
			elseif ($width > $maxwidth) {
				$newwidth = $maxwidth;
				$newheight = intval(((float)$newwidth / (float)$width) * $height);
			}
			// размеры картинки больше только по Y
			elseif ($height > $maxheight) {
				$newheight = $maxheight;
				$newwidth = intval(((float)$newheight / (float)$height) * $width);
			}
			// в остальных случаях ничего менять не надо
			else {
				$newwidth = $width;
				$newheight = $height;
			}
		}
		// требуется вертикальная картинка
		elseif ($maxwidth < $maxheight) {
			// размеры картинки больше по X и по Y
			if ($width > $maxwidth && $height > $maxheight) {
				// ширина больше или равна высоте
				if ($width >= $height) {
					$newwidth = $maxwidth;
					$newheight = intval(((float)$newwidth / (float)$width) * $height);
				}
				// высота больше
				else {
					$newheight = $maxheight;
					$newwidth = intval(((float)$newheight / (float)$height) * $width);
				}
			}
			// размеры картинки больше только по X
			elseif ($width > $maxwidth) {
				$newwidth = $maxwidth;
				$newheight = intval(((float)$newwidth / (float)$width) * $height);
			}
			// размеры картинки больше только по Y
			elseif ($height > $maxheight) {
				$newheight = $maxheight;
				$newwidth = intval(((float)$newheight / (float)$height) * $width);
			}
			// в остальных случаях ничего менять не надо
			else {
				$newwidth = $width;
				$newheight = $height;
			}
		}

		// если изменений над картинкой производить не надо - просто копируем её
		if ($newwidth == $width && $newheight == $height && $quality == 80) {
			if (copy($from, $to)) return true;
			else return false;
		}

		// создаём новое изображение
		$new = imagecreatetruecolor($newwidth, $newheight);
		$black = imagecolorallocate($new, 0, 0, 0);
		$white = imagecolorallocate($new, 255, 255, 255);
		// копируем старое в новое с учётом новых размеров
		imagefilledrectangle($new, 0, 0, $newwidth - 1, $newheight - 1, $white);
		//imagecolortransparent($new, $white);
		imagecopyresampled($new, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
		// создаём файл с новым изображением
		switch ($format) {
			case 2: // jpg
				if ($quality < 0) $quality = 0;
				if ($quality > 100) $quality = 100;
				imagejpeg($new, $to, $quality);
			break;
			case 3: // png
				$quality = intval($quality * 9 / 100);
				if ($quality < 0) $quality = 0;
				if ($quality > 9) $quality = 9;
				imagepng($new, $to, $quality);
			break;
			case 1: // gif
				imagegif($new, $to);
			break;
		}
		return true;
}

?>

Проверка на валидность:

<?php

// функция проверки изображения на валидность (защита от XSS-атак)
function verify_image ($file) {
	// защита от Null-байт уязвимости PHP
	$file = preg_replace('/\0/uis', '', $file);
	// проверка изображения
	$txt = file_get_contents($file);
	if (preg_match('#&(quot|lt|gt|nbsp|amp);#i', $txt)) return false;
	elseif (preg_match("#&\#x([0-9a-f]+);#i", $txt)) return false;
	elseif (preg_match('#&\#([0-9]+);#i', $txt)) return false;
	elseif (preg_match("#([a-z]*)=([\`\'\"]*)script:#iU", $txt)) return false;
	elseif (preg_match("#([a-z]*)=([\`\'\"]*)javascript:#iU", $txt)) return false;
	elseif (preg_match("#([a-z]*)=([\'\"]*)vbscript:#iU", $txt)) return false;
	elseif (preg_match("#(<[^>]+)style=([\`\'\"]*).*expression[^>]*>#iU]+)style=([\`\'\"]*).*behaviour" />[^>]*>#iU", $txt)) return false;
	elseif (preg_match("#</*(applet|link|style|script|iframe|frame|frameset)[^>]*>#i", $txt)) return false;
	return true;
}

?>

Скачать архив с исходником: figaroo_image_functions_1.rar.

Комментарии (5) »

  1. 1. функция проверки на валидность совместима с utf-8 ?
    2. отлавливает ли она xss если он в utf-7 написан ?

    Комментарий by snewsbot — 26 октября 2009 @ 16:18


  2. 1. Да.
    2. Должна.

    Комментарий by Figaroo — 26 октября 2009 @ 19:29


  3. тестировал сидел,вроде всё отлавливает =),
    спасибо,за статью.

    Комментарий by snewsbot — 26 октября 2009 @ 22:19


  4. Спасибо =)

    Комментарий by Figaroo — 30 октября 2009 @ 20:54


  5. я бы добавил чуть-чуть в функцию проверки файла на содержимое-картику...

    $txt = file_get_contents($file);
    if (!$txt) return false;

    это нужно в случае использования урлов в качестве исходника, но не обязательно. просто дальнейшие проверки бессмысленны, если это битая изначально ссылка.

    Комментарий by bvn13 — 18 мая 2010 @ 22:37


RSS-лента комментариев к этой записи

Оставить комментарий

Пожалуйста, заполните все поля.

© Валерий 'Figaroo' Киркиж, 2008-2012 гг.