这个场景通常出现在高级搜索或筛选功能中,用户可以在多个选项中进行选择,然后提交,后端需要获取这些被选中的值并进行查询。

整个过程分为三个部分:
- 前端显示:如何用PHP和HTML生成多选框。
- 后端接收:如何获取用户提交的多个值。
- 数据库查询:如何用获取到的多个值去查询数据库。
场景设定
假设我们要做一个文章的高级搜索,其中有一个“文章属性”的多选筛选,属性包括:“推荐”、“头条”、“特荐”、“热门”。
- 数据库字段:在
dede_archives表中,我们有一个字段叫flag,它是一个用逗号分隔的字符串,'c,h'表示“推荐”和“热门”。 - 目标:生成一个多选框,用户可以同时勾选多个属性,提交后,系统能筛选出包含所有选中属性的文章。
第一部分:前端显示 - 生成多选框
在织梦的模板文件中(advancedsearch.htm),我们可以使用PHP的循环来动态生成多选框。
使用 {dede:global name='k' /} 的原生方式
{dede:global name='k' /} 在这个场景下通常指的是一个包含所有可选选项的数组或字符串,我们可以在织梦的模板文件中直接嵌入PHP代码来实现。

<!-- 文件名:advancedsearch.htm -->
<h3>文章属性</h3>
<div class="filter-box">
<?php
// 1. 定义所有可选的属性及其对应的标识符
// 标识符最好用单个字符,方便存储和查询
$flags = array(
array('id' => 'c', 'name' => '推荐'),
array('id' => 'h', 'name' => '热门'),
array('id' => 'p', 'name' => '头条'),
array('id' => 's', 'name' => '特荐')
);
// 2. 循环生成多选框
foreach ($flags as $flag) {
// 检查当前选项是否被选中(用于页面刷新后保持选中状态)
$checked = '';
if (!empty($_REQUEST['flag']) && in_array($flag['id'], $_REQUEST['flag'])) {
$checked = 'checked';
}
// 输出HTML
echo '<label>
<input type="checkbox" name="flag[]" value="' . $flag['id'] . '" ' . $checked . ' />
' . $flag['name'] . '
</label>';
}
?>
</div>
代码解析:
$flags数组:我们定义了一个数组,每个元素是一个关联数组,包含id(值)和name(显示文本)。name="flag[]":这是HTML多选框的关键,方括号[]告诉PHP,当有多个同名复选框被选中时,将它们的值作为一个数组提交,而不是覆盖。value="' . $flag['id'] . '":每个复选框的值是我们定义的标识符(如 'c', 'h')。$checked变量:这是一个很好的用户体验优化,它会检查$_REQUEST['flag'](即用户上次提交的数据),如果当前选项在数组中,就给复选框加上checked属性,这样页面刷新后选中的状态就不会丢失。
更符合织梦习惯的写法(结合PHP和标签)
如果你不想在模板里写太多PHP,也可以先在PHP文件里处理好数据,再传给模板。
- 在PHP文件中(
advancedsearch.php):
<?php
require_once(dirname(__FILE__)."/include/common.inc.php");
// 定义所有可选的属性
$flags = array(
array('id' => 'c', 'name' => '推荐'),
array('id' => 'h', 'name' => '热门'),
array('id' => 'p', 'name' => '头条'),
array('id' => 's', 'name' => '特荐')
);
// 将处理好的数据分配给模板
$dsql->SetQuery("SELECT id,typename FROM `#@__arctype` WHERE reid=0");
$dsql->Execute();
$channelTypes = array();
while($row = $dsql->GetArray()){
$channelTypes[$row['id']] = $row['typename'];
}
// 将变量传递给模板
$templets->assign('flags', $flags);
$templets->assign('channelTypes', $channelTypes);
// 显示模板
$templets->display('advancedsearch.htm');
?>
- 在模板文件中(
advancedsearch.htm):
<h3>文章属性</h3>
<div class="filter-box">
{dede:loop name='flags' id='flag'}
<label>
<input type="checkbox" name="flag[]" value="{$flag.id}"
<?php if (!empty($_REQUEST['flag']) && in_array($flag['id'], $_REQUEST['flag'])) echo 'checked'; ?> />
{$flag.name}
</label>
{/dede:loop}
</div>
这种方式更清晰,将逻辑和视图分离。
第二部分:后端接收 - 获取提交的值
当用户提交表单后,数据会发送到你的处理脚本(advancedsearch.php),由于我们使用了 name="flag[]",PHP会自动将选中的值存入一个名为 flag 的超全局数组中。
在 advancedsearch.php 中,你可以这样获取:
<?php
// ... 引入文件等代码 ...
// 获取用户提交的“文章属性”数组
$selected_flags = isset($_REQUEST['flag']) ? $_REQUEST['flag'] : array();
// $selected_flags 现在是一个数组,
// 如果用户勾选了“推荐”和“热门”,$selected_flags array('c', 'h');
// 如果用户没有勾选任何项,$selected_flags 就是空数组 array();
// 你需要用这个数组去构建SQL查询...
第三部分:数据库查询 - 使用IN或LIKE
现在你有了 $selected_flags 数组,接下来就是最关键的一步:如何查询 flag 字段。
假设我们要查找同时满足所有选中属性的文章。
场景A:查找包含所有选中属性的文章 (AND 逻辑)
用户勾选了“推荐”和“热门”,我们想查找 flag 字段里同时包含 'c' 和 'h' 的记录。
// 假设 $selected_flags = array('c', 'h');
if (!empty($selected_flags)) {
// 1. 将数组用逗号连接成字符串,如 'c,h'
$flag_string = implode(',', $selected_flags);
// 2. 构建SQL查询
// 使用 FIND_IN_SET 函数是处理这种逗号分隔字符串最标准、最安全的方法
$sql = "SELECT * FROM `#@__archives`
WHERE FIND_IN_SET('c', flag) AND FIND_IN_SET('h', flag)
ORDER BY id DESC";
// 更动态的写法(推荐):
$sql_where = "";
foreach ($selected_flags as $f) {
// 注意:这里一定要对 $f 进行安全处理,防止SQL注入!
$f = $dsql->escapeString($f);
$sql_where .= " AND FIND_IN_SET('$f', flag)";
}
// 去掉开头的 " AND "
$sql_where = ltrim($sql_where, ' AND ');
$sql = "SELECT * FROM `#@__archives` WHERE $sql_where ORDER BY id DESC";
// 执行查询...
// $dsql->Execute('me', $sql);
// ...
}
FIND_IN_SET(str, strlist) 函数:
strlist是一个由逗号分隔的字符串,如 'a,b,c,d'。str在strlist中,则返回1,否则返回0。- 这正是我们处理
flag字段所需要的。
场景B:查找包含任意一个选中属性的文章 (OR 逻辑)
用户勾选了“推荐”和“热门”,我们想查找 flag 字段里包含 'c' 或者 'h' 的任意一个即可。
// 假设 $selected_flags = array('c', 'h');
if (!empty($selected_flags)) {
// 1. 将数组用逗号连接成字符串,如 'c,h'
$flag_string = implode(',', $selected_flags);
// 2. 构建SQL查询 (使用 IN)
// 这种方法更简洁,但要求 flag 字段的值必须和 'c,h' 完全匹配,所以不常用
// $sql = "SELECT * FROM `#@__archives` WHERE flag IN ('$flag_string')";
// 推荐使用 FIND_IN_SET 的 OR 逻辑
$sql_where = "";
foreach ($selected_flags as $f) {
$f = $dsql->escapeString($f);
$sql_where .= " OR FIND_IN_SET('$f', flag)";
}
// 去掉开头的 " OR "
$sql_where = ltrim($sql_where, ' OR ');
$sql = "SELECT `id`, `title`, `flag` FROM `#@__archives` WHERE $sql_where ORDER BY id DESC";
// 执行查询...
// $dsql->Execute('me', $sql);
// ...
}
| 步骤 | 关键点 | 代码/示例 |
|---|---|---|
| 前端生成 | 使用 name="flag[]" 将多个值构造成数组。 |
<input type="checkbox" name="flag[]" value="c"> |
| 后端接收 | $_REQUEST['flag'] 会自动是一个数组。 |
$selected_flags = $_REQUEST['flag']; // e.g., ['c', 'h'] |
| 数据库查询 | 使用 FIND_IN_SET() 函数来查询逗号分隔的字段。 |
WHERE FIND_IN_SET('c', flag) AND FIND_IN_SET('h', flag) |
通过以上三个步骤,你就可以在织梦CMS中完美实现基于 {dede:global name='k' /}(或自定义数组)的多选框功能了,在构建SQL时,永远要对用户输入进行安全转义(如 $dsql->escapeString()),以防止SQL注入攻击。
