昨天学习了一下 RSS 订阅知识之后,经过一番百度搜索,终于在自己的博客上实现了 RSS 订阅功能,但苦于技术有限,不能对 Feed 文件进行定时缓存,每次打开链接都会比较延迟。今天继续对这个功能进行了学习,突然,我发现了一个大佬提供的 rssphp 代码,有了他,很多实用功能不再需要自己去分析、判断和写代码了,最重要的是他提供了定时缓存 xml 文件的功能,于是将其拿来,在经过一番操作之后,终于在自己的博客上较为完美的实现了。

文档修改日志:

  • 2024.12.01 实现 rss 订阅
  • 2024.12.02 增加 atom 订阅,修复截取字符串乱码问题

一、下载代码存到自己的博客

上面的链接可以下载下来学习,里面也有两个 demo 文件供参考,但放入博客,真正要用的只需要 Feed.php 文件,我将其存放到自己主题目录下面,然后在 funciton.php 文件中引入(通常是放在函数代码块的前面,方便以后回忆代码)。

include_once 'path/to/feed.php';

二、建立 Feed 文件下载缓存目录

就用 demo 中所说的 tmp 目录吧,在主题目录下面建立 tmp 目录,并赋权为 777(linux系统)

sudo chmod 777 -R tmp

三、在主题目录下建立模板文件 rss.php 实现订阅

下面是我写的模板文件,重点看订阅RSS部分的php代码,主要实现了几个功能

  1. 指定时区(不知道啥用)以及指定缓存位置及下载缓存文件的时间间隔
  2. 获取 RSS 订阅网址及 atom 订阅网址数据
  3. 对每个 RSS 文件进行读取和输出相关信息
  4. 加入了 try 防止有些 feed 文件不被识别而报错
<?php

/**
 * RSS自动订阅
 *
 * @package custom
 */
?>

<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>

<!-- main-body -->
<div class="p-3 flex-1">
    <!-- 文章 -->
    <article class="flex flex-col mb-6">
        <!--标题-->
        <div
            class="mb-6 p-2 flex flex-col hyone-box">
            <p
                class="p-3 text-lg md:text-xl lg:text-2xl text-slate-900 line-clamp-1 font-extrabold tracking-tight dark:text-slate-300 ">
                <a itemprop="url"
                    href="<?php $this->permalink() ?>"><?php $this->title() ?></a>
            </p>
            <div class="px-3 text-base line-clamp-2 lg:line-clamp-3 mb-2">
                <p></p>
            </div>

        </div>

        <!-- 正文 -->
        <div
            class="mb-6 p-2 flex-1 flex flex-col hyone-box">

            <div class="px-3 md:px-6 py-6 text-base leading-9 mb-2 flex-1">


                <!-- 订阅基础设置 -->
                <?php
                // 指定时区
                if (!ini_get('date.timezone')) {
                    date_default_timezone_set('Asia/Shanghai');
                }

                // 指定缓存目录及缓存事件
                Feed::$cacheDir = __DIR__ . '/tmp';
                Feed::$cacheExpire = '6 hours';
                ?>

                <!-- 订阅RSS开始 -->
                <?php
                // 获取需要订阅RSS的网址
                $delimiter = ",";
                if ($this->options->rss) {
                    $rssfeed = explode($delimiter, $this->options->rss);
                } else {
                    $rssfeed = array(
                        "https://www.zhangxinxu.com/wordpress/feed/",
                        "https://www.hollowman.cn/feed/"
                    );
                }

                //调用每个RSS文件
                for ($i = 0; $i < count($rssfeed); $i++) {
                    $rssname = 'rss' . $i;
                    try {
                        $$rssname = Feed::loadRss($rssfeed[$i]);
                        echo ' <div class="accordion">';
                        echo ' <div class="accordion-title">' . htmlspecialchars($$rssname->title) . '</div>';
                        echo '<div class="accordion-body"><div>';

                        foreach ($$rssname->item as $item):
                            if (strlen($item->title) > 0) {
                                $description = mb_substr(trim(strip_tags($item->description)), 0, 150);
                                echo '<div class="rsspost"><a href="' . htmlspecialchars($item->url) . '" target="_blank" rel="noopener">' . htmlspecialchars($item->title) . '</a>(' . date('Y-n-j', (int) $item->timestamp) . ')<br><span class="line_over_hidden">' . htmlspecialchars($description) . '</span></div>';
                            }
                        endforeach;

                        echo '</div>';
                        echo '</div>';
                        echo '</div>';
                    } catch (Exception $e) {
                    }
                }
                ?>
                <!-- 订阅RSS结束 -->

                <!-- 订阅 atom 开始 -->
                <?php
                // 获取需要订阅 atom 的网址
                $delimiter = ",";
                if ($this->options->atom) {
                    $atomfeed = explode($delimiter, $this->options->atom);
                } else {
                    $atomfeed = array(
                        "http://www.ruanyifeng.com/blog/atom.xml"
                    );
                }

                //调用每个 atom 文件
                for ($i = 0; $i < count($atomfeed); $i++) {
                    $atomname = 'atom' . $i;
                    try {
                        $$atomname = Feed::loadAtom($atomfeed[$i]);
                        echo ' <div class="accordion">';
                        echo ' <div class="accordion-title">' . htmlspecialchars($$atomname->title) . '</div>';
                        echo '<div class="accordion-body"><div>';

                        foreach ($$atomname->entry as $entry):
                            if (strlen($entry->title) > 0) {
                                $content = mb_substr(trim(strip_tags($entry->content)), 0, 150);
                                echo '<div class="rsspost"><a href="' . htmlspecialchars($entry->url) . '" target="_blank" rel="noopener">' . htmlspecialchars($entry->title) . '</a>(' . date('Y-n-j', (int) $entry->timestamp) . ')<br><span class="line_over_hidden">' . htmlspecialchars($content) . '</span></div>';
                            }
                        endforeach;

                        echo '</div>';
                        echo '</div>';
                        echo '</div>';
                    } catch (Exception $e) {
                    }
                }
                ?>
                <!-- 订阅 atom 结束 -->

            </div>


            <div class="flex-1 px-3 md:px-6 py-6 post-content">

            </div>

        </div>

    </article>

</div>
<style>
    .rsspost {
        padding: 0 1rem;
    }

    .rsspost:hover {
        background-color: rgba(0, 0, 0, .2);
    }

    .rsspost a {
        color: green;
        font-weight: bolder;
    }

    .rsspost a:hover {
        color: yellowgreen;
    }

    /* 超出隐藏 */
    .line_over_hidden {
        overflow: hidden;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
    }
</style>

<?php $this->need('sidebar.php'); ?>
<?php $this->need('footer.php'); ?>

订阅 RSS 来源,我是通过在主题外观中添加了一个 input 框,将需要订阅的地址写入后进行订阅,如果后台不写入,则在此文件中添加默认的订阅网址。

可以在 function.php 文件的 themeConfig($form)函数中写入订阅 input 框

//主题配置
function themeConfig($form){
...
    // rss订阅链接
    $rss = new \Typecho\Widget\Helper\Form\Element\Text('rss', null, null, _t('rss订阅链接'), _t('添加需要订阅的rss地址,以逗号分割'));
    $form->addInput($rss);
    // atom订阅链接
    $atom = new \Typecho\Widget\Helper\Form\Element\Text('atom', null, null, _t('atom订阅链接'), _t('添加需要订阅的atom地址,以逗号分割'));
    $form->addInput($atom);
...
}

四、体验吧