Content type multipart form data boundary

Content type multipart form data boundary

  • Викифицировать список литературы.

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

MIME
Название Multipart form-data
Уровень (по модели OSI) Прикладной
Семейство HTTP, Multipurpose Internet Mail Extensions
Создан в 1992
Порт/ID 80/TCP
Назначение протокола Отправка данных с вложенными данными
Спецификация RFC 7578

Тип содержимого multipart/form-data — это составной тип содержимого, чаще всего использующийся для отправки HTML-форм с бинарными (не-ASCII) данными методом POST протокола HTTP. Указывается в поле заголовка Content-Type (тип содержимого) и следует правилам для составных MIME-данных в соответствии с RFC 2045. Для форм, не имеющих больших бинарных (не-ASCII) данных, может использоваться тип содержимого application/x-www-form-urlencoded .

Сообщение multipart/form-data содержит несколько частей, по одной на каждый задействованный в форме элемент управления.

Типичный пример: страницы отправки электронных писем через webmail со вложенными файлами. При отправке такого письма браузер формирует сообщение типа multipart/form-data , внедряя в него как отдельные части, введённые пользователем, тему, адрес получателя, собственно текст письма, так и вложенные файлы. Сообщение типа multipart/form-data состоит из нескольких частей, каждая из которых представляет содержимое некоторого элемента формы. Части отправляются обрабатывающему агенту в том же порядке, в котором соответствующие управляющие элементы представлены в потоке документа с формой. Каждая часть должна содержать:

  1. Заголовочное поле Content-Disposition , имеющее значение form-data .
  2. Атрибут name определяет имя соответствующего управляющего элемента. Имена управляющих элементов, изначально закодированные с использованием наборов символов, отличных от ASCII, могут кодироваться с помощью метода, описанного в RFC 2047[1] .

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/xmlhttprequest.

Во время обычной отправки формы

Здесь есть два поля: name=Ivan и surname=Ivanov .

Браузер перечисляет такие пары «имя=значение» через символ амперсанда & и, так как метод GET, итоговый запрос выглядит как /submit?name=Ivan&surname=Ivanov .

Все символы, кроме английских букв, цифр и — _ . !

* ‘ ( ) заменяются на их цифровой код в UTF-8 со знаком %.

Например, пробел заменяется на %20 , символ / на %2F , русские буквы кодируются двумя байтами в UTF-8, поэтому, к примеру, Ц заменится на %D0%A6 .

Будет отправлена так: /submit?name=%D0%92%D0%B8%D0%BA%D1%82%D0%BE%D1%80&surname=%D0%A6%D0%BE%D0%B9 .

в JavaScript есть функция encodeURIComponent для получения такой кодировки «вручную»:

Эта кодировка используется в основном для метода GET, то есть для передачи параметра в строке запроса. По стандарту строка запроса не может содержать произвольные Unicode-символы, поэтому они кодируются как показано выше.

GET-запрос

Формируя XMLHttpRequest, мы должны формировать запрос «руками», кодируя поля функцией encodeURIComponent .

Например, для посылки GET-запроса с параметрами name и surname , аналогично форме выше, их необходимо закодировать так:

Браузер автоматически добавит к запросу важнейшие HTTP-заголовки, такие как Content-Length и Connection .

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

Запрос, отправленный кодом выше через XMLHttpRequest , никак не отличается от обычной отправки формы. Сервер не в состоянии их отличить.

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

POST с urlencoded

В методе POST параметры передаются не в URL, а в теле запроса. Оно указывается в вызове send(body) .

В стандартных HTTP-формах для метода POST доступны три кодировки, задаваемые через атрибут enctype :

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text-plain

В зависимости от enctype браузер кодирует данные соответствующим способом перед отправкой на сервер.

В случае с XMLHttpRequest мы, вообще говоря, не обязаны использовать ни один из этих способов. Главное, чтобы сервер наш запрос понял. Но обычно проще всего выбрать какой-то из стандартных.

