<?php
/*
Plugin Name: jRSS
Plugin URI: http://jakobj.dk/blog/archives/35?lan=english
Description: Easy and stable displaying of feeds from other sites (Widget capable). Requires PHP5 and support the following types of feeds Atom, Feedburner, RSS0.91, RSS0.92, RSS2.0 and RDF/RSS1.0.
Author: Jakob Jensen
Version: 2.1
Author URI: http://jakobj.dk/blog/
Copyright 2006 Jakob Jensen (email : jakobj@jakobj.dk)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
== Installation ==
1. Upload this file to your /wp-content/plugins/widget/ folder.
2. Create, if it doesn't already exist, the folder /wp-content/plugins/cache/.
3. Chmod the newly-created folder to 777 (full access).
4. Look at Usage Examples to find out how to use it or if your theme supports it, use the menu item 'Presentation > Sidebar Widgets'. :)
== Usage Examples ==
<?php
$rss = new jRSS();
$rss->display('http://jakobj.dk/blog/feed/rss/');
$rss->display('http://jakobj.dk/blog/feed/rss/', 'items:3, customheading:Creator of jRSS, showdate:false, showdesc:false, updateRatio:60, type:RSS');
$rss->display('http://jakobj.dk/blog/feed/rss/', 'charset:UTF-8, cssclass:jrss, items:3, customheading:Creator of jRSS, showdate:true, dateformat:Y/m/j, shortdesc:100, updateRatio:30, type:RSS');
?>
== Notes ==
- RSS0.91 will never display a date, because a RSS0.91 feed does not contain a date.
*/
// fatal check for PHP5
if (substr(phpversion(), 0, 1) != 5)
{
trigger_error("<p><b>(jRSS) Fatal Error:</b><br />Plugin needs PHP5</p>", E_USER_ERROR);
//Failsafe. In case errors have been disabled.
echo "<p><b>(jRSS) Fatal Error:</b><br />Plugin needs PHP5</p>";
exit();
//End failsafe.
}
class jRSS
{
private $config;
private $feedLocation;
private $writableCache;
private $error;
public function __construct()
{
$this->error = false;
if (!defined('ABSPATH'))
{
$this->err_(1);
return false;
}
$this->writableCache = false;
if (!is_dir(ABSPATH .'/wp-content/plugins/cache/'))
{
if (!@mkdir(ABSPATH .'/wp-content/plugins/cache/', 0777))
{
$this->err_(2);
return false;
}
}
if (is_dir(ABSPATH .'/wp-content/plugins/cache/'))
{
if (@fclose(@fopen(ABSPATH .'/wp-content/plugins/cache/writeTest.jRSS', "w+")))
{
@chmod(ABSPATH .'/wp-content/plugins/cache/writeTest.jRSS', 0600);
$this->writableCache = true;
}
else
{
$this->err_(0);
return false;
}
}
if (!@ini_get('allow_url_fopen') && !@function_exists('curl_init'))
{
$this->err_(7);
return false;
}
return true;
}
private function setCache()
{
if (!$this->writableCache)
{
$this->err_(0);
return false;
}
if (!$feedStr = @file_get_contents($this->feedLocation))
{
if ($ch = @curl_init())
{
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@curl_setopt($ch, CURLOPT_USERAGENT, 'jRSS wordpress plugin');
@curl_setopt($ch, CURLOPT_URL, $this->feedLocation);
$feedStr = @curl_exec($ch);
@curl_close($ch);
}
}
if (!$feedStr)
{
$this->err_(5);
return false;
}
if (!$feedObj = @simplexml_load_string($feedStr))
{
$this->err_(5);
return false;
}
if ((isset($this->config['type']) && strtolower($this->config['type']) == 'auto') || !isset($this->config['type']))
{
$snippet = substr($feedStr, 0, 250);
$longsnippet = substr($feedStr, 0, 500);
if (stripos($snippet, '<rss') !== false)
{
$this->config['type'] = 'rss';
}
else if (stripos($snippet, '<rdf') !== false)
{
$this->config['type'] = 'rdf';
}
else if (stripos($longsnippet, 'xmlns:feedburner') !== false)
{
$this->config['type'] = 'feedburner';
}
else if (stripos($snippet, '<feed') !== false)
{
$this->config['type'] = 'atom';
}
}
$items = array();
$feed = array();
switch (strtolower($this->config['type']))
{
case 'rss':
foreach($feedObj->channel->item as $item)
{
array_push($items, array('title' => (string) $item->title, 'link' => (string) $item->link, 'description' => (string) $item->description));
}
$feed['title'] = (string) $feedObj->channel->title;
$feed['link'] = (string) $feedObj->channel->link;
$feed['description'] = (string) $feedObj->channel->description;
$date = (string) $feedObj->channel->lastBuildDate;
$feed['date'] = (int) (empty($date)) ? 0 : strtotime($date);
break;
case 'rdf':
foreach($feedObj->item as $item)
{
array_push($items, array('title' => (string) $item->title, 'link' => (string) $item->link, 'description' => (string) $item->description));
}
$feed['title'] = (string) $feedObj->channel->title;
$feed['link'] = (string) $feedObj->channel->link;
$feed['description'] = (string) $feedObj->channel->description;
// RDF/RSS1.0 has a <dc:date> which simplexml_load_file has a problem with, hence the hack below.
$offsetx = strpos($feedStr, '<dc:date>');
$offsety = strpos($feedStr, '</dc:date>', $offsetx);
$length = $offsety - $offsetx;
$date = (string) substr($feedStr, $offsetx, $length);
$y = substr($date, 9, 4);
$m = substr($date, 14, 2);
$d = substr($date, 17, 2);
$h = substr($date, 20, 2);
$i = substr($date, 23, 2);
$s = substr($date, 26, 2);
$date = mktime($h, $i, $s, $m, $d, $y);
// End hack.
$feed['date'] = (int) (empty($date)) ? 0 : date($date);
break;
case 'atom':
foreach($feedObj->entry as $item)
{
array_push($items, array('title' => (string) $item->title, 'link' => (string) $item->link['href'], 'description' => (string) $item->summary));
}
$feed['title'] = (string) $feedObj->title;
$feed['link'] = (string) $feedObj->link['href'];
$feed['description'] = (string) $feedObj->tagline;
$date = (string) $feedObj->modified;
$feed['date'] = (int) (empty($date)) ? 0 : strtotime($date);
break;
case 'feedburner':
foreach($feedObj->entry as $item)
{
array_push($items, array('title' => (string) $item->title, 'link' => (string) $item->link['href'], 'description' => (string) $item->summary));
}
$feed['title'] = (string) $feedObj->title;
$feed['link'] = (string) $feedObj->link['href'];
$feed['description'] = (string) $feedObj->tagline;
$date = (string) $feedObj->updated;
$feed['date'] = (int) (empty($date)) ? 0 : strtotime($date);
break;
default:
foreach($feedObj->channel->item as $item)
{
array_push($items, array('title' => (string) $item->title, 'link' => (string) $item->link, 'description' => (string) $item->description));
}
$feed['title'] = (string) $feedObj->channel->title;
$feed['link'] = (string) $feedObj->channel->link;
$feed['description'] = (string) $feedObj->channel->description;
$feed['date'] = (int) $feedObj->channel->lastBuildDate;
break;
}
$feed['items'] = $items;
$handle = @fopen(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS', "w");
if (@fwrite($handle, serialize($feed)))
{
@chmod(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS', 0600);
@fclose($handle);
return true;
}
else
{
$this->err_(0);
return false;
}
}
private function getCached()
{
if (!isset($this->config['updateratio']) || !$this->config['updateratio'])
{
$this->config['updateratio'] = 15;
}
if ((file_exists(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS') && filemtime(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS') < time()-($this->config['updateratio']*60)) || !file_exists(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS'))
{
$this->setCache();
}
if (!$feed = @unserialize(@file_get_contents(ABSPATH .'/wp-content/plugins/cache/'. md5($this->feedLocation . $this->config['type']) .'.jRSS')))
{
$this->err_(5);
return false;
}
return $feed;
}
private function setCharset($text)
{
if (!isset($this->config['charset']))
{
return strip_tags($text);
}
switch (strtolower($this->config['charset']))
{
case 'utf-8':
break;
case 'iso-8859-1':
$text = utf8_decode($text);
break;
}
return strip_tags($text);
}
private function wrapper()
{
if (!$feed = $this->getCached())
{
$this->err_(6);
return false;
}
if (isset($this->config['debug']) && $this->config['debug']) {
// "hidden feature"
echo '<pre>';
echo "Configuration:\n";
var_dump($this->config);
echo "\nLoaded ". $this->feedLocation .":\n";
var_dump($feed);
echo '</pre>';
return true;
// end hidden feature
}
printf("\n", null);
printf('<div class="%1$s">', $this->config['cssclass']);
if (isset($this->config['customheading']) && $this->config['customheading'])
{
printf('<h3 class="%1$s">%2$s</h3>', $this->config['cssclass'], $this->config['customheading']);
}
else
{
printf('<h3 class="%1$s">%2$s</h3>', $this->config['cssclass'], $this->setCharset($feed['title']));
}
if (isset($this->config['showdate']) && $this->config['showdate'] && $feed['date'])
{
$dateformat = (isset($this->config['dateformat'])) ? $this->config['dateformat'] : 'Y-m-j';
printf('<div><small>%1$s</small></div>', date($dateformat, $feed['date']));
}
printf('<ol class="%1$s">', $this->config['cssclass']);
$amount = (isset($this->config['items'])) ? $this->config['items'] : 5;
$items = @array_slice($feed['items'], 0, $amount);
foreach($items as $item)
{
if (isset($this->config['showdesc']) && $this->config['showdesc'])
{
$desc = (isset($this->config['shortdesc']) && $this->config['shortdesc']) ? substr($item['description'], 0, $this->config['shortdesc']) .'...' : $item['description'];
printf('<li><a href="%1$s">%2$s</a><br />%3$s</li>', $this->setCharset($item['link']), $this->setCharset($item['title']), $this->setCharset($desc));
}
else
{
printf('<li><a href="%1$s">%2$s</a></li>', $this->setCharset($item['link']), $this->setCharset($item['title']));
}
}
printf('</ol>', null);
printf('</div>', null);
printf("\n", null);
return true;
}
public function widget($feedLocation, $configString = '')
{
if ($this->error || !$this->parseData($feedLocation, $configString)) return false;
if (!$feed = $this->getCached())
{
$this->err_(6);
return false;
}
$output = array();
if (isset($this->config['customheading']) && $this->config['customheading'])
{
$output['title'] = $this->config['customheading'];
}
else
{
$output['title'] = $this->setCharset($feed['title']);
}
$output['jrss'] = '<div class="jRSS">';
if (isset($this->config['showdate']) && $this->config['showdate'] && $feed['date'])
{
$dateformat = (isset($this->config['dateformat'])) ? $this->config['dateformat'] : 'Y-m-j';
$output['jrss'] .= '<small>'. date($dateformat, $feed['date']) .'</small>';
}
$output['jrss'] .= '<ol>';
$amount = (isset($this->config['items'])) ? $this->config['items'] : 5;
$items = @array_slice($feed['items'], 0, $amount);
foreach($items as $item)
{
if (isset($this->config['showdesc']) && $this->config['showdesc'])
{
$desc = (isset($this->config['shortdesc']) && $this->config['shortdesc']) ? substr($item['description'], 0, $this->config['shortdesc']) .'...' : $item['description'];
$output['jrss'] .= sprintf('<li><a href="%1$s">%2$s</a><br />%3$s</li>', $this->setCharset($item['link']), $this->setCharset($item['title']), $this->setCharset($desc));
}
else
{
$output['jrss'] .= sprintf('<li><a href="%1$s">%2$s</a></li>', $this->setCharset($item['link']), $this->setCharset($item['title']));
}
}
$output['jrss'] .= '</ol><div>';
return $output;
}
public function display($feedLocation, $configString = '')
{
if ($this->error || !$this->parseData($feedLocation, $configString)) return false;
return $this->wrapper();
}
private function parseData($feedLocation, $configString)
{
if (empty($feedLocation))
{
$this->err_(4);
return false;
}
$config = array();
$bits = explode(',', $configString);
foreach($bits as $bit)
{
$set = explode(':', $bit);
switch (strtolower(trim($set[0])))
{
case 'items':
$config['items'] = (int) trim($set[1]);
break;
case 'customheading':
$config['customheading'] = (string) trim($set[1]);
break;
case 'cssclass':
$config['cssclass'] = (string) trim($set[1]);
break;
case 'charset':
$config['charset'] = (string) trim($set[1]);
break;
case 'type':
$config['type'] = (string) trim($set[1]);
break;
case 'dateformat':
$config['dateformat'] = (string) trim($set[1]);
break;
case 'showdate':
$config['showdate'] = (strtolower(trim($set[1]))!='false') ? true : false;
break;
case 'showdesc':
$config['showdesc'] = (strtolower(trim($set[1]))!='false') ? true : false;
break;
case 'shortdesc':
$config['shortdesc'] = (int) trim($set[1]);
break;
case 'updateratio':
$config['updateratio'] = (int) trim($set[1]);
break;
// "hidden feature"
case 'debug':
$config['debug'] = (strtolower(trim($set[1]))!='false') ? true : false;
break;
// end hidden feature
}
}
$this->config = $config;
$this->feedLocation = $feedLocation;
return true;
}
private function err_($type)
{
echo "<p><b>(jRSS) Fatal Error:</b><br />";
switch($type)
{
case 0:
echo "Cache is not writeable!";
break;
case 1:
echo "Plugin was not called inside WordPress!";
break;
case 2:
echo "Cache folder does not exist!";
break;
//outdated, since feed now defaults to rss.
case 3:
echo "Type of feed is unknown!";
break;
//end outdated
case 4:
echo "No feed location given!";
break;
case 5:
echo "Feed location unreadable!";
break;
case 6:
echo "No feed was displayed!";
break;
case 7:
echo "PHP configuration does not allow opening urls and cUrl is not available!";
break;
}
echo "</p>";
$this->error = true;
return true;
}
}
function widget_jrss_init()
{
if ( !function_exists('register_sidebar_widget') || !function_exists('register_widget_control') )
{
return;
}
function widget_jrss($args)
{
extract($args);
$options = get_option('widget_jrss');
$url = empty($options['url']) ? '' : $options['url'];
$conf = empty($options['conf']) ? '' : $options['conf'];
$jrss = new jRSS();
$result = $jrss->widget($url, $conf);
echo $before_widget;
echo $before_title . $result['title'] . $after_title;
echo $result['jrss'];
echo $after_widget;
}
function widget_jrss_control() {
$options = get_option('widget_jrss');
if ( $_POST['jrss-submit'] )
{
$newoptions['url'] = strip_tags(stripslashes($_POST['jrss-url']));
$newoptions['conf'] = strip_tags(stripslashes($_POST['jrss-conf']));
}
if ( $options != $newoptions )
{
$options = $newoptions;
update_option('widget_jrss', $options);
}
$url = htmlspecialchars($options['url'], ENT_QUOTES);
$conf = htmlspecialchars($options['conf'], ENT_QUOTES);
?>
<div>
<label for="jrss-url" style="line-height:35px;display:block;">Widget url: <input type="text" id="jrss-url" name="jrss-url" value="<?php echo&nb