轻量优雅的自托管图床应用,PHP 8.0+ / MySQL 5.7+,零框架依赖,原生开发。 Author : yefengs.com
悦·图床(YueAlbum)是一款面向个人和小团队的自托管图床应用。它以"轻量、优雅、实用"为设计理念,采用原生 PHP + 原生 JavaScript 开发,不依赖任何框架,部署简单、资源占用低。
主要特点:
| 组件 | 技术选型 | 说明 |
|---|---|---|
| 后端语言 | PHP 8.0+ | 推荐 PHP 8.4 |
| 数据库 | MySQL 5.7+ | MariaDB 10.3+ 兼容 |
| 图片处理 | GD 库 | 支持 JPEG/PNG/GIF/WebP |
| 前端 | 原生 JavaScript | 无框架依赖 |
| 样式 | 原生 CSS | CSS 变量 + 响应式 |
| 图标 | 内联 SVG Sprite | 零外部依赖 |
请求流程:
浏览器请求
↓
index.php (入口,定义常量)
↓
core/bootstrap.php (引导:自动加载、数据库、会话、认证)
↓
config/routes.php (路由配置)
↓
core/Router.php (路由分发)
├── 前台 → layout.php + pages/*.php
├── 后台 → admin/layout.php + admin/pages/*.php
└── API → api/*.php
核心类说明:
| 类 | 文件 | 职责 |
|---|---|---|
Database | core/Database.php | PDO 封装,CRUD、软删除、事务 |
Auth | core/Auth.php | 登录/登出、RBAC 权限校验 |
Session | core/Session.php | 会话管理、CSRF 令牌 |
Settings | core/Settings.php | 系统设置读写(数据库 kv 表) |
Router | core/Router.php | URL 解析与请求分发 |
ImageProcessor | core/ImageProcessor.php | 图片处理核心:格式转换、水印、裁切、缩放、旋转、EXIF、缩略图 |
辅助函数(core/helpers.php):
| 函数 | 说明 |
|---|---|
site_url($path) | 获取站点 URL(优先使用数据库配置) |
upload_url($path) | 获取图片 URL(优先使用图片域名配置) |
asset_url($path) | 获取静态资源 URL |
e($str) | HTML 转义 |
format_size($bytes) | 格式化文件大小 |
json_response($data) | JSON 响应输出 |
time_ago($datetime) | 相对时间显示 |
yue-album/
├── index.php 应用入口
├── install.php 安装向导入口
├── layout.php 前台布局模板
├── nginx.conf.example Nginx 配置参考
│
├── admin/ 后台管理
│ ├── layout.php 后台布局模板
│ ├── login.php 登录页
│ └── pages/ 后台功能页面
│ ├── dashboard.php 仪表盘
│ ├── images.php 图片管理
│ ├── editor.php 图片编辑器
│ ├── categories.php 分类管理
│ ├── trash.php 回收站
│ ├── watermarks.php 水印模板
│ ├── exif-templates.php EXIF模板
│ ├── upload-config.php 上传配置
│ ├── settings.php 系统设置
│ ├── anonymous.php 匿名配置
│ ├── users.php 用户管理
│ └── profile.php 个人信息
│
├── api/ API 接口
│ ├── auth.php 认证接口(登录/登出/改密)
│ ├── upload.php 上传接口
│ ├── images.php 图片查询接口
│ ├── images_edit.php 图片编辑接口
│ ├── categories.php 分类接口
│ ├── watermarks.php 水印接口
│ ├── exif.php EXIF模板接口
│ ├── settings.php 设置接口
│ └── users.php 用户接口
│
├── assets/ 静态资源
│ ├── css/
│ │ ├── system.css 公共样式(前后台共用)
│ │ ├── front.css 前台样式
│ │ ├── admin.css 后台样式
│ │ └── icons.css 图标样式
│ ├── js/
│ │ ├── app.js 前台脚本
│ │ └── admin.js 后台公共脚本
│ ├── img/ 静态图片(favicon 等)
│ └── icons.php SVG Sprite 图标定义
│
├── config/ 配置文件
│ ├── database.php 数据库配置(安装后自动生成)
│ ├── routes.php 路由配置
│ └── system.php 系统配置
│
├── core/ 核心类库
│ ├── bootstrap.php 应用引导
│ ├── Database.php 数据库封装
│ ├── Auth.php 认证与权限
│ ├── Session.php 会话管理
│ ├── Settings.php 设置管理
│ ├── Router.php 路由分发
│ ├── ImageProcessor.php 图片处理核心
│ └── helpers.php 辅助函数
│
├── install/ 安装向导
│ ├── index.php 安装流程
│ ├── schema.sql 数据库结构
│ └── view.php 安装界面
│
├── pages/ 前台页面
│ ├── home.php 首页
│ ├── upload.php 上传页
│ ├── gallery.php 图库页
│ ├── image.php 图片详情
│ └── 404.php 404 页
│
└── uploads/ 图片存储目录
└── (按日期/自定义规则组织)
共 7 张数据表,统一使用 ya_ 前缀:
| 表名 | 说明 | 关键字段 |
|---|---|---|
ya_users | 用户表 | username, password, nickname, role, permissions(JSON), status |
ya_images | 图片表 | user_id, category_id, title, file_path, file_size, width, height, format, hash, exif_data(JSON), is_favorite, status |
ya_categories | 分类表 | name, slug, description, cover_image, image_count |
ya_watermarks | 水印模板表 | name, image_path, position, margin_x(%), margin_y(%), size_type, size_width, size_percent, opacity |
ya_exif_templates | EXIF模板表 | name, camera, make, lens, exposure, aperture, iso, focal_length, author, latitude, longitude, altitude |
ya_settings | 系统设置表 | key, value(kv 结构) |
ya_access_logs | 外链访问日志 | image_id, referer, ip, user_agent |
关键设计说明:
status 标记为 trash,文件移入 uploads/.trash/ 目录,支持恢复hash 字段存储文件 SHA-256,上传时检测重复ya_users.permissions 字段存储 JSON 数组,可覆盖角色默认权限(如 ["category.manage"] 授权,["!image.manage-all"] 禁止)margin_x/margin_y 使用 decimal(5,2) 百分比,适配不同分辨率图片YueAlbum 采用简洁的自研路由,同时兼容 Apache mod_rewrite 和 Nginx try_files:
前台路由:
/ → 首页
/upload → 上传页
/gallery → 图库页
/image/{id} → 图片详情
后台路由:
/admin → 仪表盘
/admin/images → 图片管理
/admin/images?action=edit&id={id} → 图片编辑器
/admin/categories → 分类管理
/admin/trash → 回收站
/admin/watermarks → 水印模板
/admin/exif-templates → EXIF模板
/admin/upload-config → 上传配置
/admin/settings → 系统设置
/admin/anonymous → 匿名配置
/admin/users → 用户管理
/admin/profile → 个人信息
API 路由:
/api/auth/login POST 登录
/api/auth/logout POST 登出
/api/upload POST 上传图片
/api/upload/delete POST 删除图片
/api/upload/batch POST 批量上传
/api/images/list GET 图片列表
/api/images/detail GET 图片详情
/api/images_edit/* POST 图片编辑操作
/api/categories/* GET/POST 分类操作
/api/watermarks/* GET/POST 水印操作
/api/exif/* GET/POST EXIF操作
/api/settings/update POST 更新设置
/api/users/* GET/POST 用户操作
路由解析流程:
Router::resolveRoute() 优先读取 $_GET['route'](Apache mod_rewrite 传入)REQUEST_URI 中解析并去除基础路径(兼容 Nginx try_files)api/ 开头的请求进入 API 处理,自动映射到 api/*.phpadmin 开头的请求进入后台处理,登录页单独处理,其他需认证pages/*.php上传图片
↓
ImageProcessor::process($sourcePath, $options)
↓
┌── getimagesize() → 获取图片信息
├── createFromSource() → 创建 GD 图像资源
├── ensureMemory() → 动态提升 memory_limit(防止大图 OOM)
├── imagepalettetotruecolor() → 确保真彩色
├── addWatermark() → 添加水印(如已配置)
│ ├── 超大水印图预缩放至临时文件
│ ├── 百分比/固定尺寸 → 计算目标尺寸
│ ├── calcPosition() → 九宫格位置计算
│ ├── 逐像素 Alpha 调整 → 实现 PNG 半透明
│ └── imagecopy() → 合并水印(保留透明通道)
├── buildSubDir() → 根据路径规则生成子目录
├── generateFilename() → 根据命名规则生成文件名
├── saveImage() → 保存为指定格式和质量
└── 返回处理结果(路径、尺寸、大小、格式)
↓
写入数据库 ya_images 记录
↓
返回外链信息(url/html/markdown/bbcode)
| 项目 | 最低要求 | 推荐 |
|---|---|---|
| PHP | 8.0+ | 8.4 |
| MySQL | 5.7+ | 8.0 |
| PHP 扩展 | pdo_mysql, gd, mbstring, json | 同左 |
| GD 库 | 支持 JPEG/PNG | 支持 WebP 更佳 |
| 磁盘空间 | 100MB(程序 + 首批图片) | 视图片量而定 |
| 内存 | 128MB(PHP memory_limit) | 256MB+(大图处理) |
1. 下载程序
将程序文件上传到网站目录。支持根目录或二级目录部署:
# 根目录部署
/var/www/html/
# 二级目录部署
/var/www/html/yue-album/
2. 设置目录权限
# config/ 目录需要写入数据库配置
chmod 755 config/
# uploads/ 目录需要写入图片
chmod 755 uploads/
3. 配置 Web 服务器
参照下方 Web 服务器配置 章节。
4. 运行安装向导
浏览器访问站点地址,自动进入安装向导:
5. 登录后台
安装完成后访问 /admin 登录管理后台。
在 Nginx 的 server 块中添加:
# 根目录部署
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 二级目录部署(如 /yue-album)
location /yue-album/ {
try_files $uri $uri/ /yue-album/index.php?$query_string;
# 禁止访问 uploads 目录中的 PHP 文件
location ~ ^/yue-album/uploads/.*\.(php|phtml|php3|php4|php5|php7|phps)$ {
deny all;
}
# 禁止访问敏感文件
location ~ ^/yue-album/.*\.(env|sql|log|md)$ {
deny all;
}
# 静态资源缓存
location ~ ^/yue-album/.*\.(jpg|jpeg|png|gif|webp|avif|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# 重要:上传文件大小限制
client_max_body_size 20m;
⚠️
client_max_body_size默认仅 1MB,图床应用必须设置更大值,否则上传会返回 413 错误。
项目自带 .htaccess 文件,确保服务器已开启 mod_rewrite:
# 确认 httpd.conf 或虚拟主机配置中有:
AllowOverride All
1. PHP 配置
创建 .user.ini 文件(放在项目根目录或 uploads 目录):
upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 256M
max_execution_time = 60
2. 关闭错误显示
index.php 中已默认关闭,确认以下设置:
ini_set('display_errors', 0);
error_reporting(E_ALL); // 错误仍会写入日志
ini_set('log_errors', 1);
3. HTTPS 配置
建议为站点配置 HTTPS,可通过 Let's Encrypt 免费获取证书。
4. 上传目录安全
确保 Nginx/Apache 配置禁止执行 uploads/ 目录中的 PHP 文件(参考上方 Nginx 配置)。
站点首页展示介绍信息和快速上传入口。
登录用户的个人图库,按时间线浏览所有已上传图片。
查看单张图片的详细信息,包括 EXIF 数据、外链地址等。
登录后台(/admin)后可使用以下功能模块:
年/月/日、年/月、年、扁平YueAlbum 支持站点 URL 和图片域名两层 URL 配置:
| 配置项 | 作用 | 示例 |
|---|---|---|
| 站点 URL | 整站访问地址,影响页面跳转和资源路径 | https://example.com/yue-album |
| 图片域名 | 图片外链专用域名,适合 CDN | https://img.example.com/yue-album |
$_SERVER['SCRIPT_NAME'] 推导保存目录结构决定图片在 uploads/ 下的组织方式:
| 选项 | 路径示例 | 适用场景 |
|---|---|---|
| 年/月/日 | uploads/2026/04/20/xxx.jpg | 默认,图片量大时推荐 |
| 年/月 | uploads/2026/04/xxx.jpg | 中等图片量 |
| 年 | uploads/2026/xxx.jpg | 图片量较少 |
| 扁平 | uploads/xxx.jpg | 所有图片同一目录 |
文件名规则决定上传后的文件名生成方式:
| 规则 | 示例 | 说明 |
|---|---|---|
| 随机字符串 | 143022a3f2b1c4d8.jpg | 默认,安全性高 |
| 日期+随机 | 20260420_a3f2b1.jpg | 可读性好,按日期排序 |
| 保留原名 | 风景照片.jpg | 保留原始文件名,重名自动加后缀 |
| 哈希前12位 | e3b0c44295f1.jpg | 基于文件内容,天然去重 |
系统内置以下权限项:
| 权限标识 | 分组 | 说明 |
|---|---|---|
settings.manage | 系统 | 修改系统设置 |
watermark.manage | 配置 | 管理水印模板 |
exif-template.manage | 配置 | 管理EXIF模板 |
upload-config.manage | 配置 | 修改上传配置 |
category.manage | 内容 | 管理分类 |
user.manage | 系统 | 管理用户 |
trash.empty | 系统 | 清空回收站 |
image.manage-all | 内容 | 管理所有用户的图片 |
admin 角色默认拥有全部权限user 角色默认只能管理自己的图片! 前缀禁止uploads/ 目录执行 PHP 文件config/ 和 uploads/ 需要写入权限,其他目录不应给写权限.env、.sql、.log 文件upload_max_filesize/post_max_size)和 Web 服务器(Nginx client_max_body_size)的限制memory_limit ≥ 256M。系统会自动动态提升内存,但受限于 PHP 全局配置location 块需对应二级路径SCRIPT_NAME 和 REQUEST_URIya_,多应用共享数据库时可避免冲突Asia/Shanghai 时区,可在 bootstrap.php 中修改imagecopymerge(该函数不支持 Alpha 通道,会导致透明区域变黑)ya_access_logs 表记录Nginx 的 client_max_body_size 默认仅 1MB。在 Nginx 配置中添加:
client_max_body_size 20m;
修改后重启 Nginx。
需同时调整 PHP 和 Web 服务器的限制:
.user.ini
upload_max_filesize = 20M
post_max_size = 20M
client_max_body_size 20m;确保在后台「系统设置 → 基础设置」中填写了完整的站点 URL(包含 http:// 或 https://),如 https://example.com/yue-album。保存后系统会优先使用此配置生成外链地址。
在后台「系统设置 → 基础设置」中配置「图片域名及路径」字段。配置后所有图片的直链、HTML、Markdown、BBCode 都会使用此域名。例如配置 https://img.example.com/yue-album,则图片地址为 https://img.example.com/yue-album/uploads/2026/04/20/xxx.jpg。
这是 GD 库 imagecopymerge 的已知问题——该函数不支持 Alpha 通道。YueAlbum 已通过逐像素 Alpha 调整方式解决此问题。如果仍出现黑底,请确认水印图片是 PNG 格式且具有透明背景。
通常是 PHP 内存不足。解决方案:
memory_limit:在 .user.ini 中设置 memory_limit = 512Mphp.ini 全局配置约束memory_limit,建议使用 VPS确认 Nginx 配置中 try_files 指向了正确的 index.php:
location /yue-album/ {
try_files $uri $uri/ /yue-album/index.php?$query_string;
}
注意 $query_string 前的路径必须与实际部署路径一致。
MIT License
悦·图床 YueAlbum — 轻量优雅,为图片而生。