Сохранить файл из формы php. Загрузка файлов с помощью PHP на сервер

В нашей статье мы рассмотрим пример создания php скрипта загрузки файлов на сервер. Наш простой пример загрузки файлов будет иметь 2 файла: форма (form.html), php скрипт загрузки файлов (uploader.php).

Теперь разберем все детально. Сначала проанализируем файл формы form.html:


Как видите это простой html код, ничего сложного здесь нет, единственное, если форма будет загружать файлы на сервер, то должен быть прописан атрибут enctype=" multipart/ form- data" .

Наша форма будет выглядеть так:

Пример PHP скрипта загрузки файлов

Теперь разберемся с php файлом, который будет загружать файлы на сервер. Ниже предоставлен его исходный код:

// Where the file is going to be placed $target_path = ‘uploaded_files/"; /* Add the original filename to our target path. Result is "uploaded_files/filename.extension" */ $target_path = $target_path . basename($_FILES["file"]["name"]); if(move_uploaded_file($_FILES["file"]["tmp_name"], $target_path)) { echo "The file ". basename($_FILES["file"]["name"]). " has been uploaded"; } else{ echo "There was an error uploading the file, please try again!"; }

Как работает PHP скрипт загрузки файлов?

uploader.php это простой php скрипт загрузки файлов на сервер, который будет загружать наши файлы в определенную директорию сайта, которая указывается строкой $target_path = "uploaded_files/";

Ну и само собой делаем элементарный вывод сообщений с помощью if/else, чтобы понятно было, загружен наш файл или нет.

Защита от хакерских взломов при загрузке файла

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

PHP оболочка файла

Это первая проблема, связанная с загрузкой файлов на сервер. Когда загружаемый файл имеет оболочку php, и это не значит, что его расширение будет php. Он может иметь вид image.jpg (.gif, .png…). Но внутри выглядеть подобным образом:

Некоторые умельцы также могут выполнять команды на сервере с помощью серфинга по url:

$ curl http://server/uploads/shell.php?command=any_unix_command

Способ защиты:

Для защиты, можно реализовать MIME проверку файла. Ниже смотрите пример:

If($_FILES["file"]["type"] != "image/gif") { echo "Sorry, we only allow uploading GIF images"; exit; }

Данный кусок php кода проверяет, является ли загружаемый файл GIF файлом. Вставьте этот код перед php скриптом загрузки файлов. Естественно, вы можете поменять проверку на jpg, pngили другие нужные вам файлы.

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

Ограничение размера загружаемого файла

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

Можно это сделать с помощью формы, для этого нужно добавить следующую строку в контекст html формы:

Это скрытое поле ввода ограничит размер загружаемого файла. Или можно сделать проверку размера файла средствами PHP.

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

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

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

Но не буду вас запугивать, а лучше представлю вашему вниманию уже готовую функцию (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.

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

Обработка загружаемых файлов - стандартный процесс, но существует несколько мелочей, на которые необходимо обратить внимание перед началом работы. Первое, в чем нужно удостовериться, что 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 . Вы можете просматривать, загружать или клонировать репозиторий и играть с кодом, чтобы лучше понять, как работает процесс загрузки файлов.

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

PHP способен получать загруженные файлы из любого браузера, совместимого со стандартом RFC-1867.

Также следует заметить, что PHP поддерживает загрузку файлов методом PUT, который используется в клиентах Netscape Composer и W3C Amaya . Для получения более детальной документации обратитесь к разделу поддержка метода PUT .

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

Страница для загрузки файлов может быть реализована при помощи специальной формы, которая выглядит примерно так:

Отправить этот файл:

В приведенном выше примере __URL__ необходимо заменить ссылкой на PHP-скрипт.

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

Замечание :

Также следует убедиться, что форма загрузки имеет атрибут enctype="multipart/form-data" , в противном случае загрузка файлов на сервер не произойдет.

Оригинальное имя файла на компьютере клиента.

$_FILES["userfile"]["type"]

Mime-тип файла, в случае, если браузер предоставил такую информацию. В качестве примера можно привести "image/gif" . Этот mime-тип не проверяется на стороне PHP, так что не полагайтесь на его значение без проверки.

$_FILES["userfile"]["size"]

Размер в байтах принятого файла.

$_FILES["userfile"]["tmp_name"]

Временное имя, с которым принятый файл был сохранен на сервере.

$_FILES["userfile"]["error"]

По окончанию работы скрипта, если загруженный файл не был переименован или перемещен, он будет автоматически удален из временной папки.

Изображения:

foreach ($_FILES [ "pictures" ][ "error" ] as $key => $error ) {
if ($error == UPLOAD_ERR_OK ) {
$tmp_name = $_FILES [ "pictures" ][ "tmp_name" ][ $key ];
// basename() может спасти от атак на файловую систему;
// может понадобиться дополнительная проверка/очистка имени файла
$name = basename ($_FILES [ "pictures" ][ "name" ][ $key ]);
move_uploaded_file ($tmp_name , "data/ $name " );
}
}
?>

Полоса прогресса загрузки файлов может быть реализована с помощью "отслеживания прогресса загрузки файлов с помощью сессий ".

Use Psr \ Http \ Message \ UploadedFileInterface ;
use Zend \ Diactoros \ ServerRequestFactory ;

$request = ServerRequestFactory :: fromGlobals ();

if ($request -> getMethod () !== "POST" ) {
http_response_code (405 );
exit("Use POST method." );
}

$uploaded_files = $request -> getUploadedFiles ();

if (
!isset($uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ]) ||
! $uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ] instanceof UploadedFileInterface
) {
http_response_code (400 );
exit("Invalid request body." );
}

$file = $uploaded_files [ "files" ][ "x" ][ "y" ][ "z" ];

if ($file -> getError () !== UPLOAD_ERR_OK ) {
);
}

$file -> moveTo ("/path/to/new/file" );

?>

9 years ago

I think the way an array of attachments works is kind of cumbersome. Usually the PHP guys are right on the money, but this is just counter-intuitive. It should have been more like:

Array
=> Array
=> facepalm.jpg
=> image/jpeg
=> /tmp/phpn3FmFr
=> 0
=> 15476
)

=> Array
=>
=>
=>
=> 4
=>
)

and not this
Array
=> Array
=> facepalm.jpg
=>
)

=> Array
=> image/jpeg
=>
)

=> Array
=> /tmp/phpn3FmFr
=>
)

=> Array
=> 0
=> 4
)

=> Array
=> 15476
=> 0
)

Anyways, here is a fuller example than the sparce one in the documentation above:

foreach ($_FILES [ "attachment" ][ "error" ] as $key => $error )
{
$tmp_name = $_FILES [ "attachment" ][ "tmp_name" ][ $key ];
if (! $tmp_name ) continue;

$name = basename ($_FILES [ "attachment" ][ "name" ][ $key ]);

If ($error == UPLOAD_ERR_OK )
{
if (move_uploaded_file ($tmp_name , "/tmp/" . $name ))
$uploaded_array .= "Uploaded file "" . $name . "".
\n" ;
else
$errormsg .= "Could not move uploaded file "" . $tmp_name . "" to "" . $name . ""
\n" ;
}
else $errormsg .= "Upload error. [" . $error . "] on file "" . $name . ""
\n" ;
}
?>

3 years ago

The documentation doesn"t have any details about how the HTML array feature formats the $_FILES array.

Example $_FILES array:

For single file -

Array
=> Array
=> sample-file.doc
=> application/msword
=> /tmp/path/phpVGCDAJ
=> 0
=> 0
)

Multi-files with HTML array feature -

Array
=> Array
=> Array
=> sample-file.doc
=> sample-file.doc
)

=> Array
=> application/msword
=> application/msword
)

=> Array
=> /tmp/path/phpVGCDAJ
=> /tmp/path/phpVGCDAJ
)

=> Array
=> 0
=> 0
)

=> Array
=> 0
=> 0
)

The problem occurs when you have a form that uses both single file and HTML array feature. The array isn"t normalized and tends to make coding for it really sloppy. I have included a nice method to normalize the $_FILES array.

Function normalize_files_array ($files = ) {

$normalized_array = ;

Foreach($files as $index => $file ) {

If (! is_array ($file [ "name" ])) {
$normalized_array [ $index ] = $file ;
continue;
}

Foreach($file [ "name" ] as $idx => $name ) {
$normalized_array [ $index ][ $idx ] = [
"name" => $name ,
"type" => $file [ "type" ][ $idx ],
"tmp_name" => $file [ "tmp_name" ][ $idx ],
"error" => $file [ "error" ][ $idx ],
"size" => $file [ "size" ][ $idx ]
];
}

Return $normalized_array ;

?>

The following is the output from the above method.

Array
=> Array
=> Array
=> sample-file.doc
=> application/msword
=> /tmp/path/phpVGCDAJ
=> 0
=> 0
)

=> Array
=> Array
=> sample-file.doc
=> application/msword
=> /tmp/path/phpVGCDAJ
=> 0
=> 0
)

=> Array
=> sample-file.doc
=> application/msword
=> /tmp/path/phpVGCDAJ
=> 0
=> 0
)

10 years ago

