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



В этой статье достаточно полно рассказывается о широко используемом методе загрузки файлов на сервер методом POST.

Нам понадобится: html страничка с формой для выбора файла, любой браузер, поддерживающий стандарт RFC-1867 (сейчас браузер без этого найти трудно:) и, собственно, php-скрипт, который будет обрабатывать и сохранять наш файл.

Код формы html-странички (для ):

<form enctype="multipart/form-data" action="upload.php" method="post">
   <input type="hidden" name="MAX_FILE_SIZE" value="50000" />
   Выбери файл:
   <input name="userfile[]" type="file" />
   <input name="userfile[]" type="file" />
   <input name="userfile[]" type="file" />
   <input type="submit" value="Загрузить" />
</form>

Поясним:

multipart/form-data
Параметр enctype тега form устанавливает MIME-тип для данных отправляемых вместе с формой. Если в форме присутствует поле для отправки файла, необходимо определить параметр enctype как multipart/form-data.
MAX_FILE_SIZE
Указывается максимальный размер файла в байтах. Параметр введен для экономии трафика, то есть размер файла проверяется на клиенте и, если файл больше, то он не будет закачан на сервер. Не следует полагаться только на этот параметр, так как его легко обойти.
userfile[]
Мы написали имя поля формы со скобками [] чтобы была возможность, указав несколько полей для загрузки файла вместо одного, и не меняя скрипт, закачивать несколько файлов одновременнно.

Теперь создадим скрипт upload.php, принимающий файлы на сервере:

<?
$path_to_files = './files/'; // путь для сохранения файлов
// если у нас несколько полей userfile[],
// отметаем те, в которые ничего не было выбрано
$good_name = array_filter($_FILES['userfile']['name']);
if (sizeof($good_name) != 0) { // если массив файлов не пустой
   foreach ($good_name as $key => $name) {
      $type = 	$_FILES['userfile']['type'][$key];
      $tmp_name = $_FILES['userfile']['tmp_name'][$key];
      $size = 	$_FILES['userfile']['size'][$key];
      // эта функция проверяет был ли загружен файл во временную директорию php
      if (!is_uploaded_file($tmp_name)) {
         echo "An error happened while loading. Failed.";
         continue;
      }
      // выковыриваем имя и расширение файла -
      $file_ext = substr($name, 1 + strrpos($name, "."));
      // - это может понадобиться, например, для сохранения в базу данных
      $file_name = substr($name, 0, strrpos($name, "."));
      // делаем реальный путь в файловой системе
      $real_path = realpath($path_to_files);
      // создаем в нашей директории временный файл с уникальным именем,
      // это делается для того, чтобы избежать одновременного
      // закачивания файлов с одним именем
      $temp_file_name = tempnam($real_path, "UPLF");
      // делаем новое, более привлекательное, имя файла для хранения на сервере
      $file_name = $temp_file_name."original.".strtolower($file_ext);
      // переносим загруженный временный файл в файл со
      // сделанным нами уникальным именем
      if (move_uploaded_file($tmp_name, $file_name)) {
         echo "Saved!";
         unlink($temp_file_name); // удаляем временный файл
      }else {
         echo "Failed!";
         continue;
      }
   }
}else {
   echo "No files were loaded.";
}
?>

Поясним:

После нажатия кнопки "Submit" в форме происходит загрузка файла на сервер - PHP-скрипт помещает файл во временную системную директорию (после окончания скрипта файл автоматически удаляется). Доступ к этим файлом и информарции о них можно получить через глобальный массив $_FILES (используется начиная с версии PHP 4.1.0, раньше был $HTTP_POST_FILES)

Этот массив имеет структуру вида:

$_FILES['userfile']['name']
Имя файла в файловой системе пользователя. После загрузки может меняться при некоторых услових.
$_FILES['userfile']['type']
mime/type файла. Например "image/jpeg" (изображение в формате jpeg), "application/x-shockwave-flash" (flash-ролик), "application/msword" (документ MS-WORD). Более полную информацию о mime-типах файлов можно получить, например, в файле mime.types сервера Apache.
$_FILES['userfile']['size']
Размер файла в байтах.
$_FILES['userfile']['tmp_name']
Путь к файлу во временной директории на диске.
$_FILES['userfile']['error']
Код ошибки операции. Введен в версии PHP 4.2.0. Равен 0 если операция успешна. Подробнее здесь.

Кроме того, о чем мы уже сказали, следует учитывать конфигурационные настройки PHP (смотрите ваш php.ini файл):

upload_tmp_dir
Эта директива в php.ini указывает директорию для временного хранения закачиваемых файлов. Имейте ввиду что она должна быть доступна для пользователя под которым запущен Apache, а также у нее должны быть выставлены права на запись для этого пользователя.
upload_max_filesize
Указывает максимальный размер закачиваемого единичного файла, по умолчанию равна "2M" (2 мегабайта).
post_max_size
Общий максимальный размер для всех данных поступаемых методом POST. Для одновременной закачки нескольких больших файлов нужно увеличить эту настройку. По умолчанию "8M" (8 мегабайт).
file_uploads
И, наконец, переключатель, запрещающий или разрешающий закачку файлов в общем. По умолчанию "On".

Настройки Apache:

Если вы все сделали правильно, но получаете что-нибудь вроде POST Method Not Allowed, возможно у вас неправильно сконфигурирован Apache. Ищите в файле httpd.conf строки похожие на:

<Limit POST>
   Order allow,deny
   Allow from all
</Limit>

Здесь ключевым словом является allow. Измените найденные строки на приведенный фрагмент, или, если не нашли, допишите фрагмент в httpd.conf.

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

  • • Создать в директории скрипта файл .htaccess и внести в него строчку CharsetDisable On. Эта директива отключит "charset-processing module", отвечающий за перекодировку.
  • • Дописать в httpd.conf строки:
<Location />
   CharsetRecodeMultipartForms Off
</Location>

Директива CharsetRecodeMultipartForms отвечает за перекодировку данных, полученных POST-методом с заголовком Content-Type: multipart/form-data. Таким образом, все двоичные данные будут оставлены в первоначальном виде. Но при этом может возникнуть необходимость перекодировать текстовую часть запроса вручную, будьте внимательны.

Комментарии

Спасибо за урок, но вот объясните мне, что это за лажа:
Parse error: parse error, unexpected $end in x:\home\localhost\www\...\n.php on line 53

Скорее всего просто опечатка.
Чтобы сказать точно - нужно смотреть n.php

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

в какой момент вытащить?
после сабмита формы все данные (в т.ч. имена) загруженных файлов хранятся в $_FILES['userfile']['name'], а имена временных файлов в $_FILES['userfile']['tmp_name']

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

хех....спс, уже разобрался сам, ответ не требуется. Ваша статья помогла в решении :) Ре$рект ресурсу !

Скажите все таки как вывести имена уже загруженных файлов?
Спасибо.....

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Разрешаю теги: <a> <em> <strong> <pre> <ul> <ol> <li>
  • Строки и параграфы переносятся автоматически.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.

Подробнее о форматировании

Image CAPTCHA
Регистр символов учитывается.