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

свойства изображения

Сегодня я хочу рассказать о реализации довольно популярной задачи. Во-первых, это загрузка изображения на сервер. А во-вторых, это изменение размера изображения. Также рассмотрим поворот и изменение качества.

Скачать исходный код себе на компьютер!

Немного теории по загрузке изображений на сервер средствами PHP

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

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

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

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее

$_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>

Изменение размеров изображений PHP

Приступим к самому интересному, а именно изменению размеров изображения с помощью PHP. Для этого напишем функцию 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);

В зависимости от типа (эскиз или большое изображение) устанавливаем ограничение по ширине.

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее
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>

свойства изображения

Послесловие

Естественно, рассмотренный пример учебный. Однако он вполне рабочий. Что вы можете попробовать, забросив скрипт на сервер и создав папки для изображений и временных файлов. Скрипт можно бесконечно дорабатывать, изменять уровень абстракции, добавлять условия и параметры, преобразования, проверки, накладывать «водяной знак».

Идеальный вариант – осмыслить и допилить до своих требований.

Домашнее задание

Конечно, задание проверять никто не будет. Однако я рекомендую его выполнить для себя. Ведь программирование – это, прежде всего, практика. Итак:

Вынесите размеры эскиза ($max_thumb_size) и большого изображения ($max_size) из функции в настройки файла.

Попробуйте задавать их в параметрах функции. Это значительно повысит уровень абстракции.

Проработайте вариант, когда изображение ограничивается по большей стороне, а не только по ширине.

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

Попробуйте генерировать и эскиз и большой файл за одну загрузку.

Попробуйте наложить «водяной знак».

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

Удачи в разработках!

P.S. Если вы захотите генерировать не пропорциональное изображение, а вырезать серединку и делать квадратную картинку, вам поможет этот код. Вставить его в функцию resize вы должны сами. Уверен, что у вас получится.

// Создаём пустую квадратную картинку 
$dest = imagecreatetruecolor($w, $w); 

// Вырезаем квадратную серединку по x, если фото горизонтальное
if ($w_src > $h_src)
 imagecopyresampled($dest, $src, 0, 0, round((max($w_src, $h_src) - min($w_src, $h_src))/2), 0, $w, $w, min($w_src, $h_src), min($w_src, $h_src));
// Вырезаем квадратную серединку по y, если фото горизонтальное
elseif ($w_src < $h_src)
 imagecopyresampled($dest, $src, 0, 0, 0, round((max($w_src, $h_src) - min($w_src, $h_src))/2), $w, $w, min($w_src, $h_src), min($w_src, $h_src));
// Квадратная картинка масштабируется без вырезок
elseif ($w_src == $h_src)
 imagecopyresampled($dest, $src, 0, 0, 0, 0, $w, $w, $w_src, $w_src);

До следующих встреч, уважаемые читатели

Если у вас есть вопросы, по загрузке изображений на сервер и изменению размеров изображений средствами языка PHP, то пишите в комменатриях к статье, я обязательно отвечу!

Автор: Алексей Опанасенко

Редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.

E-mail: contact@webformyself.com

Проект webformyself.com — Как создать свой сайт. Основы самостоятельного сайтостроения

«Киберсант-вебмастер» — самый полный курс по сайтостроению в рунете!

P.S. Хотите опубликовать интересный тематический материал и заработать? Если ответ «Да», то жмите сюда.

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее
Самые свежие новости IT и веб-разработки на нашем Telegram-канале

Курс по программированию на языке PHP

Изучите PHP с нуля до результата!

Смотреть курс

Метки: ,

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (83)

  1. Денис

    Доброго времени друзья, скрипт очень полезен и использую его уже давно)

    Но тут пришла необходимость изменять имя файла перед тем как оно загрузиться в папку. На свое точней то что будет введено в поле input подскажите как под править этот код?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree