【第3回】PHPでお問い合わせフォームを作ろう!メールの本文の作成方法と送信の仕方
この記事からわかること
- 第2回の記事の続き
- メール本文の構築方法
- 実際にメールを送信する
- メールを送信する際の注意点
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
第1回:【自作】PHPでお問い合わせフォームを作ろう!コードと仕組みを徹底解説!
第2回:【第2回】PHPでお問い合わせフォームを作ろう!入力値の確認と値の保持の仕方
- ✔️ 入力フォームの作成(HTML)
- ✔️ 入力値のエスケープ処理と入力チェック(HTML+php)
- ✔️ 入力値の確認
- メール本文(相手に自動送信用)を作成(php)
- メール本文(自分にお問い合わせ内容送信用)を作成(php)
- 実際にメールを送信する(php)
前回の記事でここまで終了しました。今回はメールの本文作りと実際に送信するまでを作っていきたいと思います。
最初に実装すべきことを整理する
「メールの本文の作成方法と送信の仕方」でやらなければいけないことは以下の通りです。
- confirm.phpから画面(send.phpへ)を遷移させる
- 入力値を元にメールの本文を構築する
- phpでメールを送信する際のセキュリティ対策
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
<tr>
<th>内容</th>
<td><?php echo nl2br($body); ?></td>
</tr>
</table>
<p>こちらの内容で送信してもよろしいですか?</p>
<!-- POSTの送信先はsend.phpであることに注意してください -->
<form method="post" action="send.php">
<input type="hidden" name="token" value="<?php echo $token ?>">
<button type="submit" value="送信">送信</button>
<a href="form.php?action=edit">戻る</a>
</form>
</div>
第2回で上記のコード部分で設置した送信ボタンとtokenをまずは有効にしていきましょう!
メール送信ファイルへの画面の遷移
実はメール送信ファイル(send.php)への画面遷移のコードはもう記述しています。
上記9行目:<form method="post" action="send.php">
action
でPOSTの送信先を指定するとそのファイルへリダイレクトするようになっています。action
の送信先を自分のファイルにする時も新しくその画面をリロードしているのですね!
なので送信ボタンを押せば「send.php」へ切り替わるのであとは「send.php」でメール送信のコードを記述すればOKです。
画面遷移時はセキュリティ対策を
ここで前回から登場していたtoken
について解説していきます。このtokenを設置する意味は正しい順序でメール送信ファイルへ遷移したかを検証するためです。
仕組みとしては変数$token
に格納された値をPOSTとSESSIONで渡し「send.php」で差異がないかをチェックします。差異があれば強制的に最初の画面にリダイレクトさせ、差異がなければメールを送信するといった流れです。
これでURLにsend.phpのアドレスを決め打ちで入力して不正アクセスしてくるのを防ぐことができます。
では実際にどのようにトークンを作っていくのかみていきましょう。
一意なトークンの作り方
まずは以下の関数を使用してトークンを準備します。
- mt_rand関数:ランダムな数値を自動生成(乱数)
- uniqid関数 :13文字のランダムな文字列を自動生成※
- sha1関数 :データをハッシュ化(暗号化)
※:uniqid(プレフィックス(接頭辞),true/false)
→”接頭辞+生成した文字列”の値を生成true
で”接頭辞+生成した文字列”が13文字以上を許可false
で”接頭辞+生成した文字列”で13文字にする
これらの関数を組み合わせてオリジナルのトークンを作成し、そのトークンを変数$token
と$SESSION['token']
に格納しておきます。
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
$title = $_SESSION['title'];
$body = $_SESSION['body'];
}
// 以下を追加
$token = sha1(uniqid(mt_rand(),true));
$_SESSION['token'] = $token;
?>
<!DOCTYPE html>
これで第2回で記述していたコードの以下の部分が有効になります。
最初のコード10行目:<input type="hidden" name="token" value="<?php echo $token ?>">
その後に$token
に格納されたトークンの値を<?php echo $token ?>
で表示させtype="hidden"
で画面上に表示されないようにしておきます。ここはすでに記述ずみなので流れだけ理解しておきましょう!
これでSESSIONによる$token
とPOSTによる$token
が「send.php」から取得することができるようになりました。では「send.php」側での処理を見ていきましょう。
トークンに差異がないかチェック
ここからは「send.php」に記述していきます。この時点ではまだ空なのでいつものhtml:5
で記述します。その上部にphpを記述します。
<?php
session_start(); // セッションを使用するのでスタートさせます
if($_SESSION['token'] === $_POST['token']){ // #1
echo "正常なアクセスです";
// メール送信処理
} else { // #1
// 直接send.phpにアクセスしようとしたら強制的にリダイレクト
header('Location:http://localhost/Questionform/form.php');
} // #1
?>
<!DOCTYPE html>
// 〜〜〜〜〜〜〜以下いつも通りのHTMLを記述〜〜〜〜〜〜〜
SESSIONで渡されたtokenとPOSTで渡されたtokenを比較し正しければメール送信処理へ、間違っていれば強制的に「form.php」へリダイレクトさせます。
これで正常な画面遷移と不正なアクセスを予防することができます。それでは次に実際にメールを作成し送信する処理を解説していきます。
メールの本文を作成
メールの本文の作成方法の流れは以下の通りです。
- SESSIONで受け取った入力値を変数に格納
- メールアドレスに対してのセキュリティ対策
- メールの本文の作成1「自分に受付内容送信用」
- メールの本文の作成2「相手に受付完了送信用」
- メールをそれぞれ送信
- 送れなかった場合の処理
入力値をセキュリティ対策を施して適切に変数に格納する
最初にSESSIONで渡された入力値を変数に格納します。その際にメールアドレスだけは注意が必要です。
if($_SESSION['token'] === $_POST['token']){ // #1
// echo "正常なアクセスです";⇦これはコメントアウトしておきます
// ⇩新しく記述
if(isset($_SESSION['kinds'])){ // #2
$kinds = $_SESSION['kinds'];
$name = $_SESSION['name'];
$email = str_replace(array("\r","\n"),'',$_SESSION['email']);
$title = $_SESSION['title'];
$body = $_SESSION['body'];
} // #2
// 次はここに記述していく
}else{ // #1
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
この後に入力されたメールアドレスにお問い合わせ受付完了メールを送ることになります。その際にメールを送信する関数のパラメータ(引数)として入力値をそのまま使うことになるので適切なセキュリティ対策を施さないといけません。
それ以外の入力値はメール送信の関数のパラメータ(引数)として使わないのでここでの処理は省いても問題ありません。
その処理がstr_replace(array("\r","\n"),'',$_SESSION['email'])
の部分です。詳しくは⇩こちらをご覧ください。
関連記事:【絶対必須】phpのセキュリティ対策!XSSとメールヘッダーインジェクションを防ごう
メールの本文の作成
} // #2
// 自分に送るお問い合わせ内容メールを構築
$to = "自分のメールアドレス"; ⇦ここは置き換えてください。
$mailtitle = "{$name}様よりお問い合わせが届きました。";
$contents = <<<EOD
◆種別
{$kinds}
◆お名前
{$name}
◆メールアドレス
{$email}
◆件名
{$title}
◆内容
{$body}
EOD;
$from = 'From: '.$email ; //送信元メールアドレス
// 自分に送るお問い合わせ内容メールを構築
// 相手に送る送信完了メールを構築
$to2 = $email;
$mailtitle2 = "【自動送信】受付を完了いたしました。";
$contents2 = <<<EOD
お問い合わせありがとうございます。
以下の内容を送信いたしました。
必ず返信いたしますのでしばらくお待ちください。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{$contents}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
E-mail: email@email.com
サイト運営者:あめ
EOD;
$from2 = "Return-Path:" . $to . "\r\n";
$from2 = $from2 . 'From: ' . $to;
// 相手に送る送信完了メールを構築
// 次はここに記述していく
}else{ // #1
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
メールの本文は自分の自由に作ればOKです!見やすくわかりやすい本文を作成しましょう。後から各変数をパラメータ(引数)としてメール送信関数を実行します。
以下の変数にはそれぞれ適切なものを入れておいてください。($変数2も同様です)
- $to:メールの送信先
- $mailtitle:メールの件名
- $contents:メールの内容
- $from:メールの送信元
メールを送信する関数
実際にメールを送信するのはmb_send_mail
関数の役割です。
mb_send_mail(送信先,タイトル,本文,追加ヘッダ,追加コマンドラインパラメータ)
適切な引数を指定することで本当にメールを送ることができます。すごいですよね!笑
mb_send_mail
関数は何らかの不具合で送信に失敗するとfalse
を返します。なのでif(mb_send_mail
関数)として送信失敗時の処理も記載していきます。
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
// メールを送るときのおまじない
mb_language("Japanese");
mb_internal_encoding("UTF-8");
$param = "-f" . $to;
// mb_send_mail(送信先,タイトル,本文,追加ヘッダ,追加コマンドラインパラメータ)
if (mb_send_mail($to2, $mailtitle2, $contents2, $from2, $param)) { // 相手に送信 // #3
$message = '<p class="question-text">『' . $email . '』宛に確認メールを送信しました<br>お問い合わせありがとうございます。</p>';
if (mb_send_mail($to,$mailtitle,$contents,$from,$param)) { // 自分に送信 // #4
// 終了処理開始 セッションの破棄
$_SESSION = [];
if (isset($_COOKIE[session_name()])) { // #5
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params['httponly']);
}
session_destroy();
// セッションの破棄
} else { // #4
$message = '<p class="question-text error">何らかの理由で送信エラーが発生しました<br>しばらく待ってから再度送信してください</p>';
} // #4
} else { // #3
$message = '<p class="question-text error">『' . $email . '』宛に確認メールを送信できませんでした。<br>正しいメールアドレスで再度ご連絡をお願いいたします。</p>';
} // #3
メール送信処理をif文で囲み失敗(false)なら変数$messageにエラーメッセージを、2つとも成功なら変数$$messageに完了メッセージを格納しています。またSESSIONは利用が終了した時点で破棄しておきましょう。
最後にbody要素の中にメッセージを表示する場所を作って完成です。
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
<body>
<?php
if($message !== ""){
echo $message;
}
?>
<a href="form.php">TOPに戻る</a>
</body>
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
今回のまとめ
記述したファイル
- confirm.php
- send.php
記述した内容
- confirm.phpからsend.phpへのリダイレクト(confirm.php)
- トークンの生成とSESSIONとPOSTでのトークン渡し(confirm.php)
- トークンの検証(send.php)
- 入力値のセキュリティ対策と格納(send.php)
- メール本文の作成(send.php)
- メールの送信(send.php)
これで実際に使用できる「お問い合わせフォーム」が完成しました!!
自分のサーバーなどにアップして動かしてみてください。ちゃんと機能するはずです。ローカル環境で実行する場合は以下記事を参考にしてください。
【最新版】MAMPのインストール方法!Macでローカル環境を構築しよう!
うまくいかない部分があったり記載漏れがあったらコメントやお問い合わせいただけると助かります。
ここからお問い合わせお願いしますご覧いただきありがとうございました!
第1回:【自作】PHPでお問い合わせフォームを作ろう!コードと仕組みを徹底解説!
第2回:【第2回】PHPでお問い合わせフォームを作ろう!入力値の確認と値の保持の仕方
第3回:【第3回】PHPでお問い合わせフォームを作ろう!メールの本文の作成方法と送信の仕方
お問い合わせフォームの完成コード
form.php
<?php
session_start();
// 送信ボタンが押されたかどうか
if (isset($_POST['submit'])) { // #1
// POSTされたデータをエスケープ処理して変数に格納
$kinds = htmlspecialchars($_POST['kinds'], ENT_QUOTES | ENT_HTML5);
$name = htmlspecialchars($_POST['name'], ENT_QUOTES | ENT_HTML5);
$email = htmlspecialchars($_POST['email'], ENT_QUOTES | ENT_HTML5);
$title = htmlspecialchars($_POST['title'], ENT_QUOTES | ENT_HTML5);
$body = htmlspecialchars($_POST['body'], ENT_QUOTES | ENT_HTML5);
$errors = []; //エラー格納用配列
if (trim($name) === '' || trim($name) === " ") {
$errors['name'] = "名前を入力してください";
}
if (trim($title) === '' || trim($title) === " ") {
$errors['title'] = "タイトルを入力してください";
}
if (trim($body) === '' || trim($body) === " ") {
$errors['body'] = "内容を入力してください";
}
// エラー配列がなければ完了
if (count($errors) === 0) { // #2
$_SESSION['kinds'] = $kinds; //⇦エスケープ処理をして値を変数に格納済みの入力値
$_SESSION['name'] = $name;
$_SESSION['email'] = $email;
$_SESSION['title'] = $title;
$_SESSION['body'] = $body;
// URLは「http」or「https」に注意
header('Location:http://localhost/Questionform/confirm.php');
// header('Location:http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/confirm.php');
} else { // #2
// エラー配列があればエラーを表示
echo $errors['name'];
echo $errors['title'];
echo $errors['body'];
} // #2
} // #1
// confirm.phpから戻ってきたときに値を保持
if (isset($_GET) && isset($_GET['action']) && $_GET['action'] === 'edit') {
$kinds = $_SESSION['kinds'];
$name = $_SESSION['name'];
$email = $_SESSION['email'];
$title = $_SESSION['title'];
$body = $_SESSION['body'];
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="post" action="form.php">
<div>
<p>お問い合わせ種別</p>
<input type="radio" name="kinds" value="質問" <?php if (isset($kinds) && $kinds === "質問") {echo "checked";} else {echo "checked";} ?>><label>質問</label>
<input type="radio" name="kinds" value="依頼" <?php if (isset($kinds) && $kinds === "依頼") {echo "checked";} ?>><label>依頼</label>
<input type="radio" name="kinds" value="その他" <?php if (isset($kinds) && $kinds === "その他") {echo "checked";} ?>><label>その他</label>
</div>
<p>お名前</p>
<input type="text" name="name" value="<?php if (isset($name)) {echo $name;} ?>" placeholder="お名前" required>
<p>メールアドレス</p>
<input type="email" name="email" value="<?php if (isset($email)) {echo $email;} ?>" placeholder="メールアドレス" required>
<p>件名</p>
<input type="text" name="title" value="<?php if (isset($title)) {echo $title;} ?>" placeholder="件名" required>
<p>内容</p>
<textarea type="text" name="body" placeholder="お問い合わせ内容" rows="7" required><?php if (isset($body)) {echo $body;} ?></textarea><button type="submit" name="submit" value="確認">確認</button>
</form>
</body>
</html>
confirm.php
<?php
session_start(); //SESSIONを使うときは最初にスタートさせる
if (isset($_SESSION['kinds'])) {
$kinds = $_SESSION['kinds'];
$name = $_SESSION['name'];
$email = $_SESSION['email'];
$title = $_SESSION['title'];
$body = $_SESSION['body'];
}
// ここにトークンを生成するコードを記述
$token = sha1(uniqid(mt_rand(), true));
$_SESSION['token'] = $token;
// $_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(48));
// $token = htmlspecialchars($_SESSION['token'], ENT_QUOTES);
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<h2>お問い合わせ内容確認</h2>
<table>
<tr>
<th>お問い合わせ種別</th>
<td><?php echo $kinds; ?></td>
</tr>
<tr>
<th>お名前</th>
<td><?php echo $name; ?></td>
</tr>
<tr>
<th>メールアドレス</th>
<td><?php echo $email; ?></td>
</tr>
<tr>
<th>件名</th>
<td><?php echo $title; ?></td>
</tr>
<tr>
<th>内容</th>
<td><?php echo nl2br($body); ?></td>
</tr>
</table>
<p> こちらの内容で送信してもよろしいですか?</p>
<!-- POSTの送信先はsend.phpであることに注意してください -->
<form method="post" action="send.php">
<input type="hidden" name="token" value="<?php echo $token ?>">
<button type="submit" value="送信">送信</button>
<a href="form.php?action=edit">戻る</a>
</form>
</div>
</body>
</html>
send.php
<?php
session_start(); //セッションを使用するのでスタートさせます
if ($_SESSION['token'] === $_POST['token']) { // #1
if (isset($_SESSION['kinds'])) { // #2
$kinds = $_SESSION['kinds'];
$name = $_SESSION['name'];
$email = str_replace(array("\r", "\n"), '', $_SESSION['email']);
$title = $_SESSION['title'];
$body = $_SESSION['body'];
} // #2
// 自分に送るお問い合わせ内容メールを構築
$to = "sample@sample.com";
$mailtitle = "{$name}様よりお問い合わせが届きました。";
$contents = <<<EOD
◆種別
{$kinds}
◆お名前
{$name}
◆メールアドレス
{$email}
◆件名
{$title}
◆内容
{$body}
EOD;
$from = "Return-Path: " . $email . "\r\n";
$from = $from . 'From: ' . $email; //送信元メールアドレス
// 自分に送るお問い合わせ内容メールを構築
// 相手に送る送信完了メールを構築
$to2 = $email;
$mailtitle2 = "【自動送信】受付を完了いたしました。";
$contents2 = <<<EOD
お問い合わせありがとうございます。
以下の内容を送信いたしました。
必ず返信いたしますのでしばらくお待ちください。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{$contents}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
E-mail: sample@sample.com
サイト運営者:あめ
EOD;
$from2 = "Return-Path:" . $to . "\r\n";
$from2 = $from2 . 'From: ' . $to;
// 相手に送る送信完了メールを構築
// メールを送るときのおまじない
mb_language("Japanese");
mb_internal_encoding("UTF-8");
$param = "-f" . $to;
// mb_send_mail(送信先,タイトル,本文,追加ヘッダ,追加コマンドラインパラメータ)
if (mb_send_mail($to2, $mailtitle2, $contents2, $from2, $param)) { // 相手に送信 // #3
$message = '<p class="question-text">『' . $email . '』宛に確認メールを送信しました<br>お問い合わせありがとうございます。</p>';
if (mb_send_mail($to,$mailtitle,$contents,$from,$param)) { // 自分に送信 // #4
// 終了処理開始 セッションの破棄
$_SESSION = [];
if (isset($_COOKIE[session_name()])) { // #5
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params['httponly']);
}
session_destroy();
// セッションの破棄
} else { // #4
$message = '<p class="question-text error">何らかの理由で送信エラーが発生しました<br>しばらく待ってから再度送信してください</p>';
} // #4
} else { // #3
$message = '<p class="question-text error">『' . $email . '』宛に確認メールを送信できませんでした。<br>正しいメールアドレスで再度ご連絡をお願いいたします。</p>';
} // #3
} else { // #1
// 直接send.phpにアクセスしようとしたら強制的にリダイレクト
header('Location:http://localhost/Questionform/form.php');
// header('Location:http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/form.php');
} // #1
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
if ($message !== "") {
echo $message;
}
?>
<a href="form.php">TOPに戻る</a>
</body>
</html>