This is a RSS (Really Simple Syndication) feed reader / parser class, written in PHP, compatible with PHP version 5 and later.

The original RSS reader / parser (rss_reader.php) was written by Richard James Kendall and can be downloaded from his web site at http://www.richardjameskendall.com.

This version is re-written as an Object-Oriented PHP class, and has been reorganized to be more functional and robust, and to eliminate problems with the original implementation which caused pollution of the global namespace and potential function naming conflicts with other XML parsing code within the same PHP page.

Here is the code:

<?php
    
/**
    * <blockquote>
    * PHP RSS Reader v1.1
    * By Richard James Kendall
    * Bugs to richard@richardjameskendall.com
    * Free to use, please acknowledge me
    *
    * Added CSS class names and offset,limit item paging functionality.
    * - Ron Cemer, Feb 13 2006.
    * http://www.roncemer.com
    * http://www.cemer.com
    * http://www.crosswordlovers.com
    *
    * Converted to a proper PHP class and added phpDocumentor comments.
    * - Ron Cemer, Jul 25, 2006.
    *
    * How to use this script:
    *
    * Create an instance of the class.
    *
    * Set member variables to control behavior (optional).
    *
    * Call read($url, $itemOffset, $itemLimit) function.
    *
    *   For example:
    *  $rssReader = new RSSReader();
    *  $rssReader->outputChannelTitleHTML = false;
    *  $rssReader->outputChannelDescriptionHTML = false;
    *  $rssReader->read(’http://news.search.yahoo.com/news/rss?p=automobiles+cars&ei=UTF-8′);
    *
    * The read() function returns an array that is filled with data from the feed.
    * Every RSS feed is different but by and large it should contain:
    * Array {
    *  [TITLE] = feed title
    *  [DESCRIPTION] = feed description
    *  [LINK] = link to their website
    *
    *  [IMAGE] = Array {
    *     [URL] = url of image
    *     [DESCRIPTION] = alt text of image
    *    }
    *
    *  [ITEMS] = Array {
    *     [0] = Array {
    *       [TITLE] = item title
    *       [DESCRIPTION] = item description
    *       [LINK = a link to the story
    *      }
    *     .
    *     .
    *     .
    *    }
    * }
    *
    * $itemOffset is the number of initial stories to skip.  The default is
    * to NOT skip any initial stories.
    *
    * $itemLimit is the maximum number of stories to return, after optionally
    * skipping a number of initial stories (see above).  If zero (the default),
    * all (remaining) stories are returned (and optionally output as HTML).
    *
    * If $outputHTML member variable evaluates to true (the default), the
    * stor(y/ies) will be output in HTML.
    *
    * If outputting HTML, $outputChannelTitleHTML controls whether to output
    * the channel title.  true (the default) means output the channel title.
    *
    * If outputting HTML, $outputChannelDescriptionHTML controls whether to
    * output the channel description.  true (the default) means output the channel
    * description.
    *
    * The HTML elements which are output (if outputting HTML), can be styled
    * using CSS classes.  Here is an example of the HTML which is output by
    * default (extra junk removed and remainder reformatted for readability):
    *
    * &lt;div class=”rssChannelTitle”&gt;
    *  &lt;a class=”rssChannelHref” …&gt;
    *  &lt;img class=”rssChannelImg” …&gt;
    *  &lt;/a&gt;
    *  &lt;br&gt;
    *  &lt;span class=”rssChannelName”&gt;Slashdot&lt;/span&gt;
    * &lt;/div&gt;
    * &lt;div class=”rssChannelDescription”&gt;
    *  &lt;i&gt;News for nerds, stuff that matters&lt;/i&gt;
    * &lt;/div&gt;
    * &lt;div class=”rssItem”&gt;
    *  &lt;a class=”rssItemHeadlineHref” …&gt;
    *  &lt;h2 class=”rssItemTitle”&gt;(First item title goes here)&lt;/h2&gt;
    *  &lt;/a&gt;
    *  (First item text goes here)
    *  &lt;br&gt;
    *  &lt;a class=”rssItemFullStoryHref” …&gt;Full Story&lt;/a&gt;
    * &lt;/div&gt;
    * &lt;div class=”rssItem”&gt;
    *  &lt;a class=”rssItemHeadlineHref” …&gt;
    *  &lt;h2 class=”rssItemTitle”&gt;(Second item title goes here)&lt;/h2&gt;
    *  &lt;/a&gt;
    *  (Second item text goes here)
    *  &lt;br&gt;
    *  &lt;a class=”rssItemFullStoryHref” …&gt;Full Story&lt;/a&gt;
    * &lt;/div&gt;
    *</blockquote>
    */
    
