【PHP入門】最小構成で学ぶ!メールフォームの作り方(確認画面・セッション・CSRF対策)

Webサイトを運営していると、「お問い合わせフォーム」はほぼ必須の機能です。訪問者が気軽にコンタクトを取れる窓口であり、ビジネスチャンスにも繋がります。

この記事では、PHPを使って基本的なメールフォームを作成する方法を、最小限のコード構成でステップバイステップで解説します。

完成するメールフォームは、以下の3つのファイルで構成されます。

  1. index.html (入力画面): ユーザーが名前やメールアドレスを入力するフォーム。
  2. confirm.php (確認画面): 入力内容を表示し、ユーザーに間違いがないか確認してもらう画面。
  3. send.php (送信・完了画面): 実際のメール送信処理と、送信完了メッセージを表示する画面。

この構成は、ユーザーが「入力内容を間違えたまま送信してしまう」のを防ぐための、最も一般的で親切な設計です。

目次

1. 入力画面(index.html)の作成

まずは、ユーザーが情報を入力するためのHTMLフォームを作成します。これは特別なPHPの知識がなくても作成できます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>お問い合わせフォーム</title>
    <!-- (中略) スタイルシート -->
</head>
<body>
    <h2>お問い合わせフォーム</h2>
    <form action="confirm.php" method="POST">
        <div>
            <label for="name">お名前:</label>
            <input type="text" id="name" name="name" required>
        </div>
        <div>
            <label for="email">メールアドレス:</label>
            <input type="email" id="email" name="email" required>
        </div>
        <div>
            <label for="message">お問い合わせ内容:</label>
            <textarea id="message" name="message" rows="5" required></textarea>
        </div>
        <div>
            <button type="submit">入力内容を確認する</button>
        </div>
    </form>
</body>
</html>

ポイント

  • <form action="confirm.php" method="POST">
    • action="confirm.php": このフォームの送信先(データの送り先)が confirm.php であることを指定します。
    • method="POST": データの送信方法を「POST」に指定します。POSTは、URLにデータが表示されず、送信できるデータ量にも実質制限がないため、フォーム送信で一般的に使われます。
  • <input name="name">
    • name属性(name="name"name="email")が非常に重要です。ここで指定した名前が、PHP側でデータを受け取る際の「キー」になります。
  • required
    • HTML5の機能で、この項目が未入力だとブラウザが警告を出し、フォームの送信を防いでくれます。簡易的なバリデーション(入力チェック)として便利です。

2. 確認画面(confirm.php)の作成

入力画面で送信されたデータをPHPで受け取り、表示する画面です。ここでは「セッション」と「セキュリティ対策」が重要なテーマになります。

<?php
// (1) セッションを開始
session_start();

// (2) POSTデータがない場合は入力画面に戻す
if ($_SERVER["REQUEST_METHOD"] !== "POST" || empty($_POST)) {
    header("Location: index.html");
    exit;
}

// (3) POSTデータをサニタイズしてセッションに保存
// (htmlspecialcharsはXSS対策の基本です)
$_SESSION['name'] = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');
$_SESSION['email'] = htmlspecialchars($_POST['email'], ENT_QUOTES, 'UTF-8');
$_SESSION['message'] = htmlspecialchars($_POST['message'], ENT_QUOTES, 'UTF-8');

// (4) CSRF対策のトークンを生成
if (!isset($_SESSION['token'])) {
    $_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];

?>
<!DOCTYPE html>
<html lang="ja">
<!-- (中略) HTMLヘッドとスタイル -->
<body>
    <h2>お問い合わせ内容の確認</h2>
    <p>以下の内容でよろしければ「送信する」ボタンを押してください。</p>

    <div class="confirmation">
        <p><span>お名前:</span><br>
            <!-- (5) セッションからデータを表示 -->
            <?php echo nl2br($_SESSION['name']); ?>
        </p>
        <p><span>メールアドレス:</span><br>
            <?php echo nl2br($_SESSION['email']); ?>
        </p>
        <p><span>お問い合わせ内容:</span><br>
            <?php echo nl2br($_SESSION['message']); // nl2brで改行を<br>タグに変換 ?>
        </p>
    </div>

    <div class="button-group">
        <!-- (6) 修正するボタン -->
        <a href="javascript:history.back()" class="back-button">修正する</a>

        <!-- (7) 送信フォーム -->
        <form action="send.php" method="POST">
            <!-- CSRFトークンを送信 -->
            <input type="hidden" name="token" value="<?php echo htmlspecialchars($token, ENT_QUOTES, 'UTF-8'); ?>">
            <button type="submit">送信する</button>
        </form>
    </div>
</body>
</html>

ポイント解説

