家常菜谱 Recipe Hub · 项目速览

碎碎念
这个项目纯纯靠Workbuddy参考各个开源的菜谱程序,像是现有的开源菜谱程序,很多功能并不适配中文环境,用着总是别扭,这个项目前后靠AI打磨了二十多天,基本上该做的功能都有了,可以自定义每日菜谱推送给机器人,如果有bug或者想增加功能,可以自己克隆源码,也可以在项目页提交相关。
这里主推Docker部署,已经上传Docker Hub,可以直接下载,部署只需要配置端口和存储路径。
演示站点:https://caipu.dawnlife.qzz.io/
项目地址:https://github.com/xyzbz/recipe-hub
当前版本 1.1.3。自托管的中餐菜谱系统:菜谱 → 库存 → 周计划 → 采购清单,一条链闭环。
| 仓库形态 | PHP 源码,无构建步骤,拷过去就能跑 |
| 官方镜像 | xyzbz/recipe-hub:1.1.3(也带 latest) |
| 参考线上 | https://caipu.dawnlife.qzz.io/ |
| 详细文档 | 功能细节看 README.md,部署三步看 DEPLOY.md |
1. 技术线
| 层 | 选型 | 说明 |
|---|---|---|
| 后端 | PHP 8.2+(镜像内 8.3) | 无框架、无 Composer 依赖,手写路由 + PSR-4 风格自动加载(src/,命名空间 RH\) |
| 数据库 | SQLite(WAL) | 单文件 data/recipe.sqlite,无外部数据库服务;结构变更走幂等迁移(PRAGMA user_version,现 v3) |
| 前端 | 原生 ES module + hash 路由 | 无打包器、无 npm install,改完刷新即生效;路由形如 #/recipes/12,部署到任何路径都不用配服务端重写 |
| 接口 | 自写 JSON API | public/index.php 单入口分发;写请求走 CSRF 双提交(Cookie + X-CSRF-Token) |
| 图片 | 一律转 WebP | gd 缩放 + 出缩略图,exif 纠正手机竖拍方向;存在 docroot 之外,经 /uploads/… 由 PHP 带权限流式输出 |
| 容器 | php:8.3-apache | 单容器,编译进 gd(freetype/jpeg/webp)与 exif,开 rewrite/headers/expires/deflate |
2. 功能
| 模块 | 要点 |
|---|---|
| 菜谱库 | 中餐单位(克/斤/两/勺/瓣/把)、份数缩放(模糊量「少许」不参与计算)、中文搜索、公开/私有、回收站、打印贴冰箱、家人留言、下厨记录、随机「今天吃什么」 |
| 食材与库存 | 预置食材库带别名(生抽=酱油=豉油)、冷藏/冷冻/常温/干货柜、过期提醒、按现有食材倒推能做什么菜 |
| 膳食周计划 | 拖拽排一周三餐、一键换菜、整周模板、指定时段一键转采购清单 |
| 采购清单 | 同名食材跨菜谱自动相加、按买菜动线分组、勾选已买、买回一键入库 |
| 定时推送 | 企业微信 / PushPlus / Server酱 / WxPusher / 自定义 Webhook(飞书·钉钉·Telegram),到点推「今天吃什么」 |
| 权限与安全 | 管理员 / 读写 / 只读三档、可选游客浏览、登录失败锁定、password_hash 加盐、会话在库里、CSRF 双提交 |
| 备份恢复 | 只有一个入口:后台「备份」。一键产整站 zip(数据库 + 全部图片),恢复时先体检再铺图换库,换库前自动留 before-restore-* 快照 |
| 迁移 | 自家 JSON 导入导出;cli/import-mealie.php 从 Mealie 整站迁移(含图片) |
| 其它 | 深色模式、从 URL 导入未做、只做 Web(手机浏览器移动优先,可添加到主屏幕当 PWA 用) |
3. 部署环境要求(两条路线通用)
| 项目 | 要求 |
|---|---|
| PHP | 8.2 及以上(8.3 已验证;8.1 未测) |
| 必需扩展 | pdo_sqlite、sqlite3、mbstring、fileinfo、session、json |
| 图片扩展 | gd(需 WebP + JPEG + PNG + FreeType)、exif —— 缺了图片功能残废 |
| 数据库 | 无(SQLite 自带驱动) |
| Web 服务 | Apache(需 mod_rewrite)或 Nginx |
| 目录权限 | data/、data/uploads/、data/backups/ 必须可写 |
| 定时任务 | 可选,只有「膳食计划定时推送」需要(每分钟跑一次) |
| 资源占用 | 极低;镜像约 500 MB,运行内存几十 MB 起步 |
Web 根目录必须指向 public/ —— src/ 和 data/ 在上一级,绝不能被直接访问。
健康检查:访问 /healthz,正常返回 {"ok":true,"version":"1.1.3","time":"…"}。
版本以 bootstrap.php 里的 RH_VERSION 为准,各处版本号统一从它读取。
4. Docker 部署
最小 compose
services:
recipe-hub:
image: xyzbz/recipe-hub:1.1.3
container_name: recipe-hub
restart: unless-stopped
ports:
- "8080:80" # 左宿主 / 右容器(容器内固定 80)
volumes:
- ./data:/var/www/html/data # 全部家当:数据库 + 图片 + 备份
environment:
TZ: Asia/Shanghai
RH_SITE_URL: https://eat.example.comdocker compose up -d # 起来
docker compose pull && docker compose up -d # 升级(数据在卷里,不受影响)
docker compose logs -f # 看日志浏览器打开 http://服务器IP:8080,走安装向导建管理员账号。
| 项 | 值 | 为什么 |
|---|---|---|
| 端口 | 容器 80 → 宿主 8080 | 宿主端口随意改 |
| 数据卷 | /var/www/html/data | 必须挂出来,不挂容器一删数据就没 |
| 站点地址 | RH_SITE_URL | 不填推送会降级成纯文本(拼不出菜谱链接) |
| 反代 | 传 X-Forwarded-Proto | PHP 靠它判断原始协议,决定 Cookie 是否加 Secure |