PHPでつぶやきアプリの作成

PHPで作成した「<strong>つぶやきアプリ</strong>」の紹介記事となります。

前回の「簡単な計算機アプリ」に比べ自分の中では難易度が爆上がりしました。というのも前回は<strong>HTML/PHP</strong>だけを使った簡単な実装でしたが、今回は<strong><span style="color: #ff6600;">HTML</span>/<span style="color: #008000;">CSS</span>/<span style="color: #06a4d4;">PHP</span></strong>を用いてより機能的により実際のアプリを模倣したアプリになっています。

<font color="DarkRed"><strong>前回作成したアプリ</strong></font>

https://qiita.com/hiroo1120/private/094699597c7b21d7aae6


そして何よりDBの活用によるプログラムの幅の広がりや、セキュリティを意識したコードという点において未熟ながらも大変勉強になりました。

私自身、知識も経験も浅いPHP初学者であるため間違いなどもあるかもしれませんが、とりあえず学習のために動くアプリを作れたということで何卒ご勘弁をお願いいたします。


><strong>GitHub</strong>
https://github.com/Hiro1120/simpleTwitter_PHP.ver



<h1>目次</h1>

[1. アプリの作成](#アプリの作成)
　- [作成したアプリ](#作成したアプリ)
　- [完成イメージ](#完成イメージ)
[2. トップ画面の実装](#トップ画面の実装)
　- [ベーシック認証](#ベーシック認証)
[3. タイムライン1-ログイン前の実装](#タイムライン1-ログイン前の実装)
　- [クリックジャッキング対策](#クリックジャッキング対策)
　- [dbからデータを取得](#dbからデータを取得)
　- [iframe-インラインフレーム](#iframe-インラインフレーム)
[4. ユーザー登録画面の実装](#ユーザー登録画面の実装)
　- [同じphpファイル内で画面切り替え](#同じphpファイル内で画面切り替え)
　- [クロスサイトスクリプティング-xss-攻撃対策](#クロスサイトスクリプティング-xss-攻撃対策)
　- [クロスサイトリクエストフォージェリ-crsf-対策](#クロスサイトリクエストフォージェリ-crsf-対策)
[5. ログイン画面の実装](#ログイン画面の実装)
　- [sqlインジェクション攻撃対策](#sqlインジェクション攻撃対策)
[6. タイムライン2-ログイン後の実装](#タイムライン2-ログイン後の実装)
<h2>アプリの作成</h2>
<h3>作成したアプリ</h3>
それぞれの機能は後ほど紹介しますが、ログイン前のタイムラインとログイン後のタイムライン画像と操作映像のご紹介をします。
<h4><strong>ログイン前</strong></h4>
<a href="https://hiro-hobbyblog.com/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0%e5%88%9d%e5%bf%83%e8%80%85%e3%81%aephp%e4%bf%ae%e7%be%85%e3%81%ae%e9%81%93%ef%bc%832%e3%80%9c%e3%81%a4%e3%81%b6%e3%82%84%e3%81%8d/%e3%81%a4%e3%81%b6%e3%82%84%e3%81%8d%e3%83%ad%e3%82%b0%e3%82%a4%e3%83%b3%e5%89%8d/" rel="attachment wp-att-1892"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/c7b627fe5c5d9fdbb072a6c893b7500a.jpg" alt="" width="1912" height="1079" class="aligncenter wp-image-1892 size-full" /></a>
<h4><span style="font-size: 20px; color: #00cc7e;" class="marker"><strong>ログイン後</strong></span></h4>
<a href="https://hiro-hobbyblog.com/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0%e5%88%9d%e5%bf%83%e8%80%85%e3%81%aephp%e4%bf%ae%e7%be%85%e3%81%ae%e9%81%93%ef%bc%832%e3%80%9c%e3%81%a4%e3%81%b6%e3%82%84%e3%81%8d/%e3%81%a4%e3%81%b6%e3%82%84%e3%81%8d%e3%83%ad%e3%82%b0%e3%82%a4%e3%83%b3%e5%be%8c/" rel="attachment wp-att-1891"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/7bb301bb3bd34d1927a18e2201614559.jpg" alt="" width="1907" height="1078" class="aligncenter wp-image-1891 size-full" /></a>
<h4><span style="font-size: 20px; color: #993366;"><strong>デモ映像 </strong></span></h4>


<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/VZ4070nhJuU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


※（追記2023/4/29）トップ画面の実装は[コチラ](#トップ画面の実装)に変更しました

<h3>完成イメージ</h3>
「<strong>つぶやきアプリ</strong>」の作成に伴い初めに本家PC版Twitterをイメージしました。完成アプリで背景色を<span style="color: #071ca6;"><strong>紺色</strong></span>にしているのはそのためです。

<span style="color: #f24405;"><strong>CSS</strong></span>でデザインをいじったのは全ての処理をコーディングした最終工程なので、当初予定には含めていませんでした。アプリを作成する中で愛着が湧いてきたので勉強ついでにいじってみたという感じです。

<strong>【基本画面】</strong>

><strong>・トップ画面</strong>
>
><strong>・タイムライン1（ログイン前）</strong>
>
><strong>・ユーザー登録画面</strong>
>
><strong>・ログイン画面</strong>
>
><strong>・タイムライン2（ログイン後）</strong>
>
><strong>・その他：登録・ログイン・つぶやきなどの確認と完了画面等</strong>
>
<span class="marker2"><strong>【追加機能】</strong></span>
>
><strong>・CSSデザイン</strong>
>
><strong>・他サイトの表示</strong>
>
><strong>・ベーシック認証</strong>


その他の細かい詳細機能は画面ごとに紹介していきます。
<h2>トップ画面の実装</h2>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2023/04/14624e375bc5245f83ec74ec8ec31192.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2023/04/14624e375bc5245f83ec74ec8ec31192.png" alt="" width="2878" height="1638" class="aligncenter size-full wp-image-2262" /></a>


これは最後に追加した画面なので別に今回のアプリには必要のないものでしたが、せっかくなのでHTMLとCSSで遊びたいなということで追加することにしました。


<h3>ベーシック認証</h3>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/492e8d50d996e329f4fc72f199d656a9-1.png" rel="attachment wp-att-1889"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/492e8d50d996e329f4fc72f199d656a9-1.png" alt="" width="1440" height="497" class="aligncenter wp-image-1889 size-full" /></a>

このページではベーシック認証を採用しています。


<font color="SteelBlue"><strong>ベーシック認証とは？</font>
></strong><strong>WEBサイトにアクセする時に制限をかけることができる</strong><strong>最も簡易的な認証方式のこと</strong>


```php
<?php
    $pathFile = file(__DIR__ . '/path.txt');
    $path = explode('：',$pathFile[0]);
    //パスワード（暗号化）
    (password_hash($path[1], PASSWORD_BCRYPT));
?>
```
HTMLを書き始める前にこちらのphpコードを先頭に記述しています。こうすることでこのindex.phpと同じ階層にあるログイン用のパスを記述したファイルを読み込んで<font color="Salmon"><strong>$pathFile</strong></font>にそのパスを格納します。

その後、<font color="DarkGreen"><strong>password_hash()関数</strong></font>にPHP7から推奨となった<font color="MediumVioletRed"><strong>PASSWORD_BCRYPT</strong></font>を設定することで、CRYPT_BLOWFISHアルゴリズムで新たなパスワードハッシュ</span>を作ります。例えば、「<strong>12345</strong>」というパスワードにするとアルゴリズムに沿って、「<strong>&#36;$2y$10$YkEhx.5W8b8NcBUKWfF3WOmo/O.EL.raDvuRz0On3NkinIzE7Y8si</strong>」
という文字列に変換されます。

ここで必要になる隠しファイルが<strong>「.htaccess」「.htpasswd」</strong>の二つです。「.〇〇〇」というファイル名にすることで隠しファイルとして扱うことができます。
<h4><strong>①.htaccess</strong></h4>
ファイルには下記内容を記述し、最終行は改行した状態で保存します。

```
AuthType Basic  //ベーシック認証をかける
AuthName "IDとパスワードを入力してください"
AuthUserFile /Applications/・・・/.htpasswd //パスのファイルのありかを示す
require valid-user  //認証したいユーザーだけが中に入ることができる
```

<h4><strong>②.htpasswd</strong></h4>
ファイルには下記内容を記述し、最終行は改行した状態で保存します。


```
id:password  //入力するidとパスワードを設定
```


<h2> タイムライン1-ログイン前の実装</h2>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/c7b627fe5c5d9fdbb072a6c893b7500a.jpg"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/c7b627fe5c5d9fdbb072a6c893b7500a.jpg" alt="" width="1912" height="1079" class="alignnone size-full wp-image-1892" /></a>

ログイン前のタイムラインではつぶやきを投稿することはできませんが、タイムラインの閲覧は可能です。また、ログイン前はユーザーの登録画面とログイン画面への画面遷移ができます。ツイッターのロゴを押下するとトップページに戻れます。

画面構成としては縦に3分割しており、両サイドには他WEBサイトの表示とYouTubeの動画を配置しています。
<h3>クリックジャッキング対策</h3>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/39198686b91308bdab31dbf7ae2dbeef.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/39198686b91308bdab31dbf7ae2dbeef.png" alt="" width="1178" height="768" class="aligncenter wp-image-1893 size-full" /></a>
<font color="SteelBlue"><strong>クリックジャッキングとは？</strong></font>

><strong>クリックジャッキング（クリックジャック攻撃）とは、透明表示機能などによって見えないページを準備し、そのページ上にあるボタンをユーザにクリックさせることによって、思わぬ損害を与えるような攻撃のこと</strong>

<font color="DarkGreen"><strong>header()関数</strong></font>の<font color="MediumVioletRed"><strong>X-FRAME-OPTIONS</strong></font>に「<font color="MediumVioletRed"><strong>DENY</strong></font>」を設定することで、<strong>フレームでのページの読み込みの一切を禁止する</strong>ことができます。

&nbsp;

画像の引用元：<a href="https://nulab.com/ja/blog/typetalk/measure-clickjacking/">https://nulab.com/ja/blog/typetalk/measure-clickjacking/</a>

<h3>DBからデータを取得</h3>
データベースへのアクセスは<font color="DarkGreen"><strong>PDO(PHP Data Objects)</strong></font>を利用します。PDOは<span>PHPからデータベースへ簡単にアクセスするための拡張モジュールです。</span>

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/dfce31e791b0b90ddd4d8fd4db07d85d.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/dfce31e791b0b90ddd4d8fd4db07d85d.png" alt="" width="1383" height="695" class="aligncenter wp-image-1895 size-full" /></a>
<h4><strong>SQL文（SELECT）</strong></h4>
順番は前後しますが、DBに登録される情報は「<strong>ユーザー情報</strong>」と「<strong>つぶやき情報</strong>」になります。ここからデータを取り出していきます。
<h4><strong>usersテーブル</strong></h4>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/e29e6a1214c0fd6400d8d06da117d1dd.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/e29e6a1214c0fd6400d8d06da117d1dd.png" alt="" width="1502" height="476" class="aligncenter wp-image-1896 size-full" /></a>
<h4><strong>messagesテーブル</strong></h4>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/70fd6fc6b07ab3b1b655ab92b9e818ed.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/70fd6fc6b07ab3b1b655ab92b9e818ed.png" alt="" width="1416" height="358" class="aligncenter wp-image-1897 size-full" /></a>

```PHP
$selectData = $db -> prepare
(
  'SELECT 
     messages.id, 
     messages.user_id, 
     messages.text, 
     messages.created_date, 
     users.account, 
     users.NAME 
   FROM 
    `messages` 
   INNER JOIN 
    `users` 
   ON 
     messages.user_id = users.id 
   ORDER BY id 
   DESC'
);
```

<strong>top.php</strong>

<strong>内部結合</strong>することでユーザーとつぶやきを紐付け、<strong>ユーザーごとのつぶやき情報を取得</strong></span>します。また、並び順を降順にすることでタイムラインに表示させる時に常に画面上部に最新のつぶやきが表示されるようになります。

取得した情報はforeach文で回すことで、DBに登録されているつぶやきとユーザー情報を全て表示することができます。

今回は表示させたいデータとHTMLタグを下記のように一つの変数にぶち込んでいます。

```HTML
$display_messages[] = 
　　'<br>'.
　　'<font color="#08ffc8">'.
　　　　$name.'@'.$account.
　　'</font>'.
　　'<br>'.
　　　　$message_text.
　　'<br>'.
　　'<font color="#5bd1d7">'.
　　　　$created_date.
　　'</font>'.
　　'<br>';
```
<strong>top.php</strong>


なぜこうしたかというと、HTMLを記述した際の可読性を上げるためです。


```PHP
<div class="main">
　　<div class="message-block">
　　　　<?php foreach($display_messages as $display_message) :?>
       　　<div class="border-bottom border-light p-2">
          　　<?php echo nl2br($display_message); ?>
       　　</div>
　　　　<?php endforeach ;?>
　　</div>
</div><!--main-->
```

<strong>top.php</strong>

PHPではこのようにHTMLとの親和性が高いので途中で挿入することが可能です。その際に先ほどのデータを変数を入れるだけで簡潔に表示することができるようになります。

<h3>iframe-インラインフレーム</h3>
インラインフレーム要素を使うことで<span>現在のHTMLページに他のページを埋め込むことができます。
<h4><strong>左側のサイドバー</strong></h4>

```HTML
<div class="left-sidebar">
   <iframe class= "frame_center" src="https://www.famitsu.com" width="100%" height="1500"></iframe>
</div>
```

<strong>top.php</strong>
<h4><strong>右側のサイドバー</strong></h4>

```HTML
<div class="right-sidebar">
    <div class="video">
         <iframe width="560" height="315" src="https://www.youtube.com/embed/hBl5r_uxbSY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>
    <div class="video2">
         <iframe width="560" height="315" src="https://www.youtube.com/embed/Jgm4D0n4gxk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>
    <div class="video3">
         <iframe width="560" height="315" src="https://www.youtube.com/embed/DtE1nxSb4d4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>
</div><!--right-sidebar-->
```

<span style="color: #3366ff;"><strong><span style="font-size: 12px;">top.php</span></strong></span>

<h2>ユーザー登録画面の実装</h2>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/833f5bd34949f2c47b4e554f5a2274f5.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/833f5bd34949f2c47b4e554f5a2274f5.png" alt="" width="2880" height="1800" class="aligncenter wp-image-1906 size-full" /></a>

ユーザー登録画面では5項目の入力項目がありますが、<strong>自己紹介フォーム以外は入力必須項目</strong>に設定しています。パスワードに関しては入力なしの場合「<span style="color: #cc005f;"><strong>パスワードは必須です</strong></span>」と表示され、入力していても4文字未満であれば「<span style="color: #cc005f;"><strong>パスワードは4文字以上で入力してください</strong></span>」と表示されます。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/6546bf1ae22c383dd88aea762494832f.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/6546bf1ae22c383dd88aea762494832f.png" alt="" width="2880" height="1800" class="aligncenter wp-image-1907 size-full" /></a>

条件を満たす入力が完了すると確認画面へ画面が切り替わります。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/240a81fee828fe93ac4d15717788933b-1.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/240a81fee828fe93ac4d15717788933b-1-300x288.png" alt="" width="300" height="288" class="aligncenter wp-image-1909 size-medium" /></a>

このあと登録を押下することで登録完了画面が表示されます。<strong></strong>
<h3>DBへデータを登録</h3>
ユーザー登録画面ではユーザー情報の登録を行うため、DBの<strong>usersテーブル</strong>へ情報を登録する処理を行います。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/c4752ed38ddd458a3aabd53fa92b7c88.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/c4752ed38ddd458a3aabd53fa92b7c88.png" alt="" width="1916" height="1268" class="aligncenter size-full wp-image-1923" /></a>

SQL文自体は単純なINSERT文で、フォームから入力された情報を$_POSTで受け取ることで各カラムへと登録ができるようになります。

```PHP
//ユーザー登録フォームで入力された値を受け取る
$signup_name = $_POST['signup'];
$name = $_POST["name"];
$account = $_POST["account"];
$password = $_POST["password"];
$email = $_POST["email"];
$description = $_POST["description"];
```
<strong>database.php</strong>

また、このphpファイルのtry文内では<strong>ヒアドキュメント</strong>を使用しています。

<font color="SteelBlue"><strong>ヒアドキュメントとは？</strong></font>
><strong><font color="MediumVioletRed">&lt;&lt;&lt;&#95;区切り文字_
文字列
&#95;区切り文字_ ;</font>
とすることで、区切り文字内の文字列をそのまま変数に格納することができる。また、文字列中の変数はその値に置き換えることができる。</strong>

このヒアドキュメントを利用することにより、HTML内で7行分のコードを変数一つで表示でき、可読性が高くなります。

```HTML
<div class="message-block">
    <?php echo $finish_register?>
    <br>
    <p><?php echo $msg; ?></p>
</div>
```
<strong>database.php</strong>
<h3>同じphpファイル内で画面切り替え</h3>
「<strong>ユーザー登録</strong>」「<strong>登録内容確認</strong>」「<strong>登録完了</strong>」は同じPHPファイル内で処理されており、画面の切り替えは<font color="Salmon"><strong>$pageFlag</strong></font>という変数に格納する数値を切り替えることで実現させています。

```PHP
//画面切り替え
$pageFlag = 0;
if(!empty($_POST['btn_confirm']) && empty($errors)){
$pageFlag = 1;
}
if(!empty($_POST['btn_register'])){
$pageFlag = 2;
}
```
<strong>signup.php</strong>

<strong>HTML</strong>の<strong>name属性</strong>を「<strong>btn_confirm</strong>」に設定している「<strong>確認する</strong>」ボタンを押下することでフォームに入力された情報がPOSTされ、「<strong>$_POST</strong>」によってデータを受け取ることが可能になります。ボタンが押され、かつエラーがなければ確認画面に表示を切り替えることができます。

```HTML
<!--確認ボタン-->
<button type="submit" class="btn btn-primary" name="btn_confirm" value="確認する">確認する</button>
```
<strong>signup.php</strong>

エラーメッセージは別の<strong>validation.php</strong>で定義しているので、ファイルの先頭で定義しているファイルを読み込みこの<span style="color: #3366ff;"><strong>signup.php</strong></span>内で使えるようにしています。


```PHP
//validation.php
//ユーザー登録時のエラーメッセージ
    function validation($request){

        $errors = [];

        if(empty($request['name']) || 20 < mb_strlen($request['name'])){
            $errors[] = '「名前」は必須です。20文字以内で入力してください。';
        }

        if(empty($request['account']) || 20 < strlen($request['account'])){
            $errors[] = '「アカウント名」は必須です。20文字以内で入力してください。';
        }

        if(empty($request['password'])){

            $errors[] = '「パスワード」は必須です。';

        }else{

            if(0 < strlen($request['password']) && 4 > strlen($request['password'])){
                $errors[] = '「パスワード」は4文字以上で入力してください。';
            }

            if(20 < strlen($request['password'])){
                $errors[] = '「パスワード」は20文字以内で入力してください。';
            }
        }

        if(empty($request['email']) || !filter_var($request['email'], FILTER_VALIDATE_EMAIL)){
            $errors[] = '「メールアドレス」は必須です。正しい形式で入力してください。';
        }

        return $errors;
    }
```

<span style="color: #3366ff;"><strong><span style="font-size: 12px;">validation.php</span></strong></span>

<h3>クロスサイトスクリプティング-xss-攻撃対策</h3>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/1740b0dc45c18789dd9dfaf81a11b61b.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/1740b0dc45c18789dd9dfaf81a11b61b.png" alt="" width="873" height="305" class="aligncenter size-full wp-image-1911" /></a>

<font color="SteelBlue"><strong>XSS攻撃とは？</strong></font>
><strong>クロスサイトスクリプティング（XSS）とは、Webサイトの脆弱性を利用し、記述言語であるHTMLに悪質なスクリプトを埋め込む攻撃のこと</strong>

JavaScriptなどのスクリプトが実行されないように、スクリプトの構成に必要な「<strong>&amp;，&lt;，&gt;，”，’</strong>」の５文字の特殊文字が<strong>そのまま画面に表示されてしまうようにエスケープ（置換）してスクリプトのサニタイジング（無害化)</strong>を行います。

```PHP
//クロスサイトスクリプティング攻撃対策
function h($str){
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
```

$_POSTで受け取った値を下記のような感じで全てサニタイズします。

```HTML
<input type="text" class="form-control" name="name" id="signup-name" placeholder="マリオ" value="<?php if(!empty($_POST['name'])){echo h($_POST['name']);} ?>">
```


&nbsp;
引用元：<a href="https://www.shadan-kun.com/waf/xss/">https://www.shadan-kun.com/waf/xss/</a>

引用元：<a href="https://www.nttpc.co.jp/column/security/cross_site_scripting.html">https://www.nttpc.co.jp/column/security/cross_site_scripting.html</a>


<h3>クロスサイトリクエストフォージェリ-crsf-対策</h3>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/09791e001762f22a8c8d822b5102a7a6.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/09791e001762f22a8c8d822b5102a7a6.png" alt="" width="1272" height="1070" class="aligncenter size-full wp-image-1915" /></a>

<font color="SteelBlue"><strong>CSRF攻撃とは？</strong></font>
><strong>攻撃者は自身が直接攻撃対象サーバへアクセスすることなく攻撃対象のWebアプリケーションに任意の処理を行わせることにより、誘導された一般ユーザが攻撃対象サーバへの不正なリクエストを送信した攻撃者として誤認識させる攻撃のこと</strong>

誘導されたユーザーはいたずら的な書き込みや、大量の不正な書き込み、不正サイトへの誘導など本人が意図しない攻撃を行ってしまうことになります。

今回のつぶやきアプリでは「<strong>GET</strong>や<strong>POST</strong>という1度きりのやりとりではなく、<strong>SESSION</strong>という有効期限までの間は情報を保持する方法で対策」をしてみました。

```PHP
<!--csrfTokenがなければ変数に代入する-->
<?php
    if(!isset($_SESSION['csrfToken'])){
        $csrfToken = bin2hex(random_bytes(32));
        $_SESSION['csrfToken'] = $csrfToken;
    }
    $token = $_SESSION['csrfToken'];
?>
```
<strong>signup.php</strong>

<font color="DarkGreen"><strong>bin2hex(random_bytes(32))</strong></font>によって安全なバイト列を16進数に変換し、それを<font color="Salmon"><strong>SESSION['csrfToken']</strong></font>に格納します。

```HTML
<input type="hidden" name="csrf" value="<?php echo $token; ?>">
```
<strong>signup.php</strong>

この生成したtokenをhidden属性で画面に値を持たせ、切り替わった後の画面ではそのtokenを$_POSTでその値を受け取ります。こうすることで、<span style="text-decoration: underline;"><strong>画面が切り替わる前と切り替わった後でのcsrfTokenを比較する</strong></span>ことで、<strong><span style="text-decoration: underline;">意図する画面への切り替えが正常に行われているかの判定</span></strong>が実現できます。

もしここで<strong>csrfTokenが一致しなかった場合</strong>は、<span style="text-decoration: underline;">同じ見た目の悪意ある全く別のページに飛ばされてしまう</span>ことになるので画面が切り替わらないように制御しています。


<strong>【画面が切り替わる前】</strong>
><strong>・$_SESSION['csrfToken']で保持しているcsrfToken</strong>

<strong>【画面が切り替わった後】</strong>
><strong>・$_POSTで受け取ったcsrfToken</strong>

```php
<!--トークンが一致しているか判定する-->
<?php if($_POST['csrf'] === $_SESSION['csrfToken']) :?>
<!--確認画面表示などの処理-->;

<?php endif; ?>
```
<strong>signup.php</strong>


判定がfalseであれば「if~endif」で囲まれた内側の処理は行われないので、確認画面も表示されないという仕組みです。
<div class="concept-box5">


&nbsp;
引用元：<a href="https://www.trendmicro.com/ja_jp/security-intelligence/research-reports/threat-solution/csrf.html">https://www.trendmicro.com/ja_jp/security-intelligence/research-reports/threat-solution/csrf.html</a>


<h2>ログイン画面の実装</h2>
<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/a7c671211f94902e1da776f27d860f17.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/a7c671211f94902e1da776f27d860f17.png" alt="" width="2880" height="1800" class="aligncenter size-full wp-image-1920" /></a>

ログイン画面では先ほどユーザー登録画面で登録した「<strong>アカウント名</strong>か<strong>メールアドレス</strong>」と「<strong>パスワード</strong>」でログインが可能となります。

この際、登録されてないアカウントでログインしようとすると画面が切り替わり、再度ログイン画面で情報を入力するように促します。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/a087d25ce327513070d534b6dffa84c2.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/a087d25ce327513070d534b6dffa84c2.png" alt="" width="1226" height="260" class="aligncenter size-full wp-image-1921" /></a>

ログインに成功すると、ログイン完了画面へと移り、ログイン後のタイムライン画面へと進むことができるボタンが表示されます。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/01612f7ab4ff4e095cae4ac7ddfa4a3d.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/01612f7ab4ff4e095cae4ac7ddfa4a3d-640x360.png" alt="" width="640" height="360" class="aligncenter wp-image-1922 size-small_size" /></a>

基本的にはログイン画面も他の画面と同様のセキュリティ対策や画面切り替えを行っているため、ぞの部分での処理内容はそこまで大きくは変わっていません。
<h3>SQLインジェクション攻撃対策</h3>
<font color="steelBlue"><strong>SQLインジェクション攻撃とは？</strong></font>


><strong>SQLクエリの一部に不正なパラメータを含めることで意図しない操作を実行させる攻撃手法のこと。</strong>
<h4><strong>プリペアードステートメント</strong></h4>
SQL文で値がいつでも変更できるように、変更する箇所のみ命令文を作る仕組みのことです。この仕組みを使うことで、<strong>内部的に自動でエスケープ処理を施してくれ</strong>ためセキュリティ面でも安全に使用することができます。

PHPでは<font color="MediumVioletRed"><strong>PDOオブジェクト</strong></font>を使って<font color="DarkGreen"><strong>prepare()</strong></font>を使用することで可能となります。
<h4><strong>プレースホルダ</strong></h4>
プレースホルダは、<strong>「値をバインドさせる仕組み」</strong>のことです。

<font color="DarkGreen"><strong>bindvalue()</strong></font>という関数を使用することでSQL文内の目的の箇所に値を挿入することができます。これにより、<strong>実行段階で目的のパラメータを与えることができる</strong>ので、<strong>値をSQL文とは切り離して安全に活用する</strong>ことができます。


<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/52c0b18617bc1c323d4d7e788e7c6ec7.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/52c0b18617bc1c323d4d7e788e7c6ec7.png" alt="" width="1564" height="1342" class="aligncenter size-full wp-image-1925" /></a>

このつぶやきアプリではフォームから受け取った値をバインドした箇所に挿入し、<font color="DarkGreen"><strong>execute()</strong></font>で<span style="color: #3366ff;"><strong>プリペアードステートメント</strong></span>を実行しています。

また、<font color="DarkGreen"><strong>fetchAll()メソッド</strong></font>に<font color="MediumVioletRed"><strong>PDO::FETCH_ASSOC</strong></font>のフェッチスタイルを設定することで<strong>文字列キーによる配列として行全体を取得</strong>しています。

&nbsp;
引用元：<a href="https://webukatu.com/wordpress/blog/1638/">https://webukatu.com/wordpress/blog/1638/</a>

引用元：<a href="https://kinocolog.com/php_sql_injection/">https://kinocolog.com/php_sql_injection/</a>

<h2>タイムライン2-ログイン後の実装</h2>
タイムライン2（ログイン後）の画面では、タイムライン1（ログイン前）画面に加えて<span style="text-decoration: underline;">つぶやき投稿欄を追加</span>しています。ここで呟くことによってタイムラインに最新のつぶやきが表示されていきます。

ログイン後のタイムラインでは、ログイン成功のご褒美にみんな大好きひろゆきさんの動画を観ることができるようになります（笑）

つぶやき欄で好きなつぶやき（140文字以内）を打ち込み、確認するボタンを押下します。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/65133182d1a870640e4d60bd06e6c153.png"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/65133182d1a870640e4d60bd06e6c153.png" alt="" width="1920" height="1080" class="aligncenter size-full wp-image-1927" /></a>

つぶやき内容の確認画面では先ほど打ち込んだつぶやきが表示されるのでつぶやくボタンを押下することでタイムラインにつぶやきが反映されます。

また、つぶやき入力画面に戻っても先ほど入力した内容は保持されているため、つぶやきの一部を書き直したい場合でも手間なく編集できる工夫をしています。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/38773b1d37aa1b12626e6c75b98a8e55.png" style="opacity: 0.6; letter-spacing: 0.8px;"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/38773b1d37aa1b12626e6c75b98a8e55.png" alt="" width="1191" height="439" class="aligncenter size-full wp-image-1929" /></a>

投稿されるとこのようにタイムラインの上部につぶやきが表示されるようになります。

<a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/44153837159deb82fdd250f01979264d.jpg"><img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/44153837159deb82fdd250f01979264d.jpg" alt="" width="1920" height="1080" class="aligncenter size-full wp-image-1928" /></a><a href="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/65133182d1a870640e4d60bd06e6c153.png"></a>
<h2>最後に</h2>
今回の記事は結構内容が分厚めの記事となってしまいましたが、どうでしたでしょうか？

自己学習の一環で作成し始めたアプリですがいざ完成まで色々試行錯誤してみるとかなり勉強になり、<strong>本で読むだけ、動画で勉強するだけよりも遥かに高い効果が得られることがわかりました</strong>。

コードを書いていくことで頻発するエラーの解消法を探って原因を突き止めたり、このコードだとこんな処理になるというのがリアルタイムでわかるので、時間はかかりますが非常に自分の一つの経験として積み重なることを実感しています。

今回はアプリ作成を通して、HTML/CSS/PHPでのコーディング知識だけでなく、エラーの自力解決、セキュリティ対策、git操作、PDOに関するDB操作関連の知識、SESSIONの理解など幅広く学習することができ、やってよかったと思いました。

次はLaravelなどのフレームワークを活用したアプリケーションを作成して、より実務向きの技術を勉強していきたいなと思っています。

&nbsp;

ちなみにですが今回作成したつぶやきアプリ内でマリオがつぶやいている映画化は実話なので公開を楽しみに待ちたいと思います（笑）
&nbsp;
<iframe width="560" height="315" src="https://www.youtube.com/embed/R7TItoAalTg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>