前几篇写 Docker 迁移 WordPress 的时候,图的事就一直烦着。媒体库插进正文的是绝对地址,形如:
文章 HTML
→ https://旧站/wp-content/uploads/2024/06/foo.jpg 换服务器、换域名、整站一迁,文章里的图就死一片。批量替换正文又不敢,文章一多容易误伤。
所以做了个 article-image,想法很简单:正文里只写稳定的逻辑名,图放在哪由配置决定。引用和存储拆成两层:
文章正文(稳定)
article_image.php?res=cover-01
|
| 302(只改配置即可换指向)
v
图床(可拆、可搬、removeable)
wp-content/removeable/article_images/
(可以不在这)
或 https://图床服务器/...
或对象存储 / CDN 用法就是这种,带不带扩展名都行,还有 JSON:
# 不带扩展名:本地有图则自动探测格式
https://你的站点/wp-content/removeable/article_image.php?res=cover-01
# 带扩展名:精确指定格式
https://你的站点/wp-content/removeable/article_image.php?res=cover-01.jpg
# JSON 元数据
https://你的站点/wp-content/removeable/article_image.php?res=cover-01&json 路径里的 removeable 是故意的,意思是这份图床是可拆卸的附属件,不必绑死在 wp-content 下面。配置是独立的 article_image.config.php,我的配置如下:
<?php
/**
* article-image config.
* Edit these values for your own site.
*/
declare(strict_types=1);
return [
// Image files base (redirect target prefix, no trailing slash).
// Same-server example: '/wp-content/removeable/article_images'
// Remote example: 'https://cjsy.cc/wp-content/removeable/article_images'
'base_url' => 'https://cjsy.cc/wp-content/removeable/article_images',
// Local directory (relative to this project) used when check_local = true
// or when auto-detecting the extension.
// Leave '' to use ./article_images next to this script.
'local_dir' => '',
// If true and local files exist, 404 when the image is missing.
// If false, always redirect (WordPress/remote style).
'check_local' => false,
// Allowed image name after ?res=
// cover-01 → auto ext (see allowed_exts / default_ext)
// cover-01.jpg → explicit ext
'key_pattern' => '/^[A-Za-z0-9_-]{1,64}(\.[A-Za-z0-9]{1,8})?$/',
// Extensions we accept. First hit wins when auto-detecting locally.
'allowed_exts' => ['webp', 'jpg', 'jpeg', 'png', 'gif', 'avif'],
// Used when the request has no extension and auto-detect finds nothing
// (typical remote / check_local = false deployment).
'default_ext' => 'webp',
// Show the friendly bilingual notice on bad input
'show_mercy_note' => true,
]; 部署可以整份丢进 WordPress,也可以图床另放一台机器,只把两个 PHP 留在站里。方式 A(放在站点内)目录大致是:
/wp-content/removeable/article_image.php
/wp-content/removeable/article_image.config.php
/wp-content/removeable/article_images/cover-01.jpg
/wp-content/removeable/article_images/cover-02.png 方式 B(图床在另一台服务器)正文写法完全不用变,只改配置:
'base_url' => 'https://img.example.com/article_images',
'check_local' => false, 以后图床再搬家,仍然只改 base_url。整站迁移的时候:搬走 article_images/(或传到新图床)→ 新环境放两个 PHP → 改 base_url(需要时再改 local_dir)→ 不用批量替换文章。具体请参考仓库 README:https://github.com/Lossalt/article-image(设计说明在 docs: explain removable image-bed design intent,2ec9ee4)。
实现上的细节:白名单校验,免得变成任意文件读取;支持 webp / jpg / jpeg / png / gif / avif;配置文件故意叫 article_image.config.php,防和别的插件撞名。初版是 AI 写的,白名单和撞名是它提的,我一开始只想能按逻辑名出图就行。
还有一个 random-img,管随机出图,侧栏背景用。原先手滑打成 ramdom-img,GitHub 上改过来了。接口大概这几个:
https://your-domain/pc.php
https://your-domain/mobile.php
# ?serve 直出图片,?json 给程序用
https://your-domain/pc.php?serve
https://your-domain/pc.php?json JSON 返回示例:
{
"url": "pc/12.webp",
"source": "local",
"device": "pc",
"total": 197,
"file": "12.webp"
} 部署最省事是整仓 clone 到网站根目录,脚本会扫 pc/*.webp、mobile/*.webp,加图删图不用改代码。没有本地图片目录时会自动跳 GitHub raw。Nginx 配置如下:
server {
listen 80;
server_name img.example.com;
root /var/www/random-img;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
} 跟可搬迁图床一个道理:别把存储写死,开发读本地,上线可以指 GitHub。具体请参考:https://github.com/Lossalt/random-img
两个都不算框架,就是让博客的图少烦一点。迁移的时候改配置,不改正文,这点最重要。

Comments NOTHING