MENU

博客外链图片已恢复

January 27, 2021 • Read: 512 • 默认分类

我从一个多月前开始发现石墨的粘贴图片功能很好用,可以直接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;
    }

}

如果代码有问题,麻烦请告知/高抬贵手,毕竟我这博客经常忘记备份,数据被删可就麻烦了

Archives QR Code Tip
QR Code for this page
Tipping QR Code