Пример загрузки файлов на сервер (upload) на языке php. Загрузка файлов на сервер с помощью PHP Как обрабатывать multipart-формы на PHP

У Вас в браузере заблокирован JavaScript. Разрешите JavaScript для работы сайта!

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

Краткий эксурс в upload

Что такое Upload files, или почему не работает
copy ("c:\images\sample.jpg", "http://mysite.ru/uploads/sample.jpg ")

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

Send this file:

При этом в поле action должен быть указан URL Вашего php-скрипта, который в дальнейшем будет заниматься обработкой загружаемых файлов. Скрытое поле MAX_FILE_SIZE должно предшествовать полю выбора файла, и содержать максимально допустимый размер файла в байтах. Его назначение - проверка размера файла еще до момента отправки файла на сервер. Это должно избавить пользователя от длительной и безрезультатной загрузки файла на сервер и образования лишнего трафика, но не стоит особо полагаться на это ограничение, так как его легко обойти.

Что происходит, когда пользователь выбрал файл на своем диске, и нажал на кнопку "Send file"? Браузер отсылает файл на сервер, где php-интерпретатор помещает его в свою временную директорию, присваивая ему случайное имя и выполняет скрипт, указанный в поле action.

Как должен выглядеть upload.php?

$uploaddir = "/var/www/uploads/"; if (move_uploaded_file($_FILES["userfile"]["tmp_name"], $uploaddir. $_FILES["userfile"]["name"])) { print "File is valid, and was successfully uploaded."; } else { print "There some errors!"; }

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

  • $_FILES["userfile"]["name"] - оригинальное имя файла, такое, каким его видел пользователь, выбирая файл;
  • $_FILES["userfile"]["type"] - mime/type файла, к примеру, может быть image/gif; это поле полезно сохранить, если Вы хотите предоставлять интерфейс для скачивания загруженных файлов;
  • $_FILES["userfile"]["size"] - размер загруженного файла;
  • $_FILES["userfile"]["tmp_name"] - полный путь к временному файлу на диске;
  • $_FILES["userfile"]["error"] - Начиная с версии 4.2.0, содержит код ошибки, который равен 0, если операция прошла успешно.

Для PHP версии ниже 4.1.0 этот массив называется $HTTP_POST_FILES. Не стоит забывать, что в отличие от $_FILES этот массив не является суперглобальным и при обращении к нему, к примеру, из функции, необходимо явно указывать global $HTTP_POST_FILES;

Если в настройках Вашего сервера register_globals=on, будут созданы дополнительные переменные вида $userfile_name, $userfile_type, $userfile_size… Учитывая, что, начиная с версии 4.2.0, в настройках по умолчанию register_globals=off использования этих переменных не рекомендовано, даже если они определены. Лучший способ получения информации о загружаемых файлах - использовать массив $_FILES.

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

Настройка сервера

Я все сделал правильно, но у меня что-то не работает. Может, у меня неправильно сконфигурирован сервер?

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

В файле php.ini:

  • Если Вы хотите узнать, где расположен Ваш php.ini, выполните
  • file_uploads - возможность запретить или разрешить загрузку файлов в целом. По умолчанию On.
  • upload_max_filesize - максимальный размер файла, который может быть загружен. Если Вам необходимо работать с большими файлами, измените эту настройку. По умолчанию 2М. Не забудьте изменить post_max_size.
  • post_max_size - общее ограничение сверху на размер данных, передаваемых в POST запросе. Если Вам необходимо работать с большими файлами, или передавать несколько файлов одновременно, измените эту настройку. Значение по умолчанию 8М.
  • upload_tmp_dir - временная директория на сервере, в которую будут помещаться все загружаемые файлы. Проверьте, какие на нее выставлены права(если на данном этапе у Вас возникли сложности, смотрите пояснения в конце статьи). Такая директория должна существовать и у пользователя, под которым выполняется Apache, также должны быть права на запись в эту директорию. Если Вы работаете с включенным ограничением open_basedir - то временный каталог должен находиться внутри. Вам не нужно заботиться о ее чистке или об уникальности имен, PHP решает эту проблему за Вас.

