概要と目標
メールフォームを、
完成させよう。
エラーの表示や入力確認画面、メール送信処理を行い
メールフォームを完成させましょう。
エラーの表示や入力確認画面、メール送信処理を行い
メールフォームを完成させましょう。
「set.php」で$_SESSION['error']の中に、各項目ごとのエラーメッセージを格納した。
後は、このエラーメッセージを、適切な箇所に表示する。
<?php
// セッションの開始
session_start();
?>
htmlspecialchars()関数は、画面に出力する度に使うが、毎回記述量が多くてめんどくさい。<?php
// セッションの開始
session_start();
// XSS対策
function h($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
?>
input要素の下にエラーメッセージを表示するPHPを記述<form action="set.php" method="post">
<dl>
<dt><label for="name">お名前</label></dt>
<dd>
<input type="text" name="name" id="name">
<?php if ( isset($_SESSION['error']['name']) ) : ?>
<p><?php echo h($_SESSION['error']['name']); ?></p>
<?php endif; ?>
</dd>
<dt><label for="email">メールアドレス</label></dt>
<dd>
<input type="text" name="email" id="email">
<?php if ( isset($_SESSION['error']['email']) ) : ?>
<p><?php echo h($_SESSION['error']['email']); ?></p>
<?php endif; ?>
</dd>
<dt><label for="message">お問い合わせ内容</label></dt>
<dd>
<textarea name="message" id="message" rows="8" cols="50"></textarea>
<?php if ( isset($_SESSION['error']['message']) ) : ?>
<p><?php echo h($_SESSION['error']['message']); ?></p>
<?php endif; ?>
</dd>
</dl>
<p><input type="submit" value="入力確認へ"></p>
</form>
ユーザーが入力した内容も、「set.php」で $_SESSION['post']に格納している。
セッションにデータがある場合は、入力フォームの初期値として値を表示する。
input要素のvalue属性や、textarea要素の要素内容に$_SESSION['post']のデータを初期値として出力
<form action="set.php" method="post">
<dl>
<dt><label for="name">お名前</label></dt>
<dd>
<input type="text" name="name" id="name" value="<?php if (isset($_SESSION['post']['name'])) { echo h($_SESSION['post']['name']); } ?>">
<?php if ( isset($_SESSION['error']['name']) ) : ?>
<p><?php echo h($_SESSION['error']['name']); ?></p>
<?php endif; ?>
</dd>
<dt><label for="email">メールアドレス</label></dt>
<dd>
<input type="text" name="email" id="email" value="<?php if (isset($_SESSION['post']['email'])) { echo h($_SESSION['post']['email']); } ?>">
<?php if ( isset($_SESSION['error']['email']) ) : ?>
<p><?php echo h($_SESSION['error']['email']); ?></p>
<?php endif; ?>
</dd>
<dt><label for="message">お問い合わせ内容</label></dt>
<dd>
<textarea name="message" id="message" rows="8" cols="50"><?php if (isset($_SESSION['post']['message'])) { echo h($_SESSION['post']['message']); } ?></textarea>
<?php if ( isset($_SESSION['error']['message']) ) : ?>
<p><?php echo h($_SESSION['error']['message']); ?></p>
<?php endif; ?>
</dd>
</dl>
<p><input type="submit" value="入力確認へ"></p>
</form>
入力確認画面は、「set.php」で$_SESSIONに格納した内容を表示すればよい。
ただし、textarea要素で入力された内容は改行を含んでいる場合がある為、
改行コードを br要素に変換するnl2br関数が必要となる。
nl2br関数 ・・・ 改行文字の前に改行タグを挿入する関数nl2br(改行文字を含む文字列, XHTMLかどうか)
省略可
*.第2引数を false にすると、HTMLの出力になる
詳細はPHPマニュアルを参照
htmlspecialchars()関数を楽に記述するための独自関数を記述
<?php
// セッションの開始
session_start();
// XSS対策
function h($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
?>
$_SESSION['post]が空の時は、入力フォームを経由していないので、$_SESSION['post]が空の時は入力フォームにリダイレクトさせる処理を<?php
// セッションの開始
session_start();
// XSS対策
function h($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
// $_SESSION['post']が空ならリダイレクト
if ( empty( $_SESSION['post']) ) {
header('Location: ./');
exit();
}
?>
<dd> 〜 </dd>の間に、入力内容を表示するPHPを追記textarea要素から送信された内容は、改行を含む場合があるので、br要素に変換する nl2br関数を使う
<dl>
<dt>お名前</dt>
<dd>
<?php echo h($_SESSION['post']['name']); ?>
</dd>
<dt>メールアドレス</dt>
<dd>
<?php echo h($_SESSION['post']['email']); ?>
</dd>
<dt>お問い合わせ内容</dt>
<dd>
<?php echo nl2br( h($_SESSION['post']['message']), false); ?>
</dd>
</dl>
サイト管理者にメールを送信する。
送信に成功したら、セッションを破棄して送信完了ページにリダイレクトする。
<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
// メールアドレスが空の場合はリダイレクト
if ( empty($_SESSION['post']['email']) ) {
header('Location: ./');
exit();
}
mb_send_mail()関数に必要なデータを変数に代入する。<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
// メールアドレスが空の場合はリダイレクト
if ( empty($_SESSION['post']['email']) ) {
header('Location: ./');
exit();
}
// 値を変数に格納
$to = '[メールアドレス]'; // お問い合わせを受け取れるメールアドレスに変更
$subject = '【ダミー】お問い合わせありがありました。';
$message = 'お問い合わせがありました。' . PHP_EOL;
$message .= PHP_EOL;
$message .= '■お名前' .PHP_EOL;
$message .= $_SESSION['post']['name'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■メールアドレス' .PHP_EOL;;
$message .= $_SESSION['post']['email'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■お問い合わせ内容' .PHP_EOL;;
$message .= $_SESSION['post']['message'];
$from = mb_encode_mimeheader('ダミー') . '<noreply@dummy.com>';
mb_send_mail()関数でメールを送信する。<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
// メールアドレスが空の場合はリダイレクト
if ( empty($_SESSION['post']['email']) ) {
header('Location: ./');
exit();
}
// 値を変数に格納
$to = '[メールアドレス]'; // お問い合わせを受け取れるメールアドレスに変更
$subject = '【ダミー】お問い合わせありがありました。';
$message = 'お問い合わせがありました。' . PHP_EOL;
$message .= PHP_EOL;
$message .= '■お名前' .PHP_EOL;
$message .= $_SESSION['post']['name'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■メールアドレス' .PHP_EOL;;
$message .= $_SESSION['post']['email'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■お問い合わせ内容' .PHP_EOL;;
$message .= $_SESSION['post']['message'];
$from = mb_encode_mimeheader('ダミー') . '<noreply@dummy.com>';
// メールの送信
$resulut = mb_send_mail($to, $subject, $message, 'From: '. $from);
<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
// メールアドレスが空の場合はリダイレクト
if ( empty($_SESSION['post']['email']) ) {
header('Location: ./');
exit();
}
// 値を変数に格納
$to = '[メールアドレス]'; // お問い合わせを受け取れるメールアドレスに変更
$subject = '【ダミー】お問い合わせありがありました。';
$message = 'お問い合わせがありました。' . PHP_EOL;
$message .= PHP_EOL;
$message .= '■お名前' .PHP_EOL;
$message .= $_SESSION['post']['name'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■メールアドレス' .PHP_EOL;;
$message .= $_SESSION['post']['email'] .PHP_EOL;
$message .= PHP_EOL;
$message .= '■お問い合わせ内容' .PHP_EOL;;
$message .= $_SESSION['post']['message'];
$from = mb_encode_mimeheader('ダミー') . '<noreply@dummy.com>';
// メールの送信
$resulut = mb_send_mail($to, $subject, $message, 'From: '. $from);
// 送信に成功したかをチェック
if ($resulut) {
// 送信成功時
// セッションの初期化で、値を削除
$_SESSION = array();
// クッキーのセッションIDを削除
setcookie(session_name(), '', time() - 3600);
// セッションの破壊
session_destroy();
// 送信成功ページにリダイレクト
header('Location: thanks.html');
} else {
// 送信失敗時
// 送信失敗ページにリダイレクト
header('Location: error.html');
}
exit();
すでにメールフォームとしての機能は実装できているが、
時間があればCSRFという脆弱性の対策を行う。
CSRFの対策は、自分が用意したフォーム以外からデータを受け取らないようにする。
具体的には、トークンと呼ばれる推測不能なランダムな文字列を作成し、<input type="hidden">を使って、フォーム内に埋め込む。
そして、ユーザーの入力内容と一緒にトークンを送信し、
受け取り側のPHPファイルでトークン正しいかをチェックすることで対策できる。
トークンは、openssl_random_pseudo_bytes()関数とbin2hex()関数を組み合わせて、
推測されにくいランダムな文字列を生成するとよい。
openssl_random_pseudo_bytes関数 ・・・ 疑似乱数のバイト文字列を生成する関数openssl_random_pseudo_bytes(長さ)
詳細はPHPマニュアルを参照
bin2hex関数 ・・・バイナリのデータを16進表現に変換する関数bin2hex(16進表現に変換する文字列)
詳細はPHPマニュアルを参照
$_SESSIONに格納する処理を<?php
// セッションの開始
session_start();
// XSS対策
function h($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
// CSRF対策 ・・・ トークンを生成
if (!isset($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));
}
?>
<input type="hidden">にトークンを埋め込み、form要素内に配置<p><input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"></p>
<p><input type="submit" value="入力確認へ"></p>
$_POSTで受け取ったトークンと、予め$_SESSIONに格納しておいたトークンが一致するかを確認し、<?php
// セッションの開始
session_start();
// ポストが空っぽだったらリダイレクト
if ( empty($_POST) ) {
header("Location: ./");
exit();
}
// CSRF対策 ・・・ トークンを確認
if (empty($_POST['token']) || $_POST['token'] != $_SESSION['token']) {
exit('不正な投稿です。');
}
// エラーメッセージ格納用の配列を初期化
$_SESSION['error'] = array();
$_SESSIONに格納する処理を<?php
// セッションの開始
session_start();
// XSS対策
function h($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
// $_SESSION['post']が空ならリダイレクト
if ( empty( $_SESSION['post']) ) {
header('Location: ./');
exit();
}
// CSRF対策 ・・・ トークンを生成
if (!isset($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));
}
?>
form要素を作成し、<input type="hidden">でトークンを埋め込むform要素内に移動し、「送信」のリンクは<input type="submit" value="送信">に変更
<dt>お問い合わせ内容</dt>
<dd>
<?php echo nl2br( h($_SESSION['post']['message']), false); ?>
</dd>
</dl>
<form action="send.php" method="post">
<p><input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"></p>
<ul>
<li><a href="./">入力フォームへ</a></li>
<li><input type="submit" value="送信"></li>
</ul>
</form>
</body>
$_POSTで受け取ったトークンと、予め$_SESSIONに格納しておいたトークンが一致するかを確認し、<?php
// セッションの開始
session_start();
// 日本語の設定
mb_language('ja');
mb_internal_encoding('UTF-8');
// CSRF対策 ・・・ トークンの確認
if (empty($_POST['token']) || $_POST['token'] != $_SESSION['token']) {
exit('不正な投稿です。');
}
// メールアドレスが空の場合はリダイレクト
if ( empty($_SESSION['post']['email']) ) {
header('Location: ./');
exit();
}
作成したメールフォームに、セクショニング・コンテンツの要素や、
CSSを追加して、オリジナルのメールフォームを完成させよう。
メールフォームはサーバーサイドプログラミングの基本が詰まってる。