フォルダ構成
├── 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');
.htaccess
deny from all
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も読み込む */