生PHPについて知識を資産化していく②

#前提として

+ 自分が勉強してきた知識を保存するために書いています。
+ 本当に初歩的な事から書いていってます。
+ 万が一間違っている可能性もございますので、その時はご指摘頂ければ嬉しいです。
+ 常時更新していく予定です。
+ アウトプット用ですので、MAMPを使用していきます。


#####PHPについての記事はこちらから

 + [生PHPについて知識を資産化していく①](https://qiita.com/shotee/items/9d82034a0b2960c7b4cf)
 + [生PHPについて知識を資産化していく③](https://qiita.com/shotee/items/2fa14f5ae06b6c4adec2)
 + [生PHPについて知識を資産化していく④](https://qiita.com/shotee/items/345da9bfa086c82c3e33)
 + [生PHPについて知識を資産化していく⑤]()

## 処理を止める
exitを使う
手前の変数がどうなっているのか確認する時に使う

```index.php
<?php
//処理を止める
$test = 123;
$test_2 = 456;

echo $test;
exit;
echo $test_2;
//123 と表示されるが、456は表示されない

?>
```

##form(GET, POST)

###GET通信
```
<?php

if (!empty($_GET)) {
  echo '<pre>';
  var_dump($_GET);
  echo '</pre>';
}

//ここの$で始まる変数をスーパーグローバル変数という　PHPは全部で9種類ある
//連想配列になる
?>

<!DOCTYPE html>
　　　・
　　　・
　　　・
    <form action="" method="GET"> //methodはGETかPOSTの2種類 //actionは処理をするファイル
      氏名
    <input type="text" name="your_name">

    <input type="submit" value="送信">

    </form>

↓
//入力フォームに ううう と入力した場合
array(2) {
  ["your_name"]=>
  string(9) "ううう"
}

```

###POST通信

```
<?php

if (!empty($_POST)) {
  echo '<pre>';
  var_dump($_POST);
  echo '</pre>';
}

?>

<!DOCTYPE html>
　　　・
　　　・
　　　・
//methodはGETかPOSTの2種類 //actionは処理をするファイル
    <form action="input.php" method="POST"> 
      氏名
    <input type="text" name="your_name">

    <input type="submit" value="送信">

    </form>

//出力はGETの時と同じだが、アドレスバーには表示されない

}

```

+ GET　→ フォームに入力した値がアドレスバーに出てくる
+ POST → フォームに入力した値が何も表示されない

##フォームの入力・確認・完了

１つの画面で入力、確認、完了画面を作成する

```
<?php

if (!empty($_POST)) {
  echo '<pre>';
  var_dump($_POST);
  echo '</pre>';
}

// 入力画面, 確認画面, 完了画面

$pageFlag = 0; // 0 → 入力, 1 → 確認, 2 → 完了 とする

//表示を切り替える処理
//btn_confirmの値が空でないなら
if (!empty($_POST['btn_confirm'])){
  $pageFlag = 1;
}
//btn_submitの値が空でないなら
if (!empty($_POST['btn_submit'])){
  $pageFlag = 2;
}

?>

<!DOCTYPE html>
   ・
   ・
   ・

  <?php if ( $pageFlag === 1 ) : ?>

    <form action="input.php" method="POST">
      氏名
      <?php echo $_POST['your_name'] ;?>
      <br>
      メールアドレス
      <?php echo $_POST['email'] ;?>
      <br>
      <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'] ;?>">
    </form>

  <?php endif; ?>

  <?php if ( $pageFlag === 2 ) : ?>
    送信が完了しました。
  <?php endif; ?>

    <?php if ( $pageFlag === 0 ) : ?>

    <form action="input.php" method="POST">
      氏名
      <input type="text" name="your_name">
      <br>
      メールアドレス
      <input type="email" name="email">
      <br>
      <input type="submit" name="btn_confirm" value="確認する">
// 'name'と'value'でキーと値となるので、'btn_confirm'に値が入っていれば「ボタンが押された」ということになる
    </form>

    <?php endif; ?>
      ・
      ・
      ・


// 氏名・メールアドレスを入力して「確認する」を押すと、'your_name'と'email'に値が入る。
  
```

###「戻る」ボタン

```
<input type="submit" name="back" value="戻る">
```

+ 戻った後に「氏名」「メールアドレス」欄に入力した値が入っている状態にする


```
<?php
   ・
   ・
   ・
    <?php if ( $pageFlag === 0 ) : ?>

    <form action="input.php" method="POST">
      氏名
      <input type="text" name="your_name" value="<?php if (!empty($_POST['your_name'])){echo $_POST['your_name'] ;}?> ">
      <br>
      メールアドレス
      <input type="email" name="email" value="<?php if (!empty($_POST['email'])){echo $_POST['email'] ;}?> ">
      <br>
      <input type="submit" name="btn_confirm" value="確認する">
    </form>

    <?php endif; ?>
   ・
   ・
   ・

?>
```

##XSS(クロスサイトスクリプティング)
掲示板サイトやTwitterのような、ユーザーからの入力内容によって表示が動的に変わるWebページやWebアプリケーションにおいて、Webサイト（標的サイト）の脆弱性（XSS脆弱性）を利用した攻撃手法を指す。

XSSに関して詳しくはこちら
[クロスサイトスクリプティングって何？サイトのセキュリティを高めるために](https://www.kagoya.jp/howto/network/xss/)
[クロスサイトスクリプティングとは|攻撃の仕組みと対策方法を解説](https://www.amiya.co.jp/column/cross_site_scripting_20210118.html)


###htmlspecialchars
特殊文字をHTMLエンティティに変換する
php.net：[htmlspecialchars](https://www.php.net/manual/ja/function.htmlspecialchars.php)

```
<?php
   ・
   ・
   ・

// サニタイズする
function h($str)
{
  return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

   ・
   ・
   ・

  <?php if ( $pageFlag === 1 ) : ?>

    <form action="input.php" method="POST">
      氏名
      <?php echo h($_POST['your_name']) ;?>
      <br>
      メールアドレス
      <?php echo h($_POST['email']) ;?>
      <br>
      <input type="submit" name="back" value="戻る">
      <input type="submit" name="btn_submit" value="送信する">
      <input type="hidden" name="your_name" value="<?php echo h($_POST['your_name']) ;?>">
      <input type="hidden" name="email" value="<?php echo h($_POST['email']) ;?>">
    </form>

  <?php endif; ?>

   ・
   ・
   ・

    <?php if ( $pageFlag === 0 ) : ?>

    <form action="input.php" method="POST">
      氏名
      <input type="text" name="your_name" value="<?php if (!empty($_POST['your_name'])){echo h($_POST['your_name']) ;}?> ">
      <br>
      メールアドレス
      <input type="email" name="email" value="<?php if (!empty($_POST['email'])){echo h($_POST['email']) ;}?> ">
      <br>
      <input type="submit" name="btn_confirm" value="確認する">
    </form>

    <?php endif; ?>

//アラートで出力されていたのが、入力後にそのまま出力される。

?>
```

###サニタイズ
サニタイズ（Sanitize）とは、危険なコードやデータを変換または除去して無力化する処理。 たとえば、Webサイトに設置された入力フォームなどから、悪意のあるコードが入力され、その文字列が実行されることで様々な被害に遭う可能性がある。
[サニタイズ/入力値検証/エスケープ の考え方](https://qiita.com/rana_kualu/items/11cd41de5f0364ba2ee8)


##CSRF(クロスサイトリクエストフォージェリーズ)
本物のページかのように偽物のページを作り、クリックすると悪意のあるページに遷移される。
formを作成するときは、必ずCSRF対策をする。
[クロスサイトリクエストフォージェリ（CSRF）とは？](https://siteguard.jp-secure.com/blog/what-is-csrf)
[3分でわかるXSSとCSRFの違い](https://qiita.com/wanko5296/items/142b5b82485b0196a2da)

###$_SESSION(セッション)を使う
トークンともいう。
合言葉のようなものを使用して、「本物のページから来ました!!」と確認してから処理を行う

```
$_GET → データを渡すと1回きりでそのデータが消えてします
$_POST → データを渡すと1回きりでそのデータが消えてします

$_SESSION → ずっとデータが残る

この$_SESSIONを使用して合言葉のやりとりをする
```

```
<?php
// セッションを使用する
session_start();

if (!empty($_SESSION)) {
  echo '<pre>';
  var_dump($_SESSION);
  echo '</pre>';
}

   ・
   ・
   ・
    <?php if ( $pageFlag === 1 ) : ?>
      <!-- 合言葉が正しいものかどうかを確認する -->
      <?php if ($_POST['csrf'] === $_SESSION['csrfToken']) :?>

      <form action="input.php" method="POST">
        氏名
        <?php echo h($_POST['your_name']) ;?>
        <br>
        メールアドレス
        <?php echo h($_POST['email']) ;?>
        <br>
        <input type="submit" name="back" value="戻る">
        <input type="submit" name="btn_submit" value="送信する">
        <input type="hidden" name="your_name" value="<?php echo h($_POST['your_name']) ;?>">
        <input type="hidden" name="email" value="<?php echo h($_POST['email']) ;?>">
        <input type="hidden" name="csrf" value="<?php echo h($_POST['csrf']) ;?>">
      </form>

      <?php endif; ?>

    <?php endif; ?>

    <?php if ( $pageFlag === 2 ) : ?>
    <!-- 合言葉が合っていたか確認する -->
      <?php if ($_POST['csrf'] === $_SESSION['csrfToken']) :?>
      送信が完了しました。
      <?php endif; ?>
    <?php endif; ?>

    <?php if ( $pageFlag === 0 ) : ?>
    //入力画面で合言葉を作る
    //$csrfTokenが設定されていなかったら設定する
    <?php
    if (!isset($_SESSION['csrfToken'])){}
    $csrfToken =  bin2hex(random_bytes(32));
    ?>

    <form action="input.php" method="POST">
      氏名
      <input type="text" name="your_name" value="<?php if (!empty($_POST['your_name'])){echo h($_POST['your_name']) ;}?> ">
      <br>
      メールアドレス
      <input type="email" name="email" value="<?php if (!empty($_POST['email'])){echo h($_POST['email']) ;}?> ">
      <br>
      <input type="submit" name="btn_confirm" value="確認する">
      //valueの中に合言葉が入ってくる
      <input type="hidden" name="csrf" value="<?php echo $_token; ?>">

    </form>

    <?php endif; ?>

?>
```


###random_bytes(ランダムバイト)
暗号論的に安全な、擬似ランダムなバイト列を生成する
php.net：[random_bytes](https://www.php.net/manual/ja/function.random-bytes.php)


###バリデーション

フォームに文字やメールアドレスを入力していく時に間違っていないかを確認する

```
文字 → 未入力、文字数
メールアドレス → 未入力、１つだけか
性別などの選択項目 → 未入力
郵便番号,　電話番号, カナ など
```

```validation.php
<?php

function validation($request) { //$_POSTの連想配列
// エラーをまとめて保管する
  $errors = [];

// もし氏名が空か、20文字より多かったらバリデーションを出す
  if(empty($request['your_name']) || 20 < mb_strlen($request['your_name'])){
    $errors[] = '「氏名」は必須です。20文字以内で入力してください。';
  }

// メールアドレスが空か、メールアドレスでなかったらバリデーションを出す
if (empty($request['email']) || !filter_var($request['email'], FILTER_VALIDATE_EMAIL)) {
  $errors[] = '「メールアドレス」は必須です。正しい形式で入力してください。';
}

// urlが空ではなく、urlでなかったらバリデーションを出す
if (!empty($request['url'])) {
  if(!filter_var($request['url'], FILTER_VALIDATE_URL)) {
    $errors[] = '「ホームページ」は正しい形式で入力してください。';
  }
}

// もし「性別」が設定されてなかったらバリデーションを出す
if (!isset($request['gender'])) {
  $errors[] = '「性別」は必須です';
}

// もし「年齢」が設定されてないか、設定したoptionのvalueの数より大きかったらバリデーションを出す
if (!isset($request['age']) || 6 < $request['age']) {
  $errors[] = '「年齢」は必須です。';
}

// もしお問い合わせ内容が空か、200文字より多かったらバリデーションを出す
  if(empty($request['contact']) || 200 < mb_strlen($request['contact'])){
    $errors[] = '「お問い合わせ内容」は必須です。200文字以内で入力してください。';
  }

// 「注意事項にチェックする」にチェックが入ってなかったらバリデーションを出す
  if(empty($request['caution']) || 200 < mb_strlen($request['caution'])){
    $errors[] = '「注意事項」をご確認ください。';
  }


  return $errors;
}

?>
```

```input.php
<?php
   ・
   ・
   ・
//validation.phpを呼び出す
require 'validation.php';
   ・
   ・
   ・
$pageFlag = 0;
//$errorsという変数を作る
$errors = validation($_POST);
   ・
   ・
   ・
//$errorsが空の場合の処理を追加する
if (!empty($_POST['btn_confirm']) && empty($errors)){
  $pageFlag = 1;
}
   ・
   ・
   ・
<!DOCTYPE html>
   ・
   ・
   ・
    <?php if ( $pageFlag === 0 ) : ?>
   ・
   ・
   ・
    //errorsがあり、確認ボタンが押されたらバリデーション表示
    <?php if (!empty($errors) && !empty($_POST['btn_confirm']) ) : ?>
      <?php echo '<ul>' ;?>
      <?php
        foreach($errors as $error) {
          echo '<li>' . $error .'</li>';
        }
      ?>
      <?php echo '</ul>' ;?>
    <?php endif ;?>

//入力フォームで、それぞれの値が空だとvalidation.phpで設定したバリデーションエラーが出る
//「メールアドレス」と「ホームページ」は、HTML5側でバリデーションをかけていたりするので、テストをする場合は、入力画面側で type を一旦 text にして確認する

?>


```

※filter_var
指定したフィルタでデータをフィルタリングする
php.net：[filter_varとは](https://www.php.net/manual/ja/function.filter-var.php)

##Bootstrap4

よく使われるレイアウト、デザインがセットになったCSSフレームワーク。
CSS + jQuery(JavaScript)

はじめにBootstrap4の[スターターテンプレート](https://getbootstrap.jp/docs/4.5/getting-started/introduction/)を使用する

```
<!doctype html>
<html lang="ja">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
  </body>
</html>

```

Formの場合
```
Components → Forms でそれぞれのデザインとコードがある
```

[Form用のデザインとコード](https://getbootstrap.jp/docs/4.5/components/forms/)


##ベーシック認証

SSL/TSL推奨
SSL(暗号化)をかけるという。暗号化されていないとパスワードがそのまま見えてしまう。

###ベーシック認証の設定ファイル

```
・.htaccessファイルで設定
・サーバー(Apache)の設定ファイル
・ディレクトリ毎に動作を制御できる
```

```test.php
<?php
// パスワードを記録したファイルの場所
echo __FILE__;

echo '<br>';
// パスワード(暗号化)
echo (password_hash('任意のパスワード', PASSWORD_BCRYPT));

// 暗号化されたパスワードが出る
?>
```

php.net：[password_hash()](https://www.php.net/manual/ja/function.password-hash.php)


###.htaccessファイル, .htpasswdファイル

ファイル名の先頭に「.」があると隠しファイル扱いになる

###.htaccess

```
//Basic認証を噛ませる
AuthType Basic

AuthName "IDとパスワードを入力してください"

// パスワードのファイルのありかを書く
AuthUserFile /Applications/MAMP/***/***/***/.htpasswd

// 認証したユーザーだけ入れる記述をする
require valid-user
                // 最後に改行を入れる

```

###.htpasswd

```
admin: test.phpで暗号化させたパスワードを入力
　　　　　　　　　 // 最後に改行を入れる
```

ログイン画面が出るので、ユーザー名が「admin」, パスワードが「任意のパスワード」と入力すると、test.phpの内容が出力される

※パスワードをコメントなどでファイルに書いているのはセキュリティ上まずいので、消すようにしましょう。


##ファイル操作

PHPでデータを保存する方法

```
①ファイル(テキストファイル) -> 手軽・データのやり取り

②データベース(MySQL, MariaDB) -> 大量のデータを保管
```

###ファイル操作の方法

```
・ファイル名型(ファイル丸ごと)
file_get_contents, file_put_contents

・ストリーム型(1行ごと)
fopen, fclose, fgets, fwrite

・オブジェクト型(オブジェクトとして)
SplFileObject
```


###ファイル名型

```
簡単なテキストファイル

あああ
いいい
ううう
```

```test.php
<?php

$contactFile = '.contact.dat';

//ファイルごと読み込む
$fileContents = file_get_contents($contactFile);

echo $fileContents; 

// ファイルに書き込み(上書き)
file_put_contents($contactFile, 'テストです');

// ファイルに書き込み(追記)
file_put_contents($contactFile, 'テストです', FILE_APPEND);

//.contact.datファイルに読み込み、上書き、追記がそれぞれされる
?>
```

###CSV形式を表示させる

####CSV形式

コンマ(,)で区切られている形式

```
簡単なテキストファイル

タイトル1, 本文1, 日付1, カテゴリ1
タイトル2, 本文2, 日付2, カテゴリ2
タイトル3, 本文3, 日付3, カテゴリ3
```

```
<?php

$contactFile = '.contact.dat';

$fileContents = file_get_contents($contactFile);

//配列(file)で使うか、 ,ごとに区切る(explode)

$allData = file($contactFile);

foreach($allData as $lineData) {
  $lines = explode(',', $lineData);
  echo $lines[0] . '<br>';
  echo $lines[1] . '<br>';
  echo $lines[2] . '<br>';
}

↓

タイトル1
本文1
日付1
タイトル2
本文2
日付2
タイトル3
本文3
日付3
?>
```

###ストリーム型

```
①開く fopen(r, w, a)
②排他ロック flock
③読み込み/書込/追記 fgets/fwrite
④閉じる fclose(ロック解除)
```

ストリーム型、オブジェクト型についてはこちらも参考になります!!
↓↓
[PHPファイル操作機能一覧](https://qiita.com/tadsan/items/0955b3de7dc58490ddaf)
php.net：[ファイルシステム](https://www.php.net/manual/ja/book.filesystem.php)


#####PHPについての記事はこちらから

 + [生PHPについて知識を資産化していく①](https://qiita.com/shotee/items/9d82034a0b2960c7b4cf)
 + [生PHPについて知識を資産化していく③](https://qiita.com/shotee/items/2fa14f5ae06b6c4adec2)
 + [生PHPについて知識を資産化していく④](https://qiita.com/shotee/items/345da9bfa086c82c3e33)
 + [生PHPについて知識を資産化していく⑤](https://qiita.com/shotee/items/cf859e6ad4b503600924)