Home > front end >  How to display multiple RSS feeds using PHP?
How to display multiple RSS feeds using PHP?

Time:06-24

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:

  • Related