ОсновноеRadiotalkПользовательское
Программирование
6   •   Посмотреть все темы

Загрузка картинок и создание их миниатюр

 

6600
Александр @admiral
Делал для Болтайки, правда не совсем до конечного результата, но и этот результат эго вполне устроил)
Вот и сюда решил выложить этот скрипт с объяснениями как и что делается для того чтобы можно было загрузить картинку и при этом создавалась миниатюра этой картинки.

1. Создадим в корне нашего сайта папку images и в ней еще две папки, в которых будут хранится наши картинки и миниатюры (full и thumbs - соответственно).
2. Нап понадобиться создать три PHP файла, это:
- index.php - страница, которая будет видна для загрузки картинок;
- config.php - файл конфигурации;
- process.php - файл, который будет сжимать наши картинки

И так поехали разбирать что у нас в каждом из файлов:
Начнем с конфига, его содержимое с описанием ниже:
<?
$final_width_of_image = 100;
//Размер изображения, которые надо получить (и ширина и высота)
$path_to_image_directory = 'images/full/';
//Папка, куда будут загружаться полноразмерные изображения
$path_to_thumbs_directory = 'images/thumbs/';
//Папка, куда будут загружать миниатюры
?>

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

Идем дальше - файл index.php, в нем у нас будет скрипт подготовки к загрузки и сама форма для загрузки картинок:
<?php
require 'config.php';
//Подключаем файл конфигурации
require 'process.php';
//Подключаем обработчик
if(isset($_FILES['fupload'])) {
if(preg_match('/[.](jpg)|(gif)|(png)$/',
//Ставим допустимые форматы изображений для загрузки
$_FILES['fupload']['name'])) {
$filename = $_FILES['fupload']['name'];
$source = $_FILES['fupload']['tmp_name'];
$target = $path_to_image_directory . $filename;
move_uploaded_file($source, $target);
createThumbnail($filename); }
}
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Загрузка изображений</title>
</head>
<body>
<div align="center">
<h1>Загрузка изображений:</h1>
<form enctype="multipart/form-data" method="post">
<input type="file" name="fupload" />
<input type="submit" value="Загрузить" />
</form>
</div>
</body>
</html>

Тут впринципе php часть расписана в коментариях //, то есть подключаем файл конфигурации, чтобы знать куда загружать наши файлы; файл обработчика, что бы определить как нам сжимать и делать миниатюры с наших загружаемых каринок; ну и Определяем какие расширения файлов допустимы к загрузке.
Ниже пишем обычную страничку с формой загрузки картинок.

Теперь расмотрим третий файл, файл обработчика - process.php:
<?
function createThumbnail($filename) {
require 'config.php';
//Подключаем файл конфигурации
if(preg_match('/[.](jpg)$/', $filename)) {
$im = imagecreatefromjpeg($path_to_image_directory . $filename);
} else if (preg_match('/[.](gif)$/', $filename)) {
$im = imagecreatefromgif($path_to_image_directory . $filename);
} else if (preg_match('/[.](png)$/', $filename)) {
$im = imagecreatefrompng($path_to_image_directory . $filename);}
//Определяем формат изображения
$ox = imagesx($im);
$oy = imagesy($im);
$nx = $final_width_of_image;
$ny = floor($oy * ($final_width_of_image / $ox));
$nm = imagecreatetruecolor($nx, $ny);
imagecopyresized($nm, $im, 0,0,0,0,$nx,$ny,$ox,$oy);
if(!file_exists($path_to_thumbs_directory)) {
if(!mkdir($path_to_thumbs_directory)) {
die("Проблемы? Попробуйте снова!");}
}
imagejpeg($nm, $path_to_thumbs_directory.$filename);
$tn = '<div align="center"><img src="'.$path_to_thumbs_directory.$filename.'" alt="image" />';
$tn .= '<br /><h3>Изображение успешно загружено, его миниатюра удачно выполнена.<br />
Выше Вы можете просмотреть результат</h3></div>';
echo $tn;
}
//Сжимаем изображение, если есть ошибки-выводим, если их нет, то выводим получившуюся миниатюру
?>

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

PS ниже прикрепил уже готовые файлы скрипта:
**********

4036
DelFast @DelFast
Ггг.. я думал болтайка сам додумается такое написать 😀
Ничего сложного не вижу...
За старание +ик

Отредактировано DelFast - 22.02.2010
8497
Степан @Trilby
Я в пхп вообще дуб. И поверьте, я такой не один.
Если не верите - попробуйте прямо сейчас что-нибудь написать на... хм.. на ASP.NET. Много написали? Ну-ну..
За апплоадер ещё раз спасибо 😀

Отредактировано Trilby - 22.02.2010
6600
Александр @admiral
k0x! пишет:

