dede sql 如何安全高效传递参数?

99ANYc3cd6
预计阅读时长 24 分钟
位置: 首页 DEDE建站 正文

将 PHP 变量安全地拼接到 SQL 查询语句中

dede sql 传递参数
(图片来源网络,侵删)

下面我将分步骤、从简单到复杂地进行说明,并重点强调安全防范


第一步:获取参数

在 DedeCMS 中,传递参数通常有两种方式:

  1. URL GET 方式:通过 URL 的查询字符串传递,https://www.example.com/plus/list.php?tid=1&pagesize=10
  2. 表单 POST 方式:通过表单提交传递,例如搜索功能。

在 PHP 中,我们可以使用 $_GET$_POST 超全局变量来接收这些参数。

示例: 假设 URL 是 https://www.example.com/yourpage.php?typeid=5&order=hotyourpage.php 文件中,我们可以这样获取参数:

dede sql 传递参数
(图片来源网络,侵删)
// 获取 typeid 参数,如果不存在则默认为 0
$typeid = isset($_GET['typeid']) ? (int)$_GET['typeid'] : 0;
// 获取排序参数,如果不存在则默认为 'new'
$order = isset($_GET['order']) ? trim($_GET['order']) : 'new';
// 打印一下看看结果
echo "typeid: " . $typeid . "<br>";
echo "order: " . $order;

重要提示:对获取的参数进行初步的类型转换和过滤(如 (int)trim())是一个好习惯,可以避免很多不必要的麻烦。


第二步:编写 SQL 查询语句

获取到参数后,我们就可以在 SQL 语句中使用它们,最直接的方式是使用字符串拼接。

示例: 我们要查询 dede_archives 表中 typeid 为我们获取到的 $typeid 值,并且按 $order 指定的字段排序的文章。

// 1. 获取参数
$typeid = isset($_GET['typeid']) ? (int)$_GET['typeid'] : 0;
$order = isset($_GET['order']) ? trim($_GET['order']) : 'new';
// 2. 拼接 SQL 语句
$sql = "SELECT * FROM dede_archives WHERE typeid = '$typeid' ORDER BY ";
if ($order == 'hot') {
    $sql .= "click DESC"; // 按点击量降序
} else {
    $sql .= "id DESC"; // 按ID降序 (默认)
}
// 打印 SQL 语句进行检查
echo "执行的 SQL 语句是: " . $sql;

这段代码的潜在问题: 上面的拼接方式存在巨大的SQL 注入风险$typeid 是一个恶意的字符串,1 OR 1=1,SQL 语句就变成了 ... WHERE typeid = 1 OR 1=1,这会导致查询出所有数据,甚至更严重的数据泄露或破坏。

dede sql 传递参数
(图片来源网络,侵删)

第三步:安全执行 SQL 查询 (核心)

为了安全地执行 SQL,DedeCMS 提供了专门的数据库操作类 DedeSql(或 dedesql),我们应该使用它提供的方法,而不是直接执行 mysql_query

使用 SetQuery + ExecuteQuery (推荐)

这是最安全、最推荐的方式。SetQuery 方法会自动处理参数,防止 SQL 注入。

语法: $dsql->SetQuery("SQL语句 [WHERE ...]"); $dsql->Execute('别名');

关键点:

  • 在 SQL 语句中,使用 作为占位符
  • 将 PHP 变量作为第二个参数传递给 ExecuteQuery 方法,它会自动替换 。

安全改造后的代码:

// 1. 获取并过滤参数
$typeid = isset($_GET['typeid']) ? (int)$_GET['typeid'] : 0;
$order = isset($_GET['order']) ? trim($_GET['order']) : 'new';
// 2. 实例化 DedeSql 数据库操作类
$dsql = new DedeSql();
// 3. 编写带占位符的 SQL 语句
$sql = "SELECT * FROM dede_archives WHERE typeid = ##typeid## ORDER BY ";
if ($order == 'hot') {
    $sql .= "click DESC";
} else {
    $sql .= "id DESC";
}
// 4. 设置查询并执行
// 将 $typeid 变量作为数组传递给 ExecuteQuery
$dsql->SetQuery($sql);
$dsql->ExecuteQuery('list', $typeid); // 'list' 是查询结果的别名,可以自定义
// 5. 遍历查询结果
while ($row = $dsql->GetArray('list')) {
    echo "<h3>" . $row['title'] . "</h3>";
    echo "<p>" . $row['description'] . "</p>";
    echo "<hr>";
}
// 6. 释放资源
$dsql->Close();

工作原理: ExecuteQuery 方法内部会检测到 ##typeid## 占位符,然后将它替换为传递进来的 $typeid 变量的值,并且会进行必要的转义处理,从而杜绝了 SQL 注入。

