PHPでフォームを作成する基本



##フォームの基本

- 入力画面
- 確認画面
- 完了画面

index.php　→　confirm.php　→　thanks.php
と作る場合が多い

その場合、formのaction属性をそれぞれの飛び先に指定する


##入力フォーム

```php


    <form method="post" action=""> <?php //送信先が空なので、自分自身（index.php）を再度呼び出す
                                    ?>
      <div class="element_wrap">
        <label>氏名</label>
        <input type="text" name="your_name" value="<?php if (!empty($_POST['your_name'])) {
                                                      echo $_POST['your_name'];
                                                    } ?>">
        <!-- POSTパラメータが空じゃない場合のみvalue属性にセット -->
      </div>
      <div class="element_wrap">
        <label>メールアドレス</label>
        <input type="mail" name="email" value="<?php if (!empty($_POST['email'])) {
                                                  echo $_POST['email'];
                                                } ?>">
      </div>
      <div class="element_wrap">
        <label>性別</label>
        <label for="gender_male"><input id="gender_male" type="radio" name="gender" value="male">男性</label>
        <label for="gender_female"><input id="gender_female" type="radio" name="gender" value="female">女性</label>
      </div>
      <div class="element_wrap">
        <label>年齢</label>
        <select name="age">
          <option value="">選択してください</option>
          <option value="1">〜19歳</option>
          <option value="2">20歳〜29歳</option>
          <option value="3">30歳〜39歳</option>
          <option value="4">40歳〜49歳</option>
          <option value="5">50歳〜59歳</option>
          <option value="6">60歳〜</option>
        </select>
      </div>
      <div class="element_wrap">
        <label>お問い合わせ内容</label>
        <textarea name="contact"></textarea>
      </div>
      <div class="element_wrap">
        <label for="agreement"><input id="agreement" type="checkbox" name="agreement" value="1">プライバシーポリシーに同意する</label>
      </div>
      <input type="submit" name="btn_confirm" value="入力内容を確認する">
    </form>


```

##確認ページ

```php


    <form method="post" action="">
      <div class="element_wrap">
        <label>氏名</label>
        <p><?php echo $_POST['your_name']; ?></p>
      </div>
      <div class="element_wrap">
        <label>メールアドレス</label>
        <p><?php echo $_POST['email']; ?></p>
      </div>
      <div class="element_wrap">
        <label>性別</label>
        <p><?php if($_POST['gender'] === "male" ){ echo '男性'; } else {echo '女性' ; }?></p>
      </div>
      <div class="element_wrap">
        <label>年齢</label>
        <p>
          <?php if( $_POST['age'] === "1") {
            echo '〜19歳';
          }elseif($_POST['age'] === "2") {
            echo '20歳〜29歳';
            }elseif($_POST['age'] === "3") {
            echo '30歳〜39歳';
            }elseif($_POST['age'] === "4"){
            echo '40歳〜49歳';
            }elseif($_POST['age'] === "5"){
            echo '50歳〜59歳';
            }elseif($_POST['age'] === "6"){
            echo '60歳〜';
            }
          ?>
        </p>
      </div>
      <div class="element_wrap">
        <label>お問い合わせ内容</label>
        <p><?php echo nl2br($_POST['contact']); ?></p>
      </div>
      <div class="element_wrap">
        <p>
          <?php
          if($_POST['agreement'] === "1") {
            echo '同意する';
          } else {
            echo '同意しない';
          }
          ?>
        </p>
      </div>
      <!-- 入力値の受け渡し用 -->
      <input type="submit" name="btn_back" value="戻る">
      <input type="submit" name="btn_submit" value="送信">
      <input type="hidden" name="your_name" value="<?php echo $_POST['your_name']; ?>">
      <input type="hidden" name="email" value="<?php echo $_POST['email']; ?>">
      <input type="hidden" name="gender" value="<?php echo $_POST['gender']; ?>">
      <input type="hidden" name="age" value="<?php echo $_POST['age']; ?>">
      <input type="hidden" name="contact" value="<?php echo $_POST['contact']; ?>">
      <input type="hidden" name="agreement" value="<?php echo $_POST['agreement']; ?>">
    </form>

```

##ページの切り替え

```php
    <form method="post" action=""> <?php //送信先が空なので、自分自身（index.php）を再度呼び出す
```
formがこうなっているので、自分自身を再び呼び出している。

そのため、別ファイルに記述するのではなく、同じファイルに全ての内容を記述していく。


（ただし、action="confirm.php"とした場合は、しっかり別ファイルが必要になるので注意）