В частности, при POST обязателен заголовок Content-Type , содержащий кодировку. Это указание для сервера – как обрабатывать (раскодировать) пришедший запрос.

Для примера отправим запрос в кодировке application/x-www-form-urlencoded :

Всегда используется только кодировка UTF-8, независимо от языка и кодировки страницы.

Если сервер вдруг ожидает данные в другой кодировке, к примеру windows-1251, то их нужно будет перекодировать.

Кодировка multipart/form-data

Кодировка urlencoded за счёт замены символов на %код может сильно «раздуть» общий объём пересылаемых данных. Поэтому для пересылки файлов используется другая кодировка: multipart/form-data.

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

Чтобы использовать этот способ, нужно указать его в атрибуте enctype и метод должен быть POST:

Форма при такой кодировке будет выглядеть примерно так:

…То есть, поля передаются одно за другим, значения не кодируются, а чтобы было чётко понятно, какое значение где – поля разделены случайно сгенерированной строкой, которую называют «boundary» (англ. граница), в примере выше это RaNdOmDeLiMiTeR :

Читайте также:  Nikon coolpix s9300 отзывы

Сервер видит заголовок Content-Type: multipart/form-data , читает из него границу и раскодирует поля формы.

Такой способ используется в первую очередь при пересылке файлов, так перекодировка мегабайтов через urlencoded существенно загрузила бы браузер. Да и объём данных после неё сильно вырос бы.

Однако, никто не мешает использовать эту кодировку всегда для POST запросов. Для GET доступна только urlencoded.

POST с multipart/form-data

Сделать POST-запрос в кодировке multipart/form-data можно и через XMLHttpRequest.

Достаточно указать в заголовке Content-Type кодировку и границу, и далее сформировать тело запроса, удовлетворяющее требованиям кодировки.

Пример кода для того же запроса, что и раньше, теперь в кодировке multipart/form-data :

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

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

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

FormData

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

Это очень удобно. Например:

Этот код отправит на сервер форму с полями name , surname и patronym .

  • Конструктор new FormData([form]) вызывается либо без аргументов, либо с DOM-элементом формы.
  • Метод formData.append(name, value) добавляет данные к форме.

Объект formData можно сразу отсылать, интеграция FormData с XMLHttpRequest встроена в браузер. Кодировка при этом будет multipart/form-data .

Другие кодировки

XMLHttpRequest сам по себе не ограничивает кодировку и формат пересылаемых данных.

Поэтому для обмена данными часто используется формат JSON:

Итого

  • У форм есть две основные кодировки: application/x-www-form-urlencoded – по умолчанию и multipart/form-data – для POST запросов, если явно указана в enctype . Вторая кодировка обычно используется для больших данных и только для тела запроса.
  • Для составления запроса в application/x-www-form-urlencoded используется функция encodeURIComponent .
  • Для отправки запроса в multipart/form-data – объект FormData .
  • Для обмена данными JS ↔ сервер можно использовать и просто JSON, желательно с указанием кодировки в заголовке Content-Type .

В XMLHttpRequest можно использовать и другие HTTP-методы, например PUT, DELETE, TRACE. К ним применимы все те же принципы, что описаны выше.

Последняя редакция 15.11.2010, добавлено описание отправки файлов методом POST.

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

Я покажу два варианта отправки данных:
1. Content-Type: application/x-www-form-urlencoded — возможна отправка значений переменных
2. Content-type: multipart/form-data — можно отправлять и значения переменных и файлы

Первый вариант, отправка только переменных с помощью application/x-www-form-urlencoded.

Чтобы отправить переменные методом POST, нужно установить соединение с сервером и отправить в открытое соединение подобный текст:

POST /file.php HTTP/1.1

Host: test.ru

Referer: test.ru

User-Agent: Opera

Content-Type: application/x-www-form-urlencoded

Content-Length: 20

var=test&var2=privet

Как видите, принцип очень простой. Заголовки и тело запроса. В данном случае в теле находятся как раз переменные, которые передаются методом POST (var=test&var2=privet), внешне эти переменные выглядят как при обычной передаче методом GET по ссылке.
А теперь рассмотрим этот пример более подробно и сразу переложим его на PHP.

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