Ничего сложного не вижу...

А я вижу сложность в том что многие аплоадеры на многих сайтах уязвимы, тот же livejournal или securitylab были в свое время с дырамичерез которые можно было осуществить XSS атаку с картинки.
k0x!, лучше бы предложил как безопасней сделать скрипт загрузчика, думаю и твоему скрипту бы не помешало это.
Render, безопасней можно сделать, но не полностью, по крайней мере я не нашел подходящего варианта полностью обезопаситься, многое еще зависит от настроек сервера, да и не только
Если не читал, то советую почитать обе части статей ********** с хабры, вторую часть думаю найдешь без труда там)
На php сколько бы не ставилось фильтров, впринципе все их можно, если очень захотеть обойти, тот же фильтр запрешающий html теги впринципе обходиться заменой кодировки, да много всякого обхода, просто если за все писать, статья очень большая получиться. Может демон подскажет проще вариант, но не думаю что чисто на php можно написать полностью безопасный скрипт загрузчика, что у него на imgs используется и как обрабатывается я както не присматривался)

4036
DelFast @DelFast
Выдрал..
$imageinfo = getimagesize($_FILES['userfile']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {
echo "Только картинки.";
}

6600
Александр @admiral
В PHP до версии 5.2.5 в этих функциях имеются уязвимости.
Это я на счет того что удалил... за функции htmlentities() и htmlspecialchars()

А как на счет размещения такого файлика например:
<script>alert(document.cookie);</script>
с изменением кодировки на utf-7, тоесть когда наши < и > заменяются на:
+ADw-script+AD4-alert(document.cookie)+ADsAPA-/script+AD4-

2020
Don-A @Don-A
**********
Когда загружаю , и оно уменьшает в 2 раза картинку(

1897
Александр @I-believe
Да и если кириллица в названии - не сохраняет.

6600
Александр @admiral
Don-A пишет:

**********
Когда загружаю , и оно уменьшает в 2 раза картинку(

В файле config.php
//Размер изображения, которые надо получить (и ширина и высота)
Читаем внимательно, а не ставим все подрят, нужно оно или нет.

I-believe, с кирилицей гляну, что то не подумал за неё, както привык что все или в цифрах или латинице)

1130
Александр @WestSide
k0x! пишет:

Выдрал..
$imageinfo = getimagesize($_FILES['userfile']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {
echo "Только картинки.";
}


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

3473
Фарид @F_a_R_i_D
жалко что удалил свой скрипт, а где качать уже забыл 😀
хороший был скрипт для загрузки картинок + каталог смайлов

найду, поделюсь


п.с. адмиралу, если ссылку на картинку не выдаёт, то какой смысл загрузки картинки ? 😀
+ можно и .bmp файл добавить в скрипт.

Отредактировано F_a_R_i_D - 23.02.2010
4036
DelFast @DelFast
Можно сделать отдельный php файлик который уже показывает картинку - после загрузки.
Туда допистаь - выше отрывок кода, который проверяет на формат внутренность файла. Если определен другой формат то просто удаляет файлик и пишет ошибку.

6600
Александр @admiral
F_a_R_i_D, это не готовый скрипт для загрузки картинок, об этом никто и не писал, это всего лишь пример, на котором можно организовать загрузку аватар, картинок для статей например на своем сайте.
Я не писал что это идеальнаый вариант и это всего лишь загрузчик и если подумать то можно и не только .bmp или картинки сделать чтобы можно было загружать, в этом и есть смысл и разница только в том что есть дырявые готовые скрипты, а есть примеры и варианты, которые можно применять в своих скриптах и на которых учатся.
Чуть позже выложу немного другой загрузчик как допишу, но еще раз повторю, всего лишь загрузчик!
Да и вопрос поднятый в этой теме интересный на мой взгляд, как защититься от загрузки скриптов через картинки!
k0x!, проверять при загрузки надо и отсеивать, а не после, после уже может быть поздно )

4036
DelFast @DelFast
Дак можно три степени загрузки:
1) загружается, проверяется
2) проверяется на внутренний формат
3) Если все ОК - выводит ссылку на картинку и т.д.

7094
--- @Render
admiral Безопасность превыше всего. Хочется увидеть безопасный от простейших атак хотябы загрузчик, а там уже его апгрейдить до всяких.
Вынос ссылки на изображение
Смена имени файла вида 015016874046.jpg
Функция изменения разрешения при загрузки и тд.
Уже не составит большого труда...
Главное безопасный способ найти, пусть даже если придётся подключать классы или perl.

