Загрузка изображений с изменением размера

Немного теории
Вы не можете сразу загрузить файл в свою папку. Вначале он загружается во временную директорию сервера, а затем обрабатывается с помощью PHP интерпритатора. По окончанию сессии временный файл автоматически удаляется. То есть, мы вначале забрасываем файл во временную папку, а затем перекладываем в нужную.


$_FILES это массив загруженных файлов. Он имеет параметры (на примере файла picture):

$_FILES[' picture ']['name'] – настоящее имя файла. Например: image.jpg.

$_FILES[' picture ']['size'] – размер файла в байтах.

$_FILES[' picture ']['type'] – MIME-тип загруженного файла. Например: image/gif, image/png, image/jpeg.

$_FILES[' picture ']['tmp_name'] – содержит имя файла во временном каталоге, например: /tmp/phpV3b3qY. Именно этот параметр и используется для перемещения файлов после загрузки.

$_FILES[' picture ']['error'] – код ошибки.

Подготовка
Для начала нам нужна форма для загрузки. Возьмём простейшую форму.
<form enctype="multipart/form-data" method="post">
<input name="picture" type="file" />
<input type="submit" value="Загрузить" />
</form>

Параметр enctype="multipart/form-data" обязателен для такой формы. Тег <input type="file" name="picture"> отвечает за поле для ввода имени файла, который загружается на сервер.

Также нам потребуется обработчик события – загрузки файла. Вначале у нас будет одна настройка – путь сохранения изображения. Можно указывать как прямой, так и относительный путь. В случае POST запроса обработчик попробует осуществить загрузку файла по указанному пути. Скрипт сообщит о результате загрузки – удачна она или нет.
<?php
 
$path = 'i/';
 
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
if (!@copy($_FILES['picture']['tmp_name'], $path . $_FILES['picture']['name']))
echo 'Что-то пошло не так';
else
echo 'Загрузка удачна';
}
 
?>

Функция copy, как вы наверно догадались, отвечает за копирование файла из одного место в другое. Мы копируем файл из временной папки сервера в нужную, сохранив имя файла.

Договоримся, что и форма и её обработчик будут находиться в одном файле – upload.php.

Итого имеем простой, но рабочий скрипт. Его можно забросить на хостинг, создать папку i и потренироваться с загрузкой файлов.
<?php
 
// Путь загрузки
$path = 'i/';
 
// Обработка запроса
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
// Загрузка файла и вывод сообщения
if (!@copy($_FILES['picture']['tmp_name'], $path . $_FILES['picture']['name']))
echo 'Что-то пошло не так';
else
echo 'Загрузка удачна';
}
 
?>

<!DOCTYPE HTML PUBLIC  "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Загрузка изображения с изменением размеров</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<h1>Загрузка изображения с изменением размеров</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="picture">
<input type="submit" value="Загрузить">
</form>
</body>
</html>


Проверки
Любая форма представляет для сайта опасность. И особенно форма загрузки файлов. Злоумышленник может загрузить скрипт и выполнить его на сервере. Поэтому необходимо озаботиться безопасностью.

Самые простые и обязательные проверки – на размер и тип файла. Для этого укажем допустимые типы и размер.

Тип файла укажем в виде массива:
$types = array('image/gif', 'image/png', 'image/jpeg');

а размер файла в байтах:
$size = 1024000;
Проверяем тип файла. В случае недопустимого типа прекращаем работу скрипта и выводим соответствующее уведомление. Функция in_array проверяет присутствие значения в массиве.
// Проверяем тип файла
if (!in_array($_FILES['picture']['type'], $types))
die('Запрещённый тип файла. <a href="?">Попробовать другой файл?</a>');

Проверяем размер файла. В случае недопустимого размера прекращаем работу скрипта и выводим соответствующее уведомление.
// Проверяем размер файла
if ($_FILES['picture']['size'] > $size)
die('Слишком большой размер файла. <a href="?">Попробовать другой файл?</a>');


Итого получаем такой скрипт. Скрипт рабочий, можно баловаться. Немного забегая вперёд, добавим также параметр $tmp_path – путь к папке временных файлов.
<?php
 
// Пути загрузки файлов
$path = 'i/';
$tmp_path = 'tmp/';
// Массив допустимых значений типа файла
$types = array('image/gif', 'image/png', 'image/jpeg');
// Максимальный размер файла
$size = 1024000;
 
// Обработка запроса
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
// Проверяем тип файла
if (!in_array($_FILES['picture']['type'], $types))
die('Запрещённый тип файла. <a href="?">Попробовать другой файл?</a>');
 
// Проверяем размер файла
if ($_FILES['picture']['size'] > $size)
die('Слишком большой размер файла. <a href="?">Попробовать другой файл?</a>');
 
