BLOG
【PHP】シンプルなお問い合わせフォームを自作する
【PHP】お問い合わせフォームを自作する
WebサイトやLPを制作する際、必ずと言って良いほど掲載するのが「お問い合わせフォーム」です。
お問い合わせフォームは、顧客やユーザーがサイトのオーナーにアクセスする入口となるため、WebサイトやLPにとって非常に重要と言えます。
その作成方法については色々ありますが、今回はシンプルに自作する方法について解説します。
- できる限りシンプルで軽量なお問い合わせフォームを作りたい
- 静的サイトにお問い合わせフォームを導入したい
- WordPressサイトでプラグインを極力使用したくない
このような方に向けて、PHPを使用してシンプルなお問い合わせフォームを自作するを解説します。
完成版だけ確認したい方は、GitHubで確認可能です。
お問い合わせフォームの作成手順
まず始めに、お問い合わせフォームの作成手順を示しておきます。
- HTML形式でお問い合わせフォームの雛形を作成する
- HTML形式で確認画面と送信完了画面を作成する
- 自動返信メール及び通知メール機能を実装する
- フォームの入力値にバリデーションを設定する
- 多重送信を防ぐためにセッションを管理する
今回作成するお問い合わせフォームの仕様としては、
・入力内容確認画面の表示
・管理者への問い合わせ内容通知
・ユーザーに対する自動返信機能
を備えたシンプルなものとなっています。
HTML形式でお問い合わせフォームの雛形を作成する
今回は例として以下のようなお問い合わせフォーム作成します。
名前、メールアドレス、電話番号、問い合わせ内容を入力して送信するシンプルなフォームです。
まず、index.phpというファイルを作成し、以下のコードを記載してお問い合わせフォームの雛形を作成します。
<body>
<h1>お問い合わせフォーム</h1>
<form method="post" action="">
<label>お名前</label>
<input type="text" name="username" value="">
<label>メールアドレス</label>
<input type="email" name="email" value="">
<label>電話番号</label>
<input type="tel" name="tel" value="">
<label>お問い合わせ内容</label>
<textarea rows="7" name="message"></textarea>
<input type="submit" name="confirm" value="確認画面へ">
</form>
</body>
これをCSSでスタイル調整してあげると、上記の画像のようになります。
ここでのポイントは、以下の2つです。
- formタグのmethod属性とaction属性
- inputタグのname属性
それぞれ少し補足説明します。
formタグのmethod属性とaction属性
formタグのmethod属性には、“post”を指定しています。これによりサーバーとPOST通信が行われます。
POST通信とは、データを送信する際に用いられる通信方式です。
この後、ユーザーが送信したお問い合わせフォームに入力された内容を処理するため、POST通信を指定しています。
これと対となるのがGET通信です。
これは、データを取得する際に用いられる通信方式です。
よって、お問い合わせフォーム作成にはGET通信を使いません。
次に、action属性についてですが、上記データの送信先を指定します。
今回は空欄にしているので、お問い合わせフォームの送信ボタンを押せば、このファイル(index.php)が呼ばれます。
この後、このファイル上で全ての処理を完結させるためです。
inputタグのname属性
各入力項目であるinputタグには、name属性を指定します。
自分が分かりやすいよう好きな名前を付けてもらって大丈夫です。
ただし、WordPressで使う際には「予約語」に注意してください。
例えば、“name”はWordPressの予約語のため、name属性に指定するとエラーになります。
予約語の一覧は、以下を参照ください。
参考: Reserved Terms « WordPress Codex
そのため、今回の例では「お名前」のname属性を“name”ではなく、あえて“username”としています。
この後の処理では、このname属性を用いて、お問い合わせフォームに入力された内容を取得します。
HTML形式で確認画面と送信完了画面を作成する
「確認画面へ」ボタンを押した際に表示する「確認画面」と、
その画面で「送信」ボタンを押した際に表示する「送信完了画面」を作成します。
ここで1つポイントです。
先ほど述べた通り、今回はformタグのaction属性を空欄にしているので、お問い合わせフォームの「確認画面へ」または「送信」ボタンを押した際はindex.phpが呼ばれます。
つまり、「確認画面」及び「送信完了画面」は別にファイルを作るのではなく、状況に応じてindex.php上で表示を切り替えます。
(ちなみに、「確認画面」を別ファイルで作りたい場合は、formタグのaction属性にそのファイルを指定することになります。)
状況に応じてindex.php上で表示を切り替える方法と、各画面の作成方法について順に解説します。
状況に応じて表示を切り替える
他のプログラミング言語でもよく行う手法ですが、現在がどのような状況なのかを判別するための変数を用意します。
この変数は「フラグ(Flag)」と呼ばれます。
index.phpに以下の記述を加えます。
<?php
// 変数(フラグ)の初期化
$flag = 0;
// 状況に応じてフラグの切り替え
if(!empty($_POST['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
$flag = 1;
} elseif(!empty($_POST['submit'])) {
// 「送信」ボタンが押された時の処理
$flag = 2;
} else {
$flag = 0;
}
// フラグに応じて表示する画面を切り替え
if($flag === 1) {
// 確認画面のHTMLコード
} elseif($flag === 2) {
// 送信完了画面のHTMLコード
} else {
// お問い合わせフォームのHTMLコード(既に作成済み)
}
?>
「確認画面へ」ボタンが押されるとPOST通信でお問い合わせフォームに入力されたデータが送信されますが、そのデータは$_POSTを使って取得できます。
$_POST['inputタグのname属性']
$_POSTにはPOST通信で送信されたデータが、inputタグのname属性とそのvalue属性で構成される連想配列で格納されています。
よって、「確認画面へ」ボタンが押されると、そのvalue属性である”確認画面へ”が取得されます。
これをempty関数を使ってデータが取得されているかどうかを判別し、if関数により条件分岐させてそれぞれフラグを変更しています。
ちなみに、この段階では「送信」ボタンは未作成なのですが、この後送信ボタンのinputタグのname属性”submit”を指定します。
取得したデータをエスケープ処理する
実は$_POSTで送信されたデータをそのまま使用するのは、セキュリティの関係上好ましくありません。
悪意のある第三者によって、お問い合わせフォームの入力欄に記入されたプラグラムコードが送信され、予期せぬコードが実行される危険性があるためです。
それを防ぐため、$_POSTで送信されたデータにエスケープ処理を施し、たとえプラグラムコードが送信されたとしても、それをコードではなく単なる文字列として処理されるようにします。
WordPressで使用するエスケープ関数esc_html()やesc_url()と本質は同じです。
$esc = array();
if(!empty($_POST)) {
foreach($_POST as $key => $value) {
$esc[$key] = htmlspecialchars($value, ENT_QUOTES);
}
}
エスケープ処理にはhtmlspecialchars関数を使います。
$_POSTには連想配列でデータが格納されているので、それぞれのデータに対してエスケープ処理を行っています。
以上を踏まえてindex.phpを編集すると以下の通りです。
<?php
// 変数(フラグ)の初期化
$flag = 0;
// エスケープ処理後のデータを格納ための変数
$esc = array();
// エスケープ処理
if(!empty($_POST)) {
foreach($_POST as $key => $value) {
$esc[$key] = htmlspecialchars($value, ENT_QUOTES);
}
}
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
$flag = 1;
} elseif(!empty($esc['submit'])) {
// 「送信」ボタンが押された時の処理
$flag = 2;
} else {
$flag = 0;
}
// フラグに応じて表示する画面を切り替え
if($flag === 1) {
// 確認画面のHTMLコード
} elseif($flag === 2) {
// 送信完了画面のHTMLコード
} else {
// お問い合わせフォームのHTMLコード(既に作成済み)
}
?>
確認画面と送信完了画面を作成する
フラグに応じて確認画面と送信完了画面の表示を切り替えるので、index.phpの該当箇所にそれぞれの画面を構成するHTMLコードを追記します。
ここまでのコードを全てまとめると以下の通りです。
<body>
<h1>お問い合わせフォーム</h1>
<?php
// 変数(フラグ)の初期化
$flag = 0;
// エスケープ処理後のデータを格納ための変数
$esc = array();
// エスケープ処理
if(!empty($_POST)) {
foreach($_POST as $key => $value) {
$esc[$key] = htmlspecialchars($value, ENT_QUOTES);
}
}
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
$flag = 1;
} elseif(!empty($esc['submit'])) {
// 「送信」ボタンが押された時の処理
$flag = 2;
} else {
$flag = 0;
}
// フラグに応じて表示する画面を切り替え
if($flag === 1) {
// 確認画面のHTMLコード
?>
<form method="post" action="">
<label>お名前</label>
<p><?php echo $esc['username'] ?></p>
<label>メールアドレス</label>
<p><?php echo $esc['email'] ?></p>
<label>電話番号</label>
<p><?php echo $esc['tel'] ?></p>
<label>お問い合わせ内容</label>
<p><?php echo $esc['message'] ?></p>
<input type="submit" name="back" value="戻る">
<input type="submit" name="submit" value="送信">
<!-- データを受け渡すために一時的に保存 -->
<input type="hidden" name="username" value="<?php echo $esc['username'] ?>">
<input type="hidden" name="email" value="<?php echo $esc['email'] ?>">
<input type="hidden" name="tel" value="<?php echo $esc['tel'] ?>">
<input type="hidden" name="message" value="<?php echo $esc['message'] ?>">
</form>
<?php
} elseif($flag === 2) {
// 送信完了画面のHTMLコード
?>
<p>送信が完了しました。</p>
<?php
} else {
// お問い合わせフォームのHTMLコード
?>
<form method="post" action="">
<label>お名前</label>
<input type="text" name="username" value="">
<label>メールアドレス</label>
<input type="email" name="email" value="">
<label>電話番号</label>
<input type="tel" name="tel" value="">
<label>お問い合わせ内容</label>
<textarea rows="7" name="message"></textarea>
<input type="submit" name="confirm" value="確認画面へ">
</form>
<?php
}
?>
</body>
送信されたデータをエスケープ処理した後、確認画面ではそれを出力しています。
送信ボタンのinputタグのname属性には忘れず“submit”を指定します。
確認画面のHTMLコードの中に「データを受け渡すために一時的に保存」と書いて、各データをvalue属性に代入している記述があります。
これは、送信完了画面に移った後にメール作成等にデータを使うためです。
後に使うデータを一時的に保存していると考えてもらってOKです。
ユーザーからは見えないようinputタグをtype=”hidden”としています。
こうしてできた各画面をCSSでスタイルを整えると画像のようになります。
入力内容確認画面
送信完了画面
入力した内容を引き継がせる
実はこの状態だと、「戻る」ボタンを押して入力フォームへ戻った際、入力していた内容が全て消え空欄になってしまいます。
これまでに入力した内容が反映されるようindex.phpのお問い合わせフォームを構成する部分に対策を施します。
<?php
// ~~ 省略 ~~
// お問い合わせフォームのHTMLコード
?>
<form method="post" action="">
<label>お名前</label>
<input type="text" name="username" value="<?php if(!empty($esc['username'])) {echo $esc['username'];} ?>">
<label>メールアドレス</label>
<input type="email" name="email" value="<?php if(!empty($esc['email'])) {echo $esc['email'];} ?>">
<label>電話番号</label>
<input type="tel" name="tel" value="<?php if(!empty($esc['tel'])) {echo $esc['tel'];} ?>">
<label>お問い合わせ内容</label>
<textarea rows="7" name="message"><?php if(!empty($esc['message'])) {echo $esc['message'];} ?></textarea>
<input type="submit" name="confirm" value="確認画面へ">
</form>
<?php
}
// ~~ 省略 ~~
?>
各入力項目であるinputタグのvalue属性に、「送信されたデータがあればそれを代入する」という処理を加えています。
これにより、「戻る」ボタンを押して入力フォームに戻った際に、これまでに入力していた内容が初期値として入力欄に表示されるようになります。
自動返信メール及び通知メール機能を実装する
「送信」ボタンが押された際に、ユーザーに対して自動返信メールを送信する機能と、管理者に対して問い合わせがあった旨の通知メールを送信する機能を実装します。
メールを送信するためには、mb_send_mail関数を使います。
mb_send_mail(送信先, 件名, 本文, ヘッダー情報);
第一引数に送信先、第二引数に件名、第三引数に本文、第四引数にヘッダー情報を取ります。
(今回はこれだけ押さえておけばOKです。詳細な仕様を知りたい人は自分で調べてみてください。)
ちなみに、ヘッダー情報とはメールの送信元の情報のことです。
実際に使っているところを見た方が分かりやすいので、自動返信メール機能と通知メール機能それぞれの実装していきます。
自動返信メール機能を作成する
「送信」ボタンが押されたら自動返信メールを送信したいので、「送信」ボタンが押された時($flag=2の時)の処理に追記していきます。
// ~~ 省略 ~~
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
$flag = 1;
} elseif(!empty($esc['submit'])) {
// 「送信」ボタンが押された時の処理
$flag = 2;
// タイムゾーンの設定
date_default_timezone_set('Asia/Tokyo');
// 使用言語(日本語)の設定
mb_language("ja");
mb_internal_encoding("UTF-8");
// 自動返信メール件名
$reply_subject = "お問い合わせいただきありがとうございます";
// 自動返信メール本文
$reply_text = "下記の内容でお問い合わせを受け付けました。"."\n\n";
$reply_text .= "お問い合わせ受付日時:".date('Y-m-d H:i')."\n";
$reply_text .= "お名前:".$esc['username']."\n";
$reply_text .= "メールアドレス:".$esc['email']."\n";
$reply_text .= "電話番号:".$esc['tel']."\n";
$reply_text .= "お問い合わせ内容:".$esc['message']."\n\n";
$reply_text .= "Color Piece管理人";
// 自動返信メールヘッダー情報
$header = "MIME-Version: 1.0\n";
$header .= "From: Color Piece <XXX@color-piece.com>\n";
$header .= "Reply-To: Color Piece <XXX@color-piece.com>\n";
// 自動返信メールの送信
mb_send_mail($esc['email'], $reply_subject, $reply_text, $header);
} else {
$flag = 0;
}
// ~~ 省略 ~~
いくつかコードについて簡単に解説します。
date_default_timezone_set('Asia/Tokyo');
自動返信メールの本分内にお問い合わせ受け付け日時を記載するために、タイムゾーンを日本に設定しています。
mb_language("ja");
mb_internal_encoding("UTF-8");
自動返信メールで日本語を使用するために設定しています。
また、ヘッダー情報には自動返信メールの送信元としたいメールアドレスと表示名を指定します。
基本的にはお問い合わせフォームを設置するサイトのドメインと同じドメインのメールアカウントを指定しましょう。自動返信メールがスパムメールとして取り扱われにくくなり、ユーザーに届く可能性がぐっと上がります。
通知メール機能を作成する
自動返信メールとやることはほぼ同じです。
先ほどの自動返信メールを送信するコードの続きに以下を追記します。
// ~~ 省略 ~~
// 管理者通知メールの件名
$notice_subject = "ホームページからメッセージがありました";
// 管理者通知メールの本文
$notice_text = "下記の内容でお問い合わせを受け付けました。"."\n\n";
$notice_text .= "お問い合わせ受付日時:".date('Y-m-d H:i')."\n";
$notice_text .= "お名前:".$esc['username']."\n";
$notice_text .= "メールアドレス:".$esc['email']."\n";
$notice_text .= "電話番号:".$esc['tel']."\n";
$notice_text .= "お問い合わせ内容:".$esc['message']."\n";
// 管理者通知メールの送信
mb_send_mail('XXX@color-piece.com', $notice_subject, $notice_text, $header);
// ~~ 省略 ~~
管理者通知メールのヘッダー情報は、自動返信メールのものを再利用しています。
mb_send_mail関数の第一引数には、管理者通知メールを受信したい自分の好きなメールアドレスを指定します。
フォームの入力値にバリデーションを設定する
バリデーション(validation)とは、フォームに正しいデータが入力されているか確認することです。
現状のお問い合わせフォームでは、全て空欄でも送信できてしまいます。
お問い合わせ機能だけが欲しい場合にはバリデーション機能は不要ですが、スパムや誤送信を防止するために搭載することをおすすめします。
バリデーション機能を作成する
今回は、「お名前」「メールアドレス」「お問い合わせ内容」を入力必須項目とし、もし空欄の場合には「入力内容確認画面」へ遷移しないようバリデーションを設定します。
電話番号については入力は任意とし、空欄でも問題なく送信できるようにします。
またメールアドレスについては、それが正しい形式(英数字 + @ + ドメイン)になっているかも併せてチェックします。
// ~~ 省略 ~~
// バリデーションエラーを格納するための変数
$error = array();
// バリデーション関数
function validation($data) {
$error = array();
if(empty($data['username'])) {
$error[] = "「お名前」を入力してください";
}
if(empty($data['email'])) {
$error[] = "「メールアドレス」を入力してください";
} elseif(!preg_match('/^[0-9a-z_.\/?-]+@([0-9a-z-]+\.)+[0-9a-z-]+$/', $data['email'])) {
$error[] = "「メールアドレス」は正しい形式で入力してください";
}
if(empty($data['message'])) {
$error[] = "「お問い合わせ内容」を入力してください";
}
return $error;
}
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
//バリデーション
$error = validation($esc);
if(empty($error)) {
$flag = 1;
}
}
// ~~ 省略 ~~
バリデーションを行うための関数validationを用意し、「確認画面へ」ボタンが押された時にそれ実行します。
メールアドレスの形式チェックに関しては、暗号のような文字列が並んでいますがコピペでOKです。「英数字 + @ + ドメイン」の形式で入力されているか判別しているだけなので。
もし入力漏れ等があれば、変数$errorにエラーメッセージが格納されます。
この後、このエラーメッセージが画面を表示し、ユーザーにエラーを認知させるための処理を記述していきます。
入力エラーメッセージを表示する
index.phpのお問い合わせフォームのHTMLコードを記述している箇所のformタグの直前に、先ほど取得した入力エラーメッセージを表示させます。
<?php
// ~~ 省略 ~~
// お問い合わせフォームのHTMLコード
if(!empty($error)) {
?>
<ul>
<?php foreach($error as $value) { ?>
<li><?php echo $value; ?></li>
<?php } ?>
</ul>
<?php
}
// ~~ 省略 ~~
?>
また、どれが入力必須項目かユーザーが一目で分かるよう、お問い合わせフォームにその旨を記載した方が親切でしょう。
CSSでスタイルを調整すると、エラーメッセージは以下のように表示されます。
多重送信を防ぐためにセッションを管理する
まず多重送信とは、送信完了画面での再読み込みや、送信ボタンの連打によって、同じ入力内容のデータが複数回送信されてしまうという一種のエラーのことです。
これを防止するために、サーバーにユーザーが行ったアクションを記録させ、適切なルートが取られた時のみフォームの送信を許可するような処理を追加します。
この時に用いるのがセッションと呼ばれるもので、サーバーにデータを保存する仕組みのことです。
確認画面でセッションを開始する
入力内容確認画面にて、以下のコードでセッションを開始します。
session_start();
入力確認画面が表示されたことをサーバーに記録するため、セッション変数を定義します。
$_SESSION['変数名'] = 代入したい値
変数名と代入する値は何でも良いですが、今回は変数名”page”にBoolean型の”true”を代入します。
// ~~ 省略 ~~
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
//バリデーション
$error = validation($esc);
if(empty($error)) {
$flag = 1;
// セッション開始
session_start();
$_SESSION['page'] = true;
}
}
// ~~ 省略 ~~
送信完了画面でセッション変数を削除する
先ほど定義したセッションを保持した状態で送信完了画面に来た場合、それは適切なルートを辿っていることを意味するので、定義したセッション変数を削除後メール送信等の処理を行います。
何らかの理由で入力確認画面をスキップして送信完了画面に到達しようとする場合には、セッション変数が定義されていないため最初のフォーム入力画面に遷移します。
また、適切なルートを辿って送信完了画面に来た時点でセッション変数を削除するので、ページの再読み込みが行われたとしても最初のフォーム入力画面に遷移します。
// ~~ 省略 ~~
// 状況に応じてフラグの切り替え
if(!empty($esc['confirm'])) {
// 「確認画面へ」ボタンが押された時の処理
//バリデーション
$error = validation($esc);
if(empty($error)) {
$flag = 1;
// セッション開始
session_start();
$_SESSION['page'] = true;
}
} elseif(!empty($esc['submit'])) {
session_start();
if(!empty($_SESSION['page']) && $_SESSION['page'] === true) {
// セッション削除
unset($_SESSION['page']);
// 「送信」ボタンが押された時の処理
$flag = 2;
// ~~ 省略 ~~
} else {
$flag = 0;
}
} else {
$flag = 0;
}
// ~~ 省略 ~~
「セッション変数が空ではない」かつ「セッション変数’page’の中身がtrueである」という条件が満たされた場合のみ、「送信」ボタンが押された時の処理(メールの送信など)が行われます。
それ以外の場合は、フラグ$flag = 0となり、フォームの入力画面に戻ります。
おわりに
ここまでのコードを全てまとめたファイルは、配布ページ及びGitHubに置いています。
今回は全てのコードをindex.phpに記述していますが、「お問合せフォームの処理に関する部分のみ別ファイルで管理したい」という場合もあるでしょう。
また、ページの途中にお問合せフォームがあり、確認画面や送信完了画面に遷移した際に、ページトップではなくお問い合わせフォームの位置に自動スクロールして欲しいということもあります。
それらの方法については、別記事にまとめていますのでご参照ください。
そして、WordPressサイトの場合は、手間の掛からないプラグインを使うのもおすすめです。
おすすめは「Contact Form 7」です。
使い方の解説記事はこちらからどうぞ。
ご質問はお問い合わせフォームからどうぞ!