###### tags: `前後端系列`, `課程`
# 11/30 前後端系列 - 用實際例子帶你暸解後端
[TOC]
## 前置準備
- VS Code
- XAMPP (7.3.6 版本以上)
:::warning
如果 MAC OS 使用者,在安裝XAMPP遇到 **「無法打開xampp,因為無法驗證開發者。」** 可以參考此篇[解決方法](https://app.yipee.cc/92743/%E3%80%90macos-%E6%95%99%E5%AD%B8%E3%80%91%E6%95%99%E4%BD%A0%E8%A7%A3%E6%B1%BA%E3%80%8C%E7%84%A1%E6%B3%95%E6%89%93%E9%96%8B-xxx%EF%BC%8C%E5%9B%A0%E7%82%BA%E5%AE%83%E4%BE%86%E8%87%AA%E6%9C%AA%E8%AD%98/)
:::
- 到這邊下載上課要用的程式碼 [login-page](https://github.com/jovi920204/backend-course-material)
## 課程講義
### Windows
1. 下載並安裝XAMPP:
[下載連結](https://www.apachefriends.org/zh_tw/download.html)
2. 執行XAMPP, 並開啟Apache 和 Mysql 服務:

3. 在 C:\xampp\htdocs 新增資料夾

4. 將上一次實作的檔案放入資料夾裡

5. 在瀏覽器輸入 http://localhost/"資料夾名稱"/, 能成功看到畫面代表成功。

6. 在瀏覽器輸入 http://localhost/phpmyadmin/, 能成功看到畫面代表成功。

7. 建立資料庫。
- 左方選擇"新增"

- 依照下方設定: 編碼記得 **utf8mb4\_unicode\_ci**

- 成功

8. 建立資料表
- 
- 
- 儲存後

9. 手動新增USER
- 
- 進入 https://phppasswordhash.com/

- 輸入密碼,複製HASH CODE。

- 
- 
- 複製起來
```sql=
INSERT INTO `users` (`id`, `account`, `password`, `permission`) VALUES (NULL, 'admin', '$2y$10$MvOE/DStNVwKTfi1MdyIsOSqY9EGcL1zDUOgnc3bJg4kqoln6P7K6', '1');
```
:::info
auto_increment:自動新增流水號
:::
10. 
11. 將style分出來
- 
- 
12. 在 config.php 輸入
```php=
<?php
class Config
{
public $db_host = "127.0.0.1";
public $db_acconut = "root";
public $db_password = "";
public $db_name = "gdsctest";
}
?>
```
13. controller.php
```php=
<?php
require_once "./config.php";
class Controller
{
protected $config;
protected $db;
public function __construct()
{
$this->config = new Config();
$this->db = new PDO("mysql:host=" . $this->config->db_host . ";dbname=" . $this->config->db_name . ";charset=utf8", $this->config->db_account, $this->config->db_password);
// ("mysql:host=127.0.0.1;dbname=blabla_gdsc;charset=utf8", "root", "")
}
}
```
14. api.php
```php=
<?php
require_once "./controller.php"
$controller = new Controller();
?>
```
15. 在 controller.php 建立 login 函數
- 建立 login 函數
```php=
public function login()
{
$account = $_POST["account"];
$password = $_POST["password"];
echo $account;
echo $password;
}
```
- 在 api.php 加上 login()
```php=
<?php
require_once "./controller.php";
$controller = new Controller();
$controller->login();
?>
```
- 測試

- 成功

:::info
當送出表單時,如果聲明為 required 的欄位內容沒有填寫,會被瀏覽器提醒必填。


:::
16. 產生在資料庫查詢的CODE
- 在 phpmysql 中資料表的 "搜尋","account" 的運算子的部分改成 "=","值" 輸入 "admin"

- 複製他生成的語法
```sql=
SELECT * FROM `users` WHERE `account` = 'admin'
```
- 在 controller.php 中輸入
```php=
public function login()
{
$account = $_POST["account"];
$password = $_POST["password"];
$data = $this->db ->query("SELECT * FROM `users` WHERE `account` = '$account'")->fetchAll();
var_dump($data);
}
```
- 測試

- 成功

17. 資訊驗證
- 在 controller.php 中 的 login() 裡輸入
```php=
// 沒有資料
if(count($data) !== 1)
{
// die 執行後,不會再執行後面動作
die("no match");
}
// password_verify: 前面明文,後面雜湊值
if(!password_verify($password, $data[0]["password"]) )
{
// 驗證失敗
die("password not right");
}
```
- 建立 SESSION: 首先在 controller.php 的開頭加入
```php=
session_start();
```
- 設定 SESSION:
```php=
$_SESSION["id"] = $data[0]["id"];
$_SESSION["permission"] = (int)$data[0]["permission"];
echo $_SESSION["id"];
echo $_SESSION["permission"];
```
- 將 `index.html` 改為 `index.php`,並確認 SESSION 在 `index.php` 中可以執行成功
- 在開頭加入
```php=
<?php
session_start();
?>
```
- 在 body 中任意位置加入
```php=
<?= $_SESSION["id"] ?>
```
18. 設定權限及頁面跳轉
- 建立 management.php
```php=
<?php
session_start();
// SESSION 沒有設定 id 或 permission 的值
if(!isset($_SESSION["id"]) || !isset($_SESSION["permission"]))
{
// 跳轉至 index.php
header("Location: index.php");
}
// 沒有權限
if($_SESSION["permission"] !== 1)
{
// 跳轉至 normal.php
header("Location: normal.php");
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Management Page</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Management Page</h1>
</body>
</html>
```
- 建立 normal.php
```php=
<?php
session_start();
// 如果SESSION 沒有設定 id 或 permission 就跳轉回 index.php
if (!isset($_SESSION["id"]) || !isset($_SESSION["permission"])) {
header("Location: index.php");
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GDSC login</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<p>登入成功,但你沒權限QQ</p>
</body>
</html>
```
- 回到 controller.php 設定跳轉
```php=
if((int)$data[0]["permission"] === 1)
{
header("Location: management.php");
}
else
{
header("Location: normal.php");
}
```
- 測試

- 成功

19. 登出
- normal.php / management.php
```php=
<a href="api.php?function=logout">登出</a>
```
- api.php
```php=
<?php
require_once "./controller.php";
$controller = new Controller();
if (isset($_POST["function"]))
{
$data = $_POST;
}
else
{
$data = $_GET;
}
switch ($data["function"])
{
case 'login':
$controller->login();
break;
case 'logout':
$controller->logout();
break;
}
```
- index.php
```php=
<div class="fcc field">
<input required placeholder="username" type="text" name="account">
<input required placeholder="password" type="password" name="password">
<input type="hidden" name="function" value="login">
<input type="submit">
</div>
```
- controller.php
```php=
public function logout()
{
// 刪除 session 的 id 及 permission
unset($_SESSION["id"]);
unset($_SESSION["permission"]);
// 跳轉至原先的登入頁面
header("Location: index.php");
}
```
20. 新增使用者 (Optional)
- controller.php
```php=
public function add_user()
{
$account = $_POST["account"];
$password = password_hash($_POST["password"], PASSWORD_DEFAULT);
$permission = $_POST["permission"];
$data = $this->db->query("SELECT * FROM `users` WHERE `account` = '$account'")->fetchAll();
if (count($data) !== 0)
{
die("duplicated username");
}
$this->db->query("INSERT INTO `users` (`account`, `password`, `permission`) VALUES ('$account', '$password', '$permission');");
}
```
- api.php
```php=
switch ($data["function"])
{
case 'login':
$controller->login();
break;
case 'logout':
$controller->logout();
break;
case 'add_user':
$controller->add_user();
break;
}
```
- management.php
```php=
<input type="number" placeholder="0 => 一般使用者, 1 => 管理員" name="permission" min="0" max="1" required>
<input type="hidden" name="function" value="add_user">
```
---
### Mac
1. 下載並安裝XAMPP:
[下載連結](https://www.apachefriends.org/zh_tw/download.html)
2. 點到 Manage Serves 開啟Apache 和 Mysql 服務:

3. 在 Applications >> XAMPP\htdocs 中新增資料夾
4. 將上一次實作的檔案放入資料夾裡
5. 步驟 5 後請看 windows
:::info
如果看不到錯誤訊息,請到 XAMPP/etc 中找到 php.ini 檔案
將
`display_errors=Off` 改成
`display_errors=On`
:::