##ページの切り替え方法

```php


/*---------------------------------------
    ページ切り替え
-----------------------------------------*/

$page_flag = 0;

if (!empty($_POST['btn_confirm'])) {
  //$_POST[‘btn_confirm’]の値が渡されているか確認
  $page_flag  = 1;
} elseif (!empty($_POST['btn_submit'])) {
  //$_POST[‘btn_submit’]の値が渡されているか確認
  $page_flag = 2;
}
//入力ページや確認ページの表示をスイッチするフラグになる
//$_POST[‘btn_confirm’]があれば、確認ページへ進む

//[0]入力
//[1]確認
//[2]完了

```


どのボタンが押されたかによって、フラグを立て、
条件分岐させている

例えば、

```php
<input type="submit" name="btn_confirm" value="入力内容を確認する">
```

コレだと、`$_POST['btn_submit']`が送信されるため、`$page_flag`には1が入る。



フォーム記載欄に、下記のように条件分岐させればオッケー。


```php

  <?php if ($page_flag === 1) : //確認ページの内容 ?>

  <?php elseif ($page_flag === 2) : //完了ページの内容 ?>

    <p>送信が完了しました</p>

  <?php else : //入力ページの内容 ?>

  <?php endif; ?>


```



##メール送信機能

```php


/*---------------------------------------
    メール送信機能

// 変数の設定
$to = "testtaro@gray-code.com";
$subject = "メール送信のテスト";
$text = "メール本文です。";

// メール送信
mb_send_mail( $to, $subject, $text);
-----------------------------------------*/

//変数とタイムゾーン
$header = null; //メールの件名に入る文字列
$auto_reply_subject = null;
$auto_reply_text = null;
date_default_timezone_set('Asia/Tokyo');

// ヘッダー情報を設定
$header = "MIME-Version: 1.0\n";
$header .= "From: GRAYCODE <noreply@gray-code.com>\n";
$header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

//件名を設定
$auto_reply_subject = 'お問い合わせありがとうございます';

//本文設定
$auto_reply_text = "この度はお問い合わせありがとうございます。下記の内容でお問い合わせを受け付けました。\n\n";
$auto_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
$auto_reply_text .= "氏名:" . $_POST['your_name'] . "\n";
$auto_reply_text .= "メールアドレス:" . $_POST['email'] . "\n\n";
$auto_reply_text .= "CODE株式会社";

//メール送信
mb_send_mail($_POST['email'], $auto_reply_subject, $auto_reply_text);


/**--------運営者側へ送るメール */

// 運営側へ送るメールの件名
$admin_reply_subject = "お問い合わせを受け付けました";

// 本文を設定
$admin_reply_text = "下記の内容でお問い合わせがありました。\n\n";
$admin_reply_text .= "お問い合わせ日時：" . date("Y-m-d H:i") . "\n";
$admin_reply_text .= "氏名：" . $_POST['your_name'] . "\n";
$admin_reply_text .= "メールアドレス：" . $_POST['email'] . "\n\n";

// 運営側へメール送信
mb_send_mail('webmaster@gray-code.com', $admin_reply_subject, $admin_reply_text, $header);


?>
```



##入力値のサニタイズ
セキュリティ対策の一つ「入力値のサニタイズ」

フォームにHTMLやJSなどのプログラミングコードを入力しても実行されてないようにする。

→無効化したテキストデータにする

`hemlspecialchars($string,$flags,$encodinf,$h_flag)`

- `$string`　対象となる文字列
- `$flags`　エンコードのフラグ
- `$encodinf`　文字コード
-`$h_flag`　HTMl変換フラグ


HTMLエンティティへ変換し、無効化することができる。
（HTMLエンティティとは、文字列の素の姿）


