Подгружать файл с компьютера php. Загрузка файлов с помощью PHP на сервер


Что может быть общего у фотографий, находящихся в онлайн-фотоальбоме, прикреплённых к электронному письму или у файлов, представленных в онлайн-приложении для пакетной обработки? Всех их необходимо загрузить на сервер через интернет из веб-браузера. Действительно, загрузка файлов является важной особенностью многих сайтов и веб-приложений, которые мы используем ежедневно. Из этой статьи вы узнаете, как добавить к себе на сайт поддержку загрузки файлов используя для этого PHP.

Требования перед загрузкой файлов

Обработка загружаемых файлов - стандартный процесс, но существует несколько мелочей, на которые необходимо обратить внимание перед началом работы. Первое, в чем нужно удостовериться, что PHP настроен и позволяет загружать файлы. Для этого в php.ini стоит проверить директиву file_uploads , и, если она выключена, то включить.

File_uploads = On

Загружаемые файлы сначала сохраняются во временном каталоге (но не волнуйтесь... ваш PHP-скрипт впоследствии может переместить файлы в более подходящее место). Исходное местоположение является временным каталогом для системы по умолчанию. Вы можете указать другой каталог, используя директиву upload_tmp_dir в php.ini. Независимо от этого, будет не лишним проверить, что процесс PHP имеет правильные права на запись в зависимости от используемого каталога.

Upload_tmp_dir = "/tmp" tboronczyk@zarkov:~$ ls -l / | grep tmp drwxrwxrwt 13 root root 40960 2011-08-31 00:50 tmp

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

использовал метод POST и имел атрибут enctype , установленный для multipart/form-data .

Этапы загрузки файла на сервер

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

  • Посетитель просматривает HTML-страницу с формой, специально написанной для поддержки загрузки файлов;
  • Далее он предоставляет файл, который он хочет загрузить и нажимает кнопку отправить;
  • Браузер кодирует файл и отправляет его как часть запроса POST;
  • PHP получает форму отправки, декодирует файл и сохраняет его во временном месте на сервере;
  • Написанный PHP-скрипт, ответственный за обработку сообщения формы, проверяет файл и обрабатывает его каким-то образом, часто перемещая его из своего временного местоположения в постоянное, где будет храниться файл.

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

Добавляем HTML форму для загрузки файла

HTML-формы предоставляют собой интерфейс, через который пользователь инициирует загрузку файла. Нужно помнить, что элемент должен иметь свой атрибут метода, установленный для публикации, и его атрибут enctype , заданный для multipart/form-data . Элемент файла предоставляет поле, используемое для указания файла, который будет загружен. Как и любой другой элемент формы, важно указать атрибут имени, чтобы вы могли ссылаться на него в PHP скрипте, обрабатывающем форму.

Вот как выглядит типичная разметка формы загрузки файлов:


Стоит отметить, что разные браузеры будут визуализировать поле загрузки файла по-разному. IE, Firefox и Opera отображают его как текстовое поле с кнопкой рядом с ней надписью «Обзор» или «Выбрать». Safari отображает ее так же, как кнопку с надписью: «Выбрать файл». По большому счету это не проблема с тех пор, как пользователи привыкли к тому, как поле отображается в своем браузере и умеют его использовать. Иногда, однако, вы столкнетесь с клиентом или дизайнером, который непреклонно представляет его определенным образом. Количество CSS и JavaScript, которые могут применяться к файловому полю, крайне ограничено из-за соображений о безопасности, наложенных браузерами. Типизация файла может быть затруднена. Если внешний вид очень важен для вас, я рекомендую вам прочитать одну из статей «Питер-Пол Кох» типа ввода = «файл» .

Переходим на сервере и работаем с PHP

Информация о загрузке файла предоставляется с помощью многомерного массива $_FILES . Этот массив обладает своей структурой, назначенными именами для полей файла в форме HTML, точно так же, как и при работе с $_GET и $_POST . Затем массив каждого файла содержит следующие элементы:

  • $_FILES["myFile"]["name"] - хранит исходное имя файла;
  • $_FILES["myFile"]["type"] - сохраняет mime-типа файла;
  • $_FILES["myFile"]["size"] - сохраняет размер файла (в байтах);
  • $_FILES["myFile"]["tmp_name"] - хранит имя временного файла;
  • $_FILES["myFile"]["error"] - хранит код ошибки, полученный в результате передачи.

При помощи функции move_uploaded_file() мы можем перенести файл из своего временного каталога в постоянное место. Так же хорошей практикой является использовать именно её вместо copy() и rename() для этой цели, поскольку она выполняет дополнительные проверки, чтобы гарантировать, что файл был действительно загружен запросом HTTP методом POST.

Если вы собираетесь сохранить файл с исходным именем, предоставленным пользователем, рекомендуется убедиться, что это безопасно. Имя файла не должно содержать символов, которые могут повлиять на путь назначения, например, косая черта (слэш). Имя файла должно быть уникальным, чтоб избежать затирания существующих с тем же именем (если это не предусматривается вашим приложением). Гарантировать это можно заменяя любые символы символом подчеркивания, который не является буквой, а затем добавляя увеличивающийся номер, если файл с таким именем уже существует.

Вот так как выглядит получение и обработка загрузки файла при помощи PHP:

Define("UPLOAD_DIR", "/srv/www/uploads/"); if (!empty($_FILES["myFile"])) { $myFile = $_FILES["myFile"]; if ($myFile["error"] !== UPLOAD_ERR_OK) { echo "

Произошла ошибка.

"; exit; } // обеспечиваем безопасное имени файла $name = preg_replace("/[^A-Z0-9._-]/i", "_", $myFile["name"]); // не перезаписываем существующий файл $i = 0; $parts = pathinfo($name); while (file_exists(UPLOAD_DIR . $name)) { $i++; $name = $parts["filename"] . "-" . $i . "." . $parts["extension"]; } // сохраняем файл из временного каталога $success = move_uploaded_file($myFile["tmp_name"], UPLOAD_DIR . $name); if (!$success) { echo ""; exit; } // устанавливаем правильные права для нового файла chmod(UPLOAD_DIR . $name, 0644); }

Сначала мы удостоверяемся, что PHP загрузка файла на сервер прошла без ошибок. Затем определяем безопасное имя файла, как я только что описал выше, а затем перемещаем файл в его конечный каталог с помощью move_uploaded_file() . И наконец делаем вызов chmod() , чтобы убедиться, что в новом файле установлены необходимые права доступа.

Вопросы безопасности

Один из них заключается в том, чтобы проверить тип загружаемого файла, каким он должен быть. Опираться на значение $_FILES["myFile"]["type"] или на расширение имени файла не является безопасным, поскольку оба могут легко подделываться. Скорее, используйте функцию exif_imagetype() , чтобы проверить содержимое файла и определить, действительно ли это GIF, JPEG или один из нескольких других поддерживаемых форматов изображений. Если exif_imagetype() недоступен (функция требует, чтобы расширение Exif было включено), вы можете использовать getimagesize() . Массив, возвращаемый ей, будет содержать тип изображения, если он распознан.

// проверяем файл GIF, JPEG или PNG $fileType = exif_imagetype($_FILES["myFile"]["tmp_name"]); $allowed = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG); if (!in_array($fileType, $allowed)) { // тип файла не разрешен...

Для файлов без изображения вы можете использовать exec() для вызова утилиты файлов unix. он определяет тип файла, ища известные двоичные подписи в ожидаемых местах.

// проверяем файл в формате PDF $mime = "application/pdf; charset=binary"; exec("file -bi " . $_FILES["myFile"]["tmp_name"], $out); if ($out != $mime) { // файл не PDF ...

Еще один шаг, который вы можете предпринять, - наложить жесткие ограничения на общий размер запроса POST и количество файлов, которые можно загрузить. Для этого укажите соответствующее значение для директив upload_max_size , post_max_size и max_file_uploads в php.ini. Директива upload_max_size указывает максимальный размер загрузки файла. В дополнение к размеру загрузки вы можете ограничить размер всего запроса POST директивой post_max_size . max_file_uploads - это новая директива (добавлена в версии 5.2.12), которая ограничивает количество загрузок файлов. Эти три директивы помогают защитить ваш сайт от атак, которые пытаются нарушить его доступность, вызывая интенсивный сетевой трафик или загрузку системы.

Post_max_size = 8M upload_max_size = 2M max_file_uploads = 20

Третий шаг, который вы можете предпринять для минимизации риска, - это сканирование загруженных файлов с помощью антивирусного сканера. Это жизненно важно для защиты от распространённых вирусов и вредоносных программ, особенно если ваш сайт осуществляет файлообмен между разными людьми, как пример - вложения в веб-почтовый клиент или (юридический) сайт для обмена файлами. Существует расширение PHP, которое обеспечивает доступ к ClamAV , но, конечно, вы можете вызвать утилиту командной строки ClamAV так же, как я продемонстрировал для файла.

Exec("clamscan --stdout " . $_FILES["myFile"]["tmp_name"], $out, $return); if ($return) { // файл заражен...

Подводим итоги и делаем выводы

Сегодня вы узнали, как происходит настройка и осуществляется процесс PHP загрузки файлов на сервер с вашего сайта или веб-приложения. Чтобы загрузка была успешной, форма HTML должна быть отправлена через запрос POST с множественным форматированием данных, а PHP должен разрешать передачу, как указано, с помощью директивы file_uploads . После переноса файла, сценарий, ответственный за обработку загрузки, использует информацию, найденную в массиве $_FILES , чтобы переместить файл из временного каталога в нужное место. Я также поделился некоторыми дополнительными мерами предосторожности, которые вы можете предпринять, чтобы защитить себя и своих пользователей от некоторых рисков, связанных с возможностью загрузки файлов. Чтобы гарантировать свою безопасность - проверяйте тип файла, наложите жесткие ограничения на загрузку трафика и применяйте сканирование на наличие вирусов.

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

Последнее обновление: 1.11.2015

Чтобы загрузить файл на сервер, нам надо использовать форму с параметром enctype="multipart/form-data" и массив $_FILES . Итак, создадим файл upload.php со следующим содержимым:

Загрузка файла

Выберите файл:

Здесь определена форм с атрибутом enctype="multipart/form-data" . Форма содержит специальное поле для выбора файла.

Все загружаемые файлы попадают в ассоциативный массив $_FILES . Чтобы определить, а есть ли вообще загруженные файлы, можно использовать конструкцию if: if ($_FILES)

Массив $_FILES является двухмерным. Мы можем загрузить набор файлов, и каждый загруженный файл можно получить по ключу, который совпадает со значением атрибута name .

Так как элемент для загрузки файла на форме имеет name="filename" , то данный файл мы можем получить с помощью выражения $_FILES["filename"] .

У каждого объекта файла есть свои параметры, которые мы можем получить:

    $_FILES["file"]["name"] : имя файла

    $_FILES["file"]["type"] : тип содержимого файла, например, image/jpeg

    $_FILES["file"]["size"] : размер файла в байтах

    $_FILES["file"]["tmp_name"] : имя временного файла, сохраненного на сервере

    $_FILES["file"]["error"] : код ошибки при загрузке

Также мы можем проверить наличие ошибок при загрузке. Если у нас нет ошибки, то поле $_FILES["filename"]["error"] содержит значение UPLOAD_ERR_OK .

При отправке файла на сервер он сначала загружается во временное место, из которого затем с помощью функции move_uploaded_file() он перемещается в каталог сервера.

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

Ограничения и настройка загрузки

По умолчанию размер загружаемых файлов ограничен 2 мб. Однако можно настроить данный показатель в файле конфигурации. Изменим этот показатель, например, до 10 мб. Для этого найдем в файле php.ini следующую строку:

Upload_max_filesize = 2M

Изменим ее на

Upload_max_filesize = 10M

Также мы можем настроить папку для временных загружаемых файлов. Для этого в файле php.ini найдем следующую строку:

;upload_tmp_dir =

Изменим ее на

Upload_tmp_dir = "C:/php/upload"

Также в каталоге php нам надо создать папку upload .

Мультизагрузка

Изменим скрипт upload.php так, чтобы он поддерживал множественную загрузку:

$error) { if ($error == UPLOAD_ERR_OK) { $tmp_name = $_FILES["uploads"]["tmp_name"][$key]; $name = $_FILES["uploads"]["name"][$key]; move_uploaded_file($tmp_name, "$name"); } } } ?>

Загрузка файла




Каждое поле выбора файла имеет атрибут name="uploads" , поэтому сервер будет рассматривать набор отправленных файлов как единый массив.

Затем используя цикл foreach , проходим по все файлам и сохраняем их в каталог веб-сайта.

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

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

Но не буду вас запугивать, а лучше представлю вашему вниманию уже готовую функцию (PHP скрипт) для проверки и загрузки файлов на сервер. Функция 100% рабочая. Я сам использую её на своих сайтах. Данная функция написана под загрузку файлов изображений (фоток) в формате.jpg, .gif, .png. Но при желании можно внести изменения, чтобы адаптировать PHP скрипт под свои нужды.

В php скрипте реализованы две проверки:

  1. так как хостер ограничивает размер загружаемого файла (на момент написания данного материала у меня на хостинге стоит ограничение в 8 Mb), то проверка максимального размера необходима;
  2. проверка расширения файла позволяет отсеять ненужные файлы до загрузки.

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

Теперь о том, как это реализовать практически

Помещаем PHP код функции в отдельный файл: function.php и размещаем его на сервере в корневом каталоге.

И создадим html-файл в котором разместим форму для загрузки фото: index.html

upload.php - файл обработчик формы
name="button" - имя кнопки, при нажатии на которую запускается функция загрузки файла на сервер

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

Теперь разберем случай, когда необходимо загрузить на сервер сразу несколько файлов.
Для этого нам понадобиться в файлах function.php upload.php и index.html сделать некоторые изменения.





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

Еще одна функция, которая тесно связана с загрузкой графических файлов (фоток) - это функция для изменения размеров фотки:

Если Вам потребовалось отдавать файлы не напрямую веб сервером, а с помощью PHP (например для сбора статистики скачиваний), прошу под кат.

1. Используем readfile()

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

Function file_force_download($file) { if (file_exists($file)) { // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) { ob_end_clean(); } // заставляем браузер показать окно сохранения файла header("Content-Description: File Transfer"); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=" . basename($file)); header("Content-Transfer-Encoding: binary"); header("Expires: 0"); header("Cache-Control: must-revalidate"); header("Pragma: public"); header("Content-Length: " . filesize($file)); // читаем файл и отправляем его пользователю readfile($file); exit; } }
Таким способом можно отправлять даже большие файлы, так как PHP будет читать файл и сразу отдавать его пользователю по частям. В документации четко сказано, что readfile() не должен создавать проблемы с памятью.

Особенности:

  • Файл читается в внутренний буфер функции readfile(), размер которого составляет 8кБ (спасибо 2fast4rabbit)

2. Читаем и отправляем файл вручную

Метод использует тот же Drupal при отправке файлов из приватной файловой системы (файлы недоступны напрямую по ссылкам):

Function file_force_download($file) { if (file_exists($file)) { // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт // если этого не сделать файл будет читаться в память полностью! if (ob_get_level()) { ob_end_clean(); } // заставляем браузер показать окно сохранения файла header("Content-Description: File Transfer"); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=" . basename($file)); header("Content-Transfer-Encoding: binary"); header("Expires: 0"); header("Cache-Control: must-revalidate"); header("Pragma: public"); header("Content-Length: " . filesize($file)); // читаем файл и отправляем его пользователю if ($fd = fopen($file, "rb")) { while (!feof($fd)) { print fread($fd, 1024); } fclose($fd); } exit; } }
Особенности:

  • Скрипт ждет пока весь файл будет прочитан и отдан пользователю.
  • Позволяет сэкономить память сервера

3. Используем модуль веб сервера

3a. Apache
Модуль XSendFile позволяет с помощью специального заголовка передать отправку файла самому Apache. Существуют версии по Unix и Windows, под версии 2.0.*, 2.2.* и 2.4.*

В настройках хоста нужно включить перехват заголовка с помощью директивы:
XSendFile On
Также можно указать белый список директорий, файлы в которых могут быть обработаны. Важно: если у Вас сервер на базе Windows путь должен включать букву диска в верхнем регистре.

Описание возможных опций на сайте разработчика: https://tn123.org/mod_xsendfile/

Пример отправки файла:

Function file_force_download($file) { if (file_exists($file)) { header("X-SendFile: " . realpath($file)); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=" . basename($file)); exit; } }

3b. Nginx
Nginx умеет отправлять файлы из коробки через специальный заголовок.

Для корректной работы нужно запретить доступ к папку напрямую через конфигурационный файл:
location /protected/ { internal; root /some/path; }
Пример отправки файла (файл должен находиться в директории /some/path/protected):

Function file_force_download($file) { if (file_exists($file)) { header("X-Accel-Redirect: " . $file); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=" . basename($file)); exit; } }
Больше информации на странице официальной документации

Особенности:

  • Скрипт завершается сразу после выполнения всех инструкций
  • Физически файл отправляется модулем самого веб сервера, а не PHP
  • Минимальное потребление памяти и ресурсов сервера
  • Максимальное быстродействие

Update: Хабраюзер ilyaplot дает дельный совет, что лучше слать не application/octet-stream , а реальный mime type файла. Например, это позволит браузеру подставить нужные программы в диалог сохранение файла.

Приложение для загрузки файлов на сервер представляет собой HTML-форму (upload.html) и скрипт upload.php для ее обработки.

Замечание: Вы можете загрузить промышленную версию системы загрузки файлов на сервер из раздела . Система позволит вам не только загрузить файл на сервер, но и изменить его размер, фон и др.

Код формы (upload.html)

Форма для загрузки файлов



Код скрипта обработки формы (upload.php)

Результат загрузки файла 1024 * 3 * 1024 ) { echo (); exit; } // Проверяем загружен ли файл if(is_uploaded_file ($_FILES [ "filename" ][ "tmp_name" ])) { // Если файл загружен успешно, перемещаем его // из временной директории в конечную move_uploaded_file ($_FILES [ "filename" ][ "tmp_name" ], "/path/to/file/" . $_FILES [ "filename" ][ "name" ]); } else { echo("Ошибка загрузки файла" ); } ?>

Атрибут entype формы определяет вид кодировки, которую браузер применяет к параметрам формы. Для того чтобы отправка файлов на сервер действовала, атрибуту entype необходимо присвоить значение multipart/form-data. По умолчанию этот атрибут имеет значение application/x-www-form-urlencoded.

Элемент ввода этой формы должен иметь тип file.

После того, как получен HTTP-запрос, содержимое загруженного файла записывается во временный файл, который создается в каталоге сервера, заданном по умолчанию для временных файлов, если другой каталог не задан в файле php.ini (директива upload_tmp_dir).

Характеристики загруженного файла доступны через двумерный массив $_FILES.

Cкрипт upload.php загружает файл на сервер и копирует его в каталог /path/to/file/.

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

1024 * 3 * 1024 ) { echo("Размер файла превышает три мегабайта" ); exit; } ... ?>

Максимальный размер загружаемого файла можно также задать при помощи директивы upload_max_filesize, значение которой по умолчанию равно 2 Мбайт:

upload_max_filesize ) .. ?>
Похожие публикации