multipart/form-data

multipart/form-data (MIME)

[11] 媒体型 multipart/form-data は、 HTMLフォーム提出のために設計された書式です。 名前から分かる通り、 MIMEmultipart/* の書式に基づいています。

元々は HTML のフォーム、特にファイルのup (input//file) のために採用されましたが、 HTML 以外のフォームの提出にも使われています。 仕様上は任意の媒体型のデータを扱うことができます。

仕様書

構文

[40] 基本的には、 multipart/mixed と同じ書式です。 RFC 2046, HTML 4 17.13.4.2, RFC 2388 3.

前書き、後書き

[79] どのブラウザも、前書き後書きにします。 Opera が複数のファイルを提出する場合に使う multipart/mixed についてもそうです。 (HTTP の場合のみ調べました。) >>66

多部分境界

[24] 多部分境界 (boundary) はデータ中に現れてはなりません。 HTML 4 17.13.4.2, RFC 2388 4.1

[89] どのブラウザも、 boundary 引数quoted-string ではなく、 token として表現しています。 >>66

Firefox の例:

boundary=---------------------------105742468821884

Opera の例:

boundary=----------ByrdxQC7rqEXna35oMxxa7

Safari の例:

boundary=----WebKitFormBoundaryAAEEAAYDAACjAAHf

WinIE の例:

boundary=---------------------------7d839d460bd2

[124] 古の Netscape Navigatorboundary 引数を含めない不具合があったようです。

ひどいですね・・・。

[129] CGI.pm によれば、 MacIE の 3.01 と 3.02、 DreamPassport には境界文字列の前に -- を含めない不具合があったようです。

transport-padding

[125] MIME の規定によれば、境界文字列のある行の最後には任意個の空白が挿入されることがあり、 利用者エージェントはこれを無視して解釈しなければなりません。

[126] これは生成することは認められていませんが、 メールでは転送路の途中で追加されることがあり得たためそのような規定になっています。

[127] HTTPがこれに対応しているかは怪しいです。

[128] Perlモジュール HTTP::Body はこれに対応していないようです。ほどほどよく使われているモジュールのようなので、 Web互換性のためには必要ないということでしょう。

[130] CGI.pm はコードが酷くてよくわからないのですが (実際に試してみたらいいのでしょうが・・・)、 処理がいいかげんなのでたまたま対応できてるようにも見えます。

改行

[8] MIME の規定により、境界行や実体頭欄の末端の改行は CRLF でなければなりません。 CRLF だけではいけません。

[25] 他のすべての MIME 転送同様、改行は CRLF とします HTML 4 17.13.4.2。 と HTML 4 も言っています。 (転送とはどこからどこまでか、 曖昧であるのが問題ではありますが。)

[9] >>8 は大前提なんですが、 一方で HTTP ではいい加減な実装が多いので、もしかしたら・・・ CR だけとか LF だけとかで送ってくる糞 UA もあったりするんでしょうか?

多分 Mozilla とか Opera とか IE とかの有名どころは大丈夫だと思うんですが。。。

[60] MacIE 5.2 には boundary のところの改行の CR が一部欠落してしまう不具合があるそうです。

MacのIEでのmultipart/form-dataデータ <http://kvasir.skirnir.net/software/software00009.ksd>

[68] 主要ブラウザは multipart/form-data としての改行をすべて CRLF と正しく送信するようです。 >>66

本体部分の個数と順序

[65] 本体部分の個数に特に制限は設けられていないようです。

[23] フォームの各欄は、応用とフォームによって定義された順で、 それぞれ multipart/form-data本体部分とします。 RFC 2388 4.1 本体部分の順序は、 RFC 2388 では規定されていません。 RFC 2388 5.5

[41] HTML の場合、multipart/form-data本体部分は、それぞれ、 成功制御子に対応します。順序は制御子の文書順とします。 HTML 4 17.13.4.2

頭欄

[91] どのブラウザも、本体部分に使う可能性のある頭欄Content-Type]:Content-Disposition: だけのようです。他の頭欄は見たことがありません。 >>66

欄名 (制御子名)

[28] 各欄は名前を持ちます。名前はフォーム内で固有です。 RFC 2388 3. 欄名が同じ本体部分が複数あるときの取扱いは RFC 2388 では規定されていません。 RFC 2388 5. 応用により、例えば HTML ではフォーム・データ集合に同じ名前の制御子名があれば、 複数の本体部分が同じ名前となることがあります。

各本体部分は、 Content-Dispositionform-data とし、その name 引数に対応する制御子の欄名 (制御子名) を指定します HTML 4 17.13.4.2, RFC 2388 3.

[70] 主要ブラウザはどれも quoted-string を使いますが、 \" をきちんと quoted-pair にするのは Opera だけです。他のブラウザはそのまま放置します。 Opera も含めてどのブラウザも、 nameLF が含まれているとそのまま出力します。なので、 頭欄としては壊れてしまいます。 >>66

Charset

[29]ASCII 文字を含むときには、 RFC 2045 で説明されている方法で符号化して構いません HTML 4 17.13.4.2。と書いてはあるのですが、 構いませんではなくて何らかの方法で符号化しなければなりません (MIME 頭欄は ASCII と定義されています)。さて、 RFC 2045

の一体どこで Content-Disposition name を符号化する方法が説明されているのでしょうか? されていません。 詳しくは name 引数の説明をご覧ください。

相当する部分は、 RFC 2388 では RFC 2047 を参照しています RFC 2388 3., 5.4。 RFC 2047 と言うからには encoded-word を使うのでしょう。普通 quoted-string でが encoded-word は使わない (使えない) ものですが、 明示的に 2047 を参照しているのですから name 引数では特別に使えるのでしょう。

[69] 主要ブラウザでは、通常の制御子本体に使われるのと同じ charset でそのまま符号化されるようです。表現できない文字十進数文字参照になるのも本体と同じです。 (HTTP提出する場合のみ調べています。) >>66

[30]HTML 4 17.13.4.2

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

この例では、制御子名 mycontrol を表します。 この欄を含む本体部分の本体は、この名前の制御子の現在値 (またはファイル内容) になります。

ファイル情報 (ファイル名など)

[44] フォーム・ソフトウェアは、提出するファイルにファイル名やその他のファイルの属性情報をつけても構いません。 RFC 2388 4.4

[33] HTML UA は提出する各ファイルにファイル名を供給するよう試みるべきです。 ファイル名は Content-Disposition 欄の filename 引数で指定します。HTML 4 17.13.4.2

UA 側システムのファイル名が US-ASCII でないときには、 ファイル名は近似するか、 RFC 2045 の方法で符号化しなければなりません。 HTML 4 17.13.4.2>>29 に続いてここでも RFC 2045の方法が出てきましたが、 こちらもやはり RFC 2045 に規定はありません。

RFC 2388 は、 RFC 2045 ではなく、 RFC 2231 の方法を使っても良いとしています。 RFC 2388 4.4 この規定は RFC 2231 とは整合していますが、 encoded-word を使うべしとする name 引数の規定 (>>29) とは矛盾しています。本当に使い分けろというのでしょうか。

[45] 提出するファイルは相互にファイル名で参照関係を持っているかもしれませんから、 ファイル名が保存されていると便利です。 HTML 4 17.13.4.2, RFC 2388 4.4

ファイル名指定に関する様々な問題については、 filename 引数の説明をご覧ください。

[71] WinIEフルパス名を値に使います。他のブラウザは狭義のファイル名だけを値に使います。 >>66

[72] どのブラウザも常に quoted-string を使います。 WinIE\quoted-pair にしません。 >>66

[73] 未確認ですが、 name 引数の場合 (>>70) 同様、 特別な文字の扱いはどのブラウザもおかしいのだろうと思われます。

[82] 主要ブラウザでは、通常の制御子本体に使われるのと同じ charset でそのまま符号化されるようです。表現できない文字十進数文字参照になるのも本体と同じです。 (HTTP提出する場合のみ調べています。) >>66

[74] どのブラウザでも、 filename は必ず name の後に来るようです。 form-dataname 引数filename 引数の3つだけで、他の情報は付与しないみたいです。 >>66

[131] Perlモジュール HTTP::Bodyfilename 引数の有無によりある実体本体ファイルかどうか判断します。たとえ空文字列であっても、 ファイルならファイル名が必要です。

本体部分の実体本体

[31] 各本体部分の本体は、ファイル選択制御子 (input//file) ではファイルの内容、 それ以外では現在値になります。 (という説明が HTML 4 仕様書ではきちんとなされていません。)

内容転送符号化・内容符号化

[27] 各本体部分は CTE を使ってもかまいません。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.3 その他 MIME の機構により暗号化・圧縮などをしても構いません。 それは multipart/form-data を生成する応用の機能です。 RFC 2388 5.1

[53] ただし、 HTTPmultipart/form-data を使う場合は、仕様が曖昧なためその中の本体部分で Content-Transfer-Encoding を使用するべきではありません。 Content-Encoding を本体部分に適用できるのかどうかも曖昧であり、 使わない方が良いです。 (対応している実装も少ないでしょう。) Transfer-Encoding を本体部分に適用することはできません。

なお、これは multipart/form-data の各本体部分についてであり、 multipart/form-data 実体自体については >>54 をご覧下さい。

[75] どのブラウザも、内容符号化内容転送符号化は使用しないようです。 Content-Transfer-Encoding: 欄や Content-Encoding: 欄も使用していないようです。 (HTTP の場合のみ調べています。) >>66

媒体型

[26] ほかのすべての multipart/* 型と同様、 各本体部分は省略可能な Content-Type 頭欄を持ちます。省略時の既定値は text/plain です。

媒体型が分かっている場合は適当に札付けし、分からない場合は application/octet-stream とするべきです。 RFC 2388 4.1 HTML UA は、 Content-Type 欄を (charset 引数を含めて) 供給するべきです。 HTML 4 17.13.4.2

[32] 本体にファイルの内容を入れる場合には、適当な媒体型か、 分からなければ application/octet-stream を指定するべきです。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2

[76] どのブラウザも、ファイルの場合はそのファイル媒体型Content-Type: 欄として指定し、 それ以外の場合は Content-Type: 欄を省略します。 >>66

[77] ファイルの場合、どのブラウザも、 (おそらく拡張子やシステムの、またはブラウザ内蔵の対応表を使って) ファイルの媒体型を推定できればその値を、できなければ application/octet-stream を使うようです。 確認できた限りでは charset も含めて引数を指定することはありませんでした。 >>66

複数ファイルの同時提出

[51] 1つのフォーム項目として複数のファイルを同時に提出する場合には、 multipart/mixed を使って1つの本体部分とします。 HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2

ファイル名等はその multipart/mixed 内のそれぞれの本体部分の情報として付与します。

[34] 提出ファイルが複数の時の multipart/mixed 内の本体部分では Content-Disposition: file とするかのような記述が仕様書にあります HTML 4.01 17.13.4.2 が、 attachment の誤りだそうです HTML 4.01 正誤表 10.みっともないことに HTML 4.01 正誤表は RFC 2388 に責任転嫁しております(w。確かに元々 HTML 4.0 では attachment になっておりましたが、 HTML 4.01 で minor typo として修正されています HTML 4.01 A.1.3

[78] Opera 9 は Web Forms 2.0max 属性による指定を使ったファイルの複数同時提出に対応しています。 複数のファイルが含まれる場合、仕様通り multipart/mixed が使われます。その本体部分については、単体の場合と同じように挿入されます。 Content-Disposition: の値は RFC 2388 とも HTML4 とも違って form-data になります。 name 引数も単一ファイルの場合と同じように指定されます (multipart/mixed の方にも指定されますが、個々の本体部分の方にも指定されます)(複数ファイル指定可能であっても、選択数が1つ以下なら従前の方法によります。) >>66

零個のファイルを提出

[6] ファイル選択制御子 (input/file) があっても、ファイル名として何も指定されなかった場合、 WinIE も Mozilla も Opera も、空の内容を送ります。

このとき、 WinIE と Mozilla は頭欄に Content-Type: application/octet-stream と書いてきて、 Content-Disposition にも filename="" がつきます。 Opera ではどちらもつかず、本当に空 (Content-Disposition: form-data; name=名前 と空の内容だけ) になります。

[38] 頭欄がどうであれ、空の実体を送ってしまうと (一般の UA の場合に) ファイル未選択状態と内容が空のファイルを提出した場合が区別できなくなってしまいます。 ファイルを選択していないファイル選択制御子はそもそも成功にしてはいけないのではないでしょうか。

[80] HTML5 でも選択されていないファイル選択制御子フォーム・データ集合に含まれない定義になっていますがね。。。

[81] どのブラウザも、選択されていなくても空の実体本体を含めるようです。 Content-Disposition: はファイル以外の制御子の場合と同じです (filename 引数がつきません)。 Content-Type: は、 Opera 以外は application/octet-stream とします。 Opera自体を省略します。 >>66

遠隔ファイル指示子

[49] 遠隔ファイルを直接送らずに、 message/external-body を使ってその指示子だけを送ることができます。 RFC 2388 5.3

[52] message/external-body の使い方は色々ありますが、 access-type uri を使って遠隔ファイルの URI参照を送るのが現代的でよろしいのではないでしょうか。

[83] これに対応しているブラウザやフォーム処理エージェントがあるという話は聞いたことがありません。

Charset

[84] どのブラウザも、すべての実体本体name 引数filename 引数に同じ charset を使うようです。 >>66

[85] 使用することに決めた charset で表現できない文字がある場合、 Unicode における符号位置十進数文字参照形式にしたものが代わりに挿入されます。 >>66

[86] Opera は以前は multipart/form-data 自体の Content-Type: 欄に charset 引数を指定していましたが (>>2)、 互換性に難があったのか、現在はつけないようです。 他のブラウザも multipart/form-data 自体には boundary 引数だけしか指定しません。 >>66

[1] WinIEMozillaOpera も、 multipart/form-data に含まれる本体部分には charsetパラメーターを付けてくれません。 (ファイル送信を除いて Content-Type 欄そのものをつけません。)

[2] Opera は、 multipart/form-data そのものに存在しない charset 引数をつけてきます。 この charset 値は実際にはそれに含まれる本体部分の実体本体及び Content-Disposition 欄の name 引数に適用されるようです。あ、 filename にもかな? 今度確かめてみよう。

[3] 規格不適合ながらもとりあえず >>2 のように情報を送ってくる Opera に対して、 WinIE と Mozilla は既定では何もしません。ただし、 _charset_ hack を使えば一応は情報を得られます。

[4] >>2-3 の情報は、 file として送られる実体本体には適用できません。 (その実体の頭欄には適用されます。) charset=unknown-8bit とでも考えるしかなさそうです。問題は、 一般の form data と file を区別する確実な方法がないことです。 IE, Moz, Opera に限れば、 filename 引数の有無で決定できますが。。。

[5] >>4 あ、確実な方法が1つだけあります。受取る側が名前を知っていること。 これ超確実。

[88] HTML5 や元の Web Forms 2.0application/x-www-form-urlencodedtext/plain提出する場合については _charset_ hack を定義していますが、 multipart/form-data の処理は RFC 2388 に丸投げしているので、 _charset_ hack は正式にはどこでも定義されていません。

[87] Safari 以外のブラウザは _charset_ hack に対応しています。 >>66

multipart/form-data 符号化算法

[110] multipart/form-data 符号化算法 (encoding algorithm) は、 フォーム・データ集合multipart/form-data 実体として符号化するための算法です。

[111] multipart/form-data符号化算法は次のように定義されています >>109

  1. result空文字列とします。
  2. 選択された文字符号化 (selected character encoding) を、
    1. 明示的に文字符号化を指定して呼び出された場合は、それとします。
    2. そうでなく、 form 要素accept-charset 属性を有する場合、
      1. フォーム・データ集合に含まれる名前と値で使われている文字と、 利用者エージェントが対応している文字符号化の種類を鑑み、 属性中に含まれる文字符号化の中から ASCII互換文字符号化であるものいずれか一つとします。
      2. それがない場合は、 UTF-8 とします。
    3. そうでなく、文書の文字符号化ASCII互換文字符号化である場合、それとします。
    4. そうでない場合、 UTF-8 とします。
  3. charset を選択された文字符号化の優先MIME名とします。
  4. フォーム・データ集合の各項目 (entry) について、
    1. 名前が _charset_ で型が hidden なら、 値を charset に置き換えます。
    2. 名前と値の文字のうち、選択された文字符号化で表現できないものを十進数文字参照に置き換えます。
      1. ここ、十進数部分の先導0は特に禁止されていないようです。
  5. フォーム・データ集合RFC 2388 に従って符号化します。

HTML

[10] HTML 4 UA は、 multipart/form-data によるフォームの提出を実装しなければなりません HTML 4 17.13.4 と規定されていました。 HTML5 ではフォーム符号化算法などに完全に組み込まれており、 mutipart/form-data に対応しない実装が適合するのか不明です。

enctype 属性値

[104] HTMLform 要素enctype 属性と、 input 要素button 要素formenctype 属性は、属性値として multipart/form-data を指定することができる列挙型属性です >>103。この値を指定すると、当該要素 (やそのフォームに属する要素であって上書きされていないもの)enctypemultipart/form-data に設定することができます >>103要素enctypeフォーム提出算法から参照されています。

[108] enctypemultipart/form-data の時の適当なフォーム符号化算法multipart/form-data符号化算法です。 >>105

フォーム提出算法

[106] フォーム提出算法において提出する実体本体を構築するに当たり、提出子たるボタン要素enctype が参照されます。それが multipart/form-data である場合、 実体本体MIME型 (Content-Type: 欄の値) としては、

multipart/form-data; boundary=boundary-string

... が使われます。ただし boundary-stringmultipart/form-data境界文字列です。 >>103

[107] つまりすべて小文字で、 SPACE; の直後に1つだけ挿入され、 boundarytoken として表現されます。

VoiceXML

[99] VoiceXML 解釈器multipart/form-data に対応することが義務付けられています VoiceXML 2.1

XForms での利用

[96] XForms でも、「互換性のため」としながらも multipart/form-data を使うことができます。ただし、 XForms のモデル上のすべての情報を含められるわけではなく、 例えば属性節点に相当する情報は欠落します。

XForms は注記として、既存の HTML 利用者エージェント非ASCII文字等の扱いが芳しくないことを指摘しています。 それとどう関係があるのか知りませんが (だからきちんと処理するよう指導しているわけでもありません)、 multipart/relatedapplication/xml を使うことを勧めています。

WSDL での利用

[97] WSDL でも、 「XForms との互換性のため」として multipart/form-data を使うことができます。

関連

[93] WAP により規定された multipart/form-data に相当するバイナリー表現として、 application/vnd.wap.multipart.form-data 媒体型があります。

HTML と multipart/form-data

[6] HTML のフォームでは application/x-www-form-urlencoded もよく使われていますが、任意のバイナリ・データや非 ASCII 文字を効率よく確実に扱うことができないという問題があります。 バイナリ・データや非 ASCII 文字を含むフォームの提出では、 multipart/form-data を使うべきです HTML 4 17.13.4.2。 ファイル選択制御子 (input/file) を使う時には、 multipart/form-dataformenctype で指定するべきです HTML 4 17.3, 17.13.4.2

[35] HTML のフォームで multipart/form-data で提出させたい時は、 form 要素の enctype 属性に multipart/form-data と指定しておきます。

各本体部分の文字符号化方式の決定には、 form 要素の accept-charset 属性の指定を参照します。

転送プロトコルと multipart/form-data

[54] MIME の規定によれば、 multipart/* のすべての実体Content-Transfer-Encoding7bit, 8bit, binary のいずれかでなければなりません。もちろん multipart/form-data の実体にも適用されます。

注意: multipart/form-data本体部分についての規定ではありません。 本体部分の CTE については >>53 を参照して下さい。

[55] HTTP では Content-Transfer-Encoding を使用しません (常に binary 相当です) が、 Content-EncodingTransfer-Encoding があります。 Transfer-Encoding は媒体型に依存しませんので、 multipart/form-data であろうがそうでなかろうが常に使用できます。 Content-Encoding が使用できるのかどうかは微妙なところですが、 特別規定がないのですから、使用できるのでしょう。但し、 それに対応している実装 (クライアント・鯖) がどれだけあるのかは微妙なところです。

[56] Content-MD5 による簡易的な整合性情報は、 MIME では multipart/* に対して使用することが認められていませんが、 HTTP では認められています。 multipart/form-data についても例外ではありません。

しかし、 multipart/form-data 全体の MD5 ハッシュを計算するよりは、面倒でも個々の本体部分で計算した方が良いでしょう。 もし HTTP で提出された multipart/form-data が途中で MIME に変換されて (例えば電子メイルで) 送られるとすると困ったことになります。

[64] そんなことあるのか知りませんがw

その他

保安性

[50] multipart/form-data を構成するプロトコル要素やフォームの仕組み自体には、 様々な安全上の問題があることが知られています。

例えば、利用者の意図しない状態や利用者が十分な考慮を行えない状況で自動的・ 半自動的にフォームを提出させると、 利用者の私的な情報や利用者の環境の安全に関わる情報が送信されてしまう虞があります。 このほかにも、フォームの提出という仕組みそのものに起因する問題が多く見つかっています。

また、ファイルを提出する際には filename 引数を使うことができますが、フォーム処理エージェント (multipart/form-data を処理する側) が信頼して無防備に実際のファイル名等として使用すると、 既存の別のファイルやシステム・ファイルを上書きしたり、 その環境で扱えないファイル名のファイルが中途半端にできてしまったりする虞があります。 詳しくは filename 引数の説明をご覧ください。

このようなフォーム自体や multipart/form-data が利用しているプロトコル要素に関する問題や、 特定の実装に依存した問題を除いては、 multipart/form-data に関する安全上の問題は見つかっていません。

[57] 提出の途中での改竄を検出する簡易的な手段として Content-MD5 が使用できます (>>56)。 但し記述された Content-MD5 値自体が改竄されることもあり得ますから、 あくまで簡易的なものです。また、 実装している利用者エージェントは現時点で存在しないと思われます。

[58] 一般の MIME の実体の安全のための仕組みとして署名のための multipart/signed暗号化のための multipart/encrypted が、 それを使った実際のシステムとして PGP/MIMES/MIME があります。しかし、現実に multipart/form-data と組合せて使っている (使える) 例は聞いたことがありません。 multipart/form-data のどの部分を署名・暗号化するのか (あるいは全体をするのか) や、フォームの提出の手続きの中でどのように処理するのかなどの詳細な標準化がなされないと (またはデファクト標準が登場しないと) 使用するのは難しいでしょう。

[59] 現実にフォームの提出の安全のために使用されているのは TLSSSL です。 HTTP に対応した利用者エージェントや鯖では大抵 TLS over HTTP (HTTPS) が利用できるので、 フォーム処理エージェントとしては特別な処理が要らないのが普通です。 但し、 HTTP 以外の提出方法 (特に電子メイル) にはこの方法は使えません。

歴史

実装開始

[15] WinIE 3.02 用の file upload add-on は1997年の中ごろに出ました。

RFC 1867

HTML4 と RFC 2388

[92] RFC 1867 と RFC 2388 と HTML 4 の multipart/form-data の規定は文章を流用していて同じようなことが書いてありますが、 少しずつ違います。独立の仕様書になっている RFC 2388 が当然一番詳しくなっています。

[7] HTML 4multipart/form-data への言及の変遷:

  1. 勧告以前の HTML 4 原案では、高々紹介程度で RFC 1867 にほぼ丸投げ。
  2. HTML 4.0 勧告第1版: Forms in HTML documents <http://www.w3.org/TR/REC-html40-971218/interact/forms.html#didx-multipartform-data>
  3. HTML 4.0 勧告第2版: Forms in HTML documents <http://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html#didx-multipartform-data>
    • 勧告第1版と全く同内容
  4. HTML 4.01 勧告提案: Forms in HTML documents <http://www.w3.org/TR/1999/PR-html40-19990824/interact/forms.html#didx-multipartform-data>
    • RFC 1867 から RFC 2388 に参照先を変更
  5. HTML 4.01 勧告: Forms in HTML documents <http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#didx-multipartform-data>
    • typo 修正
    • 例中の Content-Disposition: attachmentContent-Disposition: file に変更
  6. HTML 4.01 正誤表: HTML 4 Errata <http://www.w3.org/MarkUp/html4-updates/errata#entry-10>
    • 勧告での attachment から file に再修正。しかも RFC 2388 に責任転嫁(藁

[22] multipart/form-data 内容は RFC 2045 で説明された多部分 MIME データ列の規則に従います。 multipart/form-data の定義は IANAREG から入手できます。 HTML 4 17.13.4.2 と書いてありますけど、むしろ RFC 2046 を読むべきでしょう。 また、後方互換性, 他の内容型との関係, 効率の問題その他については RFC 1867 HTML 4.0 17.13.4.2RFC 2388 HTML 4.01 17.13.4.2 を読むよう指示があります。 ちなみに、仕様書の発行順序は HTML 4.0 → RFC 2388 → HTML 4.01 です。

[95] HTML4フォーム非ASCII文字提出される可能性がある場合に application/x-www-form-urlencoded の代わりに multipart/form-data を使うことを勧めていましたが、 世間からは完全に無視されています。

device-upload

[98] device-upload では、音声等の新しいファイルうpの方法に適用するための device などの Content-Disposition: 引数を提案し、 その指定方法を規定していました。

WF2 と HTML5

[121] WF2 ははじめてフォーム提出算法を明確な形で仕様として規定しました。その中に multipart/form-data による提出の方法も含まれていました。

[122] HTML Living Standard (HTML5 / Web Applications 1.0) はこれを引き継ぎ、 更により明確かつ具体的に multipart/form-data の処理も規定しています。

[123] とはいえ、いずれの仕様書も multipart/form-data 自体の生成の部分は RFC に委ねており、 >>102 により曖昧な部分を明確化したとはいえ、結果として delta spec のような状態になっています。

実装

[36] 現代のほとんどの WWWブラウザmultipart/form-data によるフォームの提出を実装しています。

[37] 一方、 CGIスクリプトなどの鯖側は酷い状況です。 多くの実装は相手にもしていません。 Perl なら CGI.pm などを使えば自動的に対応できますが、最近は増えてきたとはいえモジュールを CGI スクリプトで使うことは少なく、 application/x-www-form-urlencoded にしか対応していません。ファイルのうpがしたくなったら (素直にモジュールを使えばいいのに) 見よう見まねで適当に対処しようとして、 結局特定ブラウザの特定の版でしか上手く動かないようなコードを書いてみたり。 (で、質問掲示板で暴れてみたり。) お前らちゃんと仕様書読んでくださいよ。

処理系で標準または標準に近いモジュール的なものが要求の解析をしてくれることが広く知られていて、 そのモジュール的なものの作者がちゃんと仕様を読んでコードを書くような人なら、 その処理系で書かれた処理はさほど深く考えなくても自動的に multipart/form-data を正しく処理できるはずです。 よく知りませんけど、 Java servelet とか PHP はその辺きちんとしてるのではないですか?

[66] Firefox 3.0.4、Opera 9.61、Safari 3.2、WinIE 7 の実装状況を調べてみました。

[94] enctype="multipart/form-data"で携帯からファイルアップロード « 携帯・モバイル « プログラム « Re: (kronekodow 著, 版) <http://blog.livedoor.jp/kronekodow/archives/64944587.html>

SoftBankが素敵に思えた。

データフォルダから直アップできるんですね。

fileup_auauは(W52SHは)Browse...ってボタンは出るものの反応しない。

DoCoMoはボタンすら出ない。

SoftBankでも、C端末、3GC端末などによる違など全てじゃなかったり、auも一部端末なら出来たり?(HTMLやXHTMLの違いなども関係したり)とか、可能な端末の振り分けは大変そうです。

複数ファイルをまとめて提出

[13] 1つのファイル選択制御子 (input//file) を使って複数ファイルをうpする (>>51) のは、 UA で対応してるのはなさげ、 サーバーもおそらく全滅だろうという感じですね。

www-htmlOpera の特定の版では出来るという未確認情報がありましたが、 最新版では出来ないらしいし、勘違いかなんかじゃないかなあ。

[67] その後 Opera 9 は Web Forms 2.0 に対応しましたので、 複数ファイルの提出にも対応しています。 file 制御子用の max 属性は一旦 HTML5 で削除されましたが、 multiple 属性が改めて追加される予定ですから、 いずれ他のブラウザも複数ファイルの提出に対応すると期待されます。

試験事例

[90] Index of /~wakaba/-temp/test/html/form/multipart-form-data ( 版) <http://suika.fam.cx/~wakaba/-temp/test/html/form/multipart-form-data/>

[39] HTML のフォームの例 HTML 4 17.13.4.2、改

 <FORM action="http://server.example/cgi/handle"
       enctype="multipart/form-data"
       method="post">
   <P>
   What is your name? <INPUT type="text" name="submit-name"><BR>
   What files are you sending? <INPUT type="file" name="files"><BR>
   <INPUT type="submit" value="Send"> <INPUT type="reset">
 </FORM>

このフォームで、文章入力欄に Larry と記入し、ファイル選択で file1.txt を指定して提出した場合 HTML 4 17.13.4.2, 改:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

更に file2.gif も選択していた場合 HTML 4 17.13.4.2, 改:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: multipart/mixed; boundary=BbC04y

--BbC04y

Content-Disposition: file attachment; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--BbC04y
Content-Disposition: file attachment; filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary

...contents of file2.gif...
--BbC04y--
--AaB03x--

[47] ユーロ通貨記号を値に使った例 RFC 2388 4.5、改

Content-Type: multipart/form-data; boundary="AaB03x"

--AaB03x
content-disposition: form-data; name="field1"
content-type: text/plain; charset=windows-1250
content-transfer-encoding: quoted-printable

Joe owes =80100.
--AaB03x--

Q & A

[63] Q: HTML でファイルをアップロードするにはどうしたらいいですか? ファイル名しか取得できません...

A: ファイル名しか取得できないのは、 application/x-www-form-urlencoded を使用しているからの可能性が高いと考えられます。 フォームの提出で multipart/form-data を使うようにしましょう。

関連: >>61, input//file, 提出

[61] Q: HTML によるフォームの提出でブラウザに multipart/form-data で送ってもらうにはどうしたらいいですか?

A: form 要素の enctype 属性を multipart/form-data と指定してください。

ついでに、 accept-charset 属性に希望する文字コードも指定しておきましょう。

method 属性を post にしておくのを忘れないように。

関連: form, enctype, 提出

[62] Q: CGI スクリプトで multipart/form-dataapplication/x-www-form-urlencoded を見分けるにはどうしたらいいですか?

A: CGI には CONTENT_TYPE というメタ変数 (環境変数) があります。その値で判別できます。

CONTENT_TYPE の値の先頭の19文字が multipart/form-data (大文字・小文字の区別なし) で、その次の文字が存在しないか、空白 (間隔タブ改行) か、セミコロン (;) なら、 multipart/form-data が使われています。

CONTENT_TYPE}] の値の先頭35文字が application/x-www-form-urlencoded (大文字・小文字の区別なし) で、その次の文字が存在しないか、空白 (間隔タブ改行) か、セミコロン (;) なら、 application/x-www-form-urlencoded が使われています。

それ以外なら、未知の何かが使われています。

関連: Content-Type, CONTENT_TYPE

メモ

[100] XForms 1.1 ( 版) <http://www.w3.org/TR/2009/REC-xforms-20091020/#serialize-form-data>