我从一个多月前开始发现石墨的粘贴图片功能很好用,可以直接Ctrl + V把图片放上去。
早期的时候我写博客为了避免麻烦都是不贴图片的,发现了这个功能之后就基本上是在石墨上写作,然后导出markdown文件。
但是近段时间,石墨似乎对图片外链做了限制(增加了对访问来源的检测),所以我部分文章中全部图片无法显示。
到了今天,我突发奇想要修复这个图片的问题,于是就百度搜索了一下typecho在这方面的插件,搜索到了一款插件,但当然不能拿来直接用,于是我对其代码进行了大改,最后达到效果是让文章在编辑的时候都会自动替换外链图片信息。
不得不提的是,我这款主题似乎还对typecho的插件函数进行了hook,导致我刚开始测试的时候死活用不了,后来搜索终于找到了解决方法。
感觉现在有点看厌了这款主题,似乎没刚接触的时候认为的好看,但是短时间内应该不会换了,因为找个新主题也挺麻烦的。
而且由于现在写作都是导出markdown,似乎可以考虑一下一些静态博客(那也是以后的事情了,毕竟现在的文章数量,还没能到让这个系统变得臃肿的程度)
还有不知道为啥,上传目录必须要给执行权限才能够成功的创建文件,这是啥原因有人知道吗?
我放一下源码应该不会被rce吧...按照我的水平,不知道要怎么入手来攻击。
这个脚本是为了适应我目前的主题而修改的,如果其他主题需要使用,请参照 https://www.liuguogy.com/archives/mirages-plugin-conflict-solution.html 把相关代码替换回去
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 自动下载保存远程图片
*
* @package AutoSaveImage
* @author wjh
* @version 1.0.0
* @link http://blog.wjhwjhn.com
*/
class AutoSaveImage_Plugin implements Typecho_Plugin_Interface
{
//上传文件目录(统一目录,不再按日期新建目录,查询到文件已存在时则不再处理)
const UPLOAD_DIR = '/usr/uploads/image/';
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function activate()
{
//下载保存远程图片
Typecho_Plugin::factory('Mirages_Plugin')->writePost = array('AutoSaveImage_Plugin', 'saveFile');
Typecho_Plugin::factory('Mirages_Plugin')->writePage = array('AutoSaveImage_Plugin', 'saveFile');
/*
如果你不用Mirages插件的话,就把上面的两行换成下面的部分
Typecho_Plugin::factory('Widget_Contents_Post_Edit')->write = array('AutoSaveImage_Plugin', 'saveFile');
Typecho_Plugin::factory('Widget_Contents_Page_Edit')->write = array('AutoSaveImage_Plugin', 'saveFile');
*/
}
/**
* 获取插件配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面板
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function deactivate()
{
}
/**
* 个人用户的配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
}
/**
* 下载保存远程图片
*
* @access public
* @param array $post 数据结构体
* @return array
*/
public static function saveFile($post)
{
$options = Typecho_Widget::widget('Widget_Options');
$siteUrl = $options->siteUrl;
$text = $post['text'];
$urls = self::getImageFromText($text);
if(!isset($urls) || count($urls) == 0) return $post;
$save_dir = self::UPLOAD_DIR;
$save_dir = parse_url($save_dir, PHP_URL_PATH);
$uploadDir = Typecho_Common::url($save_dir, __TYPECHO_ROOT_DIR__);
//创建上传目录
if (!is_dir($uploadDir))
{
if (!@mkdir($uploadDir, 0744))
{
throw new Typecho_Widget_Exception(_t('上传目录无法创建, 请手动创建安装目录下的 %s 目录, 并将它的权限设置为可写然后继续尝试', $uploadDir));
}
}
//获取相对路径
$domain = trim($_SERVER['HTTP_HOST']);
foreach ($urls as $url)
{
$tmp_url = strtolower(trim($url));
if (strpos($tmp_url, '://') === false || strpos($tmp_url, $domain) !== false) continue;
$hash = md5($url);
$array = pathinfo($url);
$ext = $array['extension'];
$filename = $hash.'.'.$ext;//生成要保存在本地的文件名
$dst_path = $uploadDir.$filename;//本地保存绝对路径
$dst_file = $save_dir.$filename;//相对保存路径
$dst_url = $siteUrl.$dst_file;//生成的本地文件url
if (!file_exists($dst_path))
{
//不存在文件则下载
self::get_remote_file($url, $dst_path);
}
if (file_exists($dst_path))
{
//有文件了,替换内容
$text = str_ireplace($url, $dst_url, $text);
}
}
$text = str_replace('!thumbnail', '', $text); //石墨外链特殊处理
$post['text'] = $text;
return $post;
}
static function getImageFromText($text)
{
// $patten = '!(http|https)://[a-z0-9\-\.\/]+\.(?:jpe?g|png|gif)!Ui';
$patten = '!(https?:\/\/.*\.(?:png|jpg|bmp|jpeg|gif|webp))!';
preg_match_all($patten, $text, $arr);
$result = [];
if(isset($arr) && count($arr) > 0)
{
foreach ($arr as $key => $value)
{
if(count($value) > 0)
{
foreach ($value as $v)
{
if(!in_array($v,$result))
$result[] = $v;
}
}
}
}
return $result;
}
/**
* 下载远程文件
*
*/
static function get_remote_file($url, $save)
{
if ( trim($save) === '' || trim($url) === '' ) return false;
$fp = fopen ($save, "wb");
if (!$fp) throw new Typecho_Widget_Exception(_t('上传目录无法写入文件:%s', $save));
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_REFERER, $url);
$img = curl_exec($ch);
fwrite($fp, $img);
curl_close($ch);
fclose($fp);
return true;
}
}
如果代码有问题,麻烦请告知/高抬贵手,毕竟我这博客经常忘记备份,数据被删可就麻烦了