Holmesian Blog

升级Typecho并添加AMP支持

2017年12月1日更新:AMP功能已经做成插件,详情见这里


很不幸,我使用Typecho前段时间爆出非常严重的安全漏洞,好在我之前做过习惯性地加固,install.php相关的文件也删除了,所以即使满大街都是漏洞利用工具,也没受到本次漏洞的伤害。

既然官方已经出了1.1的更新,我也就顺手将博客程序升级了:结果升级一时爽,模板火葬场。因为博客内容经过多个转换程序,而且年久失修,加上原来在模板上做过一些高耦合的hack,所有弊端一次性爆发,导致不得不推到重来一遍。于是乘着这个机会一并解决了一些遗留问题,并顺手增加AMP功能。

HTML转Markdown

由于07年至今用过Boblog,Emlog等博客系统,数据编辑器从UBB到HTML富文本都用过,所以context里的内容鱼目混杂。于是首先要进行内容格式统一:UBB转换成HTML,HTML集体转换为Markdown。UBB转HTML基本没问题,HTML转Markdown建议用html2text完成,基本上格式可以保留,记得设置.body_width =0不主动换行即可。

    import pymysql.cursors
    import html2text
    
    connection = pymysql.connect(host='localhost',
                                 user='root',
                                 password='password',
                                 db='typecho',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
    
    try:
        with connection.cursor() as cursor:
            # Read a single record
            sql = "SELECT * FROM `typecho_contents`"
            cursor.execute(sql)
            result = cursor.fetchall()
            for x in result:
                if(x['text'][0:15]=='<!--markdown-->' or x['type']=='attachment'):
                    pass
                else:
                    h = html2text.HTML2Text()
                    h.ignore_links = False
                    h.body_width =0
                    md_text='<!--markdown-->'+h.handle(x['text'])
    
                    sql="UPDATE `typecho_contents` SET `text` =%s WHERE `cid` = %s ;"
                    print(x['cid'])
                    cursor.execute(sql,(md_text,str(x['cid'])))
                    connection.commit()
    
    finally:
        connection.close()

支持AMP

之所以要统一博客内容统一成Markdown,除了强迫症之外,更主要的是为了支持AMP。Typecho至今没有出任何支持AMP的插件或主题,我没去想怎么用插件实现AMP,而是直接通过修改模板的post.php、function.php文件来暴力实现,原则上所有模板都可以用。

效果就是在任何一篇博文的url后面加上amp=1即可访问amp版的页面,例如本文的AMP页面,总之实现起来也很简单。

具体步骤如下:

对模板里的post.php文件做如下修改(后台控制台》外观》编辑当前外观》post.php):

    <?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
    <?php if (isset($_GET['amp'])){; ?>
    <!doctype html>
    <html amp lang="zh">
      <head>
        <meta charset="utf-8">
        <script async src="https://cdn.ampproject.org/v0.js"></script>
        <title><?php $this->title() ?></title>
        <link rel="canonical" href="<?php $this->permalink() ?>" />
        <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
        <script type="application/ld+json">
          {
            "@context": "http://schema.org",
            "@type": "BlogPosting",
            "headline": "<?php $this->title(); ?>",
            "mainEntityOfPage": "<?php $this->permalink() ?>",
            "author": {
              "@type": "Person",
              "name": "<?php $this->author(); ?>"
            },
            "datePublished": "<?php $this->date('F j, Y'); ?>",
            "dateModified": "<?php $this->date('F j, Y'); ?>",
            "image": {
              "@type": "ImageObject",
              "url": "<?php  print_r(get_post_img($this));?>",
              "width": 700,
              "height": 400
            },
             "publisher": {
              "@type": "Organization",
              "name": "Holmesian Blog",
              "logo": {
                "@type": "ImageObject",
                "url": "https://holmesian.org/usr/themes/Holmesian/images/holmesian.png",
                "width": 60,
                "height": 60
              }
            },
            "description": "<?php $this->excerpt(60, '...'); ?>"
          }
        </script>
         <style amp-custom>*{margin:0;padding:0}html,body{height:100%}body{background:#fff;color:#666;font-size:14px;font-family:"-apple-system","Open Sans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,sans-serif}::selection,::-moz-selection,::-webkit-selection{background-color:#2479CC;color:#eee}h1{font-size:1.5em}h3{font-size:1.3em}h4{font-size:1.1em}a{color:#2479CC;text-decoration:none}article{padding:85px 15px 0}article .entry-content{color:#444;font-size:16px;font-family:Arial,'Hiragino Sans GB',冬青黑,'Microsoft YaHei',微软雅黑,SimSun,宋体,Helvetica,Tahoma,'Arial sans-serif';-webkit-font-smoothing:antialiased;line-height:1.8;word-wrap:break-word}article h1.title{color:#333;font-size:2em;font-weight:300;line-height:35px;margin-bottom:25px}article .entry-content p{margin-top:15px}article h1.title a{color:#333;transition:color .3s}article h1.title a:hover{color:#2479CC}article blockquote{background-color:#f8f8f8;border-left:5px solid #2479CC;margin-top:10px;overflow:hidden;padding:15px 20px}article code{background-color:#eee;border-radius:5px;font-family:Consolas,Monaco,'Andale Mono',monospace;font-size:80%;margin:0 2px;padding:4px 5px;vertical-align:middle}article pre{background-color:#f8f8f8;border-left:5px solid #ccc;color:#5d6a6a;font-size:14px;line-height:1.6;overflow:hidden;padding:0.6em;position:relative;white-space:pre-wrap;word-break:break-word;word-wrap:break-word}article table{border:0;border-collapse:collapse;border-spacing:0}article pre code{background-color:transparent;border-radius:0 0 0 0;border:0;display:block;font-size:100%;margin:0;padding:0;position:relative}article table th,article table td{border:0}article table th{border-bottom:2px solid #848484;padding:6px 20px;text-align:left}article table td{border-bottom:1px solid #d0d0d0;padding:6px 20px}article .copyright-info,article .amp-info{font-size:14px}article .expire-tips{background-color:#f5d09a;border:1px solid #e2e2e2;border-left:5px solid #fff000;color:#333;font-size:15px;padding:5px 10px;margin:20px 0px}article .post-info,article .entry-content .date{font-size:14px}article .entry-content blockquote,article .entry-content ul,article .entry-content ol,article .entry-content dl,article .entry-content table,article .entry-content h1,article .entry-content h2,article .entry-content h3,article .entry-content h4,article .entry-content h5,article .entry-content h6,article .entry-content pre{margin-top:15px}article pre b.name{color:#eee;font-family:"Consolas","Liberation Mono",Courier,monospace;font-size:60px;line-height:1;pointer-events:none;position:absolute;right:10px;top:10px}article .entry-content .date{color:#999}article .entry-content ul ul,article .entry-content ul ol,article .entry-content ul dl,article .entry-content ol ul,article .entry-content ol ol,article .entry-content ol dl,article .entry-content dl ul,article .entry-content dl ol,article .entry-content dl dl,article .entry-content blockquote > p:first-of-type{margin-top:0}article .entry-content ul,article .entry-content ol,article .entry-content dl{margin-left:25px}.header{background-color:#fff;box-shadow:0 0 40px 0 rgba(0,0,0,0.1);box-sizing:border-box;font-size:14px;height:60px;padding:0 15px;position:absolute;width:100%}.footer{font-size:.9em;padding:15px 0 25px;text-align:center;width:auto}.header h1{font-size:30px;font-weight:400;line-height:30px;margin:15px 0px}.menu-list li a,.menu-list li span{border-bottom:solid 1px #ededed;color:#000;display:block;font-size:18px;height:60px;line-height:60px;text-align:center;width:86px}.header h1 a{color:#333}.tex .hljs-formula{background:#eee8d5}</style>
        <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
        <noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
      </head>
      <body>
      <header class="header"><div class="header-title"><h1><a href="/">Holmesian Blog</a></h1></div></header>
      
      <article class="post"><h1 class="title"><?php $this->title(); ?></h1>
        <div class="entry-content">
        <?php  ampInit($this);?>
        <?php $this->content(); ?>
        </div>
        <p class="expire-tips">当前页面是本站的「<a href="//www.ampproject.org/zh_cn/">Google AMP</a>」版。查看和发表评论请点击:<a href="<?php $this->permalink() ?>#comments">完整版 »</a></p>
    
      </article>
    
      </body>
    </html>
    
    <?php } else {?>
    \\这里是原模板内容
    <?php  }?>

接着在functions.php文件末尾添加下列两个函数。

    function ampInit($archive)
    {
        if ($archive->is('single')) {
            $archive->content = str_replace('<img','<amp-img width="900" height="675" layout="responsive" ',$archive->content);
            $archive->content = str_replace('img>','amp-img>',$archive->content);
            $archive->content = str_replace('<!- toc end ->','',$archive->content);
            $archive->content = str_replace('#','#',$archive->content);
        }
    
    }
    
    
    function get_post_img($archive)
    {
        $cid = $archive->cid;
        $db = Typecho_Db::get();
        $rs = $db->fetchRow($db->select('table.contents.text')
                                   ->from('table.contents')
                                   ->where('cid=?', $cid));
        $text = $rs['text'];
        $pattern = '/\<img.*?src\=\"(.*?)\"[^>]*>/i';
        $patternMD = '/\!\[.*?\]\((http(s)?:\/\/.*?(jpg|png))/i';
        $patternMDfoot = '/\[.*?\]:\s*(http(s)?:\/\/.*?(jpg|png))/i';
            if (preg_match($patternMDfoot, $text, $img)) {
                $img_url = $img[1];
            } else if (preg_match($patternMD, $text, $img)) {
                $img_url = $img[1];
            } else if (preg_match($pattern, $text, $img)) {
                preg_match("/(?:\()(.*)(?:\))/i", $img[0], $result);
                $img_url = $img[1];
            } else {
                $img_url ='https://holmesian.org/usr/themes/Holmesian/images/holmesian.png?type=markdown';
            }
            return $img_url;
    }

最后在header.php中添加下列内容

    <?php if ($this->is('post')): ?>
    <link rel="amphtml" href="<?php $this->permalink() ?>?amp=1">
    <?php endif; ?>

全部修改之后,刷新缓存,就可以访问AMP页面啦。

PS:可以到这里测试你的AMP页面是否正确有效。

PS2:Google大概会在48小时内抓取到AMP页面,并在搜索结果中体现出来。效果如下:

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »