在內容管理系統(CMS)或電商後台中,圖片管理是核心功能之一。用戶上傳圖片時,通常會在數據庫記錄元數據(名稱、路徑、上傳時間等),同時將文件存儲在服務器磁盤上。刪除操作必須保證數據庫記錄與物理文件同步移除,否則會產生「孤兒文件」佔用存儲,或「斷鏈記錄」導致前端報錯。本文通過一個完整的後台管理頁面案例,演示如何實現分頁列表、單條刪除、批量操作的最佳實踐。
該頁面採用「PHP + HTML 混合輸出」的傳統模式,包含三大模塊:
<?php
/**
* 圖片管理後台 - listUpload.php
* 功能:列表展示、分頁、單條/批量刪除(數據庫+文件)
*/
include "isLogin.php"; // 權限驗證
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gb2312">
<title>後台管理 - 圖片管理</title>
<link rel="stylesheet" href="style/lampcms.css">
<script src="javascript/common.js"></script>
</head>
<body>
<div id="main">
後台管理 → 圖片管理
<form method="post" action="">
<div class="msg-box">
<ul class="viewmess">
<li class="dark-row">
<span class="list_width width_font">圖片名稱</span>
<span class="list_width width_font">圖片路徑</span>
<span class="list_width width_font">添加時間</span>
<span class="list_width width_font">操作</span>
</li>
<?php
require "../conn/conn.php";
// ===== 1. 處理刪除請求(GET 方式,生產環境建議改 POST + CSRF)=====
if (isset($_GET['del'])) {
$id = intval($_GET['del']); // 強制轉整型,防注入
// 先查路徑
$sql2 = "SELECT picpath FROM pic WHERE id = $id";
$rst2 = mysql_query($sql2);
$row = mysql_fetch_assoc($rst2);
// 刪除數據庫記錄
mysql_query("DELETE FROM pic WHERE id = $id");
// 刪除物理文件
if ($row && file_exists($row['picpath'])) {
unlink($row['picpath']);
} elseif ($row) {
echo "<script>alert('圖片路徑不正確:{$row['picpath']}');</script>";
}
}
// ===== 2. 分頁參數計算 =====
$sql = "SELECT COUNT(*) AS total FROM pic";
$totalnum = mysql_result(mysql_query($sql), 0, 'total');
$pagenum = 5; // 每頁條數
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$begin = ($page - 1) * $pagenum;
$pagecount = ceil($totalnum / $pagenum);
// ===== 3. 當前頁數據查詢 =====
$sql2 = "SELECT * FROM pic ORDER BY id DESC LIMIT $begin, $pagenum";
$rst2 = mysql_query($sql2);
while ($row = mysql_fetch_assoc($rst2)) {
?>
<li class="light-row" style="padding: 2px 0;">
<span class="list_width width_font"><a href="" target="_blank"><?php echo htmlspecialchars($row['picname']); ?></a></span>
<span class="list_width width_font"><?php echo htmlspecialchars($row['picpath']); ?></span>
<span class="list_width width_font"><?php echo $row['ctime']; ?></span>
<span class="list_width width_font">
<a href="editUpload.php?edit=<?php echo $row['id']; ?>">【修改】</a>
<a href="listUpload.php?del=<?php echo $row['id']; ?>" onclick="return confirm('確定刪除此圖片?')">【刪除】</a>
</span>
</li>
<?php } ?>
<!-- 分頁導航 -->
<li class="dark-row">
<span class="right">
共 <?php echo $totalnum; ?> 條 ;共 <?php echo $pagecount; ?> 頁 ;每頁顯示 <?php echo $pagenum; ?> 條
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?page=1">首頁</a>
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?page=<?php echo max(1, $page-1); ?>">上一頁</a>
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?page=<?php echo min($pagecount, $page+1); ?>">下一頁</a>
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?page=<?php echo $pagecount; ?>">尾頁</a>
</span>
</li>
</ul>
</div>
</form>
</div>
</body>
</html>
代碼採用「先查路徑 → 刪數據庫 → 刪文件」的順序,這是一個關鍵設計決策:
picpath,否則刪除記錄後無法知道文件位置。$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
// 防止負數、非數字、超大頁碼
$page = min($page, max(1, $pagecount));
上述代碼通過 intval() 強制類型轉換,max()/min() 限制範圍,徹底杜絕 SQL 注入與邏輯越界。
| 風險點 | 原代碼問題 | 修復方案 |
|---|---|---|
| SQL 注入 | 直接拼接 $id 進 SQL | intval($_GET['del']) 或預處理語句 |
| XSS 攻擊 | 直接輸出 $row['picname'] 等字段 | htmlspecialchars() 轉義輸出 |
| CSRF 攻擊 | 刪除操作用 GET 請求,無 Token 驗證 | 改為 POST + 隱藏 csrf_token 驗證 |
| 路徑遍歷 | 未驗證 picpath 是否在允許目錄 | realpath() 對比 UPLOAD_ROOT 確保在沙箱內 |
若項目允許引入現代框架(Laravel/ThinkPHP/Symfony)或組件,建議:
mysql_* 函數(已棄用/移除)。PictureService::delete($id),控制器僅處理請求響應。unlink 推入消息隊列,避免阻塞 HTTP 響應。本案例展示了經典 PHP 圖片管理的核心流程:數據庫與文件系統的雙重刪除、分頁查詢、前端交互。雖然代碼風格屬於早期「頁面級腳本」模式,但其業務邏輯清晰,是理解 Web 文件管理本質的優秀教材。實際項目中,請務必在安全性、可維護性、擴展性三個維度進行分層重構,構建健壯的生產級系統。