I am making a personal feed to run on an unused monitor using PHP, and I want to display multiple RSS feeds simultaneously. Is that possible? This is my current code:
<?php
class rss
{
var $feed;
function rss($feed)
{
$this->feed = $feed;
}
function parse()
{
$rss = simplexml_load_file($this->feed);
$rss_split = array();
foreach ($rss->channel->item as $item) {
$title = (string) $item->title;
$link = (string) $item->link;
$description = (string) $item->description;
$rss_split[] = '<div >
<a href="'.$link.'" target="_blank" title="">'.$title.'</a>
<hr>
</div>';
}
return $rss_split;
}
function display($numrows,$head)
{
$rss_split = $this->parse();
$i = 0;
$rss_data = '<div >
<div >'.$head.'</div>
<div >';
while ( $i < $numrows )
{
$rss_data .= $rss_split[$i];
$i ;
}
$trim = str_replace('', '',$this->feed);
$user = str_replace('&lang=en-us&format=rss_200','',$trim);
$rss_data.='</div></div>';
return $rss_data;
}
}
$feedlist = new rss("https://rss.app/feeds/OzfHGFFGdG4RG4LV.xml");
echo $feedlist->display(1000,"");
?>
The only answer I could find on here was using SimplePie, but I would rather make it pure vanilla PHP even if it may be harder. Thanks.
CodePudding user response:
I would suggest first separating the display of the data from the retrieval of the data. Eg:
// this is important later
class RssInterface {
public function generateItems();
}
class Rss implements RssInterface {
protected $feed;
public function __construct($feed) {
// load the feed in the constructor so that relevant errors are raised immediately
$this->feed = simplexml_load_file($feed);
}
public function generateItems() {
foreach ($this->feed->channel->item as $item) {
yield $item;
}
}
}
class DisplayMyRss {
protected $rss;
public function __construct(RssInterface $rss) {
$this->rss = $rss;
}
public function asHtml() {
$out = '<div etc...>';
foreach( $rss->generateItems() as $item ) {
$out .= '<div etc...>';
// ...
$out .= '</div>';
}
$out .= '</div>';
}
}
So now you could do something like:
$feed = new Rss('https://example.com/rss1.xml');
$display = new DisplayMyRss($feed);
echo $display->asHtml();
Then we can wrap multiple RSS iterator classes in something like:
class MultiRss implements RssInterface {
protected $feeds = [];
public function __construct(array $feeds) {
foreach($feeds as $feed) {
$this->addFeed($feed);
}
}
// simply enforce that the items adhere to the interface
public function addFeed(RssInterface $feed) {
$this->feeds[] = $feed;
}
// adhere to the interface spec
public function generateItems() {
while( $this->hasValidIterators() ) {
yield $this->getNext();
}
}
// check if all the iterators have finished
protected function hasValidIterators() {
return ! empty(array_filter(array_map(function($f){return $f->valid;}, $this->feeds)));
}
// assumes lists are ordered ascending by $item->date, picks the earliest one and advances its iterator
protected function getNext() {
$next = NULL;
$feed_index = -1;
foreach( $this->feeds as $index => $feed ) {
if( ! $feed->valid ) { continue; } // skip finished iterators
$cur = $feed->cur;
if( $feed_index == -1 || $cur->date < $next->date ) {
$feed_index = $index;
}
}
$this->feeds[$next_index]->next();
return $next;
}
}
and still use the same classes and display logic:
$feeds = [
new Rss('https://example.com/rss1.xml'),
new Rss('https://example.com/rss2.xml')
];
$feed = new MultiRss($feeds);
$display = new DisplayMyRss($feed);
echo $display->asHtml();
Note that none of this code has actually been run or tested, it is straight off the top of my head and likely contains some bugs.
References: