|
1 <?php |
|
2 /* |
|
3 Plugin Name: RSS Backend |
|
4 Plugin URI: http://enano.homelinux.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://enano.homelinux.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 'link' => $link, |
|
138 'gen' => $gen, |
|
139 'email' => $email, |
|
140 'lang' => 'en-us', |
|
141 'items' => Array() |
|
142 ); |
|
143 $this->this_channel =& $this->channels[$guid]; |
|
144 $this->this_guid = $guid; |
|
145 return $guid; |
|
146 } |
|
147 |
|
148 /** |
|
149 * Selects a specific channel to add items to |
|
150 * @param string The GUID of the channel |
|
151 */ |
|
152 |
|
153 function select_channel($guid) |
|
154 { |
|
155 if ( isset($this->channels[$guid]) ) |
|
156 { |
|
157 $this->this_channel =& $this->channels[$guid]; |
|
158 $this->guid = $guid; |
|
159 } |
|
160 } |
|
161 |
|
162 /** |
|
163 * Adds a news item. |
|
164 * @param string Title of the feed entry |
|
165 * @param string Link to where more information can be found |
|
166 * @param string Short description or content area |
|
167 * @param string Date the item was published. If this is a UNIX timestamp it will be formatted with date(). |
|
168 * @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. |
|
169 */ |
|
170 |
|
171 function add_item($title, $link, $desc, $pubdate, $guid = false) |
|
172 { |
|
173 $title = htmlspecialchars($title); |
|
174 $link = htmlspecialchars($link); |
|
175 $desc = '<![CDATA[ ' . str_replace(']]>', ']]>', $desc) . ']]>'; |
|
176 if ( is_int($pubdate) || ( !is_int($pub_date) && preg_match('/^([0-9]+)$/', $pubdate) ) ) |
|
177 { |
|
178 $pubdate = date('D, d M Y H:i:s T', intval($pubdate)); |
|
179 } |
|
180 if ( !$guid ) |
|
181 { |
|
182 $guid = md5 ( $title . $link . $desc . $pubdate ); |
|
183 $sec1 = substr($guid, 0, 8); |
|
184 $sec2 = substr($guid, 8, 4); |
|
185 $sec3 = substr($guid, 12, 4); |
|
186 $sec4 = substr($guid, 16, 4); |
|
187 $sec5 = substr($guid, 20, 12); |
|
188 $guid = sprintf('%s-%s-%s-%s-%s', $sec1, $sec2, $sec3, $sec4, $sec5); |
|
189 } |
|
190 $xml = " <item> |
|
191 <title>$title</title> |
|
192 <link>$link</link> |
|
193 <description> |
|
194 $desc |
|
195 </description> |
|
196 <pubDate>$pubdate</pubDate> |
|
197 <guid>$guid</guid> |
|
198 </item>"; |
|
199 $this->this_channel['items'][] = $xml; |
|
200 } |
|
201 |
|
202 /** |
|
203 * Converts everything into the final RSS feed. |
|
204 * @param bool If true, XML headers ("<?xml version="1.0" encoding="utf-8" ?>") are included. Defaults to true. |
|
205 * @return string |
|
206 */ |
|
207 |
|
208 function render($headers = true) |
|
209 { |
|
210 $xml = ''; |
|
211 if ( $headers ) |
|
212 // The weird quotes are because of a jEdit syntax highlighting bug |
|
213 $xml .= "<?xml version=".'"'."1.0".'"'." encoding=".'"'."utf-8".'"'." ?>\n"; |
|
214 $xml .= "<rss version=".'"'."2.0".'"'.">\n"; |
|
215 foreach ( $this->channels as $channel ) |
|
216 { |
|
217 $xml .= " <channel> |
|
218 <title>{$channel['title']}</title> |
|
219 <link>{$channel['link']}</link> |
|
220 <description>{$channel['desc']}</description> |
|
221 <generator>{$channel['gen']}</generator> |
|
222 <webMaster>{$channel['email']}</webMaster> |
|
223 <language>{$channel['lang']}</language> |
|
224 |
|
225 "; |
|
226 $content = implode("\n", $channel['items']) . "\n"; |
|
227 $xml .= $content; |
|
228 $xml .= " </channel>"; |
|
229 $xml .= " |
|
230 </rss>"; |
|
231 } |
|
232 return $xml; |
|
233 } |
|
234 |
|
235 } |
|
236 |
|
237 // function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace> |
|
238 |
|
239 function page_Special_RSS() { |
|
240 global $db, $session, $paths, $template, $plugins; // Common objects |
|
241 header('Content-type: text/xml; charset=windows-1252'); //application/rss+xml'); |
|
242 $mode = $paths->getParam(0); |
|
243 $n = $paths->getParam(1); |
|
244 if(!preg_match('#^([0-9]+)$#', $n) || (int)$n > 50) $n = 20; |
|
245 else $n = (int)$n; |
|
246 switch($mode) |
|
247 { |
|
248 case "recent": |
|
249 case false: |
|
250 $title = getConfig('site_name') . ' Recent Changes'; |
|
251 $desc = getConfig('site_desc'); |
|
252 |
|
253 $rss = new RSS($title, $desc); |
|
254 |
|
255 $q = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE log_type=\'page\' ORDER BY time_id DESC LIMIT '.$n.';'); |
|
256 if(!$q) |
|
257 { |
|
258 $rss->add_item('ERROR', '', 'Error selecting log data: ' . mysql_error() . '', time()); |
|
259 } |
|
260 else |
|
261 { |
|
262 while($row = $db->fetchrow()) |
|
263 { |
|
264 $link = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']); |
|
265 $title = $paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name']; |
|
266 $desc = ( $row['edit_summary'] != '' ) ? $row['edit_summary'] : 'No edit summary given.'; |
|
267 $date = $row['time_id']; |
|
268 $guid = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']).'?oldid='.$row['time_id']; |
|
269 |
|
270 $rss->add_item($title, $link, $desc, $date, $guid); |
|
271 } |
|
272 } |
|
273 |
|
274 echo $rss->render(); |
|
275 break; |
|
276 case "comments": |
|
277 $title = getConfig('site_name') . ' Latest Comments'; |
|
278 $desc = getConfig('site_desc'); |
|
279 |
|
280 $rss = new RSS($title, $desc); |
|
281 |
|
282 $q = $db->sql_query('SELECT * FROM '.table_prefix.'comments ORDER BY time DESC LIMIT '.$n.';'); |
|
283 |
|
284 if(!$q) |
|
285 { |
|
286 $rss->add_item('ERROR', '', 'Error selecting log data: ' . mysql_error() . '', time()); |
|
287 } |
|
288 else |
|
289 { |
|
290 $n = $db->numrows(); |
|
291 //echo '<!-- Number of rows: '.$n.' -->'; // ."\n<!-- SQL backtrace: \n\n".$db->sql_backtrace().' -->'; |
|
292 for ( $j = 0; $j < $n; $j++ ) |
|
293 { |
|
294 $row = $db->fetchrow($q); |
|
295 if(!is_array($row)) die(__FILE__.':'.__LINE__.' $row is not an array'); |
|
296 $link = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']).'#comments'; |
|
297 $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']; |
|
298 $title = $row['subject'] . ': Posted on page "'.$page.'" by user '.$row['name']; |
|
299 $desc = RenderMan::render($row['comment_data']); |
|
300 $date = $row['time']; |
|
301 $guid = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] . makeUrlNS($row['namespace'], $row['page_id']).'?do=comments&comment='.$row['time']; |
|
302 |
|
303 $rss->add_item($title, $link, $desc, $date, $guid); |
|
304 } |
|
305 } |
|
306 echo $rss->render(); |
|
307 break; |
|
308 default: |
|
309 $code = $plugins->setHook('feed_me_request'); |
|
310 foreach ( $code as $cmd ) |
|
311 { |
|
312 eval($cmd); |
|
313 } |
|
314 break; |
|
315 } |
|
316 } |
|
317 |
|
318 ?> |