PHP + MySQLでアプリを作成してみた【Blogアプリ】

公式サイト: [PHP マニュアル](https://www.php.net/manual/ja/index.php)

## phpMyAdmin とは?

- ブラウザ上でMySQLデータベースを管理できるツール
➡︎ 本来はコマンドでMySQLを操作するがMAMPに最初から入っている

## データベース とは?

- データを保管できる場所

## なぜデータベースを使うのか?

- データの管理・整理・検索ができる
- 複数人で同時に利用できる

## データベースを管理するシステム(DBMS)

- データベースの操作及び管理を行うシステム
➡︎ 現在の主流は、『リレーショナルデータベース管理システム（RDBMS）』

※ リレーショナルデータベース管理システム（RDBMS）の中に『MySQL』がある

## SQL言語

- データベースの操作を行うための言語
- データの追加・更新・削除・検索を行う

## SQL文の種類

- データ定義（DDL）: 主にテーブル操作
CREATE文:テーブルを作る
DROP文:テーブルを削除
ALTER文:テーブルを更新
JOIN文:テーブルを結合

- データ定義（DML）: 主にテータ操作
SELECT文:テーブルを取得
INSERT文:テーブルを追加
UPDATE文:テーブルを更新
DELETE文:テーブルを削除

- データ定義（DCL）: 主にアクセス制御
GRANT文:ユーザー権限を付与
BEGIN文:トランザクションを開始
COMMIT文:トランザクションを確定
ROLLBACK:トランザクションを取り消す

## データ定義（DDL）: 主にテーブル操作

例)　ブログにはどんなデータが必要か？
- id ・・・『プライマリーキー』と『オートインクリメント』
プライマリーキー：重複しない値を識別するため
オートインクリメント：１から順に自動で値を振ってくれる
- タイトル
- 本文
- カテゴリ
- 日付
- 公開状態

## MySQLの型の種類

- 数値型 : INT,TINYINT,BIGINTなど
- 文字列型 : VARCHAR,TEXTなど
- 日付と時間型 : DATE,TIMESTAMPなど

## Blog Table

| データ名 | 型 | 長さ | デフォルト | A＿I | 
|:-:|:-:|:-:|:-:|:-:|
| id  | INT  |   |   | あり  |  
| title  | VARCHAR  | 191  |   |   |   
| 本文  | TEXT  |   |   |   |   
| カテゴリ  | INT   |   |   |   |      
| 日付  | TIMESTAMP  |   |   |   |   
| 公開状態  | INT  |   |  あり |   |   

## PHPからMySQLデータベースに接続する
- PDOとは？（PHP Data Object）

PHP(5.1以降)標準のデータベース接続クラスのこと

- なぜPDOを使うのか？

データベース操作はシステムごとに命令が異なるが『PDO』なら同じ関数で操作ができるから

```sample.php
//データベースに接続

MySQL => mysql_connect();

PostgreSQL => pg__connect();
```
- MySQLデータベースにに接続する
```sample.php
$dsn = 'mysql:host=localhost;dbname=<project_name>;charset=utf8';
$user = '<MySQLで作成>';
$pass = '<MySQLで作成>';
$dbh = new PDO($dsn, $user, $pass, opt);
var_dump($dbh);

//new PDO = PDO接続を呼び出す(PDOクラスのインスタンスを作成)
```
#### charasetとは？utf8とは？
文字コードのこと
コンピュータが文字を識別するために割り当てられたコード（数値）のこと

#### ユーザとは？
データベースを操作する権限を持つ
初期設定は、全権限を持つroot（ルート）ユーザが用意

## htdocsをVscodeにドラッグする
ファイルを作成する
```
mkdir <ファイル名>
```

```dbc.php
<?php
$dsn = 'mysql:host=localhost;dbname=blog_app;charset=utf8';
$user = 'blog_user';
$pass = 'aaaaa';
$dbh = new PDO($dsn, $user, $pass);
var_dump($dbh);
?>
```
- try ~ catch とは？

DBのエラーをチェックできる構文
例外処理と呼ばれる

- 書き方

```
try {
//通常処理を書く。問題がなければ次へ。

}catch(){
//例外(エラー)が発生した場合に処理

}
```
```dbc.php
try {
  $dbh = new PDO($dsn, $user, $pass, [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  ]);

  echo "接続成功";
  $dbh = null;
} catch(PDOException $e) {
  echo "接続失敗".$e->getMessage();
  exit();
};

```
## データベース操作の基本
- データを取得するまでの3つの流れ
①SQL文の準備
②SQL文の実行
③SQL文の結果取り出し

