【Typecho插件】MyUpload - 图片压缩上传插件,支持TinyPNG!

MyUpload

Typecho图片压缩上传插件,支持本地压缩和 TinyPNG 远程压缩。

插件地址:jlice/typecho-MyUpload: 🖼️Typecho图片压缩上传插件

使用方法

下载压缩包,将MyUpload文件夹上传到你的博客的usr/plugins/目录下,在后台启用,然后在插件设置里根据自己的需求设置插件:

如果是云主机,须安装jpegoptimpngquant

Ubuntu系统下安装方法:

$ sudo apt install jpegoptim pngquant

如果是虚拟主机,可以采用远程压缩,须先到https://tinypng.com/developers注册一个 API Key:

图片远程压缩速度很慢,请耐心等待(有可能超时导致压缩失败)。

说明

写博客时,如果不压缩图片,既比较费主机存储空间,还会非常拖慢页面加载速度,特别是对于带宽小的主机。可是,如果要压缩好图片后再上传又比较麻烦,放到对象存储上还另外要钱。于是乎,就撸了这个插件,在上传时自动压缩图片。压缩图片采用的方法是调用jpegoptim压缩 jpg 图片,调用pngquant压缩 png 图片,我觉得压缩效果挺好的,可以基本不降低清晰度且大幅降低图片占用空间。

UPDATE1:由于部分人反映希望能支持虚拟主机,那就加上远程压缩的功能吧,使用 TinyPNG 远程图片压缩服务,一个月免费压缩500张,应该是够用的。

除此之外,由于Typecho默认的图片重命名方式理论上可能出现重名覆盖,而且个人觉得把图片按月分文件夹有点麻烦,喜欢按年分文件夹。因此,对图片的重命名方式做了修改,不会出现重名覆盖,并且图片文件名也还是很短的,图片可以按年分文件夹,也按月分文件夹(和Typecho默认一样)。当然,这个需求比较小众,默认是保持Typecho默认的方式。

v1.5 开发笔记

本次增加了 TinyPNG 远程压缩服务,官网:TinyPNG – Compress PNG images while preserving transparency

API 文档:TinyPNG – API Reference

TinyPNG 采用 HTTP Basic Auth 做授权认证,还是非常简单的。只要把api:YOUR_API_KEY做一个Base64转换(假设为BASE64_KEY),然后在请求头设置AuthorizationBasic BASE64_KEY就可以了。

例如,假设YOUR_API_KEY是TuqxTXbr6NH3k4NptoqRpqcVXaJRbWSf(我随机生成的),进行Base64转换时注意别带上结尾的换行了,用 Shell 可以这么转换:

$ echo -n api:TuqxTXbr6NH3k4NptoqRpqcVXaJRbWSf | base64

-n参数就是不带结尾的换行。在 PHP 里的转换方法:

$apiKey = 'TuqxTXbr6NH3k4NptoqRpqcVXaJRbWSf';
$token = base64_encode('api:' . $apiKey);

另外,Typecho封装了一个 HTTP 客户端,也就是Typecho_Http_Client,支持curlfsockopen

另外,还参考了PHP: POST 方法上传 - Manual,PHP 毕竟是最好的语言,对于文件上传还专门有个$_FILES全局变量。

v1.2 开发笔记

几个月前从Hexo迁移到Typecho时就写了这个插件,由于懒癌晚期现在才写文。

插件压缩图片的方式非常简单粗暴,直接调用shell命令。png 压缩的命令是:

$ pngquant --skip-if-larger --ext .png --force --quality=60-90 xxx.png

jpg 压缩的命令是:

$ jpegoptim --max=90 --preserve --all-progressive xxx.jpg

虽然解决方案不够优雅,但不管黑猫白猫,抓到老鼠的就是好猫。这插件我自己使用了一段时间,感觉还是比较实用的,毕竟这主机小水管。

Typecho会对图片重命名,重命名的方式如下:

$fileName = sprintf('%u', crc32(uniqid())) . '.' . $ext;

crc32的碰撞概率还是挺高的,不过,Typecho将图片按月归档,所以还好。不过,我还是有强迫症,为了杜绝这种概率,我使用了另外的重命名方式:

sprintf('%s', base_convert(uniqid(), 16, 36)) . '.' . $ext;

利用36进制缩短地址长度,图片名依然不长却避免了碰撞(尽管概率基本可视为0)。

uniqid

uniqid默认返回当前微秒时间。

PHP: uniqid - Manual

源码位置

其实现还是比较简单的:

do {
    (void)gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);
} while (tv.tv_sec == prev_tv.tv_sec && tv.tv_usec == prev_tv.tv_usec);

prev_tv.tv_sec = tv.tv_sec;
prev_tv.tv_usec = tv.tv_usec;

sec = (int) tv.tv_sec;
usec = (int) (tv.tv_usec % 0x100000);

if (more_entropy) {
    uniqid = strpprintf(0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg() * 10);
} else {
    uniqid = strpprintf(0, "%s%08x%05x", prefix, sec, usec);
}

首先是获得当前微秒级时间,这里有点像 CAS 操作,不断循环直至时间变化,这样可以确保单线程下的唯一性。微秒时间对 1048576 取余(限制一下数字范围以避免转为字符串时超出字符?),最后把前缀、秒、微秒,还有可能的额外的熵拼接起来。额外熵是使用线性同余算法生成的随机数。

clearstatcache

clearstatcache清除文件状态缓存。

PHP: clearstatcache - Manual

源码位置

因为插件原地压缩图片,也就是压缩后的图片直接覆盖原图片,所以,图片的大小发生了改变。为此,需要在压缩图片后清除文件状态缓存,这样才可以得到正确的图片大小。

这个插件涉及的技术点大概就这些,还是比较简单的,但是也挺实用。

Typecho

上一篇 增加交换空间【译】
下一篇 Typecho插件开发教程1:登录界面美化

添加新评论

*
*

已有 19 条评论

  1. 开启了这个插件,为什么我上传mp4文件一直转圈?没有后缀过滤吗?

  2. Centos是yum安装吗?

  3. 老哥,我使用了COS附件上传,我可以再使用这个嘛? 也就是说我想用附件上传,然后经过这个的压缩,然后又经过另一个插件直接是上传到腾讯云的对象存储COS上

    1. 不太清楚相同时机触发的多个插件的执行顺序 你可以试试

  4. 感谢开源。服务器已安装jpegoptim pngquant两个软件包,后台添加附件一直在转圈圈,但服务器里面图片已经成功上传,没有压缩,不知道是哪里出现问题了……

    1. php开启shell_exec解决问题了,但插件设置的350KB,低于1M的压缩没有问题,3M的上传后都没有进行压缩,直接上传了。

      1. 不要填写TinyPNG API Key

  5. jclser jclser

    博主你的附件上传改过的? 启用插件后typecho默认的附件上传一直在转圈但实际上图片已经上传了,刷新页面可以看到附件(也就是说压缩并没执行成功)

    1. jclser jclser

      知道了,原来是PHP配置中禁用了shell_exec函数,博主的代码写法对于咱这种菜鸟来说看起来有点困难,最好能多加点释。

      1. philboy philboy

        我的也是一直转圈,我已经打开了shell_exec,但还是不行。。请问大佬怎么查错误信息?

        1. philboy philboy

          已OK。。结果我打开的是exec,不是shell_exec。。。听说开这两个都比较危险。。

  6. 已使用,效果不错,可惜Typecho后台图片管理没有缩略图,不如WordPress方便

    1. jclser jclser

      缩略图这种东西,自己在media.php中加个$attachment->attachment->url();就好了。

  7. skcor skcor

    怎样本地压缩啊

  8. Fatal error: Arrays are not allowed in class constants in C:\Users\cs\Desktop\USB WEB\root\usr\plugins\MyUpload\Plugin.php on line 17 报错

    1. jclser jclser

      PHP版本问题,升级到5.6以上版本就好了。

  9. 这个棒,省得自己手动压图片~谢谢分享!

  10. 虚拟主机上能用吗?

    1. 已更新!虚拟主机可以用图片远程压缩。