LM 远程图片本地化 X5 — Discuz! 外链图片转附件插件

插件标识:lm_remotepic
版本:1.1.0
适用 Discuz! 版本:X5.0 及以上
适用 PHP 版本:PHP 8.0+(使用 str_starts_with / str_ends_with / 空合并赋值运算符等新语法)
开发者:落寞(QQ 7419838)
官方站点:www.cnlog.cc

一、插件简介

LM 远程图片本地化 X5 是一款专为 Discuz! X5.0 开发的外链图片自动本地化插件。当用户发帖、回复或编辑帖子时,插件会自动检测帖子内容中的 [img]远程地址[/img] 标签,将图片下载到本站服务器并登记为论坛附件,随后把原帖中的外链替换为 [attachimg]aid[/attachimg] 格式。

这样做的好处是:无论原图站是否倒闭、是否开启防盗链、是否调整了图片路径,论坛内的图片都能稳定显示,不会出现红叉或 404 失效。

Discuz 远程图片本地化

二、核心功能

  • 发帖 / 回复 / 编辑三端全覆盖:所有带合法 formhash 的真实提交请求都会触发处理。
  • 两种运行模式:
    • 自动模式(推荐,零模板改动):默认模式,提交时直接处理,自定义模板也能用。
    • 用户勾选模式:在发帖页显示复选框,由用户自行决定,需模板包含 {hook/post_middle} 等输出位。
  • 支持多种图片标签:[img]url[/img]、[img=宽x高]url[/img],可选开启 HTML <img src=""> 标签处理。
  • 不新建任何数据表:完全复用 Discuz! 核心的 forum_attachment、forum_attachment_unused、discuz_upload、getattachnewaid()、updateattach(),卸载零残留。

三、SSR F 防护机制(重点)

插件在下载图片前进行了层层递进的安全校验,彻底堵死 SSRF 攻击路径:

  1. 协议限制:只允许 http 和 https,拒绝 file://、gopher:// 等危险协议。
  2. 端口限制:只允许 80、443、8080、8443 四个常见端口,其它一律拦截。
  3. DNS 预解析:先做 DNS 解析拿到真实 IP,再判断是否为内网 / 保留地址。
  4. 内网 IP 段拦截:拦截 127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、100.64.0.0/10(运营商级 NAT)、169.254.0.0/16、198.18.0.0/15 等所有保留地址段。
  5. 特殊后缀拦截:localhost、.local、.internal、.localhost 后缀域名一律拒绝。
  6. 必须带合法 formhash,且必须是真实的 topicsubmit / replysubmit / editsubmit 提交请求。
  7. 按真实图片内容校验类型:下载后用 getimagesize() 嗅探,不信任 URL 里的扩展名,非真实图片直接删除不留垃圾。
  8. 最小宽度过滤:小于设定宽度的图片(表情、计数像素等)自动跳过。

四、请求级预算保护(防超时白屏)

为了避免一次发帖抓取过多图片导致 PHP 超时白屏或 残留未使用附件,插件内置了三级预算:

  • 时间预算:单次请求内累计抓取耗时 不超过 20 秒。
  • 体积预算:单次请求内累计下载的图片总大小 不超过 16 MB。
  • 张数上限:单帖最多处理 20 张(后台可调整,上限 100)。

任意一项超出预算即停止后续图片下载,已成功下载的图片不受影响,保证发帖流程不被拖死。

五、后台配置项一览

配置项 类型 默认值 说明
总开关 单选 开启 关闭后插件完全不工作
运行模式 下拉 自动 自动本地化 / 用户勾选复选框
复选框默认选中 单选 是 仅勾选模式生效
允许的用户组 ID 文本 留空 逗号分隔,留空不限制
允许的版块 fid 文本 留空 逗号分隔,留空所有版块
排除域名 多行文本 留空 每行或逗号分隔,本站自动排除
单张图片最大体积 数字 2048 KB 超过则跳过
单帖最多处理张数 数字 20 上限 100
下载超时 数字 10 秒 范围 3 - 30 秒
最小图片宽度 数字 0 小于该宽度跳过,0 不限制
处理 <img src> 标签 单选 关闭 站点开启 HTML 时才有意义
跳过带 ? 参数的图片 单选 关闭 含查询字符串的 URL 不下载
记录运行日志 单选 关闭 写入 data/log/lm_remotepic_年月.log

六、环境自检页面

插件后台内置了一键环境自检,可快速排查部署问题:

  • Discuz! 版本是否为 X5.0 系列
  • discuz_upload 核心类文件是否存在
  • getattachnewaid() 附件分配函数是否可用
  • dfsockopen() 远程抓取函数是否可用
  • forum_attachment_unused 表类文件是否存在
  • 附件目录和日志目录是否可写
  • 插件开关状态、当前运行模式、各项限制参数

七、与 Discuz! 核心的协作(重点)

插件的设计哲学是 "尽量不重复造轮子",而是完整嵌入 Discuz! X5.0 的原生附件流程:

  1. 用 dfsockopen() 下载远程图片内容(核心自带函数)。
  2. 用 discuz_upload 类计算目标存储目录和文件名。
  3. 用 getattachnewaid() 向核心申请新的附件 ID。
  4. 写入 forum_attachment_unused 表,标记为"未使用附件"。
  5. 把 aid 加入 $_GET['attachnew'] 数组,后续由核心 updateattach() 自动完成绑定、缩略图生成、水印打标、FTP 远程存储等全套流程。

这意味着插件下载的图片 自动享受 Discuz! 核心的所有配置:水印、缩略图、附件分表、FTP/SFTP/OSS 远程存储……不需要在插件内重复实现一次。

八、更新记录

v1.1.0(2026-11-07)

  • 新增 「关于插件」页:开发者信息与更新记录
  • 后台自检改用文件存在性判断,修复后台未加载 discuz_upload 类时的误报
  • 新增 请求级预算(20 秒 / 16 MB),避免多图抓取超时导致白屏与残留未使用附件
  • 日志内容过滤换行符,防止伪造日志行
  • 修正非 UTF-8 帖子内容触发的正则告警
  • 加固 attachnew 参数类型判断

v1.0.0(2026-11-07)

  • 首个版本:发帖 / 回复 / 编辑提交时自动把 [img] 外链图片转为本站附件
  • 支持自动模式(零模板改动)与用户勾选模式
  • SSRF 防护:协议 / 端口 / DNS 预解析拦截内网与保留地址
  • 按真实图片内容校验类型,不信任 URL 扩展名
  • 单图体积、单帖张数、超时、最小宽度四重限制
  • 复用核心 discuz_upload / getattachnewaid / forum_attachment_unused / updateattach,不新建数据表
  • 水印、缩略图、附件分表由论坛核心统一处理

九、技术支持

使用问题请通过 QQ(7419838)反馈,并附上以下信息以便快速定位:

  • Discuz! 完整版本号
  • 插件版本号
  • PHP 版本
  • 报错截图
  • 后台开启「记录日志」后,data/log/lm_remotepic_年月.log 的日志内容

测试使用  https://bbs.cnzv.cc/

© 落寞 · www.cnlog.cc · 未经许可不得二次分发、转售