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

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

  • register_globals=Off - параметры
    передаваемые скрипту заносятся в массивы $_GET[], $_POST[], $_FILES[],
    $_COOKIE[], ...
  • register_globals=On - все
    параметры передаваемые скрипту,  автоматически становятся
    глобальными переменными и они также доступны через массивы $_GET[],
    $_POST[], $_FILES[].

Upload файлов при register_globals=On

В этом случае параметры передаваемые скрипту становятся глобальными
переменными и кроме этого PHP также формирует массивы $_GET[], $_POST[],
$_FILES[]. При такой конфигурации вы можете выбирать как вам получить
доступ к передаваемым параметрам. Либо вы пользуетесь глобальными
переменными, либо получаете доступ через массивы $_GET[], $_POST[],
$_FILES[].

Здесь будем использовать глобальные переменные, а в
следующем разделе будем использовать массив $_FILES[].

Напишем HTML
форму для отправки файла на сервер.


Содержание формы (файл upload.html):

color=#800000><html>
<body>
<FORM
ENCTYPE="multipart/form-data" ACTION="myup.php"
METHOD=POST>
Выберете файл: <INPUT NAME="myfile"
TYPE="file">
<INPUT TYPE="submit"
VALUE="Загрузить">
</FORM>
</body>
</html>


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

Так как в HTML форме мы написали <INPUT
NAME="myfile" TYPE="file">
, то при запросе в скрипте у нас
будет глобальная переменная с именем $myfile.

Здесь рассмотрим загрузку текстового файла и вывод его содержимого.

Скрипт обработки:

