友链的朋友圈 RSS的聚合页 (Typecho->handsome主题篇)
本文是《技术相关(共39篇)》目录的第 15 篇。阅读本文前,建议先阅读本文前3篇文章:
本文代码基于Typecho构建,handsome主题测试,其他主题理论上不通用。
友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版)请参考如下文章:
友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)请参考如下文章:
WordPress的RSS朋友圈发布后,感觉应该也可以为Typecho出一个,但是去做了,却发现不是那么回事儿,主要是对Typecho太不熟悉了,最后比葫芦画瓢,基于很受欢迎的handsome主题堆出来一个聚合页。
加入了异步加载机制,并支持缓存,默认8小时。
重要提示:假如以下代码文件在handsome文件夹下,使用缓存时,在handsome文件夹下建立rsscache目录,总之此文件和rsscache目录必须在同一个目录下。
第一次刷新获取,所有友链将缓存存储在rsscache目录下,8小时内刷新页面直接取cache文件显示。8小时后,重新访问这些feed地址并解析计算MD5值,如果MD5值没有变化说明友链网站未更新,则xml不变,如果MD5值变化,则重新获取该站的xml文件并存储在rsscache目录下文件,同域名下的旧xml文件自动删除。如果需要强制更新,删除rsscache目录下所有文件并重新刷新页面即可。
本地演示如下:
代码如下:
[reply]
<?php
/**
* RSS朋友圈
*
* @package custom
*/
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" id="post-content">
<?php
$rssFeeds = [];
// 获取Typecho的链接信息
$links = Typecho_Db::get()->fetchAll(Typecho_Db::get()->select()->from('table.links'));
foreach ($links as $link) {
$url = rtrim($link['url'], '/');
$domain = parse_url($url, PHP_URL_HOST);
if (!preg_match('#^https?://#i', $url)) {
$url = 'http://' . $url;
}
if (substr($url, -1) === '/') {
$url .= 'feed';
} else {
$url .= '/feed';
}
$feedMd5 = md5($url);
$cacheFile = __DIR__ . '/rsscache/' . $domain . '.' . $feedMd5 . '.xml';
$rssContent = '';
if (file_exists($cacheFile) && filemtime($cacheFile) > time() - 28800) {
$rssContent = file_get_contents($cacheFile);
} else {
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
]
]);
$rssContent = file_get_contents($url, false, $context);
if ($rssContent !== false) {
// 删除旧的缓存文件
$oldFiles = glob(__DIR__ . '/rsscache/' . $domain . '.*.xml');
foreach ($oldFiles as $file) {
if ($file !== $cacheFile) {
unlink($file);
}
}
// 将新的内容写入新的缓存文件
file_put_contents($cacheFile, $rssContent);
}
}
if ($rssContent === false) {
echo '获取 ' . $domain . ' 的 RSS 内容失败';
continue;
}
$rss = simplexml_load_string($rssContent, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($rss === false) {
echo '解析 ' . $domain . ' 的 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, 80, 'utf-8');
} else {
$description = mb_substr(strip_tags($description), 0, 80, 'utf-8');
}
if (mb_strlen(strip_tags($description), 'utf-8') > 80) {
$description = rtrim($description);
$description = mb_substr($description, 0, mb_strrpos($description, ' ', 0, 'utf-8'), 'utf-8') . '...';
}
$description = html_entity_decode($description, ENT_QUOTES, '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'];
});
// 默认显示友链网站的最新50条内容
$rssFeeds = array_slice($rssFeeds, 0, 50);
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 '<h4 class="post-title" onclick="window.open(\'' . $rssFeed['link'] . '\', \'_blank\')">' . $rssFeed['title'] . '</h4>';
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>
<script>
window.addEventListener('DOMContentLoaded', function () {
var postContent = document.getElementById('post-content');
var page = 2;
function loadMoreContent() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '<?php echo $this->options->siteUrl; ?>/page/' + page, true);
xhr.onload = function () {
if (xhr.status === 200) {
var response = xhr.responseText;
var temp = document.createElement('div');
temp.innerHTML = response;
var newContent = temp.querySelector('#post-content');
if (newContent) {
postContent.innerHTML += newContent.innerHTML;
page++;
}
}
};
xhr.send();
}
window.addEventListener('scroll', function () {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
var documentHeight = document.documentElement.scrollHeight;
if (scrollTop + windowHeight >= documentHeight - 100) {
loadMoreContent();
}
});
});
</script>
<?php $this->need('component/footer.php'); ?>
[/reply]
大功告成!
您已阅读完《技术相关(共39篇)》目录的第 15 篇。请继续阅读本文后3篇文章:
ymz316
向大佬学习,看能不能给自己的网站加上这个功能。
似水流年
欢迎👏
酷酷
看看吧
似水流年
这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。
Booky
学习一下
似水流年
这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。
一只小白菜
看看,确实不错
似水流年
这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。
obaby
竟然还有广告?abp 屏蔽了~~
网友小宋
就是谷歌那种色色广告,要嘛就是梯子广告。
似水流年
我荣耀浏览器自带屏蔽。😂
网友小宋
这个在线精品,无需等待的广告,给我整得不知道该怎么回了。
似水流年
😂插入的谷歌广告。