| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: rsslib.php,v 1.52.2.4 2008/09/16 08:55:43 moodler Exp $ 2 // This file contains all the common stuff to be used in RSS System 3 4 //This function returns the icon (from theme) with the link to rss/file.php 5 function rss_get_link($courseid, $userid, $modulename, $id, $tooltiptext='') { 6 7 global $CFG, $USER; 8 9 static $pixpath = ''; 10 static $rsspath = ''; 11 12 //In site course, if no logged (userid), use admin->id. Bug 2048. 13 if ($courseid == SITEID and empty($userid)) { 14 $admin = get_admin(); 15 $userid = $admin->id; 16 } 17 18 $rsspath = rss_get_url($courseid, $userid, $modulename, $id); 19 $rsspix = $CFG->pixpath .'/i/rss.gif'; 20 21 return '<a href="'. $rsspath .'"><img src="'. $rsspix .'" title="'. strip_tags($tooltiptext) .'" alt="'.get_string('rss').'" /></a>'; 22 23 } 24 25 //This function returns the URL for the RSS XML file. 26 function rss_get_url($courseid, $userid, $modulename, $id) { 27 global $CFG; 28 require_once($CFG->libdir.'/filelib.php'); 29 return get_file_url($courseid.'/'.$userid.'/'.$modulename.'/'.$id.'/rss.xml', null, 'rssfile'); 30 } 31 32 //This function prints the icon (from theme) with the link to rss/file.php 33 function rss_print_link($courseid, $userid, $modulename, $id, $tooltiptext='') { 34 35 print rss_get_link($courseid, $userid, $modulename, $id, $tooltiptext); 36 37 } 38 //This function iterates over each module in the server to see if 39 //it supports generating rss feeds, searching for a MODULENAME_rss_feeds() 40 //function and invoking it foreach activity as necessary 41 function cron_rss_feeds () { 42 43 global $CFG; 44 45 $status = true; 46 47 mtrace(' Generating rssfeeds...'); 48 49 //Check for required functions... 50 if(!function_exists('utf8_encode')) { 51 mtrace(' ERROR: You need to add XML support to your PHP installation!'); 52 return true; 53 } 54 55 if ($allmods = get_records('modules') ) { 56 foreach ($allmods as $mod) { 57 mtrace(' '.$mod->name.': ', ''); 58 $modname = $mod->name; 59 $modfile = "$CFG->dirroot/mod/$modname/rsslib.php"; 60 //If file exists and we have selected to restore that type of module 61 if (file_exists($modfile)) { 62 include_once($modfile); 63 $generaterssfeeds = $modname.'_rss_feeds'; 64 if (function_exists($generaterssfeeds)) { 65 if ($status) { 66 mtrace('generating ', '');; 67 $status = $generaterssfeeds(); 68 if (!empty($status)) { 69 mtrace('...OK'); 70 } else { 71 mtrace('...FAILED'); 72 } 73 } else { 74 mtrace('...SKIPPED (failed above)'); 75 } 76 } else { 77 mtrace('...NOT SUPPORTED (function)'); 78 } 79 } else { 80 mtrace('...NOT SUPPORTED (file)'); 81 } 82 } 83 } 84 mtrace(' Ending rssfeeds...', ''); 85 if (!empty($status)) { 86 mtrace('...OK'); 87 } else { 88 mtrace('...FAILED'); 89 } 90 91 return $status; 92 } 93 94 //This function saves to file the rss feed specified in the parameters 95 function rss_save_file ($modname, $mod, $result) { 96 97 global $CFG; 98 99 $status = true; 100 101 if (! $basedir = make_upload_directory ('rss/'. $modname)) { 102 //Cannot be created, so error 103 $status = false; 104 } 105 106 if ($status) { 107 $file = rss_file_name($modname, $mod); 108 $rss_file = fopen($file, "w"); 109 if ($rss_file) { 110 $status = fwrite ($rss_file, $result); 111 fclose($rss_file); 112 } else { 113 $status = false; 114 } 115 } 116 return $status; 117 } 118 119 120 function rss_file_name($modname, $mod) { 121 global $CFG; 122 123 return "$CFG->dataroot/rss/$modname/$mod->id.xml"; 124 } 125 126 //This function return all the common headers for every rss feed in the site 127 function rss_standard_header($title = NULL, $link = NULL, $description = NULL) { 128 129 global $CFG, $USER; 130 131 static $pixpath = ''; 132 133 $status = true; 134 $result = ""; 135 136 if (!$site = get_site()) { 137 $status = false; 138 } 139 140 if ($status) { 141 142 //Calculate title, link and description 143 if (empty($title)) { 144 $title = format_string($site->fullname); 145 } 146 if (empty($link)) { 147 $link = $CFG->wwwroot; 148 } 149 if (empty($description)) { 150 $description = $site->summary; 151 } 152 153 //xml headers 154 $result .= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 155 $result .= "<rss version=\"2.0\">\n"; 156 157 //open the channel 158 $result .= rss_start_tag('channel', 1, true); 159 160 //write channel info 161 $result .= rss_full_tag('title', 2, false, strip_tags($title)); 162 $result .= rss_full_tag('link', 2, false, $link); 163 $result .= rss_full_tag('description', 2, false, $description); 164 $result .= rss_full_tag('generator', 2, false, 'Moodle'); 165 if (!empty($USER->lang)) { 166 $result .= rss_full_tag('language', 2, false, substr($USER->lang,0,2)); 167 } 168 $today = getdate(); 169 $result .= rss_full_tag('copyright', 2, false, '© '. $today['year'] .' '. format_string($site->fullname)); 170 /* 171 if (!empty($USER->email)) { 172 $result .= rss_full_tag('managingEditor', 2, false, fullname($USER)); 173 $result .= rss_full_tag('webMaster', 2, false, fullname($USER)); 174 } 175 */ 176 177 //write image info 178 $rsspix = $CFG->pixpath."/i/rsssitelogo.gif"; 179 180 //write the info 181 $result .= rss_start_tag('image', 2, true); 182 $result .= rss_full_tag('url', 3, false, $rsspix); 183 $result .= rss_full_tag('title', 3, false, 'moodle'); 184 $result .= rss_full_tag('link', 3, false, $CFG->wwwroot); 185 $result .= rss_full_tag('width', 3, false, '140'); 186 $result .= rss_full_tag('height', 3, false, '35'); 187 $result .= rss_end_tag('image', 2, true); 188 } 189 190 if (!$status) { 191 return false; 192 } else { 193 return $result; 194 } 195 } 196 197 //This function returns the rss XML code for every item passed in the array 198 //item->title: The title of the item 199 //item->author: The author of the item. Optional !! 200 //item->pubdate: The pubdate of the item 201 //item->link: The link url of the item 202 //item->description: The content of the item 203 function rss_add_items($items) { 204 205 global $CFG; 206 207 $result = ''; 208 209 if (!empty($items)) { 210 foreach ($items as $item) { 211 $result .= rss_start_tag('item',2,true); 212 //Include the category if exists (some rss readers will use it to group items) 213 if (isset($item->category)) { 214 $result .= rss_full_tag('category',3,false,$item->category); 215 } 216 $result .= rss_full_tag('title',3,false,strip_tags($item->title)); 217 $result .= rss_full_tag('link',3,false,$item->link); 218 $result .= rss_add_enclosures($item); 219 $result .= rss_full_tag('pubDate',3,false,gmdate('D, d M Y H:i:s',$item->pubdate).' GMT'); # MDL-12563 220 //Include the author if exists 221 if (isset($item->author)) { 222 //$result .= rss_full_tag('author',3,false,$item->author); 223 //We put it in the description instead because it's more important 224 //for moodle than most other feeds, and most rss software seems to ignore 225 //the author field ... 226 $item->description = get_string('byname','',$item->author).'. <p>'.$item->description.'</p>'; 227 } 228 $result .= rss_full_tag('description',3,false,$item->description); 229 $result .= rss_full_tag('guid',3,false,$item->link,array('isPermaLink' => 'true')); 230 $result .= rss_end_tag('item',2,true); 231 232 } 233 } else { 234 $result = false; 235 } 236 return $result; 237 } 238 239 //This function return all the common footers for every rss feed in the site 240 function rss_standard_footer($title = NULL, $link = NULL, $description = NULL) { 241 242 global $CFG, $USER; 243 244 $status = true; 245 $result = ''; 246 247 //Close the chanel 248 $result .= rss_end_tag('channel', 1, true); 249 ////Close the rss tag 250 $result .= '</rss>'; 251 252 return $result; 253 } 254 255 //This function return an error xml file (string) 256 //to be sent when a rss is required (file.php) 257 //and something goes wrong 258 function rss_geterrorxmlfile() { 259 260 global $CFG; 261 262 $return = ''; 263 264 //XML Header 265 $return = rss_standard_header(); 266 267 //XML item 268 if ($return) { 269 $item = new object(); 270 $item->title = "RSS Error"; 271 $item->link = $CFG->wwwroot; 272 $item->pubdate = time(); 273 $item->description = get_string("rsserror"); 274 $return .= rss_add_items(array($item)); 275 } 276 277 //XML Footer 278 if ($return) { 279 $return .= rss_standard_footer(); 280 } 281 282 return $return; 283 } 284 285 // ===== This function are used to write XML tags ========= 286 // [stronk7]: They are similar to the glossary export and backup generation 287 // but I've replicated them here because they have some minor 288 // diferences. Someday all they should go to a common place. 289 290 //Return the xml start tag 291 function rss_start_tag($tag,$level=0,$endline=false,$attributes=null) { 292 if ($endline) { 293 $endchar = "\n"; 294 } else { 295 $endchar = ""; 296 } 297 $attrstring = ''; 298 if (!empty($attributes) && is_array($attributes)) { 299 foreach ($attributes as $key => $value) { 300 $attrstring .= " ".$key."=\"".$value."\""; 301 } 302 } 303 return str_repeat(" ",$level*2)."<".$tag.$attrstring.">".$endchar; 304 } 305 306 //Return the xml end tag 307 function rss_end_tag($tag,$level=0,$endline=true) { 308 if ($endline) { 309 $endchar = "\n"; 310 } else { 311 $endchar = ""; 312 } 313 return str_repeat(" ",$level*2)."</".$tag.">".$endchar; 314 } 315 316 //Return the start tag, the contents and the end tag 317 function rss_full_tag($tag,$level=0,$endline=true,$content,$attributes=null) { 318 global $CFG; 319 $st = rss_start_tag($tag,$level,$endline,$attributes); 320 $co=""; 321 $co = preg_replace("/\r\n|\r/", "\n", htmlspecialchars($content)); 322 $et = rss_end_tag($tag,0,true); 323 324 return $st.$co.$et; 325 } 326 327 //////////////////// LIBRARY FUNCTIONS FOR RSS_CLIENT BLOCK //////////////// 328 329 //initialize default config vars for rss_client block if needed 330 if (!isset($CFG->block_rss_client_submitters) ) { 331 $CFG->block_rss_client_submitters = 1; //default to admin only 332 } 333 if (empty($CFG->block_rss_client_num_entries) ) { 334 $CFG->block_rss_client_num_entries = 5; //default to 5 entries per block 335 } 336 if (!isset($CFG->block_rss_client_timeout) ) { 337 $CFG->block_rss_client_timeout = 30; //default to 30 mins 338 } 339 340 // Defines for moodle's use of magpierss classes 341 define('MAGPIE_DIR', $CFG->libdir.'/magpie/'); 342 define('MAGPIE_CACHE_DIR', $CFG->dataroot .'/cache/rsscache'); 343 define('MAGPIE_CACHE_ON', true); //might want to expose as an admin config option, but perhaps this is something that should truly just be on unless the code is tweaked 344 define('MAGPIE_CACHE_FRESH_ONLY', false); //should be exposed as an admin config option 345 define('MAGPIE_CACHE_AGE', $CFG->block_rss_client_timeout * 60); 346 define('MAGPIE_DEBUG', $CFG->debug); // magpie, like moodle, takes an integer debug 347 348 // defines for config var block_rss_client_submitters 349 define('SUBMITTERS_ALL_ACCOUNT_HOLDERS', 0); 350 define('SUBMITTERS_ADMIN_ONLY', 1); 351 define('SUBMITTERS_ADMIN_AND_TEACHER', 2); 352 353 /** 354 * @param int $courseid The id of the course the user is currently viewing 355 * @param int $userid We need this to know which feeds the user is allowed to manage 356 * @param int $rssid If present the rss entry matching this id alone will be displayed 357 * as long as the user is allowed to manage this feed 358 * @param object $context we need the context object to check what the user is allowed to do. 359 */ 360 function rss_display_feeds($courseid, $userid, $rssid='', $context) { 361 global $db, $USER, $CFG; 362 global $blogid; //hackish, but if there is a blogid it would be good to preserve it 363 364 require_once($CFG->libdir.'/tablelib.php'); 365 366 $select = ''; 367 $managesharedfeeds = has_capability('block/rss_client:manageanyfeeds', $context); 368 $manageownfeeds = has_capability('block/rss_client:manageownfeeds', $context); 369 370 if ($rssid != '') { 371 $select = 'id = '.$rssid.' AND '; 372 } 373 if ($managesharedfeeds) { 374 $select .= '(userid = '.$userid.' OR shared = 1)'; 375 } else if ($manageownfeeds) { 376 $select .= 'userid = '.$userid; 377 } 378 379 $table = new flexible_table('rss-display-feeds'); 380 381 $table->define_columns(array('feed', 'actions')); 382 $table->define_headers(array(get_string('feed', 'block_rss_client'), get_string('actions', 'moodle'))); 383 384 $table->set_attribute('cellspacing', '0'); 385 $table->set_attribute('id', 'rssfeeds'); 386 $table->set_attribute('class', 'generaltable generalbox'); 387 $table->column_class('feed', 'feed'); 388 $table->column_class('actions', 'actions'); 389 390 $table->setup(); 391 392 $feeds = get_records_select('block_rss_client', $select, sql_order_by_text('title')); 393 394 if(!empty($feeds)) { 395 foreach($feeds as $feed) { 396 397 if (!empty($feed->preferredtitle)) { 398 $feedtitle = stripslashes_safe($feed->preferredtitle); 399 } else { 400 $feedtitle = stripslashes_safe($feed->title); 401 } 402 403 if ( ($feed->userid == $USER->id && $manageownfeeds) 404 || ($feed->shared && $managesharedfeeds) ) { 405 406 $feedicons = '<a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?id='. $courseid .'&act=rssedit&rssid='. $feed->id .'&shared='.$feed->shared.'&blogid='. $blogid .'">'. 407 '<img src="'. $CFG->pixpath .'/t/edit.gif" alt="'. get_string('edit').'" title="'. get_string('edit') .'" /></a> '. 408 409 '<a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?id='. $courseid .'&act=delfeed&rssid='. $feed->id.'&shared='.$feed->shared.'blogid='. $blogid .'" 410 onclick="return confirm(\''. get_string('deletefeedconfirm', 'block_rss_client') .'\');">'. 411 '<img src="'. $CFG->pixpath .'/t/delete.gif" alt="'. get_string('delete').'" title="'. get_string('delete') .'" /></a>'; 412 } 413 else { 414 $feedicons = ''; 415 } 416 417 $feedinfo = ' 418 <div class="title"> 419 <a href="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php?id='. $courseid .'&act=view&rssid='.$feed->id .'&blogid='. $blogid .'"> 420 '. $feedtitle .'</a> 421 </div> 422 <div class="url"> 423 <a href="'. $feed->url .'">'. $feed->url .'</a> 424 </div> 425 <div class="description">'.$feed->description.'</div>'; 426 427 $table->add_data(array($feedinfo, $feedicons)); 428 } 429 } 430 431 $table->print_html(); 432 } 433 434 435 /** 436 * Wrapper function for rss_get_form 437 */ 438 function rss_print_form($act='none', $url='', $rssid='', $preferredtitle='', $shared=0, $courseid='', $context) { 439 print rss_get_form($act, $url, $rssid, $preferredtitle, $shared, $courseid, $context); 440 } 441 442 443 /** 444 * Prints or returns a form for managing rss feed entries. 445 * @param string $act The current action. If "rssedit" then and "update" button is used, otherwise "add" is used. 446 * @param string $url The url of the feed that is being updated or NULL 447 * @param int $rssid The dataabse id of the feed that is being updated or NULL 448 * @param string $preferredtitle The preferred title to display for this feed 449 * @param int $shared Whether this feed is to be shared or not 450 * @param int $courseid The id of the course that is currently being viewed if applicable 451 * @param object $context The context that we will use to check for permissions 452 * @return string Either the form is printed directly and nothing is returned or the form is returned as a string 453 */ 454 function rss_get_form($act='none', $url='', $rssid='', $preferredtitle='', $shared=0, $courseid='', $context) { 455 global $USER, $CFG, $_SERVER, $blockid, $blockaction; 456 global $blogid; //hackish, but if there is a blogid it would be good to preserve it 457 $stredit = get_string('edit'); 458 $stradd = get_string('add'); 459 $strupdatefeed = get_string('updatefeed', 'block_rss_client'); 460 $straddfeed = get_string('addfeed', 'block_rss_client'); 461 462 $returnstring = ''; 463 464 $returnstring .= '<form action="'. $CFG->wwwroot .'/blocks/rss_client/block_rss_client_action.php" method="post" id="block_rss">'."\n"; 465 print_location_comment(__FILE__,__LINE__); 466 $returnstring .= '<div id="rss_table">'."\n"; 467 if ($act == 'rssedit') { 468 $returnstring .= $strupdatefeed; 469 } else { 470 $returnstring .= $straddfeed; 471 } 472 473 $returnstring .= "\n".'<br /><input type="text" size="60" maxlength="256" name="url" value="'; 474 if ($act == 'rssedit') { 475 $returnstring .= $url; 476 } 477 478 $returnstring .= '" />'."\n"; 479 $returnstring .= '<br />'. get_string('customtitlelabel', 'block_rss_client'); 480 $returnstring .= '<br /><input type="text" size="60" maxlength="128" name="preferredtitle" value="'; 481 482 if ($act == 'rssedit') { 483 $returnstring .= $preferredtitle; 484 } 485 486 $returnstring .= '" />'."\n"; 487 488 if (has_capability('block/rss_client:createsharedfeeds', $context)) { 489 $returnstring .= '<br /><input type="checkbox" name="shared" value="1" '; 490 if ($shared) { 491 $returnstring .= 'checked="checked" '; 492 } 493 $returnstring .= '/> '; 494 $returnstring .= get_string('sharedfeed', 'block_rss_client'); 495 $returnstring .= '<br />'."\n"; 496 } 497 498 $returnstring .= '<input type="hidden" name="act" value="'; 499 500 if ($act == 'rssedit') { 501 $returnstring .= 'updfeed'; 502 } else { 503 $returnstring .= 'addfeed'; 504 } 505 506 $returnstring .= '" />'."\n"; 507 if ($act == 'rssedit') { 508 $returnstring .= '<input type="hidden" name="rssid" value="'. $rssid .'" />'. "\n"; 509 } 510 511 $returnstring .= '<input type="hidden" name="id" value="'. $courseid .'" />'."\n"; 512 $returnstring .= '<input type="hidden" name="blogid" value="'. $blogid .'" />'."\n"; 513 $returnstring .= '<input type="hidden" name="user" value="'. $USER->id .'" />'."\n"; 514 $returnstring .= '<br /><input type="submit" value="'; 515 $validatestring = "<a href=\"#\" onclick=\"window.open('http://feedvalidator.org/check.cgi?url='+getElementById('block_rss').elements['url'].value,'validate','width=640,height=480,scrollbars=yes,status=yes,resizable=yes');return true;\">". get_string('validatefeed', 'block_rss_client')."</a>"; 516 517 if ($act == 'rssedit') { 518 $returnstring .= $stredit; 519 } else { 520 $returnstring .= $stradd; 521 } 522 523 $returnstring .= '" /> '. $validatestring ."\n"; 524 // $returnstring .= '</div></form>'."\n"; // Avoiding nested forms... Ugly temporary hack #8922 525 return $returnstring . print_location_comment(__FILE__, __LINE__, true); 526 } 527 528 529 /** 530 * Adds RSS Media Enclosures for "podcasting" by examining links to media files, 531 * and attachments which are media files. Please note that the RSS that is 532 * produced cannot be strictly valid for the linked files, since we do not know 533 * the files' sizes and cannot include them in the "length" attribute. At 534 * present, the validity (and therefore the podcast working in most software) 535 * can only be ensured for attachments, and not for links. 536 * Note also that iTunes does some things very badly - one thing it does is 537 * refuse to download ANY of your files if you're using "file.php?file=blah" 538 * and can't use the more elegant "file.php/blah" slasharguments setting. It 539 * stops after ".php" and assumes the files are not media files, despite what 540 * is specified in the "type" attribute. Dodgy coding all round! 541 * 542 * @param $item object representing an RSS item 543 * @return string RSS enclosure tags 544 * @author Hannes Gassert <hannes@mediagonal.ch> 545 * @author Dan Stowell 546 */ 547 function rss_add_enclosures($item){ 548 549 global $CFG; 550 551 $returnstring = ''; 552 $rss_text = $item->description; 553 554 // list of media file extensions and their respective mime types 555 include_once($CFG->libdir.'/filelib.php'); 556 $mediafiletypes = get_mimetypes_array(); 557 558 // regular expression (hopefully) matching all links to media files 559 $medialinkpattern = '@href\s*=\s*(\'|")(\S+(' . implode('|', array_keys($mediafiletypes)) . '))\1@Usie'; 560 561 // take into account attachments (e.g. from forum) - with these, we are able to know the file size 562 if (isset($item->attachments) && is_array($item->attachments)) { 563 foreach ($item->attachments as $attachment){ 564 $extension = strtolower(substr($attachment->url, strrpos($attachment->url, '.')+1)); 565 if (isset($mediafiletypes[$extension]['type'])) { 566 $type = $mediafiletypes[$extension]['type']; 567 } else { 568 $type = 'document/unknown'; 569 } 570 $returnstring .= "\n<enclosure url=\"$attachment->url\" length=\"$attachment->length\" type=\"$type\" />\n"; 571 } 572 } 573 574 if (!preg_match_all($medialinkpattern, $rss_text, $matches)){ 575 return $returnstring; 576 } 577 578 // loop over matches of regular expression 579 for ($i = 0; $i < count($matches[2]); $i++){ 580 $url = htmlspecialchars($matches[2][$i]); 581 $extension = strtolower($matches[3][$i]); 582 if (isset($mediafiletypes[$extension]['type'])) { 583 $type = $mediafiletypes[$extension]['type']; 584 } else { 585 $type = 'document/unknown'; 586 } 587 588 // the rss_*_tag functions can't deal with methods, unfortunately 589 $returnstring .= "\n<enclosure url='$url' type='$type' />\n"; 590 } 591 592 return $returnstring; 593 } 594 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |