本篇為 [BE101] 用 PHP 與 MySQL 學習後端基礎 這門課程的學習筆記。如有錯誤歡迎指正。
課程筆記:[week 9] 後端基礎 - PHP 語法、資料庫 MySQL
前置作業
在開始實作留言板之前,需先進行前置作業:
- 規劃產品路由與功能
- 規劃資料結構:建立資料庫
Step1. 規劃產品路由與功能
頁面
- 留言板首頁
index.php
- 註冊頁面
register.php
- 登入頁面
login.php
功能
- 新增留言
handle_add_post.php
→ comments 資料庫 - 註冊
handle_register.php
→ users 資料庫 - 登入
handle_login.php
- 登出
logout.php
Step2. 規劃資料結構:建置資料庫
建立 comments 資料庫
- id
- nickname
- content
- creat_at
建立 users 資料庫
- id
- nickname
- username
- password
- creat_at
實作留言板
可分為前後端。通常會先切出前端頁面,再加入功能,從資料庫取出並資料串聯到頁面。
Step3. 實作前端頁面
依照設計稿切出所需頁面,可參考留言板 DEMO。
Step4. 實作目標功能
接著就進入重頭戲,也就是替靜態網頁加上各種功能。
PHP 常用函式
- 用
->
符號:取用物件中的變數- 例如:
$conn->error
- 例如:
require_once();
:取用資料夾中其他 library
require_once("conn.php"); // 連線到資料庫
require_once("utils.php"); // 導入常用函式
echo、print_r 與 var_dump 的區別
echo
:印出變數、字串等- 例如:
echo "hello World"
- 若使用 echo 輸出引用變數時(如陣列),只會輸出陣列名
- 例如:
print_r()
;:印出物件、陣列- 例如:
print_r($row);
- 例如:
var_dump
:印出變數型態,作用是輸出變數的詳細資訊
讀取資料
fetch_array()
:讀取資料同時,以數字與欄位名稱各存一次在陣列中fetch_assoc()
:讀取的資料 Key 值設定為欄位名稱的陣列fetch_row()
:讀取的資料 Key 值設定為依序的數字
<?php
// 把 $result 資料的 Key 值設定為欄位名稱的陣列
while($row = $result->fetch_assoc()) {
?>
<div class="card">
<div class="card__avatar"></div>
<div class="card__body">
<div class="card__info">
<span class="card__author"><?php echo $row['nickname']; ?></span>
<span class="card__time"><?php echo $row['created_at']; ?></span>
</div>
<p class="card__content"><?php echo $row['content']; ?></p>
</div>
</div>
<div class="board__hr"></div>
<?php } ?>
若以 print_r($row);
印出上述程式碼,可知 $row
為陣列:
檢查是否存在
isset()
:檢查是否有此變數empty()
:檢查是否有值
$username = NULL;
// 如果 session 中沒有存 username,就讀取 session
if(!empty($_SESSION['username'])) {
$username = $_SESSION['username'];
}
query()
:判斷資料庫查詢是否成功- 順利執行回傳 true
- 查詢的帳密有誤、查詢的指定資料庫、資料表欄位有誤等,均回傳 false
exit()
和die()
:兩者幾乎相同,均為輸出消息後退出程式
// 以 id 進行 DESC(遞減)排序:"後新增的留言"會排在前面
$result = $conn->query("SELECT * FROM comments ORDER BY id DESC");
// 檢查是否查詢成功
if (!$result) {
die('Error:' . $conn->error);
}
sprintf()
:裡面可放入替代字元
例如使用 sprintf()
做 SELECT:
// handle_login.php
$sql = sprintf(
"SELECT * FROM users WHERE username='%s' AND password='%s'",
$username,
$password
);
// 把執行結果存在 $result 這個變數中
$result = $conn->query($sql);
// 確認是否有拿到結果
if (!$result) {
die($conn->error);
}
用 sprintf()
做 INSERT INTO:
// handle_add_comment.php
$sql = sprintf(
"INSERT INTO comments(nickname, content) VALUES('%s', '%s')",
$nickname,
$content
);
// handle_register.php
$sql = sprintf(
"INSERT INTO users(nickname, username, password) VALUES('%s', '%s', '%s')",
$nickname,
$username,
$password
);
conn.php
連線資料庫
【注意】由於
conn.php
放有帳號密碼等重要資料,因此在 commit 前需加入git.ignore
,不進行版本控制。
程式碼如下:
<?php
$server_name = 'localhost';
$username = 'heidi';
$password = '1234';
$db_name = 'heidiDB';
// `mysqli` 的四個參數分別為:伺服器名稱、帳號、密碼、資料庫名稱
$conn = new mysqli($server_name, $username, $password, $db_name);
// 確認是否出現連線錯誤
if (!empty($conn->connect_error)) {
die('資料庫連線錯誤:' . $conn->connect_error);
}
// 設定編碼,避免出現亂碼
$conn->query('SET NAMES UTF8');
// 設定成臺灣時區
$conn->query('SET time_zone = "+8:00"');
?>
index.php
顯示所有留言
<?php
session_start();
// 連線到資料庫
require_once("conn.php");
require_once("utils.php");
$username = NULL;
if(!empty($_SESSION['username'])) {
$username = $_SESSION['username'];
}
// 以 id 進行 desc(遞減)排序,也就是"後新增的留言"會排在前面
$result = $conn->query("SELECT * FROM comments ORDER BY id DESC");
// 檢查是否有資料
if (!$result) {
die('Error:' . $conn->error);
}
?>
儲存狀態的方式:Cookie & Session
使用 Cookie 記住 HTTP 狀態
首先要了解 Cookie 是什麼:
- 是一種小型純文字檔案,
- 網站伺服器會將其儲存在 client 端,以記錄使用者的相關資訊。
- 例如:會員登入狀態、瀏覽紀錄、購物車等。
由於 HTTP 是一個無狀態協議,會把每一次收到的請求都視為獨立的行為。但伺服器能透過 response header 的 Set-Cookie
屬性,將使用者狀態記錄在 Cookie。
瀏覽器會在每次發送請求時,自動在 request header 帶上 Cookie 資料;伺服器即可藉由檢視 Cookie 內容,得知瀏覽器使用者的狀態。
但這麼做有個缺點,儲存在 client 端的 Cookie 是能夠被竄改的,因此不適合放機密或重要的資訊。這時有兩種解法:
1. 將 Cookie 內容加密
也就是 Cookie-based session,把狀態加密後存在 Cookie。但如果加密方式以及密鑰被破解,往後仍有安全疑慮。
2. 透過 Session ID 辨識身分
全名是 Session Identifier。如此 Server 只需在 Cookie 儲存一組亂數產生的 Session ID,其餘狀態資訊則存在 Server 端。
因此,Session 其實就是一種讓 Request 變成 stateful 的機制。
如何使用 Session
儲存 Session
當 $_SEESION
儲存成功,會進行下列三件事:
- 產生 sesseion id (token)
- 把 username 寫入檔案
set-cookie
:session-id
// 使用 Session 時,均需在開頭加上 session_start()
session_start();
$username = htmlspecialchars($_POST['username']);
// 把資料存在 Session 對應的 key 裡面
$_SEESION['username'] = $username;
讀取 Session
當 $_SESSION
讀取資料時,會進行下列三件事:
- 從 cookie 裡讀取 PHPSESSID (token)
- 從檔案裡面讀取 session id 的內容
- 把內容放到
$_SESSION
session_start();
// 若 Session 內有存過 username,則 $username 為剛才存的 $_SESSION['username']
if(isset($_SESSION['username'])) {
$username = $_SESSION['username'];
}
清除 Session
session_start();
// 直接清除所有 session
session_destroy();
參考資料:
- 27. [WEB] Cookie & Session 是什麼?
- 白話 Session 與 Cookie:從經營雜貨店開始