PHP: загрузка файла на сервер
Загрузка файлов через PHP - весьма интересное дело, к которому нужно подходить очень внимательно. В интернете можно найти множество примеров реализации загрузки файлов, но не все они хороши и отвечают правилам безопасности.
Подобные вещи нужно доводить до конца, даже если на это уйдет много времени. Если вы оставите брешь в коде, то весь ваш сервер может оказаться под угрозой.
Безопасность
При помощи PHP загрузка файлов на сервер осуществляется достаточно легко. Код очень короткий и простой. Всего лишь пара строк. Но такой метод опасен. Куда больше времени и строк кода уходит на безопасность.
Опасность заключается в том, что, если не делать проверок, любой злоумышленник сможет загрузить свои скрипты на ваш сервер. При этом у него будет полный доступ. Он сможет сделать всё, что захочет:
- удалить базы;
- удалить файлы сайтов;
- изменить файлы сайтов;
- добавить свою рекламу на ваш сайт;
- загрузить вирусы;
- перенаправлять всех пользователей на свои сайты;
- и многое другое, что придет в голову взломщику.
Всегда нужно проверять, что за файл пытается загрузить пользователь. Если, например, вы загружаете только фотографии, необходимо проверить, что этот файл точно является изображением. В противном случае к вам загрузят что угодно.
Как именно реализовать проверку, будет показано далее, при непосредственном рассмотрении скрипта загрузки файлов.
Создание формы PHP
Форма загрузки файла выглядит очень просто. Хватает кнопки обзора и кнопки загрузки.
Описывать создание формы не будем, так как это легко. Дальнейшие инструкции предполагают, что у вас уже есть базовые понятия HTML (иначе бы вы не искали информацию о загрузке на PHP).
Но обратите внимание, что для передачи данных в форме нужно добавить атрибут enctype.
Иначе данные о файле обработчику передаваться не будут.
Как это должно работать?
После этого должен будет появиться путь, где расположен файл.
Если путь не появится, то проделайте это действие еще раз.
После нажатия на кнопку загрузки файлом-обработчиком можно выдать любую информацию.
Например, можно написать строку, в которой говорится, что файл с "таким-то" названием был успешно загружен в "такую-то" папку. Разумеется, имя файла будет выдаваться всегда разное.
Обычно такую подробную информацию используют для отладки кода. Таким образом можно проверить, что данные передаются и запись происходит в нужную вам директорию. То есть даже имя файла не указывают. Поскольку это лишняя информация, которая пользователю не нужна.
Имеет смысл вывод данных об имени только в том случае, если пользователь загружает несколько файлов. Такой случай рассмотрим немного дальше. Не будем забегать вперед.
Настройка
В PHP загрузка файла на сервер требует определенных настроек, которые нужно делать в файле php.ini. В этом файле очень много настроек. Они все нам не нужны. Нас интересуют три строчки: file_uploads, upload_tmp_dir и upload_max_filesize.
Обратите внимание на то, что эти настройки коснутся всех ваших сайтов на сервере, а не только какого-то одного. Поэтому задавайте максимальный размер исходя из того, что у вас будут загружать пользователи. Не рекомендуется задавать слишком большие значения.
После того, как вы изменили значения в этих параметрах, сервер нужно перезагружать. Иначе настройки не вступят в силу, так как они считываются в момент загрузки сервера.
Сделать это можно в консоли, подключившись через SSH к серверу. Достаточно ввести команду service httpd restart, и после этого настройки вступят в силу.
Другой способ - перезапуск через ISP-панель или через биллинг-панель провайдера.
Массив с файлом
В PHP загрузка файла происходит при помощи массива $_FILES. В нем содержится вся информация о файлах, которые мы будем загружать.
Для того чтобы посмотреть, какая именно информация содержится в этом массиве, достаточно написать в файле-обработчике следующее.
Выберите любой файл и нажмите "Загрузить". На странице обработчика выведется информация, которая хранится в $_FILES. Переменная пишется полностью с большими буквами. PHP - язык регистрозависимый.
Как видите, в этом массиве есть много полей. Все они для нас важны. В первом поле хранится название файла в том виде, в котором оно используется на вашем компьютере.
В графе type указан тип файла. Полю tmp_name соответствует имя временного файла. После окончания работы скрипта он будет удален.
В поле error хранится код ошибки. Об этом немного далее. Size - размер в байтах.
Ошибки
Осуществляемая через PHP загрузка файла всегда сопровождается кодом ошибки. Сообщение об ошибке заключено в поле "error". На скриншоте ошибка равна нулю.
Рассмотрим значения всех ошибок:
Вот пример формы для загрузки файла, где указано ограничение в размере загружаемого файла.
PHP: скрипт загрузки файла
Как же все осуществляется на практике? В PHP загрузка файла происходит командой copy. Если вас интересовал вопрос о том, как загрузить файл, то ответом будет просто copy, в которой используется два параметра - исходный файл и файл назначения.
Но, как писалось выше, ограничиваться этим нельзя в целях безопасности. Например, проверить что за файл мы грузим, можно при помощи поля type в массиве $_FILES. Сначала разберемся с проверкой, а потом перейдем к полноценному скрипту
Допустим, вы хотите, чтобы пользователи могли загрузить фотографию с разрешением только GIF, JPEG или PNG. Указать это можно вот так.
if($_FILES['file_upload']['type'] != "image/gif") {
echo "Извините, мы поддерживаем загрузку только Gif-файлов";
exit;
}
Если хотите грузить все 3 типа, то просто добавьте дополнительное условие с другим типом изображения.
Копирование делается вот так: copy(файл 1, файл 2).
В нашем случае, когда работа идет с загрузкой с компьютера на сервер, можно делать так
copy($_FILES['file_upload']["tmp_name"], "1.jpg")
То есть файл будет копироваться с названием 1.jpg. Это не совсем правильно. В данном случае это только пример. Имя файла всегда нужно задавать разное, и расширение указывать в зависимости от файла.
Определить расширение можно разными способами. Всё зависит от эрудиции разработчика. Один из самых быстрых способов (разница в десятых долях секундах) определения расширения - это следующий код.
$path_info = pathinfo($_FILES['photo1']["name"]);
$ext=$path_info['extension'];
В переменной $ext у нас будет храниться искомое расширение. А имя файла можно задать случайным образом при помощи md5. Если вы планируете загружать много файлов, то лучше грузить их в разные папки. Так будет удобнее. В особенности если захотите провести чистку.
Код для загрузки будет следующим.
/// наличие фото
if ($_FILES['photo1']['tmp_name'] == null)
{
echo ("<p><strong>Файл не указан.</strong></p> <p><a href='javascript:history.back()'>Назад...</a></p> ");
exit;
}
/// . Допустим, у вас для какого-нибудь проекта на сервере разрешено грузить большие файлы (видео), но здесь будут только фотографии, и пользователей нужно ограничить
if (($_FILES["photo1"]["size"] > 1024*1024*2)
{
?>
<p>Максимально разрешённый размер изображения <strong>2 Мб</strong>
<p><a href='javascript:history.back()'>Назад...</a></p>
<?
exit;
}
// создание папок
// создание папки текущего месяца
if (!file_exists("img/".date("M")))
{
mkdir("img/".date("M"));
}
// создание папки текущего дня
if (!file_exists("img/".date("M")."/".date("d")))
{
mkdir("img/".date("M")."/".date("d"));
}
/// расширение файла
$path_info = pathinfo($_FILES['photo1']["name"]);
$ext=$path_info['extension'];
/// генерируем имя файла
$id=md5(date("Y-M-d"));
if(copy($_FILES['photo1']["tmp_name"], "img/".date("M")."/".date("d")."/".$id.$ext))
{
echo ("файл успешно загружен");
}
/// любые дальнейшие действия (запись в базу и т. п.)
}
Несколько файлов
Загрузка нескольких файлов (PHP) происходит при помощи дополнительных полей в форме.
Данный способ не очень хороший, так как ограничивает количество файлов для загрузки. Более того, считается плохим тоном в программировании. Старайтесь делать всё динамичное.
Идеальный вариант - это возможность выбора сразу большого числа файлов нажатием на одну кнопку.
Для этого форму создаем вот таким кодом.
<form method="POST" action="Ссылка на файл-обработчик" name="upload_form" enctype="multipart/form-data">
<p>
<input class="form_upload" type="file" name="file1[]" multiple value="Обзор">
<input class="form_upload" type="submit" name="upldFile" value="Добавить" />
</p>
</form>
Обратите внимание, что добавлено слово multiple, и имя задано как массив []. В этом случае массив $_FILES будет немного отличаться. У вас получится массив в массиве.
Для проверки можете опять воспользоваться var_dump($_FILES);
Все ваши файлы будут располагаться в массиве вот так:
- $_FILES["file1"]["name"][0]
- $_FILES["file1"]["name"][1]
- И так далее.
В скобках пишется номер файла в массиве. Отсчет с нуля. Обрабатываем их точно так же, просто задаем цикл и при обращении в выше описанном коде в конце добавляем индекс [$i].
$i=0;
while ($_FILES["file1"]["name"][$i]<>'')
{
/// вставляем вышеописанный код
}
Таким образом, у вас будет происходить через PHP загрузка файлов на сервер в одном цикле без лишнего повторения кода, как это обычно бывает, если использовать вариант со статичным количеством файлов (последнее фото).