フォルダ構成
├── contact
│ ├── contact.php
│ └── style.css
└── libs
├── .htaccesss
├── functions.php
├── recaptchavars.php
└── mailvars.php
contact.php
<?php
//エスケープ処理やデータチェックを行う関数のファイルの読み込み
require '../libs/functions.php';
//reCAPTCHA
require '../libs/recaptchavars.php';
// reCAPTCHA サイトキー
$siteKey = V2_SITEKEY;
// reCAPTCHA シークレットキー
$secretKey = V2_SECRETKEY;
//POSTされたがあればデータを変数に格納(変数の初期化)
$name = isset( $_POST[ 'name' ] ) ? $_POST[ 'name' ] : NULL;
$email = isset( $_POST[ 'email' ] ) ? $_POST[ 'email' ] : NULL;
$subject = isset( $_POST[ 'subject' ] ) ? $_POST[ 'subject' ] : NULL;
$body = isset( $_POST[ 'body' ] ) ? $_POST[ 'body' ] : NULL;
//reCAPTCHA 検証結果の真偽値の初期化
$result_status = false;
//送信ボタンが押された場合の処理
if (isset($_POST['submitted'])) {
//POSTされたデータに不正な値がないかを検証
$_POST = checkInput( $_POST );
//トークン(g-recaptcha-response )が生成されていれば
if ( isset( $_POST[ 'g-recaptcha-response' ] ) ) {
//cURL セッションを初期化
$ch = curl_init();
// curl_setopt() により転送時のオプションを設定
//API の URL の指定
curl_setopt($ch, CURLOPT_URL,"https://www.google.com/recaptcha/api/siteverify");
//HTTP POST メソッドを使う
curl_setopt($ch, CURLOPT_POST, true );
//API パラメータの指定
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'secret' => $secretKey,
'response' => $_POST[ 'g-recaptcha-response' ]
)));
//curl_execの返り値を文字列にする
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//転送を実行してレスポンスを $json に格納
$json = curl_exec($ch);
//セッションを終了
curl_close($ch);
//レスポンスの $json(JSON形式)をデコード
$rc_result = json_decode( $json );
//reCAPTCHA 検証結果の真偽値
$result_status = $rc_result->success ;
}
//reCAPTCHA 検証エラーフラグ(エラーメッセージの表示で使用)
if(!$result_status) {
$recaptcha_error = true;
}
//filter_var を使って値をフィルタリング
if(isset($_POST['name'])) {
//スクリプトタグがあれば除去
$name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
}
if(isset($_POST['email'])) {
//全ての改行文字を削除
$email = str_replace(array("\r", "\n", "%0a", "%0d"), '', $_POST['email']);
//E-mail の形式にフィルタ
$email = filter_var($email, FILTER_VALIDATE_EMAIL);
}
if(isset($_POST['subject'])) {
$subject = filter_var($_POST['subject'], FILTER_SANITIZE_STRING);
}
if(isset($_POST['body'])) {
$body = filter_var($_POST['body'], FILTER_SANITIZE_STRING);
}
//POST でのリクエストの場合で且つ reCAPTCHA の検証($result_status)が true の場合
if ($_SERVER['REQUEST_METHOD']==='POST' && $result_status) {
//メールアドレス等を記述したファイルの読み込み
require '../libs/mailvars.php';
//メール本文の組み立て。値は h() でエスケープ処理
$mail_body = 'コンタクトページからのお問い合わせ' . "\n\n";
$mail_body .= "お名前: " .h($name) . "\n";
$mail_body .= "Email: " . h($email) . "\n" ;
$mail_body .= "<お問い合わせ内容>" . "\n" . h($body);
//--------sendmailを使ったメールの送信処理------------
//メールの宛先(名前<メールアドレス> の形式)。値は mailvars.php に記載
$mailTo = mb_encode_mimeheader(MAIL_TO_NAME) ."<" . MAIL_TO. ">";
//Return-Pathに指定するメールアドレス
$returnMail = MAIL_RETURN_PATH; //
//mbstringの日本語設定
mb_language( 'ja' );
mb_internal_encoding( 'UTF-8' );
// 送信者情報(From ヘッダー)の設定
$header = "From: " . mb_encode_mimeheader($name) ."<" . $email. ">\n";
$header .= "Cc: " . mb_encode_mimeheader(MAIL_CC_NAME) ."<" . MAIL_CC.">\n";
$header .= "Bcc: <" . MAIL_BCC.">";
//メールの送信結果を変数に代入
if ( ini_get( 'safe_mode' ) ) {
//セーフモードがOnの場合は第5引数が使えない
$result = mb_send_mail( $mailTo, $subject, $mail_body, $header );
} else {
$result = mb_send_mail( $mailTo, $subject, $mail_body, $header, '-f' . $returnMail );
}
//メールが送信された場合の処理
if ( $result ) {
//空の配列を代入し、すべてのPOST変数を消去
$_POST = array();
//変数の値も初期化
$name = '';
$email = '';
$subject = '';
$body = '';
//再読み込みによる二重送信の防止
$params = '?result='. $result;
$url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://').$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
header('Location:' . $url . $params);
exit;
}
}
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>コンタクトフォーム</title>
<link href="../bootstrap.min.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h2>お問い合わせフォーム</h2>
<?php if (isset( $recaptcha_error ) && $recaptcha_error ): ?>
<p><span class="error">検証が失敗しました。申し訳ございませんがメールまたは電話にてご連絡ください。</span></p>
<?php endif; ?>
<?php if ( isset($_GET['result']) && $_GET['result'] ) : // 送信が成功した場合?>
<h4>送信完了!</h4>
<p>送信完了いたしました。</p>
<hr>
<?php elseif (isset($result) && !$result ): // 送信が失敗した場合 ?>
<h4>送信失敗</h4>
<p>申し訳ございませんが、送信に失敗しました。</p>
<p>しばらくしてもう一度お試しになるか、メールにてご連絡ください。</p>
<p>メール:<a href="mailto:info@example.com">Contact</a></p>
<hr>
<?php endif; ?>
<p>以下のフォームからお問い合わせください。</p>
<form id="form" method="post">
<div class="form-group">
<label for="name">お名前(必須)</label>
<input type="text" class="form-control" id="name" name="name" placeholder="氏名" required value="<?php echo h($name); ?>">
</div>
<div class="form-group">
<label for="email">Email(必須)</label>
<input type="email" class="form-control" id="email" name="email" placeholder="Email アドレス" required value="<?php echo h($email); ?>">
</div>
<div class="form-group">
<label for="subject">件名(必須)</label>
<input type="text" class="form-control" id="subject" name="subject" placeholder="件名" required value="<?php echo h($subject); ?>">
</div>
<div class="form-group">
<label for="body">お問い合わせ内容(必須)</label>
<textarea class="form-control" id="body" name="body" placeholder="お問い合わせ内容をお書きください" required rows="3"><?php echo h($body); ?></textarea>
</div>
<div id="recaptcha"></div><!-- reCAPTCHA を表示する要素 -->
<p id="warning">送信するにはチェックを入れてください。</p>
<button id="send" disabled name="submitted" type="submit" class="btn btn-primary">送信</button><!-- id(#send)と disabled 属性を指定 -->
</form>
</div>
<script>
var onloadCallback = function() {
//ウィジェットを表示するメソッド
grecaptcha.render('recaptcha', {
'sitekey' : "<?php echo $siteKey; ?>",
'callback' : verifyCallback,
'expired-callback' : expiredCallback
});
};
//チェックを入れて成功した場合に呼び出されるコールバック関数
var verifyCallback = function(response) { //コールバック関数の定義
//#warning の p 要素のテキストを空にf
document.getElementById("warning").textContent = '';
//#send の button 要素の disabled 属性を解除
document.getElementById("send").disabled = false;
};
//期限切れの場合に呼び出されるコールバック関数
var expiredCallback = function() { //コールバック関数の定義
//#warning の p 要素のテキストに文字列を設定
document.getElementById("warning").textContent = '送信するにはチェックを入れてください。';
//#send の button 要素に disabled 属性を設定
document.getElementById("send").disabled = true;
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
</body>
</html>
functions.php
<?php
//エスケープ処理を行う関数
function h($var) {
if(is_array($var)){
//$varが配列の場合、h()関数をそれぞれの要素について呼び出す(再帰)
return array_map('h', $var);
}else{
return htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
}
}
//入力値に不正なデータがないかなどをチェックする関数
function checkInput($var){
if(is_array($var)){
return array_map('checkInput', $var);
}else{
//NULLバイト攻撃対策
if(preg_match('/\0/', $var)){
die('不正な入力です。');
}
//文字エンコードのチェック
if(!mb_check_encoding($var, 'UTF-8')){
die('不正な入力です。');
}
//改行、タブ以外の制御文字のチェック
if(preg_match('/\A[\r\n\t[:^cntrl:]]*\z/u', $var) === 0){
die('不正な入力です。制御文字は使用できません。');
}
return $var;
}
}
mailvars.php
<?php
//メールの宛先(To)のメールアドレス
define('MAIL_TO', "xxxx@xxxxx.com");
//メールの宛先(To)の名前
define('MAIL_TO_NAME', "xxx xxx xxx");
//Cc の名前
define('MAIL_CC', 'xxxx@xxxxxx.com');
//Cc の名前
define('MAIL_CC_NAME', 'xxxxxx');
//Bcc
define('MAIL_BCC', 'xxxxx@xxxxx.com');
//Return-Pathに指定するメールアドレス
define('MAIL_RETURN_PATH', 'xxxxx@xxxxx.com');
//自動返信の返信先名前
define('AUTO_REPLY_NAME', 'xxxx xxxx xxxx');
recaptchavars.php
<?php
// reCAPTCHA v2 サイトキー
define('V2_SITEKEY', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
// reCAPTCHA v2 シークレットキー
define('V2_SECRETKEY', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx');
style.css
@charset "utf-8";
.container {
width: 100%;
max-width: 760px;
margin: 50px auto;
}
/* input 要素 */
#name, #email, #subject, #email_check, #tel {
max-width:400px;
}
#body {
max-width: 640px;
}
/* エラー表示 */
p.error, span.error {
color: red;
}
/* フォーム要素(Bootstrap4 のスタイルを上書き) */
.form-control {
border-radius: 0px;
background-color: #fdfdfd;
font-size: 14px;
}
.form-control:focus {
border-color: #aadbe8;
outline: 0;
-webkit-box-shadow: inset 0 0px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.4);
box-shadow: inset 0 0px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.4);
background-color:#fff;
}
/* Google Chrome, Safari, Opera 15+, Android, iOS */
::-webkit-input-placeholder {
font-size: 13px;
}
/* Firefox 18- */
:-moz-placeholder {
font-size: 13px; }
/* Firefox 19+ */
::-moz-placeholder {
font-size: 13px; }
/* IE 10+ */
:-ms-input-placeholder {
font-size: 13px; }
::placeholder{
font-size: 13px;
}
textarea.form-control {
height: 200px;
}
#send {
margin-top: 30px;
}
/* この他に Bootstrap4 のCSSも読み込む */