Отредактировано Render - 23.02.2010
6600
Александр @admiral
Видоизменил скрипт в корне, все помещается в одном файле, описание работы по шагам описаны в самом скрипте, так что нет смысла их расписывать еще раз, проверяем, кому нужно и кто знает для чего, где и как применить могут, забираем )
PS сразу оговорюсь, задачи не стояло разрешить загрузку различных форматов, этот скрипт всего лишь описание метода загрузки, кому будет интересно и нужно добавить другие разширения файлов допустимые к загрузке, по аналогии может дописать скрипт )

1. Создаем файлик index.php, ну и все, остальное в скрипте )))
ЗЫ да еще не забываем что скрипт писался с файлом загрузчика в корне сайта, а так же не забываем создать папку images и в ней еще две папки full и thumbs, для загрузки в них наших картинок и миниатюр, соответственно.
<?
// поехали 😀
if (!empty($_FILES['imgs'])) {
// назначим наши переменные
$imgs = $_FILES['imgs'];
$imgs_size = $_FILES['imgs']['size'];
$imgs_type = $_FILES['imgs']['type'];
$imgs_name = $_FILES['imgs']['name'];
$imgs_tmp_name = $_FILES['imgs']['tmp_name'];
// задаем максимальный вес картинки, если превышен, то выводим ошибку
if ($imgs_size > 5*1024*1000) die ('<center>Размер картинки превысил лимит в 5 МБ. <a href="'.$PHP_SELF.'">Загрузить заного</a></center>');
// получаем расширения файлов для загрузки
preg_match("'([a-z]+)\/[x\-]*([a-z]+)'", $imgs_type, $ext);
switch($ext[2]) {
case "jpg":
case "jpeg":
case "pjpeg":
break;
default: die("<center>Ошибка!<br />\n Допускаются файлы: <b>.jpg, .jpeg, .pjpeg</b> до 5МБ<br /> <a href='{$PHP_SELF}'>Загрузить заного</a></center>");
}
// задаем допустимые размеры картинок для загрузки
$width_max = 640;
$height_max = 480;
// получаем размеры
$img_size = getimagesize($imgs_tmp_name);
$width_original = $img_size[0];
$height_original = $img_size[1];
// еще одна проверка на размер загружаемых картинок, если превышен, то ошибка
if ($width_original < $width_max || $height_original < $height_max) die ("<center>Запрещено загружать картинки с размерами меньше {$width_max}x{$height_max}. <a href='{$PHP_SELF}'>Загрузить заного</a></center>");
// создадим пустое изображение с нужными нам размерами
$image_p = imagecreatetruecolor($width_max, $height_max);
// собственно создали 😀
$image = imagecreatefromjpeg($imgs_tmp_name);
// определим пропорции для дальнейшей обрезки до них
$w_prp = ($width_original / $width_max);
$h_prp = ($height_original / $height_max);
// определим высоту и ширину будущих сжатых картинок
$p_w = ($width_max / $width_original);
$h_new = ($height_original * $p_w);
$y1 = (($h_new - $height_max) / 2);

$p_h = ($height_max / $height_original);
$w_new = ($width_original * $p_h);
$x1 = (($w_new - $width_max) / 2);

// описываем когда приходиться сжимать ширину, а высоту резать
if ($w_prp < $h_prp) {
$image_p_1 = imagecreatetruecolor($width_max, $h_new);
// выполним копирование и ресамдлинг нашей картинки, т.е. с помощью GD библиотеки сгладим и заполним промежуточными цветами недостающие точки
imagecopyresampled($image_p_1, $image, 0, 0, 0, 0, $width_max, $h_new, $width_original, $height_original);
imagecopyresampled($image_p, $image_p_1, 0, 0, 0, $y1, $width_max, $height_max, $width_max, $height_max);
}
// описываем когда приходиться сжимать высоту, а ширину резать
elseif ($w_prp > $h_prp) {
$image_p_1 = imagecreatetruecolor($w_new, $height_max);
// сного выполним копирование и ресамдлинг нашей картинки, т.е. с помощью GD библиотеки сгладим и заполним промежуточными цветами недостающие точки
imagecopyresampled($image_p_1, $image, 0, 0, 0, 0, $w_new, $height_max, $width_original, $height_original);
imagecopyresampled($image_p, $image_p_1, 0, 0, $x1, 0, $width_max, $height_max, $width_max, $height_max);
}
// если все размеры соблюдены, то сжимаем
elseif ($w_h_prp == $curr_prp) {
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width_max, $height_max, $width_original, $height_original);
}
// определяем время для названия картинки, удобно если заносим в базу сортировать по времени добавления
$time = time();
// определяем пути до картинок и их миниатюр и названия для них
$imgs_path = "images/full/{$time}.jpg";
$thumb_path = "images/thumbs/{$time}.jpg";
if (imagejpeg($image_p, $imgs_path, 100)) {
// если все замечательно, создаем файл миниатюры, метод немного отличается для разнообразия от того, что описан выше, если захотите можете потренироваться и сделать создание миниатюр так же как и выше
$thumb_width = 150;
$thumb_height = 113;
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
$w_point = (($width_original - $thumb_width) / 2);
$h_point = (($height_original - $thumb_height) / 2);
imagecopyresampled($thumb, $image, 0, 0, $w_point, $h_point, $thumb_width, $thumb_height, $thumb_width, $thumb_height);
imagejpeg($thumb, $thumb_path, 100);
// описываем вывод, опять же, если захотите можете выводить запрос в базу данных или куда еще будет угодно
$vvd = "тут можно отправить запрос в базу";
if ($vvd) {
echo "<div align='center'><img src='$imgs_path' alt='image' /><br /><h4>Изображение успешно загружено</h4><img src='$thumb_path' alt='image' /><br /><h4>Его миниатюра удачно создана.</h4><br /><h2>Поздравляем!!!</h2><br />\n<a href='{$PHP_SELF}'>Загрузить ещё</a></div>";
}
// очередная проверка, если картинка ни куда не добавлена, то ошибка
else {
echo "Ошибка. Картинка не добавлена!";
unlink($imgs_path);
unlink($thumb_path);
}
}
// вывод ошибки при копировании
else print ("Ошибка!");
}
else {
// ну и наконец то наша форма для загрузки картинок
echo "<html>\n";
echo "<head>\n";
echo "<meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>\n";
echo "<title>Загрузка изображений</title>\n";
echo "</head>\n";
echo "<body>\n";
echo "<div align='center'><h1>Загрузка изображений:</h1>\n";
echo "<form action='{$PHP_SELF}' method='post' enctype='multipart/form-data'>\n";
echo "<h3>Выбрать файл для загрузки:</h3><input name='imgs' type='file' size='50' /><br /><br />\n";
echo "<input type='submit' value='Загрузить' /> <input type='reset' value='Отменить'><br />Разрешено загружать только: <b>.jpg, .jpeg, .pjpeg</b> файлы весом до 5МБ.<br />\n";
echo "</form>\n";
echo "</div>\n";
echo "</body>\n";
echo "</html>";
}
// и в конце то концов, это метод загрузки картинок расширений джипег, для остальных разрешений, если захотите можете написать свои функции, используя например такие функции как imagecreatefromgif, imagecreatefrompng и т.д.
?>