使用 Select 快捷方法 (更简洁)

对于简单的 SELECT 查询,DedeSql 类还提供了一个非常方便的 Select 方法。

语法: $dsql->Select("表名", "字段", "WHERE条件", "排序限制");

示例:

// 1. 获取并过滤参数
$typeid = isset($_GET['typeid']) ? (int)$_GET['typeid'] : 0;
$order = isset($_GET['order']) ? trim($_GET['order']) : 'new';
// 2. 实例化 DedeSql
$dsql = new DedeSql();
// 3. 使用 Select 方法
// 注意:这里的条件部分同样使用 ## 作为占位符
$dsql->Select("dede_archives", "*", "typeid=##typeid##", "id DESC", $typeid);
// 4. 遍历结果
while ($row = $dsql->GetArray()) {
    echo "<h3>" . $row['title'] . "</h3>";
    echo "<p>" . $row['description'] . "</p>";
    echo "<hr>";
}
// 5. 释放资源
$dsql->Close();

这种方式更紧凑,但功能上不如 SetQuery + ExecuteQuery 灵活。


第四步:综合实例 - 自定义列表页

这是一个完整的、可以在 DedeCMS 模板文件中使用的例子,假设我们要做一个“热门文章排行榜”页面,可以通过 URL 指定分类 ID。

文件路径:/templets/default/custom_hotlist.htm

<!DOCTYPE html>
<html>
<head>热门文章列表</title>
</head>
<body>
    <h1>热门文章排行榜</h1>
    <?php
    // 1. 包含并初始化 DedeSql
    // (通常在 DedeCMS 的 PHP 文件中,$dsql 全局变量已经存在,但在独立页面需要自己创建)
    if (!defined('DEDEINC')) exit('dedecms error!');
    require_once(DEDEINC.'/dedesql.class.php');
    $dsql = new DedeSql();
    // 2. 获取 URL 参数
    $typeid = isset($_GET['tid']) ? (int)$_GET['tid'] : 0;
    $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10; // 可选:限制条数
    // 3. 构建 SQL 语句并执行
    if ($typeid > 0) {
        // 如果指定了分类ID,则查询该分类下的热门文章
        $sql = "SELECT id, title, click, litpic FROM dede_archives WHERE typeid = ##typeid## AND arcrank > -1 ORDER BY click DESC LIMIT 0, ##limit##";
        $dsql->SetQuery($sql);
        // 传递多个参数
        $dsql->ExecuteQuery('hotlist', array('typeid' => $typeid, 'limit' => $limit));
    } else {
        // 如果没有指定分类ID,则查询全站热门文章
        $sql = "SELECT id, title, click, litpic FROM dede_archives WHERE arcrank > -1 ORDER BY click DESC LIMIT 0, ##limit##";
        $dsql->SetQuery($sql);
        $dsql->ExecuteQuery('hotlist', array('limit' => $limit));
    }
    // 4. 在模板中循环输出
    while ($row = $dsql->GetArray('hotlist')) {
        $arcUrl = GetOneArchive($row['id']); // 使用系统函数获取文章链接
        echo "<div class='hot-item'>";
        echo "<a href='" . $arcUrl['arcurl'] . "'>" . $row['title'] . "</a>";
        echo "<span>点击: " . $row['click'] . "</span>";
        echo "</div>";
    }
    // 5. 释放资源
    $dsql->Close();
    ?>
</body>
</html>

如何访问: 访问 https://www.yoursite.com/templets/default/custom_hotlist.htm?tid=5&limit=20 即可查看 ID 为 5 的分类下的前 20 篇热门文章。


总结与最佳实践

  1. 永远不要相信外部输入:对所有通过 $_GET, $_POST 等获取的参数进行过滤和验证。
  2. 优先使用 DedeSql 的占位符:始终使用 ##变量名## 作为占位符,并通过 ExecuteQuery 的第二个参数传递变量,这是防止 SQL 注入的黄金法则
  3. 限制查询范围:在 WHERE 条件中,尽量加上 arcrank > -1(表示审核通过)等条件,避免调用到未发布或被删除的内容。
  4. 使用系统函数:获取文章链接、栏目链接等,尽量使用 DedeCMS 自带的函数(如 GetOneArchive, GetTypeLink),而不是自己硬编码 URL。
  5. 及时释放资源:查询结束后,调用 $dsql->Close() 关闭数据库连接,释放内存。

遵循以上原则,你就可以在 DedeCMS 中安全、灵活地使用 SQL 语句并传递参数了。

-- 展开阅读全文 --
头像
C语言1 1 2 1 2 3是什么规律?
« 上一篇 今天
C、C++、Java,三者如何选择?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]