<?php
// Загрузка файлов на сервер
//
Если register_globals=On

    print("Имя файла на
нашем сервере (во время запроса):
".$myfile."<br>");
    print("Имя файла на
компьютере пользователя:
".$myfile_name."<br>");
    print("MIME-тип файла:
".$myfile_type."<br>");
    print("Размер файла:
".$myfile_size."<br><br>");

    //
Получаем содержимое файла
    $fp =
fopen($myfile,"r");
    $content = fread($fp,
filesize($myfile));
   
fclose($fp);

    // Вывод содержимого
файла
    print($content);
?>

Пояснения:

$myfile - имя временного файла, в котором находятся загруженные
данные;

Когда пользователь отправляет форму, PHP автоматически определяет ещё
несколько переменных:

$myfile_name - имя файла на компьютере компьютере
пользователя;

$myfile_type - MIME-тип файла.

$myfile_size - размер файла в байтах.

При загрузке текстовых файлов переменная $myfile_type = "text/plain",
при загрузке изображения gif переменная $myfile_type = "image/gif".

При register_globals=On можно пользоваться массивом $_FILES[]. Как им
пользоваться мы рассмотрим ниже.

Upload файлов при register_globals=Off

При register_globals=Off параметры передаваемые скрипту заносятся в
массивы $_GET[], $_POST[], $_FILES[]. В нашем случае нас интересует массив
$_FILES[]. В этом массиве храниться вся информация о всех загружаемых
файлах. В нашем случае структура этого массива следующая:

$_FILES["myfile"]["tmp_name"] - Имя временного
файла
$_FILES["myfile"]["name"] - Имя файла на компьютере
пользователя
$_FILES["myfile"]["size"] - Размер файла в
байтах
$_FILES["myfile"]["type"] - MIME-тип
файла
$_FILES["myfile"]["error"] - код ошибки.

{mospagebreak} 

PHP код для обработки формы (файл myup.php):

<?php
// Загрузка файлов на сервер
//
Если register_globals=Off

    // Если upload
файла
   
if(isset($_FILES["myfile"]))
   
{
        $myfile =
$_FILES["myfile"]["tmp_name"];
       
$myfile_name =
$_FILES["myfile"]["name"];
       
$myfile_size =
$_FILES["myfile"]["size"];
       
$myfile_type =
$_FILES["myfile"]["type"];
       
$error_flag =
$_FILES["myfile"]["error"];

       
// Если ошибок не было
       
if($error_flag == 0)
       
{
           
print("Имя файла на нашем сервере (во время запроса):
".$myfile."<br>");
           
print("Имя файла на компьютере пользователя:
".$myfile_name."<br>");
           
print("MIME-тип файла:
".$myfile_type."<br>");
           
print("Размер файла:
".$myfile_size."<br><br>");

           
// Получаем содержимое
файла
           
$fp =
fopen($myfile,"r");
           
$content = fread($fp,
filesize($myfile));
           
fclose($fp);

           
// Вывод содержимого
файла
           
print($content);

        } //
end of if 2
    } // end of if 1
?>

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

Значения
$_FILES["myfile"]["error"]:

0 - ошибок не было, файл загружен.
1 - размер
загруженного файла превышает размер установленный параметром
upload_max_filesize в php.ini
2 - размер загруженного файла
превышает размер установленный параметром MAX_FILE_SIZE в HTML форме.
3
- загружена только часть файла
4 - файл не был загружен (Пользователь в
форме указал неверный путь к файлу).

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


  • copy ( string source, string dest);
  • move_uploaded_file ( string filename, string destination);

Функция copy() копирует файл source в место назначения dest.

Функция move_uploaded_file() перемещает загруженный файл filename в место назначение указанное в параметре
destination.

Ещё хочется отметить что при одновременной загрузке нескольких файлов
т.е. когда HTML форма содержит:

<INPUT NAME="myfile1"
TYPE="file">
<INPUT NAME="myfile2" TYPE="file">
<INPUT
NAME="myfile3" TYPE="file">

массив $_FILES[] будет иметь следующую структуру:

$_FILES["myfile1"]["tmp_name"] - Имя временного файла
1
$_FILES["myfile1"]["name"] - Имя файла на компьютере
пользователя 1
$_FILES["myfile1"]["size"] - Размер файла 1 в
байтах 
$_FILES["myfile1"]["type"] - MIME-тип файла
1
$_FILES["myfile1"]["error"] - код ошибки для файла 1.

$_FILES["myfile2"]["tmp_name"] - Имя временного файла
2
$_FILES["myfile2"]["name"] - Имя файла на компьютере
пользователя 2
$_FILES["myfile2"]["size"] - Размер файла 2 в
байтах 
$_FILES["myfile2"]["type"] - MIME-тип файла
2
$_FILES["myfile2"]["error"] - код ошибки для файла 2.

$_FILES["myfile3"]["tmp_name"] - Имя временного файла
3
$_FILES["myfile3"]["name"] - Имя файла на компьютере
пользователя 3
$_FILES["myfile3"]["size"] - Размер файла 3 в
байтах 
$_FILES["myfile3"]["type"] - MIME-тип файла
3
$_FILES["myfile3"]["error"] - код ошибки для файла 3.

это пример для одновременной загрузки трёх файлов.

Таким же образом можно загружать и двоичные файлы, например файлы
картинок gif, jpeg и т.д. 

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

по словам Дмитрия Бородина (
href="../../php.spb.ru/default.htm">http://php.spb.ru/
) возможно, что при загрузке двоичных файлов у вас возникнут проблемы. Файлы будут загружаться
с перекодировкой.

Вот часть статьи "Какделать UPLOAD файлов на сервер и о возможных глюках" которая возможно поможет
вам устранить причину проблемы:

{mospagebreak} 

ЦИТИРОВАНИЕ

Попробуйте аплодить таким способом на сервер бинарные файлы. Скорее
всего файлы окажутся "битыми": фотки не будут показываться, программы не
запустятся, архивы не распакуются. Текстовые файлы (почти точно) не
повредятся. Дело в том, что Русский Апач (ваш веб-сервер) перекодирует все
подряд. Например, символ с кодом 0х00 он заменяет на пробел (символ
с кодом 0х20). Чтобы выключить эту ненужную перекодировку, допишите
в файл httpd.conf из каталога Апача (/usr/local/apache) следующие
строки. Если у вас нет доступа к этому файлу и админ сервера не может
сделать это за вас, ткните его в эти строки. 


color=#800000><Location />
CharsetRecodeMultipartForms
Off
</Location>


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

КОНЕЦ ЦИТИРОВАНИЯ

Сохранение загружаемого файла на сервере

Выше уже говорилось, что
загружаемый файл помещается во временную директорию. В этой директории
файл будет храниться только во время запроса, а после запроса PHP удалит
временный файл. Чтобы сохранить загружаемый файл, его необходимо
переместить в нужную директорию. Для этого в PHP есть специальная функция
bool move_uploaded_file ( string filename, string destination).
Второй параметр string destination должен содержать полный путь к
файлу. Полный путь к файлу содержит: путь к домашней директории, путь
к директории куда перемещать файл и имя самого файла. У меня путь к
домашней директории выглядит так: /home/proger/. 

Если вы не
знаете путь к директории где лежат ваши файлы, то можно воспользоваться
переменной $DOCUMENT_ROOT или $_SERVER["DOCUMENT_ROOT"]. Переменная
$DOCUMENT_ROOT содержит путь к директории (обычно www) где лежат ваши HTML
файлы. У меня $DOCUMENT_ROOT содержит следующее: /home/proger/www. Эта
переменная зависит от конфигурации веб-сервера.

Итак, HTML форма для выбора загружаемого файла:


color=#800000><html>
<body>
<FORM
ENCTYPE="multipart/form-data" ACTION="myup.php"
METHOD=POST>
Выберете файл: <INPUT NAME="myfile"
TYPE="file">
<INPUT TYPE="submit"
VALUE="Загрузить">
</FORM>
</body>
</html>



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

Скрипт обработки:

<?php
// Загрузка файла на сервер и его
сохранение

    // Если upload
файла
   
if(isset($_FILES["myfile"]))
   
{
        $myfile =
$_FILES["myfile"]["tmp_name"];
       
$myfile_name =
$_FILES["myfile"]["name"];
       
$myfile_size =
$_FILES["myfile"]["size"];
       
$myfile_type =
$_FILES["myfile"]["type"];
       
$error_flag =
$_FILES["myfile"]["error"];

       
// Если ошибок не было
       
if($error_flag == 0)
       
{
           
print("Имя файла на нашем сервере (во время запроса):
".$myfile."<br>");
           
print("Имя файла на компьютере пользователя:
".$myfile_name."<br>");
           
print("MIME-тип файла:
".$myfile_type."<br>");
           
print("Размер файла:
".$myfile_size."<br><br>");

           
// Сохранение файла (Перемещаем файл в нужную
директорию)
           
$uploaddir = $_SERVER["DOCUMENT_ROOT"]."/up/";  // Дир-я куда
перемещать
файл

           
if(move_uploaded_file($myfile,
$uploaddir.$myfile_name))
           
{
               
print("Файл
сохранён");
           
}
           
else
           
{
               
print("Ошибка");
           
}

       
}
    }
?>

У меня данный скрипт сохраняет загружаемый файл в директорию:
/home/proger/www/up/.

В принципе тут всё просто. Самое главное это указать правильный путь к файлу (второй параметр функции move_uploaded_file).