先日PHPを使った基本的な「問い合わせフォーム」作成の記事を書きました。
この記事で作成した「問い合わせフォーム」は全て「PHP」を使って
入力フォーム → 確認画面 → 送信完了画面
という流れで入力フォームの内容を指定したメールアドレスに送信する仕様でした。
このように、いくつかの画面の変遷を経て入力フォームの内容が送信させる方法のほかに、画面を変遷させずに入力フォームの内容を送信する方法もあります。
その方法とは入力フォームのデータの受け渡しにjQueryの「Ajax」を使用する方法です。
「Ajax」により、入力フォームのページから画面を変遷をさせることなくフォームの内容を管理者にメールで送信することができます。
今日は「Ajax」を使って簡単な「問い合わせフォーム」を作ってみたいと思います。
もくじ
Ajaxを使ってお問い合わせフォームを作る
作成するのは以下のようなフォームです。
- フォームの項目は「名前」「メールアドレス」「内容」の3つ
- フォームの入力内容のバリデーションはしない
- 問い合わせフォームの入力内容を管理者宛てにメールする
- 入力フォーム画面から遷移しない
処理の流れは以下のような感じです。
入力フォーム(form.php) → 入力フォームからデータを取得してAjaxでメール送信プログラムに送る(main.js) → 入力フォームの内容をメールで送信し、送信結果をAjaxに返す(send_mail.php) → 送信結果を受け取って表示する(main.js)
画面は最初から最後まで変遷せずにずっとform.phpのままです。
form.php(入力フォーム画面)
イメージ
<?php
session_start();
//クリックジャッキングへの対策
header('X-Frame-Options: DENY');
//トークンの生成
$token = sha1(uniqid(rand(), true));
//トークンを$_SESSIONに格納し、それをキーとする
$_SESSION['key'] = $token;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>お問い合わせフォーム【ajax】</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="contact">
<div class="inner">
<h2 class="contact-title">問い合わせフォーム</h2>
<form class="contact-form">
<ul class="contact-form-list">
<li class="contact-form-item">
<input type="text" name="name" placeholder="お名前" required>
</li>
<li class="contact-form-item">
<input type="email" name="email" placeholder="メールアドレス" required>
</li>
<li class="contact-form-item">
<textarea name="comment" placeholder="内容" required></textarea>
</li>
<li class="contact-form-item">
<!-- 作成したトークンを次のページに引き継ぐ-->
<input type="hidden" name="token" value="<?= $token ?>">
</li>
<li class="contact-form-item">
<button class='submit' type="submit">送信</button>
</li>
</ul>
</form>
<!-- 送信中に表示するモーダルウィンドウ -->
<div id="modal">
<p>送信中です・・・</p>
</div><!-- /#modal -->
<!-- 結果メッセージ -->
<div id="result"></div><!-- /#result -->
</div><!-- /.inner -->
</div><!-- /#contact -->
<!-- jQueryの読み込み -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="main.js"></script>
</body>
</html>
まずsessionを開始しトークンを作成します。
このトークンを$_SESSIONのキーとして設定します。
さらにこのトークンをinput-type="hidden"でメール送信プログラム(send_mail.php)に送るようにします。
メール送信プログラム(send_mail.php)でセッションのキーとAjaxで送られてきたトークンの照合を行うことで、クロスサイトリクエストフォージェリというセキュリティ上の対策をしています。
AjaxにはjQueryを使うので、その読み込みも忘れないように行います。
main.js(Ajaxによるデータの送受信)
「Ajax」を用いてフォームに入力されたデータをメール送信のプログラムに渡します。
$(function(){
$('.contact-form').submit(function(e) {
//フォームの既定の動作をキャンセルする
e.preventDefault();
//フォームの入力値を変数に格納する
var form_data = $('form').serialize();
//フォームの入力内容をajaxにより送信する
$.ajax ({
url: 'send_mail.php',//送信先のURL
type: 'POST',//POST送信
data: form_data,//送信するデータを指定
timeout: 60000, //タイムアウトの設定
beforeSend: function (xhr, settings) {
//リクエスト送信前にボタンを非活性化する
$('.submit-btn').attr('disabled', true);
//モーダルウィンドウの表示
$('#modal').fadeIn();
},
complete: function(xhr, textStatus) {
//モーダルウィンドウを消す
$('#modal').fadeOut();
//リクエスト送信が完了したら、ボタンの非活性化を解除する
$('.submit-btn').attr('disabled', false);
}
}).done(function(data, textStatus, jqXHR) {
//通信成功時の処理
$('form')[0].reset();//フォームに入力している値をリセット
$('#result').text(data);//send_mail.phpから返ってきたメッセージをHTMLに入れて表示する
}).fail(function(jqXHR, textStatus, errorThrown) {
//通信失敗時の処理
$('#result').text('送信できませんでした');//失敗メッセージをHTMLに入れて表示する
});
});
});
コードに関する細かな説明はコード内の各箇所にコメントとして記載してありますので、そちらをご覧ください。
フォームの入力値は1つ1つ取得しなくてもserializeメソッドを利用することですべての項目の入力値を簡単に取得することができます。
beforeSendには送信前の処理を書くことができるのですが、送信中であることが利用者にわかるようにフォームを覆うモーダルウィンドウを表示する処理を書いています。
送信ボタンをクリックしてAjaxでデーターが送信されるまでにはタイムラグがあります。
送信中であることを示すメッセージやアニメーションを表示させないと
とフォームの利用者は思うでしょう。
ですので送信中であることを利用者にわかってもらうための措置です。
また2重投稿の防止のため、Ajaxリクエストを送信前に送信ボタンを不活性にしてクリックされても2重投稿にならないようにしています。
completeには通信が完了したときの処理が書かれており、モーダルウィンドウをフェードアウトさせ、送信ボタンを活性化させてます。
.doneには通信成功時の処理として、入力内容の消去とsend_mail.phpから受け取ったメッセージの表示。
.failには通信失敗時の処理として失敗メッセージの表示を記述しています。
send_mail.php(入力内容の送信)
「Ajax」で送られてきたデータを受け取ってメールを送信し、送信結果のメッセージをechoで「AJax」に返します。
<?php
session_start();
//このページに直接アクセスした場合は拒否する
if(!isset($_POST['token'])) {
echo '不正なアクセスの可能性があります';
exit;
}
//キーとトークンが一致したら管理者に入力内容がメールで送られる
if($_SESSION['key'] === $_POST['token']) {
$name = $_POST['name'];
$email = $_POST['email'];
$comment = $_POST['comment'];
//メールの送り先
$to = '宛先メールアドレス';
//メールの件名
$subject = $name . 'さんからの入力フォームでの送信です';
//メール本文
$comment = '名前:' . $name . "\r\n\r\n" . 'メールアドレス:' . $email . "\r\n\r\n" . '内容:' . $comment;
//メールヘッダー
$header = 'From: ' . mb_encode_mimeheader($name). ' <' . $email. '>';
//文字化け対策
mb_language('ja');
mb_internal_encoding('UTF-8');
if(mb_send_mail($to, $subject, $comment, $header)) {
echo '送信しました';
} else {
echo '送信に失敗しました';
}
} else {
echo 'キーとトークンが一致しません';
}
まず最初にトークンを持っているかを確認し、持っていなければフォームを経ていないものとみなしてアクセスを拒否します。
次にindex.phpから「Ajax」で運ばれてきたトークンとセッションに格納されているキーを比較します。
これが一致しなければ正当なフォームを経てないものとみなしてメールは送信しません。
「Ajax」で送られてきた問い合わせフォームの各データは、おなじみの$_POST['name属性の値']で取り出すことができます。
フォームのデータを取り出したら、メール送信のためのmb_send_mail関数の各引数にセットすればいいだけです。
このプログラムにより、以下のような感じで入力内容が記載されたメールが管理者に送信されます。
そしてAjaxの成功時の処理が行われ、send_mailから送られたメッセージが表示されます。
デモ
以下のリンク先にデモページを作成しました。
メール送信部分に該当するコードは削除してあります。
ですので送信ボタンをクリックして「送信しました」とメッセージが表示されても実際にはメールは送信されませんのでご安心ください。
何かの参考になれば幸いです
以上が「Ajax」による「問い合わせフォーム」でした。
実際に「問い合わせフォーム」を実装するには、さらに入力値のバリデーション処理なども必要になると思います。
Ajaxを使ったお問い合わせフォームのデータのやり取りの流れの参考になれば幸いです。
ところで「Ajax」ですが「エイジャックス」と呼ぶみたいですね。
僕はずっと「アジャックス」と呼んでいました。
恥ずかしいので、このことはくれぐれもご内密にお願いします。
それでは、またー。