(1) session_start(); PHPでセッション機能を使うための宣言です。セッションとは、複数のページをまたいでユーザーのデータ(訪問回数やログイン状態、フォームの入力内容など)を一時的にサーバー上に保存しておく仕組みです。 必ず、HTMLの出力よりも前に呼び出す必要があります。

(2) 不正アクセスの防止 confirm.phpindex.html からPOST送信されることを前提としています。もしブラウザで直接 confirm.php にアクセスされた場合(POSTデータがない場合)は、index.html に強制的に戻します。

(3) データの受け取りとXSS対策

  • $_POST['name'] のように、$_POST というPHPのグローバル変数で、index.htmlname 属性をキーにしてデータを受け取れます。
  • htmlspecialchars(): これは非常に重要な関数で、「クロスサイトスクリプティング(XSS)」という攻撃を防ぎます。
    • もし攻撃者がお問い合わせ内容に <script>alert('攻撃!');</script> のような悪意のあるコードを入力した場合、htmlspecialchars を使わずにそのまま表示すると、そのスクリプトが実行されてしまいます。
    • この関数を通すことで、<> といった記号を &lt;&gt; のような無害なHTMLエンティティに変換し、スクリプトの実行を防ぎます。
  • $_SESSION['name'] = ...: 受け取ったデータを、セッション変数($_SESSION)に保存しています。これにより、次の send.php でもこのデータを参照できます。

(4) CSRF対策

  • クロスサイト・リクエスト・フォージェリ(CSRF)」という攻撃を防ぐための対策です。
  • bin2hex(random_bytes(32)) でランダムな文字列(トークン)を生成し、セッションに保存します。
  • このトークンを、次の送信フォームに input type="hidden" で埋め込みます((7)参照)。
  • send.php では、「セッションに保存されたトークン」と「フォームから送信されたトークン」が一致するかをチェックします。これにより、「正規の確認画面を経由して送信されたリクエストであること」を証明できます。

(5) データの表示と nl2br()

  • $_SESSION に保存したデータを echo で表示します。
  • nl2br() は、改行文字(\n)をHTMLの <br> タグに変換する関数です。textarea で入力された改行を、HTML上で正しく表示するために使います。

(6) 「修正する」ボタン

  • javascript:history.back() は、ブラウザの「戻る」ボタンと同じ機能です。入力画面に戻り、内容を修正できるようにします。

(7) 「送信する」フォーム

  • 次の send.php へデータを送るためのフォームです。
  • このフォームにはユーザーが入力する項目はありませんが、(4)で生成したCSRFトークンを type="hidden" でこっそり含めて送信しています。

3. 送信・完了画面(send.php)の作成

確認画面で「送信する」ボタンが押されたときに、実際にメールを送信し、ユーザーに完了メッセージを伝える画面です。

<?php
// (1) セッションを開始
session_start();

// (2) CSRFトークンの検証
if ($_SERVER["REQUEST_METHOD"] !== "POST" || !isset($_POST['token']) || $_POST['token'] !== $_SESSION['token']) {
    echo "不正なリクエストです。";
    // (中略) セッション破棄
    exit;
}

// (3) セッションからデータを取得
if (!isset($_SESSION['name']) || !isset($_SESSION['email']) || !isset($_SESSION['message'])) {
    header("Location: index.html");
    exit;
}
$name = $_SESSION['name'];
$email = $_SESSION['email'];
$message = $_SESSION['message'];

// (4) メール送信処理
// ★★★ ここはあなたのメールアドレスに変更してください ★★★
$to = "your-email@example.com"; 
$subject = "お問い合わせフォームからのメッセージ";
$body = "お問い合わせフォームから以下のメッセージが届きました。\n\n";
$body .= "=================\n";
$body .= "お名前: " . $name . "\n";
$body .= "メールアドレス: " . $email . "\n";
$body .= "お問い合わせ内容:\n";
$body .= $message . "\n";
$body .= "=================\n";

// (5) メールのヘッダー
$headers = "From: " . $email . "\r\n";
$headers .= "Reply-To: " . $email . "\r\n";
$headers .= "X-Mailer: PHP/" . phpversion();

// (6) 日本語メール送信のための設定
mb_language("Japanese");
mb_internal_encoding("UTF-8");

// (7) メール送信
$send_result = mb_send_mail($to, $subject, $body, $headers);

// (8) 送信結果のメッセージ
if ($send_result) {
    $result_message = "お問い合わせいただきありがとうございます。メッセージは正常に送信されました。";
} else {
    $result_message = "メッセージの送信に失敗しました。恐れ入りますが、時間をおいて再度お試しください。";
}

// (9) セッションデータを破棄(二重送信防止)
$_SESSION = [];
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
}
session_destroy();