В файле httpd.conf :

  • Прежде всего, убедитесь, что Вы используете веб-сервер Apache 1.3 (последняя версия на момент написания статьи - 1.3.27). Если Вы используете Apache 2.0, Вам следует прочитать следующий отрывок из документации:

    Do not use Apache 2.0 and PHP in a production environment neither on Unix nor on Windows.

  • Если Вы получили сообщение "POST Method Not Allowed", это означает, что надо искать что-то похожее на следующие директивы, и использовать ключевое слово Allow: Order allow,deny Allow from all
  • Проблемы с загрузкой бинарных файлов - классический вопрос "почему бьются файлы при upload". Вот способ решения, предложенный Димой Бородином (http://php.spb.ru): В директории, где лежит скрипт, делаем файл .htaccess , в котором пишем: CharsetDisable On В файл httpd.conf дописать строки: CharsetRecodeMultipartForms Off

Небольшие пояснения, к этому рецепту: вышеописанная проблема, когда загруженные на сервер архивы не распаковываются и картинки не отображаются, может возникать из-за того, что используется веб-сервер Russian Apache. Директива CharsetDisable отключает модуль charset-processing module, т.е. никакой перекодировки при скачивании файлов, находящихся в данной папке, происходить не будет. Директива CharsetRecodeMultipartForms выключает перекодировку данных, переданных методом POST с заголовком Content-Type: multipart/form-data. Т.е. двоичные данные, переданные с такой настройкой, будут оставлены в первоначальном виде, а все остальное наполнение сайта будет перекодировано согласно текущим настройкам сервера.

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

Используйте директиву CharsetRecodeMultipartForms, которая появилась в PL23, но при этом вам все-равно придется перекодировать вручную текстовые части запросов. Для этого можно использовать Russian Apache API, доступное в других модулях или Russian Apache Perl API, доступное из mod_perl.

Один из примеров определения кодировки вы можете найти тут: http://tony2001.phpclub.net/detect_charset/detect.phps

Самая свежая документация по Russian Apache находится на его официальном сайте: http://apache.lexa.ru/.

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

Также возможна настройка параметров Apach с помощью.htaccess:

Php_value upload_max_filesize 50M php_value post_max_size 50M

Дополнительные возможности

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

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

Send these files:


И не забудьте увеличить post_max_size , если предполагается много файлов

Автоматическая загрузка файлов на сервер

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

Хранение файлов в базе данных mySQL

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

  • Необходимо использовать поле типа BLOB
  • Перед тем, как класть в базу, не забыть применить к строке mysql_escape_string()
  • При отображении файла необходимо указывать заголовок content/type

Помните, что скрипт отображающий ваш HTML никак не связан со скриптом, который должен выводить изображение. Это должны быть два различные приложения.

Хранение картинок в базе не является хорошем стилем. Гораздо удобней хранить в базе лишь пути к файлам изображений.

Получение свойств изображения.

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

Загрузка файлов, имеющих русско-язычное название

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

Отображения статуса загрузки (Progress bar)

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

Права на файлы

Проблемы с правами на сервере (upload_tmp_dir)

В Unix-подобных операционных системах каждой папке, файлу, ссылке выставлены соответствие права доступа. Они могут выглядеть как rwx-rw-r- или же как число 754.

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

Владелец Группа Прочие (u) (g) (o) rwx rwx rwx

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

r Право на чтение. (4)
w Право на запись. (2)
x Право на выполнение (поиск в каталоге). (1)

  • Установить владельцем каталога пользователя, с чьими привелегиями выполняется apache. Это можно узнать из файла httpd.conf или просмотрев список процессов на сервере. Права на каталог должны быть 700 (rwx------).
  • Независимо от того, кто является владельцем каталога, установить права 777 (rwxrwxrwx).

    Пример реализации загрузки картинок на сервер.

    $max_image_width = 380; $max_image_height = 600; $max_image_size = 64 * 1024; $valid_types = array("gif","jpg", "png", "jpeg"); if (isset($_FILES["userfile"])) { if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) { $filename = $_FILES["userfile"]["tmp_name"]; $ext = substr($_FILES["userfile"]["name"], 1 + strrpos($_FILES["userfile"]["name"], ".")); if (filesize($filename) > $max_image_size) { echo "Error: File size > 64K."; } elseif (!in_array($ext, $valid_types)) { echo "Error: Invalid file type."; } else { $size = GetImageSize($filename); if (($size) && ($size < $max_image_width) && ($size < $max_image_height)) { if (@move_uploaded_file($filename, "/www/htdocs/upload/")) { echo "File successful uploaded."; } else { echo "Error: moving fie failed."; } } else { echo "Error: invalid image properties."; } } } else { echo "Error: empty file."; } } else { echo "
    Send this file:
    "; }

    Оригинал статьи находится на сайте PHP Club


    Как скачать файл с сервера?
  • Как загрузить файл на сервер используя PHP? В этой статье мы подробно рассмотрим этот вопрос с примерами.

    HTML-форма для отправки файла

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

    Вот пример HTML-кода такой формы:

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



    Что уникального в этой форме:

    1. Тег form должен обязательно содержать атрибут enctype="multipart/form-data . Именноо этот атрибут указывает на то, что форма будет передавать файл. По умолчанию атрибут enctype имеет значение application/x-www-form-urlencoded .
    2. Форма должна содержать скрытый атрибут (type="hidden") с именем MAX_FILE_SIZE в значении которого (value) указывается размер файла. Теоретически, браузеры должны сообщать о том, что файл превышает допустимые размеры, но на практике браузеры не поддерживают это. Я думаю, что этот атрибут можно не указывать.
    3. Для выбора передаваемого файла служит тег input , у которого атрибут type="file" .

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

    Если хотите чтобы файл на этом этапе сохранялся в другой каталог, укажите его в директиве upload_tmp_dir файла php.ini.

    Для перемещения загруженного файла в новое место используется функция move_uploaded_file .

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

    Итак, после того, как скрипт получил данные формы с переданным файлом, файл он записал в специальную папку, а данные о файле записал в двумерный массив $_FILES .

    Давайте рассмотрим пример, который выводит содержимое массива $_FILES на экран.

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


    "; } else { echo "
    ", print_r($_FILES), "
    "; } ?>

    Вот что мы получим в результате работы этого скрипта:

    Рис.1. Массив $_FILES.

    Теперь давайте разберём, что содержится в этом массиве.

    В нашем двумерном массиве $_FILES есть один элемент filename . Это значение поля name из элемента формы:

    Данные для этого файла:

    • $_FILES["filename"]["name"] - имя файла;
    • $_FILES["filename"]["type"] - тип файла;
    • $_FILES["filename"]["tmp_name"] - полный путь к временному каталогу на диске;
    • $_FILES["filename"]["error"] - содержит код ошибки, который это 0, если операция прошла успешно;
    • $_FILES["filename"]["size"] - размер файла.

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


    В этом случае наш массив выглядел бы так:


    Рис.2. Массив $_FILES.

    Итак, теперь мы знаем как устроен массив $_FILES и следующий шаг - положить полученный файл в нужное нам место.

    Функция move_uploaded_file

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

    Синтаксис функции move_uploaded_file:

    move_uploaded_file (откуда переносить, куда переносить)

    Функция move_uploaded_file возвращает булево значение:

    • TRUE - в случае успеха,
    • FALSE - если первый аргумент является загруженным файлом, но по каким-либо причинам не может быть перемещён в указанное место, в этом случае никаких действий не предпринимается.

    Используем эту функцию в примере:

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


    "; } else { move_uploaded_file ($_FILES["filename"]["tmp_name"], __DIR__ . DIRECTORY_SEPARATOR . $_FILES["filename"]["name"]); } ?>

    Этот скрипт перемещает картинку в ту же папку, в которой он сам находится. Для этого мы используем встроенные в PHP константы для указания пути:

    • __DIR__ - одна из "волшебных" констант, содержит директорию файла.
    • DIRECTORY_SEPARATOR - предопределённая константа, содержащая разделитель пути. Для ОС Windows это «\», для ОС Linux и остальных - «/».

    Внимание: Если результирующий файл уже существует, он будет перезаписан.

    Функция is_uploaded_file

    Ест ещё одна функция, которую нужно обязательно использовать при работе с загрузкой файлов на сервер. Это функция is_uploaded_file и она используется из соображений безопасности.

    is_uploaded_file - определяет, был ли файл загружен при помощи HTTP POST и возвращает TRUE, если это так.

    Использование этой функции целесообразно для удостоверения, что злонамеренный пользователь не пытается обмануть скрипт так, чтобы он работал с файлами, с которыми работать не должен - к примеру, /etc/passwd .

    Обратите внимание: для правильной работы функции is_uploaded_file нужно передать путь к файлу на временном хранилище на сервере, то есть аргумент вида $_FILES["filename"]["tmp_name"] , - а вот имя закачиваемого файла на клиентской машине ($_FILES["filename"]["name"]) тут не подходит.

    Наш конечный пример скрипта, обрабатывающего форму отправки файла, будет выглядеть так:

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


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

    Ограничиваем размер файла

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

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

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

    $upload_max_filesize) ... ?>

    Настройки php.ini для загрузки файлов на сервер

    Итак, мы узнали про директиву upload_max_filesize файла php.ini которая устанавливает максимальный размер загружаемого файла. Какие ещё директивы файла php.ini отвечают за загрузку файлов на сервер?

    Кстати, если Вы хотите узнать, где расположен Ваш файл php.ini, выполните скриптик:

    Итак, список директив файла php.ini:

    • file_uploads - возможность запретить или разрешить загрузку файлов на сервер в целом, по умолчанию разрешена (значение On).
    • post_max_size - общее ограничение сверху на размер данных, передаваемых в POST запросе. Если Вам необходимо передавать несколько файлов одновременно, или работать с большими файлами, измените значение этой директивы. Значение по умолчанию 8Мб.
    • upload_max_filesize - уже рассмотренная нами директива. Не забывайте при необходимости также менять post_max_size .
    • upload_tmp_dir - временная директория на сервере, в которую будут помещаться все загружаемые файлы.

    Это всё, что я хотел сказать Вам по теме "Загрузка файлов на сервер в PHP".

    Данная возможность позволяет загружать как текстовые, так и бинарные файлы. С помощью 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" );

    ?>

    10 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.

    Multiple files can be uploaded using different name for input .

    It is also possible to upload multiple files simultaneously and have the information organized automatically in arrays for you. To do so, you need to use the same array submission syntax in the HTML form as you do with multiple selects and checkboxes:

    Send these files:


    Warning

    As of PHP 5.2.12, the max_file_uploads configuration setting acts as a limit on the number of files that can be uploaded in one request. You will need to ensure that your form does not try to upload more files in one request than this limit.

    14 years ago

    When uploading multiple files, the $_FILES variable is created in the form:

    Array
    => Array
    => foo.txt
    => bar.txt
    )

    => Array
    => text/plain
    => text/plain
    )

    => Array
    => /tmp/phpYzdqkD
    => /tmp/phpeEwEWG
    )

    => Array
    => 0
    => 0
    )

    => Array
    => 123
    => 456
    )

    I found it made for a little cleaner code if I had the uploaded files array in the form

    Array
    => Array
    => foo.txt
    => text/plain
    => /tmp/phpYzdqkD
    => 0
    => 123
    )

    => Array
    => bar.txt
    => text/plain
    => /tmp/phpeEwEWG
    => 0
    => 456
    )

    I wrote a quick function that would convert the $_FILES array to the cleaner (IMHO) array.

    Function reArrayFiles (& $file_post ) {

    $file_ary = array();
    $file_count = count ($file_post [ "name" ]);
    $file_keys = array_keys ($file_post );

    For ($i = 0 ; $i < $file_count ; $i ++) {
    foreach ($file_keys as $key ) {
    $file_ary [ $i ][ $key ] = $file_post [ $key ][ $i ];
    }
    }

    Return $file_ary ;
    }

    ?>

    Now I can do the following:

    If ($_FILES [ "upload" ]) {
    $file_ary = reArrayFiles ($_FILES [ "ufile" ]);

    Foreach ($file_ary as $file ) {
    print "File Name: " . $file [ "name" ];
    print "File Type: " . $file [ "type" ];
    print "File Size: " . $file [ "size" ];
    }
    }

    ?>

    5 years ago

    This is also needed for elements.

    So, if you have an input element like this:

    This should be written as

    else you"ll only be able to get one of the files.

    9 years ago

    Here is a function to fix the indices of a multi-dimensional for easier parsing when dealing with file uploads. It takes a single $_FILES field array as a parameter and separates each individual uploaded file by numeric key. This allows for iterating like:

    fixFilesArray ($_FILES [ "array_of_files" ]);
    foreach ($_FILES [ "array_of_files" ] as $position => $file ) {
    // should output array with indices name, type, tmp_name, error, size
    var_dump ($file );
    }
    ?>

    Here"s the code:

    /**
    * Fixes the odd indexing of multiple file uploads from the format:
    *
    * $_FILES["field"]["key"]["index"]
    *
    * To the more standard and appropriate:
    *
    * $_FILES["field"]["index"]["key"]
    *
    * @param array $files
    * @author Corey Ballou
    * @link http://www.jqueryin.com
    */
    function fixFilesArray (& $files )
    {
    $names = array("name" => 1 , "type" => 1 , "tmp_name" => 1 , "error" => 1 , "size" => 1 );

    Foreach ($files as $key => $part ) {
    // only deal with valid keys and multiple files
    $key = (string) $key ;
    if (isset($names [ $key ]) && is_array ($part )) {
    foreach ($part as $position => $value ) {
    $files [ $position ][ $key ] = $value ;
    }
    // remove old key reference
    unset($files [ $key ]);
    }
    }
    }
    ?>

    3 years ago

    This is a very simple example:





    Document







    echo "

    "
    ;
    $img = $_FILES [ "img" ];

    if(!empty($img ))
    {
    $img_desc = reArrayFiles ($img );
    print_r ($img_desc );

    Foreach($img_desc as $val )
    {
    $newname = date ("YmdHis" , time ()). mt_rand (). ".jpg" ;
    move_uploaded_file ($val [ "tmp_name" ], "./uploads/" . $newname );
    }
    }

    function reArrayFiles ($file )
    {
    $file_ary = array();
    $file_count = count ($file [ "name" ]);
    $file_key = array_keys ($file );

    For($i = 0 ; $i < $file_count ; $i ++)
    {
    foreach($file_key as $val )
    {
    $file_ary [ $i ][ $val ] = $file [ $val ][ $i ];
    }
    }
    return $file_ary ;
    }

    2 years ago

    Once I had to do a maintenance in a huge ERP that had several multiple upload inputs inside an array. Just like this:







    The $_FILES array is created like this:

    Array
    => Array
    => Array
    => teste.c
    => teste
    )

    => Array
    => text/x-csrc
    => application/octet-stream
    )

    => Array
    => /opt/lampp/temp/phpuf3KNj
    => /opt/lampp/temp/php0yPZap
    )

    => Array
    => 0
    => 0
    )

    => Array
    => 1960
    => 8661
    )

    => Array
    => Array
    => jefrey.html
    => notas.txt
    )

    => Array
    => text/html
    => text/plain
    )

    => Array
    => /opt/lampp/temp/php87nfyu
    => /opt/lampp/temp/phpUBlvVz
    )

    => Array
    => 0
    => 0
    )

    => Array
    => 583
    => 191
    )

    I"ve managed to re-arrange this array like this:

    Array
    => Array
    => Array
    => teste.c
    => text/x-csrc
    => /opt/lampp/temp/phpuf3KNj
    => 0
    => 1960
    )

    => Array
    => teste
    => application/octet-stream
    => /opt/lampp/temp/php0yPZap
    => 0
    => 8661
    )

    => Array
    => Array
    => jefrey.html
    => text/html
    => /opt/lampp/temp/php87nfyu
    => 0
    => 583
    )

    => Array
    => notas.txt
    => text/plain
    => /opt/lampp/temp/phpUBlvVz
    => 0
    => 191
    )

    Here"s my snippet:
    function reArrayFilesMultiple (& $files ) {
    $uploads = array();
    foreach($_FILES as $key0 => $FILES ) {
    foreach($FILES as $key => $value ) {
    foreach($value as $key2 => $value2 ) {
    $uploads [ $key0 ][ $key2 ][ $key ] = $value2 ;
    }
    }
    }
    $files = $uploads ;
    return $uploads ; // prevent misuse issue
    }
    ?>

    3 years ago

    This is just a modification of the code which is the top note by "phpuser" here. His/her version requires that the $file_post array passed in to the function was created by a form submitted with the multiple attribute set. With multiple set in the html input tag, $_FILES["fileInputName"]["name"] is an array no matter if only one file is sent or multiple. But when is used without the multiple attribute then $_FILES["fileInputName"]["name"] is not an array, it contains the the string with the filename. To use this neat function with or without multiple set and to get back an array which you can "foreach" over in either case, use this modification:

    function reArrayFiles(&$file_post)
    {
    $file_ary = array();
    $multiple = is_array($file_post["name"]);

    $file_count = $multiple ? count($file_post["name"]) : 1;
    $file_keys = array_keys($file_post);

    For ($i=0; $i<$file_count; $i++)
    {
    foreach ($file_keys as $key)
    {
    $file_ary[$i][$key] = $multiple ? $file_post[$key][$i] : $file_post[$key];
    }
    }

    Return $file_ary;
    }

    3 years ago

    Recursive solution for complex situations (supports any nested arrays including indexed arrays)

    function getFixedFilesArray() {
    $walker = function ($arr, $fileInfokey, callable $walker) {
    $ret = array();
    foreach ($arr as $k => $v) {
    if (is_array($v)) {
    $ret[$k] = $walker($v, $fileInfokey, $walker);
    } else {
    $ret[$k][$fileInfokey] = $v;
    }
    }
    return $ret;
    };

    $files = array();
    foreach ($_FILES as $name => $values) {
    // init for array_merge
    if (!isset($files[$name])) {
    $files[$name] = array();
    }
    if (!is_array($values["error"])) {
    // normal syntax
    $files[$name] = $values;
    } else {
    // html array feature
    foreach ($values as $fileInfoKey => $subArray) {
    $files[$name] = array_replace_recursive($files[$name], $walker($subArray, $fileInfoKey, $walker));
    }
    }
    }

    Return $files;
    }

    10 years ago

    If you try and upload files with multi-dimensional names like this:


    You will get an unexpected format like this:

    array(
    "submission" => array
    "name" => array("screenshot" => "monster_wallpaper.jpg" ),
    "type" => array("screenshot" => "image/jpeg" ),
    "tmp_name" => array("screenshot" => "/tmp/php48lX2Y" ),
    "error" => array("screenshot" => 0 ),
    "size" => array("screenshot" => 223262 ),
    ),
    ....
    ?>

    You can use the following function to re-format the array recursively in the usual format:

    function format_files_array ($files , $name = null , & $new = false , $path = false ){
    $names = array("name" => "name" , "type" => "type" , "tmp_name" => "tmp_name" , "error" => "error" , "size" => "size" );

    Foreach($files as $key => & $part )
    {
    $key = (string) $key ;
    if(in_array ($key , $names ))
    $name = $key ;
    if(! in_array ($key , $names ))
    $path = $key ;
    if(is_array ($part ))
    $part = format_files_array ($part , $name , $new , $path );
    elseif(! is_array ($part ))
    {
    $current =& $new ;
    foreach($path as $p )
    $current =& $current [ $p ];
    $current [ $name ] = $part ;
    unset($path );
    $name = null ;
    }
    }

    Return $new ;
    }
    ?>

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


    Http://localhost/index.php?name=myname&page=10

    определяет запрос GET к странице index.php. При этом скрипту передаются параметры "name" и "page" со значениями "myname" и "10" соответственно. Как видите, запрос состоит из пар "имя=значение", объединённых через "&". Запрос отделяется от адреса страницы знаком вопроса "?".

    Но GET не подходит для передачи больших данных. Для этого существует метод POST. Этот метод передаёт данные скрыто от пользователя, а адрес страницы остаётся неизменным. Теоретически, метод POST позволяет передавать огромные блоки данных, но большинство провайдеров устанавливают жесткое ограничение в 5-10 мегабайт.

    Для реализации загрузки файла необходимо снабдить пользователя соответствующей формой. Для загрузки файлов предназначен тег input типа file.

    Выберите файл для загрузки:

    Пользователь выбирает нужный файл, нажимает кнопку "Отправить!", после чего браузер передаёт указанный файл на сервер. По окончании загрузки файла запускается receiver.php, и ему автоматически становятся доступны все переданные в форме данные.

    Список загруженных файлов хранится в глобальном массиве $_FILES. Это ассоциативный массив, где каждый элемент содержит описание одного из файлов. Рассмотрим на примере:

    3145728) { $filesize = ($filesize != 0)? sprintf("(%.2f Мб)" , $filesize / 1024): ""; die("Ошибка: Размер прикреплённого файла ". $filesize." больше допустимого (3 Мб)."); } else { $filename = $_FILES["file"]["name"]; $filepath = $_FILES["file"]["tmp_name"]; $filetype = $_FILES["file"]["type"]; if($this->filetype == null || $this->filetype == "") $this->filetype = "unknown/unknown"; } } } echo "Успешно загружен файл: " . $filename; ?>

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

    Информация о каждом загруженном файле представляется в скрипте как элемены массива $_FILES. Имя элемента определяется атрибутом name тега формы. В нашем случае атрибут name равен "ufile", значит данные об этом файле будут храниться в элементе $_FILES["ufile"].

    Каждый элемент $_FILES так же является массивом, содержащим пять элементов с фиксированными именами:

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