如何使用原生PHP同时解析展示多个RSS订阅源?
纯原生PHP多RSS源聚合展示实现
你现有单源RSS解析的核心逻辑是可用的,只需要扩展多源遍历能力、补充基础容错和缓存即可,完全不需要依赖第三方库,以下是可直接运行的改造方案:
改造点说明
- 保留原生
simplexml解析逻辑,无额外依赖 - 支持批量传入多个RSS源配置,每个源可自定义显示名称
- 增加解析容错:单个源加载失败/格式异常不会导致整个页面崩溃
- 增加轻量文件缓存:避免每次访问都拉取源内容,提升加载速度、防止被源站限流
- 支持两种展示模式:跨源按发布时间混排(时间线模式)、按订阅源分组展示
- 补全发布时间字段解析,支持跨源时间排序
完整实现代码
<?php class RssAggregator { private $feeds = []; private $cachePath; private $cacheTime = 600; // 缓存时长,单位秒,默认10分钟 /** * 初始化聚合器 * @param array $feeds 订阅源列表,格式:[['url'=>'rss地址', 'name'=>'源名称'], ...] * @param int $cacheTime 缓存时长 */ public function __construct(array $feeds, int $cacheTime = 600) { $this->feeds = $feeds; $this->cacheTime = $cacheTime; $this->cachePath = sys_get_temp_dir() . '/rss_agg_cache_' . md5(serialize($feeds)) . '.tmp'; } /** * 获取所有解析后的条目,优先读缓存 * @return array */ public function getItems(): array { // 缓存存在且未过期直接返回 if (file_exists($this->cachePath) && (time() - filemtime($this->cachePath)) < $this->cacheTime) { return json_decode(file_get_contents($this->cachePath), true) ?: []; } $allItems = []; // 开启XML内部错误捕获,避免解析警告直接输出 libxml_use_internal_errors(true); foreach ($this->feeds as $feed) { if (!isset($feed['url']) || empty($feed['url'])) continue; // 加载RSS内容 $rss = @simplexml_load_file($feed['url']); if (!$rss || !isset($rss->channel->item)) { // 该源解析失败,直接跳过 continue; } // 遍历当前源的条目 foreach ($rss->channel->item as $item) { $pubDate = strtotime((string)$item->pubDate) ?: time(); $allItems[] = [ 'title' => (string)$item->title, 'link' => (string)$item->link, 'description' => (string)$item->description, 'pub_date' => $pubDate, 'source_name' => $feed['name'] ?? '未知来源' ]; } } libxml_clear_errors(); // 按发布时间倒序排序 usort($allItems, function($a, $b) { return $b['pub_date'] - $a['pub_date']; }); // 写入缓存 file_put_contents($this->cachePath, json_encode($allItems), LOCK_EX); return $allItems; } /** * 按时间线混排渲染 * @param int $limit 最多显示条目数 * @return string */ public function renderTimeline(int $limit = 100): string { $items = array_slice($this->getItems(), 0, $limit); $html = '<div class="timeline-container">'; foreach ($items as $item) { $pubTime = date('Y-m-d H:i', $item['pub_date']); $html .= <<<HTML <div class="item"> <div class="meta"> <span class="source">{$item['source_name']}</span> <span class="time">{$pubTime}</span> </div> <a href="{$item['link']}" target="_blank">{$item['title']}</a> <hr> </div> HTML; } $html .= '</div>'; return $html; } /** * 按订阅源分组渲染 * @param int $perSourceLimit 每个源最多显示条目数 * @return string */ public function renderGrouped(int $perSourceLimit = 20): string { $items = $this->getItems(); $grouped = []; foreach ($items as $item) { $grouped[$item['source_name']][] = $item; } $html = '<div class="grouped-container">'; foreach ($grouped as $sourceName => $sourceItems) { $sourceItems = array_slice($sourceItems, 0, $perSourceLimit); $html .= '<div class="source-block"><div class="source-title">'.htmlspecialchars($sourceName).'</div><div class="links">'; foreach ($sourceItems as $item) { $html .= <<<HTML <div class="item"> <a href="{$item['link']}" target="_blank">{$item['title']}</a> <hr> </div> HTML; } $html .= '</div></div>'; } $html .= '</div>'; return $html; } } // 配置你的订阅源列表 $feedConfig = [ ['url' => 'https://rss.app/feeds/OzfHGFFGdG4RG4LV.xml', 'name' => '订阅源1'], // 在这里新增更多RSS源即可,格式同上 // ['url' => '第二个RSS地址', 'name' => '第二个源名称'], // ['url' => '第三个RSS地址', 'name' => '第三个源名称'], ]; // 初始化聚合器 $rss = new RssAggregator($feedConfig, 600); // 选择渲染模式:二选一即可 // 1. 时间线混排模式,最多显示200条 echo $rss->renderTimeline(200); // 2. 按源分组模式,每个源最多显示30条 // echo $rss->renderGrouped(30); ?>
使用说明
- 把所有需要展示的RSS地址按照示例格式填入
$feedConfig数组即可,没有数量限制 - 默认缓存时间10分钟,可根据自己的刷新需求修改
$cacheTime参数,单位为秒 - 长期运行在闲置显示器上建议搭配前端自动刷新(比如meta标签设置每10分钟刷新一次页面)即可实现信息流自动更新
- 只需要PHP默认开启的SimpleXML扩展即可运行,不需要安装任何额外组件
- 可根据自己的前端样式需求,修改两个render方法里的HTML结构和class类名,适配显示器的展示效果
内容的提问来源于stack exchange,提问作者Devalappar
相关产品推荐
相关产品推荐