## DBからデータを取得する
- blogテーブルから全データを取得する
①SQL文の準備
```
$sql = "SELECT * FROM blog";
　　　　　　//　* 全部　　blogテーブルから
```
②SQL文の実行
```
$stmt = $dbh->query($sql);
//$stmt = PDOstatement の意
```
③SQL文の結果取り出し

```
$result = $stmt-> fetchAll(PDO::FETCH_ASSOC) 
```

```dbc.php
<?php
$dsn = 'mysql:host=localhost;dbname=blog_app;charset=utf8';
$user = 'blog_user';
$pass = 'aaaaa';

try {
  $dbh = new PDO($dsn, $user, $pass, [
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  ]);
  //echo "接続成功";
  //①SQLの準備
  $sql = 'SELECT * FROM blog';
  //②SQLの実行
  $stmt = $dbh->query($sql);
  //③SQLの結果を受け取る
  $result = $stmt->fetchall(PDO::FETCH_ASSOC);
  // var_dump($result);
  $dbh = null;
} catch(PDOException $e) {
  echo "接続失敗".$e->getMessage();
  exit();
};

// var_dump($dbh);
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>BLOG一覧</title>
</head>
<body>
<h2>BLOG一覧</h2>
  <table>
    <tr>
      <th>No</th>
      <th>Title</th>
      <th>Category</th>
    </tr>
    <?php foreach($result as $column): ?>
    <tr>
      <th><?php echo $column['id'] ?></th>
      <th><?php echo $column['title'] ?></th>
      <th><?php echo $column['category'] ?></th>
    </tr>
    <?php endforeach; ?>
</table>
</body>
</html>
```

## 関数（引数・返り値）
- 関数とは？
あるデータが渡されている（IN）と、
それに応じてあるデータを返す（OUT）機能のこと

1. 内部(ビルドイン)関数
PHPにデフォルトで用意されている関数
例)htmlspecialchars,nl2br,count

2. 内部(ビルドイン)関数
独自に作成した関数

- 関数で覚えておきたい2つのこと

1. 引数
関数に渡されるデータのこと

2. 返り値(戻り値)
関数から返ってくるデータのこと

- あるデータが渡されている（引数）と、
それに応じてあるデータを返す（返り値）機能のこと

① 関数を定義する

```
function 関数名(引数){
   return 返り値;
}
```
② 関数を実行する
```
関数名(引数)
```


```dbc.php
<?php
//関数一つに一つの機能のみを持たせる
//1.データベースを接続
//2.データを取得する
//3.カテゴリー名を表示

//1.データベースを接続
//引数：無
//返り値：接続結果を返す

function dbConnect()
{
  $dsn = 'mysql:host=localhost;dbname=blog_app;charset=utf8';
  $user = 'blog_user';
  $pass = 'aaaaa';

  try {
    $dbh = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);
  } catch (PDOException $e) {
    echo "接続失敗" . $e->getMessage();
    exit();
  };
  return $dbh;
}
//2.データを取得する
//引数：無
//返り値：取得したデータ
function getAllBlog(){
  $dbh = dbConnect();
//①SQLの準備
  $sql = 'SELECT * FROM blog';
  //②SQLの実行
  $stmt = $dbh->query($sql);
  //③SQLの結果を受け取る
  $result = $stmt->fetchall(PDO::FETCH_ASSOC);
  return $result;
  $dbh = null;
}
//取得したデータを表示
$blogData = getAllBlog();

//3.カテゴリー名を表示
//引数：数字
//返り値：カテゴリーの文字列
function setCategoryName($category){
  if ($category === '1'){
    return 'ブログ';
  } elseif ($category === '2') {
    return '日常';
  } else {
    return 'その他';
  }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>BLOG一覧</title>
</head>
<body>
<h2>BLOG一覧</h2>
  <table>
    <tr>
      <th>No</th>
      <th>Title</th>
      <th>Category</th>
    </tr>
    <?php foreach($blogData as $column): ?>
    <tr>
      <th><?php echo $column['id'] ?></th>
      <th><?php echo $column['title'] ?></th>
      <th><?php echo setCategoryName($column['category']) ?></th>
    </tr>
    <?php endforeach; ?>
</table>
</body>
</html>
```
## プレースホルダーを使ってブログ詳細画面を表示する

