一个「能真正跑起来」的社区,不是脚手架 demo —— 从信息流到一整套积分经济都接通了。
- 🧩 零依赖、开箱即跑:后端是原生 PHP(PDO),没有框架、没有
composer install、没有构建步骤。 默认 SQLite,docker compose up或一条php命令就能起。要上生产再切 MySQL。 - 📰 完整的微博式社区:信息流(最新/热门/多类型筛选/游标分页)、发帖框(图文/视频/音频/投票/ 红包/隐藏内容/#话题#/@提及,都带联想)、两级楼中楼评论、长文编辑器、个人主页、私信、通知中心、 关注/收藏/转发/举报/屏蔽、软删除 + 回收站、PWA、明暗主题、放歌不断的 SPA 站内导航。
- 🪙 一整套积分经济:积分/经验规则引擎(发帖、被赞、签到都涨,全写进明细)、等级、 每日签到、称号抽奖(按档加权的老虎机)、双色球(抓真实开奖号)、红包(拼手气/平均,零和)、 VIP 套餐、认证中心(站长认证会真去抓域名校验文件)、自动勋章、黄V/蓝V。
- 🛒 积分商城:用户开店、用积分买卖,平台按比例抽成,剩下的到卖家账上。有等级门槛(站长后台设)、 库存、自动/手动发货、审核、待发货订单可原路退款。账目严格守恒(有 41 项断言测试守着)。
- 🎮 小程序平台:可以容纳用户提交的网页小游戏,每个都跑在不给同源的沙箱 iframe 里 —— 读不到本站 Cookie、调本站接口不带凭据、够不着外层页面。充值/账号面板由平台代画(沙箱里的 第三方代码画不了假的收款框)。体量太大装不进沙箱的(比如三国杀那种带 IndexedDB 硬依赖的) 可以走「站外源」用独立端口托管。本仓库不预装任何游戏,只带平台本身,你自己上传即可(见下文)。
- 🛡️ 后台四级权限:游客/版主/管理员/站长逐级放权,动作逐项白名单,站长专属项(提权、模拟登录、 改设置、动账)一条都不外放;封禁即时生效、操作留痕。
- 🔒 安全:服务端会话 + CSRF、登录失败限流、bcrypt 存密码、越权分级、 富文本/头像/上传的 XSS 与 SSRF 防护、SVG 上传已禁、报错不泄漏 SQL。经过一轮渗透测试(见文末)。
| 积分商城(用户开店) | 小程序平台(沙箱) |
|---|---|
![]() |
![]() |
| 用积分买卖,平台抽成、等级门槛、自动/手动发货、可原路退款 | 网页小游戏跑在不给同源的沙箱里。截图里那两个是作者自己上传的,仓库不带任何游戏 |
| 积分与等级 | 称号抽奖 |
|---|---|
![]() |
![]() |
| 每一笔涨跌都写进明细,规则表直接摊给用户看 | 26 个称号分五档加权,抽到重复退一半积分;「至尊」档抽不到,只能靠攒 |
| 管理后台 | 暗色主题 |
|---|---|
![]() |
![]() |
| 20+ 个管理页,四级身份逐项放权,站长专属项一条都不外放 | 全站明暗双主题,跟随系统或手动切 |
装了 Docker 就一条命令:
docker compose up # 首次会构建镜像 + 自动建库,约 1–2 分钟然后浏览器打开 http://localhost:8080 —— 首次已写入演示数据,用
admin / ChangeMe123! 登录(登录后请尽快改密码)。
- 默认 SQLite,不需要额外的数据库容器;数据落在具名卷里,容器重建也不丢。
- 想用 MySQL/MariaDB:
docker compose --profile mysql up,并按docker-compose.yml里的注释给app补上DB_*环境变量。 - 内置 PHP 服务器够自托管和演示用;对外扛量请按下方「部署示例」换成 Nginx + PHP-FPM。
不想用 Docker 就看下面的「快速开始」——同样零配置。
需要 PHP ≥ 8.1,并启用 pdo_sqlite、gd、mbstring、fileinfo 扩展。
用到小程序(用户提交网页小游戏)还需要 zip 扩展,并把上传上限调大:
; 一个 Cocos / Unity 的网页构建产物动辄二三十兆、上千个文件
upload_max_filesize = 64M
post_max_size = 72M
max_execution_time = 120⚠ post_max_size 一定要比 upload_max_filesize 大一截:请求体超过它时
PHP 会把 $_POST 和 $_FILES 一起清空且不报错,表单看起来像是什么都没填。
cd aism
php bin/console.php serve 8080 # 或:php -S 127.0.0.1:8080 -t public public/index.php打开 http://127.0.0.1:8080 即可。首次访问会自动建表并写入演示数据
(AUTO_MIGRATE=1)。
演示管理员账号:admin / ChangeMe123!(首次登录后请尽快改密码)。
-
建库建号:
CREATE DATABASE aism CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'aism'@'127.0.0.1' IDENTIFIED BY '你的密码'; GRANT ALL PRIVILEGES ON aism.* TO 'aism'@'127.0.0.1';
-
用环境变量指定连接(PHP 不自动读
.env,见.env.example):export DB_DRIVER=mysql DB_HOST=127.0.0.1 DB_DATABASE=aism \ DB_USERNAME=aism DB_PASSWORD='你的密码' APP_DEBUG=0 php bin/console.php migrate # 建表 + 演示数据
-
用 Nginx + PHP-FPM 部署时,把
public/作为站点根,所有非静态请求交给public/index.php(下方有示例)。
aism/
├─ public/ # 站点根(唯一对外暴露的目录)
│ ├─ index.php # 前端控制器 + 静态直通
│ ├─ static/{css,js,img} # 复用的原版前端资源 + app-extra.css(补样式)
│ └─ uploads/ # 用户上传(按 年月 分桶)
├─ app/
│ ├─ bootstrap.php # 装载配置/会话/自动加载/自动迁移
│ ├─ Router.php View.php # 极简路由 + 模板渲染
│ ├─ Auth.php Database.php helpers.php
│ ├─ routes.php # 全部路由表
│ ├─ Models/ # 领域层(Posts/Comments/Users/Uploads/...)
│ ├─ Controllers/ # 页面控制器 + JSON API 控制器
│ └─ Views/ # 布局 + 页面 + 片段(feed/评论/发帖框等)
├─ config/config.php # 全部配置(可被环境变量覆盖)
├─ database/ # schema.sqlite.sql / schema.mysql.sql
├─ storage/ # SQLite 数据 + 缓存 + 用户提交的小程序(均不进仓库)
├─ tests/ # 隔离库跑的账目/权限测试(如 shop_test.php)
├─ bin/console.php # 迁移 / 播种 / 起服务 / 各种维护命令
├─ Dockerfile # 一键部署镜像(php:8.3-cli + 所需扩展)
└─ docker-compose.yml # docker compose up 即起(默认 SQLite)
-
信息流:最新 / 热门、原创/图片/视频/音乐/文章筛选、高级搜索、游标分页;版块 / 话题 / 用户 / 搜索 / 收藏 多种范围。
-
发帖框:灰底圆角输入区 + 右下角提示与字数;工具条 表情 / 图片 / 视频 / 音频 / 话题 / 好友,其余(附件、投票、红包、隐藏内容)收进「更多」;版块与可见范围是自绘下拉(原生
<select>的选项列表由系统绘制,暗色模式下改不了配色)。一份模板三种形态:内联、整页is-full(只留图标 42×42)、编辑弹层is-edit(去卡片外壳、收掉 @)。 -
发帖:文字、图片、视频、音频、附件、外链、#话题#、@提及(都带联想补全)、投票、红包、隐藏内容;桌面端首页内联发帖框,移动端整页发帖(
/compose在宽屏自动跳/#composer)。 -
编辑已发内容:帖子「···」→ 编辑 打开弹层(
GET /api/posts/{id}/edit),原文、图片、附件、音视频全部回填;普通用户 30 分钟内最多改 5 次,会员和管理员不限。 -
长文:所见即所得编辑器(
/article/new、/article/{id}/edit),Markdown 存储 + 白名单渲染,自动保存、字数统计、封面、导语、发布设置、转回草稿、预览、删除;发布后镜像成信息流里的文章卡片。 -
互动:点赞、收藏、转发(引用)、关注(含互关)、作者置顶、管理员首页置顶、软删除 + 回收站恢复、举报、屏蔽、用户悬浮名片。
-
评论:两级楼中楼、热/新排序、翻页、图片评论、回复、作者置顶、软删、四档评论权限。
-
个人主页
/u/{uid}:封面(上传更换 / 恢复默认)+ 访问量、110px 悬挂头像、内容/关注/粉丝/转评赞四项计数、仅自己可见的昨日发博 / 昨日阅读 / 昨日互动 / 累计阅读、简介与加入时间、六个分类页(全部 / 相册 / 视频 / 文章 / 赞过 / 收藏,后两个仅本人)、主页内搜索(关键字 + 类型 + 日期)、等级 / 积分 / 勋章卡片;粉丝与关注列表在/u/{uid}/followers、/u/{uid}/following。 -
个人中心
/me/*:积分与等级(等级进度 + 「怎么获得积分」规则表 + 积分明细分页)、我的勋章(点选佩戴,最多 3 枚,去抖后自动存)、我的收藏、VIP会员、我的收益、申请认证,外加左栏底部通往/settings/*的出口;/rank是积分排行榜。 -
积分 / 经验规则引擎(
Models/Points.php是唯一入口,全部写进point_logs明细):规则 积分 上限 注册账号 +20 不限次数 每日登录 +5 每天最多 1 次 发布内容 +5 每天最多 10 次 发表评论 +2 每天最多 10 次 内容被赞 +1 每天最多 50 次,同一对象只计一次 内容被转发 +2 每天最多 30 次,同一对象只计一次 被关注 +2 每天最多 30 次,同一对象只计一次 内容被删(后台删) -5 不限次数 每日签到 4 + 连续天数(第 7 天起 11) 每天 1 次 「同一对象只计一次」靠
point_logs.target去重(取消赞再点不刷分,换个人赞同一条照算);扣分不会把余额扣成负数,也不扣经验。 -
等级与经验:经验只增不减(花掉积分不会降级),等级由经验现算 ——
LEVEL_STEPS = [0, 50, 200, 500, 1200, 3000]。 -
收益:付费内容按站长设的
author_share(默认 70%)分成,积分解锁全额进作者余额;「我的收益」的收支明细是从订单 / 解锁 / 红包记录现算的,没有另一份流水表可以对不上。
- 注册 / 登录 / 退出、服务端会话 + CSRF(
X-CSRF-Token/_token)。 - 两步验证(TOTP):符合 RFC 6238(已用官方测试向量校验),兼容 Google Authenticator;含 8 个一次性恢复码、关闭与重新生成。
- 邮箱绑定:验证码 + 60 秒限流;未配置发信时验证码回显并写入
storage/mail.log。 - 邀请码:每人 5 个未使用额度、注册消耗、邀请人奖励;可在后台切换为「仅邀请注册」。
- 封禁即时生效(下一次请求就退出登录)、登录日志、账号注销(软删 + 释放身份)。
- 隐藏内容四种模式(积分 / 现金 / 评论可见 / 会员可见)、会员套餐下单、收银台 3 秒轮询、
sync=1补单。 - 红包(平均 / 拼手气):发的时候就从发的人余额里扣掉,余额不够直接拦在发帖之前;发的人自己也能抢(钱已经扣过了,抢到的是自己刚付出去的那份,全程零和);同一个人只能抢一次;到期没抢完的部分退回发的人(读到即结算,幂等)。
- 认证中心:个人 / 机构 / 站长三类;站长认证会真的去抓取
你的域名/aism-verify.txt校验归属,通过即时生效;工本费用积分支付。
- 称号抽奖:26 个称号分六档(普通/稀有/史诗/传说/限定/至尊),按档加权、同档等概率平分,所以往一档里加称号不会抬高这一档的爆率;十连一次结算、重复退还部分积分、老虎机式转盘(全程只动
transform,等接口的时间藏在动画里)。 - 至尊称号「富可敌国」:抽不到(权重 0),只能攒 —— 持有一百万积分或集齐奖池里的全部称号,满足任意一条自动到手并自动佩戴。
- 自动勋章:25 枚勋章 / 14 条规则,全部从已有数据现算(不开计数器,免得跟删帖、封号、迁移对不上);12 个触发点 + 打开勋章墙时全量补发一次;四档稀有度对应四档特效。
- 大 V 认证:黄 V / 蓝 V,认证说明可在后台逐个填写;前台每颗 V 可点开一张认证卡(只回公开字段,不回申请材料里的真名和证件号)。
- 双色球:抓真实开奖号(多数据源,实测只有 500.com 还稳定)、自选/机选、六档奖金、按期结算;概率与期望回报在页面上明写。
- 全网热榜:聚合 8 个平台(微博/百度/知乎/B站/抖音/头条/GitHub/IT之家),每个源都配了备用接口,一个挂了不会把整块榜单变白;带 ↑n/↓n/新 的排名变化。
- 用户开店:谁都能发布商品,买家用积分付款,平台按站长设的比例抽成(默认 5%),剩下的到卖家账上。
- 发布门槛:要到某个等级才能发(默认 Lv.3,站长在
/admin/shop里调);等级靠经验攒, 换小号刷不出来。每人同时在售件数有上限。 - 库存与发货:库存可限量 / 不限量(
-1);发货分「自动」(付款即给卡密/链接)和「联系卖家」两种。 - 订单:卖家可标记发货、买卖双方在「待发货」阶段都能取消退款;退款时买家永远先拿回全款, 卖家余额不够就由站方垫付并记账 —— 买家不被卡住是这里唯一不妥协的规则。
- 账目守恒:一笔成交在明细里买卖双方各留一行;
tests/shop_test.php有 41 项断言守着 「钱不会凭空多也不会凭空少」,包括并发下不超卖、余额不足回滚库存、第三方看不到发货内容。
- 可容纳用户提交的网页小游戏 / 小工具,后台审核后上架;一格一个,点开就玩,不用下载安装。
- 沙箱隔离是安全根基:每个小程序跑在
sandbox="allow-scripts"、故意不给allow-same-origin的 iframe 里 —— 拿到的是「不透明源」,读不到本站 Cookie、调本站接口不带凭据、够不着外层页面 DOM。 - 充值/账号面板由平台代画:花积分和看账号的界面不交给沙箱里的第三方代码(它画个一模一样的框 问你要密码,你分不出真假)—— 跟微信小程序把支付交给原生弹窗是同一个道理。用积分 1:1 兑换游戏币。
- 两类承载:普通小游戏走沙箱;体量太大或对
IndexedDB/ServiceWorker有硬依赖的(如三国杀那种 上千文件、1GB 素材的),走「站外源」—— 由 nginx 在独立端口托管,独立端口即独立源, 隔离性比同源更强(详见app/Models/MiniApps.php里的说明)。 - 自带后端的小游戏:允许小程序带自己的 Node/socket.io 服务,站长在后台登记端口,nginx 按
/ms/<端口>/反代 —— 客户端只认location.host,服务器 IP 变了也不用改客户端包。 - ⚠ 本仓库不预装任何游戏(游戏文件体积大且多为第三方版权)。平台代码是自带的,
上架自己的小程序有两条路:① 后台/前台提交 zip 包(
/mini/new,会解压进storage/miniapps/{id}); ② 站外源——把游戏部署到独立端口,在MiniApps::EXTERNAL_PORTS登记。
- 私信(8 秒轮询)、通知中心(分类 + 未读 30 秒轮询,进入即已读、红点当场清)、签到积分、徽章墙与佩戴、音乐广场、热搜榜、话题联想、链接卡片(真实抓取 OG 标签,带 SSRF 防护)、PWA、明暗主题、SPA 站内导航(放歌不中断)。
| 身份 | users.role |
能做什么 |
|---|---|---|
| 普通用户 | 0 | 没有任何管理权限 |
| 版主 | 1 | 只管自己负责的版块:删帖、删评论、处理本版块举报、板块内禁言 |
| 管理员 | 2 | 权限由站长逐项勾选(16 项),勾到哪儿管到哪儿 |
| 站长 | 3 | 全部,外加设置别人的身份与权限 |
设计上有几处是刻意为之,改代码前值得先读一遍 app/Models/Perm.php 顶上的注释:
is_admin保留原意「≥2 级」,版主那一级它是 0。 全站二十来处旧判断读的是这一列,让版主也置 1 会让那些判断一起静悄悄放行。加一级身份不该让任何一处旧判断变松。- 权限判断在 switch 之前一次做完(
Perm::denyReason()),不散在 40 多个 case 里;Perm::ACTIONS是白名单,没登记的动作一律拒绝。 - 站点设置、模拟登录、设置别人的权限这三件事不做成可勾选项 —— 它们等于站长本人。
- 「对方级别不低于你就动不了」是严格大于,所以两个管理员不能互相封禁、也没人能对自己动手。
- 版主看到的列表是在 SQL 里限定的,不是把别的行藏起来 —— 列表能翻到 id 就等于能删(删是按 id 提交的),列表和动作必须用同一套边界。
- 版主只能软删(移入回收站),不能彻底删:给版主的工具里不该有任何一件事是站长撤不回来的。
自带一套独立样式(app.js 本身就把 SPA 导航排除在 /admin 之外),共 20 个页面,没勾到的页面在侧边栏里不出现、直接输网址也是 403:
| 页面 | 权限键 | 能做什么 |
|---|---|---|
| 控制台 | — | 用户/内容/评论/举报/认证/营收 KPI、近 14 天趋势;「最近操作」要 logs 权限才看得到 |
| 用户 | users |
搜索(含按 IP 搜、覆盖登录历史)、封禁/解封、发认证、发徽章、加减积分(带备注)、开会员、重置密码;身份与权限只有站长看得见 |
| 内容 / 评论 | content |
搜索、删除(软/彻底)、回收站恢复、首页置顶 |
| 举报 | reports |
待处理/已处理,一键删被举报内容、标记处理、驳回 |
| 我的版块 | 版主 / boards |
负责的版块一览 + 板块内禁言名单(禁言只在一个版块里生效) |
| 认证 | verifies |
查看申请资料与证明图、通过 / 驳回(含备注) |
| 订单 | orders |
按状态筛选、手动标记已支付(补单) |
| 版块 | boards |
增删版块、任免版主(被任命自动升为版主,管的最后一个版块被撤掉自动降回普通用户) |
| 话题 / 公告 / 会员套餐 | topics announce plans |
增删改 |
| 徽章 | badges |
图标、颜色、稀有度、自动发放条件与目标值 |
| 称号 | titles |
奖池增删改、稀有度(含「抽不到」那一档的说明) |
| 全网热榜 | hotfeeds |
手动抓取、按平台开关 |
| 双色球 | ssq |
拉取开奖、手工结算、经营概况 |
| 广告位 | ads |
6 个位置,文字 / 图片 / 自定义 HTML(HTML 会过滤脚本与 javascript:) |
| 媒体库 | media |
全站文件浏览与删除 |
| 站点设置 | 站长专属 | 站名、描述、关键词、开放注册、仅邀请注册、积分名称、页脚等 |
| 日志 | logs |
管理操作审计 + 登录日志 |
所有写操作都记入 admin_logs(含被拒绝的越权尝试),可在「日志」页追溯。
apt install ffmpeg # 装上即自动启用,无需改配置上传视频时同步做两件轻活:用 ffprobe 探测真实时长/分辨率(浏览器给的数字不可信,
iOS 的 .mov 常常根本没有时长),以及抽一帧作为封面(前端没给封面时)。
需要转码的才排队,不阻塞上传响应:
- 判定条件:非 mp4/webm 容器、视频编码不在
h264/vp8/vp9/av1、音频不在aac/mp3/opus/vorbis/flac、 高度超 1080p 或码率超 8 Mbps。 - 转码目标:H.264 + AAC、
yuv420p(Safari 要求)、-movflags +faststart(边下边播)、长边压到 1080p。 - 队列在
media_jobs表,上传后会自动 spawn 一个一次性 worker。转码期间原文件照常可播, 完成后uploads行和引用它的帖子一起指向新文件,原文件删除。
生产环境建议挂一个常驻 worker 而不是依赖 spawn:
php bin/console.php media:work # 常驻,空队列时每 5 秒轮询
php bin/console.php media:status # 看队列与最近任务没装 ffmpeg 也不会报错——视频原样保存,只是没有封面和转码。后台「站点设置」页会显示 ffmpeg 状态。
默认关闭,在后台「站点设置 → 网易云音乐导入」打开(会同步 window.APP.neteaseOn,
前端音频弹窗里那一页才出现)。
- 粘贴形态全都认:分享链接、
#/song?id=、/song/123、163cn.tv短链、<iframe>嵌入码、纯数字 ID。 - 只取 ID 和元数据(歌名/歌手/专辑/封面/时长),音频不转存到本站,播放走网易云的外链地址。
- 会主动探测能不能匿名播放;受版权或地区限制的曲目返回
playable:false, 前端提示「发出来访客可能听不到声音」——提醒但不拦截。 - 导入的曲目会进媒体库(
uploads.source='netease'),可重复使用而不再请求网易云。
⚠️ 请只导入你有权分享的内容。这个功能不绕过任何付费或 DRM 机制, 也正因如此,大量商业曲目在站外是放不出声的。
server {
listen 80;
server_name your.domain;
root /var/www/aism/public;
index index.php;
client_max_body_size 60m; # 与 UPLOAD_MAX_BYTES 对齐
# ⚠ 一定要开压缩:app.css + app.js 未压缩是 830 KB,gzip 之后 265 KB。
# 缺了这一条,跨国线路上每次首屏都要多等好几秒。
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/css application/javascript application/json image/svg+xml text/plain application/xml;
location / { try_files $uri $uri/ /index.php$is_args$args; }
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DB_DRIVER mysql;
fastcgi_param DB_DATABASE aism;
fastcgi_param DB_USERNAME aism;
fastcgi_param DB_PASSWORD "你的密码";
fastcgi_param APP_DEBUG 0;
}
# 静态资源与上传。
# /static 下的引用都带 ?v=<mtime>(见 helpers.php 的 asset_version),
# 所以可以放心 immutable —— 文件一改 URL 就变,用户不会拿到旧的。
location ~* ^/static/ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; }
location ~* ^/uploads/ { expires 30d; access_log off; }
}走 nginx 时静态文件不会进 PHP,上面这两段就是它的缓存策略。 直接
php bin/console.php serve跑的时候,同样的策略由app/static_serve.php自己实现(缓存头 + gzip + 304 + Range), 因为 PHP 内置服务器一个缓存头都不发。
- 生产务必设置
APP_DEBUG=0(否则异常堆栈会直接返回给访客)。 - 所有正文/评论/资料在服务端统一转义后再渲染,链接只放行 http(s) 与站内相对路径。
- CSRF:所有写操作校验
X-CSRF-Token或 body 里的_token;会话 Cookie 为HttpOnly+SameSite=Lax。 - 登录失败限流:同一来源 IP 15 分钟内失败满 15 次即临时拒绝(
AuthController)。按 IP 不按账号 —— 按账号会被人拿你的用户名故意锁你(拒绝服务);复用已有的login_logs表,不引依赖。 - 后台权限逐项白名单、分四级(
app/Models/Perm.php):版主 < 管理员 < 站长,站长专属项 (提权、模拟登录、改站点设置、动已成交的账)一条都不外放;can()用「严格大于」判上下级, 两个管理员无法互封,任何人无法对自己提权。 - 支付为演示实现(
sync=1直接置为已支付),接入真实支付平台前请替换app/Controllers/PayController.php的fulfill()/status()。 - 邮件发信、网易云导入等为占位,未接第三方。
- 头像地址是服务端校验的(
safe_avatar_value(),入库和出库各过一次)。它不是"多一层保险":app.js拼私信气泡时是'<img src="' + box.dataset.peerAvatar + '">',而dataset读出来是解码后的原串 —— PHP 那边h()转义过也挡不住,所以这个字段必须从根上不允许出现引号和尖括号。 - 不收 SVG 上传。SVG 是能带
<script>的 XML 文档,落在public/uploads下由同源发出去、直接访问就会执行,nosniff挡不住(响应类型本来就是 svg)。另外/uploads/*一律带Content-Security-Policy: default-src 'none'; sandbox(实测不影响<img>渲染)。 - 昵称会洗掉零宽字符、双向覆写和控制字符(
clean_display_name())。输出本来就是安全的(h()+json_encode_safe带JSON_HEX_TAG),洗的是"看不见的字符"——那是拿来冒充别人和绕过字数上限的。 - 登录页那行演示账号只在
APP_DEBUG=1时显示,生产按上面把它设成 0 就自动消失。 - 发布前做过一轮渗透测试(SQL 注入 / 越权提权 / CSRF / IDOR / 存储型 XSS / 路径穿越 / 负数溢出), 普通用户和版主的越权尝试全部被拒;期间修掉了「商城下单数量未校验」和「登录无限流」两处。
- 支付是演示实现:
sync=1直接置为已支付。接真实支付平台请替换app/Controllers/PayController.php的status()/fulfill()。 - 邮件默认不发信(
MAIL_ENABLED=0),验证码回显并写storage/mail.log;接 SMTP 请改app/Models/Mailer.php。 - 未接第三方 OAuth 登录,
/connect/unbind会明确返回「本站未接入第三方登录」。 - 网易云导入只存 ID + 元数据,音频走网易云自己的外链播放,本站不转存;受版权/地区限制的曲目匿名播不出声,接口会用
playable:false明确告知(前端会提示站长)。






