form

1. 基本情報

説明 フォームを示す
語源 FORM
所属モジュール Forms
所属コンテントセット Form
内容 Heading, Block-form, List
内容の書式 ( Heading | Block-form | List )+
関連項目 なし
公式な実装 DTD

2. 属性

2-1. 一般属性

属性 属性値の型 説明
Common [属性コレクション]

XHTMLの要素が大抵持っている、一般的な属性を集めたコレクションです。

2-2. 固有属性

属性 属性値の型 説明
action [必須] URI (CDATA)

フォームから送られたデータを処理するプログラムのURIを指定します。

method [選択]

action属性で指定したプログラムにデータを送る時のHTTPメソッドを指定します。

  • get [既定値] - GETメソッドを使います。
  • post - POSTメソッドを使います。
enctype ContentType (CDATA)

method属性がpostの時に、action属性で指定したプログラムへデータを渡す時に用いるコンテントタイプを指定します。

accept ContentTypes (CDATA)

action属性で指定したプログラムが処理可能なコンテントタイプを指定します。

accept-charset Charsets (CDATA)

action属性で指定したプログラムが処理可能な文字エンコーディングを指定します。

onsubmit Script (CDATA)

フォームのサブミットボタンが押された時に実行するスクリプトを記述します。

onreset Script (CDATA)

フォームのリセットボタンが押された時に実行するスクリプトを記述します。

3. 解説

3-1. 概要

form要素は、フォーム (Form)を作ります。フォームというのは、大雑把に言って、閲覧者に何らかの情報を入力させ、サーバのプログラムに送信させる時のユーザーインターフェースです。例えば、掲示板の書き込みの際、名前や記事の内容を記入する部分もフォームとその部品で構成されていますし、オンラインショッピングサイトで、名前や住所、クレジットカード番号などを入力させるのもフォームを使って実現されています。

3-2. コントロール

フォームを構成する各部品、例えば単一行のテキスト入力欄や、有効・無効を切り替えられるチェック欄、押す事でデータが送信されるボタンなどの部品は、コントロール (Control)と呼ばれます。各コントロールに入力された値、あるいは選択された値は、その入力値を識別する「名前」(name属性で記述)と共に、指定されたプログラムに送られます。つまり、ユーザはコントロールを通してプログラムと対話する訳です。

3-3. 使用可能なコントロール

フォームで使用可能なコントロールは、次の通りです。

タイプ 説明
プッシュボタン(Buttons)

選択された時(フォーカスを得て押された時)、何らかの処理を行うものです。ボタンには3つの種類があります。

送信ボタン(Submit Buttons)

選択時にフォームのデータを送信します。送信ボタンは、一つのフォームに複数存在する事ができます。

リセットボタン(Reset Buttons)

選択時にフォームのデータを初期化します。

ただのプッシュボタン(Push Buttons)

規定の動作は無く、イベントを発生させる為に使われます。Intrinsic Eventsモジュールを参照して下さい。

プッシュボタンは、button要素input要素で作ります。前者の方が表現力が豊かで、できればbutton要素を使う事をお勧めしますが、ユーザーエージェントの対応が今一良くないかも知れません。

チェックボックス(Checkboxes)

チェックボックスは、オンとオフの二つの状態を持つ、ボタンの一種です。選択する事で状態をトグルさせる事ができます。

同じ名前を持つ複数のチェックボックスを作る事ができます。この場合、同じ名前を持つデータが複数送られてくる可能性があります。

チェックボックスを作るには、type属性がcheckboxであるinput要素を使います。

ラジオボタン(Radio Buttons)

ラジオボタンも、オンとオフの二つの状態を持つボタンです。選択する事でオンにする事ができます。チェックボックスとの決定的な違いは、同じ名前を持つ複数のラジオボタンの内、オンにできるのはただ一つという事です。ある一つのラジオボタンをオンにすれば、同じ名前を持つ他のラジオボタンは全てオフになります。従って、同じ名前を持つデータが複数送られる事はありません。

ラジオボタンを作るには、type属性がradioであるinput要素を使います。

メニュー(Menus)

メニューは、複数の選択肢の中から一つを選ばせるコントロールです。その役割ではラジオボタンに似ていますが、ユーザに表示される形態では異なっています。

