『建站笔记#4』可迁移图床

cjsy 发布于 6 小时前 11 次阅读


前几篇写 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

两个都不算框架,就是让博客的图少烦一点。迁移的时候改配置,不改正文,这点最重要。

此作者没有提供个人介绍。
最后更新于 2026-09-24