4036
DelFast @DelFast
Если надо будет - можно сделать переменную-селектор,
для уменьшения фотографий. То есть, в форме выбираем (например)
240x240 = картинка сжимается до 240x-240y

6600
Александр @admiral
k0x!, Это уже дело хозяйское) можно не только эти мелочи забабахать )

1130
Александр @WestSide
Эта информация скрыта и доступна только зарегистрированным пользователям.

помоему самая надежная защита + к проверки mime-type

7094
--- @Render
Апнем темку)
Адмирал, наверно все вопросы будут тебе адресованы, т.к действительно разбирающихся в таких делах на форуме единицы.
В общем по порядку:
1. Можно ли как-нибудь оптимизировать работу загрузчика? Для чего это нужно? Столкнулся с такой проблемой, что при загрузке изображения чуть меньше 5мб, вылетает
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 14592 bytes)
Конечно в такой ситуации можно использовать
ini_set("memory_limit", "150M"); или в htaccess прописать память, но это не выход.
А что будет если одновременно будут пытаться загрузить изображение скажем человек 5 или даже боюсь подумать, 10? (создание миниатюры не используется, только загрузка и ресамдлинг).
Вот это первая проблема.
2. Как можно сделать проверку на обновление страницы в загрузчике тогда, когда изображение уже загружено и показывается? Тоесть после загрузки изображения если нажать на f5 или на иконку обновить в браузере, то получается скрипт снова выполняется всё с тем же изображением, которое было загружено только что и такими обновлениями можно забить прилично памяти на HDD.
Нужно либо запретить обновление страницы для загруженного изображения, либо сделать какую-то проверку, чтобы при обновлении страницы вылетала ошибка.
3. Нужна помощь, точнее пример кода по ресайзу изображения во 2 примере аплоадера, который привел адмирал.
При загрузки картинки в селекторе выбираешь, на какое разрешение уменьшить картинку. Как-то так:
<select name="rz">
<option value="">оставить как есть</option>
<option value="640">640px</option>
<option value="800">800px</option>
</select>
Ну и выполняется соответствующая процедура в скрипте уменьшающая картинку, самому пока не удалось сделать правильную функцию.
Были ещё какие-то вопросы интересующие, но уже забыл блин...

Отредактировано Render - 07.01.2011