在 PHP 中,PDO(PHP Data Objects)是目前連線與操作資料庫的標準規範,而 Prepared Statement(預備陳述式)則是防禦 SQL Injection 攻擊的核心防線。
今天目標是建立 config/database.php,讓 PHP 能夠穩定連線到 MySQL 。
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 連線除錯
在執行php test_db.php驗證連線時遇到了連線失敗的問題,以下是排查與修正步驟:
- 改 catch 印出真實錯誤訊息以便除錯
- root@localhost 因 auth_socket 認證被拒
- mysql_native_password 外掛未載入導致建帳號失敗
- 改用 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 邏輯。