Files
FeedLite/config.example.php
T

177 lines
10 KiB
PHP
Raw Normal View History

<?php
/**
* FeedLite · 轻反馈 · 配置文件
* ------------------------------------------------------------------
* 部署后请务必修改 admin_password 与 api_token(及 ip_salt),
* 并按需填写下方的 smtp 段以开启"回复邮件通知"。
*/
return [
/* ---------------- 基本 ---------------- */
// SQLite 数据库文件路径。
// 放在站内 data/ 目录(已被 .htaccess 拒绝直接访问);也可改为站点目录之外的绝对路径。
'db_path' => __DIR__ . '/data/feedback.db',
'site_name' => '轻反馈',
'site_desc' => '欢迎在这里反馈使用问题、提出功能建议。任何人都可以提问与回复,无需注册;只需填写昵称与邮箱。',
// 展示用的官方邮箱(可留空)
'admin_email' => 'support@example.com',
// 站点根地址(用于邮件正文里的链接)。留空则按访问域名自动探测。
// 例如:'https://feedback.example.com'
'base_url' => '',
/* ---------------- 安全 ---------------- */
// 管理员口令:在"回复"表单里填入它,即以「官方」身份回复(高亮显示),并触发邮件通知。
// ★★ 请务必修改! ★★
'admin_password' => 'CHANGE_ME_admin',
// API 令牌:供自动化脚本 / AI 读取数据用。★ 请务必修改 ★
'api_token' => 'CHANGE_ME_api_token',
// 对访客 IP 做加盐哈希(数据库只保存哈希,不保存明文 IP)。★ 请修改为随机值 ★
'ip_salt' => 'CHANGE_ME_random_salt',
/* ---------------- 问题分类 ---------------- */
'categories' => [
'usage' => '使用问题',
'bug' => 'Bug 反馈',
'feature' => '功能建议',
'sync' => '同步问题',
'other' => '其他',
],
/* ---------------- 处理状态 ---------------- */
'statuses' => [
'open' => '待处理',
'doing' => '处理中',
'resolved' => '已解决',
'closed' => '已关闭',
],
/* ---------------- 邮件通知(SMTP) ---------------- */
'smtp' => [
'enabled' => false, // 填好下面参数后改为 true 才会真正发信
'host' => 'smtp.example.com', // 如 smtp.qiye.aliyun.com / smtp.exmail.qq.com
'port' => 465,
'secure' => 'ssl', // ssl(465)| tls(587 STARTTLS)| ''(25 不加密)
'user' => 'noreply@example.com',
'pass' => '', // 邮箱密码或"授权码"
'from' => 'noreply@example.com', // 发件地址(通常与 user 相同)
'from_name' => '轻反馈',
'timeout' => 15,
'verify_ssl' => true, // 若服务器缺少 CA 证书可临时设为 false
],
// 通知策略
'notify' => [
'enabled' => true, // 回复时是否尝试发送通知邮件
'on_every_reply' => true, // true=任何人回复都通知发帖人;false=仅"官方"回复才通知
'cooldown_seconds' => 300, // 同一帖同一收件人的通知节流(秒)
],
/* ---------------- 审核(先审后显) ----------------
* enabled = true:新提交的问题默认**不公开**,由管理员在 admin.php 审核;
* · 通过 → 公开显示(visible=1)
* · 关闭 → 判定"不是应用的问题",保持不公开,并把管理员填写的说明邮件发给提问人
* 审核后台入口:/feedback/admin.php(口令= admin_password)
*/
'moderation' => [
'enabled' => true,
'close_mail_subject' => '关于你反馈的问题《%s》', // %s 会替换成问题标题
],
/* ---------------- 附件上传(阿里云 OSS · 服务器代理) ----------------
* ★ 架构:私有桶 + 内网 Endpoint,读写全部经服务器代理
* 桶设为【私有】、且只用【内网 Endpoint】(*-internal.aliyuncs.com,仅同地域 ECS 可达),
* 浏览器既不直传、也不直连。数据流:
* 上传:浏览器 → upload.php → 服务器 PUT 到内网 OSS
* 读取:浏览器 → media.php → 服务器 GET 内网 OSS 并流式转发(支持 Range)
* 好处:桶可彻底私有、公网完全看不到 Endpoint、AccessKey 永不出服务器。
* 代价:附件流量经过服务器(占带宽),需保证服务器磁盘临时空间够放单个上传文件。
*
* ★ 凭证方式:ECS 实例 RAM 角色(推荐,服务器上不保存长期 AccessKey)或静态 AccessKey。
* 实例角色下,程序从内网元数据服务(http://100.100.100.200,链路本地、不出公网)
* 读取一份「有时效、会自动轮换」的临时凭证来签名。AccessKey 永不落盘、永不进本文件。
*
* ★ 开通步骤(详见 README.md):
* ① 创建【与 ECS 同地域】的 Bucket,读写权限设为「私有」
* ⚠️ 内网 Endpoint 跨地域不通!ECS 在哪个地域,桶就建在哪个地域。
* ② RAM 建权限策略:只授予该 Bucket(某前缀下)的 oss:PutObject / GetObject / DeleteObject
* ③ RAM 建角色(如 FeedLiteOssRole)并赋予上一步的策略
* ④ ECS 控制台把该角色【授予本实例】
* ⑤ 把 endpoint / bucket / instance_role 填到下面,use_internal_endpoint 保持 true,enabled = true
* ⑥ 后台「站点设置 → 存储体检」确认桶连通性为 ✅
* (代理架构下【不需要】配置 CORS,也【不需要】绑定自定义域名)
*
* ★ 前提:站点必须运行在【阿里云 ECS】上并且已绑定 RAM 角色;
* 未绑定则取不到凭证,上传接口会明确报错(其它功能不受影响)。
*/
'oss' => [
'enabled' => false, // 填好参数后改为 true 才启用上传
'endpoint' => 'oss-cn-qingdao.aliyuncs.com', // 不含 http://;填公网或内网均可,程序按下方开关自动转换
'bucket' => 'your-bucket-name',
// ★ ECS 实例 RAM 角色名 —— 必须与【ECS 实例实际绑定的角色名】逐字一致。
// 查法:curl http://100.100.100.200/latest/meta-data/ram/security-credentials/
// 注意:RAM 里"创建的角色名"和"授予实例后实例上生效的角色名"可能不同(如
// 建的是 MyOssRole,授予实例后生效名可能是系统预置策略对应的角色),以查询结果为准。
'instance_role' => '',
// ★ 是否用内网 Endpoint(默认开)。开启后程序自动把 endpoint 改写成 *-internal 形式,
// 走阿里云内网访问 OSS:免公网流量费、延迟更低,且公网完全无法直连该地址。
// ⚠️ 仅当【桶与本机 ECS 同地域】时可用;跨地域时内网不可达,必须关掉本开关
// (回落公网 Endpoint)或改用同地域的桶。后台「存储体检」会探测并提示。
'use_internal_endpoint' => true,
// ---- 以下一般不用改 ----
'metadata_url' => '', // 留空=http://100.100.100.200(ECS 内网元数据服务)
'metadata_v2' => false, // true=加固模式(先取一次性 token 再读元数据,防 SSRF 探测)
'metadata_ttl' => 600, // 加固模式 token 有效期(秒,最长 21600)
'credential_cache' => '', // 凭证缓存文件;留空=与数据库同目录的 oss.sts.php
'credential_refresh_margin' => 300, // 到期前多少秒就提前换新(秒)
'domain' => '', // 代理架构下【不再使用】:附件一律经本站 media.php 输出,无需自定义域名
'url_scheme' => 'https', // 公网 Endpoint 时使用的协议(内网 Endpoint 强制走 http)
'prefix' => 'fb', // 对象键前缀:fb/2026/09/xxxxxxxx.jpg
'visibility' => 'private', // 记录桶的读写权限:代理架构下推荐 private(浏览器永不直连桶)
'sign_ttl' => 600, // 服务器内部签名 URL 的有效期(秒),仅服务器侧使用
'link_ttl' => 604800, // 兼容保留;代理读取时签名有效期由代码收敛到 ≤300 秒
'image_process' => true, // 列表缩略图使用 OSS 图片处理(服务端缩放后再转发,省下行流量)
'verify' => true, // 提交时 HEAD 复核对象(防伪造/防超限)
'host_override' => '', // 仅特殊网关/联调使用;留空自动按 bucket.endpoint 拼接
],
/* ---------------- 附件限额 ----------------
* 单位:字节。原图上限指「压缩前」的原始文件大小(前端会先压缩到最长边 1600px)。
*/
'upload' => [
'image_max_per_post' => 4,
'image_max_bytes' => 5242880, // 5 MB / 张
'image_exts' => ['jpg', 'jpeg', 'png', 'webp', 'gif'],
'image_mimes' => ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
'image_max_side' => 1600, // 前端压缩后的最长边(像素)
'video_max_per_post' => 1,
'video_max_bytes' => 52428800, // 50 MB / 个
'video_exts' => ['mp4', 'mov', 'webm'],
'video_mimes' => ['video/mp4', 'video/quicktime', 'video/webm'],
'total_cap_bytes' => 1073741824, // 全站附件总量上限 1 GB,达到后暂停接收新上传
'retention_days' => 365, // 附件保留天数,超期由 cron.php 清理
'upload_per_hour' => 60, // 每 IP 每小时最多申请多少次上传凭证
],
/* ---------------- 反垃圾 ---------------- */
'rate_limit' => [
'thread_per_hour' => 5, // 每个 IP 每小时最多发起的主题数
'reply_per_hour' => 20, // 每个 IP 每小时最多回复数
],
'post_min_seconds' => 3, // 打开表单到提交不得少于该秒数(过快视为机器人)
/* ---------------- 列表 ---------------- */
'page_size' => 20,
];