Пятница, 29.03.2024, 02:46 | RSS | Приветствую Вас Гость
Главная | Регистрация | Вход
Меню сайта
Категории раздела
Разное [10]
Решения задач (студентам) [9]
PC Игры - кодинг [2]
Python [1]
PHP, Mysql [1]
HTML, CSS, Javascript [1]
Scilab [1]
Поиск
Опрос
Какой браузер вы сейчас используете?
Всего ответов: 51
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » PHP, Mysql

PHP. Безопасная загрузка аватара на сервер.
Как говорил Линус Торвалдс (Linus Torvalds) - "Болтовня ничего не стоит. Покажите мне код.", а потому перейду сразу к скрипту.

Скрипт для загрузки аватара.

if(empty($_FILES['filename']) && $_FILES['filename']['size'] > 30*1024)
{
    print( '<span style="color:red;">Объем файла превышает 30 килобайт или файл не удалось принять!</span><br>');
}
elseif (is_uploaded_file($_FILES['filename']['tmp_name']))
{
    $imginfo = getimagesize(realpath($_FILES['filename']['tmp_name']));
    if ($imginfo[2] == '1' || $imginfo[2] == '2' || $imginfo[2] == '3')
    {
        if ($imginfo[0] == '100' && $imginfo[1] == '100')
        {
            if ($imginfo[2] == '1')
            {
                $im = imageCreateFromGif(realpath($_FILES['filename']['tmp_name']));
                $w = imageSX($im);
                $h = imageSY($im);
                $w_new=40;
                $h_new=40;
                $im_mini = imageCreate($w_new, $h_new);
                imageCopyResized($im_mini, $im, 0, 0, 0, 0, $w_new, $h_new, $w, $h);
                if ($im && $im_mini)
                {
                    imageJpeg($im, $_SERVER['DOCUMENT_ROOT'].'/ava/'.$_SESSION['uid'].'.jpg', 90);
                    imageJpeg($im_mini, $_SERVER['DOCUMENT_ROOT'].'/avatars/mini_'.$_SESSION['uid'].'.jpg', 90);
                    imageDestroy($im);
                    imageDestroy($im_mini);
                    $sql = mysql_query("UPDATE usr SET ava='".$_SESSION['uid'].".jpg' WHERE id='".$_SESSION['uid']."'");
                    if ($sql)
                    {
                        print( '<span style="color:green;">Аватар успешно загружен!</span><br>');
                    }
                }
                else print( '<span style="color:red;">Загруженный вами файл не является изображением!</span><br>');
               
            }
            elseif ($imginfo[2] == '2')
            {
                $im = imageCreateFromJpeg(realpath($_FILES['filename']['tmp_name']));
                $w = imageSX($im);
                $h = imageSY($im);
                $w_new=40;
                $h_new=40;
                $im_mini = imageCreate($w_new, $h_new);
                imageCopyResized($im_mini, $im, 0, 0, 0, 0, $w_new, $h_new, $w, $h);
                if ($im && $im_mini)
                {
                    imageJpeg($im, $_SERVER['DOCUMENT_ROOT'].'/avatars/'.$_SESSION['uid'].'.jpg', 90);
                    imageJpeg($im_mini, $_SERVER['DOCUMENT_ROOT'].'/avatars/mini_'.$_SESSION['uid'].'.jpg', 90);
                    imageDestroy($im);
                    imageDestroy($im_mini);
                    $sql = mysql_query("UPDATE users SET ava='".$_SESSION['uid'].".jpg' WHERE id='".$_SESSION['uid']."'");
                    if ($sql)
                    {
                        print( '<span style="color:green;">Аватар успешно загружен!</span><br>');
                    }
                }
                else print( '<span style="color:red;">Загруженный вами файл не является изображением!</span><br>');
               
            }
            elseif ($imginfo[2] == '3')
            {
                $im = imageCreateFromPng(realpath($_FILES['filename']['tmp_name']));
                $w = imageSX($im);
                $h = imageSY($im);
                $w_new=40;
                $h_new=40;
                $im_mini = imageCreate($w_new, $h_new);
                imageCopyResized($im_mini, $im, 0, 0, 0, 0, $w_new, $h_new, $w, $h);
                if ($im && $im_mini)
                {
                    imageJpeg($im, $_SERVER['DOCUMENT_ROOT'].'/ava/'.$_SESSION['uid'].'.jpg', 90);
                    imageJpeg($im_mini, $_SERVER['DOCUMENT_ROOT'].'/ava/mini_'.$_SESSION['uid'].'.jpg', 90);
                    imageDestroy($im);
                    imageDestroy($im_mini);
                    $sql = mysql_query("UPDATE users SET avatar='".$_SESSION['uid'].".jpg' WHERE id='".$_SESSION['uid']."'");
                    if ($sql)
                    {
                        print('<span style="color:green;">Аватар успешно загружен!</span><br>');
                    }
                }
                else print('<span style="color:red;">Загруженный вами файл не является изображением!</span><br>');
            }
        }
        else print('<span style="color:red;">Изображение должно иметь размеры 100x100!</span><br>');
    }
    else print('<span style="color:red;">Не верный тип файла!<br>Поддерживаемые типы: jpg, png</span><br>');
}
else print('<span style="color:red;">Возникла ошибка при загрузке изображения! Попробуйте снова.</span><br>');

