PictShare 介绍与选型指南
说清 PictShare 的定位、架构与功能边界,并与同类自托管图床/文件分享工具量化对比,帮助判断是否值得引入。
PictShare 介绍与选型指南
目标:说清 PictShare 是什么、解决什么问题、架构与功能边界如何,以及与同类自托管图床/文件分享工具的量化对比,帮助读者判断是否值得引入。基于官方仓库 HaschekSolutions/PictShare 与官方镜像实查(版本 3.7.5,查询日期 2026-10-30),并在 Ubuntu 22.04 服务器上以官方 Docker 镜像完成部署与功能实测(部署过程见《PictShare 3.7.5 Docker Compose 部署指南》https://www.quzuo.net/document/ILUkOrJVYiZD )。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64,内核 5.15+)
- 软件版本:PictShare 3.7.5(官方最新稳定版 tag
v3.7.5,镜像 3.7.5 于 2026-10-27 推送,来源官方仓库 tags 与 Docker Hub 实查,查询日期 2026-10-30) - 社区活跃度:GitHub 星数 951、复刻数 137(shields.io 实查,查询日期 2026-10-30)
- 开源许可:Apache License 2.0
- 技术栈:PHP 8.4 + FrankenPHP(Caddy 内嵌 PHP)、内置 Redis(URL→文件映射缓存)、ffmpeg(音视频转码)
- 官方镜像:
hascheksolutions/pictshare(Docker Hub)与ghcr.io/hascheksolutions/pictshare(GHCR) - 实测环境:单机 Docker Compose 部署,Web 端口 8131,自定义 bridge 子网 10.89.59.0/24
二、软件概述
2.1 项目定位
PictShare 是 Haschek Solutions 开源的自托管多媒体托管服务(self-hosted media hosting),口号是「Host your own images, gifs, mp4s, text bins and stay in control」。它把图片、GIF 动图、MP4 视频、音频、文本片段(pastebin)统一托管在自己的域名下,核心卖点是三点:
- 纯文件存储、零数据库:所有上传内容以内容寻址(SHA1 摘要)方式落盘为目录与文件,元数据存每个文件旁的
meta.json,部署与备份只需要拷目录; - URL 即变换:缩放、旋转、滤镜、格式转换全部通过改 URL 路径实现(如
/300x200/hash.png),无需预生成多种尺寸; - 隐私友好:上传时自动清除 EXIF(GPS 位置、相机型号等),重复文件自动去重不占额外空间。
项目自 2013 年前后起步(v1/v2 以传统 PHP+Nginx 形态运行),2025 年起发布的 v3 从零重构:API 全面转向 RESTful 风格、镜像底座换成 FrankenPHP(Caddy 内嵌 PHP,无需 Nginx+php-fpm 双进程)、内置 Redis 缓存、新增相册/文本仓/URL 缩短/MCP 端点等能力。官方明确提示 v3 与旧版不完全兼容(配置项 TITLE、UPLOAD_FORM_LOCATION、ALLOW_BLOATING 曾被移除后又部分回归,文件名必须位于 URL 末段等破坏性变更)。
2.2 解决的核心痛点
- 团队/个人需要把截图、录屏、动图快速变成可外链 URL,又不想把数据交给第三方图床(Imgur 等);
- 论坛、Wiki、IM 中贴图需要稳定的直链与按需缩略图,而不想为每种尺寸各传一份;
- 手机照片直传后担心 EXIF 泄露位置信息;
- 需要一次性、可删除、可审计的临时文件分享出口。
💡 技术拓展:自托管「图床/文件分享」类工具按内容生命周期可分三类——① 永久图床(Chevereto、PictShare、Zipline):文件长期保留,靠管理端与删除码治理;② 一次性/阅后即焚(Jirafeau、goploader、0x0):下载一次或到期自动销毁,适合敏感文件;③ 对象存储直传(MinIO+预签名 URL、S3):无 UI、纯 API,适合程序集成。PictShare 属第一类并带部分第二类特征(每个文件有独立删除码,可随时销毁),适合作为团队的常驻外链服务。
三、核心架构
3.1 单容器多组件架构
PictShare 3.x 官方镜像基于 dunglas/frankenphp:php8.4-alpine 构建,一个容器内集成四个组件:
| 组件 | 角色 | 说明 |
|---|---|---|
| FrankenPHP/Caddy | Web 服务器 + PHP 运行时 | Caddy 直接内嵌 PHP 解释器(php_server),监听 80 端口,无 Nginx+php-fpm 两段式 |
| PHP 8.4 应用 | 业务逻辑 | 内容控制器(按 MIME 分流)+ 存储控制器(按位置分流)双插件体系 |
| Redis | URL→文件映射缓存 | 容器内以 unix socket /run/redis/redis.sock 运行,缓存 cache:byurl:*、lastaccessed:*、served:* 等键,关掉会显著变慢 |
| ffmpeg | 音视频转码 | GIF→MP4 转码、MP4 缩放、预览帧生成(实测产物 h264 编码) |
配置在容器启动时由 /etc/start.sh 从环境变量生成 src/inc/config.inc.php(define('KEY', value) 形式),改配置即改环境变量后重启容器,无独立配置文件需要维护(参数全表见《PictShare 3.7.5 配置参数详解》https://www.quzuo.net/document/K2LlXSHlRiG6 )。
3.2 内容寻址存储模型
上传文件按「哈希目录」落盘,实测 data/ 目录结构:
data/
├── mrokk1.png/ # 一个上传文件一个目录(目录名=对外 hash)
│ ├── mrokk1.png # 原始文件
│ ├── 9d4e826c..._mrokk1.png # 变换产物(md5 前缀_原名,如缩放/滤镜版本)
│ └── meta.json # 元数据:mime、大小、sha1、上传时间、IP、删除码
├── sha1.csv # sha1 → hash 映射,用于去重判断
└── naughty.csv # 已删除文件黑名单(v3.7.5 实测为空,见 3.3 限制)
特点(均实测验证):
- 去重:同一文件重复上传返回相同 hash 与
"duplicate": true,服务器只存一份(依赖sha1.csv判断); - 变换即新文件:
/300x200/hash.png的结果以300_hash.png形态缓存在原 hash 目录下,再次访问直接命中; - 无数据库:备份 = 拷贝
data/目录,迁移 = 拷贝 + 改URL环境变量。
3.3 内容控制器与存储控制器
- 内容控制器(按 MIME 决定「怎么处理」):IMAGE、SVG、TEXT、VIDEO、URL、HTML(危险,默认关)、MARKDOWN、IDENTICON(字符串生成识别图)、PLACEHOLDER(按尺寸生成占位图)、AUDIO。可用
CONTENTCONTROLLERS白名单收缩(实测设置IMAGE,VIDEO后文本上传被拒)。 - 存储控制器(按位置决定「存哪里」):本地 + 可选 ALT_FOLDER(NFS 双写)、S3 兼容(MinIO/Garage/AWS)、FTP/FTPS,外部存储可配
ENCRYPTION_KEY做 XChaCha20 加密;本地未命中时自动到外部存储回源取回并伺服。 - 维护 CLI:镜像内置
tools/下 6 个 PHP CLI 脚本(cron.php 的 uploadqueue/flushviews 子命令、ffmpeg_worker.php 转码队列等),供定时任务与排障使用。
3.4 已知限制(v3.7.5 实测)
- README 宣称的 Markdown 渲染:实测
.md文件按text/plain入库走文本仓(<pre><code>展示),未触发独立 Markdown 渲染管线; - 删除文件不写
naughty.csv黑名单(源码deleteHash内有@todo: add hash to deleted list),删除后同内容重传会得到新 hash,不会被拦截; - 已删除文件的 URL 访问结果分两种(实测):删除前从未被访问过的文件 URL 立即 404;删除前被访问过(Redis 已缓存 URL 映射)的文件 URL 继续返回 200 但内容为空壳(1 字节空 body),做监控探测时判据用
GET /api/info/<hash>(返回Hash not found即已删除); - URL 抓取上传(
/api/upload?url=)带 SSRF 防护:目标为私网 IP 时直接拒绝(实测返回Private IP range); - 无多用户/账号体系:没有登录与个人空间,治理靠 UPLOAD_CODE 上传口令、删除码与管理端(
/admin,ADMIN_PASSWORD控制)。
四、功能特性
以下特性均在 3.7.5 实测环境中逐项验证(完整命令与回显见《PictShare 3.7.5 URL 参数与 HTTP API 详解》https://www.quzuo.net/document/hepbPtXpdr8g ):
| 功能 | 说明 | 实测结果 |
|---|---|---|
| 多格式上传 | JPG/PNG/WebP/GIF/MP4/MP3/文本等 | PNG/JPG/GIF/MP4 上传均返回 JSON(hash/url/delete_code) |
| URL 即缩放 | /300x200/hash.png | 800×600 原图缩放为 300×225(等比缩放,取宽定高) |
| URL 即旋转 | `/left | right |
| 图像滤镜 | gray/sepia/pixelate/blur 等 30+ | gray、pixelate_10 返回 200 且体积变化 |
| 格式转换 | /webp/hash.jpg、JPG/PNG→WebP | 返回 WEBP (800,600) |
| GIF→MP4 | /mp4/hash.gif | ffmpeg 转码 h264,播放器页 + /raw 直流 |
| 视频缩放 | /320x180/hash.mp4 | 产物 320×180 h264,poster 预览帧 JPEG 320×180 |
| 文本仓 | 任意文本上传为 .txt | 直链返回渲染页,/hash.txt/raw 取原文 |
| EXIF 清除 | 上传时剥离元数据 | 官方特性,phone 照片 GPS/机型被清 |
| 去重 | SHA1 内容寻址 | 重复上传返回 "duplicate": true |
| 相册 | 多 hash 组合成不可变画廊 URL | POST /api/album 返回 058zu99c.album |
| 删除码 | 每文件独立 32 位删除码 | 错误码拒绝 Invalid delete code,正确码删除成功 |
| 上传口令 | UPLOAD_CODE 全局上传口令 | 无码/错码返回 Access denied,对码成功 |
| 私网白名单 | ALLOWED_SUBNET CIDR 限制上传与 admin | 生效值实测写回 config.inc.php |
| 管理端 | /admin 统计与日志页 | ADMIN_PASSWORD 认证后显示 Stats 页 |
| identicon/占位图 | /identicon/字符串、/placeholder/555x250/... | 返回 SVG 与 JPEG (555,250) |
| MCP 端点 | POST /mcp 供 LLM 代理调用 | initialize 握手返回 serverInfo PictShare 1.0.0 |
五、快速开始(最小可用示例)
5.1 一行启动
docker run -d -p 8080:80 -e "URL=http://<服务器IP>:8080/" hascheksolutions/pictshare:3.7.5
浏览器打开 http://<服务器IP>:8080/ 即是拖拽上传页。URL 必填且以斜杠结尾,它决定上传结果 JSON 里返回的外链前缀。
5.2 命令行上传与外链访问(实测回显)
curl -s -F "file=@test.png" http://127.0.0.1:8080/api/upload
{
"status": "ok",
"hash": "mrokk1.png",
"filetype": "image\/png",
"url": "http:\/\/192.168.146.128:8131\/mrokk1.png",
"delete_code": "pj6q3f3i9awmp6kx7hyjt2y5idjnzhda",
"delete_url": "http:\/\/192.168.146.128:8131\/delete_pj6q3f3i9awmp6kx7hyjt2y5idjnzhda\/mrokk1.png"
}
拿到 url 后即可外链引用;在域名后拼变换参数得到衍生版本:
curl -sI http://127.0.0.1:8131/300x200/mrokk1.png | grep -iE 'HTTP|content-type'
HTTP/1.1 200 OK
Content-Type: image/png
六、适用场景与限制
6.1 适合的场景
- 团队内网图床/截图外链:配合截图工具与
curl别名,拖拽或命令行即得外链,EXIF 自动清除; - 内容站点配图 CDN 前置:URL 即缩放/转 WebP,前端按需引用不同尺寸,省去预裁剪流水线;
- 临时素材与文本分享:文本仓 + 独立删除码,分享完即可销毁;
- LLM 代理集成:内置 MCP 端点,Claude Code 等 Agent 可直接
upload_from_url/get_file_info/create_album。
6.2 不适合的场景
- 需要多用户注册、空间配额、相册权限管理的「社区图床」(选 Chevereto);
- 强合规的一次性机密文件交换(选 Jirafeau/goploader,阅后即焚语义更明确);
- 海量对象存储场景直接当存储层用(PictShare 定位是伺服层,外部存储仅作回源/双写)。
七、同类选型对比
| 维度 | PictShare 3.7.5 | Chevereto | Jirafeau 4.7.2 | goploader 1.0.2 | Zipline |
|---|---|---|---|---|---|
| 语言/运行时 | PHP 8.4 + FrankenPHP | PHP + MariaDB | PHP(无数据库) | Go(服务端+客户端) | Node.js |
| 存储 | 纯文件(可选 S3/FTP/NFS 双写+加密) | 文件 + 数据库 | 纯文件 | 纯文件 | 数据库 + 文件/S3 |
| 视频托管/转码 | ✅ MP4 缩放、GIF→MP4(ffmpeg) | ✅(商业版更强) | ❌ 仅文件托管 | ❌ | ✅ |
| URL 即变换(缩放/滤镜/转码) | ✅ 核心特色,30+ 滤镜 | ❌ 需预生成 | ❌ | ❌ | 部分 |
| 去重 | ✅ SHA1 自动去重 | ❌ | ❌ | ❌ | ❌ |
| EXIF 清除 | ✅ 自动 | ✅ | ❌ | ❌ | 可选 |
| 一次性/过期删除 | ❌(仅手动删除码) | ❌ | ✅ 到期自毁 | ✅ 一次性链接 | ❌ |
| 多用户体系 | ❌ | ✅ 完善 | ❌ | ❌ | ✅ |
| REST API | ✅ RESTful + MCP | ✅ | 脚本端点 | ✅ CLI 优先 | ✅ |
| 星数(2026-10-30 实查) | 951 | ~4k | ~1.3k | ~0.4k | ~2.5k |
选型解读:要「改 URL 就能缩放/转码 + 零数据库运维」选 PictShare;要完整多用户图床社区选 Chevereto;要阅后即焚的一次性分享选 Jirafeau 或 goploader(两者在本平台另有专栏实测:Jirafeau 见 https://www.quzuo.net/document/9M8Fmc0Fcj39 、goploader 见 https://www.quzuo.net/document/I0STQ0XFyGOQ)。
⚠️ 注意:上表星数为 2026-10-30 经 shields.io 实查的瞬时值,仅反映相对热度,选型时建议以当时实查为准。
八、参考链接
- 官方仓库:https://github.com/HaschekSolutions/PictShare(v3.7.5,查询日期 2026-10-30)
- 官方配置手册:https://github.com/HaschekSolutions/PictShare/blob/master/rtfm/CONFIG.md
- 官方 API 手册:https://github.com/HaschekSolutions/PictShare/blob/master/rtfm/API.md
- 官方 Docker 镜像:https://hub.docker.com/r/hascheksolutions/pictshare
- 官网演示:https://pictshare.net
- 本专栏系列:《PictShare 3.7.5 Docker Compose 部署指南》(https://www.quzuo.net/document/ILUkOrJVYiZD)、《PictShare 3.7.5 配置参数详解》(https://www.quzuo.net/document/K2LlXSHlRiG6)、《PictShare 3.7.5 URL 参数与 HTTP API 详解》(https://www.quzuo.net/document/hepbPtXpdr8g)。