$data = "var=test&var2=privet" ;
В данном примере используются две переменные( var и var2 ), первая имеет значение " test " вторая " privet ". Можете продолжать список переменных, разделяя их символом `&`.

Теперь нужно сформировать данные для отправки на сервер. Создаем еще одну текстовую переменную $out .

$out = "POST /file.php HTTP/1.1
" ; // здесь указываем какой файл запрашиваем и какой метод передачи данных будет использован. В данном примере вызывается файл file.php. Здесь нужно указывать путь до файла от корневой директории сайта (/path/file.php)

$out .= "Host: test.ru
" ; // тут указывается хост с которым будем соединяться (адрес вашего сайта)
$out .= "Referer: test.ru/
" ; // откуда идет отправка данных
$out .= "User-Agent: Opera
" ; // каким браузером притвориться
$out .= "Content-Type: application/x-www-form-urlencoded
" ; // это тип отправляемых данных из формы. Такой тип данных стоит у форм по умолчанию.

$out .= "Content-Length: " . strlen ( $data ). "

" ; // здесь указывается размер передаваемых данных.
$out .= $data. "

" ; // создаем полный набор данных для отправки.

Строка $out готова для отправки данных на сайт.
Остается только открыть соединение с сервером и кинуть ему эти данные.

Читайте также:  Как настроить гарнитуру блютуз на телефон

Делается это так:

$fp = fsockopen ( "test.ru" , 80 , $errno , $errstr , 10 );
В качестве параметров этой функции указываем хост для соединения(test.ru).
Затем порт (80), как правило другой номер порта используется редко.
$errno и $errstr получают установки, указывающие фактический уровень системной ошибки, в случае ошибки соединения, особой необходимости в них нет.
И последняя цифра (10) — это таймаут соединения, то есть сколько секунд будет ждать скрипт установки соединения.

Итак, соединение с хостом открыто.
Передаем открытому соединению созданные данные:

fputs ( $fp , $out );
Вот и все. Осталось закрыть соединение:

fclose ( $fp );
Переменные
var=test
и
var2=privet
улетели по адресу http://test.ru/file.php методом POST, так же, как это сделала бы html форма.

А вот и полный листинг:

= "var=test&var2=privet" ;
$fp = fsockopen ( "test.ru" , 80 , $errno , $errstr , 10 );
$out = "POST /file.php HTTP/1.1
" ;
$out .= "Host: test.ru
" ;
$out .= "Referer: test.ru/
" ;
$out .= "User-Agent: Opera
" ;
$out .= "Content-Type: application/x-www-form-urlencoded
" ;
$out .= "Content-Length: " . strlen ( $data ). "

" ;
$out .= $data . "

" ;
fputs ( $fp , $out );
fclose ( $fp );
?>

Это был самый простой пример, в нем я показал только принцип отправки данных.
Сейчас расширю данный пример, для демонстрации отправки данных методом POST и GET одновременно и получения ответа от сервера.

= "http://test.ru/patch/file.php?var=23&var2=54" ; // это адрес, по которому скрипт передаст данные методом POST. Как видно, здесь указаны переменные, которые будут переданы через GET
$parse_url = parse_url ( $url ); // при помощи этой функции разбиваем адрес на массив, который будет содержать хост, путь и список переменных.
$path = $parse_url [ "path" ]; // путь до файла(/patch/file.php)
if( $parse_url [ "query" ]) // если есть список параметров
$path .= "?" . $parse_url [ "query" ]; // добавляем к пути до файла список переменных(?var=23&var2=54)
$host = $parse_url [ "host" ]; // тут получаем хост (test.ru)
$data = "var3=test&var4=" . urlencode ( "еще тест" ); // а вот тут создаем список переменных с параметрами. Эти данные будут переданы через POST. Все значения переменных обязательно нужно кодировать urlencode ("еще тест")

