'http://feeds.feedburner.com/tekArtist', 'Slashdot' => 'http://rss.slashdot.org/Slashdot/slashdot', 'Digg' => 'http://www.digg.com/rss/index.xml', 'Google News' => 'http://news.google.com/?output=rss'); // Define items per page preferences // Start with a small number as a default view, because many // small devices have drastic memory requirements that lead // to easily lead to http errors (413: Request entity too large). // Options: 1, 5, 10, 15, 20 $minLimit = 1; $maxLimit = 25; $defaultLimit = 5; // Define how many character we want to see from each entry // description, to provide only an excerpt when the feed // publishes very long content. Number of characters to remain // after the description has been stripped of all HT/XML tags. $descLimit = 1024; ### END USER CONFIGURABLE OPTIONS ############################################# $defaultOffset = 0; define(COOKIE_DEFAULT_SOURCE, 'parseMe_defaultSource'); define(COOKIE_DEFAULT_LIMIT, 'parseMe_defaultLimit'); // start the xhtml interface print '<'.'?xml version="1.0"?'.">\n"; print "\n"; print "\n"; print "\n"; // Define a default xml source key $sourceKeys = array_keys($xmlSourceList); $defaultSource = $sourceKeys[0]; // Get and clean user input $sourceChoice = rawurldecode($_GET['src']); $limit = intval($_GET['lmt']); $offset = intval($_GET['ofst']); $saveDefault = intval($_GET['sv']); // If no valid source key choice, then use default if( ($sourceChoice == '') or (!isset($xmlSourceList[$sourceChoice])) ){ // see if the user has a saved preference (cookie) $userDefaultSource = $_COOKIE[COOKIE_DEFAULT_SOURCE]; if($userDefaultSource != ''){ if(isset($xmlSourceList[$userDefaultSource])){ $sourceChoice = $userDefaultSource; } } else{ $sourceChoice = $defaultSource; } } elseif($saveDefault > 0){ // if a source is submitted and valid, save // it as a new user default if requested. setcookie (COOKIE_DEFAULT_SOURCE, $sourceChoice, strtotime('5 years'), '/'); } // Get the url of the chosen source $xmlSource = $xmlSourceList[$sourceChoice]; // Cleanup the source key for display in the header $cleanSourceChoice = htmlspecialchars($sourceChoice); // Set page title and header $title .= $appName.' » '.$cleanSourceChoice; // Cleanup the selected page offset and item limit if( ($limit < $minLimit) or ($limit > $maxLimit) ){ // see if the user has a saved preference (cookie) $userDefaultLimit = $_COOKIE[COOKIE_DEFAULT_LIMIT]; if($userDefaultLimit != ''){ $limit = $userDefaultLimit; } else{ $limit = $defaultLimit; } } elseif($saveDefault > 0){ // if a limit is submitted and valid, save // it as a new user default if requested. setcookie (COOKIE_DEFAULT_LIMIT, $limit, strtotime('5 years'), '/'); } if( ($offset < 1) or ($offset > 100) ) $offset = $defaultOffset; // Print head block w/ defined and clean info print " \n"; print " {$title}\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; if(!file_exists($cacheDir)){ print "

Sorry, but the cache directory cannot be found.

\n"; print "

Please create a writable directory at {$cacheDir}.

\n"; } elseif(!is_dir($cacheDir)){ print "

Sorry, but the cache location is not a directory.

\n"; print "

Please create a writable directory at {$cacheDir}.

\n"; } elseif(!is_writable($cacheDir)){ print "

Sorry, but the cache directory is not writable.

\n"; print "

Please make the directory writable: {$cacheDir}.

\n"; } else{ // Define the name and location of the local xml cache file $cacheFileName = str_replace('%','_',rawurlencode($xmlSource)).'.cache.xml'; $cacheDestination = "./cache/{$cacheFileName}"; // Set the cache creation/modification time $cacheMtime = time(); // Define if we should get new content from the source, // or use the local cache instead if(!file_exists($cacheDestination)){ file_put_contents($cacheDestination, file_get_contents($xmlSource)); } elseif(filemtime($cacheDestination) < strtotime($cacheTTL.' ago')){ file_put_contents($cacheDestination, file_get_contents($xmlSource)); } else{ $cacheMtime = filemtime($cacheDestination); } // Load and test xml content from RSS or Atom feed if(($xml = simplexml_load_file($cacheDestination)) === false){ print "

Sorry, but \"{$cleanSourceChoice}\" cannot be parsed at this time.

\n"; } else{ // Use the ParseFeed function (see below) to parse // whichever xml format we got into a clean, standard // structure, taking in consideration the current // paging preferences (offset, limit) $displayData = ParseFeed($xml); // Print the file body header print "

" ."\"XML\"" ." " .$displayData['feedTitle']." " ."

\n"; // If we have any, loop on the entries if(count($displayData['feedEntries']) > 0){ print "
\n"; foreach($displayData['feedEntries'] as $entry){ print "
".$entry['title'] . "
\n"; print "
".$entry['description']."
\n"; } print "
\n"; } // Deal with the paging toolbar if($displayData['entryCount'] > $limit){ print "

| \n"; $link = $_SERVER['REQUEST_URI']; if(strstr($link, 'ofst=') === false) $link .= '?'; // "Previous" link if($offset > 0){ if(strstr($link, 'ofst=')) $link = preg_replace('/(\&ofst=\d{1,2})/','',$link); $link .= '&ofst='.($offset - $limit); print " « previous\n"; } // "Next" link if($displayData['entryCount'] > ($limit + $offset)){ if($offset > 0) print " | \n"; if(strstr($link, 'ofst=')) $link = preg_replace('/(\&ofst=\d{1,2})/','',$link); $link .= '&ofst='.($limit + $offset); print " next »\n"; } print " |

