From 0eb35827c6b66f6bf58af88e99d8f07c08b6fc4e Mon Sep 17 00:00:00 2001 From: dhawes Date: Fri, 17 Dec 2004 02:45:21 +0000 Subject: [PATCH] first addition of extra rss files needed by rss_client block. templib functionality should be moved to rsslib.php if Eloy is OK with that --- rss/class.Atom.php | 270 ++++++++++++++++++++++++++++++++++++ rss/class.RSS.php | 335 +++++++++++++++++++++++++++++++++++++++++++++ rss/templib.php | 251 +++++++++++++++++++++++++++++++++ 3 files changed, 856 insertions(+) create mode 100644 rss/class.Atom.php create mode 100644 rss/class.RSS.php create mode 100644 rss/templib.php diff --git a/rss/class.Atom.php b/rss/class.Atom.php new file mode 100644 index 0000000000..fa7f483f1e --- /dev/null +++ b/rss/class.Atom.php @@ -0,0 +1,270 @@ + + * Version: 0.1 + * License: GPL + * + * The lastest version of phAnTOM can be obtained from: + * http://www.simplog.org + * + * For questions, help, comments, discussion, etc., please join the + * Simplog Atom mailing list: + * simplog-atom@lists.sourceforge.net + * + * This code is based on the MagpieRSS parser v0.52 written + * by Kellan Elliott-McCrea and released under the GPL + */ + + +/* + * The lastest Atom feed spec is at http://diveintomark.org/public/2003/08/atom02spec.txt + * + * + * RSS/Atom validators are readily available on the web at: + * http://feeds.archive.org/validator/ + * + */ + +class Atom { + /* + * Useage Example: + * + * $xml = "feed['title']; + * + * // print the title of each entry + * foreach ($atom->entries as $entry ) { + * print $entry[title]; + * } + * + */ + + var $parser; + + var $current_item = array(); // item currently being parsed + var $entries = array(); // collection of parsed items + var $feed = array(); // hash of channel fields + + var $parent_field = array('RDF'); + var $author = array(); + var $contributor = array(); + var $current_field = ''; + var $current_namespace = false; + + var $ERROR = ''; + +/*======================================================================*\ + Function: MagpieRSS + Purpose: Constructor, sets up XML parser,parses source, + and populates object.. + Input: String containing the RSS to be parsed +\*======================================================================*/ + function Atom ($source) { + + # if PHP xml isn't compiled in, die + # + if (!function_exists('xml_parser_create')) { + $this->error( 'Failed to load PHP\'s XML Extension. ' . + 'http://www.php.net/manual/en/ref.xml.php', + E_USER_ERROR ); + } + + $parser = @xml_parser_create(); + + if (!is_resource($parser)) + { + $this->error( 'Failed to create an instance of PHP\'s XML parser. ' . + 'http://www.php.net/manual/en/ref.xml.php', + E_USER_ERROR ); + } + + + $this->parser = $parser; + + # pass in parser, and a reference to this object + # setup handlers + # + xml_set_object( $this->parser, $this ); + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler( $this->parser, 'cdata' ); + + + $status = xml_parse( $this->parser, $source ); + + if (! $status ) { + $errorcode = xml_get_error_code( $this->parser ); + if ( $errorcode != XML_ERROR_NONE ) { + $xml_error = xml_error_string( $errorcode ); + $error_line = xml_get_current_line_number($this->parser); + $error_col = xml_get_current_column_number($this->parser); + $errormsg = $xml_error .' at line '. $error_line .', column '. $error_col; + + $this->error( $errormsg ); + } + } + + xml_parser_free( $this->parser ); + } + + function start_element ($p, $element, &$attrs) { + $element = strtolower( $element ); + # check for a namespace, and split if found + # + $namespace = false; + if ( strpos( $element, ':' ) ) { + list($namespace, $element) = split( ':', $element, 2); + } + $this->current_field = $element; + if ( $namespace ) { + $this->current_namespace = $namespace; + } + + if ( $element == 'feed' ) { + array_unshift( $this->parent_field, 'feed' ); + } else if ( $element == 'items' ) { + array_unshift( $this->parent_field, 'items' ); + } else if ( $element == 'entry' ) { + array_unshift( $this->parent_field, 'entry' ); + } else if ( $element == 'author' ) { + array_unshift( $this->parent_field, 'author' ); + } else if ( $element == 'contributor' ) { + array_unshift( $this->parent_field, 'contributor' ); + } + } + + function end_element ($p, $element) { + $element = strtolower($element); + + if ( $element == 'entry' ) { + $this->entries[] = $this->current_item; + $this->current_item = array(); + array_shift( $this->parent_field ); + } else if ( $element == 'feed' or $element == 'items' or + $element == 'author' or $element == 'contributor') { + array_shift( $this->parent_field ); + } + + $this->current_field = ''; + $this->current_namespace = false; + } + + function cdata ($p, $text) { + # skip item, channel, items first time we see them + # + if ( $this->parent_field[0] == $this->current_field or + ! $this->current_field ) { + return; + } else if ( $this->parent_field[0] == 'feed') { + if ( $this->current_namespace ) { + $this->append( + $this->feed[ $this->current_namespace ][ $this->current_field ], + $text); + } else { + $this->append($this->feed[ $this->current_field ], $text); + } + + } else if ( $this->parent_field[0] == 'entry' ) { + if ( $this->current_namespace ) { + $this->append( + $this->current_item[ $this->current_namespace ][$this->current_field ], + $text); + } else { + $this->append( + $this->current_item[ $this->current_field ], + $text ); + } + } else if ( $this->parent_field[0] == 'author' ) { + if ( $this->current_namespace ) { + $this->append( + $this->author[ $this->current_namespace ][ $this->current_field ], + $text ); + } else { + $this->append( + $this->author[ $this->current_field ], + $text ); + } + } else if ( $this->parent_field[0] == 'contributor' ) { + if ( $this->current_namespace ) { + $this->append( + $this->contributor[ $this->current_namespace ][ $this->current_field ], + $text ); + } else { + $this->append( + $this->contributor[ $this->current_field ], + $text ); + } + } + } + + function append (&$str1, $str2='') { + if (!isset($str1) ) { + $str1=''; + } + $str1 .= $str2; + } + + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( $php_errormsg ) { + $errormsg .= ' ('. $php_errormsg .')'; + } + $this->ERROR = $errormsg; + if ( ATOM_DEBUG ) { + trigger_error( $errormsg, $lvl); + } else { + error_log( $errormsg, 0); + } + } + + +/*======================================================================*\ + EVERYTHING BELOW HERE IS FOR DEBUGGING PURPOSES +\*======================================================================*/ + function show_list () { + print '
    '."\n"; + foreach ($this->entries as $item) { + print '
  1. '. $this->show_entry( $item ); + } + print '