一覧画面でかくブログをクリックすると、そのブログの詳細へ遷移
↓
データベースから該当のブログを取り出す
取り出す　➡︎ 　SELECT文
↓
データベースからの該当のブログを取り出す
『id』

①一覧画面からブログのidを送る
GETリクエストでidをURLにつけて送る

```dbc.php
<td><a href="/detail.php?id=<?php echo $column['id'] ?>">詳細</a></td>
```



②一覧画面からブログのidを送る
PHPの$_GETdでidを取得

```detail.php
<?php
$id = $_GET['id'];
echo $id;
?>
```




③idをもとにデータベースから記事を取得
SELECT文でプレースホルダーを使う

④詳細ページに表示する
HTMLにPHPを埋め込んで表示

```detail.php
<?php

//②一覧画面からブログのidを送る
$id = $_GET['id'];

if(empty($id)){
    exit('idが不正です。');
}

// ③idをもとにデータベースから記事を取得
Function dbConnect()
{
  $dsn = 'mysql:host=localhost;dbname=blog_app;charset=utf8';
  $user = 'blog_user';
  $pass = 'aaaaa';

  try {
    $dbh = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
  } catch (PDOException $e) {
    echo "接続失敗" . $e->getMessage();
    exit();
  };
  return $dbh;
}
$dbh = dbConnect();

//SQL準備
$stmt = $dbh->prepare('SELECT * FROM blog where id = :id');
$stmt->bindValue(':id',(int)$id,PDO::PARAM_INT);
//SQL準備
$stmt->execute();
//SQL準備
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if(empty($result)){
    exit('ブログがありません。');
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>BLOG詳細</title>
</head>
<body>
<!-- ④詳細ページに表示する -->
<h2>BLOG詳細</h2>
<h3>TITLE:<?php echo $result['title'] ?></h3>
<p>投稿日時：<?php echo $result['post_at'] ?></p>
<p>カテゴリ：<?php echo $result['category'] ?></p>
    <hr>
      <p>本文：<?php echo $result['content'] ?></p>
</body>
</html>
```
## プレースホルダーとは？
- SQL文に設定したい場所を確保して、後でSQLと分離して値を渡すことでSQL文を完成させる
- SQLインジェクション対策で利用
- 2種類の方法がある
1.　名前付きプレースホルダ
2.　疑問符プレースホルダ

## 外部ファイルを読み込む
- 外部ファイルを読み込みとは?
指定ファイルをまるっと読みこめる　⇨ つまり、再利用できる

- PHPの関数
require: 読み込み失敗で処理を中止
require_once: 再読み込みしない
include: 読み込み失敗でも処理は継続
include_once: 再読み込みしない

=>　処理が続行しても問題ないHTMLはincludeを使う
=>　ロジック系はrequire_onceを使う

- 名前空間とは(namespace)とは？
変数名・関数名などの重複（名前衝突）を回避するために使われる
- use（エイリアス）が一緒に使われる事が多い
例)namespace Name(名前空間名);
※ namespace は一番最初に書く事(厳密に言えばdeclare文は例外)





## 参考サイト
[【PHP/MySQL入門】MAMPのphpMyAdminでデータベースを使う準備 ~ブログアプリ作成~ #01](https://www.youtube.com/watch?v=ytw2GwWaLvk)
[【PHP/MySQL入門】テーブルを作ってSQLでデータを入れよう！ ~ブログアプリ作成~ #02](https://www.youtube.com/watch?v=8hWoyQKErTc)
[【PHP/MySQL入門】PDOを使ってMySQLデータベースに接続しよう！ ~ブログアプリ作成~ #03](https://www.youtube.com/watch?v=zz7KzILdBpU)
[【PHP/MySQL入門】データベースからブログ内容を取り出して一覧表示しよう！ ~ブログアプリ作成~ #04](https://www.youtube.com/watch?v=hnBUheNUAL0)
[【PHP/MySQL入門】関数（引数・返り値）をマスターしよう！ ~ブログアプリ作成~ #05](https://www.youtube.com/watch?v=iDo099q-njw)
[【PHP/MySQL入門】プレースホルダーでブログ詳細画面を表示しよう！ #06](https://www.youtube.com/watch?v=RxeE_HFSUJ0)
[【PHP/MySQL入門】外部ファイル読み込み(require,include)と名前空間を理解しよう！ ~ブログアプリ作成~ #07](https://www.youtube.com/watch?v=m-jdVjFij7E)