フォームデータの送信
ブラウザからのデータデータは、特別な形式でエンコードされて送信されることになっています。画面に表示されるフォームのコントロールで入力する以外にも、隠されたデータの情報を送ったり、フォームを使わずに送信するなど、いくつかの方法があります。
目次:
作者の設定したデータを送る
input要素などで用意する「コントロール」はユーザーがそれを操作してデータを入力するためのものです。しかし、場合によってはHTMLの制作者が指定したデータをプログラムに送信したい場合もあるでしょう。このようなデータはユーザーが操作する必要はなく、ユーザーの目に触れないほうが都合がよいものです。そのために、input要素のタイプの一つとしてhidden型が用意されています。
(例)<input type="hidden
" name="info" value="secret" />
このような情報をフォームに書きこんでおくと、ユーザーの目に触れることなく「info」という名前と「secret」という値を持ったデータがプログラムに送信されます。汎用のプログラムに特定の動作をさせたい場合などに使います。
読みとり専用コントロール
作者指定のデータが必要でも、それをユーザーから隠さず、きちんと表示しておく方が望まし場合もあるでしょう。そのためHTML 4.0では、input要素、textarea要素にreadonly属性を設定して、データを表示しつつユーザーによる変更を禁止できるようになりました。
(記述例)<input type="text" readonly="readonly"
name="info" value="読みとり専用です" />
このようにして用意したコントロールは、普通のコントロールと同様に表示されますが、内容を編集することができません。
ただしHTML 4.0に対応していないブラウザだと編集できてしまうので、作者の設定したデータを固定して送信したい場合は、hidden型のinput要素を使う方がよいでしょう。
データ送信とURLエンコード
フォームのコントロールを通して入力されたデータは、送信命令(submit型のinput要素)によってサーバーに送られます。そのとき、英数字以外のデータは利用者が入力したそのままの形ではなく、%と数字やアルファベットで構成されたURLエンコード形式という形に変換され、およそ次のようなイメージになります。
(URLエンコードされたデータの例)%8FZ%8F%8A=
Tokyo&
%8E%81%96%BC=
Masahide+Kanzaki
URLエンコードは、フォームで入力されたデータを次のように変換します:
- それぞれのデータ(文字列)の中で、スペース文字を
+
に変換 - さらに英数字と一部記号以外のものを
%
とその文字を表す2桁の16進数
に変換 - 変数名(name)と内容(value)を
=
で結ぶ - 各項目のデータを
&
で連結する
上記の例は、「住所」という変数名に対し「Tokyo」という値、「氏名」という変数名に対し「Masahide Kanzaki」という値がデータとして送信されたものです。
フォームから直接メール送信
form要素のaction属性でプログラムの代わりにmailto:
型のURIを指定すると、フォームの内容を直接メール送信させることができます。
(記述例)
<form method="post" action="mailto:
メールアドレス?Subject=Page_enquete">
<p>ごく簡単なHTMLは
<input type="radio" name="this_page_is"
value="useful" checked="checked" /> とても役に立つ
<input type="radio" name="this_page_is"
value="not_very_useful" /> そうでもない</p>
<p><input type="submit" value="ご意見を送信" /></p>
</form>
このフォームを使うと、利用者がラジオボタンで選択した結果がURLエンコードされ、actionで示したメールアドレスに送信されます。アドレスのあとに ? に続けてSubject=...と記述することで、メールの件名が設定できます(対応しないブラウザもあるかも知れません。mailtoの記述方法についてはRFC 2368に定められています)。
(表示例)
この方法で送信したメールは、フォームの内容に日本語が含まれているとURLエンコードされて届くので、もとの日本語にデコードするツールが必要になります(Subjectには日本語を直接指定できません)。テキスト型inputやtextareaを使って文字を入力するフォームは、扱いにくいでしょう。
〔補足〕
mailtoのようなHTTP以外のURIに対する挙動はHTML 4.01仕様書17.3 actionの定義においてundefinedとされているので、100%働く保証はありません。文字のエンコード以外に、次のような問題が考えられます。
- ブラウザによってはそもそもこの方法をサポートしていないことがある
- ブラウザの初期設定でメールサーバーを指定していないと送信できない
- 送信してもページが更新されないので、利用者は何かエラーが生じたと思い、何度も送信してしまう可能性がある(適切な説明が必要)
- ブラウザによっては、セキュリティの警告が出されることもある
CGIを必要としない手軽な方法なので、フォームの練習や「訪問記念」ボタンには手頃ですが、本格的なデータ送信にはあまり適さないでしょう。
〔以上補足〕
エンコードのタイプとファイル送信
input要素のtype属性をfileとすると、ファイルを選択するためのコントロールを用意することができます。このタイプを用いて、ファイルの中身をフォームのデータとして送信することができます。
ファイルの中身はバイナリファイルだったりテキストでもサイズが大きかったりするので、通常のURLエンコードでの送信は無理があります。この場合は、form要素のenctype属性をmultipart/form-dataに設定し、MIMEのマルチパートデータとしてファイルやその他の項目の内容を送ります。。
(例)
<form action="ファイル処理CGIのURI"
method="post" enctype="multipart/form-data"
>
...
氏名 :<input type="text" name="username" />
送信ファイル:<input type="file" name="submitfile" />
...
</form>
このエンコードで送られたフォームのデータは、URLエンコードではなく、次のようなMIMEのマルチパートデータとしてプログラムに届きます。
(送信データ例)
Content-Type: multipart/form-data; boundary=-AabbZ ---AabbZ Content-Disposition: form-data; name="username" Masahide Kanzaki ---AabbZ Content-Disposition: form-data; name="submitfile"; filename="myfile.txt" Content-Type: text/plain This is a sample file.... (ファイルの中身) ---AabbZ--
マルチパートのデータは、この例のように「境界(boundary)」となる行でデータ項目が区切られ、それぞれがContent-Dispositionという説明情報などのあとに実際のデータが続くという形を取ります。処理方法の詳細はここでは取り上げませんが、このようにするとユーザーにオンラインで情報を入力してもらわなくても、あらかじめ必要事項を書き込んだファイルを用意してもらい、それをアップロードしてもらうという手段が提供できます(MIMEのマルチパートの詳細についてはRFC 2045を参照)。
上記例の1行目でboundary=---AabbZ
と記述していましたが、ここで定義した境界線を使うときにその前に--
を加えるのがMIMEの規則なので、定義行ではboundary=-AabbZ
でなければなりません。お詫びして訂正します。
〔補足〕
このエンコードをmailtoアクションと組み合わせると、MIMEの添付ファイルの形式でフォームの内容をメール送信できることもあります。うまく機能すれば、CGIを使わなくても日本語を記述したフォームをメール送信させられそうですが、期待通りに働くかどうかはブラウザ次第で、文字化けする可能性もあります。
なお、URLエンコード形式のエンコードタイプはapplication/x-www-form-urlencodedとなります。通常はあえて指定する必要はありません。
〔以上補足〕
GETメソッドとPOSTメソッド
前章では、form要素のmethod属性でpostもしくはgetを指定することを簡単に述べました。postメソッドの場合は、ブラウザはサーバーに接続して、URLエンコードした内容をプログラムに渡すように要求します。getメソッドを使うと、プログラムを呼び出すURLの後ろに、URLエンコードしたデータ(クエリ)を?
でつないでサーバーに送信します。たとえばaction属性で /cgi-bin/htm-form
を指定しているとき、getメソッドは次のような形でデータを送ります。
(送信データ例)/cgi-bin/htm-form?
address=Tokyo
つまりgetを使うとデータはURLの一部として送られるわけです。「URLエンコード」とは、データをURLに埋め込んでも問題が生じないように、英数字以外の文字や/などの記号を安全な形に変換することを意味します。サーバーは受け取ったURLを ? を境に分割し、その前半に示されているプログラムを呼び出して、後半の値(フォームの内容=クエリ)を処理データとして渡します。
HTTPのメソッド
(注)この節は技術的な詳細を説明するので、読み飛ばしても差し支えありません
POST, GETはフォーム送信だけのものではなく、ブラウザがサーバーに対して要求を送る(HTTPリクエスト)ときの一般的なメソッドです。通常、リンクを辿ったりアドレス欄にURLを入力したりしてHTMLページを呼び出すとき、ブラウザはGETを使ってサーバーにファイルを要求しています。例えば、/index.htmlというファイルを開く場合は
(例)GET /index.html HTTP/1.0
というリクエストを送信します。フォームのgetメソッドを使っても同様のリクエストで、/index.htmlの代わりにプログラムのURLとデータが送られます。
(例)GET /cgi-bin/htm-form?address=Tokyo HTTP/1.0
POSTの場合は、このリクエスト行にはデータの内容は書き込まれず、これに続く本体(エンティティ)にデータが入って送信されます。
(例)
POST /cgi-bin/htm-form HTTP/1.0 ... address=Tokyo
postメソッドはメッセージの投稿、データベースへのデータの追加などを処理する方法として用意されており、必ずしもHTMLファイルのような情報を取り出すことを目的としていません。
※フォームのpost,getメソッドは大小文字を区別せず、ここでは他のタグの記述と合わせて小文字にしていますが、HTTPリクエストでは大文字を使います。
GETとPOSTの使い分け
getメソッドとpostメソッドは次のような考え方で使い分けます。
- getはその名の通り、何かをゲットする(取り出す)のが本来の役割です。データベースにキーワードを送って検索結果を「取り出す」などのためにgetを用います。
- getを使った場合、その結果はクライアントのディスクにキャッシュされ、次回以降はそのキャッシュの内容を利用することが期待されているので、(少なくとも短期的には)同じクエリによるリクエストに対しては同じ結果を返さなければなりません。また、getはクエリがURIの一部になるため、それがそのままブックマークされたり、リンク先として用いられたりする可能性もあります。
- postは「投稿する」を意味します。メッセージの書き込み、新規データの登録など、何かをプログラムに送って内容を書き換えるような場合はpostを使わなければなりません。
- getのクエリはサーバーの環境変数を経由してCGIに渡されるので、非常に長いデータを送るのには向きません。上限はサーバーによって違いがありますが、せいぜい数KB程度なので、texarea要素などで長いテキストを入力する場合はpostが適切です(一般的には、このようなケースはデータの登録であり、postの本来の定義に合致する使い方になるでしょう)。
- getの場合はクエリの内容がURIの一部としてブラウザのアドレス欄などにも表示されたり、サーバーのログファイルに記録されたりします。プライバシーの保護上、postのほうが望ましい場合があるかもしれません(たとえばinput要素のtypeをpasswordとしているのに、getメソッドを使ってURIにその内容が残るのはまずいかも)。
検索などの常に一定の結果を伴うものはget、新しいデータの送信・登録はpostというのが原則です。
GETを使って直接データを送る
getメソッドがURLの一部になることを応用すると、フォームを用いずにデータを直接CGIプログラムに送信することができます。たとえば、kwという名前で送ったデータをキーワードにデータベースを検索するプログラムdbase.cgiがあるとすると
(例)この手順を<a href="/cgi-bin/dbase.cgi?kw=CGI
">CGI</a>と呼びます
という形のアンカーを用意することで、用語をクリックするとその説明をデータベースで検索して表示するような仕掛けを提供できます。
なお、この方法で複数の項目を送信するためのHTMLを記述する場合、項目を連結する&はそのまま記述するのではなく、&
という形で文字参照を用いなければならないことに注意してください。