From: poltawski Date: Wed, 29 Jul 2009 13:44:28 +0000 (+0000) Subject: block_rss_client: MDL-13932/MDL-7946 - Switch to use Simplepie X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=0864a0837bcfd80689fc943acd7a59b23f9c8cd1;p=moodle.git block_rss_client: MDL-13932/MDL-7946 - Switch to use Simplepie Simplepie is actively maintained and supports a broader range of feeds --- diff --git a/blocks/rss_client/block_rss_client.php b/blocks/rss_client/block_rss_client.php index 36c454b53d..1241be364c 100644 --- a/blocks/rss_client/block_rss_client.php +++ b/blocks/rss_client/block_rss_client.php @@ -1,20 +1,28 @@ -. /** - * This class is for a block which defines a block for display on - * any Moodle page. + * A block which displays Remote feeds + * + * @package rss_client + * @copyright Daryl Hawes + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL */ + class block_rss_client extends block_base { function init() { @@ -43,81 +51,70 @@ } function get_content() { - global $CFG, $editing, $USER; - - if (!empty($this->page->course)) { - $this->courseid = $this->page->course->id; - } - - /// When displaying feeds in block, we double $CFG->block_rss_client_timeout - /// so those feeds retrieved and cached by the cron() process will have a - /// better chance to be used - if (!empty($CFG->block_rss_client_timeout)) { - $CFG->block_rss_client_timeout *= 2; - } - - require_once($CFG->libdir .'/rsslib.php'); + global $CFG, $DB; - if($this->content !== NULL) { + if ($this->content !== NULL) { return $this->content; } + // initalise block content object $this->content = new stdClass; $this->content->text = ''; $this->content->footer = ''; if (empty($this->instance)) { - // We're being asked for content without an associated instance return $this->content; } - $output = ''; - $rssid = -1; - $display_description = false; - if (isset($CFG->block_rss_client_num_entries) && is_numeric($CFG->block_rss_client_num_entries) ) { - $shownumentries = intval($CFG->block_rss_client_num_entries); - } else { - $shownumentries = 5; //default to 5 entries is not specified in admin section or instance - } + if (!isset($this->config)) { + // The block has yet to be configured - just display configure message in + // the block if user has permission to configure it + + if (has_capability('block/rss_client:manageanyfeeds', $this->context)) { + $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client'); + } - if (empty($this->config)) { - $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client'); return $this->content; } + // How many feed items should we display? + $maxentries = 5; + if ( !empty($this->config->shownumentries) ) { + $maxentries = intval($this->config->shownumentries); + }elseif( isset($CFG->block_rss_client_num_entries) ) { + $maxentries = intval($CFG->block_rss_client_num_entries); + } + + + /* --------------------------------- + * Begin Normal Display of Block Content + * --------------------------------- */ + + $output = ''; + + if (!empty($this->config->rssid)) { - if (is_array($this->config->rssid)) { - $rssidarray = $this->config->rssid; - } else { // Make an array of the single value - $rssidarray = array($this->config->rssid); + list($rss_ids_sql, $params) = $DB->get_in_or_equal($this->config->rssid); + + $rss_feeds = $DB->get_records_select('block_rss_client', "id $rss_ids_sql", $params); + + $showtitle = false; + if (count($rss_feeds) > 1) { + // when many feeds show the title for each feed + $showtitle = true; } - } - if (!empty($this->config->display_description)) { - $display_description = intval($this->config->display_description); - } - if (!empty($this->config->shownumentries)) { - $shownumentries = intval($this->config->shownumentries); - } - // Daryl Hawes note: if count of rssidarray is greater than 1 - // we should possibly display a drop down menu of selected feed titles - // so user can select a single feed to view (similar to RSSFeed) - if (!empty($rssidarray)) { - $numids = count($rssidarray); - $count = 0; - foreach ($rssidarray as $rssid) { - $output .= $this->get_rss_by_id($rssid, $display_description, $shownumentries, ($numids > 1) ? true : false); - if ($numids > 1 && $count != $numids -1 && !empty($rssfeedstring)) { - $output .= '
'; - } - $count ++; + foreach($rss_feeds as $feed){ + $output.= $this->get_feed_html($feed, $maxentries, $showtitle); } } $this->content->text = $output; + return $this->content; } + function instance_allow_multiple() { return true; } @@ -131,127 +128,145 @@ } /** - * @param int $rssid The feed to be displayed - * @param bool $display_description Should the description information from the feed be displayed or simply the title? - * @param int $shownumentries The maximum number of feed entries to be displayed. - * @param bool $showtitle True if the feed title should be displayed above the feed entries. - * @return string|NULL + * Returns the html of a feed to be displaed in the block + * + * @param mixed feedrecord The feed record from the database + * @param int maxentries The maximum number of entries to be displayed + * @param boolean showtitle Should the feed title be displayed in html + * @return string html representing the rss feed content */ - function get_rss_by_id($rssid, $display_description, $shownumentries, $showtitle=false) { - global $CFG, $DB; - $returnstring = ''; - $now = time(); - require_once($CFG->libdir .'/rsslib.php'); - require_once(MAGPIE_DIR .'rss_fetch.inc'); - - $rss_record = $DB->get_record('block_rss_client', array('id'=>$rssid)); - if (isset($rss_record) && isset($rss_record->id)) { - // By capturing the output from fetch_rss this way - // error messages do not display and clutter up the moodle interface - // however, we do lose out on seeing helpful messages like "cache hit", etc. - ob_start(); - $rss = fetch_rss($rss_record->url); - $rsserror = ob_get_contents(); - ob_end_clean(); - - if ($rss === false) { - debugging($rsserror); - } + function get_feed_html($feedrecord, $maxentries, $showtitle){ + global $CFG; + require_once($CFG->libdir.'/simplepie/moodle_simplepie.php'); - // first we must verify that the rss feed is loaded - // by checking $rss and $rss->items exist before using them - if (empty($rss) || empty($rss->items)) { - return ''; - } + $feed = new moodle_simplepie($feedrecord->url); - if ($shownumentries > 0 && $shownumentries < count($rss->items) ) { - $rss->items = array_slice($rss->items, 0, $shownumentries); - } + if(isset($CFG->block_rss_client_timeout)){ + $feed->set_cache_duration($CFG->block_rss_client_timeout*60); + } - if (empty($rss_record->preferredtitle)) { - if (isset($rss->channel['title'])) { // Just in case feed is dead - $feedtitle = $this->format_title($rss->channel['title']); - } else { - $feedtitle = ''; - } - } else { - $feedtitle = $this->format_title($rss_record->preferredtitle); - } + if(debugging() && $feed->error()){ + return '

'. $feedrecord->url .' Failed with code: '.$feed->error().'

'; + } - if (isset($this->config) && - isset($this->config->block_rss_client_show_channel_image) && - $this->config->block_rss_client_show_channel_image && - isset($rss->image) && isset($rss->image['link']) && isset($rss->image['title']) && isset($rss->image['url']) ) { + $r = ''; // return string - $rss->image['title'] = s($rss->image['title']); - $returnstring .= "\n".'
'. $rss->image['title'] .'
'; + if($this->config->block_rss_client_show_channel_image){ + if($image = $feed->get_image_url()){ + $imagetitle = s($feed->get_image_title()); + $imagelink = $feed->get_image_link(); + $r.='
'."\n"; + if($imagelink){ + $r.=''; + } + $r.=''.$imagetitle.''."\n"; + if($imagelink){ + $r.=''; + } + $r.= '
'; } + } - if ($showtitle) { - $returnstring .= '
'. $feedtitle .'
'; - } + if(empty($feedrecord->preferredtitle)){ + $feedtitle = $this->format_title($feed->get_title()); + }else{ + $feedtitle = $this->format_title($feedrecord->preferredtitle); + } - $formatoptions->para = false; + if($showtitle){ + $r.='
'.$feedtitle.'
'; + } - /// Accessibility: markup as a list. - $returnstring .= '\n"; + } - if (!empty($rss->channel['link'])) { - $rss->channel['link'] = str_replace('&', '&', $rss->channel['link']); + if (empty($this->config->title)){ + //NOTE: this means the 'last feed' displayed wins the block title - but + //this is exiting behaviour.. + $this->title = strip_tags($feedtitle); + } - if (!empty($this->config) && isset($this->config->block_rss_client_show_channel_link) && $this->config->block_rss_client_show_channel_link) { - $this->content->footer = ''. get_string('clientchannellink', 'block_rss_client') .''; - } - if (!empty($feedtitle) ) { - $feedtitle = ''. $feedtitle .''; - } - } + return $r; + } + + + /** + * Returns the html list item of a feed item + * + * @param mixed item simplepie_item representing the feed item + * @return string html li representing the rss feed item + */ + function get_item_html($item){ + + $link = $item->get_link(); + $title = $item->get_title(); + $description = $item->get_description(); + + + if(empty($title)){ + // no title present, use portion of description + $title = substr(strip_tags($description), 0, 20) . '...'; + }else{ + $title = break_up_long_words($title, 30); } - // if block has no custom title - if (empty($this->config) || (!empty($this->config) && empty($this->config->title))) { - // if the feed has a title - if (!empty($feedtitle) and ($feedtitle != '')) { - // set the block's title to the feed's title - $this->title = strip_tags($feedtitle); - } + if(empty($link)){ + $link = $item->get_id(); } - return $returnstring; + + + $r = "
  • \n"; + $r.= '\n"; + + if($this->config->display_description && !empty($description)){ + + $description = break_up_long_words($description, 30); + + $formatoptions = new object; + $formatoptions->para = false; + + $r.= '
    '; + $r.= format_text($description, FORMAT_MOODLE, $formatoptions, $this->page->course->id); + $r.= '
    '; + } + + $r.= '
  • '; + + return $r; } - // just strips the title down and adds ... for excessively long titles. + /** + * Strips a large title to size and adds ... if title too long + * + * @param string title to shorten + * @param int max character length of title + * @return string title s() quoted and shortened if necessary + */ function format_title($title,$max=64) { - /// Loading the textlib singleton instance. We are going to need it. + // Loading the textlib singleton instance. We are going to need it. $textlib = textlib_get_instance(); if ($textlib->strlen($title) <= $max) { @@ -261,45 +276,53 @@ } } - // cron function, used to refresh all the RSS feeds from Moodle cron + /** + * cron - goes through all feeds and retrieves them with the cache + * duration set to 0 in order to force the retrieval of the item and + * refresh the cache + * + * @return boolean true if all feeds were retrieved succesfully + */ function cron() { global $CFG, $DB; + require_once($CFG->libdir.'/simplepie/moodle_simplepie.php'); - /// We are going to measure execution times + // We are going to measure execution times $starttime = microtime(); - /// And we have one initial $status + // And we have one initial $status $status = true; - /// We require some stuff - require_once($CFG->libdir .'/rsslib.php'); - require_once(MAGPIE_DIR .'rss_fetch.inc'); - - /// Fetch all site feeds. + // Fetch all site feeds. $rs = $DB->get_recordset('block_rss_client'); $counter = 0; mtrace(''); foreach ($rs as $rec) { mtrace(' ' . $rec->url . ' ', ''); - /// Fetch the rss feed, using standard magpie caching - /// so feeds will be renewed only if cache has expired - // sometimes the cron times out on moodle.org during fetching, - // there is a 5s limit in magpie which should work, but does not sometimes :-( + // Fetch the rss feed, using standard simplepie caching + // so feeds will be renewed only if cache has expired @set_time_limit(60); - if ($rss = fetch_rss($rec->url)) { - mtrace ('ok'); - } else { + + $feed = new moodle_simplepie(); + $feed->set_cache_duration(0); + $feed->set_feed_url($rec->url); + $feed->init(); + + if ($feed->error()) { mtrace ('error'); + mtrace ('SimplePie failed with error:'.$feed->error()); $status = false; + } else { + mtrace ('ok'); } $counter ++; } $rs->close(); - /// Show times + // Show times mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)'); - /// And return $status + // And return $status return $status; } } diff --git a/blocks/rss_client/editfeed.php b/blocks/rss_client/editfeed.php index 8ae4496a46..1fd9813073 100644 --- a/blocks/rss_client/editfeed.php +++ b/blocks/rss_client/editfeed.php @@ -26,8 +26,7 @@ require_once(dirname(__FILE__) . '/../../config.php'); require_once($CFG->libdir . '/formslib.php'); -require_once($CFG->libdir .'/rsslib.php'); -require_once(MAGPIE_DIR .'rss_fetch.inc'); +require_once($CFG->libdir .'/simplepie/moodle_simplepie.php'); class feed_edit_form extends moodleform { protected $isadding; @@ -75,15 +74,13 @@ class feed_edit_form extends moodleform { function validation($data, $files) { $errors = parent::validation($data, $files); - ob_start(); - $rss = fetch_rss($data['url']); - $rsserrors = ob_get_clean(); + $rss = new moodle_simplepie($data['url']); - if (!$rss) { - $errors['url'] = get_string('errorloadingfeed', 'block_rss_client', $rsserrors); + if ($rss->error()) { + $errors['url'] = get_string('errorloadingfeed', 'block_rss_client', $rss->error()); } else { - $this->title = $rss->channel['title']; - $this->description = $rss->channel['description']; + $this->title = $rss->get_title(); + $this->description = $rss->get_description(); } return $errors; diff --git a/blocks/rss_client/viewfeed.php b/blocks/rss_client/viewfeed.php index a0085e6a15..55e1bbcc93 100644 --- a/blocks/rss_client/viewfeed.php +++ b/blocks/rss_client/viewfeed.php @@ -24,8 +24,7 @@ */ require_once(dirname(__FILE__) . '/../../config.php'); -require_once($CFG->libdir .'/rsslib.php'); -require_once(MAGPIE_DIR .'rss_fetch.inc'); +require_once($CFG->libdir .'/simplepie/moodle_simplepie.php'); require_login(); if (isguest()) { @@ -68,12 +67,10 @@ $PAGE->set_generaltype('popup'); $rssrecord = $DB->get_record('block_rss_client', array('id' => $rssid), '*', MUST_EXIST); -ob_start(); -$rss = fetch_rss($rssrecord->url); -$rsserrors = ob_get_clean(); +$rss = new moodle_simplepie($rssrecord->url); -if (!$rss) { - debugging($rsserrors); +if ($rss->error()) { + debugging($rss->error()); print_error('errorfetchingrssfeed'); } @@ -98,26 +95,18 @@ echo $OUTPUT->header($navigation); if (!empty($rssrecord->preferredtitle)) { $feedtitle = $rssrecord->preferredtitle; } else { - $feedtitle = $rss->channel['title']; + $feedtitle = $rss->get_title(); } echo ''."\n"; echo ''."\n"; -foreach ($rss->items as $item) { - if ($item['link'] == '') { - $item['link'] = $item['guid']; - } - - if ($item['title'] == '') { - $item['title'] = '>>'; - } - +foreach ($rss->get_items() as $item) { echo ''."\n"; echo ''."\n"; echo ''."\n"; + echo $item->get_description() .''."\n"; } echo '
    '. $feedtitle .'
    '."\n"; - echo ''. $item['title']; + echo ''. $item->get_title(); echo ''."\n"; echo '
    '; - echo $item['description'] .'
    '."\n";