PHP 搭配 MySQL 是動態網站開發的經典組合。本文梳理使用 MySQLi 擴展進行資料庫查詢的五大標準步驟,涵蓋資料過濾、連線建立、查詢執行、結果獲取與資源釋放,並說明物件導向與程序式兩種風格的差異。
所有外部輸入($_GET、$_POST、$_COOKIE)皆視為不可信,必須過濾。
| 函數 | 用途 |
|---|---|
trim() | 移除首尾空白字元 |
addslashes() | 在特殊字元前加反斜線(單引號、雙引號、NULL) |
stripslashes() | 移除 addslashes() 加入的反斜線 |
get_magic_quotes_gpc() | 檢查魔術引號是否開啟(PHP 5.4+ 已移除) |
htmlspecialchars() | 將 HTML 特殊字元轉為實體(防 XSS) |
最佳實踐: 使用 Prepared Statements(預處理語句)徹底防止 SQL 注入,而非依賴轉義函數。
MySQLi 提供兩種介面:
@$db = new mysqli('hostname', 'username', 'password', 'dbname');
if ($db->connect_errno) {
die("連線失敗: " . $db->connect_error);
}
@$db = mysqli_connect('hostname', 'username', 'password', 'dbname');
if (mysqli_connect_errno()) {
die("連線失敗: " . mysqli_connect_error());
}
錯誤抑制符 @: 防止預設錯誤訊息洩露敏感資訊,建議搭配自訂錯誤處理。
選擇資料庫: $db->select_db('dbname') 或 mysqli_select_db($db, 'dbname')。
$query = "SELECT * FROM user";
$result = $db->query($query); // OO 風格,回傳 mysqli_result 物件
// 或
$result = mysqli_query($db, $query); // 程序式,回傳資源
if (!$result) die("查詢失敗: " . $db->error);
$num_rows = $result->num_rows; // OO
$num_rows = mysqli_num_rows($result); // 程序式
while ($row = $result->fetch_assoc()) { // OO
// $row['欄位名'] = 值
}
// 或
while ($row = mysqli_fetch_assoc($result)) { ... }
fetch_row():數值索引陣列fetch_object():物件屬性對應欄位fetch_array(MYSQLI_BOTH):同時包含關聯與數值索引$result->free(); // 釋放結果集記憶體
$db->close(); // 關閉連線
// 程序式對應:mysqli_free_result($result); mysqli_close($db);
注意: 腳本結束時會自動釋放,但長時間運行的腳本(如 CLI)建議顯式釋放。
<?php
$db = new mysqli('localhost', 'user', 'pass', 'testdb');
if ($db->connect_errno) die("連線失敗");
$keyword = $db->real_escape_string($_GET['q'] ?? '');
$sql = "SELECT id, title FROM articles WHERE title LIKE '%{$keyword}%'";
$result = $db->query($sql);
if ($result) {
while ($row = $result->fetch_assoc()) {
echo "{$row['id']}: {$row['title']}<br>";
}
$result->free();
}
$db->close();
?>
prepare()/bind_param())防禦 SQL 注入。display_errors,啟用錯誤日誌。