// Загрузка файла и вывод сообщения
if (!@copy($_FILES['picture']['tmp_name'], $path . $_FILES['picture']['name']))
echo 'Что-то пошло не так';
else
echo 'Загрузка удачна <a href="$path . $_FILES['picture']['name'] . '">Посмотреть</a> ' ;
}
 
?>

<!DOCTYPE HTML PUBLIC  "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Загрузка изображения с изменением размеров</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<h1>Загрузка изображения с изменением размеров</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="picture">
<input type="submit" value="Загрузить">
</form>
</body>
</html>

Изменение размеров
Приступим к самому интересному. К изменению параметров изображения. Для этого напишем функцию resize. Сделаем также возможным изменять качество изображения и поворачивать его.

Размер изображения будем подставлять исходя из параметра. Это будет либо эскиз ($type = 1), либо большое изображение ($type = 2).

Итак, шапка функции у нас получилась такая:
function resize($file, $type = 1, $rotate = null, $quality = null)

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

Устанавливаем ограничение размера изображения по ширине. Функцию можно сделать более абстрактной, если задавать эти значения в параметрах, а также сделать возможным ограничение и по высоте. Однако в данном случае нам не нужна такая универсальность.
$max_thumb_size = 200;
$max_size = 800;

Устанавливаем качество изображения по умолчанию (при $quality = null) равным 75%.
if ($quality == null)
$quality = 75;

Далее создаём изображение для дальнейших преобразований. Для создания используем функцию в зависимости от типа файла (jpg, png или gif). Функции создания называются очень лаконично imagecreatefrom + тип файла.
if ($file['type'] == 'image/jpeg')
$source = imagecreatefromjpeg ($file['tmp_name']);
elseif ($file['type'] == 'image/png')
$source = imagecreatefrompng ($file['tmp_name']);
elseif ($file['type'] == 'image/gif')
$source = imagecreatefromgif ($file['tmp_name']);
else
return false;

Если указан параметр $rotate, выполняем поворот изображения. Делаем это с помощью функции rotate(), параметрами которой являются: изображение, градусы, фон изображения для закрашивания пустых областей, образованных при повороте. Для того чтобы пустые области не возникали, поворачиваем изображение на угол в 90, 180, 270 градусов.
if ($rotate != null)
$src = imagerotate($source, $rotate, 0);

Далее определяем высоту и ширину изображения с помощью функций imagesx и imagesy.
$w_src = imagesx($src);
$h_src = imagesy($src);

В зависимости от типа (эскиз или большое изображение) устанавливаем ограничение по ширине.
if ($type == 1)
$w = $max_thumb_size;
elseif ($type == 2)
$w = $max_size;

Далее, если ширина изображения больше максимальной, проводим преобразования. Иначе просто сохраняем изображение и очищаем память. Сохраняем изображение с помощью функции imagejpeg. В данном примере, рассмотрено сохранение только в формате jpg, однако функционал всегда можно расширить. Удаляем изображения из памяти с помощью функции imagedestroy.

В качестве результата работы функции возвращаем имя файла. Оно нам ещё понадобится.
if ($w_src > $w)
{
// преобразования
}
else
{
imagejpeg($src, $tmp_path . $file['name'], $quality);
imagedestroy($src);
 
return $file['name'];
}

Вернёмся к преобразованию. Вначале вычисляем пропорции изображения и размеры преобразованного изображения.
$ratio = $w_src/$w;
$w_dest = round($w_src/$ratio);
$h_dest = round($h_src/$ratio);

Далее создаём пустую картинку (функция imagecreatetruecolor) с шириной и высотой, полученными на прошлом шаге.
$dest = imagecreatetruecolor($w_dest, $h_dest);

И копируем исходное изображение ($src) в только что созданное ($dest), изменяя его размеры. Функция imagecopyresampled делает это с пересэмплированием, что улучшает качество.
imagecopyresampled($dest, $src, 0, 0, 0, 0, $w_dest, $h_dest, $w_src, $h_src);

И наконец, сохраняем полученное изображение и очищаем память.
imagejpeg($src, $tmp_path . $file['name'], $quality);
imagedestroy($dest);
imagedestroy($src);

Итого, функция получает исходное изображение и параметры преобразования, выполняет преобразования, сохраняет полученный файл во временную папку и возвращает имя изображения. Теперь нам осталось только переложить файл в конечную папку.

Отвечу заранее на вопрос «Почему мы не можем сразу положить изменённый файл в конечную папку?». Можем. Однако не делаем для увеличения глубины абстракции, то есть, чтобы придать определённую универсальность функции. Вы же сможете её использовать на разных сайтах.

Совсем забыл. Добавляем в начало функции строку:
global $tmp_path;

Она обозначает, что в функции будет использована глобальная переменная $tmp_path – путь к временной папке.

