簡単なフォーム

ソース

<?php
  if (isset($_POST['onamae']) && $_POST['onamae'] != '') {
    $x = htmlspecialchars($_POST['onamae']);
    echo "<p>こんにちは,$x さん。</p>";
  }
?>

<form action="form.php" method="post">
<p>お名前: <input name="onamae" size="20"></p>
</form>

< > & " といったHTMLで特別な意味を持つ文字を &lt; &gt; &amp; &quot; に変換する関数 htmlspecialchars() を使っています。この理由はセキュリティ上の配慮をご覧ください。

PHP 5.4より古いPHPでは,htmlspecialchars() に文字コードも指定するほうが安全性が増します。UTF-8を使っているなら

    $x = htmlspecialchars($_POST['onamae'], ENT_COMPAT, 'UTF-8');

のようにします。2番目の引数 ENT_COMPAT はデフォルトの挙動を指定するものですが,文字コードを第3引数に指定するために入れておきます。以下では簡単にするために文字コード指定をほとんど省略しています。

action="form.php" の部分は,自分のファイル名を書きます。もしデフォルトのファイル名(index.htmlindex.php)の場合は action="./" と書きます。

ファイル名を間違えないようにするには, action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" のようにするといいでしょう。 $_SERVER['PHP_SELF'] は自分自身のファイル名(パス)で,このファイルでは /~okumura/php/form.phpとなります。 ただしPHPではファイル名の後に / で区切って任意の文字列を付けられるので,出力する際には htmlspecialchars() を使います。

labelを使おう

上の例は実際には次のように書かれています。

<form action="form.php" method="post">
<p><label>お名前: <input name="onamae" size="20"></label></p>
</form>

このように label を使うと,ラベル(上の例では「お名前」)をクリックすれば,入力欄に入力可能な状態になります。label のこの動作は,厳密にはHTML5では必須とされていませんが,多くのブラウザでサポートされているようです。

上の形の label はIE6では対応していませんでしたので,以前のこのページでは次の書き方を推奨していました。

<form action="form.php" method="post">
<p><label for="onamae">お名前:</label> <input id="onamae" name="onamae" size="20"></p>
</form>

もうIE6はないので大丈夫でしょう。

最初のテキストボックスを選択した状態にするには

ページを開くと最初のテキストボックスがフォーカスされるようにするには,HTML5で新しく導入された autofocus というオプションを使うのが簡単です:

<p><label>お名前: <input name="onamae" size="20" autofocus></label></p>

HTML5以前のブラウザで使えるようにするには,

<p><label>お名前: <input id="onamae" name="onamae" size="20"></label></p>

のように id を付けておき,bodyタグに

<body onload="document.getElementById('onamae').focus()">

のような細工をします(JavaScript講座)。

ポストされたかの判断のいろいろ

上の例では,名前が入力されているかどうかを if (isset($_POST['onamae']) && $_POST['onamae'] != '') で判断しています。これ以外に次のような判断法が考えられますが,意味は少しずつ違います。

if (isset($_POST['onamae']))
このページを最初に訪れたときは $_POST['onamae'] がセットされていません(var_dump($_POST['onamae']) を表示すると NULL となります)ので,これで判断できます。ただ,このページで何も入力しないで Enter キーを押した場合は空文字列 "" がセットされていますので,「こんにちは, さん」と表示されてしまいます。
if (!empty($_POST['onamae']))
空文字列には反応しなくなりますが,0 と入力しても無入力と判断されてしまいます。
if ($_POST['onamae'])
同上。
if ($_POST['onamae'] != '')
空文字列でないことを判断します。$_POST['onamae'] がセットされていない場合には,警告が出ることがありますが,正しく処理されます。
if ($_POST['onamae'] !== '')
空文字列でないことを(より厳密に)判断します。$_POST['onamae'] がセットされていない場合には,警告が出ることがあるだけでなく,「こんにちは」が表示されてしまいます。
if (isset($_POST['onamae']) && $_POST['onamae'] != '')
$_POST['onamae'] が定義され,かつ空文字列でないことを判断します。
if (@$_POST['onamae'] != '')
このように @ をかぶせることによってエラーや警告が出るのを抑制します。事実上,isset($_POST['onamae']) のチェックをしたかのような振舞いになります。

isset(...) は,セットされているか(is set?)を調べる命令です。複数のものがすべてセットされているかを調べるには,isset($_POST['onamae'], $_POST['email']) のように連続して書くことができます。

上でも書きましたが,存在しない $_POST['onamae'] を使うと, "PHP Notice: Undefined index: onamae in /home/okumura/public_html/php/form.php on line 17” のような警告が出ることがあります。

警告が(画面またはApacheのerror_logに)出ないようにするには,PHPの設定ファイルphp.iniの error_reporting = E_ALLerror_reporting = E_ALL & ~E_NOTICE または error_reporting = E_ALL & ~E_NOTICE | E_STRICT のようにします。

CSRF対策

$_SERVER['HTTP_REFERER'] を調べれば,不正な書き込みが検出できます。 ただし,HTTP_REFERERを送らないブラウザがあると,ややこしくなります。

セッション管理を使う対策のほうが一般的です。高木さんのクロスサイトリクエストフォージェリ(CSRF)の正しい対策方法をご覧ください。

具体的には,一つ前のページのformの中に

<input type="hidden" name="sessionid" value="<?php
  echo htmlspecialchars(session_id(), ENT_COMPAT, 'UTF-8');
?>">

と書いておき,最終処理をするページで

if ($_POST['sessionid'] != session_id()) die("だめよ");

のようなチェックをします。