メニューを作るにはselect要素を使います。size属性multiple属性を使えば、一つだけでなく複数の選択肢を選ばせる事も可能です。

テキストボックス(Text Input)

テキストボックスは、一行あるいは複数行のテキスト入力欄です。ユーザはキーボードなどを使って、任意の文字列をプログラムに渡す事ができます。

単一行テキストボックスを作るには、type属性がtextあるいはpasswordであるinput要素を、複数行テキストボックスを作るにはtextarea要素を使います。

ファイル選択欄(File Select)

ファイル選択欄は、指定されたファイルの内容をプログラムに送信する為のテキスト入力欄です。直接内容を記入するのではなく、ファイルの内容をユーザーエージェントが読み取ってアップロードしてくれる為、省力化もでき、バイナリデータもスマートに送れます。

ファイル選択欄を作るには、type属性がfileであるinput要素を使います。

隠しコントロール(Hidden Controls)

隠しコントロールは、ユーザの目には見えないけれども、フォームの送信時には他のコントロールと一緒に送信されます。主に、入力を複数ページに分けて行わせるプログラムや、前回の入力結果を元に新しいページを作るプログラムが使用します。

隠しコントロールを作るには、type属性がhiddenであるinput要素を使います。

オブジェクトコントロール(Object Controls)

汎用オブジェクトは、object要素から受け取るデータをそのまま送信するコントロールです。どのようなデータが送られるかは、データの種類によります。

オブジェクトコントロールを作るには、name属性を持つobject要素を使います。

3-4. Windowsとのコントロール対応表

Windowsでの呼称しか知らないのですが、対応表を載せておきます。

Windowsでの呼称 対応するコントロール
ラベル(スタティックテキスト)
テキストボックス(単一行)
テキストボックス(単一行パスワード)
テキストボックス(複数行)
プッシュボタン
チェックボックス
ラジオボタン
リストボックス
コンボボックス(通常、ドロップダウン)
  • なし
コンボボックス(ドロップダウンリスト)
グループボックス
その他
  • なし

3-5. formの役割

form要素の主な役割は、これらのコントロールのコンテナになる事です。form要素の子孫であるコントロールの名前と値は、送信時にenctype属性のエンコード方法を使い、method属性に則って、action属性のプログラムにまとめて送信されます。

form要素自体は表示上の制約を与えません。そこで、実際にフォームを作る場合は、div要素p要素fieldset要素などを使って体裁を整えたり、意味付け(グループ化)を行う事になります。

3-6. フォームの送信

3-6-1. メソッド

フォームの内容を送信するには、大きく分けて二つの方法があります。HTTPのGETメソッドを使う方法と、POSTメソッドを使う方法です。これらのメソッドは、フォームの送信の目的によって適宜使い分けます。詳しくはmethod属性を参照して下さい。

3-6-2. サクセスフルコントロール

サクセスフルコントロール (Successful Control)という呼び方は奇妙に聞こえますが、要はフォームの送信ボタンが押された時に、名前と値のペアが送信されるコントロールの事です。例えば:

  • チェックボックスでは、オンになっているチェックボタン全てがサクセスフルになり、ラジオボタンの場合、オンになっているラジオボタンはサクセスフルですが、同じ名前を持つ他の(オフになっている)ラジオボタンは非サクセスフルです。
  • 送信ボタンは、選択されたもののみがサクセスフルです。複数あった場合、押されなかった送信ボタンは非サクセスフルです。
  • 何か入力されているテキストボックスは常にサクセスフルですが、テキストボックスに限らず、何も入力されていないものは非サクセスフルになるかもしれません(ユーザーエージェントの実装に依存します)。
  • 隠しコントロールもサクセスフルです。また、CSSでdisplay : none;、あるいはvisibility : hidden;とされているようなコントロールもサクセスフルです。
  • declare属性を持つobject要素は非サクセスフルです。
  • disabled属性を持つコントロールは常に非サクセスフルです。readonly属性を持つ場合は、サクセスフルにもなり得ます。
  • name属性を持たないコントロールは全て非サクセスフルです。
  • どのform要素の子孫でもないコントロールは常に非サクセスフルです。

3-6-3. フォームの内容の整形

フォームの内容として送るべきデータを、action属性のプログラムに渡せるように整形するまでに、ユーザーエージェントは以下の手順を踏みます。

