6.2 KiB
从 sablog 导入
把 SaBlog-X 的内容迁到 LaraBlog:保留文章 / 分类 ID 与内容向 URL,附件进对象存储(或本地磁盘),源库只读、不改源站文件。
命令:php artisan sablog:import
实现:app/Console/Commands/SablogImportCommand.php
回归夹具:tests/fixtures/sablog/(php artisan test --filter=SablogImportTest)
迁什么、不迁什么
源表(默认前缀 sablog_) |
结果 |
|---|---|
users |
保留 userid;密码写入 password_legacy(无盐 MD5);随机 bcrypt 占位;邮箱为空 |
categories |
保留 cid |
articles |
保留 articleid、阅读数、置顶、可见、关闭评论、阅读密码 |
comments |
visible=1 → 已通过,否则待审;不触发评论插件/AI 审核 |
tags + aids |
标签及文章关联 |
links / stylevars |
友情链接、站点片段 |
attachments |
元数据 + 按 --attachments 目录上传;正文仍存引用,不写死 CDN |
trackbacks / trackbacklog / searchindex / sessions |
跳过,只在报告里计数 |
不导入旧 PHP 后台、WAP、Trackback。旧 /admin/*.php 在新站返回 410;新后台是 /admin(Filament)。
导入前
- 目标库已
php artisan migrate(含插件 migration;AppServiceProvider会加载plugins/*/database/migrations)。 - 不要先跑完整
db:seed。 演示种子占用users.id=1、categories.id=1、articles.id=1/2,导入按同 ID upsert 覆盖,还可能留下演示站多出来的行。 - 角色表是空的:导入不会写 Spatie 角色。导入后要自己建
admin并赋给旧站管理员(见文末)。 - 配好附件盘:开发
ATTACHMENTS_DRIVER=local;生产用 S3/R2 等(见 deploy.md)。 - 源库账号建议只读。
源库与附件目录
.env(连接名默认 sablog,见 config/database.php):
SABLOG_DB_DRIVER=mysql
SABLOG_DB_HOST=127.0.0.1
SABLOG_DB_PORT=3306
SABLOG_DB_DATABASE=sablog
SABLOG_DB_USERNAME=readonly
SABLOG_DB_PASSWORD=
SABLOG_DB_CHARSET=utf8mb4
旧库若是 GBK:
SABLOG_DB_CHARSET=gbk
命令里再加 --encoding=gbk 或 --encoding=auto(非合法 UTF-8 时按 GBK 转)。
附件目录必须是绝对路径,且相对路径与表字段 filepath 一致。例如库里是 2020/01/foo.jpg,则文件应在:
/data/sablog/attachments/2020/01/foo.jpg
缩略图字段 thumb_filepath 同样按该根目录拼接;存在则一并上传。
两种正文模式
--mode |
库内正文 | content_format |
附件引用 |
|---|---|---|---|
raw(推荐先跑) |
保持 HTML | html |
原样 [attach=123] |
markdown |
HTML → Markdown | markdown |
改成 attach:123(避免 [] 被 Markdown 吃掉) |
两种模式都不把对象存储 URL 写进正文。前台渲染再变成 /attachment.php?id=123。
不确定旧文 HTML 质量时先 raw,确认站点可访问后再决定是否用 markdown 重导(同 ID upsert,可重跑)。
命令
先连通、只计数(不写目标库、不上传):
php artisan sablog:import --mode=raw --dry-run
正式导入:
php artisan sablog:import \
--mode=raw \
--connection=sablog \
--prefix=sablog_ \
--attachments=/绝对路径/sablog/attachments \
--disk=attachments \
--encoding=auto
| 参数 | 默认 | 说明 |
|---|---|---|
--connection |
sablog |
Laravel 连接名 |
--prefix |
sablog_ |
源表前缀 |
--attachments |
空 | 本地附件根目录;不传则附件记为 missing |
--mode |
raw |
raw | markdown |
--encoding |
auto |
utf8 | gbk | auto |
--disk |
attachments |
目标 disk |
--retry-failed |
关 | 已有 synced_at 的附件默认跳过;打开则重试失败/缺失 |
--dry-run |
关 | 只读源库并打印计数 |
成功后打印一张表:users / categories / articles / comments / tags / links / stylevars / attachments_ok / attachments_missing / attachments_failed / 跳过的 trackback 等。源库与源文件不会被修改。
整次导入包在一个事务里(附件上传在事务内;失败会 warn 并继续记 missing/failed 行)。缺文件不会中断整次导入。
附件补传
第一次没带 --attachments、或路径不对导致 attachments_missing:
php artisan sablog:import --mode=raw --attachments=/正确/路径 --retry-failed
已成功(synced_at 有值)的附件默认不再上传。
导入后:登录与后台
旧站密码是 MD5。导入后:
- 前台
/login.shtml用用户名 + 旧密码可登录;校验成功后升级为 bcrypt,并清空password_legacy。 - Filament
/admin用邮箱登录。导入用户email为空,且没有admin角色,所以要补一步:
php artisan tinker
use App\Models\User;
use Spatie\Permission\Models\Role;
Role::findOrCreate('admin');
Role::findOrCreate('editor');
Role::findOrCreate('member');
$user = User::query()->where('username', '旧站管理员用户名')->first();
$user->forceFill(['email' => 'you@example.com'])->save();
$user->assignRole('admin');
然后打开 /admin,邮箱 + 旧站密码(或升级后的同一密码)。
AI 设置可单独灌,不必跑演示博客种子:
php artisan db:seed --class=Database\\Seeders\\AiSettingsSeeder
导入后检查
- 首页、
/show-{旧文章id}.shtml、/category-{旧分类id}.shtml - 正文图是否经
/attachment.php?id=能打开 - 评论作者、友情链接、站点片段
attachments_missing/attachments_failed是否可接受- 阅读密码文章:前台仍走密码墙(与单篇付费、会员可见互斥,见后台校验)
注意
- 幂等:按原 ID upsert,可重复执行;附件成功过的默认跳过。
- ID 对齐是为了 SEO:不要在导入后再批量改文章 ID。
- 导入用户没有邮箱、没有角色;前台读者用用户名登录即可。
- 插件付费/会员数据不在 sablog 里,导入后如需付费墙,在新后台按篇配置。
- 夹具库仅供测试,不是完整 sablog 结构说明;以你线上表为准。缺表则该项计数为 0,不报错退出。