iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0

在 PHP 中,PDO(PHP Data Objects)是目前連線與操作資料庫的標準規範,而 Prepared Statement(預備陳述式)則是防禦 SQL Injection 攻擊的核心防線。

今天目標是建立 config/database.php,讓 PHP 能夠穩定連線到 MySQL 。

步驟一:使用 Claude Code 建立 config/database.php

單例模式 (Singleton Pattern) 來管理資料庫連線,確保整個應用程式在執行期間只會建立一次連線,避免無謂的資源浪費。
在 WSL2 專案目錄下啟動 Claude Code,並下達以下 Prompt:

請幫我在 ~/library-system/config/database.php 撰寫一個使用 PDO 連線 MySQL 資料庫的函數或類別。

1.  資料庫名稱:library_system,主機:127.0.0.1,預設字元集:utf8mb4。

2.  請設定 PDO 錯誤模式為拋出例外 Exception(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)。

3.  預設抓取模式設定為關聯陣列(PDO::FETCH_ASSOC)。

4.  關閉模擬預備陳述式(PDO::ATTR_EMULATE_PREPARES => false)。

5.  使用 try-catch 區塊,若連線失敗請印出友善的錯誤訊息並停止程式。

生成出的程式碼:

<?php

class Database
{
    private static ?PDO $connection = null;

    public static function getConnection(): PDO
    {
        if (self::$connection === null) {
            $host = '127.0.0.1';
            $dbName = 'library_system';
            $charset = 'utf8mb4';
            $username = 'root';
            $password = '';

            $dsn = "mysql:host={$host};dbname={$dbName};charset={$charset}";

            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                // 設定預設的抓取模式:將查詢結果資料統一轉換為「關聯陣列」(Key-Value)
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                // 關閉模擬預備陳述式:強制要求 MySQL 使用原生的 Prepared Statement
                // 此設定能防止傳入的參數被當成 SQL 指令執行,是防範 SQL Injection 的關鍵
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            
            try {
                // 實例化 PDO 物件,傳入 DSN、帳號、密碼與設定選項,並賦值給靜態屬性
                self::$connection = new PDO($dsn, $username, $password, $options);
            } catch (PDOException $e) { // 當連線失敗或帳密錯誤時,捕捉拋出的 PDOException 例外物件 $e
                // 向使用者印出抽象且友善的錯誤訊息,避免暴露底層路徑或敏感資安資訊
                echo '資料庫連線失敗,請稍後再試或聯絡系統管理員。' . PHP_EOL;
                exit(1);
            }
        }
        // 當連線已存在(或剛建立完成),回傳靜態屬性中儲存的 PDO 連線物件
        return self::$connection;
    }
}

步驟二:建立測試檔 test_db.php 驗證 PDO 連線

在根目錄建立 test_db.php 來測試剛剛寫好的連線與 Prepare 查詢:

<?php

require __DIR__ . '/config/database.php';

// 測試用腳本:驗證資料庫連線與 Prepared Statement 查詢是否正常
$pdo = Database::getConnection();

// 查詢「程式設計」類別的書籍,確認連線與查詢結果正確
$sql = "SELECT id, title, available FROM books WHERE category = :category";
$stmt = $pdo->prepare($sql);
$stmt->execute([':category' => '程式設計']);
$books = $stmt->fetchAll();

echo "=== 查詢成功!程式設計類別書籍 ===" . PHP_EOL;
print_r($books);

在 WSL2 終端機中執行測試:

php test_db.php

執行結果,出現以下畫面就完成測試:
PDO 連線

PDO 連線除錯
在執行 php test_db.php 驗證連線時遇到了連線失敗的問題,以下是排查與修正步驟:

  1. 改 catch 印出真實錯誤訊息以便除錯
  2. root@localhost 因 auth_socket 認證被拒
  3. mysql_native_password 外掛未載入導致建帳號失敗
  4. 改用 caching_sha2_password、同時建 127.0.0.1 和 localhost 兩個 host 才成功
CREATE USER 'library_app'@'127.0.0.1' IDENTIFIED BY '';
CREATE USER 'library_app'@'localhost' IDENTIFIED BY '';
GRANT ALL PRIVILEGES ON library_system.* TO 'library_app'@'127.0.0.1';
GRANT ALL PRIVILEGES ON library_system.* TO 'library_app'@'localhost';
FLUSH PRIVILEGES;

今天建立了 PDO 資料庫連線架構,解決了 Ubuntu / WSL2 環境下的 MySQL 問題,並驗證了 Prepared Statements 的運作。明天會運用這套連線架構,正式開發圖書管理系統的核心 CRUD 邏輯。


上一篇
Day 10 Claude 給的第一版 schema,我改了什麼
下一篇
Day 12 書籍列表:第一個看得到的畫面
系列文
從零打造圖書管理系統:WSL2 × MySQL × Claude Code 的整合實作 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言