Вызов функции
Функцию нужно вызывать сразу после проверок. А также следует изменить ту часть скрипта, где мы копируем изображение в конечную папку. Вы ведь теперь работаем с новым изображением. Теперь схема загрузки такова: компьютер → временная папка сервера → наша временная папка → конечная папка. То есть, добавился ещё один промежуточный пункт.

Для пущего веселья добавим в нашу форму выпадающий список, чтобы мы устанавливать тип загрузки и поля для ввода градуса поворота.

В таком случае вызов функции будет такой:
$name = resize($_FILES['picture'], $_POST['file_type'], $_POST['file_rotate']);

Конечный результат
И наконец, конечный результат.
<!DOCTYPE HTML PUBLIC  "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Загрузка изображения с изменением размеров</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<h1>Загрузка изображения с изменением размеров</h1>
<?php
 
// Пути загрузки файлов
$path = 'i/';
$tmp_path = 'tmp/';
// Массив допустимых значений типа файла
$types = array('image/gif', 'image/png', 'image/jpeg');
// Максимальный размер файла
$size = 1024000;
 
// Обработка запроса
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
// Проверяем тип файла
if (!in_array($_FILES['picture']['type'], $types))
die('<p>Запрещённый тип файла. <a href="?">Попробовать другой файл?</a></p>');
 
// Проверяем размер файла
if ($_FILES['picture']['size'] > $size)
die('<p>Слишком большой размер файла. <a href="?">Попробовать другой файл?</a></p>');
 
// Функция изменения размера
// Изменяет размер изображения в зависимости от type:
//  type = 1 - эскиз
//  type = 2 - большое изображение
//  rotate - поворот на количество градусов (желательно использовать значение 90, 180, 270)
//  quality - качество изображения (по умолчанию 75%)
function resize($file, $type = 1, $rotate = null, $quality = null)
{
global $tmp_path;
 
// Ограничение по ширине в пикселях
$max_thumb_size = 200;
$max_size = 600;
 
// Качество изображения по умолчанию
if ($quality == null)
$quality = 75;
 
// Cоздаём исходное изображение на основе исходного файла
if ($file['type'] == 'image/jpeg')
$source = imagecreatefromjpeg($file['tmp_name']);
elseif ($file['type'] == 'image/png')
$source = imagecreatefrompng($file['tmp_name']);
elseif ($file['type'] == 'image/gif')
$source = imagecreatefromgif($file['tmp_name']);
else
return false;
 
// Поворачиваем изображение
if ($rotate != null)
$src = imagerotate($source, $rotate, 0);
else
$src = $source;
 
// Определяем ширину и высоту изображения
$w_src = imagesx($src);
$h_src = imagesy($src);
 
// В зависимости от типа (эскиз или большое изображение) устанавливаем ограничение по ширине.
if ($type == 1)
$w = $max_thumb_size;
elseif ($type == 2)
$w = $max_size;
 
// Если ширина больше заданной
if ($w_src > $w)
{
// Вычисление пропорций
$ratio = $w_src/$w;
$w_dest = round($w_src/$ratio);
$h_dest = round($h_src/$ratio);
 
// Создаём пустую картинку
$dest = imagecreatetruecolor($w_dest, $h_dest);
 
// Копируем старое изображение в новое с изменением параметров
imagecopyresampled($dest, $src, 0, 0, 0, 0, $w_dest, $h_dest, $w_src, $h_src);
 
// Вывод картинки и очистка памяти
imagejpeg($dest, $tmp_path . $file['name'], $quality);
imagedestroy($dest);
imagedestroy($src);
 
return $file['name'];
}
else
{
// Вывод картинки и очистка памяти
imagejpeg($src, $tmp_path . $file['name'], $quality);
imagedestroy($src);
 
return $file['name'];
}
}
 
$name = resize($_FILES['picture'], $_POST['file_type'], $_POST['file_rotate']);
 
// Загрузка файла и вывод сообщения
if (!@copy($tmp_path . $name, $path . $name))
echo '<p>Что-то пошло не так.</p>';
else
echo '<p>Загрузка прошла удачно <a href="' . $path . $_FILES['picture']['name'] . '">Посмотреть</a>.</p>';
 
// Удаляем временный файл
unlink($tmp_path . $name);
}
 
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="picture">
<br>
<label>Тип загрузки</label>
<br>
<select name="file_type">
<option value="1">Эскиз</option>
<option value="2">Большое изображение</option>
</select>
<br>
<label>Поворот</label>
<br>
<input type="text" name="file_rotate">
<br>
<input type="submit" value="Загрузить">
</form>
</body>
</html>
Теги:
Загрузка, изменение размера
Добавлено: 01 Мая 2018 18:21:09 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...