---
# System prepended metadata

title: 11/30 前後端系列 - 用實際例子帶你暸解後端
tags: [前後端系列, 課程]

---

###### 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 服務: 
    ![](https://i.imgur.com/bLs09Tk.png)

3. 在 C:\xampp\htdocs 新增資料夾
    ![](https://i.imgur.com/xOCU1lb.png)

4. 將上一次實作的檔案放入資料夾裡
    ![](https://i.imgur.com/P1zXsmP.png)

5. 在瀏覽器輸入 http://localhost/"資料夾名稱"/， 能成功看到畫面代表成功。
    ![](https://i.imgur.com/lfKnVft.jpg)
    
6. 在瀏覽器輸入 http://localhost/phpmyadmin/， 能成功看到畫面代表成功。
    ![](https://i.imgur.com/VQm2eew.png)

7. 建立資料庫。
    - 左方選擇"新增"
        ![](https://i.imgur.com/NnBbHvh.png)
    - 依照下方設定: 編碼記得 **utf8mb4\_unicode\_ci**

        ![](https://i.imgur.com/PIEzUJ9.png)
    - 成功
        ![](https://i.imgur.com/aQtPpby.png)

8. 建立資料表
    - ![](https://i.imgur.com/NevhChP.png)
    - ![](https://i.imgur.com/6X1oH7B.png)
    - 儲存後
        ![](https://i.imgur.com/MtYy6RH.png)

9. 手動新增USER
    - ![](https://i.imgur.com/Yzkn1Tx.png)
    - 進入 https://phppasswordhash.com/ 
        ![](https://i.imgur.com/Lj4UbyY.png)
    - 輸入密碼，複製HASH CODE。
        ![](https://i.imgur.com/dirXDmt.png)
    - ![](https://i.imgur.com/bSeFbBe.png)
    - ![](https://i.imgur.com/BdQW42B.png)
    - 複製起來
    ```sql=
    INSERT INTO `users` (`id`, `account`, `password`, `permission`) VALUES (NULL, 'admin', '$2y$10$MvOE/DStNVwKTfi1MdyIsOSqY9EGcL1zDUOgnc3bJg4kqoln6P7K6', '1');
    ```

:::info
auto_increment：自動新增流水號
:::

10. ![](https://i.imgur.com/HsNzrAG.png)

11. 將style分出來
    - ![](https://i.imgur.com/hCOGhdf.png)
    - ![](https://i.imgur.com/wlqvOgD.png)

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();
    ?>
    ```
    - 測試
    ![](https://i.imgur.com/0CO3mNz.png)

    - 成功
    ![](https://i.imgur.com/As0tJ9A.png)

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

![](https://i.imgur.com/6FqAJwr.png)

![](https://i.imgur.com/PQE6F5N.png)

:::

16. 產生在資料庫查詢的CODE
    - 在 phpmysql 中資料表的 "搜尋"，"account" 的運算子的部分改成 "="，"值" 輸入 "admin"
    ![](https://i.imgur.com/wqIlCbR.png)
    - 複製他生成的語法
    ```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);
    }
    ```

    - 測試
    ![](https://i.imgur.com/GqwoAz4.png)
    - 成功
    ![](https://i.imgur.com/kZRRcpb.png)

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");
    }
    ```
    
    - 測試
    
    ![](https://i.imgur.com/kNIhiHL.png)
    
    - 成功
    
    ![](https://i.imgur.com/d9YN8Fx.png)

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 服務: 
    ![](https://i.imgur.com/RysdN7X.png)

3. 在 Applications >> XAMPP\htdocs 中新增資料夾
4. 將上一次實作的檔案放入資料夾裡
5. 步驟 5 後請看 windows


:::info
如果看不到錯誤訊息，請到 XAMPP/etc 中找到 php.ini 檔案
將 
`display_errors=Off` 改成
`display_errors=On`
:::