]> git.mjollnir.org Git - moodle.git/commitdiff
block_rss_client: MDL-13932/MDL-7946 - Switch to use Simplepie
authorpoltawski <poltawski>
Wed, 29 Jul 2009 13:44:28 +0000 (13:44 +0000)
committerpoltawski <poltawski>
Wed, 29 Jul 2009 13:44:28 +0000 (13:44 +0000)
Simplepie is actively maintained and supports a broader range of feeds

blocks/rss_client/block_rss_client.php
blocks/rss_client/editfeed.php
blocks/rss_client/viewfeed.php

index 36c454b53d74fbdf119ffaf166b679dc0d806185..1241be364c218ee4ac3c40751f067abc9cbaa934 100644 (file)
@@ -1,20 +1,28 @@
-<?php //$Id$
-
-/*******************************************************************
-* This file contains one class which defines a block for display on
-* any Moodle page. This block can be configured to display the contents
-* of a remote RSS news feed in your web site.
-*
-* @author Daryl Hawes
-* @version  $Id$
-* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
-* @package base
-******************************************************************/
+<?php 
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle 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 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle 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 Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * 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() {
     }
 
     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 .= '<hr style="width=:80%" />';
-                }
-                $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;
     }
     }
 
     /**
-     * @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 '<p>'. $feedrecord->url .' Failed with code: '.$feed->error().'</p>';
+        }
 
-            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".'<div class="image" title="'. $rss->image['title'] .'"><a href="'. $rss->image['link'] .'"><img src="'. $rss->image['url'] .'" alt="'. $rss->image['title'] .'" /></a></div>';
+        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.='<div class="image" title="'.$imagetitle.'">'."\n";
+                if($imagelink){
+                    $r.='<a href="'.$imagelink.'">';
+                }
+                $r.='<img src="'.$image.'" alt="'.$imagetitle.'" />'."\n";
+                if($imagelink){
+                    $r.='</a>';
+                }
+                $r.= '</div>';
             }
+        }
 
-            if ($showtitle) {
-                $returnstring .= '<div class="title">'. $feedtitle .'</div>';
-            }
+        if(empty($feedrecord->preferredtitle)){
+            $feedtitle = $this->format_title($feed->get_title());
+        }else{
+            $feedtitle = $this->format_title($feedrecord->preferredtitle);
+        }
 
-            $formatoptions->para = false;
+        if($showtitle){
+            $r.='<div class="title">'.$feedtitle.'</div>';
+        }
 
 
-            /// Accessibility: markup as a list.
-            $returnstring .= '<ul class="list">'."\n";
+        $r.='<ul class="list">'."\n";
 
-            foreach ($rss->items as $item) {
-                if ($item['title'] == '') {
-                    // no title present, use portion of description
-                    $item['title'] = substr(strip_tags($item['description']), 0, 20) . '...';
-                } else {
-                    $item['title'] = break_up_long_words($item['title'], 30);
-                }
+        $feeditems = $feed->get_items(0, $maxentries);
+        foreach($feeditems as $item){
+            $r.= $this->get_item_html($item);
+        }
 
-                if ($item['link'] == '') {
-                    $item['link'] = $item['guid'];
-                }
-                $item['title'] = s($item['title']);
+        $r.='</ul>';
 
-                $item['link'] = str_replace('&', '&amp;', $item['link']);
 
-                $returnstring .= '<li><div class="link"><a href="'. $item['link'] .'" onclick="this.target=\'_blank\'" >'. $item['title'] . "</a></div>\n";
+        if ($this->config->block_rss_client_show_channel_link) {
 
-                if ($display_description && !empty($item['description'])) {
-                    $item['description'] = break_up_long_words($item['description'], 30);
-                    $returnstring .= '<div class="description">'.
-                                     format_text($item['description'], FORMAT_MOODLE, $formatoptions, $this->courseid) .
-                                     '</div>';
-                }
-                $returnstring .= "</li>\n";
+            $channellink = str_replace('&', '&amp;', $feed->get_link());
+
+            if (!empty($channellink)){
+                //NOTE: this means the 'last feed' display wins the block title - but
+                //this is exiting behaviour..
+                $this->content->footer = '<a href="'. $channellink.'">'. get_string('clientchannellink', 'block_rss_client') .'</a>';
             }
-            $returnstring .= "</ul>\n";
+        }
 
-            if (!empty($rss->channel['link'])) {
-                $rss->channel['link'] = str_replace('&', '&amp;', $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 =  '<a href="'. $rss->channel['link'] .'">'. get_string('clientchannellink', 'block_rss_client') .'</a>';
-                } 
-                if (!empty($feedtitle) ) {
-                    $feedtitle = '<a href="'. $rss->channel['link'] .'">'. $feedtitle .'</a>';
-                }
-            }
+        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 != '<a href="'. $rss->channel['link'] .'"></a>')) {
-                // 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 = "<li>\n";
+        $r.= '<div class="link"><a href="'.$link.'" onclick="this.target=\'_blank\'" >'."\n";
+        $r.= s($title);
+        $r.= "</a></div>\n";
+
+        if($this->config->display_description && !empty($description)){
+
+            $description = break_up_long_words($description, 30);
+
+            $formatoptions = new object;
+            $formatoptions->para = false;
+
+            $r.= '<div class="description">';
+            $r.= format_text($description, FORMAT_MOODLE, $formatoptions, $this->page->course->id);
+            $r.= '</div>';
+        }
+
+        $r.= '</li>';
+
+        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) {
         }
     }
 
-    // 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;
     }
 }
index 8ae4496a46d11b30de4af1261ff44b20c42f7b12..1fd9813073b1f019c7acf32887a2badaf26e3db5 100644 (file)
@@ -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;
index a0085e6a157e3492adfc25f9100859e16f81170f..55e1bbcc93e367e54e21e595f1c432b8f9942eea 100644 (file)
@@ -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 '<table align="center" width="50%" cellspacing="1">'."\n";
 echo '<tr><td colspan="2"><strong>'. $feedtitle .'</strong></td></tr>'."\n";
-foreach ($rss->items as $item) {
-    if ($item['link'] == '') {
-        $item['link'] = $item['guid'];
-    }
-
-    if ($item['title'] == '') {
-        $item['title'] = '&gt;&gt;';
-    }
-
+foreach ($rss->get_items() as $item) {
     echo '<tr><td valign="middle">'."\n";
-    echo '<a href="'. $item['link'] .'" target="_blank"><strong>'. $item['title'];
+    echo '<a href="'. $item->get_description() .'" target="_blank"><strong>'. $item->get_title();
     echo '</strong></a>'."\n";
     echo '</td>'."\n";
     echo '</tr>'."\n";
     echo '<tr><td colspan="2"><small>';
-    echo $item['description'] .'</small></td></tr>'."\n";
+    echo $item->get_description() .'</small></td></tr>'."\n";
 }
 echo '</table>'."\n";