class RSSReader {
        
/**
        * boolean true (the default) to output the selected items as HTML.
        */
        
public $outputHTML true;
        
/**
        * boolean true (the default) to output the channel title.  Only applies
        * when outputting HTML.
        */
        
public $outputChannelTitleHTML true;
        
/**
        * boolean true (the default) to output the channel description.  Only applies
        * when outputting HTML.
        */
        
public $outputChannelDescriptionHTML true;
         
        private 
$currentlyWriting;
        private 
$main;
        private 
$itemCounter;
        private 
$channelData;
         
        
/**
        * Read an RSS feed, and optionally output it as HTML.
        * @param $url string The URL for the RSS feed.
        * @param $itemOffset int The number of initial items to skip, or <code>0</code>
        * (the default) to start reading at the first item.
        * @param $itemLimit int The maximum number of items to read (after optionally
        * skipping the specified number of initial items), or <code>0</code> (the
        * default) to read all remaining items in the feed.
        * @return array An associative array, in the following (general) format (contents
        * may vary slightly by feed):<br>
        *<blockquote>
        * Array {
        * [TITLE] = feed title
        * [DESCRIPTION] = feed description
        * [LINK] = link to their website
        *
        * [IMAGE] = Array {
        *    [URL] = url of image
        *    [DESCRIPTION] = alt text of image
        *   }
        *
        * [ITEMS] = Array {
        *    [0] = Array {
        *      [TITLE] = item title
        *      [DESCRIPTION] = item description
        *      [LINK = a link to the story
        *     }
        *    .
        *    .
        *    .
        *   }
        * }
        *</blockquote>
        */
        
public function read($url$itemOffset 0$itemLimit 0) {
            
$this->currentlyWriting ‘’;
            
$this->main ‘’;
            
$this->itemCounter 0;
            
$this->channelData = array();
             
            
$xmlParser xml_parser_create();
            
xml_set_object($xmlParser$this);
            
xml_set_element_handler($xmlParser’startElement’‘endElement’);
            
xml_set_character_data_handler($xmlParser‘characterData’);
            if (!(
$fp fopen($url‘r’))) {
                die(
“RSSReader: Could not open XML input: $url”);
            }
             
            while (
$data fread($fp4096)) {
                if (!
xml_parse($xmlParser$datafeof($fp))) {
                    
fclose($fp);
                    
$errorCode xml_get_error_code($xmlParser);
                    
$lineNumber xml_get_current_line_number($xmlParser);
                    
xml_parser_free($xmlParser);
                    die(
sprintf(
                    
‘XML error: %s at line %d; url %s’,
                        
xml_error_string($errorCode),
                        
$lineNumber,
                        
$url));
                }
            }
            
fclose($fp);
            
xml_parser_free($xmlParser);
             
            if (isset(
$this->channelData[‘ITEMS’])) {
                if (
$itemOffset >= 1) {
                    if (
$itemOffset >= count($this->channelData[‘ITEMS’])) {
                        
$this->channelData[‘ITEMS’] = array();
                    } else {
                        
array_splice($this->channelData[‘ITEMS’], 0$itemOffset);
                    }
                }
                if (
$itemLimit >= 1) {
                    
array_splice($this->channelData[‘ITEMS’], $itemLimit);
                }
                
// Decode HTML entities within the descriptions.
                
for ($i 0$n count($this->channelData[‘ITEMS’]); $i $n$i++) {
                    if (isset(
$this->channelData[‘ITEMS’][$i][‘description’])) {
                        
$this->channelData[‘ITEMS’][$i][‘description’] = htmlspecialchars_decode($this->channelData[‘ITEMS’][$i][‘description’]);
                    }
                }
            }
             
            if (
$this->outputHTML$this->outputHTML($this->channelData);
                return 
$this->channelData;
        }
         
        
/**
        * Output RSS data from an associative array as HTML.
        * @param $channelData array An associative array of channel data, as returned
        * from the <code>read($url, $itemOffset, $itemLimit)</code> function.
        */
        
public function outputHTML($channelData) {
            if (
$this->outputChannelTitleHTML) {
                print(
‘<div class=”rssChannelTitle”>’);
                if (isset(
$channelData[‘IMAGE’])) {
                    print(
                    
‘<a class=”rssChannelHref” href=”‘ $channelData[‘LINK’] . ‘” target=”_blank”><img class=”rssChannelImg” border=”0″ src=”‘ $channelData[‘IMAGE’][‘URL’] . ‘” align=”middle” alt=”‘ $channelData[‘IMAGE’][‘TITLE’] . ‘”></a><br>’);
                }
                print(
‘<span class=”rssChannelName”>’ $channelData[‘TITLE’] . ‘</span>’);
                print(
‘</div>’ “\n”);
            }
            if (
$this->outputChannelDescriptionHTML) {
                print(
                
‘<div class=”rssChannelDescription”><i>’ $channelData[‘DESCRIPTION’] . ‘</i></div>’ “\n”);
            }
            if (isset(
$channelData[‘ITEMS’])) {
                for (
$i 0$n count($channelData[‘ITEMS’]); $i $n$i++) {
                    print (
‘<div class=”rssItem”>’);
                    if (isset(
$channelData[‘ITEMS’][$i][‘LINK’])) {
                        print(
                        
‘<a class=”rssItemHeadlineHref” href=”‘ $channelData[‘ITEMS’][$i][‘LINK’] . ‘” target=”_blank”><h2 class=”rssItemTitle”>’ $channelData[‘ITEMS’][$i][‘TITLE’] . ‘</h2></a>’);
                    }
                    print(
$channelData[‘ITEMS’][$i][‘DESCRIPTION’]);
                    if (isset(
$channelData[‘ITEMS’][$i][‘LINK’])) {
                        print(
                        
‘<br><a class=”rssItemFullStoryHref” href=”‘ $channelData[‘LINK’] . ‘” target=”_blank”>Full Story</a>’);
                    }
                    print(
‘</div>’ “\n”);
                }
            }
        }
         
        function 
startElement($parser$name$attrs) {
            switch(
$name) {
                case 
‘RSS’:
                case 
‘RDF:RDF’:
                case 
‘ITEMS’:
                
$this->currentlyWriting ‘’;
                break;
                case 
‘CHANNEL’:
                
$this->main ‘CHANNEL’;
                break;
                case 
‘IMAGE’:
                
$this->main ‘IMAGE’;
                
$this->channelData[‘IMAGE’] = array();
                break;
                case 
‘ITEM’:
                
$this->main ‘ITEMS’;
                break;
                default:
                
$this->currentlyWriting $name;
                break;
            }
        }
         
        function 
endElement($parser$name) {
            
$this->currentlyWriting ‘’;
            if (
$name == ‘ITEM’) {
                
$this->itemCounter++;
            }
        }
         
        function 
characterData($parser$data) {
            if (
$this->currentlyWriting != ‘’) {
                switch(
$this->main) {
                    case 
‘CHANNEL’:
                    if (isset(
$this->channelData[$this->currentlyWriting])) {
                        
$this->channelData[$this->currentlyWriting] .= $data;
                    } else {
                        
$this->channelData[$this->currentlyWriting] = $data;
                    }
                    break;
                    case 
‘IMAGE’:
                    if (isset(
$this->channelData[$this->main][$this->currentlyWriting])) {
                        
$this->channelData[$this->main][$this->currentlyWriting] .= $data;
                    } else {
                        
$this->channelData[$this->main][$this->currentlyWriting] = $data;
                    }
                    break;
                    case 
‘ITEMS’:
                    if (isset(
$this->channelData [$this->main] [$this->itemCounter][$this->currentlyWriting])) {
                        
$this->channelData [$this->main] [$this->itemCounter][$this->currentlyWriting] .= $data;
                    } else {
                        
$this->channelData [$this->main] [$this->itemCounter][$this->currentlyWriting] = $data;
                    }
                    break;
                }
            }
        }
    }
?>