Тест

Загрузка файла(ов) на сервер из формы средствами PHP

Сегодня загрузка файлов является практически неотъемлемым атрибутом современного web приложения. В данной статье речь пойдёт о том, как же загрузить файл(ы) на сервер с помощью PHP.

Настройка php.ini

[Resource Limits] ; Максимальное время выполнения скрипта в секундах max_execution_time = 60 ; Максимальное потребление памяти одним скриптом memory_limit = 64M [Data Handling] ; Максимально допустимый размер данных отправляемых методом POST post_max_size = 5M [File Uploads] ; Разрешение на загрузку файлов file_uploads = On ; Папка для хранения файлов во время загрузки upload_tmp_dir = home/user/temp ; Максимальный размер загружаемого файла upload_max_filesize = 5M ; Максимально разрешённое количество одновременно загружаемых файлов max_file_uploads = 10

Конфигурационный файл php.ini необходимо настраивать согласно бизнес-логики проекта! Например, мы планируем загружать не более десяти файлов до 2 Мбайт, а это значит нам понадобиться ~20 Мбайт памяти.

Загрузка одного файла на сервер из формы

Для начала разберём механизм загрузки одной картинки на сервер. Для загрузки картинки с компьютера пользователя необходимо с помощью HTML-формы отправить нужный (выбранный) файл PHP-скрипту upload.php методом POST и указать способ кодирования данных enctype=»multipart/form-data» (в данном случае данные не кодируются и это значение применяется только для отправки бинарных файлов).

После отправки файла PHP-скрипту upload.php его можно перехватить с помощью суперглобальной переменной $_FILES с таким же именем, которая в массиве содержит информацию о файле (в нашем случае image ):

Array ( [name] => image.jpg // оригинальное имя файла [type] => image/jpeg // MIME-тип файла [tmp_name] => home\user\temp\phpD07E.tmp // бинарный файл [error] => 0 // код ошибки [size] => 17170 // размер файла в байтах )

Не всем данным из $_FILES можно доверять: MIME-тип и размер файла можно подделать, т. к. они формируются из HTTP-ответа, а расширению в имени файла не стоит доверять в силу того, что за ним может скрываться совершенно другой файл. Тем не менее, дальше нам нужно проверить корректно ли загрузился наш файл и загрузился ли он вообще. Для этого необходимо проверить ошибки в $_FILES[‘image’][‘error’] и удостовериться, что файл загружен методом POST с помощью функции is_uploaded_file() . Если что-то идёт не по плану, значит выводим ошибку на экран:

// Если в $_FILES существует "image" и она не NULL if (isset($_FILES['image'])) < $image = $_FILES['image']; // Получаем нужные элементы массива "image" $fileTmpName = $_FILES['image']['tmp_name']; $errorCode = $_FILES['image']['error']; // Проверим на ошибки if ($errorCode !== UPLOAD_ERR_OK || !is_uploaded_file($fileTmpName)) < // Массив с названиями ошибок $errorMessages = [ UPLOAD_ERR_INI_SIZE =>'Размер файла превысил значение upload_max_filesize в конфигурации PHP.', UPLOAD_ERR_FORM_SIZE => 'Размер загружаемого файла превысил значение MAX_FILE_SIZE в HTML-форме.', UPLOAD_ERR_PARTIAL => 'Загружаемый файл был получен только частично.', UPLOAD_ERR_NO_FILE => 'Файл не был загружен.', UPLOAD_ERR_NO_TMP_DIR => 'Отсутствует временная папка.', UPLOAD_ERR_CANT_WRITE => 'Не удалось записать файл на диск.', UPLOAD_ERR_EXTENSION => 'PHP-расширение остановило загрузку файла.', ]; // Зададим неизвестную ошибку $unknownMessage = 'При загрузке файла произошла неизвестная ошибка.'; // Если в массиве нет кода ошибки, скажем, что ошибка неизвестна $outputMessage = isset($errorMessages[$errorCode]) ? $errorMessages[$errorCode] : $unknownMessage; // Выведем название ошибки die($outputMessage); > else < echo 'Ошибок нет.'; >>;

Для того, чтобы «редиска» не загрузил вредоносный код, встроенный в изображение, нельзя доверять функции getimagesize() , которая также возвращает MIME-тип. Функция ожидает, что первый аргумент является ссылкой на корректный файл изображения. Определить настоящий MIME-тип картинки можно через расширение FileInfo . Код ниже проверит наличие ключевого слова image в типе нашего загружаемого файла и если его не окажется, выдаст ошибку:

// Создадим ресурс FileInfo $fi = finfo_open(FILEINFO_MIME_TYPE); // Получим MIME-тип $mime = (string) finfo_file($fi, $fileTmpName); // Проверим ключевое слово image (image/jpeg, image/png и т. д.) if (strpos($mime, 'image') === false) die('Можно загружать только изображения.');

Таким образом, при необходимости, делаем проверку и на другие MIME-типы. Например, для zip архивов проверка будет такая:

// Проверим ключевое слово zip (application/zip) if (strpos($mime, 'zip') === false) die('Можно загружать только архивы ZIP.');

На данном этапе мы уже можем загружать абсолютно любые картинки на наш сервер, прошедшие проверку на MIME-тип, но для загрузки изображений по определённым характеристикам нам необходимо валидировать их с помощью функции getimagesize() , которой отдадим сам бинарный файл $_FILES[‘image’][‘tmp_name’] . В результате мы получим массив из элементов:

// Результат функции запишем в переменную $image = getimagesize($fileTmpName); var_dump($image);die; // Результат Array ( [0] => 1280 // ширина [1] => 768 // высота [2] => 2 // тип [3] => width="1280" height="768" // атрибуты для HTML [bits] => 8 // глубина цвета [channels] => 3 // цветовая модель [mime] => image/jpeg // MIME-тип )

Для дальнейшей валидации изображения и работы над ним нам необходимо знать только 3 значения: ширину, высоту и размер файла (для вычисления размера применим функцию filesize() для бинарного файла из временной папки).

// Результат функции запишем в переменную $image = getimagesize($fileTmpName); // Зададим ограничения для картинок $limitBytes = 1024 * 1024 * 5; $limitWidth = 1280; $limitHeight = 768; // Проверим нужные параметры if (filesize($fileTmpName) > $limitBytes) die('Размер изображения не должен превышать 5 Мбайт.'); if ($image[1] > $limitHeight) die('Высота изображения не должна превышать 768 точек.'); if ($image[0] > $limitWidth) die('Ширина изображения не должна превышать 1280 точек.');

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

// Сгенерируем новое имя файла на основе MD5-хеша $name = md5_file($fileTmpName); // Сгенерируем расширение файла на основе типа картинки $extension = image_type_to_extension($image[2]); // Сократим .jpeg до .jpg $format = str_replace('jpeg', 'jpg', $extension); // Переместим картинку с новым именем и расширением в папку /upload if (!move_uploaded_file($fileTmpName, __DIR__ . '/upload/' . $name . $format)) < die('При записи изображения на диск произошла ошибка.'); >echo 'Картинка успешно загружена!';

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

function getRandomFileName($path) < $path = $path ? $path . '/' : ''; do < $name = md5(microtime() . rand(0, 9999)); $file = $path . $name; >while (file_exists($file)); return $name; >

Генерация имени для картинки теперь будет такой:

// Сгенерируем новое имя файла через функцию getRandomFileName() $name = getRandomFileName($fileTmpName);

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

Читайте также:  Running methods in python

Загрузка нескольких файлов на сервер из формы

Разберём механизм загрузки нескольких изображений за один раз с локальной машины пользователя. Продолжим дальше работать с $_FILES . Наша новая HTML-форма будет немного отличаться от старой.

Как видно в конец имени поля выбора файла name=»images[]» добавились фигурные скобки и атрибут multiple , который разрешает браузеру выбрать несколько файлов. Все файлы снова загрузятся во временную папку, если не будет никаких ошибок в php.ini . Перехватить их можно в $_FILES , но на этот раз суперглобальная переменная будет иметь неудобную структуру для обработки данных в массиве. Решается эта задача небольшими манипуляциями с массивом:

// Изменим структуру $_FILES foreach($_FILES['images'] as $key => $value) < foreach($value as $k =>$v) < $_FILES['images'][$k][$key] = $v; >// Удалим старые ключи unset($_FILES['images'][$key]); > // Загружаем все картинки по порядку foreach ($_FILES['images'] as $k => $v) < // Загружаем по одному файлу $fileTmpName = $_FILES['images'][$k]['tmp_name']; $errorCode = $_FILES['images'][$k]['error']; // Проверим на ошибки // . >

Мы реализовали механизм загрузки нескольких файлов на сервер. Весь код целиком лежит здесь .

Источник

Как я могу выбрать и загрузить несколько файлов с помощью HTML и PHP, используя HTTP POST?

У меня есть опыт загрузки одного файла с помощью . Однако у меня возникают проблемы с загрузкой более одного файла за раз. Например, я хочу выбрать серию изображений и загрузить их на сервер все сразу. Было бы здорово использовать элемент управления вводом одного файла, если это возможно. Кто-нибудь знает, как этого добиться?

Ответ 1

Это возможно в HTML5. Пример (PHP 5.4):

if (isset($_FILES[‘my_file’]))

$myFile = $_FILES[‘my_file’];

$fileCount = count($myFile[«name»]);

for ($i = 0; $i < $fileCount; $i++)

?>

File #:

Имя:

Временный файл:

Тип:

Размер:

Ошибка:

Читайте также:  Таблицы

>

>

?>

Это лишь набросок полностью рабочего ответа. Смотрите Руководство по PHP:

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

Ответ 2

Есть несколько вещей, которые необходимо сделать, чтобы создать загрузку нескольких файлов . Н а самом деле это довольно просто. Вам не нужно использовать Java, Ajax, Flash. Просто создайте обычную форму загрузки файлов, начиная с:

И тогда:

НЕ забывайте про скобки! В файле post_upload.php попробуйте сделать следующее:

Обратите внимание, что вы получите массив с данными tmp_name, что будет означать, что вы можете обращаться к каждому файлу с помощью третьей пары скобок с примером файла ‘number’:

$_FILES[‘file’][‘tmp_name’][0]

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

Ответ 3

Полное решение для Firefox:

echo «Количество файлов для загрузки : «.count($_FILES[‘infile’][‘name’]).»
«;

$uploadDir = «images/»;

for ($i = 0; $i < count($_FILES['infile']['name']); $i++)

echo «File names : «.$_FILES[‘infile’][‘name’][$i].»
«;

$ext = substr(strrchr($_FILES[‘infile’][‘name’][$i], «.»), 1);

// генерируем случайное новое имя файла, чтобы избежать конфликта имен

$fPath = md5(rand() * time()) . «.$ext»;

echo «Путь к файлу : «.$_FILES[‘infile’][‘tmp_name’][$i].»
«;

$result = move_uploaded_file($_FILES[‘infile’][‘tmp_name’][$i], $uploadDir . $fPath);

if (strlen($ext) > 0)

echo «Загрузка произведена». $fPath .» успешно.
«;

>

>

echo «Загрузка завершена.
«;

?>

Ответ 4

Если вы хотите выбрать несколько файлов из диалогового окна выбора файлов, которое отображается при выборе пункта browse, то вам в основном не повезло. Вам нужно будет использовать Java-апплет или что-то подобное (я думаю, что есть один вариант, который использует небольшой flash-файл, я обновлю, если найду его). В настоящее время ввод одного файла позволяет выбрать только один файл. Если вы говорите об использовании ввода нескольких файлов, то не должно быть большой разницы с использованием одного. Существует один метод использования одной кнопки « browse » , который использует flash. Я никогда не использовал его лично, но читал о нем достаточно много. Думаю, это лучший вариант.

Читайте также:  Таблица число колонок html

http://swfupload.org/

Ответ 5

Выберите изображение для загрузки:

Использование цикла FOR:

$file_dir = «uploads»;

if (isset($_POST[«submit»]))

for ($x = 0; $x < count($_FILES['file']['name']); $x++)

$file_name = $_FILES[‘file’][‘name’][$x];

$file_tmp = $_FILES[‘file’][‘tmp_name’][$x];

/* местоположение для сохранения файла */

$file_target = $file_dir . DIRECTORY_SEPARATOR . $file_name; /* DIRECTORY_SEPARATOR = / or \ */

if (move_uploaded_file($file_tmp, $file_target))

echo » был загружен.
«;

> else

echo «Ошибка, файл не был загружен .»;

>

>

>

?>

Использование цикла FOREACH:

$file_dir = «uploads»;

if (isset($_POST[«submit»]))

foreach ($_FILES[‘file’][‘name’] as $key => $value)

$file_name = $_FILES[‘file’][‘name’][$key];

$file_tmp = $_FILES[‘file’][‘tmp_name’][$key];

/* местоположение для сохранения файла */

$file_target = $file_dir . DIRECTORY_SEPARATOR . $file_name; /* DIRECTORY_SEPARATOR = / or \ */

if (move_uploaded_file($file_tmp, $file_target))

echo » был загружен.
«;

> else

echo «Ошибка, файл не был загружен .»;

>

>

>

?>

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.

Источник

Оцените статью