plugins/SpecialRSS.php
changeset 3 f71442e3a95f
parent 2 882c793b0f37
child 4 308a696fce01
equal deleted inserted replaced
2:882c793b0f37 3:f71442e3a95f
     1 <?php
       
     2 /*
       
     3 Plugin Name: RSS Frontend
       
     4 Plugin URI: http://enanocms.org/Feed_me
       
     5 Description: Provides the page Special:RSS, which is used to generate RSS feeds of site and page content changes.
       
     6 Author: Dan Fuhry
       
     7 Version: 1.0
       
     8 Author URI: http://enanocms.org/
       
     9 */
       
    10 
       
    11 /*
       
    12  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
    13  * Version 1.0 release candidate 2
       
    14  * Copyright (C) 2006-2007 Dan Fuhry
       
    15  *
       
    16  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
    17  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    18  *
       
    19  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    20  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    21  */
       
    22  
       
    23 global $db, $session, $paths, $template, $plugins; // Common objects
       
    24 
       
    25 $plugins->attachHook('base_classes_initted', '
       
    26   $paths->add_page(Array(
       
    27     \'name\'=>\'RSS Feed - Latest changes\',
       
    28     \'urlname\'=>\'RSS\',
       
    29     \'namespace\'=>\'Special\',
       
    30     \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
       
    31     ));
       
    32   ');
       
    33 
       
    34 $plugins->attachHook('session_started', '__enanoRSSAttachHTMLHeaders();');
       
    35 
       
    36 function __enanoRSSAttachHTMLHeaders()
       
    37 {
       
    38   global $db, $session, $paths, $template, $plugins; // Common objects
       
    39   $template->add_header('<link rel="alternate" title="'.getConfig('site_name').' Changes feed" href="'.makeUrlNS('Special', 'RSS/recent', null, true).'" type="application/rss+xml" />');
       
    40   $template->add_header('<link rel="alternate" title="'.getConfig('site_name').' Comments feed" href="'.makeUrlNS('Special', 'RSS/comments', null, true).'" type="application/rss+xml" />');
       
    41 }
       
    42 
       
    43 define('ENANO_FEEDBURNER_INCLUDED', true);
       
    44 
       
    45 /**
       
    46  * Class for easily generating RSS feeds.
       
    47  * @package Enano
       
    48  * @subpackage Feed Me
       
    49  * @license GNU General Public License <http://www.gnu.org/licenses/gpl.html>
       
    50  */
       
    51  
       
    52 class RSS
       
    53 {
       
    54   
       
    55   /**
       
    56    * List of channels contained in this feed.
       
    57    * @var array
       
    58    */
       
    59   
       
    60   var $channels = Array();
       
    61   
       
    62   /**
       
    63    * The channel that's currently being operated on
       
    64    * @var array
       
    65    */
       
    66   
       
    67   var $this_channel = Array();
       
    68   
       
    69   /**
       
    70    * GUID of the current channel
       
    71    * @var string
       
    72    */
       
    73   
       
    74   var $this_guid = '';
       
    75   
       
    76   /**
       
    77    * List of fully XML-formatted feed entries.
       
    78    * @var array
       
    79    */
       
    80   
       
    81   var $items = Array();
       
    82   
       
    83   /**
       
    84    * Constructor.
       
    85    * @param string Feed title
       
    86    * @param string Feed description
       
    87    * @param string Linkback
       
    88    * @param string Generator
       
    89    * @param string E-mail of webmaster
       
    90    */
       
    91   
       
    92   function __construct($title = false, $desc = false, $link = false, $gen = false, $email = false)
       
    93   {
       
    94     $this->create_channel($title, $desc, $link, $gen, $email);
       
    95   }
       
    96   
       
    97   /**
       
    98    * PHP 4 constructor.
       
    99    */
       
   100   
       
   101   function RSS($title = false, $desc = false, $link = false, $gen = false, $email = false)
       
   102   {
       
   103     $this->__construct($title, $desc, $link, $gen, $email);
       
   104   }
       
   105   
       
   106   /** 
       
   107    * Creates a new channel.
       
   108    */
       
   109   
       
   110   function create_channel($title = false, $desc = false, $link = false, $gen = false, $email = false)
       
   111   {
       
   112     if ( empty($title) )
       
   113       $title = 'Untitled feed';
       
   114     else
       
   115       $title = htmlspecialchars($title);
       
   116     if ( empty($desc) )
       
   117       $desc = 'Test feed';
       
   118     else
       
   119       $desc = htmlspecialchars($desc);
       
   120     if ( empty($link) )
       
   121       $link = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . scriptPath . '/';
       
   122     else
       
   123       $link = htmlspecialchars($link);
       
   124     if ( !empty($gen) )
       
   125       $gen = htmlspecialchars($gen);
       
   126     else
       
   127       $gen = 'Enano CMS ' . enano_version();
       
   128     if ( !empty($email) )
       
   129       $email = htmlspecialchars($email);
       
   130     else
       
   131       $email = getConfig('contact_email');
       
   132     
       
   133     $this->channels = Array();
       
   134     $guid = md5(microtime() . mt_rand());
       
   135     $this->channels[$guid] = Array(
       
   136         'title' => $title,
       
   137         'desc' => $desc,
       
   138         'link' => $link,
       
   139         'gen' => $gen,
       
   140         'email' => $email,
       
   141         'lang' => 'en-us',
       
   142         'items' => Array()
       
   143       );
       
   144     $this->this_channel =& $this->channels[$guid];
       
   145     $this->this_guid = $guid;
       
   146     return $guid;
       
   147   }
       
   148   
       
   149   /**
       
   150    * Selects a specific channel to add items to
       
   151    * @param string The GUID of the channel
       
   152    */
       
   153   
       
   154   function select_channel($guid)
       
   155   {
       
   156     if ( isset($this->channels[$guid]) )
       
   157     {
       
   158       $this->this_channel =& $this->channels[$guid];
       
   159       $this->guid = $guid;
       
   160     }
       
   161   }
       
   162   
       
   163   /**
       
   164    * Adds a news item.
       
   165    * @param string Title of the feed entry
       
   166    * @param string Link to where more information can be found
       
   167    * @param string Short description or content area
       
   168    * @param string Date the item was published. If this is a UNIX timestamp it will be formatted with date().
       
   169    * @param string A Globally-Unique Identifier (GUID) for this item. Doesn't have to be a 128-bit hash - usually it's a link. If one is not provided, one is generated based on the first three parameters.
       
   170    */
       
   171   
       
   172   function add_item($title, $link, $desc, $pubdate, $guid = false)
       
   173   {
       
   174     $title = htmlspecialchars($title);
       
   175     $link = htmlspecialchars($link);
       
   176     $desc = '<![CDATA[ ' . str_replace(']]>', ']]&gt;', $desc) . ']]>';
       
   177     if ( is_int($pubdate) || ( !is_int($pub_date) && preg_match('/^([0-9]+)$/', $pubdate) ) )
       
   178     {
       
   179       $pubdate = date('D, d M Y H:i:s T', intval($pubdate));
       
   180     }
       
   181     if ( !$guid )
       
   182     {
       
   183       $guid = md5 ( $title . $link . $desc . $pubdate );
       
   184       $sec1 = substr($guid, 0, 8);
       
   185       $sec2 = substr($guid, 8, 4);
       
   186       $sec3 = substr($guid, 12, 4);
       
   187       $sec4 = substr($guid, 16, 4);
       
   188       $sec5 = substr($guid, 20, 12);
       
   189       $guid = sprintf('%s-%s-%s-%s-%s', $sec1, $sec2, $sec3, $sec4, $sec5);
       
   190     }
       
   191     $xml = "    <item>
       
   192       <title>$title</title>
       
   193       <link>$link</link>
       
   194       <description>
       
   195         $desc
       
   196       </description>
       
   197       <pubDate>$pubdate</pubDate>
       
   198       <guid>$guid</guid>
       
   199     </item>";
       
   200     $this->this_channel['items'][] = $xml;
       
   201   }
       
   202   
       
   203   /**
       
   204    * Converts everything into the final RSS feed.
       
   205    * @param bool If true, XML headers ("<?xml version="1.0" encoding="utf-8" ?>") are included. Defaults to true.
       
   206    * @return string
       
   207    */
       
   208   
       
   209   function render($headers = true)
       
   210   {
       
   211     $xml = '';
       
   212     if ( $headers )
       
   213       // The weird quotes are because of a jEdit syntax highlighting bug
       
   214       $xml .= "<?xml version=".'"'."1.0".'"'." encoding=".'"'."utf-8".'"'." ?>\n";
       
   215     $xml .= "<rss version=".'"'."2.0".'"'.">\n";
       
   216     foreach ( $this->channels as $channel )
       
   217     {
       
   218       $xml .= "  <channel>
       
   219     <title>{$channel['title']}</title>
       
   220     <link>{$channel['link']}</link>
       
   221     <description>{$channel['desc']}</description>
       
   222     <generator>{$channel['gen']}</generator>
       
   223     <webMaster>{$channel['email']}</webMaster>
       
   224     <language>{$channel['lang']}</language>
       
   225 
       
   226 ";
       
   227       $content = implode("\n", $channel['items']) . "\n";
       
   228       $xml .= $content;
       
   229       $xml .= "  </channel>";
       
   230       $xml .= "
       
   231 </rss>";
       
   232     }
       
   233     return $xml;
       
   234   }
       
   235   
       
   236 }
       
   237 
       
   238 // function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace>
       
   239 
       
   240 function page_Special_RSS()
       
   241 {
       
   242   global $db, $session, $paths, $template, $plugins; // Common objects
       
   243   header('Content-type: text/xml; charset=utf-8'); //application/rss+xml');
       
   244   global $aggressive_optimize_html;
       
   245   $aggressive_optimize_html = false;
       
   246   $session->sid_super = false;
       
   247   if ( $session->auth_level > USER_LEVEL_MEMBER )
       
   248     $session->auth_level = USER_LEVEL_MEMBER;
       
   249   $mode = $paths->getParam(0);
       
   250   $n = $paths->getParam(1);
       
   251   if(!preg_match('#^([0-9]+)$#', $n) || (int)$n > 50) $n = 20;
       
   252   else $n = (int)$n;
       
   253   switch($mode)
       
   254   {
       
   255     case "recent":
       
   256       $title = getConfig('site_name') . ' Recent Changes';
       
   257       $desc = getConfig('site_desc');
       
   258       
       
   259       $rss = new RSS($title, $desc);
       
   260       
       
   261       $q = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE log_type=\'page\' ORDER BY time_id DESC LIMIT '.$n.';');
       
   262       if(!$q)
       
   263       {
       
   264         $rss->add_item('ERROR', '', 'Error selecting log data: ' . mysql_error() . '', time());
       
   265       }
       
   266       else
       
   267       {
       
   268         while($row = $db->fetchrow())
       
   269         {
       
   270           $link = makeUrlComplete($row['namespace'], $row['page_id'], "oldid={$row['time_id']}"); // makeUrlComplete($row['namespace'], $row['page_id']);
       
   271           $title = $paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'];
       
   272           $desc = "Change by {$row['author']}:<br />";
       
   273           $desc .= ( $row['edit_summary'] != '' ) ? $row['edit_summary'] : 'No edit summary given.';
       
   274           $date = $row['time_id'];
       
   275           $guid = false;
       
   276           
       
   277           $rss->add_item($title, $link, $desc, $date, $guid);
       
   278         }
       
   279       }
       
   280       
       
   281       echo $rss->render();
       
   282       break;
       
   283     case "comments":
       
   284       $title = getConfig('site_name') . ' Latest Comments';
       
   285       $desc = getConfig('site_desc');
       
   286       
       
   287       $rss = new RSS($title, $desc);
       
   288       
       
   289       $q = $db->sql_query('SELECT * FROM '.table_prefix.'comments ORDER BY time DESC LIMIT '.$n.';');
       
   290         
       
   291       if(!$q)
       
   292       {
       
   293         $rss->add_item('ERROR', '', 'Error selecting log data: ' . mysql_error() . '', time());
       
   294       }
       
   295       else
       
   296       {
       
   297         $n = $db->numrows();
       
   298         //echo '<!-- Number of rows: '.$n.' -->'; // ."\n<!-- SQL backtrace: \n\n".$db->sql_backtrace().' -->';
       
   299         for ( $j = 0; $j < $n; $j++ )
       
   300         {
       
   301           $row = $db->fetchrow($q);
       
   302           if(!is_array($row)) die(__FILE__.':'.__LINE__.' $row is not an array');
       
   303           $link = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']).'#comments';
       
   304           $page = ( isset($paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]) ) ? $paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'] : $paths->nslist[$row['namespace']].$row['page_id'];
       
   305           $title = $row['subject'] . ': Posted on page "'.$page.'" by user '.$row['name'];
       
   306           $desc = RenderMan::render($row['comment_data']);
       
   307           $date = $row['time'];
       
   308           $guid = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']).'?do=comments&amp;comment='.$row['time'];
       
   309           
       
   310           $rss->add_item($title, $link, $desc, $date, $guid);
       
   311         }
       
   312       }
       
   313       echo $rss->render();
       
   314       break;
       
   315     default:
       
   316       $code = $plugins->setHook('feed_me_request');
       
   317       foreach ( $code as $cmd )
       
   318       {
       
   319         eval($cmd);
       
   320       }
       
   321       break;
       
   322   }
       
   323 }
       
   324 
       
   325 ?>