[htmlspecialchars](http://php.net/manual/ja/function.htmlspecialchars.php)

###フォームにサニタイズを実装する


```php
$clean = array();

//サニタイズ
if (!empty($_POST)) {
  foreach ($_POST as $key => $value) {
    $clean[$key] = htmlspecialchars($value, ENT_QUOTES);
  }
}

```

POSTパラメータが存在するかを判断、
そもそもPOSTがなかったら、サニタイズも必要ないので、ifで条件分岐させる

foreachでPOSTパラメータを配列ごと渡して、入力値を１つずつ取り出してサニタイズする。
その後、値を$cleanに格納


サニタイズされた入力値は$cleanに入っているので、$cleanの配列から値を取り出すように変更すればOK


##バリデーション

- 氏名 – 未入力チェック、文字の長さチェック
- メールアドレス – 未入力チェック、形式チェック
- 性別 – 未入力チェック、形式チェック
- 年齢 – 未入力チェック、形式チェック
- お問い合わせ内容 – 未入力チェック
- プライバシーポリシーに同意 – 未入力チェック、形式チェック

さらに、「未入力チェック」は全項目に用意する


###未入力チェック

```php

$error = array();

if (!empty($clean['btn_confirm'])) {
  //$_POST[‘btn_confirm’]の値が渡されているか確認

  $error = validation($clean);

  if( empty($error)) {
    $page_flag  = 1;
  }


function validation($data) {
  $error = array();

  //氏名のバリデーション
  if( empty($data['your_name'])) {
    $error[] = "氏名は必ず入力して下さい";
  }
  return $error;
}

```

バリデーション用にvalidation関数を用意
関数の返り血でエラーが合ったかどうかを判断する。

empty関数で、入力がない場合、$errorへメッセージを追加


```php
  $error = validation($clean);

  if( empty($error)) {
    $page_flag  = 1;
  }
```

エラーが見つからない場合は、$page_flagに１を設定し、ページを確認ページに切り替える


###エラーメッセージの表示

```php

  <?php if (!empty($error)) { ?>
  <ul class="error_list">
    <?php foreach ($error as $value) : ?>
    <li><?php echo $value; ?></li>
    <?php endforeach; ?>
  </ul>
  <?php } ?>
```

ここはもう簡単で、
emptyで$errorがあるかを判断して出力するだけ。

$errorは配列なので、foreachでループして出力する



###入力値の長さ（文字数）を調べる

```php
  if (empty($data['your_name'])) {
    $error[] = "氏名は必ず入力して下さい";
  } elseif( 20 < mb_strlen($data['your_name'])) {
    $error[] = "指名は20文字以内で入力して下さい";
  }
```

`mb_strlen`は、引数で渡した文字列の長さを返す


###アドレスの形式を調べる

```php

  if (empty($data['email'])) {
    $error[] = "メールアドレスは必ず入力して下さい";
  } elseif( !preg_match( '/^[0-9a-z_.\/?]+@([0-9a-z-]+\.)+[0-9a-z-]+$/',$data['email'])) {
    $error[] = "メールアドレスは正しい形式で入力して下さい";
  }
```

[メールアドレス正規表現](http://phpspot.net/php/pg%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE%EF%BC%9A%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E8%AA%BF%E3%81%B9%E3%82%8B.html)


###特定の値が入力されているかを調べる

```php

  if (empty($data['gender'])) {
    $error[] = "性別は必ず入力して下さい";
  } elseif( $data['gender'] !== 'male' && $data['gender'] !=='female') {
    $error[] = "性別は必ず入力して下さい";
  }
```

ラジオボタンなど、いずれかの入力が必須の場合

###特定の範囲が入力されているか調べる

```php
// 年齢のバリデーション
if( empty($data['age']) ) {
	$error[] = "「年齢」は必ず入力してください。";

} elseif( (int)$data['age'] < 1 || 6 < (int)$data['age'] ) {
	$error[] = "「年齢」は必ず入力してください。";
}
```

セレクトボックスなど、

value属性の値が1より小さい（0以下)、または6より大きい(7以上)の場合にエラーと判断しています。



###チェックボックスのチェックを調べる

```php
  if (empty($data['agreement'])) {
    $error[] = "プライバシーポリシーを確認して下さい";
  } elseif ((int) $data['agreement'] !== 1) {
    $error[] = "プライバシーポリシーをご確認ください。";
  }
```


##セッションを作る

```php
// セッションの書き込み
session_start();
$_SESSION['page'] = true;
```

確認ページ


session_start()でセッション開始の合図を出し、$_SESSION[‘page’]に「true」を格納



完了ページ

```php
	session_start();
	if( !empty($_SESSION['page']) && $_SESSION['page'] === true ) {

		// セッションの削除
		unset($_SESSION['page']);

//$_SESSION['page']が空じゃない時のみ、完了ページの処理を実行する


	} else {
		$page_flag = 0;
	}
```


```php

<?php
// var_dump($_POST);


//変数の初期化

/*---------------------------------------
    ページ切り替え
-----------------------------------------*/

$page_flag = 0;
$clean = array();
$error = array();

//サニタイズ
if (!empty($_POST)) {
  foreach ($_POST as $key => $value) {
    $clean[$key] = htmlspecialchars($value, ENT_QUOTES);
  }
}


if (!empty($clean['btn_confirm'])) {
  //$_POST[‘btn_confirm’]の値が渡されているか確認

  $error = validation($clean);

  if (empty($error)) { //エラーがなかった時、確認ページへ
    $page_flag  = 1;

    // セッションの書き込み
    session_start();
    $_SESSION['page'] = true;
  }
} elseif (!empty($clean['btn_submit'])) {
  //$_POST[‘btn_submit’]の値が渡されているか確認
  $page_flag = 2;
}
//入力ページや確認ページの表示をスイッチするフラグになる
//$_POST[‘btn_confirm’]があれば、確認ページへ進む

//[0]入力
//[1]確認
//[2]完了


session_start();
if (!empty($_SESSION['page']) && $_SESSION['page'] === true) {

  // セッションの削除
  unset($_SESSION['page']);



  /*---------------------------------------
    メール送信機能

// 変数の設定
$to = "testtaro@gray-code.com";
$subject = "メール送信のテスト";
$text = "メール本文です。";

// メール送信
mb_send_mail( $to, $subject, $text);
-----------------------------------------*/

  //変数とタイムゾーン
  $header = null; //メールの件名に入る文字列
  $auto_reply_subject = null;
  $auto_reply_text = null;
  date_default_timezone_set('Asia/Tokyo');

  // ヘッダー情報を設定
  $header = "MIME-Version: 1.0\n";
  $header .= "From: GRAYCODE <noreply@gray-code.com>\n";
  $header .= "Reply-To: GRAYCODE <noreply@gray-code.com>\n";

  //件名を設定
  $auto_reply_subject = 'お問い合わせありがとうございます';

  //本文設定
  $auto_reply_text = "この度はお問い合わせありがとうございます。下記の内容でお問い合わせを受け付けました。\n\n";
  $auto_reply_text .= "お問い合わせ日時:" . date("Y-m-d H:i") . "\n";
  $auto_reply_text .= "氏名:" . $clean['your_name'] . "\n";
  $auto_reply_text .= "メールアドレス:" . $clean['email'] . "\n\n";
  $auto_reply_text .= "CODE株式会社";

  //メール送信
  mb_send_mail($clean['email'], $auto_reply_subject, $auto_reply_text);


  /**--------運営者側へ送るメール */

  // 運営側へ送るメールの件名
  $admin_reply_subject = "お問い合わせを受け付けました";

  // 本文を設定
  $admin_reply_text = "下記の内容でお問い合わせがありました。\n\n";
  $admin_reply_text .= "お問い合わせ日時：" . date("Y-m-d H:i") . "\n";
  $admin_reply_text .= "氏名：" . $clean['your_name'] . "\n";
  $admin_reply_text .= "メールアドレス：" . $clean['email'] . "\n\n";

  // 運営側へメール送信
  mb_send_mail('webmaster@gray-code.com', $admin_reply_subject, $admin_reply_text, $header);
} else {
  $page_flag = 0;
}


function validation($data)
{
  $error = array();

  //氏名のバリデーション
  if (empty($data['your_name'])) {
    $error[] = "氏名は必ず入力して下さい";
  } elseif (20 < mb_strlen($data['your_name'])) {
    $error[] = "指名は20文字以内で入力して下さい";
  }


  if (empty($data['email'])) {
    $error[] = "メールアドレスは必ず入力して下さい";
  } elseif (!preg_match('/^[0-9a-z_.\/?]+@([0-9a-z-]+\.)+[0-9a-z-]+$/', $data['email'])) {
    $error[] = "メールアドレスは正しい形式で入力して下さい";
  }


  if (empty($data['gender'])) {
    $error[] = "性別は必ず入力して下さい";
  } elseif ($data['gender'] !== 'male' && $data['gender'] !== 'female') {
    $error[] = "性別は必ず入力して下さい";
  }


  if (empty($data['age'])) {
    $error[] = "年齢は必ず入力して下さい";
  } elseif ((int) $data['age'] < 1 || 6 < (int) $data['age']) {
    $error[] = "年齢は必ず入力して下さい";
  }

  if (empty($data['contact'])) {
    $error[] = "お問い合わせ内容は必ず入力して下さい";
  }

  if (empty($data['agreement'])) {
    $error[] = "プライバシーポリシーを確認して下さい";
  } elseif ((int) $data['agreement'] !== 1) {
    $error[] = "プライバシーポリシーをご確認ください。";
  }


  return $error;
}

?>

<!DOCTYPE>
<html lang="ja">

<head>
  <title>お問い合わせフォーム</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <h1>お問い合わせフォーム</h1>

  <?php if ($page_flag === 1) : // 　----------------確認ページの内容-----------------------
  ?>

  <form method="post" action="">
    <div class="element_wrap">
      <label>氏名</label>
      <p><?php echo $clean['your_name']; ?></p>
    </div>
    <div class="element_wrap">
      <label>メールアドレス</label>
      <p><?php echo $clean['email']; ?></p>
    </div>
    <div class="element_wrap">
      <label>性別</label>
      <p><?php if ($clean['gender'] === "male") {
              echo '男性';
            } else {
              echo '女性';
            } ?></p>
    </div>
    <div class="element_wrap">
      <label>年齢</label>
      <p>
          <?php if ($clean['age'] === "1") {
            echo '〜19歳';
          } elseif ($clean['age'] === "2") {
            echo '20歳〜29歳';
          } elseif ($clean['age'] === "3") {
            echo '30歳〜39歳';
          } elseif ($clean['age'] === "4") {
            echo '40歳〜49歳';
          } elseif ($clean['age'] === "5") {
            echo '50歳〜59歳';
          } elseif ($clean['age'] === "6") {
            echo '60歳〜';
          }
          ?>
        </p>
    </div>
    <div class="element_wrap">
      <label>お問い合わせ内容</label>
      <p><?php echo nl2br($clean['contact']); ?></p>
    </div>
    <div class="element_wrap">
      <p>
          <?php
          if ($clean['agreement'] === "1") {
            echo '同意する';
          } else {
            echo '同意しない';
          }
          ?>
        </p>
    </div>
    <!-- 入力値の受け渡し用 -->
    <input type="submit" name="btn_back" value="戻る">
    <input type="submit" name="btn_submit" value="送信">
    <input type="hidden" name="your_name" value="<?php echo $clean['your_name']; ?>">
    <input type="hidden" name="email" value="<?php echo $clean['email']; ?>">
    <input type="hidden" name="gender" value="<?php echo $clean['gender']; ?>">
    <input type="hidden" name="age" value="<?php echo $clean['age']; ?>">
    <input type="hidden" name="contact" value="<?php echo $clean['contact']; ?>">
    <input type="hidden" name="agreement" value="<?php echo $clean['agreement']; ?>">
  </form>

  <?php elseif ($page_flag === 2) : //　----------------完了ページの内容-----------------------
  ?>

  <p>送信が完了しました</p>

  <?php else : //----------------入力ページの内容-----------------------
  ?>

  <?php if (!empty($error)) { ?>
  <ul class="error_list">
    <?php foreach ($error as $value) : ?>
    <li><?php echo $value; ?></li>
    <?php endforeach; ?>
  </ul>
  <?php } ?>

  <form method="post" action=""> <?php //送信先が空なので、自分自身（index.php）を再度呼び出す
                                    ?>
    <div class="element_wrap">
      <label>氏名</label>
      <input type="text" name="your_name" value="<?php if (!empty($clean['your_name'])) {
                                                      echo $clean['your_name'];
                                                    } ?>">
      <!-- POSTパラメータが空じゃない場合のみvalue属性にセット -->
    </div>
    <div class="element_wrap">
      <label>メールアドレス</label>
      <input type="mail" name="email" value="<?php if (!empty($clean['email'])) {
                                                  echo $clean['email'];
                                                } ?>">
    </div>
    <div class="element_wrap">
      <label>性別</label>
      <label for="gender_male"><input id="gender_male" type="radio" name="gender" value="male">男性</label>
      <label for="gender_female"><input id="gender_female" type="radio" name="gender" value="female">女性</label>
    </div>
    <div class="element_wrap">
      <label>年齢</label>
      <select name="age">
        <option value="">選択してください</option>
        <option value="1">〜19歳</option>
        <option value="2">20歳〜29歳</option>
        <option value="3">30歳〜39歳</option>
        <option value="4">40歳〜49歳</option>
        <option value="5">50歳〜59歳</option>
        <option value="6">60歳〜</option>
      </select>
    </div>
    <div class="element_wrap">
      <label>お問い合わせ内容</label>
      <textarea name="contact"></textarea>
    </div>
    <div class="element_wrap">
      <label for="agreement"><input id="agreement" type="checkbox" name="agreement" value="1">プライバシーポリシーに同意する</label>
    </div>
    <input type="submit" name="btn_confirm" value="入力内容を確認する">
  </form>

  <?php endif; ?>
</body>

</html>


```




##参考記事
[フォームの基本構造を作成する | GRAYCODE PHPプログラミング ](https://gray-code.com/php/make-the-form-vol1/)