PHPを用いた予約フォーム（Windows版）

# はじめに
プログラミング超初心者かつ、Quiita初投稿です。
成長のため何か行動せねば！と思い、PHPを用いて動的なWebページを作成してみることにしました。今回は初心者向けの以下を参考に予約フォームを作成しました！
（温かい目で読んでいただけると嬉しいです！）
>[PHP]カレンダーを利用した予約システムの作り方[初心者向け]|WATSUNBLOG
>https://watsunblog.com/php-reservation-calender/

# PHPとは
PHPは動的にWebページを作成できるサーバサイドのスクリプト言語です。
他言語との違いとして、HTMLは静的にWebページを表示し、JavaScriptではクライアントサイドのスクリプトという違いがあります。

# 環境構築
ネットでPHPのプログラミング方法を見るとVisualstudioを用いて環境構築しているものもありましたが、「XAMPP（ザンプ）」の方が簡単そうだったので、今回はこちらを使用しました。
XAMPPはウェブアプリケーションの実行に必要なフリーソフトウェアをパッケージとしてまとめたもので、apachefriends.orgから提供されています。

以下を参考にXAMPPをインストールしました。

>開発環境構築と初めてのPHPプログラム作成（Windows版）
>https://blog.senseshare.jp/dev-tools.html

# データベースの用意
__【文字化け対策】__
C:\xampp\mysql\bin配下の[my.ini]というファイルをサクラエディタで開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/574072dd-6f92-731c-b184-21fabd16eb38.png)

①[client]のすぐ下に1行追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/5e8c88ef-1b9b-5344-a764-05fb83f7162f.png)
②[mysqld]のすぐ下に2行追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/b2bf9953-0627-c02d-f302-b2c86aab4cd7.png)

__【データベースの作成】__
①データベースをメンテナンスする画面を開く
XAMPPコントロールパネルのMySQLの[Admin]ボタンを押すとブラウザが自動で起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/6f83b613-0e7c-f56f-5222-3616f3d8df90.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/4d71e612-8922-09d8-7e8f-63f2383efbd8.png)


②データベースの作成
データベース名「reservation」、照合順序「utf8_unicode_ci」を設定し、[作成]ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/a5797ae5-3d9b-daf3-b464-9871882df0e5.png)
名前にテーブル名[booking]を入力（半角で）し、カラム数を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/5972d9d5-9e61-19cf-3ccd-35fdc0a64941.png)
フィールドを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/b16c2028-7500-614b-d23d-8bded42e8a67.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/040bfe4b-6807-7c02-3669-ce3553b4bd7c.png)