\n"; } // Print the cache specs print "

\n"; print " {$cleanSourceChoice} XML cached on ".date('Y-m-d \a\t H:i:s T',$cacheMtime)."
\n"; print " ".date('i \m\i\n. s \s\e\c.',( 1800 - (time() - $cacheMtime) ))." to refresh.
\n"; print " Powered by {$appName}\n"; print "

\n"; } // Now let's display the preference form // List the available sources print "
\n"; print "
\n"; print "
\n"; foreach($xmlSourceList as $sourceName => $sourceURL){ $checkedSource = ''; if($sourceName == $sourceChoice) $checkedSource = 'checked="checked"'; print " {$sourceName}
\n"; } print "
\n"; // List the available items per page limits $checkedLimit = ''; if($limit == $minLimit) $checkedLimit = 'checked="checked"'; print "
\n"; print " {$minLimit}\n"; for($i=5; $i<=$maxLimit; $i+=5){ $checkedLimit = ''; if($i == $limit) $checkedLimit = 'checked="checked"'; print " {$i}\n"; if($i % 10 != 0) print "
\n"; } // A submit button print "
\n"; // And for extra fluff, the "set as default" checkbox so users can save the // results of the form submission as the prefs when first accessing the script. print " Set as default
\n"; print "
\n"; print "
\n"; } // Close the xhtml file print " \n"; print "\n"; // And we're done with the processing! exit; // Now let's move on to the parsing functions /** * ParseFeed is a simple decisional wrapper. It simply * defines type of feed we are dealing with (RSS or Atom) * and calls the approriate xml parser. * * @param object $xml SimpleXML object (http://php.net/simplexml) * @return array $displayData Associative array to be used for display * * $displayData => feedTitle * ............ => feedLink * ............ => feedEntries => idx => link * .................................. => title * .................................. => description * ............ => entryCount */ function ParseFeed(&$xml){ $displayData = array(); if(isset($xml->channel)){ ParseRSS($xml, $displayData); } elseif(isset($xml->entry)){ ParseAtom($xml, $displayData); } return $displayData; } /** * ParseRSS, as the name implies, will parse an RSS * feed into the standard array we expect for display. * See http://en.wikipedia.org/wiki/RSS_%28file_format%29 * * @param object $xml RSS, SimpleXML object (http://php.net/simplexml) * @param array $displayData Empty array, see ParseFeed * @global int $limit Only list x items per page * @global int $offset Start listing from item number x * @global int $descLimit show only x characters from the descrition * @return array $displayData Associative array to be used for display */ function ParseRSS(&$xml, &$displayData){ global $limit, $offset, $descLimit; // Get the feed basic info $displayData['feedTitle'] = $xml->channel->title; $displayData['feedLink'] = $xml->channel->link; $displayData['feedEntries'] = array(); $displayData['entryCount'] = 0; // Test for the doc entries structure, depending on // the RSS version (items in/outside of channel) if(isset($xml->item)){ $feedEntries = $xml->item; } elseif(isset($xml->channel->item)){ $feedEntries = $xml->channel->item; } else{ $feedEntries = false; } // Loop on the found entries, based on paging prefs if(is_object($feedEntries)){ $displayData['entryCount'] = count($feedEntries); $i=0; foreach($feedEntries as $entry){ if($i >= $offset){ $displayData['feedEntries'][$i] = array(); $displayData['feedEntries'][$i]['link'] = $entry->link; $displayData['feedEntries'][$i]['title'] = $entry->title; $displayData['feedEntries'][$i]['description'] = substr(strip_tags(str_replace("\n",' ', $entry->description)),0,$descLimit); if(strlen($entry->description) >= $descLimit) $displayData['feedEntries'][$i]['description'] .= '...'; } $i++; if($i >= ($limit + $offset)) break; } } return $displayData; } /** * ParseAtom, as the name implies, will parse an Atom * feed into the standard array we expect for display. * See http://en.wikipedia.org/wiki/Atom_%28standard%29 * * @param object $xml Atom, SimpleXML object (http://php.net/simplexml) * @param array $displayData Empty array, see ParseFeed * @global int $limit Only list x items per page * @global int $offset Start listing from item number x * @global int $descLimit show only x characters from the descrition * @return array $displayData Associative array to be used for display */ function ParseAtom(&$xml, &$displayData){ global $limit, $offset, $descLimit; // Get the feed basic info $displayData['feedTitle'] = $xml->title; $feedLinkAttributes = $xml->link->attributes(); $displayData['feedLink'] = $feedLinkAttributes['href']; $displayData['feedEntries'] = array(); $displayData['entryCount'] = 0; // Test for the doc entries structure if(isset($xml->entry)){ $feedEntries = $xml->entry; } else{ $feedEntries = false; } // Loop on the found entries, based on paging prefs if(is_object($feedEntries)){ $displayData['entryCount'] = count($feedEntries); $i=0; foreach($feedEntries as $entry){ if($i >= $offset){ $displayData['feedEntries'][$i] = array(); $entryAttributes = $entry->link->attributes(); $displayData['feedEntries'][$i]['link'] = $entryAttributes['href']; $displayData['feedEntries'][$i]['title'] = $entry->title; $displayData['feedEntries'][$i]['description'] = substr(strip_tags(str_replace("\n",' ', $entry->content)),0,$descLimit); if(strlen($displayData['feedEntries'][$i]['description']) >= $descLimit) $displayData['feedEntries'][$i]['description'] .= strlen($entry->content).'...'; } $i++; if($i >= ($limit + $offset)) break; } } return $displayData; } // Fin - Still under 500 lines, despite all the inline comments. :) ?>