Watermark 2.0:真正保护 Typecho 原图的水印插件
我最近基于旧版 Typecho Watermark 插件重构了一个 2.0.0 版本。
独立仓库位于:https://github.com/NHPT/Watermark
社区仓库位于:https://github.com/typecho-fans/plugins/tree/master/Watermark
在把 Typecho 升级到 1.3 版本后,我发现插件在这个版本存在一些问题,并且我发现插件只支持动态水印,可以通过访问解码后的地址获取无水印图片,且缺少很多我想要的功能。我觉得应该增加一个保护原图的功能:让公开目录里只保留水印成品,把原图保存到 Web 根目录外。在修复、优化的过程中,我发现改动挺大了,不如重构一个版本把。
实际效果可以在我的博客看到。
优缺点
我之前使用过的水印插件有两类:
- 直接覆盖原图。优点是公开目录里确实只剩水印图;缺点是如果没有可靠备份,原图可能无法恢复,而且容易出现重复加水印。
- 动态水印。优点是改动小,关闭插件后影响少;缺点是原图仍然公开,不能阻止别人直接访问上传目录里的原图。
Watermark 2.0.0 采用的是折中但更稳的方式。它的优点是:
- 支持动态模式和原图保护模式;
- 支持图片/文字水印、单点/平铺、旋转、透明度、尺寸过滤、路径排除、静态缓存;
- 原图不再放在 Web 可访问目录;
- 公开路径继续可用,不需要改文章内容;
- 支持新上传图片自动处理;
- 支持历史图片批量迁移;
- 支持从私有目录恢复公开原图;
- 通过元数据避免重复加水印;
- 目录、权限和
open_basedir问题会在后台提示; - 批量任务支持自动分批、暂停继续、失败重试。
它的缺点也需要提前说清楚:
- 必须有 GD 扩展;
- 服务器必须允许 PHP 写入私有原图目录;
- 首次迁移大量历史图片需要时间;
- 私有原图目录必须长期备份;
如果只是想让文章图片“显示时带水印”,动态模式够用;如果想避免公开路径直接暴露无水印原图,就应该使用原图保护模式。
核心亮点
1. 原图保护模式
启用原图保护后,插件会把无水印原图保存到站点根目录之外,例如:/path/to/.typecho-watermark/。
公开目录 usr/uploads 中保留的是水印成品。文章里的图片路径不用改,访客访问到的仍然是原来的公开路径,但文件内容已经是带水印版本。私有目录非常重要。它保存的是唯一可恢复的无水印版本,不能删除、清空、覆盖,也不应该放在临时目录里。
2. 历史图片迁移
新上传和替换的图片可以立即处理,但老站点通常已经有大量历史图片。Watermark 2.0.0 提供两种处理方式:
- 正文中的历史图片首次访问时自动懒迁移;
- 后台执行“迁移或重新生成现有图片”,集中扫描并处理
usr/uploads。
后台批量迁移不限于正文引用图片,也会处理上传目录里的其他图片,因此更适合老站点升级。
3. 自动分批处理
图片处理不能一次请求跑完,尤其是站点图片很多时,很容易超时。所以插件采用“前端自动连续请求 + 服务端分批处理”的方式,每批最多处理 20 张。管理员点击一次即可开始,页面会自动续批,并显示:
- 候选图片数量;
- 已完成;
- 待处理;
- 失败;
- 当前处理阶段。
任务支持暂停、继续、失败项重试和关闭弹窗后续传。首次扫描和每批处理时也会显示 loading 和阶段说明,避免长时间白屏。
4. 防止重复加水印
重复加水印是水印插件很常见的问题。Watermark 2.0.0 会记录原图、水印图和当前配置的 SHA-256 指纹。只要图片已经是当前配置生成的水印图,就不会重复处理;如果水印配置变了,会从私有原图重新生成,而不是拿已经带水印的公开图继续叠加。
5. 可恢复、可迁移
启用原图保护后,如果以后想退出,可以在后台执行“恢复公开原图”。插件会从私有目录把无水印原图恢复到 usr/uploads。如果需要更换私有原图目录,插件提供“安全迁移私有目录”,会分批复制、校验 SHA-256,全部通过后才切换配置,旧目录会保留用于回滚。这两个功能是我认为很重要的安全边界:插件不能只会“保护”,还必须能让用户安全退出。
如何使用
推荐从 Release 下载:https://github.com/NHPT/Watermark/releases
安装步骤:
- 下载
Watermark.zip。 - 解压到 Typecho 的
usr/plugins/,最终目录应为usr/plugins/Watermark/。 - 在 Typecho 后台启用插件。
- 进入插件设置,选择水印类型、位置、透明度、平铺、旋转等参数。
- 如果只需要展示水印,保持动态模式即可。
- 如果要保护原图,切换到“原图保护模式”,并确认私有目录校验成功。
- 对已有站点执行“迁移或重新生成现有图片”。
从 1.x 升级到 2.0.0 时,建议先截图或记录旧设置。旧版本没有自动备份和恢复配置功能,而 Typecho 停用插件时会删除普通插件配置。停用或删除插件不会自动恢复原图,也不会删除私有目录。
设计流程
这次重构是从一个实际问题开始的:文章里看到的是水印图,但公开上传路径仍然能访问原图。所以我先把目标拆成几个问题:
- 原图应该放在哪里,才能避免 Web 直接访问?
- 公开路径如何继续兼容已有文章?
- 历史图片如何迁移?
- 如何避免重复加水印?
- 用户如何恢复原图?
- 目录权限、
open_basedir、批量超时这些部署问题如何处理?
最终代码大致分成三块:
Protection.php:负责私有原图存储、元数据、状态识别、恢复和目录迁移。Plugin.php:负责 Typecho 钩子、设置页、上传/替换/删除处理、内容图片改写。Action.php:负责动态图片输出、首次访问懒迁移、后台批量迁移、恢复和目录迁移任务。
渲染器 class.php 也做了增强,支持只保存不输出、失败回滚、确认水印确实被绘制,避免批量任务中把坏结果写入公开目录。
开发完成后做过 PHP 7.4 到 8.5、GD 生命周期、原图保护、恢复、目录迁移、open_basedir、批量任务、暂停续传、失败重试和大批量图片场景测试。
适合谁
我建议下面这类 Typecho 用户使用 Watermark 2.0.0:
- 站点有较多原创图片;
- 不希望别人直接拿到无水印原图;
- 希望公开图片路径保持不变;
- 希望历史图片可以批量迁移;
- 希望以后还能恢复原图;
- 希望插件停用、升级、重装后还能找回原图关系。
最后更新于 2026-08-26 「部分内容存在时效性,如有失效请留言反馈」
除注明外为 Hack All Sec 的博客 原创文章,转载请注明出处。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
Hack All Sec 的博客