需要明确的是,直接给出一个完整的、可以直接运行的“发帖功能”源代码是不现实的,因为发帖功能是一个涉及前端表单提交、后端数据处理、数据库交互、权限验证等多个环节的复杂系统,织梦CMS作为一个成熟的CMS系统,其代码结构也比较复杂。

我将为你分解整个发帖流程,并提供每个关键环节的核心代码片段和文件路径,并附上详细的解释,这样你就能理解其工作原理,并可以根据自己的需求进行修改或二次开发。
核心概念:织梦的“发帖”是什么?
在织梦CMS中,用户在前台发布的“帖子”或“文章”,在后台数据模型中,通常对应以下两种之一:
- 普通文章模型:这是最常见的方式,用户发布的帖子被当作一篇文章来处理,这种方式的优点是可以直接利用织梦强大的文章管理、分类、标签、评论等功能。
- 自定义模型:如果你需要一个更复杂的帖子结构(带有不同字段如“价格”、“联系方式”、“地理位置”等),可以在后台创建一个自定义模型,然后在前台调用这个模型的发布接口。
我们将以最常见的“普通文章模型”为例,来解析其发帖流程。
第一部分:前端发布页面 (用户看到和操作的界面)
这是用户填写标题、内容等信息并点击“发布”按钮的页面。

文件位置
织梦默认的前台发布页面位于:
/templets/default/article_add.htm
这是系统默认的模板文件,如果你使用了其他模板,或者创建了自定义的发布页面,路径会相应改变。
核心代码分析 (article_add.htm)
这个文件主要由 HTML 和织梦的模板标签({dede:})构成。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">发布文章 - {dede:global.cfg_webname/}</title>
<!-- 引入编辑器,如百度UEditor -->
{dede:include filename="head.htm"/}
</head>
<body>
<!-- ... 网站头部 ... -->
<div class="main">
<h3>发布文章</h3>
<form name='form1' action='article_add.php' enctype='multipart/form-data' method='post'>
<!-- 关键:织梦的CSRF令牌,用于安全验证 -->
<input type='hidden' name='dede_fieldshash' value='{dede:hash md5/}' />
<!-- 1. 标题输入框 -->
<div class="form-group">
<label for="title">标题:</label>
<input type="text" name="title" id="title" class="form-control" required />
</div>
<!-- 2. 所属栏目选择 -->
<div class="form-group">
<label>所属栏目:</label>
{dede:channel type='self' typeid='0'}
<option value='{dede:field.id/}'>{dede:field.typename/}</option>
{/dede:channel}
</div>
<!-- 3. 文章内容编辑器 (这里是百度UEditor) -->
<div class="form-group">
<label>内容:</label>
<script type="text/plain" id="editor" name="body" style="width:100%;height:400px;"></script>
</div>
<!-- 4. 其他字段,如作者、来源、缩略图等 -->
<div class="form-group">
<label>作者:</label>
<input type="text" name="writer" value="{dede:global.cfg_webname/}" />
</div>
<div class="form-group">
<label>来源:</label>
<input type="text" name="source" value="原创" />
</div>
<div class="form-group">
<label>缩略图:</label>
<input type="file" name="litpic" />
</div>
<!-- 5. 提交按钮 -->
<button type="submit" class="btn btn-primary">发布文章</button>
</form>
</div>
<!-- 初始化编辑器 -->
<script>
var ue = UE.getEditor('editor');
</script>
<!-- ... 网站底部 ... -->
</body>
</html>
代码解释:
<form>标签:action='article_add.php':指定了表单数据提交的目标处理文件,这是整个流程的入口。enctype='multipart/form-data':允许表单上传文件(如缩略图)。
{dede:hash md5/}:这是一个织梦模板标签,用于生成一个随机的哈希值,作为dede_fieldshash的值,这是织梦防止CSRF(跨站请求伪造)攻击的重要机制。name="title",name="body",name="litpic":这些name属性的值至关重要,它们与后端PHP代码中的变量名一一对应。{dede:channel type='self'...}:这是一个织梦标签,用于动态加载当前网站的所有“普通文章”类别的栏目,让用户选择文章所属的分类。
第二部分:后端处理逻辑 (服务器核心代码)
当用户在前台点击“发布”后,表单数据会被发送到 article_add.php 文件,这个文件是处理发帖请求的核心。
文件位置
/plus/article_add.php
核心代码分析 (article_add.php)
这个文件是纯PHP代码,负责接收、验证、处理数据,并最终写入数据库。
<?php
require_once(dirname(__FILE__)."/../include/common.inc.php");
require_once(DEDEINC."/arc.archives.class.php");
// 1. 权限检查
if($cfg_ml->M_Rank > 0 || $cfg_ml->M_Rank == -1)
{
// 普通会员或游客可以发布
}
else
{
ShowMsg("您尚未登录,或者没有发布权限!", "-1");
exit();
}
// 2. CSRF 安全验证
if(empty($dede_fieldshash) || $dede_fieldshash != md5($cfg_cookie_encode.$svar))
{
ShowMsg("安全验证失败,请刷新页面后重试!", "-1");
exit();
}
// 3. 接收并处理表单数据
$arc = new Archives(); // 实例化一个文章处理类
// 从POST请求中获取数据
$title = isset($title) ? HtmlReplace($title, 1) : '';
$typeid = isset($typeid) ? intval($typeid) : 0;
$body = isset($body) ? stripslashes($body) : ''; // 注意:stripslashes用于去除转义字符
// ... 其他字段如 writer, source, litpic 的接收和验证 ...
// 4. 调用核心发布函数
$arc->MakeHtml(); // 这个方法内部会处理大部分逻辑,包括保存到数据库
// 5. 处理上传的缩略图
if(isset($_FILES['litpic']))
{
$arc->UploadImg('litpic'); // 调用上传图片的方法
}
// 6. 保存到数据库
$arc->SaveToDb(); // 将文章数据最终保存到 `dede_archives` 等表中
// 7. 根据设置生成HTML静态页面
if($cfg_ishtml == 'Y')
{
$arc->MakeHtml(); // 生成文章详情页
}
// 8. 操作成功提示
$arc->Close(); // 关闭数据库连接
ShowMsg("发布成功!", "/"); // 跳转到首页
exit();
?>
代码解释:
- 权限检查:
$cfg_ml->M_Rank是会员等级变量,这里会检查用户是否有权限发布内容。 - CSRF验证:将前端提交的
dede_fieldshash值与服务器端根据特定规则生成的值进行比较,如果不一致,则认为是非法请求。 Archives类:这是织梦处理文章的核心类,定义在/include/arc.archives.class.php,它封装了文章发布的所有复杂逻辑,包括数据处理、数据库操作、HTML生成等。- 数据接收:从
$_POST和$_FILES超全局变量中获取前端提交的数据。HtmlReplace和stripslashes是织梦内置的数据过滤和清理函数,用于防止XSS攻击。 - 核心方法调用:
UploadImg('litpic'):处理缩略图上传,并将路径保存。SaveToDb():这是最关键的一步,它将文章信息写入数据库,它会向dede_archives(主表,存标题、ID等)、dede_arctype(栏目关联)、dede_addonarticle(附加表,存内容body)等多个表中插入数据。
- 静态化处理:如果开启了全站静态化,
MakeHtml()方法会根据文章ID和栏目信息,生成对应的HTML文件(如/a/2025/12345.html),并放置到/html/目录下。 - 成功提示:使用
ShowMsg函数弹出一个提示框,并跳转到指定页面。
第三部分:核心类文件 (Archives.class.php)
真正的“魔法”发生在这个文件里,它负责将所有数据组织好并写入数据库。
文件位置
/include/arc.archives.class.php
核心方法 SaveToDb() (伪代码逻辑)
// 在 arc.archives.class.php 中
class Archives
{
// ... 属性定义 ...
/**
* 保存文章数据到数据库
*/
function SaveToDb()
{
// 1. 准备主表 (dede_archives) 的数据
$inQuery = "INSERT INTO `#@__archives`
(typeid, typeid2, arcrank, title, writer, source, litpic, pubdate, senddate, mid)
VALUES
({$this->typeid}, {$this->typeid2}, {$this->arcrank}, '{$this->title}', '{$this->writer}', '{$this->source}', '{$this->litpic}', '{$this->pubdate}', '{$this->senddate}, {$this->mid})";
// 执行插入主表,并获取自增的ID
$this->id = $dsql->ExecuteNoneQuery2($inQuery);
// 2. 准备附加表 (dede_addonarticle) 的数据
$addQuery = "INSERT INTO `#@__addonarticle`
(aid, body, userip)
VALUES
({$this->id}, '{$this->body}', '{$_SERVER['REMOTE_ADDR']}')";
// 执行插入附加表
$dsql->ExecuteNoneQuery($addQuery);
// 3. 更新栏目文章数
// ... 更新 dede_arctype 表中对应栏目的 `totalnum` 字段 ...
return true;
}
// ... 其他方法如 UploadImg(), MakeHtml() ...
}
逻辑总结:
- 织梦将文章数据拆分到两个表中:主表 (
archives) 存储公共信息,附加表 (addonarticle) 存储特定于文章模型的内容(如body)。 - 先向主表插入数据,获取文章ID (
$this->id)。 - 再用这个ID作为关联,向附加表插入文章内容。
- 最后更新相关栏目的文章计数。
总结与自定义发帖功能
如果你想自定义一个发帖功能,比如增加一个“标签”字段,可以按以下步骤操作:
-
修改前端模板 (
article_add.htm):- 在表单中增加一个输入框,
<div class="form-group"> <label>标签:</label> <input type="text" name="tags" id="tags" class="form-control" /> </div>
- 在表单中增加一个输入框,
-
修改后端处理 (
article_add.php):- 在接收数据的地方增加一行:
$tags = isset($tags) ? HtmlReplace($tags, 1) : '';
- 在
SaveToDb()方法执行成功后,增加处理标签的逻辑:// 在 $arc->SaveToDb(); 之后 if (!empty($tags)) { $tagArr = explode(',', $tags); foreach ($tagArr as $tag) { $tag = trim($tag); if (!empty($tag)) { // 调用织梦内置的添加标签函数 InsertTags($tag, $arc->id); } } }
- 在接收数据的地方增加一行:
通过以上分解,你应该能清晰地理解织梦CMS发帖功能的完整工作流程和核心代码结构,这个流程是理解很多CMS系统后台逻辑的典型范例。