Форма загрузки.

<form enctype="multipart/form-data" method="post" action="load.php">
<table>
<tr><td>Изображение</td><td><input name="filename" type="file" /></td></tr>
<tr align="center"><td colspan="2"><input type="submit" name="send" value="Загрузить" /></td></td></tr>
</table>
</form>

Через multipart-форму во временный каталог на сервере загружается файл и далее обрабатывается приведенным выше кодом.

Идея проста. Проверяется, приходило ли что-нибудь через форму и объем того, что пришло, и для перестраховки делается проверка временного файла функцией is_uploaded_file(). Если все нормально, получаем информацию о загруженном файле (предполагая, что это изображение!) с помощью функции getimagesize(). Эта функция выдает тип изображения и его размеры в пикселях (а большего и не надо, если кто вспомнил полный набор возвращаемых значений!). В первую очередь проверяется тип изображения. За это отвечает 2-й (по индексу) элемент возвращаемого функцией массива. В данном примере используются форматы GIF,JPEG и  PNG. То есть 2-й элемент результата должен равняться соответственно 1, 2 или 3. Данная проверка не только ограничит выполнение действий над изображением неподходящего формата, но и не пропустит любой другой файл кроме изображения (например файл с php-скриптом!).

Далее, если изображение нужного формата, проверяется его размер в пикселях. За это отвечают 0-й и 1-й (высота и ширина) элементы результата функции. И если размер соответствует требуемому, производится "считывание" изображения из временного файла с помощью функции imageCreateFromGif, imageCreateFromJpeg или imageCreateFromPng (в зависимости от считанного ранее формата) и создание его миниатюры с помощью функции imageCopyResized(). Затем полученные изображения сохраняются в нужный каталог на сервере с помощью функции imageJpeg, imageGif или imagePng (в зависимости от нужного формата). Но в данном примере изображения в любом случае сохраняются в формате JPEG. Это делается из соображений экономии места на сервере. Как показала практика, изображение, которое в PNG формате весит 16 КБ, с мизерными (незаметными!) потерями в качестве в JPEG формате может весить 3 КБ. Я думаю, тут замечания по поводу мелочности будут неуместными (зачем хранить лишний объем?). Ну это уже кому как нравится.

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

Категория: PHP, Mysql | Добавил: =Sanek= (04.08.2011)
Просмотров: 8347 | Комментарии: 10 | Теги: PHP, getimagesize(), аватар, mysql, загрузка файлов на сервер, загрузка изображения на сервер | Рейтинг: 2.0/1
Всего комментариев: 10
5 Draug  
0
А код огромен можно сделать намного компактней

2 Draug  
-1
Да и создавать целую таблицу только для аватаров глупо!

3 =Sanek=  
0
Я ни слова не сказал о создании отдельной таблицы для аватаров. Ссылка на аватар запоминается прямо в таблице с пользователями.

7 Draug  
0
Сорри не заметил то что там база user

1 Draug  
0
Безопасность, это не только загрузка на сервер, а также вывод этих аватаров ...
Просто если загружать данным образом, то никакого труда не составит сливать абсолютно все аватары куда угодно! А это ни есть copyright-но

4 =Sanek=  
0
Ну, во-первых, я ставил задачу - загружать "чистые" картинки. А во-вторых, поясни на счет "сливать куда угодно". Путь для сохранения аватаров постоянный... А на счет copyright-но... Если пользователь загружает на сайт какое-то фото (и если его могут видеть все!), то он должен понимать, что он этим действием разрешил распространение этой фотографии. К стати на Facebook'е при загрузке фотографий сразу так и предупреждают.

6 Draug  
1
Сливать куда угодно я и имел ввиду то, что данным кодом ты создал пополняемую базу аватаров!
Т.е. трафик твоего сайта будет уходить на сторонние ресурсы без какой либо трудности!

8 =Sanek=  
0
Есть идеи по ограничению утечки трафика?
Конечно, если выводить аватары напрямую, само собой ссылки на них смогут использовать где угодно. Но с другой стороны, если принимать всякие меры по ограничению их распространения (вот на счет этого ТВОИ ИДЕИ!), это тоже будет хавать трафик... Ну а вообще это уже тема для другой статьи...

9 Draug  
1
Выход прост smile
md5("avatar_".$_SESSION['uid'].time()).".jpg"
тут уже если даже и узнаешь адрес одной аватары, вторую будет очень трудно вытащить wink

10 =Sanek=  
0
А... так вот что ты имел в виду! Типа в скрипте все имена аватаров по id пользователя выдаются... Да точно... Я даже как-то сразу и не заметил подвоха. biggrin

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

© 2024 raznocoding.do.am