'; + } + + function show_feed () { + print 'feed:
'; + print ''; + } + + function show_entry ($item) { + print 'entry: '. $item[title]; + print ''; + } + +/*======================================================================*\ + END DEBUGGING FUNCTIONS +\*======================================================================*/ + +} # end class Atom +?> \ No newline at end of file diff --git a/rss/class.RSS.php b/rss/class.RSS.php new file mode 100644 index 0000000000..e5319f60c9 --- /dev/null +++ b/rss/class.RSS.php @@ -0,0 +1,335 @@ + + * Version: 0.51 + * License: GPL + * + * The lastest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * magpierss-general@lists.sourceforge.net + * + */ + + +/* + * NOTES ON RSS PARSING PHILOSOPHY (moderately important): + * MagpieRSS parse all versions of RSS with a few limitation (mod_content, and + * mod_taxonomy support is shaky) into a simple object, with 2 fields, + * the hash 'channel', and the array 'items'. + * + * MagpieRSS is a forgiving and inclusive parser. It currently makes no + * attempt to enforce the validity on an RSS feed. It will include any + * properly formatted tags it finds, allowing to you to mix RSS 0.93, with RSS + * 1.0, with tags or your own imagining. This sort of witches brew is a bad + * bad idea! But Magpie is less pendantic then I am. + * + * RSS validators are readily available on the web at: + * http://feeds.archive.org/validator/ + * http://www.ldodds.com/rss_validator/1.0/validator.html + * + */ + +/* + * EXAMPLE PARSE RESULTS: + * + * Magpie tries to parse RSS into ease to use PHP datastructures. + * + * For example, Magpie on encountering RSS 1.0 item entry: + * + * + * Weekly Peace Vigil + * http://protest.net/NorthEast/calendrome.cgi?span=event&ID=210257 + * Wear a white ribbon + * Peace + * 2002-06-01T11:00:00 + * Northampton, MA + * 2002-06-01T12:00:00 + * Protest + * + * + * Would transform it into the following associative array, and push it + * onto the array $rss-items + * + * array( + * title => 'Weekly Peace Vigil', + * link => + * 'http://protest.net/NorthEast/calendrome.cgi?span=event&ID=210257', + * description => 'Wear a white ribbon', + * dc => array ( + * subject => 'Peace' + * ), + * ev => array ( + * startdate => '2002-06-01T11:00:00', + * enddate => '2002-06-01T12:00:00', + * type => 'Protest', + * location => 'Northampton, MA' + * ) + * ) + * + */ + +class MagpieRSS { + /* + * Hybrid parser, and object. (probably a bad idea! :) + * + * Useage Example: + * + * $some_rss = "channel['title']; + * + * // print the title of each item + * foreach ($rss->items as $item ) { + * echo $item[title]; + * } + * + * see rss_fetch.inc for a simpler interface + */ + + var $parser; + + var $current_item = array(); // item currently being parsed + var $items = array(); // collection of parsed items + var $channel = array(); // hash of channel fields + var $textinput = array(); + var $image = array(); + + var $parent_field = array('RDF'); + var $current_field = ''; + var $current_namespace = false; + + var $ERROR = ""; + + /*======================================================================*\ + Function: MagpieRSS + Purpose: Constructor, sets up XML parser,parses source, + and populates object.. + Input: String containing the RSS to be parsed + \*======================================================================*/ + function MagpieRSS ($source) { + + # if PHP xml isn't compiled in, die + # + if (!function_exists('xml_parser_create')) { + $this->error( "Failed to load PHP's XML Extension. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + $parser = @xml_parser_create(); + + if (!is_resource($parser)) + { + $this->error( "Failed to create an instance of PHP's XML parser. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + + $this->parser = $parser; + + # pass in parser, and a reference to this object + # setup handlers + # + xml_set_object( $this->parser, $this ); + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler( $this->parser, 'cdata' ); + + + $status = xml_parse( $this->parser, $source ); + + if (! $status ) { + $errorcode = xml_get_error_code( $this->parser ); + if ( $errorcode != XML_ERROR_NONE ) { + $xml_error = xml_error_string( $errorcode ); + $error_line = xml_get_current_line_number($this->parser); + $error_col = xml_get_current_column_number($this->parser); + $errormsg = "$xml_error at line $error_line, column $error_col"; + + $this->error( $errormsg ); + } + } + + xml_parser_free( $this->parser ); + } + + function start_element ($p, $element, &$attrs) { + $element = strtolower( $element ); + # check for a namespace, and split if found + # + $namespace = false; + if ( strpos( $element, ':' ) ) { + list($namespace, $element) = split( ':', $element, 2); + } + $this->current_field = $element; + if ( $namespace and $namespace != 'rdf' ) { + $this->current_namespace = $namespace; + } + + if ( $element == 'channel' ) { + array_unshift( $this->parent_field, 'channel' ); + } + elseif ( $element == 'items' ) { + array_unshift( $this->parent_field, 'items' ); + } + elseif ( $element == 'item' ) { + array_unshift( $this->parent_field, 'item' ); + } + elseif ( $element == 'textinput' ) { + array_unshift( $this->parent_field, 'textinput' ); + } + elseif ( $element == 'image' ) { + array_unshift( $this->parent_field, 'image' ); + } + + } + + function end_element ($p, $element) { + $element = strtolower($element); + + if ( $element == 'item' ) { + $this->items[] = $this->current_item; + $this->current_item = array(); + array_shift( $this->parent_field ); + } + elseif ( $element == 'channel' or $element == 'items' or + $element == 'textinput' or $element == 'image' ) { + array_shift( $this->parent_field ); + } + + $this->current_field = ''; + $this->current_namespace = false; + } + + function cdata ($p, $text) { + # skip item, channel, items first time we see them + # + if ( $this->parent_field[0] == $this->current_field or + ! $this->current_field ) { + return; + } + elseif ( $this->parent_field[0] == 'channel') { + if ( $this->current_namespace ) { + $this->append( + $this->channel[ $this->current_namespace ][ $this->current_field ], + $text); + } + else { + $this->append($this->channel[ $this->current_field ], $text); + } + + } + elseif ( $this->parent_field[0] == 'item' ) { + if ( $this->current_namespace ) { + $this->append( + $this->current_item[ $this->current_namespace ][$this->current_field ], + $text); + } + else { + $this->append( + $this->current_item[ $this->current_field ], + $text ); + } + } + elseif ( $this->parent_field[0] == 'textinput' ) { + if ( $this->current_namespace ) { + $this->append( + $this->textinput[ $this->current_namespace ][ $this->current_field ], + $text ); + } + else { + $this->append( + $this->textinput[ $this->current_field ], + $text ); + } + } + elseif ( $this->parent_field[0] == 'image' ) { + if ( $this->current_namespace ) { + $this->append( + $this->image[ $this->current_namespace ][ $this->current_field ], + $text ); + } + else { + $this->append( + $this->image[ $this->current_field ], + $text ); + } + } + } + + function append (&$str1, $str2="") { + if (!isset($str1) ) { + $str1=""; + } + $str1 .= $str2; + } + + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + $this->ERROR = $errormsg; + //if ( MAGPIE_DEBUG ) { + // trigger_error( $errormsg, $lvl); + //} + //else { + error_log( $errormsg, 0); + //} + } + + + /*======================================================================*\ + EVERYTHING BELOW HERE IS FOR DEBUGGING PURPOSES + \*======================================================================*/ + function show_list () { + echo "
    \n"; + foreach ($this->items as $item) { + echo "
  1. ", $this->show_item( $item ); + } + echo "