# 予約フォームの作成
簡単な「予約フォーム」を作成し、こちらから名前、電話番号、日時などの情報をユーザーに登録してもらいます。
コードは以下のような感じで、[calender.php]へactionさせています。
```php
<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8">
 <title>Reservation Form</title>
 <style>
 </style>
</head>
<body>
 <?php
 echo '必要事項を入力してください。';
 ?>
 <form method="post"action="calender.php">
  お名前
  <div><input name="name"type="text"placeholder="山田太郎"style="width:120px"></div>
  電話番号
  <div><input name="number"type="tel"placeholder="09012349876"></div>
  人数
  <div><input name="member"></div>
  日付
  <div><input name="day"type="date"list="daylist"min=""></div>
  <div><input type="submit"value="Send"></div>
  <div><input type="reset"value="Reset"></div>
 </form>
</body>
</html>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/8060ec9e-8b53-2551-3f62-2db9be732468.png)


[calender.php]でデータベースへの書き込みを行います。
[calender.php]のコードは以下の通りです。
```php
     <!DOCTYPE html>
     <html lang="ja">
     <head>
      <meta charset="utf-8">
      <title>Calender</title>
      <link rel= "stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
      <style>
       .container{
        font-family: "メイリオ";
        margin-top: 80px;
       }
       h3{
        margin-bottom: 30px;
       }
       th{
        height: 30px;
        text-align: center;
       }
       td{
        height: 100px;
       }
       .today{
        background: aqua;  //日付が今日の場合は背景を水色に設定
       }
       th:nth-of-type(1),td:nth-of-type(1){
        color: red; //日曜日は赤
       }
       th:nth-of-type(7),td:nth-of-type(7){
        color: blue; //土曜日は青
       }
       .green{
            color: green;
        }
      </style>
     </head>
     <body>
     <?php
      if(isset($_POST['name'])) {
      //名前が送信されたら以下の処理を行う        
      //「予約フォーム」からの情報をそれぞれ変数に格納しておく↓
      $name=htmlspecialchars($_POST["name"], ENT_QUOTES);
      $number=htmlspecialchars($_POST["number"], ENT_QUOTES);
      $member=htmlspecialchars($_POST["member"], ENT_QUOTES);
      $day=htmlspecialchars($_POST["day"], ENT_QUOTES);
      
      //DBへ接続 
      $dsn='mysql:dbname=reservation;host=localhost;charset=utf8';
      $user='root';
      $pass='';
      
      try{
      $dbh = new PDO($dsn,$user,$pass);
      $dbh->query("INSERT INTO booking (ban,name,number,member,day)
       VALUES (NULL,'$name','$number','$member','$day')");     
      }catch (Exception $e) {
       echo $e->getMessage() . PHP_EOL;
      }
     
　　　//予約された日の予約人数を取得する
      function getreservation(){
      $dsn='mysql:dbname=reservation;host=localhost;charset=utf8';
      $user='root';
      $pass='';
      $dbh = new PDO($dsn,$user,$pass);
      $ps = $dbh->query("SELECT * FROM booking");
      $reservation_member = array(); //各日付の予約人数を$reservation_memberへ入れるための配列を用意する
      
      foreach($ps as $out){ //登録された予約情報をすべて$outに入れる
　　　//予約された全ての日付情報を文字列として$day_outへ格納
      $day_out = strtotime((string) $out['day']);
      //予約された全ての日のそれぞれの人数を文字列として$member_outへ格納      
      $member_out = (string) $out['member'];
      //$day_outで取得した日付をもとにそれぞれの予約人数を$reservation_memberへ格納   
      $reservation_member[date('Y-m-d', $day_out)] = $member_out;        
      }  
        return $reservation_member;
      }
      
      $reservation_array = getreservation();
     //getreservation関数を$reservation_arrayに代入しておく
      
     function reservation($date,$reservation_array){
     //カレンダーの日付と予約された日付を照合する関数
         
         if(array_key_exists($date,$reservation_array)){
         //もし"カレンダーの日付"と"予約された日"が一致すれば以下を実行する
                 
               $reservation_member = "<br/>"."<span class='green'>".$reservation_array[$date]."人"."</span>";
                 
             return $reservation_member;                  
         }
     }
     //タイムゾーンを設定
     date_default_timezone_set('Asia/Tokyo');

     //前月・次月リンクが選択された場合は、GETパラメーターから年月を取得
     if(isset($_GET['ym'])){ 
         $ym = $_GET['ym'];
     }else{
         //今月の年月を表示
         $ym = date('Y-m');
     }

     //タイムスタンプ（どの時刻を基準にするか）を作成し、フォーマットをチェックする
     //strtotime('Y-m-01')
     $timestamp = strtotime($ym . '-01'); 
     if($timestamp === false){ //エラー対策として形式チェックを追加
         //falseが返ってきた時は、現在の年月・タイムスタンプを取得
         $ym = date('Y-m');
         $timestamp = strtotime($ym . '-01');
     }

     //今月の日付　フォーマット　例）2020-10-2
     $today = date('Y-m-j');

     //カレンダーのタイトルを作成　例）2020年10月
     $html_title = date('Y年n月', $timestamp);//date(表示する内容,基準)

     //前月・次月の年月を取得
     //strtotime(,基準)
     $prev = date('Y-m', strtotime('-1 month', $timestamp));
     $next = date('Y-m', strtotime('+1 month', $timestamp));

     //該当月の日数を取得
     $day_count = date('t', $timestamp);

     //１日が何曜日か
     $youbi = date('w', $timestamp);

     //カレンダー作成の準備
     $weeks = [];
     $week = '';

     //第１週目：空のセルを追加
     //str_repeat(文字列, 反復回数)
     $week .= str_repeat('<td></td>', $youbi);

     for($day = 1; $day <= $day_count; $day++, $youbi++){

         $date = $ym . '-' . $day; //2020-00-00
         
         $reservation = reservation(date("Y-m-d",strtotime($date)),$reservation_array);
      
         if($today == $date){
             $week .= '<td class="today">' . $day; //今日の場合はclassにtodayをつける
         }elseif(reservation(date("Y-m-d",strtotime($date)),$reservation_array)){
             $week .= '<td>' . $day . '<br>' . $reservation;
         }else{
         
         $week .= '<td>' . $day;
         }
         $week .= '</td>';

         if($youbi % 7 == 6 || $day == $day_count){//週終わり、月終わりの場合
             //土曜日を取得

             if($day == $day_count){//月の最終日、空セルを追加
                 $week .= str_repeat('<td></td>', 6 - ($youbi % 7));
             }

             $weeks[] = '<tr>' . $week . '</tr>'; //weeks配列にtrと$weekを追加
             $week = '';//weekをリセット
         }
     }

     ?>
     <div class="container">
      <h3><a href="?ym=<?php echo $prev; ?>">&lt;</a><?php echo $html_title; ?><a href="?ym=<?php echo $next; ?>">&gt;</a></h3>
       <table class="table table-bordered">
        <tr>
         <th>日</th>
         <th>月</th>
         <th>火</th>
         <th>水</th>
         <th>木</th>
         <th>金</th>
         <th>土</th>
        </tr>
        <?php
          foreach($weeks as $week){
           echo $week;
           }
        ?>
       </table>
     </div>
     </body>
     </html>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829365/0699a3e1-bf12-18f7-8240-b44137067578.png)

# おわりに、そして今後に向けて
DBから予約人数を取り出し、所定の日付に表示させる方法や、予約が入っていない日付が正しくカレンダーの枠に入らない時の原因究明に苦戦し、時間を要しました。
細かく変数の値を公開ページに表示させ、どこまで正しく入っているか確認しながら進めることでどこに原因があるかを検討しました。
また、キータの初投稿ということもあり、慣れるまでは記事の書き方が難しいですね。
今後は予約人数の制限や入力チェック、予約者を確認するためのページを作っていきたいです。