1. サクセスフルコントロールの特定

送信するフォームのform要素の子孫であるコントロールを調べ、その中でサクセスフルコントロールのみを拾い上げます。

2. データセットの作成

全てのサクセスフルコントロールについて、コントロールの名前と値をペアにします。

3. データセットのエンコード

enctype属性で指定されたエンコード方法を用いて、データセットを実際に送られる形にします。この値は大抵application/x-www-form-urlencodedですが、ファイルのアップロードをする場合などはmultipart/form-dataになります。

4. エンコードされたデータセットの送信

エンコード済みのデータを、method属性で指定された方法でaction属性のプログラムに向けて送信します。

5. 応答の表示

整形とは関係無いですが、ユーザーエージェントは送信が終わった後、サーバからの応答──即ち、プログラムの標準出力を読み取って表示します。

メソッドやエンコード方法などについて、現存する全てのものがサポートされている事は殆ど無いでしょうが、HTML4に対応していると謳っている(まともな)ユーザーエージェントは、次の二つの状況をサポートしています。

  • method属性がgetで、action属性がHTTPのURIの時。この時はenctype属性に拘らずapplication/x-www-form-urlencodedが使われ、プログラムのURIの後に、'?'を区切り文字としてエンコード済みのデータセットを続けます。プログラムは、このデータをクエリ文字列から取得できます。例えば、Perlなら環境変数$ENV{"QUERY_STRING"}(文字列)でエンコード済みのデータセットを取得できますし、PHPならスーパーグローバル$_GET(連想配列)に、デコードされ、しかもペアごとに分けられた状態で取得できます。
  • method属性がpostで、action属性がHTTPのURIの時enctype属性のエンコード方法に基づいてデータセットをエンコードし、メッセージボディとして送信します。プログラムは、このデータを標準入力から取得できます。Perlならread( STDIN, $messageBody, $ENV{"CONTENT_LENGTH"} );$messageBody(文字列)に読み取れますが、PHPの場合はこれもスーパーグローバル$_POST(連想配列)に、デコードされ、しかもペアごとに分けられた状態で取得できます。

3-7. フォーム用エンコード方法

データセットをエンコードする時に使われる規則は、ContentTypeデータタイプとしてenctype属性で指定します。現存する全てのエンコード方法がサポートされているなんて事は無いでしょうが、次の二つは(まともなユーザーエージェントなら)必ずサポートされています。

3-7-1. URLエンコード

URLエンコードは、コンテントタイプapplication/x-www-form-urlencodedで識別されるエンコード方法です。GETメソッドを使う場合は常にこの方法が使われ、POSTメソッドを使う場合でも大抵はこれが使われます(enctype属性の既定値です)。

URLエンコードを使う場合、ユーザーエージェントはまず、コントロールの名前とその値をエスケープ (使ってはまずい、あるいは使えない文字を使っても良い文字の組み合わせで表現する事)します。例えばスペースは'+'で、その他の使用不可の文字はパーセントエンコード (Percent Encode)されて'%'+'HH'(2桁の16進数)で表されます。例えば、改行はキャリッジリターン (Carriage Return、CR)ラインフィード (Line Feed、LF)の組(CR+LFと短縮される)で表されますが、これは%0D%0Aになります。また、テキストボックスに~x means a bitwise NOT, or a ones' complement.と入力された場合、これは%7Ex+means+a+bitwise+NOT%2C+or+a+ones%27+complement.とエンコードされます。

エンコードが終われば、ユーザーエージェントは、サクセスフルコントロールが文書中に現れた順番に、コントロールの名前と値をペアにします。名前と値は'='で分けられ、ペア同士は'&'で分けられます。例えば、次のようなフォームがあったとしましょう。

[プログラムコード開始]

<form action="http://www.example.com/search.cgi" method="get">
<div>Word : <input type="text" name="word" value="word"/></div>
<div>Description : <input type="text" name="description" value="description"/></div>
<div><button type="submit">Submit</button></div>
</form>

[プログラムコード終了]

ここで、Word欄に~x、Description欄にMeans a bitwise NOT, or a ones' complement.と入力し、Submitボタンを押します。すると、ユーザーエージェントは、HTTPのGETメソッドを使って、www.example.comサーバに

[出力例開始]