Also note that since MAX_FILE_SIZE hidden field is supplied by the browser doing the submitting, it is easily overridden from the clients" side. You should always perform your own examination and error checking of the file after it reaches you, instead of relying on information submitted by the client. This includes checks for file size (always check the length of the actual data versus the reported file size) as well as file type (the MIME type submitted by the browser can be inaccurate at best, and intentionally set to an incorrect value at worst).

3 years ago

For clarity; the reason you would NOT want to replace the example script with
$uploaddir = "./";
is because if you have no coded file constraints a nerd could upload a php script with the same name of one of your scripts in the scripts directory.

Given the right settings and permissions php-cgi is capable of replacing even php files.

Imagine if it replaced the upload post processor file itself. The next "upload" could lead to some easy exploits.

Even when replacements are not possible; uploading an .htaccess file could cause some problems, especially if it is sent after the nerd throws in a devious script to use htaccess to redirect to his upload.

There are probably more ways of exploiting it. Don"t let the nerds get you.

More sensible to use a fresh directory for uploads with some form of unique naming algorithm; maybe even a cron job for sanitizing the directory so older files do not linger for too long.

2 years ago

I have found it useful to re-order the multidimensional $_FILES array into a more intuitive format, as proposed by many other developers already.

Unfortunately, most of the proposed functions are not able to re-order the $_FILES array when it has more than 1 additional dimension.

Therefore, I would like to contribute the function below, which is capable of meeting the aforementioned requirement:

function get_fixed_files () {
$function = function($files , $fixed_files = array(), $path = array()) use (& $function ) {
foreach ($files as $key => $value ) {
$temp = $path ;
$temp = $key ;

If (is_array ($value )) {
$fixed_files = $function ($value , $fixed_files , $temp );
} else {
$next = array_splice ($temp , 1 , 1 );
$temp = array_merge ($temp , $next );

$new = & $fixed_files ;

Foreach ($temp as $key ) {
$new = & $new [ $key ];
}

$new = $value ;
}
}

Return $fixed_files ;
};

Return $function ($_FILES );
}
?>

Side note: the unnamed function within the function is used to avoid confusion regarding the arguments necessary for the recursion within the function, for example when viewing the function in an IDE.

Multipart-формы

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

Загрузка файла на сервер осуществляется с помощью multipart -формы, в которой есть поле загрузки файла. В качестве параметра enctype указывается значение multipart/form-data :



Вот так примерно будет выглядеть приведенная multipart-форма (вы можете попробовать с ее помощью посмотреть результат работы multipart-форм, загрузив какой-нибудь файл небольшого размера на сервер):

Multipart-формы обычно используют метод передачи POST. Как видно из предыдущего примера, данная форма имеет два поля:

  • Поле выбора файла для закачки ;
  • Поле указания имени файла, которое он должен будет иметь на сервере .

Обработка multipart-форм

Прежде, чем приступить к написанию скрипта обработки multipart-формы, нужно отредактировать файл конфигурации php.ini , чтобы разрешить загрузку файлов на сервер.

Конфигурационный файл PHP php.ini имеет три параметра, связанные с загрузкой файлов на сервер:

  • file_uploads=On - разрешает загрузку файлов на сервер по протоколу HTTP;
  • upload_tmp_dir=/tmp - устанавливает каталог для временного хранения загруженных файлов;
  • upload_max_filesize=2M - устанавливает максимальный объем загружаемых файлов.

Если ваш веб-сервер работает под управлением операционной системы Linux, то нужно перезапустить сервис:

service httpd restart

Как же PHP обрабатывает multipart-формы? Получив файл, он сохраняет его во временном каталоге upload_tmp_dir , имя файла выбирается случайным образом. Затем он создает четыре переменных суперглобального массива $_FILES . Этот массив содержит информацию о загруженном файле.

Переменные, определенные для загруженных файлов, зависят от версии PHP и текущей конфигурации. Суперглобальный массив $_FILES доступен начиная с PHP 4.1.0. В случае, если конфигурационная директива register_globals установлена значением on , дополнительно будут объявлены переменные с соответствующими именами. Начиная с версии 4.2.0 значением по умолчанию для опции register_globals является off .

Содержимое массива $_FILES для нашего примера приведено ниже. Обратите внимание, что здесь предполагается использование имени uploadfile для поля выбора файла, в соответствии с приведенной выше multipart-форме. Разумеется, имя поля может быть любым.

  • $_FILES["uploadfile"]["name"] - имя файла до его отправки на сервер, например, pict.gif;
  • $_FILES["uploadfile"]["size"] - размер принятого файла в байтах;
  • $_FILES["uploadfile"]["type"] - MIME-тип принятого файла (если браузер смог его определить), например: image/gif, image/png, image/jpeg, text/html;
  • (так мы назвали поле загрузки файла) - содержит имя файла во временном каталоге, например: /tmp/phpV3b3qY;
  • $_FILES["uploadfile"]["error"] - Код ошибки, которая может возникнуть при загрузке файла. Ключ ["error"] был добавлен в PHP 4.2.0. С соответствующими кодами ошибок вы можете ознакомиться

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