?>
<!DOCTYPE html>
<html lang="ja">
<!-- (中略) HTMLヘッドとスタイル -->
<body>
    <h2>送信完了</h2>
    <div class="result-message">
        <p><?php echo htmlspecialchars($result_message, ENT_QUOTES, 'UTF-8'); ?></p>
    </div>
    <a href="index.html" class="back-link">フォームのトップに戻る</a>
</body>
</html>

ポイント解説

(1) session_start(); confirm.php で保存したセッションデータを読み込むため、ここでも最初に呼び出します。

(2) CSRFトークンの検証 confirm.php から送られてきた $_POST['token'] と、セッションに保存されている $_SESSION['token'] を比較します。これらが一致しない(または存在しない)場合は、不正なリクエストとみなし、処理を中断します。

(3) セッションからデータを取得 $_SESSION に保存されていた nameemail の情報を、ローカル変数($name, $email など)に代入します。この時点でセッションデータが何らかの理由で消えていた場合は、入力画面に戻します。

(4) メール本文の作成 $body という変数に、メールに書きたい内容を文字列として連結していきます。\n は改行を意味します。

(5) メールのヘッダー

  • $headers には、メールの補助情報を設定します。
  • From: " . $email : 送信元(From)を、フォームに入力されたメールアドレスに設定します。これにより、メールソフトで受信した際に、誰からの問い合わせかが分かりやすくなります。
  • Reply-To: " . $email : 返信先(Reply-To)も設定しておくと、メールソフトの「返信」ボタンを押したときに、自動でユーザーのメールアドレスが宛先に入り便利です。

(6) 日本語メール設定 mb_send_mail で日本語(マルチバイト文字)を正しく送信するためのおまじないです。文字化けを防ぐために設定します。

(7) メール送信 mb_send_mail($to, $subject, $body, $headers); この関数が、実際にメールを送信する処理を行います。送信に成功すれば true、失敗すれば false を返します。

(8) 送信結果のメッセージ $send_result の結果(truefalseか)を見て、ユーザーに表示するメッセージを切り替えます。

(9) セッションデータの破棄 非常に重要です。 メール送信が完了(成功・失敗に関わらず)したら、セッションに保存したフォームデータとトークンを破棄します。

  • $_SESSION = []; でセッション変数を空にします。
  • session_destroy(); でセッション自体を完全に破棄します。
  • もしこれを忘れると、ユーザーが送信完了画面でブラウザの「更新」ボタンを押したときに、send.php が再度実行され、同じメールが何度も送信されてしまう(二重送信)可能性があります。

4. 動作確認と注意点

(1) 宛先メールアドレスの変更

send.php(4) の部分にある $to = "your-email@example.com"; を、必ずあなたが受信できるメールアドレスに変更してください。

(2) サーバー環境

このコードは、PHPが動作するサーバー(XAMPP, MAMP, レンタルサーバーなど)にアップロードしないと動作しません。

(3) メールが送信されない場合

レンタルサーバーなどでは、迷惑メール対策としてPHPからのメール送信に制限がかかっていたり、別途設定が必要だったりする場合があります。 また、ローカル環境(XAMPPなど)からメールを送信するには、PC自体にメール送信サーバー(SMTPサーバー)の設定が必要となり、ハードルが上がります。

テストがうまくいかない場合は、まず send.phpif ($send_result) の分岐を強制的に if (true) にしてみて、完了画面が表示されるか(処理が最後まで通るか)を確認するのも一つの手です。

5. 次のステップ(機能向上)

この記事のコードは、学習のための最小構成です。実際の運用では、以下の点を改良することを強く推奨します。

  • 入力値のバリデーション強化:
    • confirm.php の冒頭で、$_POST の内容を厳しくチェックします。
    • 「お名前」が空でないか?(requiredだけでは不十分な場合もある)
    • 「メールアドレス」が正しい形式か?(filter_var($email, FILTER_VALIDATE_EMAIL) などを使う)
    • 「お問い合わせ内容」が長すぎないか?
  • スパム対策:
    • このまま公開すると、海外のボット(プログラム)から大量のスパムメールが送られてくる可能性があります。
    • Googleの「reCAPTCHA」などを導入するのが一般的です。
  • 自動返信メール(サンキューメール):
    • send.php で管理者宛のメールを送信した後、入力されたメールアドレス($email)宛にも「お問い合わせを受け付けました」という内容のメールを別途送信すると、ユーザーが安心できます。

まとめ

PHPでメールフォームを作る流れを解説しました。 一見難しそうに見えますが、「HTMLでデータを受け取り」「PHPで処理してメールを送る」という流れが基本です。

重要なのは、htmlspecialchars(XSS対策)や トークン(CSRF対策)、セッション破棄(二重送信防止)といったセキュリティやユーザビリティへの配慮です。

この記事のコードをベースに、ぜひ自分だけのメールフォームを作成してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次