造了个 Typora 图片上传的轮子。我目前用的"图床"就是 Nginx 自带的静态文件路由,因此想简化下上传的流程,免得每次都要手动把文件放到服务器的指定目录,太麻烦了。
由于Typora支持用脚本自定义上传图片的过程(官方说明:https://support.typora.io/Upload-Image/#custom),因此这个工程可分为两部分:Web端的PHP文件保存,以及本地的Python上传。
既然搭建好了那当然要测试一下,使用效果:(小坑,源代码模式不支持拖放插入图片)

(似乎有些异样)
Web 端
- upload.php
<?php
const TOKEN = '预设的Token,用于鉴权';
if(!hash_equals($_GET['token'],TOKEN)){
http_response_code(403);
die('Invalid token');
}
$img = $_FILES['img'];
$ext = end(explode('.',$img['name']));
$path = $img['tmp_name'];
$err = $img['error'];
if($path==null){
http_response_code(400);
die('Unable to get file');
}
if($err!==0){
http_response_code(500);
die("Upload error with code {$err}");
}
// 设置时区
date_default_timezone_set("Asia/Shanghai");
// 格式化文件名,格式"yymmdd-0123456789abcdef.ext"
// 后面的16位hex是文件哈希
$fmtName = date('ymd').'-'.substr(hash_file('sha256',$path),0,16).".{$ext}";
// 移动临时文件到指定路径
move_uploaded_file($path,"./img/{$fmtName}");
echo $fmtName;
- * img.php 可有可无,放在博客的目录下,用于重定向,这样万一需要迁移图床只需要更改这个文件即可,否则要修改MarkDown文件中所有图片的URL。
<?php
$picName = $_GET['p'];
if(!isset($picName)){
http_response_code(404);
die('Undefined image name');
}
header('Location: https://file.icyu.me:41259/img/'.$picName);
本地上传
- typora_img_upload.py
#!/bin/python3
import sys
import requests
TOKEN = '和服务端一致的鉴权Token'
# 上面的PHP文件所在URL
UPLOAD_URL = f'https://file.icyu.me:41259/upload.php?token={TOKEN}'
# 由于我用了重定向,MarkDown文件内嵌的URL指向了图片实际URL,因此需要转换
FINAL_PATH = 'https://blog.icyu.me/usr/img.php?p={}'
# 调用上传脚本时,Typora将会以命令行参数的形式传入本地图片的绝对路径。
for file in sys.argv[1:]:
r = requests.post(UPLOAD_URL,files={'img':open(file,'rb')})
if r.status_code!=200:
sys.exit(1)
name = r.text
# 输出已上传图片的URL,注意应以"http(s)://"或"file://"开头
print(FINAL_PATH.format(name))
Typora 配置
(Windows 端,不知道是否通用)文件 -> 偏好设置 -> 图像 -> 上传服务,设置为Custom Command,然后下面填写脚本位置即可。点击验证图片上传选项可以测试配置是否成功。
格式 -> 图像 ,可选择上传全部本地图片。
Nginx 和 PHP 配置
Nginx 默认文件上限为1M,PHP-fpm 默认为2M,一张图片很容易超过这个限制,因此需要修改配置文件。
Nginx:在http配置里,将client_max_body_size设置为更大的值,如“20M”。
PHP:更改php.ini(注意版本,以及注意是fpm,不是cgi / cli),将upload_max_filesize修改为更大的值。