GET /search.cgi?word=%7Ex&description=Means+a+bitwise+NOT%2C+or+a+ones%27+complement.

[出力例終了]

とリクエストします。ちなみに、最後のbutton要素name属性が無い為、データセットは作られません(非サクセスフル)。

3-7-2. マルチパート

URLエンコードは、データ量が少ない場合には適切で、しかもGETメソッドならURIとして入力した情報を保存できる為、例えばGoogleの検索結果に対してリンクを張るという事が可能でした。しかし、ASCII文字でないものが多く存在する時、例えば一般のファイル、日本語の長い文字列などではやたらとデータが長くなってしまいます。こういう場合、multipart/form-dataで識別されるマルチパート方式を採用するべきでしょう。

POSTメソッドでmultipart/form-dataエンコードを使うと、エンコードされたデータセットはメッセージボディとして送られる事はフォームの内容の整形で触れましたが、そのメッセージボディの中でも、各サクセスフルコントロールごとに区分されて送られます。

例えば、次のフォームを、値を変えずにそのまま送信してみたとしましょう。

[プログラムコード開始]

<form action="/bbs/post.cgi" method="post" enctype="multipart/form-data">
<div>お名前 : <input type="text" name="writer-name" value="お名前をどうぞ"/></div>
<div>E-mail : <input type="text" name="e-mail" value="foo@bar.com"/></div>
<div>管理パスワード : <input type="password" name="password" value="pass"/></div>
<div><button type="submit">送信</button></div>
</form>

[プログラムコード終了]

これに対して、ユーザーエージェント、例えばMicrosoft Internet Exproler 6.0の場合、次のようなHTTPメッセージを送ります。

[出力例開始]

Content-Type: multipart/form-data; boundary=---------------------------7d636d1010340
 
-----------------------------7d636d1010340
Content-Disposition: form-data; name="writer-name"
 
お名前をどうぞ
-----------------------------7d636d1010340
Content-Disposition: form-data; name="e-mail"
 
foo@bar.com
-----------------------------7d636d1010340
Content-Disposition: form-data; name="password"
 
pass
-----------------------------7d636d1010340--

[出力例終了]

見て大体感じは掴めるかと思いますが、説明を加えていきましょう。

大量の'-'の後に16進数が並んでいる行は、パートバウンダリ (Part Boundaries)などと呼ばれるもので、サクセスフルコントロールを区切る為に使われます。このバウンダリは、Content-Typeヘッダで、Content-Type: multipart/form-data; boundary=---------------------------7d636d1010340のようにプログラムに渡されています。パートバウンダリは送信の度に変わりますし、ユーザーエージェントによって生成方法も違うので、必ず毎回Content-Typeヘッダを見る必要があります。ただ、送信されるデータの中にパートバウンダリが含まれる事は一切無い事が保証されています(ユーザーエージェントは、そうなるようにパートバウンダリを作り出します)。

よく数を数えてみると判りますが、Content-Typeヘッダで示されるバウンダリがそのまま使われている訳ではありません。サクセスフルコントロールの区切りには先頭に二つのハイフンが、データの終わりには先頭と末尾にそれぞれ二つのハイフンが付きます。これらによって、プログラムはサクセスフルコントロールごとにデータを分けて受け取る事ができます。

パートバウンダリによって分けられた各パートを見てみると、Content-Dispositionヘッダがあります。これは大抵Content-Disposition: form-data; name="コントロールの名前"の書式を持っています。ヘッダとデータ(コントロールの値)の間はCR+LF二つで分けられます(一行の空行ができる)。プログラムは次のバウンダリが現れるまでデータを読み取っていき、バウンダリが現れた所で最後のCR+LFを取り去ればコントロールの値が取得できる訳です。

コントロールの値に非ASCII文字が含まれる場合、何らかの手法でデータがエンコードされて送られる事があります。この時は、各パートのContent-Transfer-Encodingヘッダを見て、然るべき手法でデコードをしなければなりません。あるいは、エンコードされずに、Content-Typeヘッダが(HTTPメッセージのヘッダにではなく、各パートのヘッダに)付いている場合があります。この時は、charsetパラメータを見て内容を判断してやります。

フォームの中にファイル選択欄が含まれる場合、そのパートの中身はファイルの内容になります。例えば、次のフォームを考えます。

[プログラムコード開始]