$fp = fsockopen ( $host , 80 , $errno , $errstr , 10 );
if ( $fp )
<
$out = "POST " . $path . " HTTP/1.1
" ;
$out .= "Host: " . $host . "
" ;
$out .= "Referer: " . $url . "/
" ;
$out .= "User-Agent: Opera
" ;
$out .= "Content-Type: application/x-www-form-urlencoded
" ;
$out .= "Content-Length: " . strlen ( $data ). "

" ;
$out .= $data. "

" ;

fputs ( $fp , $out ); // отправляем данные

// после отправки данных можно получить ответ сервера и прочитать информацию выданную файлом, в который отправили данные.
// читаем данные построчно и выводим их. Конечно, эти данные можно использовать по своему усмотрению.
while( $gets = fgets ( $fp , 2048 ))
<
print $gets ;
>
fclose ( $fp );
>
?>

В этом примере файл file.php получил переменные:
GET var = "23" и var2 = "54"
POST var3 = "test" и var4 = "еще тест"

Хочу обратить ваше внимание, данные передаваемые через POST или GET всегда передаются строкой(string), независимо от того, через форму они передаются или через скрипт.
Поэтому передавая число, помните, что в скрипт оно попадет как string.

Второй вариант отправки данных, с помощью multipart/form-data для отправки файлов.

POST /file.php HTTP/1.0 r

Host: test.ru

Referer: test.ru

Content-type: multipart/form-data, boundary=ccf8111910

Content-length: 333

—ccf8111910

Content-Disposition: form-data; name="mass[qwe]"

значение переменной mass[qwe]

—ccf8111910

Content-Disposition: form-data; name="var"

значение переменной var

—ccf8111910

Content-Disposition: form-data; name="var_file"; filename="a.txt"

Content-Type: text/plain

содержимое файла

—ccf8111910—

В данном примере передаются переменные mass[qwe] и var, а так же текстовый файл a.txt, имеющий имя в форме var_file

В первую очередь обратите внимание на заголовок Content-type: multipart/form-data, boundary=ccf8111910. Именно multipart/form-data дает право пересылать не только текстовые значения переменных, но и файлы.
Так же в этой строке указывается разделитель данных boundary=. Это любой набор цифр или символов и будет служить для отделения значений друг от друга. Значение boundary должно быть уникальным в пределах пересылаемой информации, то есть таких символов не должно встречаться в пересылаемых файлах или переменных.
Все остальные заголовки точно такие же, как при отправке первым методом описаным в начале статьи.

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

—ccf8111910
Content-Disposition: form-data; name="mass[qwe]"

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

Для отправки файла нужно добавить еще тип и имя файла

—ccf8111910
Content-Disposition: form-data; name="var_file"; filename="a.txt"
Content-Type: text/plain

Читайте также:  Затухание линии adsl норма

В конце перечисления файлов и переменных нужно закрыть разделитель, добавив в конце разделителя ""
—ccf8111910—

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

Сейчас покажу как этот пример реализовать на php

= "test.ru" ; // с каким хостом соединяемся
$file_send = "a.txt" ; // файл который нужно отправить, можно указать абсолютный или относительный путь до файла
$boundary = md5 ( rand ( 0 , 32000 )); // создаем разделитель, md5 на основе случайного числа
$filesize = filesize ( $file_send ); // получаем размер пересылаемого файла. если будете пересылать не файл, а текст, то здесь нужно посчитать количество символов текста

// создаем код для отправки двух переменных
$data = "—" . $boundary . "
" ; // разделитель
$data .= "Content-Disposition: form-data; name="mass[qwe]"

" ; // имя перемнной
$data .= "значение переменной mass[qwe]
" ; // значение переменной
$data .= "—" . $boundary . "
" ; // разделитель, начало следующего блока данных
$data .= "Content-Disposition: form-data; name="var"

" ; // имя следующей переменной
$data .= "значение переменной var
" ; // ее значение

