
本文详解如何通过 url 查询参数(get)将 php 动态生成的课程卡片按钮所对应的数据库 id,从 `theory.php` 可靠传递至 `theory1.php`,并给出防 sql 注入、避免硬编码索引、提升可维护性的完整实践方案。
在构建课程展示类 Web 应用时,常需根据数据库中的多条记录动态生成卡片式 UI,并为每张卡片配备一个“进入详情”按钮。关键挑战在于:点击不同卡片的按钮时,必须精准、安全地将对应课程的唯一标识(如 courseID)传递到目标页面(如 theory1.php),以便后续查询和渲染专属内容。
原始代码中存在两个核心问题:
- 使用循环变量 $i 作为 courseID 值(WHERE courseID = '$i'),但 $i 是数组下标而非真实数据库主键,极易因数据删除/排序导致错位;
- URL 中拼接参数时误用单引号字符串,导致 href="theory1.php?course_ID=$i" 中的 $i 未被解析(PHP 变量在单引号内不生效)。
✅ 正确做法是:直接使用数据库查询结果中的真实主键字段(如 $rowQuery['courseID'])构造 URL 参数,并确保在双引号或字符串拼接中正确输出。
以下是优化后的 theory.php 关键代码(已移除冗余查询、修复变量解析、增强健壮性):
立即学习“PHP免费学习笔记(深入)”;
<?php
require('components/db.php');
// ✅ 一次性获取全部课程,避免 N+1 查询
$query = "SELECT courseID, courseName, courseTextOne, imageLink FROM `courses` ORDER BY courseID";
$result = mysqli_query($connect, $query) or die("Database error: " . mysqli_error($connect));
if (mysqli_num_rows($result) > 0) {
while ($row = mysqli_fetch_assoc($result)) {
// ✅ 使用真实 courseID 构建链接 —— 安全、准确、可预测
$courseID = (int)$row['courseID']; // 强制转整型,防御基础注入
echo <<<HTML
<div class="card">
<img class="cardImage" src="{$row['imageLink']}" alt="{$row['courseName']}">
<h3>{$row['courseName']}</h3>
<p>{$row['courseTextOne']}</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站"><img
src="https://img.php.cn/upload/skill/000/000/081/179040786932301.jpg" alt="btpanel phpsite 宝塔面板PHP网站" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站">btpanel phpsite 宝塔面板PHP网站</a>
<p>宝塔面板 PHP 网站管理:站点创建、删除、启停、PHP 版本切换、域名管理、SSL证书管理、伪静态管理、数据库管理</p>
</div>
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
<a href="theory1.php?courseID={$courseID}" class="button">Proceed</a>
</div>
HTML;
}
} else {
echo "<p>No courses available.</p>";
}
?>? 关键改进说明: 使用 while 遍历单次查询结果,大幅提升性能; 直接取 $row['courseID'] 而非循环索引 $i,确保 ID 与数据库真实主键一致; 对 courseID 强制 (int) 类型转换,既过滤非法字符,又为后续 $_GET 使用提供安全基础; 采用 Heredoc 语法(
在 theory1.php 中,应始终对传入参数进行验证与过滤,再用于业务逻辑:
<?php
require('components/db.php');
// ✅ 安全获取并校验 courseID
$courseID = isset($_GET['courseID']) ? (int)$_GET['courseID'] : 0;
if ($courseID <= 0) {
die("Invalid or missing course ID.");
}
// ✅ 使用预处理语句防止 SQL 注入(强烈推荐)
$stmt = $connect->prepare("SELECT * FROM `courses` WHERE courseID = ?");
$stmt->bind_param("i", $courseID);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 1) {
$course = $result->fetch_assoc();
echo "<h2>{$course['courseName']}</h2>";
echo "<p>{$course['courseTextOne']}</p>";
// 这里可继续渲染课程详情...
} else {
echo "<p>Course not found.</p>";
}
?>⚠️ 重要注意事项:
- 永远不要信任 $_GET 输入:即使前端做了限制,攻击者仍可手动构造 URL。务必强制类型转换 + 服务端校验;
- 避免 Session 临时存储 ID 作跳转依据:原代码中 $_SESSION['course_ID'] = $i 在循环中被反复覆盖,且无法保证用户点击的是最后一次赋值的卡片——此方式不可靠,应弃用;
- URL 参数可见且可篡改:若涉及敏感操作(如删除、权限变更),请改用 POST + CSRF Token 或后端会话绑定校验;
- 考虑使用语义化路由:如 theory1.php/123(配合 .htaccess 重写),但 GET 参数仍是当前最简洁通用的方案。
综上,通过「真实主键 + 安全拼接 + 严格校验 + 预处理查询」四步,即可稳健实现跨页 ID 传递。这不仅是功能实现,更是构建可维护、可审计、符合 Web 安全最佳实践的 PHP 应用的基础能力。


















