[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Contains block_rss_client 19 * @package block_rss_client 20 * @copyright Daryl Hawes 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL 22 */ 23 24 /** 25 * A block which displays Remote feeds 26 * 27 * @package block_rss_client 28 * @copyright Daryl Hawes 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL 30 */ 31 32 class block_rss_client extends block_base { 33 /** The maximum time in seconds that cron will wait between attempts to retry failing RSS feeds. */ 34 const CLIENT_MAX_SKIPTIME = 43200; // 60 * 60 * 12 seconds. 35 36 function init() { 37 $this->title = get_string('pluginname', 'block_rss_client'); 38 } 39 40 function applicable_formats() { 41 return array('all' => true, 'tag' => false); // Needs work to make it work on tags MDL-11960 42 } 43 44 function specialization() { 45 // After the block has been loaded we customize the block's title display 46 if (!empty($this->config) && !empty($this->config->title)) { 47 // There is a customized block title, display it 48 $this->title = $this->config->title; 49 } else { 50 // No customized block title, use localized remote news feed string 51 $this->title = get_string('remotenewsfeed', 'block_rss_client'); 52 } 53 } 54 55 /** 56 * Gets the footer, which is the channel link of the last feed in our list of feeds 57 * 58 * @param array $feedrecords The feed records from the database. 59 * @return block_rss_client\output\footer|null The renderable footer or null if none should be displayed. 60 */ 61 protected function get_footer($feedrecords) { 62 $footer = null; 63 64 if ($this->config->block_rss_client_show_channel_link) { 65 global $CFG; 66 require_once($CFG->libdir.'/simplepie/moodle_simplepie.php'); 67 68 $feedrecord = array_pop($feedrecords); 69 $feed = new moodle_simplepie($feedrecord->url); 70 $channellink = new moodle_url($feed->get_link()); 71 72 if (!empty($channellink)) { 73 $footer = new block_rss_client\output\footer($channellink); 74 } 75 } 76 77 return $footer; 78 } 79 80 function get_content() { 81 global $CFG, $DB; 82 83 if ($this->content !== NULL) { 84 return $this->content; 85 } 86 87 // initalise block content object 88 $this->content = new stdClass; 89 $this->content->text = ''; 90 $this->content->footer = ''; 91 92 if (empty($this->instance)) { 93 return $this->content; 94 } 95 96 if (!isset($this->config)) { 97 // The block has yet to be configured - just display configure message in 98 // the block if user has permission to configure it 99 100 if (has_capability('block/rss_client:manageanyfeeds', $this->context)) { 101 $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client'); 102 } 103 104 return $this->content; 105 } 106 107 // How many feed items should we display? 108 $maxentries = 5; 109 if ( !empty($this->config->shownumentries) ) { 110 $maxentries = intval($this->config->shownumentries); 111 }elseif( isset($CFG->block_rss_client_num_entries) ) { 112 $maxentries = intval($CFG->block_rss_client_num_entries); 113 } 114 115 /* --------------------------------- 116 * Begin Normal Display of Block Content 117 * --------------------------------- */ 118 119 $renderer = $this->page->get_renderer('block_rss_client'); 120 $block = new \block_rss_client\output\block(); 121 122 if (!empty($this->config->rssid)) { 123 list($rssidssql, $params) = $DB->get_in_or_equal($this->config->rssid); 124 $rssfeeds = $DB->get_records_select('block_rss_client', "id $rssidssql", $params); 125 126 if (!empty($rssfeeds)) { 127 $showtitle = false; 128 if (count($rssfeeds) > 1) { 129 // When many feeds show the title for each feed. 130 $showtitle = true; 131 } 132 133 foreach ($rssfeeds as $feed) { 134 if ($renderablefeed = $this->get_feed($feed, $maxentries, $showtitle)) { 135 $block->add_feed($renderablefeed); 136 } 137 } 138 139 $footer = $this->get_footer($rssfeeds); 140 } 141 } 142 143 $this->content->text = $renderer->render_block($block); 144 if (isset($footer)) { 145 $this->content->footer = $renderer->render_footer($footer); 146 } 147 148 return $this->content; 149 } 150 151 152 function instance_allow_multiple() { 153 return true; 154 } 155 156 function has_config() { 157 return true; 158 } 159 160 function instance_allow_config() { 161 return true; 162 } 163 164 /** 165 * Returns the html of a feed to be displaed in the block 166 * 167 * @param mixed feedrecord The feed record from the database 168 * @param int maxentries The maximum number of entries to be displayed 169 * @param boolean showtitle Should the feed title be displayed in html 170 * @return block_rss_client\output\feed|null The renderable feed or null of there is an error 171 */ 172 public function get_feed($feedrecord, $maxentries, $showtitle) { 173 global $CFG; 174 require_once($CFG->libdir.'/simplepie/moodle_simplepie.php'); 175 176 $simplepiefeed = new moodle_simplepie($feedrecord->url); 177 178 if(isset($CFG->block_rss_client_timeout)){ 179 $simplepiefeed->set_cache_duration($CFG->block_rss_client_timeout * 60); 180 } 181 182 if ($simplepiefeed->error()) { 183 debugging($feedrecord->url .' Failed with code: '.$simplepiefeed->error()); 184 return null; 185 } 186 187 if(empty($feedrecord->preferredtitle)){ 188 $feedtitle = $this->format_title($simplepiefeed->get_title()); 189 }else{ 190 $feedtitle = $this->format_title($feedrecord->preferredtitle); 191 } 192 193 if (empty($this->config->title)){ 194 //NOTE: this means the 'last feed' displayed wins the block title - but 195 //this is exiting behaviour.. 196 $this->title = strip_tags($feedtitle); 197 } 198 199 $feed = new \block_rss_client\output\feed($feedtitle, $showtitle, $this->config->block_rss_client_show_channel_image); 200 201 if ($simplepieitems = $simplepiefeed->get_items(0, $maxentries)) { 202 foreach ($simplepieitems as $simplepieitem) { 203 try { 204 $item = new \block_rss_client\output\item( 205 $simplepieitem->get_id(), 206 new moodle_url($simplepieitem->get_link()), 207 $simplepieitem->get_title(), 208 $simplepieitem->get_description(), 209 new moodle_url($simplepieitem->get_permalink()), 210 $simplepieitem->get_date('U'), 211 $this->config->display_description 212 ); 213 214 $feed->add_item($item); 215 } catch (moodle_exception $e) { 216 // If there is an error with the RSS item, we don't 217 // want to crash the page. Specifically, moodle_url can 218 // throw an exception of the param is an extremely 219 // malformed url. 220 debugging($e->getMessage()); 221 } 222 } 223 } 224 225 // Feed image. 226 if ($imageurl = $simplepiefeed->get_image_url()) { 227 try { 228 $image = new \block_rss_client\output\channel_image( 229 new moodle_url($imageurl), 230 $simplepiefeed->get_image_title(), 231 new moodle_url($simplepiefeed->get_image_link()) 232 ); 233 234 $feed->set_image($image); 235 } catch (moodle_exception $e) { 236 // If there is an error with the RSS image, we don'twant to 237 // crash the page. Specifically, moodle_url can throw an 238 // exception if the param is an extremely malformed url. 239 debugging($e->getMessage()); 240 } 241 } 242 243 return $feed; 244 } 245 246 /** 247 * Strips a large title to size and adds ... if title too long 248 * 249 * @param string title to shorten 250 * @param int max character length of title 251 * @return string title s() quoted and shortened if necessary 252 */ 253 function format_title($title,$max=64) { 254 255 if (core_text::strlen($title) <= $max) { 256 return s($title); 257 } else { 258 return s(core_text::substr($title,0,$max-3).'...'); 259 } 260 } 261 262 /** 263 * cron - goes through all the feeds. If the feed has a skipuntil value 264 * that is less than the current time cron will attempt to retrieve it 265 * with the cache duration set to 0 in order to force the retrieval of 266 * the item and refresh the cache. 267 * 268 * If a feed fails then the skipuntil time of that feed is set to be 269 * later than the next expected cron time. The amount of time will 270 * increase each time the fetch fails until the maximum is reached. 271 * 272 * If a feed that has been failing is successfully retrieved it will 273 * go back to being handled as though it had never failed. 274 * 275 * CRON should therefor process requests for permanently broken RSS 276 * feeds infrequently, and temporarily unavailable feeds will be tried 277 * less often until they become available again. 278 * 279 * @return boolean Always returns true 280 */ 281 function cron() { 282 global $CFG, $DB; 283 require_once($CFG->libdir.'/simplepie/moodle_simplepie.php'); 284 285 // Get the legacy cron time, strangely the cron property of block_base 286 // does not seem to get set. This means we must retrive it here. 287 $this->cron = $DB->get_field('block', 'cron', array('name' => 'rss_client')); 288 289 // We are going to measure execution times 290 $starttime = microtime(); 291 $starttimesec = time(); 292 293 // Fetch all site feeds. 294 $rs = $DB->get_recordset('block_rss_client'); 295 $counter = 0; 296 mtrace(''); 297 foreach ($rs as $rec) { 298 mtrace(' ' . $rec->url . ' ', ''); 299 300 // Skip feed if it failed recently. 301 if ($starttimesec < $rec->skipuntil) { 302 mtrace('skipping until ' . userdate($rec->skipuntil)); 303 continue; 304 } 305 306 // Fetch the rss feed, using standard simplepie caching 307 // so feeds will be renewed only if cache has expired 308 core_php_time_limit::raise(60); 309 310 $feed = new moodle_simplepie(); 311 // set timeout for longer than normal to be agressive at 312 // fetching feeds if possible.. 313 $feed->set_timeout(40); 314 $feed->set_cache_duration(0); 315 $feed->set_feed_url($rec->url); 316 $feed->init(); 317 318 if ($feed->error()) { 319 // Skip this feed (for an ever-increasing time if it keeps failing). 320 $rec->skiptime = $this->calculate_skiptime($rec->skiptime); 321 $rec->skipuntil = time() + $rec->skiptime; 322 $DB->update_record('block_rss_client', $rec); 323 mtrace("Error: could not load/find the RSS feed - skipping for {$rec->skiptime} seconds."); 324 } else { 325 mtrace ('ok'); 326 // It worked this time, so reset the skiptime. 327 if ($rec->skiptime > 0) { 328 $rec->skiptime = 0; 329 $rec->skipuntil = 0; 330 $DB->update_record('block_rss_client', $rec); 331 } 332 // Only increase the counter when a feed is sucesfully refreshed. 333 $counter ++; 334 } 335 } 336 $rs->close(); 337 338 // Show times 339 mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)'); 340 341 return true; 342 } 343 344 /** 345 * Calculates a new skip time for a record based on the current skip time. 346 * 347 * @param int $currentskip The curreent skip time of a record. 348 * @return int A new skip time that should be set. 349 */ 350 protected function calculate_skiptime($currentskip) { 351 // The default time to skiptime. 352 $newskiptime = $this->cron * 1.1; 353 if ($currentskip > 0) { 354 // Double the last time. 355 $newskiptime = $currentskip * 2; 356 } 357 if ($newskiptime > self::CLIENT_MAX_SKIPTIME) { 358 // Do not allow the skip time to increase indefinatly. 359 $newskiptime = self::CLIENT_MAX_SKIPTIME; 360 } 361 return $newskiptime; 362 } 363 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |