Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

无法通过插件注入自定义field更改头图内容 #1642

Open
FaceChan opened this issue Oct 29, 2023 · 1 comment
Open

无法通过插件注入自定义field更改头图内容 #1642

FaceChan opened this issue Oct 29, 2023 · 1 comment
Labels
question Further information is requested

Comments

@FaceChan
Copy link

1. 该问题的重现步骤是什么?

博客使用CDN分流,想通过插件的方式更换头图url为CDN地址

2. 你期待的结果是什么?实际看到的又是什么?

文章可以实现替换效果,但头图无法注入。

尝试直接给$archive赋值,在单个文章页面成功,但在索引页面返回的依然是空值。

3. 问题出现的环境

  • 操作系统版本:
  • Apache/NGINX 版本:
  • 数据库版本:
  • PHP 版本:
  • Typecho 版本:1.2
  • 浏览器版本:
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
 * 简易替换插件,可用作镜像类CDN地址转换,方便以后整站迁移。
 *
 * @package SimpleCDN
 * @author Quarkay
 * @version 1.0.0
 * @link https://www.quarkay.com
 */
class SimpleCDN_Plugin implements Typecho_Plugin_Interface
{
    /**
     * 激活插件方法,如果激活失败,直接抛出异常
     *
     * @access public
     * @return void
     * @throws Typecho_Plugin_Exception
     */
    public static function activate(){
        Typecho_Plugin::factory("Widget_Archive")->beforeRender = array('SimpleCDN_Plugin', 'replace_content');
    }

    /**
     * 禁用插件方法,如果禁用失败,直接抛出异常
     *
     * @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 config(Typecho_Widget_Helper_Form $form){
        // 设置替换分割符和替换规则
        $sep_flag = new Typecho_Widget_Helper_Form_Element_Text('sep_flag', NULL, '-_-', _t('规则分割符'), _t('规则分割符默认为 -_- ,可根据需要进行设置。'));
        $to_replace = new Typecho_Widget_Helper_Form_Element_Text('to_replace', NULL, '', _t('替换前地址'));
        $replace_to = new Typecho_Widget_Helper_Form_Element_Text('replace_to', NULL, '', _t('替换后地址'));
        $form->addInput($sep_flag);
        $form->addInput($to_replace);
        $form->addInput($replace_to);
        // 设置替换分割符和替换规则
        $form->addInput(new Typecho_Widget_Helper_Form_Element_Select('cdn_type', array('tencent' => '腾讯', 'UPY' => '又拍云'), 'UPY', 'CDN服务商'));
        $cdn_domain = new Typecho_Widget_Helper_Form_Element_Text('cdn_domain', NULL, 'https://static.ezo.biz', _t('CDN域名'), _t('例:https://static.ezo.biz'));
        $pkey = new Typecho_Widget_Helper_Form_Element_Text('pkey', NULL, '', _t('鉴权密钥'), _t('目前仅支持TypeC方式'));
        $lifeTime = new Typecho_Widget_Helper_Form_Element_Text('lifeTime', NULL, '30', _t('生存期限'), _t('单位秒,超过该时间鉴权失效,建议30秒'));
        $form->addInput($cdn_domain);
        $form->addInput($pkey);
        $form->addInput($lifeTime);
    }

    /**
     * 个人用户的配置面板
     *
     * @access public
     * @param Typecho_Widget_Helper_Form $form
     * @return void
     */
    public static function personalConfig(Typecho_Widget_Helper_Form $form){}

    /**
     * 插件实现方法
     *
     * @access public
     * @param Widget_Archive $archive
     * @return void
     */
    public static function replace_content(Widget_Archive $archive)
    {
        // 先得到函数参数避免重复运算
        list($to_replace, $replace_to) = self::prepare_replace_args();

        // 依次对队列中文章的指定内容进行替换
        foreach($archive->stack as $index=>$con){
            // 替换文章标题
            if(array_key_exists('text', $con)){
                $archive->stack[$index]['text'] = preg_replace($to_replace, $replace_to, $con['text']);
            }
            // 替换文章内容
            if(array_key_exists('title', $con)){
                $archive->stack[$index]['title'] = preg_replace($to_replace, $replace_to, $con['title']);
            }
            // 替换头图内容
            if(array_key_exists('banner', $con)){
                $archive->stack[$index]['fields']['banner'] = preg_replace($to_replace, $replace_to, $con['fields']['banner']);
                $archive->stack[$index]['banner'] = $archive->stack[$index]['fields']['banner'];
            }
        }

        // 对 Widget_Archive->row 中对应信息进行更新
        $archive->text = self::ParseImg(preg_replace($to_replace, $replace_to, $archive->text));
        $archive->title = self::ParseImg(preg_replace($to_replace, $replace_to, $archive->title));
        $archive->banner = self::ParseImg(preg_replace($to_replace, $replace_to, $archive->fields->banner));
    }

    /**
     * 准备替换规则参数
     *
     */
    private static function prepare_replace_args()
    {
        // 获取规则分割符
        $sep_flag = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->sep_flag;

        // 分割得到规则并进行预处理
        $to_replace = explode($sep_flag, Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->to_replace);
        $to_replace = array_map(self::sep_callback(), $to_replace);
        $replace_to = explode($sep_flag, Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->replace_to);
        return array($to_replace, $replace_to);
    }

    /**
     * 替换规则预处理
     *
     * @return Callback Function
     */
    private static function sep_callback()
    {
        return function($item){
            // 若本身就是Pattern参数格式,则无需处理
            return preg_match('/^\/.*\/[a-z]*$/i', $item) ? $item : '/'.$item.'/';
        };
    }
    
    
    private static function PrivateKeyC($org_url){
        
        $key = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->pkey;
        
        $domain = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->cdn_domain;
    
        $time2 = dechex(time());
        
        $filename = str_replace($domain, '', $org_url);
        
        //$sstring=PrivateKeyFileNametime
        
        $sstring = $key.$filename[0].$time2;
        
        $md5 = md5($sstring);
        
        $url = $domain."/".$md5."/".$time2."/".$filename[0];
        
        return $url;
    }
    
    private static function PrivateKeyUPY($org_url){
        
        $key = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->pkey;
        
        $domain = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->cdn_domain;
        
        $time1 = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->lifeTime;
        
        $etime = time() + $time1;
        
        $filename = str_replace($domain, '', $org_url);
        if(is_array($org_url)){
            $uri = $filename[0];
        }else{
            $uri = $filename;
        }
        
        $sign_key = $key."&".$etime."&".$uri;
        $sign = md5($sign_key);
        
        $sign8 = substr($sign,12,8);
        
        $_upt = $sign8 . $etime;
        
        return $domain . $uri . "?_upt=" . $_upt;
    }
    
    private static function ParseImg($content){
        $cdn_type = Typecho_Widget::widget('Widget_Options')->plugin('SimpleCDN')->cdn_type;
        switch ($cdn_type) {
            case 'UPY':
                $cdn_handle = 'self::PrivateKeyUPY';
                break;
            case 'tencent':
                $cdn_handle = 'self::PrivateKeyC';
                break;
            default:
                $cdn_handle = 'self::PrivateKeyUPY';
                break;
        }
        $reg = "/https\:\/\/(.+?)(\.gif|png|jpg|jpeg)/i";
        $content = preg_replace_callback($reg, $cdn_handle, $content);
        return $content;
    }
    
    public static function cdnIMG($archive){
        $url = self::ParseImg($archive);
        return $url;
    }

}
@fenbox fenbox added the question Further information is requested label Jan 10, 2024
@xiamuguizhi
Copy link

@chatgtp4

你的插件代码看起来已经很接近你想要的功能了。但是,从你的描述来看,你在索引页面无法成功替换头图 URL。这可能是因为在 Typecho 的索引页面中,文章的自定义字段(如头图URL)可能并没有被预加载,所以你在处理索引页面时无法访问这些字段。

你可以尝试在你的主题的索引页面模板中,使用 fields() 方法来预加载文章的自定义字段。以下是一个示例代码:

// 在你的主题的 index.php 文件中
$posts = $this->widget('Widget_Contents_Post_Recent');
while($posts->next()){
    $posts->fields(); // 预加载自定义字段
    // 然后你可以像在文章页面一样访问自定义字段
    echo $posts->fields->banner;
}

然后你可以在你的插件中,使用类似的方法来处理索引页面的文章:

public static function replace_content(Widget_Archive $archive)
{
    // ...
    foreach($archive->stack as $index=>$con){
        // ...
        // 替换头图内容
        if(array_key_exists('fields', $con) && array_key_exists('banner', $con['fields'])){
            $archive->stack[$index]['fields']['banner'] = preg_replace($to_replace, $replace_to, $con['fields']['banner']);
            $archive->stack[$index]['banner'] = $archive->stack[$index]['fields']['banner'];
        }
    }
    // ...
}

这样应该可以解决你的问题。如果还有问题,可能需要更详细地调试你的代码和环境。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants