文章

PHP - PDO 介紹與安全性


課程簡介

PDO(PHP Data Objects)是 PHP 提供的一個輕量級資料庫抽象層,支援多種資料庫。它的主要優點包括簡單易用、具可移植性,以及防止 SQL 注入的安全機制。本課程將介紹 PDO 的基本使用方法及如何編寫更安全的資料庫操作程式碼。


為什麼選擇 PDO

1. 支援多種資料庫

PDO 支援 MySQL、PostgreSQL、SQLite 等多種資料庫,僅需更改連接字串即可切換資料庫。

2. 防止 SQL 注入

PDO 支援參數化查詢,能有效防範 SQL 注入攻擊。

3. 統一的 API

無論操作哪種資料庫,PDO 使用的語法一致,減少學習成本。


PDO 基本操作

1. 建立連接

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$dsn = "mysql:host=localhost;dbname=example_db;charset=utf8mb4";
$username = "root";
$password = "";

try {
    $pdo = new PDO($dsn, $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "連接成功!";
} catch (PDOException $e) {
    echo "連接失敗:" . $e->getMessage();
}
?>

2. 插入資料(使用參數化查詢)

1
2
3
4
5
6
7
8
9
<?php
$sql = "INSERT INTO users (username, email) VALUES (:username, :email)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
    ":username" => "Alice",
    ":email" => "alice@example.com"
]);
echo "資料新增成功!";
?>

3. 查詢資料

使用 query() 查詢多筆資料

1
2
3
4
5
6
<?php
$sql = "SELECT * FROM users";
foreach ($pdo->query($sql) as $row) {
    echo "ID: " . $row["id"] . " - Name: " . $row["username"] . "<br>";
}
?>

使用 prepare() 與條件查詢

1
2
3
4
5
6
7
8
9
10
<?php
$sql = "SELECT * FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute([":username" => "Alice"]);

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $row) {
    echo "ID: " . $row["id"] . " - Email: " . $row["email"] . "<br>";
}
?>

4. 更新與刪除資料

更新資料

1
2
3
4
5
6
7
8
9
<?php
$sql = "UPDATE users SET email = :email WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute([
    ":email" => "new_email@example.com",
    ":username" => "Alice"
]);
echo "資料更新成功!";
?>

刪除資料

1
2
3
4
5
6
<?php
$sql = "DELETE FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute([":username" => "Alice"]);
echo "資料刪除成功!";
?>

提高安全性的實踐

1. 使用參數化查詢

參數化查詢能有效避免 SQL 注入攻擊,例如:

1
2
3
4
5
<?php
$sql = "SELECT * FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute([":username" => $_GET['username']]);
?>

避免的範例:

1
2
3
4
<?php
$sql = "SELECT * FROM users WHERE username = '" . $_GET['username'] . "'";  // 容易被注入攻擊
$result = $pdo->query($sql);
?>

2. 嚴格的錯誤處理

設定 PDO 屬性以拋出例外,便於除錯和處理錯誤:

1
2
3
<?php
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
?>

3. 使用交易(Transaction)

在執行多個相關操作時使用交易,確保操作的一致性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
try {
    $pdo->beginTransaction();

    $stmt = $pdo->prepare("INSERT INTO users (username, email) VALUES (:username, :email)");
    $stmt->execute([":username" => "Bob", ":email" => "bob@example.com"]);

    $stmt = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE user_id = :user_id");
    $stmt->execute([":amount" => 100, ":user_id" => 1]);

    $pdo->commit();
    echo "交易成功!";
} catch (Exception $e) {
    $pdo->rollBack();
    echo "交易失敗:" . $e->getMessage();
}
?>

4. 使用加密保護敏感資料

對密碼等敏感資料進行加密存儲:

1
2
3
4
5
6
7
8
9
<?php
$hashedPassword = password_hash("my_secure_password", PASSWORD_DEFAULT);

$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (:username, :password)");
$stmt->execute([
    ":username" => "Charlie",
    ":password" => $hashedPassword
]);
?>

驗證密碼:

1
2
3
4
5
6
7
<?php
if (password_verify("my_secure_password", $hashedPassword)) {
    echo "密碼正確!";
} else {
    echo "密碼錯誤!";
}
?>

教學練習

練習 1:參數化查詢

建立一個搜尋功能,使用參數化查詢根據使用者名稱查詢資料。


練習 2:交易操作

模擬購物車結帳功能,實現扣除庫存與更新使用者餘額的交易操作。


練習 3:加密與驗證

設計一個註冊與登入系統,將使用者密碼加密後儲存,並實現密碼驗證功能。


教學重點

  • 理解 PDO 的基本操作與優點。
  • 掌握參數化查詢的應用以防止 SQL 注入。
  • 熟悉交易的使用與敏感資料的加密保護技巧。

本文章以 CC BY 4.0 授權