# picbed
**Repository Path**: xunjinlu/picbed
## Basic Information
- **Project Name**: picbed
- **Description**: PicBed - 轻量级多类型文件管理系统 | 支持图片/视频/音频/文档上传管理、在线预览、同源安全防护、子目录部署、响应式界面
- **Primary Language**: PHP
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: https://gitee.com/xunjinlu/picbed
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-01-13
- **Last Updated**: 2026-07-13
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
PicBed - 轻量级多类型文件管理系统
支持图片、视频、音频、文档、文本、代码等多种文件类型的上传与在线预览
## 功能特性
### 文件管理
- **全类型支持** - 图片、视频、音频、文档、文本、代码、压缩包等
- **在线预览** - 图片直接查看,视频/音频在线播放,文本/代码在线阅读,PDF 在线预览
- **文件分类** - 自动识别文件类型,彩色标签标识(图片/视频/音频/文档/文本/代码/压缩包)
- **批量上传** - 支持拖拽上传、多文件同时上传
- **文件替换** - 保持链接不变,替换文件内容
- **文件删除** - 管理员可删除文件
### 链接格式
上传后支持 7 种链接格式输出:
- **URL** - 直接链接
- **Markdown** - ``
- **HTML** - `
` 标签
- **BBCode** - `[img]url[/img]`
- **UBB** - `[IMG]url[/IMG]`
- **CSS** - `background-image`
- **JSON** - JSON 格式
### 命名规则
支持 7 种文件命名方式:
- 自然序号递增(从 1 开始,自动增加位数)
- 时间戳(YmdHis)
- 日期+序号
- UUID
- MD5 随机
- 短随机字符(8位)
- 前缀+日期
### 系统功能
- **JSON 配置** - 所有配置通过 Web 页面管理,存储在 `data/config.json`
- **自定义上传目录** - 可在设置中自定义上传文件夹路径,支持多层子目录,默认 `img/`
- **多文件夹管理** - 支持多个上传目录共存,文件库可按目录筛选,历史目录文件不丢失
- **手动扫描** - 保存设置时自动扫描所有历史目录补全数据,新版部署不自动扫描
- **同源安全校验** - 所有写操作检查 Origin/Referer 同源,防止外部抓包直接调用 API
- **本地数据库** - `data/db.json` 存储文件元信息(名称、大小、时间)
- **自动迁移** - 首次使用自动扫描已有文件导入数据库
- **密码安全** - password_hash 加密存储
- **会话管理** - 可配置超时时间,支持记住登录
- **游客上传** - 可配置是否需要登录才能上传
- **页脚配置** - 支持版权信息、ICP 备案号、公安备案号
- **累计统计** - 显示当前文件数量和占用空间
- **响应式设计** - 完美适配手机和电脑
### 文件类型快捷配置
设置页面提供文件类型预设按钮:
- 仅图片
- 图片+视频+音频
- 文档
- 代码
- 全部类型
## 安装部署
### 环境要求
- PHP 7.4 / 8.0 / 8.2
- Web 服务器(Nginx / Apache)
- 目录写权限
### 安装步骤
1. 下载源码并上传到服务器
2. 解压到 Web 目录
3. 确保 `data/` 目录有写权限
4. 确保 `img/` 目录有写权限
5. 访问 `index.php` 开始使用
### 目录权限
```bash
chmod 755 /path/to/picbed
chmod 755 /path/to/picbed/data
chmod 755 /path/to/picbed/img
```
### Nginx 配置示例
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/picbed;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* ^/(data)/ {
deny all;
}
}
```
## 目录结构
```
picbed/
├── index.php # 上传页面
├── gallery.php # 文件库页面
├── settings.php # 设置页面
├── api.php # API 接口(全部合并)
├── README.md # 说明文档
├── assets/
│ ├── css/
│ │ ├── common.css # 公共样式
│ │ ├── index.css # 上传页面样式
│ │ ├── gallery.css # 文件库样式
│ │ └── settings.css # 设置页面样式
│ └── js/
│ ├── common.js # 公共脚本
│ ├── index.js # 上传页面脚本
│ ├── gallery.js # 文件库脚本
│ └── settings.js # 设置页面脚本
├── data/
│ ├── .htaccess # 禁止直接访问
│ ├── config.json # 站点配置
│ ├── db.json # 文件数据库
│ └── stats.json # 统计数据(累计上传数、占用空间、计数器)
└── img/ # 上传文件存储目录
```
## API 接口
### 认证相关
| 接口 | 方法 | 说明 |
|------|------|------|
| `?act=auth_status` | GET | 获取认证状态 |
| `?act=login` | POST | 登录(JSON: `{password}`) |
| `?act=logout` | POST | 登出 |
| `?act=changepwd` | POST | 修改密码(JSON: `{old_password, new_password}`) |
### 文件操作
| 接口 | 方法 | 说明 |
|------|------|------|
| `?act=upload` | POST | 上传文件(FormData: `image[]`) |
| `?act=list` | GET | 文件列表(参数: `page`, `sort`, `per_page`) |
| `?act=info` | GET | 文件信息(参数: `filename`) |
| `?act=filetype` | GET | 文件类型分类(参数: `filename`) |
| `?act=delete` | POST | 删除文件(JSON: `{filename}`) |
| `?act=replace` | POST | 替换文件(FormData: `image`, `replace_filename`) |
### 配置相关
| 接口 | 方法 | 说明 |
|------|------|------|
| `?act=config` | GET | 获取公开配置 |
| `?act=config_all` | GET | 获取完整配置(需登录) |
| `?act=config_save` | POST | 保存配置(需登录) |
| `?act=stats` | GET | 获取统计数据 |
### 文件类型分类
系统自动将文件分为以下类别:
| 分类 | 扩展名 | 预览方式 |
|------|--------|----------|
| 图片 | jpg, png, gif, webp, svg, bmp, tiff | 直接预览 |
| 视频 | mp4, avi, mov, mkv, webm | 在线播放 |
| 音频 | mp3, wav, ogg, flac, aac | 在线播放 |
| 文档 | pdf, doc, docx, xls, xlsx, ppt, pptx | PDF 在线预览,其他下载 |
| 文本 | txt, md, log, csv, ini, rtf | 在线查看 |
| 代码 | json, xml, html, css, js, py, sql, sh 等 | 在线查看(等宽字体) |
| 压缩包 | zip, rar, 7z, tar, gz | 仅上传,不支持预览 |
## 配置说明
所有配置存储在 `data/config.json`,可通过设置页面修改:
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| site_name | PicBed | 站点名称 |
| enable_auth | true | 启用鉴权 |
| upload_auth | true | 上传需要登录 |
| admin_password | admin123 | 管理员密码 |
| session_timeout | 7200 | 会话超时(秒) |
| remember_login | true | 记住登录 |
| allowed_types | jpg,png,gif,... | 允许的文件类型 |
| naming_rule | sequential | 命名规则 |
| naming_prefix | | 命名前缀 |
| max_file_size_mb | 50 | 最大文件大小(MB) |
| upload_dir | img | 当前上传目录(支持多层子目录,如 uploads/images) |
| upload_dirs | ["img"] | 历史上传目录列表(自动维护) |
| images_per_page | 20 | 每页文件数 |
| copyright | | 版权信息 |
| icp | | ICP 备案号 |
| police_icp | | 公安备案号 |
## 更新日志
### v3.38.1 (2026-06-20)
- 完善 counter 同步机制,确保删除后编号永不回退
- `picbed_getNextCounter()` 改为始终取 `max(counter, max_seq+1)`,不再有条件判断
- `picbed_rebuild_stats()` 增加 counter 同步:取 `max(已有counter, db最大编号+1)`
- `picbed_migrate_stats()` 从旧文件迁移时也确保 `counter >= db最大编号+1`
- 部署/升级时自动检索 db.json 更新 counter,无需手动操作
- 删除文件后编号永久废弃,新文件接着最大编号继续递增
### v3.38.0 (2026-06-20)
- 修复递增命名填补已删除编号空缺的问题
- 新增 `picbed_getMaxSeqFromDb()` 从 db.json 提取最大顺序编号
- `picbed_getNextCounter()` 确保 counter 不小于 db 中最大编号+1
- 删除文件后上传新文件,接着最大编号继续递增,而非填补空缺
- `picbed_migrate_stats()` 初始化 counter 改为最大编号+1(原为 `count($db)`)
- 修复 `stats.json` 丢失后 counter 从0开始导致填补空缺的问题
### v3.37.3 (2026-06-20)
- 修复子目录部署扫描双重路径问题(彻底修复)
- 扫描逻辑重构:只扫描当前 `upload_dir`,不再扫描 `upload_dirs` 中的历史目录
- 之前扫描 `upload_dirs` 中所有目录(包括 `img` 三级目录),导致文件被记录为 `dir='img'`
- URL 生成 `baseUrl + 'img/' + filename` 出现双重路径(如 `/img/img/filename`)
- 现在只扫描当前 `upload_dir`,所有记录的 `dir` 统一为当前 `upload_dir` 值
- `picbed_db_repair()` 同步重构:只检查当前 `upload_dir`,统一 `dir` 字段
- 不在当前 `upload_dir` 中的文件记录将被自动清理
- 修复 PicBed 部署在 `/img/` 且 `upload_dir='.'` 时 URL 出现 `/img/img/` 的问题
### v3.37.2 (2026-06-20)
- 修复子目录部署时扫描生成双重路径名
- `picbed_rebuild_db_from_all_dirs()` 保留旧记录时增加文件位置验证
- 旧记录的文件不在原 `dir` 时,自动尝试当前 `upload_dir`,找到则更新 `dir`
- 文件不存在于任何目录时丢弃记录,避免产生无效 URL
- `picbed_db_repair()` 增加根目录兜底查找,修正错误的 `dir` 字段
- 修复 PicBed 部署在子目录(如 `/img/`)且 `upload_dir='.'` 时 URL 出现双重 `img` 的问题
### v3.37.1 (2026-06-20)
- 修复根目录扫描系统文件 + 计数不一致
- 新增 `picbed_isSystemFile()` 函数,扫描时排除系统文件
- 所有 `.php` 文件、`.htaccess`、`README.md` 等不再被扫描记录
- 根目录额外排除 `LICENSE`、`CHANGELOG.md`、`Dockerfile` 等项目文件
- `dirs` API 计数改为按 `allowed_types` 过滤,与文件库显示一致
- `picbed_db_repair()` 自动清理已存在的系统文件记录
### v3.37.0 (2026-06-20)
- 安全机制完全重构
- 移除 CSRF Token 机制(导致 session 竞态、登录失败、保存失败)
- 改用 Origin/Referer 同源检查,防止外部抓包直接调用 API
- 所有写操作(upload/delete/replace/config_save/changepwd)增加同源校验
- 同源检查兼容 HTTP/HTTPS、不同端口、反向代理场景
- 移除 `getPublicConfig` 中的 `csrf_token` 字段
- 前端移除所有 CSRF Token 相关代码(`csrfToken`/`ensureCsrfToken`)
- 恢复所有写请求为原始格式,不再携带 Token
### v3.36.3 (2026-06-20)
- 修复 CSRF Token 异步竞态导致验证失败
- `checkAuth()` 中获取 CSRF Token 的 fetch 是异步的,callback 不等它完成
- 新增 `ensureCsrfToken()` 等待机制,确保 Token 获取后再发送写请求
- 所有写操作(upload/save/delete/replace/changepwd)使用 `ensureCsrfToken` 包裹
### v3.36.2 (2026-06-20)
- 修复 CSRF Token 验证后销毁导致后续操作失败
- 移除 `picbed_verifyCsrfToken()` 中验证后销毁 token 的逻辑
- Token 在 session 生命周期内持续有效,支持多次操作
- 修复设置页面保存、文件删除等操作提示"安全验证失败"的问题
### v3.36.1 (2026-06-20)
- 修复 CSRF Token 多次调用覆盖导致验证失败
- Token 改为复用机制:session 中已有 token 则复用,不再每次覆盖
### v3.36.0 (2026-06-20)
- 上传安全机制 + 根目录支持修复
- 新增 CSRF Token 防护,防止抓包直接调用 API 上传
- 所有写操作(upload/replace/delete/config_save/changepwd)需携带 Token
- Token 通过 session 生成,页面加载时从 `api.php?act=config` 获取
- Token 验证后自动销毁,防止重放攻击
- 修复根目录(`.`)配置:URL 生成去除 `./` 前缀
- 新增 `picbed_getFilePath()` 辅助函数统一处理根目录路径
### v3.35.0 (2026-06-20)
- 多文件夹支持 + 扫描机制重构
- `db.json` 每条记录新增 `dir` 字段,记录文件所在目录
- `config.json` 新增 `upload_dirs` 数组,记录所有使用过的上传目录
- 扫描机制改为手动触发(保存设置时扫描所有历史目录)
- 新版部署后不再自动扫描,改为用户保存设置时才扫描
- `list` API 新增 `dir` 参数,支持按目录过滤文件
- 新增 `dirs` API,返回所有已知的上传目录列表及各目录文件数
- 删除/替换操作优先使用记录中的 `dir` 字段定位文件
- 文件库页面新增文件夹选择器,支持按目录筛选
- 不选择目录时显示所有目录的文件(兼容历史文件)
- 编号计数器全局递增,跨目录继承编号
- `getPublicConfig` API 返回 `upload_dirs` 供前端使用
### v3.34.0 (2026-06-20)
- 新增自定义上传文件夹功能
- 设置页面"上传设置"中新增"上传目录"配置项
- 支持自定义上传文件夹路径,如 `uploads/images/2026`
- 支持多层子目录,支持根目录(`.`)直接上传到站点根
- 不配置时默认使用 `img` 文件夹
- 路径安全校验:禁止 `../` 路径穿越,禁止绝对路径
- 文件库灯箱和卡片缩略图路径改为动态获取 `upload_dir`
- `getPublicConfig` API 返回 `upload_dir` 供前端使用
### v3.33.0 (2026-06-19)
- 优化卡片堆叠密度和溢出问题
- 卡片尺寸从 80px 缩小到 72px,重叠间距从 -24px 缩小到 -20px
- 手机端卡片 56px,重叠间距 -14px
- 手机端最多显示 5 张卡片,桌面端最多 8 张,超出显示 `+N`
- 旋转角度收窄(-8° 到 +13°),更紧凑美观
- `+N` 卡片使用虚线边框区分
- 选择框和上传结果区域统一优化
### v3.32.0 (2026-06-19)
- 恢复灯箱抽屉为固定高度
### v3.31.0 (2026-06-19)
- 修复覆盖安装后 stats.json 为空不自动重建的问题
### v3.30.0 (2026-06-19)
- 修复覆盖安装后 db.json 为空不自动重建的问题
### v3.29.0 (2026-06-19)
- 彻底恢复 v3.25 的文件库 UI 样式
### v3.28.0 (2026-06-19)
- 修复文件库页面 UI 完全崩溃的问题
### v3.27.0 (2026-06-19)
- 修复文件库页面报错(灯箱 HTML/JS/CSS 结构不匹配)
### v3.26.0 (2026-06-19)
- 灯箱预览区域真正自适应
### v3.25.0 (2026-06-19)
- 页脚链接支持自定义
### v3.24.0 (2026-06-19)
- 修复顺序命名计数器不递增的问题
### v3.23.0 (2026-06-19)
- 上传页面显示已选文件总大小
### v3.22.0 (2026-06-19)
- 版本升级检测 + 自动修复统计数据
### v3.21.0 (2026-06-19)
- 修复上传结果区域文档预览触发下载的问题
### v3.20.0 (2026-06-19)
- 上传动效 + 逐个上传燃尽效果
### v3.18.0 (2026-06-19)
- 上传页面全面优化
### v3.17.3 (2026-06-19)
- 预览区域高度自适应,超出弹窗支持滚动
### v3.17.2 (2026-06-19)
- 修复视频预览控制条被挤出弹窗的问题
### v3.17.1 (2026-06-19)
- 修复 PDF 在线预览加载失败的问题
- 禁用 pdf.js Web Worker,改用主线程解析 PDF
- 避免 worker 文件路径加载失败或 CORS 跨域问题
- 错误提示显示具体错误信息,便于排查问题
### v3.17.0 (2026-06-19)
- 卡片缩略图增强
- 视频卡片自动加载视频首帧(0.5秒处)作为封面缩略图
- 视频封面右下角显示播放按钮(鼠标悬停时显示)
- 音频卡片显示渐变色封面(紫蓝粉渐变 + 音乐图标)
- 图片卡片保持原有缩略图显示
- 动态照片兼容
- 各手机厂商的动态照片(Motion Photo,后缀为 .jpg)正常显示静态图片部分
- 浏览器 `
` 标签自动渲染 JPEG 中的静态图片
### v3.16.0 (2026-06-19)
- JS 库本地化部署
- marked.js、pdf.js(含 worker)、mammoth.js 下载到 `assets/libs/` 目录
- 不再依赖外部 CDN,避免国外站点访问慢或关闭导致预览失败
- 灯箱预览区域动态高度
- 预览区域改为 `flex:1` 自适应,不再固定 `max-height`
- 灯箱总高度增大到 85vh(电脑)/ 90vh(手机/大屏)
- 文档/文本/PDF/视频等文件预览区域自动占满剩余空间
- MD 文档、PDF、Word 等文件预览空间大幅增加
### v3.15.0 (2026-06-19)
- PDF 文件在线预览(使用 pdf.js 渲染到 Canvas)
- 解决 iframe 直接嵌入 PDF 触发浏览器下载的问题
- 支持多页 PDF 逐页渲染,自动适配容器宽度
- 加载失败时显示友好错误提示
- Word (.docx) 文件在线预览(使用 mammoth.js 转换为 HTML)
- 支持标题、段落、表格、图片等元素渲染
- 加载/解析失败时显示友好错误提示
### v3.14.0 (2026-06-19)
- MD 文件渲染为网页格式在线预览
- 引入 marked.js 库,MD 文件在灯箱弹窗中渲染为格式化网页
- 预览区域右上角添加「渲染/源码」切换按钮
- MD 文件默认显示渲染视图,其他文本/代码默认显示源码
- 渲染视图支持标题、列表、代码块、表格、引用、链接、图片等完整 Markdown 语法
- 渲染视图样式美观,与系统主题一致
- PDF 文件保持 iframe 在线预览
### v3.13.2 (2026-06-19)
- 修复 db.json 中缺少上传时间字段的问题
- 新增 `picbed_db_repair()` 自动修复函数
- 每次页面加载时自动检测并补充缺失的 time/size/path/remark 字段
- 从实际文件获取 filemtime 作为上传时间
### v3.13.1 (2026-06-19)
- 修复设置页面未登录时加载动画一直显示不消失的问题
### v3.13.0 (2026-06-19)
- 页面标题统一移到顶部导航栏
- 所有页面去除主体区域的页面标题(如"文件库"、"上传文件"、"系统设置")
- 顶部栏品牌名改为「站点名 - 页面名」格式(如 `PicBed - 文件库`)
- 文件库工具栏布局重构
- 搜索框固定在左侧,排序/布局/管理按钮固定在右侧
- 电脑端:搜索框和按钮在同一行,两端对齐
- 手机端:搜索框独占第一行,按钮在第二行右对齐
- 统计信息(共 X 个文件)移至工具栏上方单独一行
### v3.12.0 (2026-06-19)
- 文件库页面新增搜索功能:支持按文件名和备注关键词搜索
- 搜索框带 350ms 防抖,避免频繁请求
- 搜索结果自动重置到第一页
- 支持清除搜索按钮一键清空
- 上传页面自动提取文件名作为备注
- 仅对非图片文件生效(文档/音频/文本/视频/代码等)
- 单文件选择时自动将文件名(去掉扩展名)填入备注框
- 图片文件不自动填入备注
- 备注框已有内容时不覆盖
### v3.11.0 (2026-06-19)
- 文件库卡片标签显示具体扩展名(如 "文档 DOCX"、"视频 MP4"、"音频 MP3")
- 页脚重构:去除底部栏,改为 flex 布局
- 手机端(<768px):三行显示(版权 / ICP / 公安备案各一行)
- 电脑端:一行显示,自动居中排列
- 版权信息年份自动跟随当前时间(`date('Y')`)
- 版权信息链接跳转到 copyright.gov.cn
- 设置页面版权输入提示优化:只需输入公司名/版权主体
### v3.10.0 (2026-06-18)
- 全面美化 UI 动效
- 音频播放器:圆形图标脉冲动画 + 音频波形条动画 + 渐变背景
- 视频播放器:圆角美化 + 投影效果 + 控制栏渐变背景
- 上传进度条:渐变填充 + 光泽流动动画
- 卡片入场动画(淡入+上浮+缩放弹性效果)
- 卡片悬停:增强阴影 + 边框高亮 + 图片缩放
- 下拉菜单:弹性弹出动画
- Toast 通知:弹性滑入动画
- 模态框:弹性缩放动画
- 关闭按钮:悬停旋转 90 度效果
- 类型标签:滑入动画
- 分页按钮:悬停上浮 + 选中发光
- 空状态图标:上下浮动动画
- 新增骨架屏 shimmer 动画基础样式
### v3.9.0 (2026-06-18)
- 合并 counter.txt 和 total.txt 为 stats.json 统一存储
- 新增 total_size 字段记录占用空间总计
- stats API 直接读取 stats.json,不再遍历 db.json 计算空间
- 上传/删除/替换自动同步占用空间统计
- 自动从旧版 counter.txt/total.txt 迁移到 stats.json
### v3.8.0 (2026-06-18)
- 上传文件支持自定义备注(remark 字段)
- 文件库卡片显示备注标签
- 灯箱弹窗显示文件备注
- info API 返回 remark 字段
- 上传页面增加备注输入框
- 备注存储在 data/db.json 中
### v3.7.3 (2026-06-18)
- 修复 settings.php 文件缺少 `