本文代码基于Typecho构建,handsome主题测试,其他主题理论上不通用。
基于很受欢迎的handsome主题堆出来一个聚合页。
加入了异步加载机制,并支持缓存,默认2小时。
重要提示:假如以下代码文件在handsome文件夹下,使用缓存时,在handsome文件夹下建立cache目录,总之此文件和cache目录必须在同一个目录下。
第一次刷新获取,所有友链将缓存存储在cache目录下,2小时后自动过期。2小时内刷新页面直接取cache文件显示,2小时后过期重新获取新的xml存储在cache目录。如果需要强制更新,删除cache目录下所有文件并重新刷新页面即可。
本地演示如下:

代码逻辑可以参考WordPress篇,这个和WP不同的地方在于没有加入缓存机制,实时的,但是本地测试挺快。
代码如下:
<?php/*** RSS朋友圈** @package custom*/date_default_timezone_set('Asia/Shanghai'); // 设置时区为上海,即中国标准时间if (!defined('__TYPECHO_ROOT_DIR__')) exit;$this->need('component/header.php');?><?php $this->need('component/aside.php'); ?><style>.avatar{width:60px;height:60px;border-radius:50%;transition:transform 1s ease-in-out;margin:0 auto}.avatar:hover{transform:rotate(360deg)}.post-content{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:stretch}.post-content-item{flex-basis:100%;display:flex;border:1px dashed #ccc;margin-bottom:20px}.post-content-left{flex-basis:20%;display:flex;flex-direction:column;justify-content:space-around;padding:10px;box-sizing:border-box}.post-content-right{flex-basis:80%;display:flex;flex-direction:column;justify-content:space-between;padding:10px;box-sizing:border-box}.site-name{text-align:center;cursor:pointer}.post-title{cursor:pointer;font-size:1.8rem}.post-content-description{margin-bottom:10px}.author-info{text-align:right}</style><main class="app-content-body" <?php Content::returnPageAnimateClass($this); ?>><div class="hbox hbox-auto-xs hbox-auto-sm"><div class="content"><article class="post"><div class="post-content"><?php$db = Typecho_Db::get();$links = $db->fetchAll($db->select()->from('table.links'));$rssFeeds = [];foreach ($links as $link) {$url = rtrim($link['url'], '/');// 判断协议并添加if (!preg_match('#^https?://#i', $url)) {$url = 'http://' . $url;}if (substr($url, -1) === '/') {$url .= 'feed';} else {$url .= '/feed';}// 使用 curl 函数获取远程内容$curl = curl_init();curl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向$rssContent = curl_exec($curl);if ($rssContent === false) {echo '获取 RSS 内容失败';continue;}$rss = simplexml_load_string($rssContent, 'SimpleXMLElement', LIBXML_NOCDATA);if ($rss === false) {echo '解析 RSS 内容失败';continue;}// 获取网站链接$siteLink = (string) $rss->channel->link;$items = $rss->channel->item;foreach ($items as $item) {$description = (string) $item->description;if (empty($description)) {$description = mb_substr(strip_tags((string) $item->content), 0, 60, 'utf-8');} else {$description = mb_substr(strip_tags($description), 0, 60, 'utf-8');}$rssFeeds[] = ['title' => (string) $item->title,'link' => (string) $item->link,'pubDate' => strtotime((string) $item->pubDate),'name' => htmlspecialchars($link['name']), // 对数据进行转义'image' => htmlspecialchars($link['image']), // 对数据进行转义'description' => htmlspecialchars($description), // 对数据进行转义'author' => (string) $item->children('dc', true)->creator,'siteLink' => htmlspecialchars($siteLink), // 网站链接];}}// 按照更新时间降序排列usort($rssFeeds, function ($a, $b) {return $b['pubDate'] - $a['pubDate'];});// 显示前30条记录$rssFeeds = array_slice($rssFeeds, 0, 30);// 输出友情链接的 RSS 内容foreach ($rssFeeds as $rssFeed) {echo '<div class="post-content-item">';echo '<div class="post-content-left">';echo '<img class="avatar" src="' . $rssFeed['image'] . '" alt="站标">';echo '<p class="site-name" onclick="window.open(\'' . $rssFeed['siteLink'] . '\', \'_blank\')">' . $rssFeed['name'] . '</p>';echo '</div>';echo '<div class="post-content-right">';echo '<h3 class="post-title" onclick="window.open(\'' . $rssFeed['link'] . '\', \'_blank\')">' . $rssFeed['title'] . '</h3>';echo '<p class="post-content-description">' . $rssFeed['description'] . '</p>';echo '<p class="author-info">作者:' . $rssFeed['author'] . ' | 更新时间:' . date('Y-m-d H:i:s', $rssFeed['pubDate']) . '</p>';echo '</div>';echo '</div>';}?></div></article></div><?php echo WidgetContent::returnRightTriggerHtml() ?><?php $this->need('component/sidebar.php'); ?></div></main><?php $this->need('component/footer.php'); ?><?php /** * RSS朋友圈 * * @package custom */ date_default_timezone_set('Asia/Shanghai'); // 设置时区为上海,即中国标准时间 if (!defined('__TYPECHO_ROOT_DIR__')) exit; $this->need('component/header.php'); ?> <?php $this->need('component/aside.php'); ?> <style>.avatar{width:60px;height:60px;border-radius:50%;transition:transform 1s ease-in-out;margin:0 auto}.avatar:hover{transform:rotate(360deg)}.post-content{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:stretch}.post-content-item{flex-basis:100%;display:flex;border:1px dashed #ccc;margin-bottom:20px}.post-content-left{flex-basis:20%;display:flex;flex-direction:column;justify-content:space-around;padding:10px;box-sizing:border-box}.post-content-right{flex-basis:80%;display:flex;flex-direction:column;justify-content:space-between;padding:10px;box-sizing:border-box}.site-name{text-align:center;cursor:pointer}.post-title{cursor:pointer;font-size:1.8rem}.post-content-description{margin-bottom:10px}.author-info{text-align:right}</style> <main class="app-content-body" <?php Content::returnPageAnimateClass($this); ?>> <div class="hbox hbox-auto-xs hbox-auto-sm"> <div class="content"> <article class="post"> <div class="post-content"> <?php $db = Typecho_Db::get(); $links = $db->fetchAll($db->select()->from('table.links')); $rssFeeds = []; foreach ($links as $link) { $url = rtrim($link['url'], '/'); // 判断协议并添加 if (!preg_match('#^https?://#i', $url)) { $url = 'http://' . $url; } if (substr($url, -1) === '/') { $url .= 'feed'; } else { $url .= '/feed'; } // 使用 curl 函数获取远程内容 $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 $rssContent = curl_exec($curl); if ($rssContent === false) { echo '获取 RSS 内容失败'; continue; } $rss = simplexml_load_string($rssContent, 'SimpleXMLElement', LIBXML_NOCDATA); if ($rss === false) { echo '解析 RSS 内容失败'; continue; } // 获取网站链接 $siteLink = (string) $rss->channel->link; $items = $rss->channel->item; foreach ($items as $item) { $description = (string) $item->description; if (empty($description)) { $description = mb_substr(strip_tags((string) $item->content), 0, 60, 'utf-8'); } else { $description = mb_substr(strip_tags($description), 0, 60, 'utf-8'); } $rssFeeds[] = [ 'title' => (string) $item->title, 'link' => (string) $item->link, 'pubDate' => strtotime((string) $item->pubDate), 'name' => htmlspecialchars($link['name']), // 对数据进行转义 'image' => htmlspecialchars($link['image']), // 对数据进行转义 'description' => htmlspecialchars($description), // 对数据进行转义 'author' => (string) $item->children('dc', true)->creator, 'siteLink' => htmlspecialchars($siteLink), // 网站链接 ]; } } // 按照更新时间降序排列 usort($rssFeeds, function ($a, $b) { return $b['pubDate'] - $a['pubDate']; }); // 显示前30条记录 $rssFeeds = array_slice($rssFeeds, 0, 30); // 输出友情链接的 RSS 内容 foreach ($rssFeeds as $rssFeed) { echo '<div class="post-content-item">'; echo '<div class="post-content-left">'; echo '<img class="avatar" src="' . $rssFeed['image'] . '" alt="站标">'; echo '<p class="site-name" onclick="window.open(\'' . $rssFeed['siteLink'] . '\', \'_blank\')">' . $rssFeed['name'] . '</p>'; echo '</div>'; echo '<div class="post-content-right">'; echo '<h3 class="post-title" onclick="window.open(\'' . $rssFeed['link'] . '\', \'_blank\')">' . $rssFeed['title'] . '</h3>'; echo '<p class="post-content-description">' . $rssFeed['description'] . '</p>'; echo '<p class="author-info">作者:' . $rssFeed['author'] . ' | 更新时间:' . date('Y-m-d H:i:s', $rssFeed['pubDate']) . '</p>'; echo '</div>'; echo '</div>'; } ?> </div> </article> </div> <?php echo WidgetContent::returnRightTriggerHtml() ?> <?php $this->need('component/sidebar.php'); ?> </div> </main> <?php $this->need('component/footer.php'); ?><?php /** * RSS朋友圈 * * @package custom */ date_default_timezone_set('Asia/Shanghai'); // 设置时区为上海,即中国标准时间 if (!defined('__TYPECHO_ROOT_DIR__')) exit; $this->need('component/header.php'); ?> <?php $this->need('component/aside.php'); ?> <style>.avatar{width:60px;height:60px;border-radius:50%;transition:transform 1s ease-in-out;margin:0 auto}.avatar:hover{transform:rotate(360deg)}.post-content{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:stretch}.post-content-item{flex-basis:100%;display:flex;border:1px dashed #ccc;margin-bottom:20px}.post-content-left{flex-basis:20%;display:flex;flex-direction:column;justify-content:space-around;padding:10px;box-sizing:border-box}.post-content-right{flex-basis:80%;display:flex;flex-direction:column;justify-content:space-between;padding:10px;box-sizing:border-box}.site-name{text-align:center;cursor:pointer}.post-title{cursor:pointer;font-size:1.8rem}.post-content-description{margin-bottom:10px}.author-info{text-align:right}</style> <main class="app-content-body" <?php Content::returnPageAnimateClass($this); ?>> <div class="hbox hbox-auto-xs hbox-auto-sm"> <div class="content"> <article class="post"> <div class="post-content"> <?php $db = Typecho_Db::get(); $links = $db->fetchAll($db->select()->from('table.links')); $rssFeeds = []; foreach ($links as $link) { $url = rtrim($link['url'], '/'); // 判断协议并添加 if (!preg_match('#^https?://#i', $url)) { $url = 'http://' . $url; } if (substr($url, -1) === '/') { $url .= 'feed'; } else { $url .= '/feed'; } // 使用 curl 函数获取远程内容 $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 $rssContent = curl_exec($curl); if ($rssContent === false) { echo '获取 RSS 内容失败'; continue; } $rss = simplexml_load_string($rssContent, 'SimpleXMLElement', LIBXML_NOCDATA); if ($rss === false) { echo '解析 RSS 内容失败'; continue; } // 获取网站链接 $siteLink = (string) $rss->channel->link; $items = $rss->channel->item; foreach ($items as $item) { $description = (string) $item->description; if (empty($description)) { $description = mb_substr(strip_tags((string) $item->content), 0, 60, 'utf-8'); } else { $description = mb_substr(strip_tags($description), 0, 60, 'utf-8'); } $rssFeeds[] = [ 'title' => (string) $item->title, 'link' => (string) $item->link, 'pubDate' => strtotime((string) $item->pubDate), 'name' => htmlspecialchars($link['name']), // 对数据进行转义 'image' => htmlspecialchars($link['image']), // 对数据进行转义 'description' => htmlspecialchars($description), // 对数据进行转义 'author' => (string) $item->children('dc', true)->creator, 'siteLink' => htmlspecialchars($siteLink), // 网站链接 ]; } } // 按照更新时间降序排列 usort($rssFeeds, function ($a, $b) { return $b['pubDate'] - $a['pubDate']; }); // 显示前30条记录 $rssFeeds = array_slice($rssFeeds, 0, 30); // 输出友情链接的 RSS 内容 foreach ($rssFeeds as $rssFeed) { echo '<div class="post-content-item">'; echo '<div class="post-content-left">'; echo '<img class="avatar" src="' . $rssFeed['image'] . '" alt="站标">'; echo '<p class="site-name" onclick="window.open(\'' . $rssFeed['siteLink'] . '\', \'_blank\')">' . $rssFeed['name'] . '</p>'; echo '</div>'; echo '<div class="post-content-right">'; echo '<h3 class="post-title" onclick="window.open(\'' . $rssFeed['link'] . '\', \'_blank\')">' . $rssFeed['title'] . '</h3>'; echo '<p class="post-content-description">' . $rssFeed['description'] . '</p>'; echo '<p class="author-info">作者:' . $rssFeed['author'] . ' | 更新时间:' . date('Y-m-d H:i:s', $rssFeed['pubDate']) . '</p>'; echo '</div>'; echo '</div>'; } ?> </div> </article> </div> <?php echo WidgetContent::returnRightTriggerHtml() ?> <?php $this->need('component/sidebar.php'); ?> </div> </main> <?php $this->need('component/footer.php'); ?>
大功告成!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容