Files
YwxAppThink/.env.example
T
yangwx 18101cf11a feat: 上线前安全加固与发布工程化;appmall 由插件迁移为独立应用
安全(P0)
- 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、
  ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签
  (ywxapp.framework_package_verify,默认开启)
- JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret()
  校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET
- /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验
- 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流
- TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive
- 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php)
- 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis
- paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG

工程化 / 交付
- 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本
- 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过
- 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障
- .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess

结构
- appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
2026-10-22 00:53:39 +08:00

200 lines
10 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================
# YwxApp 环境变量模板 (.env.example)
# -------------------------------------------------------------
# 用法:cp `config.example` `.env` 后填写真实值。
# .env 已被 .gitignore 忽略,不会入库。
# 注意:等号两侧不要留空格(`KEY=value`,不能是 `KEY= value` 或 `KEY =value`)。
# 注释行以 `#` 起始;空值表示「使用代码内默认值」(详见各键说明)。
# 章节:① 部署相关 ② 应用基础 ③ 数据库 ④ Redis 缓存 ⑤ 文件存储
# ⑥ 多语言 ⑦ JWT/鉴权 ⑧ 邮件 ⑨ 数据同步 ⑩ 支付
# ⑪ 应用市场 / 插件密钥 ⑫ 第三方插件(短信等可选)
# =============================================================
# ==================== ① 部署相关 ====================
# 用于将打包产物(scripts/package_*.php 生成)通过 FTP 推送到生产服务器。
# 该变量是「部署者专用钩子」,不依赖项目内任何脚本——
# 部署脚本(如 PowerShell / Bash 等)由部署方自行维护,scripts/ 内不存在此脚本。
# 部署脚本读取建议:优先环境变量 $env:WXAPP_FTP_PASS / $WXAPP_FTP_PASS,其次本文件。
# 仅用于部署发布,与运行期无关;不需要可留空。
WXAPP_FTP_PASS=
# ==================== ② 应用基础 ====================
# 读取:config/app.php — app_debug / app_host
APP_DEBUG=true
# APP_DEBUG=true → 显示错误、SQL 日志、关闭模板缓存(仅本地/调试用)
# APP_DEBUG=false → 生产环境务必设为 false
APP_HOST=
# 官方 API 地址:用于框架在线升级、远程市场同步
# 读取:config/ywxapp.php — api_url(env('APP_API_URL', 'https://www.ywxapp.cn'))
# 中心站模式留空或指向本机;客户机模式指向中心站域名。
APP_API_URL=https://www.ywxapp.cn
# 市场角色(控制 is_market_client()):center / client / auto
# 读取:config/ywxapp.php — market_mode(env('APP_MARKET_MODE', 'auto'))
# center → 显式锁定本机为中心站(本地开发推荐,不再依赖 api_url 推断)
# client → 显式锁定本机为客户机(应用市场公开入口会主动 404)
# auto → api_url 为空/本机时为中心站,否则为客户机(默认,受 api_url 影响)
# 显式声明优于 auto,避免后续误改 APP_API_URL 时角色被翻转。
APP_MARKET_MODE=auto
# ==================== ③ 数据库(ThinkPHP 标准键) ====================
# 读取:config/database.php
# 安装向导(public/install/Installer.php)会重新写入这些键。
DB_DRIVER=mysql # default 连接驱动(一般无需修改)
DB_TYPE=mysql # connections.mysql.type
DB_HOST=127.0.0.1
DB_NAME=ywxapp
DB_USER=root
DB_PASS=
DB_PORT=3306
DB_CHARSET=utf8mb4 # 建议 utf8mb4(emoji/中文兼容)
DB_PREFIX=wxapp_ # 表前缀,安装时由 Installer 统一写入
DB_PERSISTENT=true # 是否启用长连接(高并发场景视 MySQL 配置决定)
# ==================== ④ Redis 缓存(ThinkPHP 标准键) ====================
# 读取:config/cache.php
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# ==================== ⑤ 文件存储 ====================
# 读取:config/storage.php — default + drivers.{alioss,qcos}
# 取值:local(默认)/ alioss / qcos(其它驱动需在 drivers 中添加)
FILE_STORAGE_DRIVER=local
# ---- 阿里云 OSS(FILE_STORAGE_DRIVER=alioss 时必填)----
ALIOSS_ACCESS_KEY=
ALIOSS_SECRET_KEY=
ALIOSS_ENDPOINT= # 如 oss-cn-hangzhou.aliyuncs.com
ALIOSS_BUCKET=
ALIOSS_CDN_DOMAIN= # 可选:启用 CDN 加速域名
# ---- 腾讯云 COS(FILE_STORAGE_DRIVER=qcos 时必填)----
QCOS_REGION= # 如 ap-guangzhou
QCOS_SECRET_ID=
QCOS_SECRET_KEY=
QCOS_BUCKET=
# ==================== ⑥ 多语言 ====================
# 读取:config/lang.php — default_lang
# 取值:zh-cn / en-us / 自定义语种(需配套语言包)
DEFAULT_LANG=zh-cn
# ==================== ⑦ JWT / 鉴权 ====================
# 后台 / 会员 JWT 鉴权密钥
# 读取:config/jwt.php — secret(默认值仅为占位,生产务必替换)
# HS256 要求 ≥ 256 bits(32 字节)。建议用 `openssl rand -base64 48` 生成。
JWT_SECRET=replace_with_48_byte_base64_strong_random_secret_key_xxxxx
# ==================== ⑧ 邮件 ====================
# 读取:config/mail.php
# 留空时发信功能不会启用;建议使用 SMTP 协议 + SSL。
MAIL_HOST=smtp.example.com
MAIL_PORT=465
MAIL_SECURE=ssl # ssl / tls / 空
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM=
MAIL_FROM_NAME=YwxApp 应用市场
# ==================== ⑨ 数据同步 ====================
# 读取:config/sync.php — isEnable / baseUrl / key
# 用于「主框架 ↔ 业务后台」数据同步通道(开关、目标地址、共享密钥)。
SYNC_IS_ENABLE=false
SYNC_BASE_URL=https://sync.example.com
SYNC_KEY=your-256-bit-secret-key-here
# ==================== ⑩ 支付 ====================
# 读取:config/pay.php
# 三重防御(已就位):
# 1) 本键默认关闭(防御性默认,避免默认值泄露);
# 2) Installer.writeEnv() 会强制把 PAY_MOCK=false 写入 .env;
# 3) MarketService / Market 在生产(APP_DEBUG=false)拒绝执行 mock。
# 本地调试:显式设 PAY_MOCK=true(须与 APP_DEBUG=true 配对)。
PAY_MOCK=false
# 说明:真实的下单 / 验签 / 回调已收拢到支付中心插件 addon/paycenter(见其 README)。
# 下面的 PAY_ALIPAY_* / PAY_WECHAT_* 仍是密钥的唯一来源(不进数据库),插件与核心共用。
# 自检:php think paycenter:check --ping(--channel=alipay|wechat|all)
# ---- 支付宝(证书模式,Yansongda Pay v3.7 的硬性要求)----
# 普通公钥模式在该版本已不被识别,必须在开放平台「接口加签方式」切换为证书并下载三份证书。
# 私钥可填 PEM 全文、单行 base64,或文件路径;三份证书放 runtime/cert/ 下即可(路径可以是相对路径,
# 配 config/pay.php 会按项目根目录解析成绝对路径,避免 Web 入口 CWD 在 public/ 时读不到)。
# 文件名随意,只要与下面三个 *_PATH 对得上:官方下载名分别是
# appCertPublicKey_*.crt(应用公钥证书)/ alipayCertPublicKey_*.crt(支付宝公钥证书)/ alipayRootCert.crt(根证书)
PAY_ALIPAY_MODE=0 # 整数:0=正式 1=沙箱 2=服务商(见 Yansongda\Pay\Pay::MODE_*)
PAY_ALIPAY_APP_ID=
PAY_ALIPAY_APP_SECRET_CERT= # 应用私钥(或填私钥文件路径)
PAY_ALIPAY_APP_PUBLIC_CERT_PATH=runtime/cert/appCertPublicKey.crt
PAY_ALIPAY_PUBLIC_CERT_PATH=runtime/cert/alipayCertPublicKey.crt
PAY_ALIPAY_ROOT_CERT_PATH=runtime/cert/alipayRootCert.crt
# 仅 Windows/未配 curl.cainfo 的 PHP 需要:连网关报 cURL error 60(SSL certificate problem)时,
# 下载 https://curl.se/ca/cacert.pem 放本地并在这里指向它;正常服务器留空即可
PAY_HTTP_CA=
# ---- 微信支付(v3;微信已无官方沙箱,mode 恒为 0,只能真实小额支付后退款)----
# 商户平台 → API 安全:设置 APIv3 密钥、下载 API 证书(apiclient_cert.pem)与私钥(apiclient_key.pem)
PAY_WECHAT_MCH_ID=
PAY_WECHAT_APP_ID= # 未单独配置时 mp/mini 也用它
PAY_WECHAT_MP_APP_ID= # 公众号 JSAPI(可选,默认取 APP_ID)
PAY_WECHAT_MINI_APP_ID= # 小程序(可选,默认取 APP_ID)
PAY_WECHAT_SECRET_KEY= # APIv3 密钥
PAY_WECHAT_SECRET_CERT= # 商户 API 私钥(PEM / 单行 base64 / 文件路径)
PAY_WECHAT_PUBLIC_CERT_PATH=runtime/cert/apiclient_cert.pem
# 平台证书(回调验签用)留空即可:SDK 会凭 APIv3 密钥自动下载;
# 生产环境建议 php think paycenter:check 触发一次后落到 runtime/cert/wechat/ 并配置 wechat_public_cert_path。
# ==================== ⑪ 应用市场 / 插件密钥 ====================
# ---- 开发者令牌:后台「发布到官方市场」与 appmall 插件开发者中心共用 ----
# 读取:
# config/appmall.php → config('appmall.developer_token')
# config/ywxapp.php → config('ywxapp.developer_token')(已与 appmall 同源)
# app/backend/controller/Addons.php::submitOfficial() 实际取的是上面这个值
# 留空则后台操作时会提示「未配置开发者令牌:请在 .env 设置 APPMARKET_DEV_TOKEN」。
APPMARKET_DEV_TOKEN=
# 开发者账号名(可选,仅用于显示)
APPMARKET_DEV_NAME=
# 远程市场共享密钥:仅当本机作「客户机」连接中心站时需要
# 读取:config/appmall.php → config('appmall.remote_token')
# 单站点中心站模式留空即可;客户机必须与中心站 APPMARKET_REMOTE_TOKEN 一致。
APPMARKET_REMOTE_TOKEN=
# 连接远程市场时是否校验 SSL 证书(生产建议 true)
APPMARKET_SSL_VERIFY=true
# 平台抽成比例(0~1):插件市场成交时平台分账比例,默认 0.2(20%)
APPMARKET_COMMISSION_RATE=0.2
# 发布前 PHP 语法 + 高危函数扫描(生产建议 true)
APPMARKET_SECURITY_SCAN=true
# ---- 插件签名 / 下载校验密钥(中心站与客户机共享)----
# 读取:config/ywxapp.php — addon_secret
# 生产务必替换为强随机值;中心站与所有客户机必须一致。
ADDON_SECRET=change_me_to_a_strong_addon_secret
# 是否允许未知来源插件(离线包)安装:true 时跳过远程授权校验
# 读取:config/ywxapp.php — unknownsources(仅当 APP_DEBUG=true 时生效)
ADDON_UNKNOWN_SOURCES=false
# 开发者模式开关:开启后后台「插件」出现「设计插件」入口
# 读取:config/ywxapp.php — addon_developer
# 生产务必保持 false(与 APP_DEBUG 解耦的独立开关)。
ADDON_DEVELOPER=false
# ==================== ⑫ 第三方插件(按需启用) ====================
# 短信插件 addon/smssend 需配置网关(由插件自身 config 维护,不一定走 .env);
# 其他插件的配置项请参考各插件 addon/<name>/README.md。
# =============================================================
# 提示:以下为「代码硬编码、未走 env()」的项目,仅作备忘。
# config/ywxapp.php: addon_license_check=false (运行期授权巡检开关,写死 false;
# 如需开启,请直接编辑该文件或后续 PR 改造为 env() 控制)
# =============================================================