本文按逐文件源码形式提供一个可本地运行的黄冈资讯站起始工程,包含栏目筛选、关键词检索、文章列表、正文查看和后台发布入口。将代码按目录保存并初始化 SQLite 数据库,即可在本机测试,再根据乡镇动态、教育文化、生活服务等实际栏目替换示例记录。
冻结声明说明:现有字段记录了年份“2026”和版本标签“官方版”,但版本号与适用平台均未提供,也没有授权或价格条款。因此,本文不把某个未核实的官方压缩包、平台兼容性或“永久免费”许可说成已确认事实。这里直接给出可复制保存的源码,不附压缩文件或下载链接;使用前请以实际项目的授权文本为准。
工程规格与功能
| 字段 | 取值 | 用途 |
|---|---|---|
| PHP 运行环境 | PHP 8.1 或更高版本 | 执行列表、正文和后台发布脚本 |
| 数据库驱动 | PDO SQLite | 读取与保存文章记录 |
| 数据库文件 | storage/site.sqlite | 保存栏目、标题、摘要、正文和发布状态 |
| 字符编码 | UTF-8 | 处理中文标题、栏目名与正文 |
| 检索参数 | q、category、id | 按标题搜索、筛选栏目、打开指定文章 |
- 资讯列表:只展示已发布记录,按发布时间倒序排列,最多读取三十条。
- 关键词检索:使用预处理语句匹配标题,避免把用户输入直接拼入 SQL。
- 栏目筛选:支持政务动态、乡镇资讯、教育文化和生活服务等自定义分类。
- 正文查看:根据文章编号读取单条记录,输出时转义文字,换行转换为段落间隔。
- 后台发布:使用服务器环境变量设置管理员凭据;后台提供带 CSRF 校验的新增发布入口。
项目目录
huanggang-site/
├── app/
│ ├── db.php
│ └── helpers.php
├── public/
│ ├── index.php
│ ├── article.php
│ └── admin.php
├── storage/
│ └── site.sqlite
└── install.sql
public 放置可由 Web 服务访问的 PHP 脚本,app 保存数据库连接和转义函数,storage 保存 SQLite 文件。请将站点根目录指向 public,不要把数据库目录暴露给访客。栏目名称、站点名称和页脚文字可在各脚本输出的 HTML 模板中修改。
数据库初始化源码
将以下语句保存为 install.sql。示例记录用于本地测试,不代表黄冈任何机构发布的真实通知。
CREATE TABLE IF NOT EXISTS articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
category TEXT NOT NULL DEFAULT '本地资讯',
summary TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL,
published_at TEXT NOT NULL,
status INTEGER NOT NULL DEFAULT 1 CHECK (status IN (0, 1))
);
INSERT INTO articles (title, category, summary, body, published_at, status)
VALUES (
'示例:乡镇便民服务安排',
'生活服务',
'用于检查列表摘要和正文跳转。',
'这是本地测试用的虚构记录,请替换为经核实的公告。',
'2026-01-01 09:00:00',
1
);
在工程根目录创建 storage 后,可用 SQLite 命令行执行初始化:sqlite3 storage/site.sqlite < install.sql。若没有命令行工具,也可使用本机数据库管理工具运行同一份 SQL。正式发布前,应核对通知来源与发布时间,并为数据库文件设置仅服务进程可读写的权限。
数据库连接与文字转义
将下方代码分别保存为 app/db.php 和 app/helpers.php。连接脚本会在缺少存储目录时尝试创建目录;部署账户仍须具有相应写入权限。
<?php
$path = dirname(__DIR__) . '/storage/site.sqlite';
$dir = dirname($path);
if (!is_dir($dir) && !mkdir($dir, 0750, true) && !is_dir($dir)) {
throw new RuntimeException('无法创建数据库目录');
}
$pdo = new PDO('sqlite:' . $path, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$pdo->exec('PRAGMA foreign_keys = ON');
?>
<?php
function e($value): string
{
return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
?>
资讯列表与搜索入口
把以下源码保存为 public/index.php。访客可用 ?q=关键词 搜标题,也可用 ?category=生活服务 查看指定栏目;两个条件可以同时使用。
<?php
require dirname(__DIR__) . '/app/db.php';
require dirname(__DIR__) . '/app/helpers.php';
$q = isset($_GET['q']) && is_string($_GET['q'])
? trim($_GET['q']) : '';
$category = isset($_GET['category']) && is_string($_GET['category'])
? trim($_GET['category']) : '';
$sql = 'SELECT id, title, category, summary, published_at
FROM articles WHERE status = 1';
$args = [];
if ($q !== '') {
$sql .= ' AND title LIKE :q';
$args[':q'] = '%' . $q . '%';
}
if ($category !== '') {
$sql .= ' AND category = :category';
$args[':category'] = $category;
}
$sql .= ' ORDER BY published_at DESC, id DESC LIMIT 30';
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
$rows = $stmt->fetchAll();
?>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>黄冈本地资讯</title>
</head>
<body>
<h1>黄冈本地资讯</h1>
<p>按标题关键词或栏目名查找已发布文章。</p>
<form method="get">
<label>标题关键词
<input name="q" value="<?= e($q) ?>">
</label>
<label>栏目
<input name="category" value="<?= e($category) ?>">
</label>
<button type="submit">查找</button>
</form>
<ul>
<?php foreach ($rows as $row): ?>
<li>
<a href="article.php?id=<?= (int)$row['id'] ?>">
<?= e($row['title']) ?>
</a>
<span><?= e($row['category']) ?></span>
<time><?= e($row['published_at']) ?></time>
<p><?= e($row['summary']) ?></p>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>
文章正文入口
保存为 public/article.php。编号先转换为整数,再通过预处理语句查询;访客无法打开未发布记录。正文按纯文字处理,不执行文章字段中可能出现的 HTML 标签。
<?php
require dirname(__DIR__) . '/app/db.php';
require dirname(__DIR__) . '/app/helpers.php';
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$id || $id < 1) {
http_response_code(404);
exit('未找到这篇文章');
}
$stmt = $pdo->prepare(
'SELECT title, category, body, published_at
FROM articles WHERE id = :id AND status = 1'
);
$stmt->execute([':id' => $id]);
$row = $stmt->fetch();
if (!$row) {
http_response_code(404);
exit('未找到这篇文章');
}
?>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title><?= e($row['title']) ?></title>
</head>
<body>
<article>
<h1><?= e($row['title']) ?></h1>
<p>栏目:<?= e($row['category']) ?></p>
<time><?= e($row['published_at']) ?></time>
<p><?= nl2br(e($row['body']), false) ?></p>
</article>
<p><a href="index.php">返回资讯列表</a></p>
</body>
</html>
后台发布入口
将以下源码保存为 public/admin.php。管理员账号与密码从服务器环境变量 HG_ADMIN_USER、HG_ADMIN_PASSWORD 读取,不要把真实密码写进源码。后台只提供新增发布,不包含编辑、删除或角色管理;对公网开放前,应使用 HTTPS,并在 Web 服务侧增加访问限制。
<?php
require dirname(__DIR__) . '/app/db.php';
require dirname(__DIR__) . '/app/helpers.php';
$user = getenv('HG_ADMIN_USER') ?: '';
$pass = getenv('HG_ADMIN_PASSWORD') ?: '';
if ($user === '' || $pass === '') {
http_response_code(503);
exit('尚未设置后台凭据');
}
$givenUser = $_SERVER['PHP_AUTH_USER'] ?? '';
$givenPass = $_SERVER['PHP_AUTH_PW'] ?? '';
if (!hash_equals($user, $givenUser) || !hash_equals($pass, $givenPass)) {
header('WWW-Authenticate: Basic realm="资讯维护"');
http_response_code(401);
exit('需要管理员认证');
}
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$token = $_POST['token'] ?? '';
if (!is_string($token) || !hash_equals($_SESSION['token'], $token)) {
http_response_code(403);
exit('请求校验失败');
}
$title = trim((string)($_POST['title'] ?? ''));
$category = trim((string)($_POST['category'] ?? ''));
$summary = trim((string)($_POST['summary'] ?? ''));
$body = trim((string)($_POST['body'] ?? ''));
if ($title === '' || $category === '' || $body === '') {
http_response_code(422);
exit('标题、栏目和正文不能为空');
}
$stmt = $pdo->prepare(
'INSERT INTO articles
(title, category, summary, body, published_at, status)
VALUES (:title, :category, :summary, :body, :published_at, 1)'
);
$stmt->execute([
':title' => $title,
':category' => $category,
':summary' => $summary,
':body' => $body,
':published_at' => date('Y-m-d H:i:s'),
]);
header('Location: admin.php');
exit;
}
?>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>资讯发布维护</title>
</head>
<body>
<h1>发布本地资讯</h1>
<form method="post">
<input type="hidden" name="token"
value="<?= e($_SESSION['token']) ?>">
<label>标题
<input name="title" required maxlength="200">
</label>
<label>栏目
<input name="category" required maxlength="80">
</label>
<label>摘要
<textarea name="summary" maxlength="500"></textarea>
</label>
<label>正文
<textarea name="body" required rows="12"></textarea>
</label>
<button type="submit">发布文章</button>
</form>
</body>
</html>
本地运行与后续维护
确认 PHP 已启用 PDO SQLite 后,在工程根目录初始化数据库,再用本机 PHP 开发服务器启动:php -S 127.0.0.1:8000 -t public。浏览器访问本机的 index.php 检查列表、关键词检索、栏目筛选和正文跳转;配置管理员环境变量后,再访问 admin.php 测试发布流程。
上线前应替换虚构测试记录,核对每条通知的来源、栏目和发布时间,设置独立管理员凭据,并定期备份 storage/site.sqlite。若要增加分页、文章编辑、撤稿、图片管理或多管理员权限,应分别补充输入校验、操作审计和数据库备份策略;不要仅靠隐藏后台入口保护文章数据。
