class myRSSParser { # keeps track of current and preceding elements var $tags = array(); # array containing all feed data var $output = array(); # return value for display functions var $retval = ""; # constructor for new object function myRSSParser($file) { # instantiate xml-parser and assign event handlers $xml_parser = xml_parser_create(""); xml_set_object($xml_parser, $this); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "parseData"); # open file for reading and send data to xml-parser $fp = @fopen($file, "r") or die("myRSSParser: Could not open $file for input"); while($data = fread($fp, 4096)) { xml_parse($xml_parser, $data, feof($fp)) or die( sprintf("myRSSParser: Error %s at line %d
", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser)) ); } fclose($fp); # dismiss xml parser xml_parser_free($xml_parser); } function startElement($parser, $tagname, $attrs=array()) { # RSS 2.0 - ENCLOSURE if($tagname == "ENCLOSURE" && $attrs) { $this->startElement($parser, "ENCLOSURE"); foreach($attrs as $attr => $attrval) { $this->startElement($parser, $attr); $this->parseData($parser, $attrval); $this->endElement($parser, $attr); } $this->endElement($parser, "ENCLOSURE"); } # check if this element can contain others - list may be edited if(preg_match("/^(RDF|RSS|CHANNEL|IMAGE|ITEM)/", $tagname)) { if($this->tags) { $depth = count($this->tags); list($parent, $num) = each($tmp = end($this->tags)); if($parent) $this->tags[$depth-1][$parent][$tagname]++; } array_push($this->tags, array($tagname => array())); } else { if(!preg_match("/^(A|B|I)$/", $tagname)) { # add tag to tags array array_push($this->tags, $tagname); } } } function endElement($parser, $tagname) { if(!preg_match("/^(A|B|I)$/", $tagname)) { # remove tag from tags array array_pop($this->tags); } } function parseData($parser, $data) { # return if data contains no text if(!trim($data)) return; $evalcode = "\$this->output"; foreach($this->tags as $tag) { if(is_array($tag)) { list($tagname, $indexes) = each($tag); $evalcode .= "[\"$tagname\"]"; if(${$tagname}) $evalcode .= "[" . (${$tagname} - 1) . "]"; if($indexes) extract($indexes); } else { if(preg_match("/^([A-Z]+):([A-Z]+)$/", $tag, $matches)) { $evalcode .= "[\"$matches[1]\"][\"$matches[2]\"]"; } else { $evalcode .= "[\"$tag\"]"; } } } eval("$evalcode = $evalcode . '" . addslashes($data) . "';"); } # display a single channel as HTML function display_channel($data, $limit) { extract($data); if($IMAGE) { # display channel image(s) foreach($IMAGE as $image) $this->display_image($image); } if($TITLE) { # display channel information $this->retval .= ""; if($LINK) $this->retval .= ""; $this->retval .= stripslashes($TITLE); if($LINK) $this->retval .= ""; $this->retval .= "
\n"; if($DESCRIPTION) $this->retval .= "$DESCRIPTION
\n\n"; $tmp = array(); if($PUBDATE) $tmp[] = "Published: $PUBDATE"; if($COPYRIGHT) $tmp[] = "Copyright: $COPYRIGHT"; if($tmp) $this->retval .= "" . implode("
\n\n"; } if($ITEM) { # display channel item(s) foreach($ITEM as $item) { $this->display_item($item, "CHANNEL"); if(is_int($limit) && --$limit retval .= "
\n", $tmp) . "\n\n"; $this->retval .= ""; if($LINK) $this->retval .= ""; $this->retval .= "
retval .= " width=\"$WIDTH\" height=\"$HEIGHT\""; $this->retval .= " border=\"0\" alt=\"$TITLE\">"; if($LINK) $this->retval .= ""; $this->retval .= "\n\n"; } # display a single item as HTML function display_item($data, $parent) { extract($data); if(!$TITLE) return; $this->retval .= "
"; if($LINK) $this->retval .= ""; $this->retval .= stripslashes($TITLE); if($LINK) $this->retval .= ""; $this->retval .= ""; if(!$PUBDATE && $DC["DATE"]) $PUBDATE = $DC["DATE"]; if($PUBDATE) $this->retval .= " ($PUBDATE)"; $this->retval .= "\n"; # use feed-formatted HTML if provided if($CONTENT["ENCODED"]) { $this->retval .= "
" . stripslashes($CONTENT["ENCODED"]) . "\n"; } elseif($DESCRIPTION) { $this->retval .= "
" . stripslashes($DESCRIPTION) . "\n\n"; } # RSS 2.0 - ENCLOSURE if($ENCLOSURE) { $this->retval .= "
Media: "; $this->retval .= $ENCLOSURE['TYPE']; $this->retval .= " ({$ENCLOSURE['LENGTH']} bytes)\n\n"; } if($COMMENTS) { $this->retval .= "
"; $this->retval .= "Comments"; $this->retval .= "\n\n"; } } function fixEncoding($input, $output_encoding) { if(!function_exists('mb_detect_encoding')) return $input; $encoding = mb_detect_encoding($input); switch($encoding) { case 'ASCII': case $output_encoding: return $input; case '': return mb_convert_encoding($input, $output_encoding); default: return mb_convert_encoding($input, $output_encoding, $encoding); } } # display entire feed as HTML function getOutput($limit=false, $output_encoding='UTF-8') { $this->retval = ""; $start_tag = key($this->output); switch($start_tag) { case "RSS": # new format - channel contains all foreach($this->output[$start_tag]["CHANNEL"] as $channel) { $this->display_channel($channel, $limit); } break; case "RDF:RDF": # old format - channel and items are separate if(isset($this->output[$start_tag]['IMAGE'])) { foreach($this->output[$start_tag]['IMAGE'] as $image) { $this->display_image($image); } } foreach($this->output[$start_tag]['CHANNEL'] as $channel) { $this->display_channel($channel, $limit); } foreach($this->output[$start_tag]['ITEM'] as $item) { $this->display_item($item, $start_tag); } break; case "HTML": die("Error: cannot parse HTML document as RSS"); default: die("Error: unrecognized start tag '$start_tag' in getOutput()"); } return $this->fixEncoding($this->retval, $output_encoding); } # return raw data as array function getRawOutput($output_encoding='UTF-8') { return $this->fixEncoding($this->output, $output_encoding); } }
Miután ezt felmásoltuk a szerverre jön maga a fájl, amely kiiratja az RSS hírforrást. Ebben a fájlban végezhetünk el különböző beállításokat értelemszerűen értelmezve a következő változókat:
$FEEDURL - Ez az RSS címe pl.: http://www.sg.hu/plain/rss.xml
$NUMITEMS - mennyi bejegyzést akarunk kilistázni
$TIMEFORMAT - a dátum milyen formában jelenjen meg.
$CACHEFILE - a letárolt tartalmat hova mentse a program (erre azért van szükség, hogy ne minden oldatelöltéskor szedjük le az RSS-t, mert az belassítaná a rendszert, hanem megadott időközönként frissítsünk csak)
$CACHETIME - milyen időközönként kapcsolódjon fel az RSS-re és szedje le az új bejegyzéseket.
Ennyit kell gyakorlatilag tudni a beállításokhoz most pedig lássuk a magát a kódot:
header('Content-Type: text/html; charset=utf-8'); # define script parameters $FEEDURL = "http://www.sg.hu/plain/rss.xml"; $NUMITEMS = 20; $TIMEFORMAT = "Y. F j., h:i"; $CACHEFILE = "/tmp/" . md5($FEEDURL); $CACHETIME = 1; # hours # download the feed iff a cached version is missing or too old if(!file_exists($CACHEFILE) || ((time() - filemtime($CACHEFILE)) > 3600 * $CACHETIME)) { if($feed_contents = @file_get_contents($FEEDURL)) { # write feed contents to cache file $fp = fopen($CACHEFILE, 'w'); fwrite($fp, $feed_contents); fclose($fp); } } include "rss.parser.php"; $rss_parser = new myRSSParser($CACHEFILE); # read feed data from cache file $feeddata = $rss_parser->getRawOutput(); extract($feeddata['RSS']['CHANNEL'][0], EXTR_PREFIX_ALL, 'rss'); # display leading image if(isset($rss_IMAGE[0]) && $rss_IMAGE[0]) { extract($rss_IMAGE[0], EXTR_PREFIX_ALL, 'img'); echo "
"; } # display feed title echo "
".htmlspecialchars($rss_TITLE)."
"; # display feed items $count = 0; foreach($rss_ITEM as $itemdata) { # article title echo "".htmlspecialchars(stripslashes($itemdata['TITLE']))."
"; # article description echo htmlspecialchars(stripslashes($itemdata['DESCRIPTION'])),"
\n"; # article date echo "",date($TIMEFORMAT, strtotime($itemdata['PUBDATE'])),"\n\n"; if(++$count >= $NUMITEMS) break; }
A php 27. sorától kezdve lehet szépítgetni a megjelenítést. A program, ha képet tlaál az RSS-ben az automatikusan kirakja, ezen felül kiírja az RSS címét a bejegyzések címeit leírásait és dátumát is.