Если кнопка "Submit" нажата, то файл уже будет загружен на сервер и его имя будут в переменной $_FILES["uploadfile"]["name"] . В этом случае скрипт должен сразу скопировать файл с именем $_FILES["uploadfile"]["tmp_name"] в какой-нибудь каталог (необходимы права на запись в этот каталог).

Копирование файла производится функцией copy() :

Используйте только функцию копирования copy() , а не перемещения, поскольку:

  • Временный файл будет удален автоматически;
  • Если временный каталог находится на другом носителе, будет выведено сообщение об ошибке.

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

// На всякий случай создадим каталог. Если он уже создан,
// сообщение об ошибки мы не увидим, поскольку воспользуемся оператором @:

@mkdir("uploads", 0777);

// Копируем файл из /tmp в uploads
// Имя файла будет таким же, как и до отправки на сервер:

Copy($_FILES["uploadfile"]["tmp_name"],"uploads/".basename($_FILES["uploadfile"]["name"]));

В Linux все намного сложнее - нам нужно учитывать права доступа к каталогу uploads . Скорее всего в таком случае, функция mkdir() не сработает, так как у нас нет прав на запись в каталог DocumentRoot (обычно это /var/www/html или /home/httpd/html). Зарегистрируйтесь в системе как пользователь root , создайте каталог uploads и измените его владельца и права доступа следующим образом:

// Создаем каталог uploads

// Устанавливаем имя владельца apache и его группу - тоже apache:

Chown apache:apache uploads

// Разрешение записи всем (777) + установка закрепляющего бита (1):

Chmod 1777 uploads

Размер файла можно ограничить, при желании можно отредактировать файл .htaccess и ограничить доступ к каталогу uploads - указать или конкретных пользователей, которым можно обращаться к каталогу, или IP-адреса.

Вот теперь можно загружать файлы на сервер.

Пишем PHP скрипт загрузки файлов на сервер


// Каталог, в который мы будем принимать файл:
$ uploaddir = "./files/" ;
$ uploadfile = $ uploaddir . basename ($ _FILES [ "uploadfile" ][ "name" ]);

// Копируем файл из каталога для временного хранения файлов:
if (copy ($ _FILES [ "uploadfile" ][ "tmp_name" ], $ uploadfile ))
{
echo "

Файл успешно загружен на сервер

" ;
}
else { echo "

Ошибка! Не удалось загрузить файл на сервер!

"
; exit ; }

// Выводим информацию о загруженном файле:
echo "

Информация о загруженном на сервер файле:

"
;
echo "

Оригинальное имя загруженного файла: " .$ _FILES [ "uploadfile" ][ "name" ]. "

" ;
echo "

Mime-тип загруженного файла: " .$ _FILES [ "uploadfile" ][ "type" ]. "

" ;
echo "

Размер загруженного файла в байтах: " .$ _FILES [ "uploadfile" ][ "size" ]. "

" ;
echo "

Временное имя файла: " .$ _FILES [ "uploadfile" ][ "tmp_name" ]. "

" ;

?>

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

Также предусмотрена возможность автоматического получения организованной в массив информации о нескольких одновременно загружаемых файлах. Для реализации такой возможности используйте тот же синтаксис отправки массива из HTML-формы, что и для множественных полей select и checkbox :


Send these files:






В случае, если такая форма была отправлена, массивы $_FILES["userfile"] , $_FILES["userfile"]["name"] , и $_FILES["userfile"]["size"] будут инициализированы (точно так же, как и $HTTP_POST_FILES для PHP 4.1.0 и более ранних версий). Если конфигурационная директива register_globals установлена значением on , также будут инициализированы сопутствующие глобальные переменные. Каждая из таких переменных будет представлять собой численно индексированный массив соответствующих значений для принятых файлов.

Предположим, что были загружены файлы /home/test/some.html и /home/test/file.bin . В таком случае переменная $_FILES["userfile"]["name"] будет иметь значение some.html , а переменная $_FILES["userfile"]["name"] - значение file.bin . Аналогично, переменная $_FILES["userfile"]["size"] будет содержать размер файла some.html и так далее.

Переменные $_FILES["userfile"]["name"] , $_FILES["userfile"]["tmp_name"] , $_FILES["userfile"]["size"] и $_FILES["userfile"]["type"] также будут инициализированы.

Заключение:

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



<<< Назад Содержание Вперед >>>
Есть еще вопросы или что-то непонятно - добро пожаловать на наш


В продолжение темы:
Android

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