[11] [[媒体型]] [DFN[[CODE(MIME)[multipart/form-data]]]] は、 [[HTML]] の[[フォーム]]の[[提出]]のために設計された書式です。 名前から分かる通り、 [[MIME]] の [CODE(MIME)[[[multipart/[VAR[*]]]]]] の書式に基づいています。 元々は HTML のフォーム、特にファイルの[[up]] ([[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]]) のために採用されましたが、 HTML 以外のフォームの提出にも使われています。 仕様上は任意の[[媒体型]]のデータを扱うことができます。 [[#comment]] * 仕様書 [21] 仕様書: - [[HTML]] 系 -- [[RFC 1867]] -- [[RFC 2388]] [CITE[Returning Values from Forms: multipart/form-data]] -- [[HTML 4]] --- [CITE[multipart/form-data]] --- [CITE[A.1.3 Minor typographical errors that were corrected]] --- HTML 4.01 正誤表 [CITE[10. content-disposition: attachment]] --[CITE[Form-based Device Input and Upload in HTML]] ([TIME[2000-03-13 23:37:05 +09:00]] 版) --[CITE@en-GB-x-Hixie[Web Forms 2.0]] ([TIME[2006-10-12 09:55:44 +09:00]] 版) -- [[HTML 5]] -[CITE@EN[Voice Extensible Markup Language (VoiceXML) 2.1]] ([TIME[2007-06-17 03:12:27 +09:00]] 版) -[CITE@EN[XForms 1.0 (Third Edition)]] ([TIME[2007-10-30 03:02:40 +09:00]] 版) - [CITE@en[Web Services Description Language (WSDL) Version 2.0 Part 2: Adjuncts]] ([TIME[2007-06-23 05:33:39 +09:00]] 版) ** HTML4 に関して [92] RFC 1867 と RFC 2388 と HTML 4 の [CODE(MIME)[multipart/form-data]] の規定は文章を流用していて同じようなことが書いてありますが、 少しずつ違います。独立の仕様書になっている RFC 2388 が当然一番詳しくなっています。 [7] [[HTML 4]] の [CODE(MIME)[multipart/form-data]] への言及の変遷: = 勧告以前の HTML 4 原案では、高々紹介程度で [[RFC 1867]] にほぼ丸投げ。 = HTML 4.0 勧告第1版: ''Forms in HTML documents'' = HTML 4.0 勧告第2版: ''Forms in HTML documents'' -- 勧告第1版と全く同内容 = HTML 4.01 勧告提案: ''Forms in HTML documents'' -- RFC 1867 から [[RFC 2388]] に参照先を変更 = HTML 4.01 勧告: ''Forms in HTML documents'' -- typo 修正 -- 例中の [CODE(MIME)[Content-Disposition: attachment]] を [CODE(MIME)[Content-Disposition: file]] に変更 = HTML 4.01 正誤表: ''HTML 4 Errata'' -- 勧告での [CODE(MIME)[attachment]] から [CODE(MIME)[file]] に再修正。しかも RFC 2388 に責任転嫁(藁 [22] [CODE(MIME)[multipart/form-data]] 内容は [[RFC 2045]] で説明された[[多部分]] MIME データ列の規則に従います。 [CODE(MIME)[multipart/form-data]] の定義は [[IANAREG]] から入手できます。 [SRC[HTML 4 17.13.4.2]] と書いてありますけど、むしろ [[RFC 2046]] を読むべきでしょう。 また、後方互換性, 他の内容型との関係, 効率の問題その他については [[RFC 1867]] [SRC[HTML 4.0 17.13.4.2]] ・ [[RFC 2388]] [SRC[HTML 4.01 17.13.4.2]] を読むよう指示があります。 ちなみに、仕様書の発行順序は HTML 4.0 → RFC 2388 → HTML 4.01 です。 [[#comment]] * 構文 [40] 基本的には、 [CODE(MIME)[[[multipart/mixed]]]] と同じ書式です。 [SRC[[[RFC 2046]], HTML 4 17.13.4.2, RFC 2388 3.]] ** 前書き、後書き [79] どのブラウザも、[[前書き]]も[[後書き]]も[[空]]にします。 [[Opera]] が複数のファイルを[[提出]]する場合に使う [CODE(MIME)@en[[[multipart/mixed]]]] についてもそうです。 ([[HTTP]] の場合のみ調べました。) [SRC@en[>>66]] ** 多部分境界 [24] 多部分境界 ([CODE(MIME)[[[boundary]]]]) はデータ中に現れてはなりません。 [SRC[HTML 4 17.13.4.2, RFC 2388 4.1]] [89] どのブラウザも、 [CODE(MIME)@en[[[boundary]]]] [[引数]]は [[quoted-string]] ではなく、 [[token]] として表現しています。 [SRC@en[>>66]] [[Firefox]] の例: [PRE(MIME example code)[ boundary=---------------------------105742468821884 ]PRE] [[Opera]] の例: [PRE(MIME example code)[ boundary=----------ByrdxQC7rqEXna35oMxxa7 ]PRE] [[Safari]] の例: [PRE(MIME example code)[ boundary=----WebKitFormBoundaryAAEEAAYDAACjAAHf ]PRE] [[WinIE]] の例: [PRE(MIME example code)[ boundary=---------------------------7d839d460bd2 ]PRE] ** 改行 [8] MIME の規定により、境界行や実体頭欄の末端の改行は [CODE(char)[[[CRLF]]]] でなければなりません。 [CODE(char)[[[CR]]]] や [CODE(char)[[[LF]]]] だけではいけません。 [25] 他のすべての MIME 転送同様、改行は [CODE(char)[[[CRLF]]]] とします [SRC[HTML 4 17.13.4.2]]。 と HTML 4 も言っています。 ([Q[転送]]とはどこからどこまでか、 曖昧であるのが問題ではありますが。) [9] >>8 は大前提なんですが、 一方で HTTP ではいい加減な実装が多いので、もしかしたら・・・ [CODE(char)[CR]] だけとか [CODE(char)[LF]] だけとかで送ってくる糞 UA もあったりするんでしょうか? 多分 [[Mozilla]] とか [[Opera]] とか [[IE]] とかの有名どころは大丈夫だと思うんですが。。。 [60] [[MacIE]] 5.2 には [CODE(MIME)[[[boundary]]]] のところの改行の [CODE(ABNF)[[[CR]]]] が一部欠落してしまう不具合があるそうです。 [CITE[MacのIEでのmultipart/form-dataデータ]] [68] 主要ブラウザは [CODE(MIME)@en[[[multipart/form-data]]]] としての[[改行]]をすべて [[CRLF]] と正しく送信するようです。 [SRC@en[>>66]] [[#comment]] ** 本体部分の個数と順序 [65] [[本体部分]]の個数に特に制限は設けられていないようです。 [23] フォームの各欄は、応用とフォームによって定義された順で、 それぞれ [CODE(MIME)[multipart/form-data]] の[[本体部分]]とします。 [SRC[RFC 2388 4.1]] 本体部分の順序は、 RFC 2388 では規定されていません。 [SRC[RFC 2388 5.5]] [41] HTML の場合、[CODE(MIME)[multipart/form-data]] の[[本体部分]]は、それぞれ、 [[成功]]制御子に対応します。順序は制御子の[[文書順]]とします。 [SRC[HTML 4 17.13.4.2]] ** 頭欄 [91] どのブラウザも、[[本体部分]]に使う可能性のある[[頭欄]]は [CODE(MIME)@en[[[Content-Type]]]:]] と [CODE(MIME)@en[[[Content-Disposition]]:]] だけのようです。他の[[頭欄]]は見たことがありません。 [SRC@en[>>66]] ** 欄名 (制御子名) [28] 各欄は名前を持ちます。名前はフォーム内で固有です。 [SRC[RFC 2388 3.]] 欄名が同じ本体部分が複数あるときの取扱いは RFC 2388 では規定されていません。 [SRC[RFC 2388 5.]] 応用により、例えば HTML では[[フォーム・データ集合]]に同じ名前の制御子名があれば、 複数の本体部分が同じ名前となることがあります。 各本体部分は、 [CODE(MIME)[[[Content-Disposition]]]] を [CODE(MIME)[[[form-data]]]] とし、その [CODE(MIME)[[[name]]]] 引数に対応する制御子の欄名 ([[制御子名]]) を指定します [SRC[HTML 4 17.13.4.2, RFC 2388 3.]]。 [70] 主要ブラウザはどれも [[quoted-string]] を使いますが、 [CODE(char)[[[\]]]] や [CODE(char)[[["]]]] をきちんと [[quoted-pair]] にするのは [[Opera]] だけです。他のブラウザはそのまま放置します。 [[Opera]] も含めてどのブラウザも、 [CODE(HTMLa)@en[[[name]]]] に [CODE(charname)@en[[[LF]]]] が含まれているとそのまま出力します。なので、 [[頭欄]]としては壊れてしまいます。 [SRC@en[>>66]] *** Charset [29] 非 [[ASCII]] 文字を含むときには、 [[RFC 2045]] で説明されている方法で符号化して構いません [SRC[HTML 4 17.13.4.2]]。と書いてはあるのですが、 [Q[構いません]]ではなくて何らかの方法で符号化しなければ'''なりません''' (MIME 頭欄は ASCII と定義されています)。さて、 RFC 2045 の一体どこで [CODE(MIME)[Content-Disposition]] [CODE(MIME)[name]] を符号化する方法が説明されているのでしょうか? されていません。 詳しくは [CODE(MIME)[[[name]]]] 引数の説明をご覧ください。 相当する部分は、 RFC 2388 では [[RFC 2047]] を参照しています [SRC[RFC 2388 3., 5.4]]。 RFC 2047 と言うからには [CODE(ABNF)[[[encoded-word]]]] を使うのでしょう。普通 [CODE(ABNF)[[[quoted-string]]]] でが [CODE(ABNF)[encoded-word]] は使わない (使えない) ものですが、 明示的に 2047 を参照しているのですから [CODE(MIME)[name]] 引数では特別に使えるのでしょう。 [69] 主要ブラウザでは、通常の[[制御子]]の[[本体]]に使われるのと同じ [[charset]] でそのまま[[符号化]]されるようです。表現できない[[文字]]が[[十進数文字参照]]になるのも[[本体]]と同じです。 ([[HTTP]] で[[提出]]する場合のみ調べています。) [SRC@en[>>66]] *** 例 [30] 例 [SRC[HTML 4 17.13.4.2]] [PRE(MIME)[ Content-Disposition: form-data; name="mycontrol" ]PRE] この例では、制御子名 [SAMP[mycontrol]] を表します。 この欄を含む本体部分の[[本体]]は、この名前の制御子の[[現在値]] (またはファイル内容) になります。 [[#comment]] ** ファイル情報 (ファイル名など) [44] フォーム・ソフトウェアは、[[提出]]する[[ファイル]]にファイル名やその他のファイルの属性情報をつけても構いません。 [SRC[RFC 2388 4.4]] [33] HTML UA は提出する各ファイルにファイル名を供給するよう試みるべきです。 ファイル名は [CODE(MIME)[Content-Disposition]] 欄の [CODE(MIME)[[[filename]]]] 引数で指定します。[SRC[HTML 4 17.13.4.2]] UA 側システムのファイル名が [[US-ASCII]] でないときには、 ファイル名は近似するか、 RFC 2045 の方法で符号化しなければなりません。 [SRC[HTML 4 17.13.4.2]] と >>29 に続いてここでも [Q[RFC 2045の方法]]が出てきましたが、 こちらもやはり RFC 2045 に規定はありません。 RFC 2388 は、 RFC 2045 ではなく、 [[RFC 2231]] の方法を使っても良いとしています。 [SRC[RFC 2388 4.4]] この規定は RFC 2231 とは整合していますが、 [CODE(ABNF)[encoded-word]] を使うべしとする [CODE(MIME)[name]] 引数の規定 (>>29) とは矛盾しています。本当に使い分けろというのでしょうか。 [45] 提出するファイルは相互にファイル名で参照関係を持っているかもしれませんから、 ファイル名が保存されていると便利です。 [SRC[HTML 4 17.13.4.2, RFC 2388 4.4]] ファイル名指定に関する様々な問題については、 [CODE(MIME)[[[filename]]]] 引数の説明をご覧ください。 [71] [[WinIE]] は[[フルパス名]]を値に使います。他のブラウザは狭義の[[ファイル名]]だけを値に使います。 [SRC@en[>>66]] [72] どのブラウザも常に [[quoted-string]] を使います。 [[WinIE]] は [CODE(char)[[[\]]]] を [[quoted-pair]] にしません。 [SRC@en[>>66]] [73] 未確認ですが、 [CODE(MIME)@en[[[name]]]] [[引数]]の場合 (>>70) 同様、 特別な[[文字]]の扱いはどのブラウザもおかしいのだろうと思われます。 [82] 主要ブラウザでは、通常の[[制御子]]の[[本体]]に使われるのと同じ [[charset]] でそのまま[[符号化]]されるようです。表現できない[[文字]]が[[十進数文字参照]]になるのも[[本体]]と同じです。 ([[HTTP]] で[[提出]]する場合のみ調べています。) [SRC@en[>>66]] [74] どのブラウザでも、 [CODE(MIME)@en[[[filename]]]] は必ず [CODE(MIME)@en[[[name]]]] の後に来るようです。 [CODE(MIME)@en[[[form-data]]]] と [CODE(MIME)@en[[[name]]]] [[引数]]と [CODE(MIME)@en[[[filename]]]] [[引数]]の3つだけで、他の情報は付与しないみたいです。 [SRC@en[>>66]] ** 本体部分の実体本体 [31] 各本体部分の[[本体]]は、ファイル選択制御子 ([[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]]) ではファイルの内容、 それ以外では[[現在値]]になります。 [WEAK[(という説明が HTML 4 仕様書ではきちんとなされていません。)]] [[#comment]] *** 内容転送符号化・内容符号化 [27] 各本体部分は [ABBR[[[CTE]]] [[CODE(MIME)[[[Content-Transfer-Encoding]]]]]] を使ってもかまいません。 [SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.3]] その他 MIME の機構により暗号化・圧縮などをしても構いません。 それは [CODE(MIME)[multipart/form-data]] を生成する応用の機能です。 [SRC[RFC 2388 5.1]] [53] ただし、 [[HTTP]] で [CODE(MIME)[[[multipart/form-data]]]] を使う場合は、仕様が曖昧なためその中の本体部分で [CODE(MIME)[Content-Transfer-Encoding]] を使用するべきではありません。 [CODE(HTTP)[[[Content-Encoding]]]] を本体部分に適用できるのかどうかも曖昧であり、 使わない方が良いです。 [WEAK[(対応している実装も少ないでしょう。)]] [CODE(HTTP)[[[Transfer-Encoding]]]] を本体部分に適用することはできません。 なお、これは [CODE(MIME)[multipart/form-data]] ''内''の各本体部分についてであり、 [CODE(MIME)[multipart/form-data]] 実体自体については >>54 をご覧下さい。 [75] どのブラウザも、[[内容符号化]]や[[内容転送符号化]]は使用しないようです。 [CODE(MIME)@en[[[Content-Transfer-Encoding]]:]] 欄や [CODE(HTTP)@en[[[Content-Encoding]]:]] 欄も使用していないようです。 ([[HTTP]] の場合のみ調べています。) [SRC@en[>>66]] *** 媒体型 [26] ほかのすべての [CODE(MIME)[[[multipart/[VAR[*]]]]]] 型と同様、 各本体部分は省略可能な [CODE(MIME)[[[Content-Type]]]] 頭欄を持ちます。省略時の既定値は [CODE(MIME)[[[text/plain]]]] です。 媒体型が分かっている場合は適当に札付けし、分からない場合は [CODE(MIME)[[[application/octet-stream]]]] とするべきです。 [SRC[RFC 2388 4.1]] HTML [[UA]] は、 [CODE(MIME)[Content-Type]] 欄を ([CODE(MIME)[[[charset]]]] 引数を含めて) 供給するべきです。 [SRC[HTML 4 17.13.4.2]] [32] 本体にファイルの内容を入れる場合には、適当な[[媒体型]]か、 分からなければ [CODE(MIME)[[[application/octet-stream]]]] を指定するべきです。 [SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2]] [76] どのブラウザも、[[ファイル]]の場合はその[[ファイル]]の[[媒体型]]を [CODE(MIME)@en[[[Content-Type]]:]] 欄として指定し、 それ以外の場合は [CODE(MIME)@en[[[Content-Type]]:]] 欄を省略します。 [SRC@en[>>66]] [77] [[ファイル]]の場合、どのブラウザも、 [WEAK[(おそらく[[拡張子]]やシステムの、またはブラウザ内蔵の対応表を使って)]] ファイルの[[媒体型]]を推定できればその値を、できなければ [CODE(MIME)@en[[[application/octet-stream]]]] を使うようです。 確認できた限りでは [CODE(MIME)@en[[[charset]]]] も含めて[[引数]]を指定することはありませんでした。 [SRC@en[>>66]] *** 複数ファイルの同時提出 [51] 1つのフォーム項目として複数のファイルを同時に提出する場合には、 [CODE(MIME)[[[multipart/mixed]]]] を使って1つの[[本体部分]]とします。 [SRC[HTML 4 17.13.4.2, RFC 2388 3., RFC 2388 4.2]] ファイル名等はその [CODE(MIME)[multipart/mixed]] 内のそれぞれの[[本体部分]]の情報として付与します。 [34] 提出ファイルが複数の時の [CODE(MIME)[multipart/mixed]] 内の本体部分では [CODE(MIME)[Content-Disposition: file]] とするかのような記述が仕様書にあります [SRC[HTML 4.01 17.13.4.2]] が、 [CODE(MIME)[attachment]] の誤りだそうです [SRC[HTML 4.01 正誤表 10.]]。 [WEAK[みっともないことに HTML 4.01 正誤表は [[RFC 2388]] に責任転嫁しております(w。確かに元々 HTML 4.0 では [CODE(MIME)[attachment]] になっておりましたが、 HTML 4.01 で [Q[minor typo]] として修正されています [SRC[HTML 4.01 A.1.3]]。]] [78] [[Opera]] 9 は [[Web Forms 2.0]] の [CODE(HTMLa)@en[[[max]]]] [[属性]]による指定を使った[[ファイル]]の複数同時[[提出]]に対応しています。 複数のファイルが含まれる場合、仕様通り [CODE(MIME)@en[[[multipart/mixed]]]] が使われます。その[[本体部分]]については、単体の場合と同じように挿入されます。 [CODE(MIME)@en[[[Content-Disposition]]:]] の値は [[RFC 2388]] とも [[HTML4]] とも違って [CODE(MIME)@en[[[form-data]]]] になります。 [CODE(MIME)@en[[[name]]]] [[引数]]も単一ファイルの場合と同じように指定されます [WEAK[([CODE(MIME)@en[[[multipart/mixed]]]] の方にも指定されますが、個々の[[本体部分]]の方にも指定されます)]]。 [WEAK[(複数ファイル指定可能であっても、選択数が1つ以下なら従前の方法によります。)]] [SRC@en[>>66]] *** 零個のファイルを提出 [6] ファイル選択制御子 ([[[CODE(HTMLe)[input]]/[CODE(HTML)[file]]]]) があっても、ファイル名として何も指定されなかった場合、 WinIE も Mozilla も Opera も、空の内容を送ります。 このとき、 WinIE と Mozilla は頭欄に [CODE(MIME)[[[Content-Type]]: [[application/octet-stream]]]] と書いてきて、 [CODE(MIME)[[[Content-Disposition]]]] にも [CODE(MIME)[[[filename]]=""]] がつきます。 Opera ではどちらもつかず、本当に空 ([CODE(MIME)[Content-Disposition: [[form-data]]; name=[VAR[名前]]]] と空の内容だけ) になります。 [38] 頭欄がどうであれ、空の実体を送ってしまうと [WEAK[(一般の UA の場合に)]] ファイル未選択状態と内容が空のファイルを提出した場合が区別できなくなってしまいます。 ファイルを選択していないファイル選択制御子はそもそも[[成功]]にしてはいけないのではないでしょうか。 [80] [[HTML5]] でも選択されていない[[ファイル選択制御子]]は[[フォーム・データ集合]]に含まれない定義になっていますがね。。。 [81] どのブラウザも、選択されていなくても空の[[実体本体]]を含めるようです。 [CODE(MIME)@en[[[Content-Disposition]]:]] はファイル以外の[[制御子]]の場合と同じです ([CODE(MIME)@en[[[filename]]]] [[引数]]がつきません)。 [CODE(MIME)@en[[[Content-Type]]:]] は、 [[Opera]] 以外は [CODE(MIME)@en[[[application/octet-stream]]]] とします。 [[Opera]] は[[欄]]自体を省略します。 [SRC@en[>>66]] [[#comment]] *** 遠隔ファイル指示子 [49] 遠隔ファイルを直接送らずに、 [CODE(MIME)[[[message/external-body]]]] を使ってその[[指示子]]だけを送ることができます。 [SRC[RFC 2388 5.3]] [52] [CODE(MIME)[message/external-body]] の使い方は色々ありますが、 [CODE(MIME)[[[access-type]]]] [CODE(MIME)[[[uri]]]] を使って遠隔ファイルの [[URI参照]]を送るのが現代的でよろしいのではないでしょうか。 [83] これに対応しているブラウザや[[フォーム処理エージェント]]があるという話は聞いたことがありません。 [[#comment]] ** Charset [84] どのブラウザも、すべての[[実体本体]]、 [CODE(MIME)@en[[[name]]]] [[引数]]、 [CODE(MIME)@en[[[filename]]]] [[引数]]に同じ [[charset]] を使うようです。 [SRC@en[>>66]] [85] 使用することに決めた [[charset]] で表現できない[[文字]]がある場合、 [[Unicode]] における[[符号位置]]を[[十進数文字参照]]形式にしたものが代わりに挿入されます。 [SRC@en[>>66]] [86] [[Opera]] は以前は [CODE(MIME)@en[[[multipart/form-data]]]] 自体の [CODE(MIME)@en[[[Content-Type]]:]] 欄に [CODE(MIME)@en[[[charset]]]] [[引数]]を指定していましたが (>>2)、 互換性に難があったのか、現在はつけないようです。 他のブラウザも [CODE(MIME)@en[[[multipart/form-data]]]] 自体には [CODE(MIME)@en[[[boundary]]]] [[引数]]だけしか指定しません。 [SRC@en[>>66]] [1] [[WinIE]] も [[Mozilla]] も [[Opera]] も、 [CODE(MIME)[multipart/form-data]] に含まれる[[本体部分]]には [[charsetパラメーター]]を付けてくれません。 (ファイル送信を除いて [CODE(MIME)[[[Content-Type]]]] 欄そのものをつけません。) [2] Opera は、 [CODE(MIME)[multipart/form-data]] そのものに存在しない [CODE(MIME)[charset]] 引数をつけてきます。 この charset 値は実際にはそれに含まれる本体部分の[[実体本体]]及び [CODE(MIME)[[[Content-Disposition]]]] 欄の [CODE(MIME)[[[name]]]] 引数に適用されるようです。あ、 [CODE(MIME)[[[filename]]]] にもかな? 今度確かめてみよう。 [3] 規格不適合ながらもとりあえず >>2 のように情報を送ってくる Opera に対して、 WinIE と Mozilla は既定では何もしません。ただし、 [CODE(HTML)[[[_charset_]]]] hack を使えば一応は情報を得られます。 [4] >>2-3 の情報は、 [CODE(HTML)[[[file]]]] として送られる実体本体には適用できません。 (その実体の頭欄には適用されます。) [CODE(MIME)[charset=[[unknown-8bit]]]] とでも考えるしかなさそうです。問題は、 一般の form data と file を区別する確実な方法がないことです。 IE, Moz, Opera に限れば、 [CODE(MIME)[filename]] 引数の有無で決定できますが。。。 [5] >>4 あ、確実な方法が1つだけあります。受取る側が名前を知っていること。 これ超確実。 [88] [[HTML5]] や元の [[Web Forms 2.0]] は [CODE(MIME)@en[[[application/x-www-form-urlencoded]]]] や [CODE(MIME)@en[[[text/plain]]]] で[[提出]]する場合については [CODE(HTML)@en[[[_charset_]]]] hack を定義していますが、 [CODE(MIME)@en[[[multipart/form-data]]]] の処理は [[RFC 2388]] に丸投げしているので、 [CODE(HTML)@en[[[_charset_]]]] hack は正式にはどこでも定義されていません。 [87] [[Safari]] 以外のブラウザは [CODE(HTML)@en[[[_charset_]]]] hack に対応しています。 [SRC@en[>>66]] [[#comment]] * 関連 [93] [[WAP]] により規定された [CODE(MIME)@en[[[multipart/form-data]]]] に相当する[[バイナリー]]表現として、 [CODE(MIME)@en[[[application/vnd.wap.multipart.form-data]]]] [[媒体型]]があります。 ** HTML と [CODE(MIME)[multipart/form-data]] [6] HTML のフォームでは [CODE(MIME)[[[application/x-www-form-urlencoded]]]] もよく使われていますが、任意のバイナリ・データや非 ASCII 文字を効率よく確実に扱うことができないという問題があります。 バイナリ・データや非 ASCII 文字を含むフォームの提出では、 [CODE(MIME)[multipart/form-data]] を使うべきです [SRC[HTML 4 17.13.4.2]]。 ファイル選択制御子 ([[[CODE(HTMLe)[input]]/[CODE(HTML)[file]]]]) を使う時には、 [CODE(MIME)[multipart/form-data]] を [CODE(HTMLe)[form]] の [CODE(HTMLa)[enctype]] で指定するべきです [SRC[HTML 4 17.3, 17.13.4.2]]。 [35] HTML のフォームで [CODE(MIME)[multipart/form-data]] で提出させたい時は、 [CODE(HTMLe)[[[form]]]] 要素の [CODE(HTMLa)[[[enctype]]]] 属性に [CODE(MIME)[multipart/form-data]] と指定しておきます。 各本体部分の文字符号化方式の決定には、 [CODE(HTMLe)[form]] 要素の [CODE(HTMLa)[[[accept-charset]]]] 属性の指定を参照します。 [[#comment]] ** 転送プロトコルと [CODE(MIME)[multipart/form-data]] [54] [[MIME]] の規定によれば、 [CODE(MIME)[[[multipart/[VAR[*]]]]]] のすべての[[実体]]の [CODE(MIME)[[[Content-Transfer-Encoding]]]] は [CODE(MIME)[[[7bit]]]], [CODE(MIME)[[[8bit]]]], [CODE(MIME)[[[binary]]]] のいずれかでなければなりません。もちろん [CODE(MIME)[multipart/form-data]] の実体にも適用されます。 注意: [CODE(MIME)[multipart/form-data]] の''中''の[[本体部分]]についての規定では''ありません''。 本体部分の [ABBR[CTE]] については >>53 を参照して下さい。 [55] [[HTTP]] では [CODE(MIME)[Content-Transfer-Encoding]] を使用しません (常に [CODE(MIME)[binary]] 相当です) が、 [CODE(HTTP)[[[Content-Encoding]]]] と [CODE(HTTP)[[[Transfer-Encoding]]]] があります。 [CODE(HTTP)[Transfer-Encoding]] は媒体型に依存しませんので、 [CODE(MIME)[multipart/form-data]] であろうがそうでなかろうが常に使用できます。 [CODE(HTTP)[Content-Encoding]] が使用できるのかどうかは微妙なところですが、 特別規定がないのですから、使用できるのでしょう。但し、 それに対応している実装 (クライアント・鯖) がどれだけあるのかは微妙なところです。 [56] [CODE(MIME)[[[Content-MD5]]]] による簡易的な整合性情報は、 MIME では [CODE(MIME)[multipart/[VAR[*]]]] に対して使用することが認められて''いません''が、 HTTP では認められています。 [CODE(MIME)[multipart/form-data]] についても例外ではありません。 しかし、 [CODE(MIME)[multipart/form-data]] 全体の [[MD5]] ハッシュを計算するよりは、面倒でも個々の本体部分で計算した方が良いでしょう。 もし HTTP で提出された [CODE(MIME)[multipart/form-data]] が途中で MIME に変換されて [WEAK[(例えば電子メイルで)]] 送られるとすると困ったことになります。 ;; [64] そんなことあるのか知りませんがw [[#comment]] ** その他 [[#comment]] * 保安性 [50] [CODE(MIME)[multipart/form-data]] を構成するプロトコル要素や[[フォーム]]の仕組み自体には、 様々な安全上の問題があることが知られています。 例えば、利用者の意図しない状態や利用者が十分な考慮を行えない状況で自動的・ 半自動的にフォームを提出させると、 利用者の私的な情報や利用者の環境の安全に関わる情報が送信されてしまう虞があります。 このほかにも、フォームの提出という仕組みそのものに起因する問題が多く見つかっています。 また、ファイルを提出する際には [CODE(MIME)[filename]] 引数を使うことができますが、フォーム処理エージェント ([CODE(MIME)[multipart/form-data]] を処理する側) が信頼して無防備に実際のファイル名等として使用すると、 既存の別のファイルやシステム・ファイルを上書きしたり、 その環境で扱えないファイル名のファイルが中途半端にできてしまったりする虞があります。 詳しくは [CODE(MIME)[[[filename]]]] 引数の説明をご覧ください。 このようなフォーム自体や [CODE(MIME)[multipart/form-data]] が利用しているプロトコル要素に関する問題や、 特定の実装に依存した問題を除いては、 [CODE(MIME)[multipart/form-data]] に関する安全上の問題は見つかっていません。 [57] 提出の途中での改竄を検出する簡易的な手段として [CODE(MIME)[[[Content-MD5]]]] が使用できます (>>56)。 但し記述された [CODE(MIME)[Content-MD5]] 値自体が改竄されることもあり得ますから、 あくまで簡易的なものです。また、 実装している[[利用者エージェント]]は現時点で存在しないと思われます。 [58] 一般の MIME の実体の安全のための仕組みとして[[署名]]のための [CODE(MIME)[[[multipart/signed]]]] や[[暗号化]]のための [CODE(MIME)[[[multipart/encrypted]]]] が、 それを使った実際のシステムとして [[PGP/MIME]] や [[S/MIME]] があります。しかし、現実に [CODE(MIME)[multipart/form-data]] と組合せて使っている (使える) 例は聞いたことがありません。 [CODE(MIME)[multipart/form-data]] のどの部分を署名・暗号化するのか (あるいは全体をするのか) や、フォームの提出の手続きの中でどのように処理するのかなどの詳細な標準化がなされないと (または[[デファクト標準]]が登場しないと) 使用するのは難しいでしょう。 [59] 現実にフォームの提出の安全のために使用されているのは [[TLS]] や [[SSL]] です。 [[HTTP]] に対応した利用者エージェントや鯖では大抵 TLS over HTTP ([[HTTPS]]) が利用できるので、 [[フォーム処理エージェント]]としては特別な処理が要らないのが普通です。 但し、 HTTP 以外の提出方法 (特に電子メイル) にはこの方法は使えません。 [[#comment]] * 処理モデル [10] HTML 4 UA は、 [CODE(MIME)[multipart/form-data]] によるフォームの提出を実装しなければなりません [SRC[HTML 4 17.13.4]]。 [[#comment]] * VoiceXML [99] [[VoiceXML]] [[解釈器]]は [CODE(MIME)@en[[[multipart/form-data]]]] に対応することが義務付けられています [SRC@en[[[VoiceXML 2.1]]]]。 * XForms での利用 [96] [[XForms]] でも、「互換性のため」としながらも [CODE(MIME)@en[[[multipart/form-data]]]] を使うことができます。ただし、 [[XForms]] のモデル上のすべての情報を含められるわけではなく、 例えば[[属性節点]]に相当する情報は欠落します。 [[XForms]] は注記として、既存の [[HTML]] [[利用者エージェント]]は[[非ASCII文字]]等の扱いが芳しくないことを指摘しています。 それとどう関係があるのか知りませんが (だからきちんと処理するよう指導しているわけでもありません)、 [CODE(MIME)@en[[[multipart/related]]]] や [CODE(MIME)@en[[[application/xml]]]] を使うことを勧めています。 * WSDL での利用 [97] [[WSDL]] でも、 「[[XForms]] との互換性のため」として [CODE(MIME)@en[[[multipart/form-data]]]] を使うことができます。 * 歴史 [95] [[HTML4]] は[[フォーム]]で[[非ASCII文字]]が[[提出]]される可能性がある場合に [CODE(MIME)@en[[[application/x-www-form-urlencoded]]]] の代わりに [CODE(MIME)@en[[[multipart/form-data]]]] を使うことを勧めていましたが、 世間からは完全に無視されています。 [98] [[device-upload]] では、[[音声]]等の新しい[[ファイル]]の[[うp]]の方法に適用するための [CODE(MIME)@en[[[device]]]] などの [CODE(MIME)@en[[[Content-Disposition]]:]] [[引数]]を提案し、 その指定方法を規定していました。 * 実装 [15] WinIE 3.02 用の file upload add-on は1997年の中ごろに出ました。 [36] 現代のほとんどの [[WWWブラウザ]]は [CODE(MIME)[multipart/form-data]] によるフォームの提出を実装しています。 [37] 一方、 [[CGIスクリプト]]などの鯖側は酷い状況です。 多くの実装は相手にもしていません。 [[Perl]] なら [CODE(file)[[[CGI.pm]]]] などを使えば自動的に対応できますが、[WEAK[最近は増えてきたとはいえ]]モジュールを CGI スクリプトで使うことは少なく、 [CODE(MIME)[application/x-www-form-urlencoded]] にしか対応していません。ファイルのうpがしたくなったら (素直にモジュールを使えばいいのに) 見よう見まねで適当に対処しようとして、 結局特定ブラウザの特定の版でしか上手く動かないようなコードを書いてみたり。 [WEAK[(で、質問掲示板で暴れてみたり。)]] お前らちゃんと仕様書読んでくださいよ。 処理系で標準または標準に近いモジュール的なものが[[要求]]の解析をしてくれることが広く知られていて、 そのモジュール的なものの作者がちゃんと仕様を読んでコードを書くような人なら、 その処理系で書かれた処理はさほど深く考えなくても自動的に [CODE(MIME)[multipart/form-data]] を正しく処理できるはずです。 [WEAK[よく知りませんけど、 Java servelet とか PHP はその辺きちんとしてるのではないですか?]] [66] [[Firefox]] 3.0.4、[[Opera]] 9.61、[[Safari]] 3.2、[[WinIE 7]] の実装状況を調べてみました。 [94] [CITE@ja[enctype="multipart/form-data"で携帯からファイルアップロード « 携帯・モバイル « プログラム « Re:]] ([[kronekodow]] 著, [TIME[2008-11-25 17:16:30 +09:00]] 版) >SoftBankが素敵に思えた。 >データフォルダから直アップできるんですね。 >fileup_auauは(W52SHは)Browse...ってボタンは出るものの反応しない。 >DoCoMoはボタンすら出ない。 >SoftBankでも、C端末、3GC端末などによる違など全てじゃなかったり、auも一部端末なら出来たり?(HTMLやXHTMLの違いなども関係したり)とか、可能な端末の振り分けは大変そうです。 ** 複数ファイルをまとめて提出 [13] 1つのファイル選択制御子 ([[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]]) を使って複数ファイルをうpする (>>51) のは、 [[UA]] で対応してるのはなさげ、 サーバーもおそらく全滅だろうという感じですね。 [[www-html]] で [[Opera]] の特定の版では出来るという未確認情報がありましたが、 最新版では出来ないらしいし、勘違いかなんかじゃないかなあ。 [67] その後 [[Opera]] 9 は [[Web Forms 2.0]] に対応しましたので、 複数ファイルの[[提出]]にも対応しています。 [CODE(HTML)@en[[[file]]]] [[制御子]]用の [CODE(HTMLa)@en[[[max]]]] [[属性]]は一旦 [[HTML5]] で削除されましたが、 [CODE(HTMLa)@en[[[multiple]]]] [[属性]]が改めて追加される予定ですから、 いずれ他のブラウザも複数ファイルの[[提出]]に対応すると期待されます。 [[#comment]] * 試験事例 [90] [CITE[Index of /~wakaba/-temp/test/html/form/multipart-form-data]] ([TIME[2008-11-25 16:03:16 +09:00]] 版) * 例 [39] HTML のフォームの例 [SRC[HTML 4 17.13.4.2、改]] [PRE(HTML)[

What is your name?
What files are you sending?

]PRE] このフォームで、文章入力欄に [SAMP[Larry]] と記入し、ファイル選択で [SAMP(file)[file1.txt]] を指定して提出した場合 [SRC[HTML 4 17.13.4.2, 改]]: [PRE(MIME)[ 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 '''''' [VAR[... contents of file1.txt ...]] --AaB03x-- ]PRE] 更に [SAMP(file)[file2.gif]] も選択していた場合 [SRC[HTML 4 17.13.4.2, 改]]: [PRE(MIME)[ 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: [DEL[file]] [INS[attachment]]; filename="file1.txt" Content-Type: text/plain '''''' [VAR[... contents of file1.txt ...]] --BbC04y Content-Disposition: [DEL[file]] [INS[attachment]]; filename="file2.gif" Content-Type: image/gif Content-Transfer-Encoding: binary '''''' [VAR[...contents of file2.gif...]] --BbC04y-- --AaB03x-- ]PRE] [47] ユーロ通貨記号を値に使った例 [SRC[RFC 2388 4.5、改]] [PRE(HTML)[ 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-- ]PRE] [[#comment]] * Q & A [63] '''Q: HTML でファイルをアップロードするにはどうしたらいいですか? ファイル名しか取得できません...''' A: ファイル名しか取得できないのは、 [CODE(MIME)[[[application/x-www-form-urlencoded]]]] を使用しているからの可能性が高いと考えられます。 フォームの提出で [CODE(MIME)[[[multipart/form-data]]]] を使うようにしましょう。 関連: >>61, [[[CODE(HTMLe)[input]]//[CODE(HTML)[file]]]], [[提出]] [61] '''Q: HTML によるフォームの提出でブラウザに [CODE(MIME)[multipart/form-data]] で送ってもらうにはどうしたらいいですか?''' A: [CODE(HTMLe)[[[form]]]] 要素の [CODE(HTMLa)[[[enctype]]]] 属性を [CODE(MIME)[[[multipart/form-data]]]] と指定してください。 ついでに、 [CODE(HTMLa)[[[accept-charset]]]] 属性に希望する[[文字コード]]も指定しておきましょう。 [CODE(HTMLa)[[[method]]]] 属性を [CODE(HTML)[[[post]]]] にしておくのを忘れないように。 関連: [CODE(HTMLe)[[[form]]]], [CODE(HTMLa)[[[enctype]]]], [[提出]] [62] '''Q: CGI スクリプトで [CODE(MIME)[multipart/form-data]] と [CODE(MIME)[application/x-www-form-urlencoded]] を見分けるにはどうしたらいいですか?''' A: [[CGI]] には [CODE(CGI)[[[CONTENT_TYPE]]]] という[[メタ変数]] ([[環境変数]]) があります。その値で判別できます。 [CODE(CGI)[CONTENT_TYPE]] の値の先頭の19文字が [CODE(MIME)[multipart/form-data]] [WEAK[(大文字・小文字の区別なし)]] で、その次の文字が存在しないか、[[空白]] ([[間隔]]、 [[タブ]]、[[改行]]) か、[[セミコロン]] ([CODE(MIME)[;]]) なら、 [CODE(MIME)[multipart/form-data]] が使われています。 [CODE(CGI)[CONTENT_TYPE}] の値の先頭35文字が]] [CODE(MIME)[application/x-www-form-urlencoded]] [WEAK[(大文字・小文字の区別なし)]] で、その次の文字が存在しないか、[[空白]] ([[間隔]]、 [[タブ]]、[[改行]]) か、[[セミコロン]] ([CODE(MIME)[;]]) なら、 [CODE(MIME)[application/x-www-form-urlencoded]] が使われています。 それ以外なら、未知の何かが使われています。 関連: [CODE(MIME)[[[Content-Type]]]], [CODE(CGI)[[[CONTENT_TYPE]]]] [[#comment]] * メモ