"; + } + + function show_channel () { + echo "channel:
"; + echo ""; + } + + function show_item ($item) { + echo "item: $item[title]"; + echo ""; + } + + /*======================================================================*\ + END DEBUGGING FUNCTIONS + \*======================================================================*/ + +} # end class RSS +?> diff --git a/rss/templib.php b/rss/templib.php new file mode 100644 index 0000000000..c84cf08a44 --- /dev/null +++ b/rss/templib.php @@ -0,0 +1,251 @@ +block_rss_client_submitters) ) { + $CFG->block_rss_client_submitters = 2; //default to admin only +} +if (empty($CFG->block_rss_client_num_entries) ) { + $CFG->block_rss_client_num_entries = 5; //default to 5 entries per block +} + +/* +* rss_get_feed +* Determines whether or not to get a news feed remotely or from cache and reads it into a string +* rssid - id of feed in blog_rss table +* url - remote url of feed +* type - either 'A' or 'R' where A is an atom feed and R is either rss or rdf +* NOTE that this requires allow_url_fopen be On in your php.ini file (it may +* be off for security by your web host) +*/ +function rss_get_feed($rssid, $url, $type) { + + global $CFG;; + $write = 0; + + $secs = $CFG->block_rss_timeout * 60; + + if (!file_exists($CFG->dataroot .'/cache/')) { + mkdir($CFG->dataroot .'/cache'); + } + if (!file_exists($CFG->dataroot .'/cache/rsscache/')) { + mkdir($CFG->dataroot .'/cache/rsscache'); + } + $file = $CFG->dataroot .'/cache/rsscache/'. $rssid .'.xml'; +// echo "file = ". $file; //debug + + //if feed in cache + if (file_exists($file)) { + //check age of cache file + // echo "file exists $file"; //debug + if ($CFG->debug){ + $data = stat($file); + } else { + $data = @stat($file); + } + $now = time(); + if (($now - $data[10]) > $secs) { //if timedout + // echo "read from original"; //debug + //read from source + if ($CFG->debug){ + $xml = file($url) or die ('Could not open the feed located at the url: ' . $url . 'allow_url_fopen needs to be On in the php.ini file for this file wrapper call to work. Please refer to http://us2.php.net/filesystem'); + } else { + $xml = @file($url) or die ('Could not open the feed located at the url: ' . $url .'allow_url_fopen needs to be On in the php.ini file for this file wrapper call to work. Please refer to http://us2.php.net/filesystem'); + } + $write = 1; + } else { + // echo "read from cache"; //debug + //read in from cache + if ($CFG->debug){ + $xml = file($file) or die ('Could not open the file located at: ' . $file); + } else { + $xml = @file($file) or die ('Could not open the file located at: ' . $file); + } + } + } else { //DNE, read from source + // echo "url: ".$url; //debug + + if ($CFG->debug){ + $xml = file($url) or die ('Could not open the feed located at the url: ' . $url . 'allow_url_fopen needs to be Onin the php.ini file for this file wrapper call to work. Please refer to http://us2.php.net/filesystem'); + } else { + $xml = @file($url) or die ('Could not open the feed located at the url: ' . $url . 'allow_url_fopen needs to be On in the php.ini file for this file wrapper call to work. Please refer to http://us2.php.net/filesystem'); + } + $write = 1; + } + + //print_object($xml); //debug + if ($CFG->debug){ + $xmlstr = implode(' ', $xml); + } else { + $xmlstr = @implode(' ', $xml); + } + + if ( $write && !empty($xmlstr) ) { //write file to cache + // jlb: adding file:/ to the start of the file name fixed + // some caching problems that I was experiencing. + //$file="file:/" + $file; + file_put_contents($file, $xmlstr); + } + + if ($type == 'A') { + //note: Atom is being modified by a working group + //http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html + include_once($CFG->dirroot .'/rss/class.Atom.php'); + $atom = new Atom($xmlstr); + $atom->channel = $atom->feed; + $atom->items = $atom->entries; + $atom->channel['description'] = $atom->channel['tagline']; + for($i=0;$iitems);$i++) { + $atom->items[$i]['description'] = $atom->items[$i]['content']; + } + return $atom; + } else { + include_once($CFG->dirroot .'/rss/class.RSS.php'); + $rss = new MagpieRSS($xmlstr); + return $rss; + } +} + + +function rss_display_feeds($rssid='none') { + global $db, $USER, $CFG, $THEME; + global $blogid; //hackish, but if there is a blogid it would be good to preserve it + + $closeTable = false; + //Daryl Hawes note: convert this sql statement to a moodle function call + if ($rssid != 'none'){ + $sql = 'SELECT * FROM '. $CFG->prefix .'block_rss_client WHERE id='. $rssid; + } else { + $sql = 'SELECT * FROM '. $CFG->prefix .'block_rss_client'; + } + + $res = $db->Execute($sql); +// print_object($res); //debug + + if ($res->fields){ + $closeTable = true; + ?> + + + + + + + fields){ + while(!$res->EOF) { + $editString = ' '; + $deleteString = ' '; + if ($res->fields['userid'] == $USER->id || isadmin()){ + $editString = ''; + $editString .= ''. get_string('edit');
+$editString .= ''; + + $deleteString = ''; + $deleteString .= ''. get_string('delete');
+$deleteString .= ''; + } + print '' ."\n"; + print '' ."\n"; + print ''."\n"; + $res->MoveNext(); + } + } + if ($closeTable){ + print '
'. $res->fields['title'] .'
' ."\n"; + print $res->fields['description'] .' 
' ."\n"; + print $res->fields['url'] .'  ' ."\n"; + print '(Validate)'; + print '
'. $editString .''. $deleteString .'
'."\n"; + } +} + +function rss_get_form($act, $url, $rssid, $rsstype, $printnow=true) { + global $USER, $CFG, $_SERVER, $blockid, $blockaction; + global $blogid; //hackish, but if there is a blogid it would be good to preserve it + + $returnstring = '
'; + if ($act == 'rss_edit') { + $returnstring .= get_string('edit'); + } else { + $returnstring .= get_string('block_rss_add_new', 'block_rss_client'); + } + $returnstring .= ' '. get_string('block_rss_feed', 'block_rss_client'); + + $returnstring .= '
'; + + $returnstring .= '
'; + $returnstring .= 'URL:
'; + $returnstring .= ''; + $returnstring .= ' 
'; + + $returnstring .= '
    ' . get_string('block_rss_find_more_feeds', 'block_rss_client'); +// removed as this is possibly out of place here +// $returnstring .= '
  • syndic8
  • NewsIsFree'; + $returnstring .= '
'; + $returnstring .= '
'; + + if ($printnow){ + print $returnstring; + } + return $returnstring; +} + +/** + * added by Daryl Hawes for rss/atom feeds + * found at http://us4.php.net/manual/en/function.fwrite.php + * added check for moodle debug option. if off then use '@' to suppress error/warning messages + */ +if (! function_exists('file_put_contents')){ + function file_put_contents($filename, $content) { + global $CFG; + $nr_of_bytes = 0; + if ($CFG->debug){ + if (($file = fopen($filename, 'w+')) === false) return false; + } else { + if (($file = @fopen($filename, 'w+')) === false) return false; + } + if ($CFG->debug){ + if ($nr_of_bytes = fwrite($file, $content, strlen($content)) === false) return false; + } else { + if ($nr_of_bytes = @fwrite($file, $content, strlen($content)) === false) return false; + } + fclose($file); + return $nr_of_bytes; + } +} +?> \ No newline at end of file -- 2.39.5