// создаем заголовки файла
$head_file = "—" . $boundary . "
" ; // разделитель
$head_file .= "Content-Disposition: form-data; name="var_file"; filename="" . $file_send . ""
" ; // имя переменной с файлом и имя пересылаемого файла
$head_file .= "Content-Type: " . mime_content_type ( $file_send ). "

" ; // mime-type файла. данная функция определения типа файла может не работать на многих серверах, поэтому ищите другой способ указания типа файла, можете вручную прописывать тип, например application/octet-stream

// считаем размер данных. размер нужно считать всего, что идет после основных заголовков, вместе с разделителями и всем остальным
// складываем данные с переменными, заголовки файла, размер файла который будет вставлен позже и плюс завершающий разделитель
$contentlength = strlen ( $data ) + strlen ( $head_file ) + $filesize + strlen ( "—" . $boundary . "—
" );

// теперь создаем основные заголовки, сам запрос
$headers = "POST /test/file.php HTTP/1.0
" ; // путь до скрипта, который принимает данные
$headers .= "Host: " . $host . "
" ;
$headers .= "Referer: " . $host . "
" ;
$headers .= "User-Agent: Opera
" ;
$headers .= "Content-type: multipart/form-data, boundary=" . $boundary . "
" ; // тип передаваемых данных и разделитель
$headers .= "Content-length: " . $contentlength . "

" ; // размер всех данных

if(! $fp = fsockopen ( $host , 80 )) exit; // открываем соединение
fputs ( $fp , $headers ); // посылаем основные заголовки в открытый поток
fputs ( $fp , $data ); // посылаем переменные
fputs ( $fp , $head_file ); // посылаем заголовки файла и ниже отправим сам файл

$fp2 = fopen ( $file_send , "rb" ); // открываем файл, который будет отправлять
while(! feof ( $fp2 )) // начинаем читать этот файл
<
$as = fgets ( $fp2 , 2048 ); // читаем кусок файла
fputs ( $fp , $as ); // посылаем этот кусок файла в открытый поток
>
fclose ( $fp2 ); // закрываем файл, который прочитали и отправили в поток

fputs ( $fp , "
—" . $boundary . "—
" ); // завершаем, отправляем закрывающий разделитель, указывающий на конец даных

// вывод ответа от скрипта
while( $gets = fgets ( $fp , 2048 ))
<
print $gets ;
>

fclose ( $fp ); // закрыли поток.
?>
Вот так можно отправить файл методом POST с помощью php.

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

Комментарии

06.06.2007 Андрей
Благодарю. какраз нужно было.

09.06.2007 Виктор
Отличная статья

21.08.2007 Димон
То что нужно. Полезная штука. Огромное спасибо.

08.09.2007 Александр
Огромное спасибо за статью.Давно искал подобную информацию.webi Вы лучшии .

24.10.2007 Антон
Огромное спасибо. Инфа полезная, но долго не мог найти в инете ничего с примерами.

22.11.2007 Андрей
Большое спасибо, только что искал нечто подобное )))

23.11.2007 Ярослав
Спасибо) То что нужно.

26.11.2007 Javad
Спасибо,давно такое искал.

07.12.2007 JonniK
А как таким способом передать массив? Как должна выглядеть строка $data?

07.12.2007 Рвота
Ура, теперь зафлужу одних идиотов нахрен! Спасибо за статью!

29.12.2007 Vik
отлично большое спасибо
то что искал

10.05.2008 ScREW
Порезались символы переноса строки "
". Куда-то потерялся слэш.

11.07.2008 GDP
слэш по-моему тут нашли все ))))
Огромное спасибо за мануал. В отличии от того, что представлено на PHP.net данный ман сработал

11.07.2008 Lewik
Спасибо огромное, особенно за массив через GET POST!

23.07.2008 clgs
не чего интересно не увидел. не понимаю восхищения.

07.08.2008 Сергей
Спасибо, с удовольствием подпишусь на вашу рассылку)

28.09.2008 TROLL
ТО ЧТО НУЖНО.

Ссылка на основную публикацию
Adblock detector