<form action="/bbs/upload.cgi" method="post" enctype="multipart/form-data">
<div>サーバ上のファイル名 : <input type="text" name="local-name" value="uploaded.png"/></div>
<div>アップロードするファイル : <input type="file" name="remote-file"/></div>
<div><button type="submit">アップロード</button></div>
</form>

[プログラムコード終了]

このフォームで、remote-fileのファイル選択欄でvalid-xhtml11.pngと入力し(実際には絶対パスで入力する事になるでしょう)、アップロードボタンを押すと、例えばIEでは次のようにメッセージが送られます。

[出力例開始]

Content-Type: multipart/form-data; boundary=---------------------------7d62b12510340
 
-----------------------------7d62b12510340
Content-Disposition: form-data; name="local-name"
 
uploaded.png
-----------------------------7d62b12510340
Content-Disposition: form-data; name="remote-file"; filename="valid-xhtml11.pngの絶対パス"
Content-Type: image/x-png
 
valid-xhtml11.pngファイルの内容
-----------------------------7d62b12510340--

[出力例終了]

local-nameの方は特筆すべき事はありませんが、remote-fileの方は少し違います。

まず、Content-Dispositionヘッダにfilenameパラメータが追加されます。これは必ず付いている保証はありませんが(強制はされていない)、余程の事情が無ければ付いているでしょう。filenameパラメータの値にはその名の通りファイル名(あるいはパス)が与えられますが、非ASCII文字が含まれている場合、エンコードされているかも知れません。

次に、Content-Typeヘッダが追加されます。これも強制されている訳ではありませんが、大抵付いている事でしょう。ただ、これが信用に値するかどうかは疑問です。中身がテキストファイルであっても知らない拡張子であればapplication/octet-streamになったり、上の例ではきちんと拡張子pngが付いているにも拘らず古いimage/x-pngで送られています。大概、本当に安全なファイルかどうかは、内容を見て決めなければならないでしょう。

また、ファイルの内容がエンコードされている場合には同様にContent-Transfer-Encodingヘッダが付きます。そして、エンコードの有無に拘らず、パートバウンダリはファイルの中身にも含まれない事が保証されています。

生のマルチパート形式を扱う上で必要な事は、大体こんな所でしょう。実際にこれを解釈しようとすると、それなりに面倒です。Perlでは生のままプログラム側で加工しなければならないので、ライブラリを自作するか、既にそういうものがあれば借りてくるのが楽でしょう。PHPなら、勝手にスーパーグローバル$_FILES(連想配列)に必要な情報をまとめてくれるので、扱いが非常に楽になります。$_POSTと併せれば言う事無しですね。本当にPHPは楽です。

3-8. 使用例

これまでのコード例で気付いたかも知れませんが、form要素はInlineコンテントセットPCDATAデータタイプを直下に持つ事はできないので、間に何かを噛ませる必要があります。解説ではあまり大きなフォームを作らなかったので全てdiv要素で済ませていますが、大きなフォームの場合はfieldset要素を使うと良いでしょう。

[プログラムコード開始]

<form action="/members/register.php" method="post" enctype="multipart/form-data">
<fieldset>
<legend>個人情報</legend>
<div>ユーザID : <input type="text" name="user-id" value="ユーザID"/></div>
<div>パスワード : <input type="password" name="password" value="password"/></div>
<div>本名(姓) : <input type="text" name="family-name" value="苗字"/></div>
<div>本名(名) : <input type="text" name="first-name" value="名前"/></div>
<!-- その他の設定項目…… -->
</fieldset>
<fieldset>
<legend>お支払い</legend>
<div>種別 : <input type="radio" name="pay-type" value="credit-card" checked="checked"/>クレジットカード <input type="radio" name="pay-type" value="web-money"/>WebMoney</div>
<!-- その他の設定項目…… -->
</fieldset>
</form>

[プログラムコード終了]

あんまり関係無いですが、個人情報を送る場合は、少なくともSSL (Secure Socket Layer)が使われている事と、送信先が信頼の置けるものである事を確認しましょう。

[form]
Published : 2006-03-26T09:00:00+09:00
Last Modified : 2007-07-27T17:40:27+09:00
Table of Contents : 要素目次
Index : 要素索引
Verified with : Valid XHTML 1.1
Copyright © 2006 - 2007  E+X.