DedeCMS(织梦内容管理系统)作为国内早期开源CMS代表,至今仍占有约12%的中小网站市场份额(数据来源:2024年开源CMS使用统计报告),其中内容展示类网站占比超60%。阅读量是内容类网站核心数据指标之一,不仅用于衡量内容热度,还影响内容排序权重。本文针对V5.7及V5.8两个主流稳定版本,从底层存储结构、原生标签调用、自定义调用、常见问题排查、安全优化五个维度展开讲解。
DedeCMS阅读量的底层存储结构位于织梦核心数据表`dede_archives`中,核心字段为`click`,类型为INT(10) UNSIGNED,默认值为0。该字段通过每次用户访问内容页时触发数据库更新指令实现累加,V5.7/V5.8版本的原生触发逻辑均依赖内容页模板中的`{dede:field.click/}`标签调用,单独调用不会触发计数,需配合页面加载时的内联JS完成(部分第三方修改模板可能使用AJAX异步触发)。
原生阅读量标签的标准化调用
原生阅读量标签分为全局静态调用和内容页动态触发调用两类,两类标签的语法结构完全一致,但作用场景和计数逻辑不同。
全局静态调用指在列表页、首页、专题页等非内容详情页使用标签,仅从`dede_archives`表读取`click`字段的当前值,不会触发数据更新。
内容页动态触发调用是获取并更新阅读量的核心方式,模板加载时,内联JS会向织梦内置的`/plus/count.php`文件发送请求,实现单次访问计数+1的操作。
基础调用语法
基础调用语法仅展示纯数字阅读量,是最常用的调用形式。
```
{dede:field.click/}
```
将该标签放置在内容页模板的对应位置,即可完成基础数字展示,V5.7/V5.8通用。
带单位的调用语法
部分网站需要展示“次阅读”“人浏览”等单位,可使用DedeCMS的字符串拼接标签实现。
```
{dede:field.click/}次阅读
```
或使用`function='str_replace'`实现动态格式调整(如添加千分位),添加千分位的调用示例如下:
```
{dede:field.click function='number_format(@me)/'}次阅读
```
`number_format`是PHP内置函数,可自动将大于999的数字转换为带千分位的格式,如“12345”转换为“12,345”。
列表页多条件调用阅读量
列表页调用阅读量时,需配合`{dede:arclist/}`或`{dede:list/}`标签使用,默认这两个标签已包含`click`字段的查询权限,无需额外指定字段参数。
```
{dede:arclist row='10' titlelen='30'}
[field:title/]
阅读:[field:click function='number_format(@me)/']
{/dede:arclist}
```
上述代码可调用最新10篇文章的标题、链接和带千分位的阅读量。
自定义阅读量标签的实现方案
原生阅读量标签仅能展示基础数据,部分场景需要展示“今日阅读量”“周阅读量”“总/今日混合阅读量”等自定义数据,需通过修改数据表、添加自定义函数或修改`/plus/count.php`文件实现。
今日/周阅读量的存储与调用
首先需在`dede_archives`表中添加两个新字段,用于存储今日和周阅读量的数据。操作步骤如下:
1. 登录网站后台,进入【系统】→【SQL命令行工具】。
2. 选择【多行命令】,输入以下SQL语句:
```
ALTER TABLE `dede_archives` ADD `click_today` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '今日阅读量';
ALTER TABLE `dede_archives` ADD `click_week` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '周阅读量';
```
3. 点击【确定】按钮执行,系统提示“成功执行2条SQL语句”即完成字段添加。
接下来需修改`/plus/count.php`文件,添加今日/周阅读量的更新逻辑。找到文件中第46行左右的`$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `click`=`click`+1 WHERE `id`='$aid'");`语句,在其下方添加以下代码:
```php
// 获取今日0点的时间戳
$today_start = strtotime(date('Y-m-d'));
// 获取本周一0点的时间戳
$week_start = strtotime('this week Monday', time());
// 查询文章的最后更新阅读量时间
$last_click_time = $dsql->GetOne("SELECT `last_click_time` FROM `@__archives` WHERE `id`='$aid'");
// 若last_click_time不存在则添加该字段
if(!$last_click_time){
$dsql->ExecuteNoneQuery("ALTER TABLE `@__archives` ADD `last_click_time` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '最后更新阅读量时间'");
}
// 判断是否需要重置今日/周阅读量
if($last_click_time['last_click_time'] < $today_start){
$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `click_today`=1 WHERE `id`='$aid'");
}else{
$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `click_today`=`click_today`+1 WHERE `id`='$aid'");
}
if($last_click_time['last_click_time'] < $week_start){
$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `click_week`=1 WHERE `id`='$aid'");
}else{
$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `click_week`=`click_week`+1 WHERE `id`='$aid'");
}
// 更新最后更新阅读量时间
$dsql->ExecuteNoneQuery("UPDATE `@__archives` SET `last_click_time`=".time()." WHERE `id`='$aid'");
```
最后在模板中调用自定义字段即可,内容页调用示例:
```
总阅读:{dede:field.click function='number_format(@me)/'}
今日阅读:{dede:field.click_today function='number_format(@me)/'}
周阅读:{dede:field.click_week function='number_format(@me)/'}
```
列表页调用需在`{dede:arclist/}`或`{dede:list/}`标签中添加`addfields='click_today,click_week'`参数,示例:
```
{dede:arclist row='10' titlelen='30' addfields='click_today,click_week' channelid='1'}
[field:title/]
今日阅读:[field:click_today function='number_format(@me)/']
{/dede:arclist}
```
注意`channelid`参数需设置为对应内容模型的ID,普通文章模型为1,图片集模型为2,软件模型为3。
阅读量标签的常见问题排查
DedeCMS阅读量标签的常见问题主要集中在不显示、不计数、计数异常三个方面,以下逐一排查。
阅读量不显示
1. 检查标签语法是否正确,V5.7/V5.8版本的字段调用标签必须用`{dede:field.字段名/}`,列表页需放在`{dede:arclist/}`或`{dede:list/}`标签内部。
2. 检查模板是否更新,修改模板后需进入后台【生成】→【更新主页HTML】/【更新栏目HTML】/【更新文档HTML】生成对应页面,或开启【系统】→【系统基本参数】→【性能选项】中的“使HTML缓存”为“否”(开发阶段建议关闭,生产阶段可开启并设置合理的缓存时间)。
3. 检查数据库中`dede_archives`表的`click`字段是否存在,若不存在可通过SQL命令行工具添加:
```
ALTER TABLE `dede_archives` ADD `click` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '阅读量';
```
阅读量不计数
1. 检查内容页是否有调用`{dede:field.click/}`标签,单独调用`/plus/count.php`文件不会触发计数,必须配合标签调用(内联JS依赖标签调用时生成的`aid`参数)。
2. 检查`/plus/count.php`文件是否存在或被篡改,可从织梦官方下载对应版本的压缩包,解压后替换该文件。
3. 检查数据库用户是否有`dede_archives`表的UPDATE权限,可通过phpMyAdmin等工具查看数据库用户权限。
4. 检查是否安装了缓存插件或CDN,若安装了缓存插件,需将内容页设置为不缓存;若使用了CDN,需将`/plus/count.php`文件设置为不缓存。
阅读量计数异常
1. 检查是否有恶意刷量行为,可通过查看服务器访问日志,分析`/plus/count.php`文件的访问频率,若同一IP短时间内多次访问,可通过IP封禁插件或修改`/plus/count.php`文件添加IP限制逻辑。
2. 检查是否使用了AJAX异步触发但逻辑重复,部分第三方修改模板会同时保留原生内联JS和自定义AJAX,导致单次访问计数+2,需删除其中一个。
3. 检查`last_click_time`字段是否正常(自定义阅读量场景),若该字段值异常,可通过SQL命令行工具批量重置为0:
```
UPDATE `dede_archives` SET `last_click_time`=0;
```
阅读量标签的安全优化
`/plus/count.php`文件是织梦的一个高危文件,容易被恶意利用进行刷量或SQL注入,需进行以下安全优化:
1. 限制访问IP:在`/plus/count.php`文件开头添加IP白名单逻辑,仅允许网站自身服务器IP和CDN回源IP访问,示例:
```php
$allowed_ips = array('127.0.0.1', '服务器公网IP', 'CDN回源IP1', 'CDN回源IP2');
$client_ip = $_SERVER['REMOTE_ADDR'];
if(!in_array($client_ip, $allowed_ips)){
die('Access Denied');
}
```
注意需将示例中的IP替换为实际IP。
2. 添加参数验证:原文件中的`aid`参数未进行严格验证,容易被SQL注入,需在文件开头添加参数验证逻辑,示例:
```php
$aid = isset($_GET['aid']) ? intval($_GET['aid']) : 0;
if($aid <= 0){
die('Invalid Request');
}
```
3. 重命名文件:将`/plus/count.php`文件重命名为一个随机字符串,如`/plus/count_abc123.php`,然后修改所有内容页模板中的内联JS路径,内联JS通常位于模板的``或``标签末尾,格式为:
```
```
需将`count.php`替换为重命名后的文件名。
4. 删除多余代码:原文件中的`view=yes`参数用于控制是否显示阅读量,若不需要该功能,可删除相关代码,进一步降低安全风险。
主流版本的阅读量展示与更新逻辑基本一致,但自定义开发时需注意V5.8版本对PHP版本的要求更高(建议PHP7.0-PHP7.4),部分PHP5.6的语法可能无法正常运行。生产环境中建议开启HTML缓存并设置合理的缓存时间,减少数据库查询压力,同时定期备份数据库,防止数据丢失。