webmaster@1
|
1 <?php |
webmaster@9
|
2 // $Id: aggregator.module,v 1.374.2.3 2008/08/08 20:10:01 dries Exp $ |
webmaster@1
|
3 |
webmaster@1
|
4 /** |
webmaster@1
|
5 * @file |
webmaster@1
|
6 * Used to aggregate syndicated content (RSS, RDF, and Atom). |
webmaster@1
|
7 */ |
webmaster@1
|
8 |
webmaster@1
|
9 /** |
webmaster@1
|
10 * Implementation of hook_help(). |
webmaster@1
|
11 */ |
webmaster@1
|
12 function aggregator_help($path, $arg) { |
webmaster@1
|
13 switch ($path) { |
webmaster@1
|
14 case 'admin/help#aggregator': |
webmaster@1
|
15 $output = '<p>'. t('The aggregator is a powerful on-site syndicator and news reader that gathers fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="@rss">RSS</a>, <a href="@rdf">RDF</a>, and <a href="@atom">Atom</a>.', array('@rss' => 'http://cyber.law.harvard.edu/rss/', '@rdf' => 'http://www.w3.org/RDF/', '@atom' => 'http://www.atomenabled.org')) .'</p>'; |
webmaster@1
|
16 $output .= '<p>'. t('Feeds contain feed items, or individual posts published by the site providing the feed. Feeds may be grouped in categories, generally by topic. Users view feed items in the <a href="@aggregator">main aggregator display</a> or by <a href="@aggregator-sources">their source</a>. Administrators can <a href="@feededit">add, edit and delete feeds</a> and choose how often to check each feed for newly updated items. The most recent items in either a feed or category can be displayed as a block through the <a href="@admin-block">blocks administration page</a>. A <a href="@aggregator-opml">machine-readable OPML file</a> of all feeds is available. A correctly configured <a href="@cron">cron maintenance task</a> is required to update feeds automatically.', array('@aggregator' => url('aggregator'), '@aggregator-sources' => url('aggregator/sources'), '@feededit' => url('admin/content/aggregator'), '@admin-block' => url('admin/build/block'), '@aggregator-opml' => url('aggregator/opml'), '@cron' => url('admin/reports/status'))) .'</p>'; |
webmaster@1
|
17 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@aggregator">Aggregator module</a>.', array('@aggregator' => 'http://drupal.org/handbook/modules/aggregator/')) .'</p>'; |
webmaster@1
|
18 return $output; |
webmaster@1
|
19 case 'admin/content/aggregator': |
webmaster@7
|
20 $output = '<p>'. t('Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="@rss">RSS</a>, <a href="@rdf">RDF</a>, and <a href="@atom">Atom</a>.', array('@rss' => 'http://cyber.law.harvard.edu/rss/', '@rdf' => 'http://www.w3.org/RDF/', '@atom' => 'http://www.atomenabled.org')) .'</p>'; |
webmaster@1
|
21 $output .= '<p>'. t('Current feeds are listed below, and <a href="@addfeed">new feeds may be added</a>. For each feed or feed category, the <em>latest items</em> block may be enabled at the <a href="@block">blocks administration page</a>.', array('@addfeed' => url('admin/content/aggregator/add/feed'), '@block' => url('admin/build/block'))) .'</p>'; |
webmaster@1
|
22 return $output; |
webmaster@1
|
23 case 'admin/content/aggregator/add/feed': |
webmaster@1
|
24 return '<p>'. t('Add a feed in RSS, RDF or Atom format. A feed may only have one entry.') .'</p>'; |
webmaster@1
|
25 case 'admin/content/aggregator/add/category': |
webmaster@1
|
26 return '<p>'. t('Categories allow feed items from different feeds to be grouped together. For example, several sport-related feeds may belong to a category named <em>Sports</em>. Feed items may be grouped automatically (by selecting a category when creating or editing a feed) or manually (via the <em>Categorize</em> page available from feed item listings). Each category provides its own feed page and block.') .'</p>'; |
webmaster@1
|
27 } |
webmaster@1
|
28 } |
webmaster@1
|
29 |
webmaster@1
|
30 /** |
webmaster@1
|
31 * Implementation of hook_theme() |
webmaster@1
|
32 */ |
webmaster@1
|
33 function aggregator_theme() { |
webmaster@1
|
34 return array( |
webmaster@1
|
35 'aggregator_wrapper' => array( |
webmaster@1
|
36 'arguments' => array('content' => NULL), |
webmaster@1
|
37 'file' => 'aggregator.pages.inc', |
webmaster@1
|
38 'template' => 'aggregator-wrapper', |
webmaster@1
|
39 ), |
webmaster@1
|
40 'aggregator_categorize_items' => array( |
webmaster@1
|
41 'arguments' => array('form' => NULL), |
webmaster@1
|
42 'file' => 'aggregator.pages.inc', |
webmaster@1
|
43 ), |
webmaster@1
|
44 'aggregator_feed_source' => array( |
webmaster@1
|
45 'arguments' => array('feed' => NULL), |
webmaster@1
|
46 'file' => 'aggregator.pages.inc', |
webmaster@1
|
47 'template' => 'aggregator-feed-source', |
webmaster@1
|
48 ), |
webmaster@1
|
49 'aggregator_block_item' => array( |
webmaster@1
|
50 'arguments' => array('item' => NULL, 'feed' => 0), |
webmaster@1
|
51 ), |
webmaster@1
|
52 'aggregator_summary_items' => array( |
webmaster@1
|
53 'arguments' => array('summary_items' => NULL, 'source' => NULL), |
webmaster@1
|
54 'file' => 'aggregator.pages.inc', |
webmaster@1
|
55 'template' => 'aggregator-summary-items', |
webmaster@1
|
56 ), |
webmaster@1
|
57 'aggregator_summary_item' => array( |
webmaster@1
|
58 'arguments' => array('item' => NULL), |
webmaster@1
|
59 'file' => 'aggregator.pages.inc', |
webmaster@1
|
60 'template' => 'aggregator-summary-item', |
webmaster@1
|
61 ), |
webmaster@1
|
62 'aggregator_item' => array( |
webmaster@1
|
63 'arguments' => array('item' => NULL), |
webmaster@1
|
64 'file' => 'aggregator.pages.inc', |
webmaster@1
|
65 'template' => 'aggregator-item', |
webmaster@1
|
66 ), |
webmaster@1
|
67 'aggregator_page_opml' => array( |
webmaster@1
|
68 'arguments' => array('feeds' => NULL), |
webmaster@1
|
69 'file' => 'aggregator.pages.inc', |
webmaster@1
|
70 ), |
webmaster@1
|
71 'aggregator_page_rss' => array( |
webmaster@1
|
72 'arguments' => array('feeds' => NULL, 'category' => NULL), |
webmaster@1
|
73 'file' => 'aggregator.pages.inc', |
webmaster@1
|
74 ), |
webmaster@1
|
75 ); |
webmaster@1
|
76 } |
webmaster@1
|
77 |
webmaster@1
|
78 /** |
webmaster@1
|
79 * Implementation of hook_menu(). |
webmaster@1
|
80 */ |
webmaster@1
|
81 function aggregator_menu() { |
webmaster@1
|
82 $items['admin/content/aggregator'] = array( |
webmaster@1
|
83 'title' => 'Feed aggregator', |
webmaster@1
|
84 'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.", |
webmaster@1
|
85 'page callback' => 'aggregator_admin_overview', |
webmaster@1
|
86 'access arguments' => array('administer news feeds'), |
webmaster@1
|
87 'file' => 'aggregator.admin.inc', |
webmaster@1
|
88 ); |
webmaster@1
|
89 $items['admin/content/aggregator/add/feed'] = array( |
webmaster@1
|
90 'title' => 'Add feed', |
webmaster@1
|
91 'page callback' => 'drupal_get_form', |
webmaster@1
|
92 'page arguments' => array('aggregator_form_feed'), |
webmaster@1
|
93 'access arguments' => array('administer news feeds'), |
webmaster@1
|
94 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
95 'parent' => 'admin/content/aggregator', |
webmaster@1
|
96 'file' => 'aggregator.admin.inc', |
webmaster@1
|
97 ); |
webmaster@1
|
98 $items['admin/content/aggregator/add/category'] = array( |
webmaster@1
|
99 'title' => 'Add category', |
webmaster@1
|
100 'page callback' => 'drupal_get_form', |
webmaster@1
|
101 'page arguments' => array('aggregator_form_category'), |
webmaster@1
|
102 'access arguments' => array('administer news feeds'), |
webmaster@1
|
103 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
104 'parent' => 'admin/content/aggregator', |
webmaster@1
|
105 'file' => 'aggregator.admin.inc', |
webmaster@1
|
106 ); |
webmaster@1
|
107 $items['admin/content/aggregator/remove/%aggregator_feed'] = array( |
webmaster@1
|
108 'title' => 'Remove items', |
webmaster@1
|
109 'page callback' => 'drupal_get_form', |
webmaster@1
|
110 'page arguments' => array('aggregator_admin_remove_feed', 4), |
webmaster@1
|
111 'access arguments' => array('administer news feeds'), |
webmaster@1
|
112 'type' => MENU_CALLBACK, |
webmaster@1
|
113 'file' => 'aggregator.admin.inc', |
webmaster@1
|
114 ); |
webmaster@1
|
115 $items['admin/content/aggregator/update/%aggregator_feed'] = array( |
webmaster@1
|
116 'title' => 'Update items', |
webmaster@1
|
117 'page callback' => 'aggregator_admin_refresh_feed', |
webmaster@1
|
118 'page arguments' => array(4), |
webmaster@1
|
119 'access arguments' => array('administer news feeds'), |
webmaster@1
|
120 'type' => MENU_CALLBACK, |
webmaster@1
|
121 'file' => 'aggregator.admin.inc', |
webmaster@1
|
122 ); |
webmaster@1
|
123 $items['admin/content/aggregator/list'] = array( |
webmaster@1
|
124 'title' => 'List', |
webmaster@1
|
125 'type' => MENU_DEFAULT_LOCAL_TASK, |
webmaster@1
|
126 'weight' => -10, |
webmaster@1
|
127 ); |
webmaster@1
|
128 $items['admin/content/aggregator/settings'] = array( |
webmaster@1
|
129 'title' => 'Settings', |
webmaster@1
|
130 'page callback' => 'drupal_get_form', |
webmaster@1
|
131 'page arguments' => array('aggregator_admin_settings'), |
webmaster@1
|
132 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
133 'weight' => 10, |
webmaster@1
|
134 'access arguments' => array('administer news feeds'), |
webmaster@1
|
135 'file' => 'aggregator.admin.inc', |
webmaster@1
|
136 ); |
webmaster@1
|
137 $items['aggregator'] = array( |
webmaster@1
|
138 'title' => 'Feed aggregator', |
webmaster@1
|
139 'page callback' => 'aggregator_page_last', |
webmaster@1
|
140 'access arguments' => array('access news feeds'), |
webmaster@1
|
141 'weight' => 5, |
webmaster@1
|
142 'file' => 'aggregator.pages.inc', |
webmaster@1
|
143 ); |
webmaster@1
|
144 $items['aggregator/sources'] = array( |
webmaster@1
|
145 'title' => 'Sources', |
webmaster@1
|
146 'page callback' => 'aggregator_page_sources', |
webmaster@1
|
147 'access arguments' => array('access news feeds'), |
webmaster@1
|
148 'file' => 'aggregator.pages.inc', |
webmaster@1
|
149 ); |
webmaster@1
|
150 $items['aggregator/categories'] = array( |
webmaster@1
|
151 'title' => 'Categories', |
webmaster@1
|
152 'page callback' => 'aggregator_page_categories', |
webmaster@1
|
153 'access callback' => '_aggregator_has_categories', |
webmaster@1
|
154 'file' => 'aggregator.pages.inc', |
webmaster@1
|
155 ); |
webmaster@1
|
156 $items['aggregator/rss'] = array( |
webmaster@1
|
157 'title' => 'RSS feed', |
webmaster@1
|
158 'page callback' => 'aggregator_page_rss', |
webmaster@1
|
159 'access arguments' => array('access news feeds'), |
webmaster@1
|
160 'type' => MENU_CALLBACK, |
webmaster@1
|
161 'file' => 'aggregator.pages.inc', |
webmaster@1
|
162 ); |
webmaster@1
|
163 $items['aggregator/opml'] = array( |
webmaster@1
|
164 'title' => 'OPML feed', |
webmaster@1
|
165 'page callback' => 'aggregator_page_opml', |
webmaster@1
|
166 'access arguments' => array('access news feeds'), |
webmaster@1
|
167 'type' => MENU_CALLBACK, |
webmaster@1
|
168 'file' => 'aggregator.pages.inc', |
webmaster@1
|
169 ); |
webmaster@1
|
170 $items['aggregator/categories/%aggregator_category'] = array( |
webmaster@1
|
171 'title callback' => '_aggregator_category_title', |
webmaster@1
|
172 'title arguments' => array(2), |
webmaster@1
|
173 'page callback' => 'aggregator_page_category', |
webmaster@1
|
174 'page arguments' => array(2), |
webmaster@1
|
175 'access callback' => 'user_access', |
webmaster@1
|
176 'access arguments' => array('access news feeds'), |
webmaster@1
|
177 'file' => 'aggregator.pages.inc', |
webmaster@1
|
178 ); |
webmaster@1
|
179 $items['aggregator/categories/%aggregator_category/view'] = array( |
webmaster@1
|
180 'title' => 'View', |
webmaster@1
|
181 'type' => MENU_DEFAULT_LOCAL_TASK, |
webmaster@1
|
182 'weight' => -10, |
webmaster@1
|
183 ); |
webmaster@1
|
184 $items['aggregator/categories/%aggregator_category/categorize'] = array( |
webmaster@1
|
185 'title' => 'Categorize', |
webmaster@1
|
186 'page callback' => 'drupal_get_form', |
webmaster@1
|
187 'page arguments' => array('aggregator_page_category', 2), |
webmaster@1
|
188 'access arguments' => array('administer news feeds'), |
webmaster@1
|
189 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
190 'file' => 'aggregator.pages.inc', |
webmaster@1
|
191 ); |
webmaster@1
|
192 $items['aggregator/categories/%aggregator_category/configure'] = array( |
webmaster@1
|
193 'title' => 'Configure', |
webmaster@1
|
194 'page callback' => 'drupal_get_form', |
webmaster@1
|
195 'page arguments' => array('aggregator_form_category', 2), |
webmaster@1
|
196 'access arguments' => array('administer news feeds'), |
webmaster@1
|
197 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
198 'weight' => 1, |
webmaster@1
|
199 'file' => 'aggregator.admin.inc', |
webmaster@1
|
200 ); |
webmaster@1
|
201 $items['aggregator/sources/%aggregator_feed'] = array( |
webmaster@1
|
202 'page callback' => 'aggregator_page_source', |
webmaster@1
|
203 'page arguments' => array(2), |
webmaster@5
|
204 'access arguments' => array('access news feeds'), |
webmaster@1
|
205 'type' => MENU_CALLBACK, |
webmaster@1
|
206 'file' => 'aggregator.pages.inc', |
webmaster@1
|
207 ); |
webmaster@1
|
208 $items['aggregator/sources/%aggregator_feed/view'] = array( |
webmaster@1
|
209 'title' => 'View', |
webmaster@1
|
210 'type' => MENU_DEFAULT_LOCAL_TASK, |
webmaster@1
|
211 'weight' => -10, |
webmaster@1
|
212 ); |
webmaster@1
|
213 $items['aggregator/sources/%aggregator_feed/categorize'] = array( |
webmaster@1
|
214 'title' => 'Categorize', |
webmaster@1
|
215 'page callback' => 'drupal_get_form', |
webmaster@1
|
216 'page arguments' => array('aggregator_page_source', 2), |
webmaster@1
|
217 'access arguments' => array('administer news feeds'), |
webmaster@1
|
218 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
219 'file' => 'aggregator.pages.inc', |
webmaster@1
|
220 ); |
webmaster@1
|
221 $items['aggregator/sources/%aggregator_feed/configure'] = array( |
webmaster@1
|
222 'title' => 'Configure', |
webmaster@1
|
223 'page callback' => 'drupal_get_form', |
webmaster@1
|
224 'page arguments' => array('aggregator_form_feed', 2), |
webmaster@1
|
225 'access arguments' => array('administer news feeds'), |
webmaster@1
|
226 'type' => MENU_LOCAL_TASK, |
webmaster@1
|
227 'weight' => 1, |
webmaster@1
|
228 'file' => 'aggregator.admin.inc', |
webmaster@1
|
229 ); |
webmaster@1
|
230 $items['admin/content/aggregator/edit/feed/%aggregator_feed'] = array( |
webmaster@1
|
231 'title' => 'Edit feed', |
webmaster@1
|
232 'page callback' => 'drupal_get_form', |
webmaster@1
|
233 'page arguments' => array('aggregator_form_feed', 5), |
webmaster@1
|
234 'access arguments' => array('administer news feeds'), |
webmaster@1
|
235 'type' => MENU_CALLBACK, |
webmaster@1
|
236 'file' => 'aggregator.admin.inc', |
webmaster@1
|
237 ); |
webmaster@1
|
238 $items['admin/content/aggregator/edit/category/%aggregator_category'] = array( |
webmaster@1
|
239 'title' => 'Edit category', |
webmaster@1
|
240 'page callback' => 'drupal_get_form', |
webmaster@1
|
241 'page arguments' => array('aggregator_form_category', 5), |
webmaster@1
|
242 'access arguments' => array('administer news feeds'), |
webmaster@1
|
243 'type' => MENU_CALLBACK, |
webmaster@1
|
244 'file' => 'aggregator.admin.inc', |
webmaster@1
|
245 ); |
webmaster@1
|
246 |
webmaster@1
|
247 return $items; |
webmaster@1
|
248 } |
webmaster@1
|
249 |
webmaster@1
|
250 /** |
webmaster@1
|
251 * Menu callback. |
webmaster@1
|
252 * |
webmaster@1
|
253 * @return |
webmaster@1
|
254 * An aggregator category title. |
webmaster@1
|
255 */ |
webmaster@1
|
256 function _aggregator_category_title($category) { |
webmaster@1
|
257 return $category['title']; |
webmaster@1
|
258 } |
webmaster@1
|
259 |
webmaster@1
|
260 /** |
webmaster@1
|
261 * Implementation of hook_init(). |
webmaster@1
|
262 */ |
webmaster@1
|
263 function aggregator_init() { |
webmaster@1
|
264 drupal_add_css(drupal_get_path('module', 'aggregator') .'/aggregator.css'); |
webmaster@1
|
265 } |
webmaster@1
|
266 |
webmaster@1
|
267 /** |
webmaster@1
|
268 * Find out whether there are any aggregator categories. |
webmaster@1
|
269 * |
webmaster@1
|
270 * @return |
webmaster@1
|
271 * TRUE if there is at least one category and the user has access to them, FALSE otherwise. |
webmaster@1
|
272 */ |
webmaster@1
|
273 function _aggregator_has_categories() { |
webmaster@1
|
274 return user_access('access news feeds') && db_result(db_query('SELECT COUNT(*) FROM {aggregator_category}')); |
webmaster@1
|
275 } |
webmaster@1
|
276 |
webmaster@1
|
277 /** |
webmaster@1
|
278 * Implementation of hook_perm(). |
webmaster@1
|
279 */ |
webmaster@1
|
280 function aggregator_perm() { |
webmaster@1
|
281 return array('administer news feeds', 'access news feeds'); |
webmaster@1
|
282 } |
webmaster@1
|
283 |
webmaster@1
|
284 /** |
webmaster@1
|
285 * Implementation of hook_cron(). |
webmaster@1
|
286 * |
webmaster@1
|
287 * Checks news feeds for updates once their refresh interval has elapsed. |
webmaster@1
|
288 */ |
webmaster@1
|
289 function aggregator_cron() { |
webmaster@1
|
290 $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < %d', time()); |
webmaster@1
|
291 while ($feed = db_fetch_array($result)) { |
webmaster@1
|
292 aggregator_refresh($feed); |
webmaster@1
|
293 } |
webmaster@1
|
294 } |
webmaster@1
|
295 |
webmaster@1
|
296 /** |
webmaster@1
|
297 * Implementation of hook_block(). |
webmaster@1
|
298 * |
webmaster@1
|
299 * Generates blocks for the latest news items in each category and feed. |
webmaster@1
|
300 */ |
webmaster@1
|
301 function aggregator_block($op = 'list', $delta = 0, $edit = array()) { |
webmaster@1
|
302 if (user_access('access news feeds')) { |
webmaster@1
|
303 if ($op == 'list') { |
webmaster@1
|
304 $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title'); |
webmaster@1
|
305 while ($category = db_fetch_object($result)) { |
webmaster@1
|
306 $block['category-'. $category->cid]['info'] = t('!title category latest items', array('!title' => $category->title)); |
webmaster@1
|
307 } |
webmaster@1
|
308 $result = db_query('SELECT fid, title FROM {aggregator_feed} ORDER BY fid'); |
webmaster@1
|
309 while ($feed = db_fetch_object($result)) { |
webmaster@1
|
310 $block['feed-'. $feed->fid]['info'] = t('!title feed latest items', array('!title' => $feed->title)); |
webmaster@1
|
311 } |
webmaster@1
|
312 } |
webmaster@1
|
313 else if ($op == 'configure') { |
webmaster@1
|
314 list($type, $id) = explode('-', $delta); |
webmaster@1
|
315 if ($type == 'category') { |
webmaster@1
|
316 $value = db_result(db_query('SELECT block FROM {aggregator_category} WHERE cid = %d', $id)); |
webmaster@1
|
317 } |
webmaster@1
|
318 else { |
webmaster@1
|
319 $value = db_result(db_query('SELECT block FROM {aggregator_feed} WHERE fid = %d', $id)); |
webmaster@1
|
320 } |
webmaster@1
|
321 $form['block'] = array('#type' => 'select', '#title' => t('Number of news items in block'), '#default_value' => $value, '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20))); |
webmaster@1
|
322 return $form; |
webmaster@1
|
323 } |
webmaster@1
|
324 else if ($op == 'save') { |
webmaster@1
|
325 list($type, $id) = explode('-', $delta); |
webmaster@1
|
326 if ($type == 'category') { |
webmaster@1
|
327 $value = db_query('UPDATE {aggregator_category} SET block = %d WHERE cid = %d', $edit['block'], $id); |
webmaster@1
|
328 } |
webmaster@1
|
329 else { |
webmaster@1
|
330 $value = db_query('UPDATE {aggregator_feed} SET block = %d WHERE fid = %d', $edit['block'], $id); |
webmaster@1
|
331 } |
webmaster@1
|
332 } |
webmaster@1
|
333 else if ($op == 'view') { |
webmaster@1
|
334 list($type, $id) = explode('-', $delta); |
webmaster@1
|
335 switch ($type) { |
webmaster@1
|
336 case 'feed': |
webmaster@1
|
337 if ($feed = db_fetch_object(db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE fid = %d', $id))) { |
webmaster@1
|
338 $block['subject'] = check_plain($feed->title); |
webmaster@1
|
339 $result = db_query_range('SELECT * FROM {aggregator_item} WHERE fid = %d ORDER BY timestamp DESC, iid DESC', $feed->fid, 0, $feed->block); |
webmaster@1
|
340 $read_more = theme('more_link', url('aggregator/sources/'. $feed->fid), t("View this feed's recent news.")); |
webmaster@1
|
341 } |
webmaster@1
|
342 break; |
webmaster@1
|
343 |
webmaster@1
|
344 case 'category': |
webmaster@1
|
345 if ($category = db_fetch_object(db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = %d', $id))) { |
webmaster@1
|
346 $block['subject'] = check_plain($category->title); |
webmaster@1
|
347 $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = %d ORDER BY i.timestamp DESC, i.iid DESC', $category->cid, 0, $category->block); |
webmaster@1
|
348 $read_more = theme('more_link', url('aggregator/categories/'. $category->cid), t("View this category's recent news.")); |
webmaster@1
|
349 } |
webmaster@1
|
350 break; |
webmaster@1
|
351 } |
webmaster@1
|
352 $items = array(); |
webmaster@1
|
353 while ($item = db_fetch_object($result)) { |
webmaster@1
|
354 $items[] = theme('aggregator_block_item', $item); |
webmaster@1
|
355 } |
webmaster@1
|
356 |
webmaster@1
|
357 // Only display the block if there are items to show. |
webmaster@1
|
358 if (count($items) > 0) { |
webmaster@1
|
359 $block['content'] = theme('item_list', $items) . $read_more; |
webmaster@1
|
360 } |
webmaster@1
|
361 } |
webmaster@1
|
362 if (isset($block)) { |
webmaster@1
|
363 return $block; |
webmaster@1
|
364 } |
webmaster@1
|
365 } |
webmaster@1
|
366 } |
webmaster@1
|
367 |
webmaster@1
|
368 /** |
webmaster@1
|
369 * Add/edit/delete aggregator categories. |
webmaster@1
|
370 * |
webmaster@1
|
371 * @param $edit |
webmaster@1
|
372 * An associative array describing the category to be added/edited/deleted. |
webmaster@1
|
373 */ |
webmaster@1
|
374 function aggregator_save_category($edit) { |
webmaster@1
|
375 $link_path = 'aggregator/categories/'; |
webmaster@1
|
376 if (!empty($edit['cid'])) { |
webmaster@1
|
377 $link_path .= $edit['cid']; |
webmaster@1
|
378 if (!empty($edit['title'])) { |
webmaster@1
|
379 db_query("UPDATE {aggregator_category} SET title = '%s', description = '%s' WHERE cid = %d", $edit['title'], $edit['description'], $edit['cid']); |
webmaster@1
|
380 $op = 'update'; |
webmaster@1
|
381 } |
webmaster@1
|
382 else { |
webmaster@1
|
383 db_query('DELETE FROM {aggregator_category} WHERE cid = %d', $edit['cid']); |
webmaster@9
|
384 // Make sure there is no active block for this category. |
webmaster@9
|
385 db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'", 'aggregator', 'category-' . $edit['cid']); |
webmaster@1
|
386 $edit['title'] = ''; |
webmaster@1
|
387 $op = 'delete'; |
webmaster@1
|
388 } |
webmaster@1
|
389 } |
webmaster@1
|
390 else if (!empty($edit['title'])) { |
webmaster@1
|
391 // A single unique id for bundles and feeds, to use in blocks |
webmaster@1
|
392 db_query("INSERT INTO {aggregator_category} (title, description, block) VALUES ('%s', '%s', 5)", $edit['title'], $edit['description']); |
webmaster@1
|
393 $link_path .= db_last_insert_id('aggregator', 'cid'); |
webmaster@1
|
394 $op = 'insert'; |
webmaster@1
|
395 } |
webmaster@1
|
396 if (isset($op)) { |
webmaster@1
|
397 menu_link_maintain('aggregator', $op, $link_path, $edit['title']); |
webmaster@1
|
398 } |
webmaster@1
|
399 } |
webmaster@1
|
400 |
webmaster@1
|
401 /** |
webmaster@1
|
402 * Add/edit/delete an aggregator feed. |
webmaster@1
|
403 * |
webmaster@1
|
404 * @param $edit |
webmaster@1
|
405 * An associative array describing the feed to be added/edited/deleted. |
webmaster@1
|
406 */ |
webmaster@1
|
407 function aggregator_save_feed($edit) { |
webmaster@1
|
408 if (!empty($edit['fid'])) { |
webmaster@1
|
409 // An existing feed is being modified, delete the category listings. |
webmaster@1
|
410 db_query('DELETE FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']); |
webmaster@1
|
411 } |
webmaster@1
|
412 if (!empty($edit['fid']) && !empty($edit['title'])) { |
webmaster@1
|
413 db_query("UPDATE {aggregator_feed} SET title = '%s', url = '%s', refresh = %d WHERE fid = %d", $edit['title'], $edit['url'], $edit['refresh'], $edit['fid']); |
webmaster@1
|
414 } |
webmaster@1
|
415 else if (!empty($edit['fid'])) { |
webmaster@1
|
416 $items = array(); |
webmaster@1
|
417 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $edit['fid']); |
webmaster@1
|
418 while ($item = db_fetch_object($result)) { |
webmaster@1
|
419 $items[] = "iid = $item->iid"; |
webmaster@1
|
420 } |
webmaster@1
|
421 if (!empty($items)) { |
webmaster@1
|
422 db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items)); |
webmaster@1
|
423 } |
webmaster@1
|
424 db_query('DELETE FROM {aggregator_feed} WHERE fid = %d', $edit['fid']); |
webmaster@1
|
425 db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $edit['fid']); |
webmaster@9
|
426 // Make sure there is no active block for this feed. |
webmaster@9
|
427 db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'", 'aggregator', 'feed-' . $edit['fid']); |
webmaster@1
|
428 } |
webmaster@1
|
429 else if (!empty($edit['title'])) { |
webmaster@1
|
430 db_query("INSERT INTO {aggregator_feed} (title, url, refresh, block, description, image) VALUES ('%s', '%s', %d, 5, '', '')", $edit['title'], $edit['url'], $edit['refresh']); |
webmaster@1
|
431 // A single unique id for bundles and feeds, to use in blocks. |
webmaster@1
|
432 $edit['fid'] = db_last_insert_id('aggregator_feed', 'fid'); |
webmaster@1
|
433 } |
webmaster@1
|
434 if (!empty($edit['title'])) { |
webmaster@1
|
435 // The feed is being saved, save the categories as well. |
webmaster@1
|
436 if (!empty($edit['category'])) { |
webmaster@1
|
437 foreach ($edit['category'] as $cid => $value) { |
webmaster@1
|
438 if ($value) { |
webmaster@1
|
439 db_query('INSERT INTO {aggregator_category_feed} (fid, cid) VALUES (%d, %d)', $edit['fid'], $cid); |
webmaster@1
|
440 } |
webmaster@1
|
441 } |
webmaster@1
|
442 } |
webmaster@1
|
443 } |
webmaster@1
|
444 } |
webmaster@1
|
445 |
webmaster@1
|
446 /** |
webmaster@1
|
447 * Removes all items from a feed. |
webmaster@1
|
448 * |
webmaster@1
|
449 * @param $feed |
webmaster@1
|
450 * An associative array describing the feed to be cleared. |
webmaster@1
|
451 */ |
webmaster@1
|
452 function aggregator_remove($feed) { |
webmaster@1
|
453 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $feed['fid']); |
webmaster@1
|
454 while ($item = db_fetch_object($result)) { |
webmaster@1
|
455 $items[] = "iid = $item->iid"; |
webmaster@1
|
456 } |
webmaster@1
|
457 if (!empty($items)) { |
webmaster@1
|
458 db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items)); |
webmaster@1
|
459 } |
webmaster@1
|
460 db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $feed['fid']); |
webmaster@1
|
461 db_query("UPDATE {aggregator_feed} SET checked = 0, etag = '', modified = 0 WHERE fid = %d", $feed['fid']); |
webmaster@1
|
462 drupal_set_message(t('The news items from %site have been removed.', array('%site' => $feed['title']))); |
webmaster@1
|
463 } |
webmaster@1
|
464 |
webmaster@1
|
465 /** |
webmaster@1
|
466 * Call-back function used by the XML parser. |
webmaster@1
|
467 */ |
webmaster@1
|
468 function aggregator_element_start($parser, $name, $attributes) { |
webmaster@1
|
469 global $item, $element, $tag, $items, $channel; |
webmaster@1
|
470 |
webmaster@1
|
471 switch ($name) { |
webmaster@1
|
472 case 'IMAGE': |
webmaster@1
|
473 case 'TEXTINPUT': |
webmaster@1
|
474 case 'CONTENT': |
webmaster@1
|
475 case 'SUMMARY': |
webmaster@1
|
476 case 'TAGLINE': |
webmaster@1
|
477 case 'SUBTITLE': |
webmaster@1
|
478 case 'LOGO': |
webmaster@1
|
479 case 'INFO': |
webmaster@1
|
480 $element = $name; |
webmaster@1
|
481 break; |
webmaster@1
|
482 case 'ID': |
webmaster@1
|
483 if ($element != 'ITEM') { |
webmaster@1
|
484 $element = $name; |
webmaster@1
|
485 } |
webmaster@1
|
486 case 'LINK': |
webmaster@1
|
487 if (!empty($attributes['REL']) && $attributes['REL'] == 'alternate') { |
webmaster@1
|
488 if ($element == 'ITEM') { |
webmaster@1
|
489 $items[$item]['LINK'] = $attributes['HREF']; |
webmaster@1
|
490 } |
webmaster@1
|
491 else { |
webmaster@1
|
492 $channel['LINK'] = $attributes['HREF']; |
webmaster@1
|
493 } |
webmaster@1
|
494 } |
webmaster@1
|
495 break; |
webmaster@1
|
496 case 'ITEM': |
webmaster@1
|
497 $element = $name; |
webmaster@1
|
498 $item += 1; |
webmaster@1
|
499 break; |
webmaster@1
|
500 case 'ENTRY': |
webmaster@1
|
501 $element = 'ITEM'; |
webmaster@1
|
502 $item += 1; |
webmaster@1
|
503 break; |
webmaster@1
|
504 } |
webmaster@1
|
505 |
webmaster@1
|
506 $tag = $name; |
webmaster@1
|
507 } |
webmaster@1
|
508 |
webmaster@1
|
509 /** |
webmaster@1
|
510 * Call-back function used by the XML parser. |
webmaster@1
|
511 */ |
webmaster@1
|
512 function aggregator_element_end($parser, $name) { |
webmaster@1
|
513 global $element; |
webmaster@1
|
514 |
webmaster@1
|
515 switch ($name) { |
webmaster@1
|
516 case 'IMAGE': |
webmaster@1
|
517 case 'TEXTINPUT': |
webmaster@1
|
518 case 'ITEM': |
webmaster@1
|
519 case 'ENTRY': |
webmaster@1
|
520 case 'CONTENT': |
webmaster@1
|
521 case 'INFO': |
webmaster@1
|
522 $element = ''; |
webmaster@1
|
523 break; |
webmaster@1
|
524 case 'ID': |
webmaster@1
|
525 if ($element == 'ID') { |
webmaster@1
|
526 $element = ''; |
webmaster@1
|
527 } |
webmaster@1
|
528 } |
webmaster@1
|
529 } |
webmaster@1
|
530 |
webmaster@1
|
531 /** |
webmaster@1
|
532 * Call-back function used by the XML parser. |
webmaster@1
|
533 */ |
webmaster@1
|
534 function aggregator_element_data($parser, $data) { |
webmaster@1
|
535 global $channel, $element, $items, $item, $image, $tag; |
webmaster@1
|
536 $items += array($item => array()); |
webmaster@1
|
537 switch ($element) { |
webmaster@1
|
538 case 'ITEM': |
webmaster@1
|
539 $items[$item] += array($tag => ''); |
webmaster@1
|
540 $items[$item][$tag] .= $data; |
webmaster@1
|
541 break; |
webmaster@1
|
542 case 'IMAGE': |
webmaster@1
|
543 case 'LOGO': |
webmaster@1
|
544 $image += array($tag => ''); |
webmaster@1
|
545 $image[$tag] .= $data; |
webmaster@1
|
546 break; |
webmaster@1
|
547 case 'LINK': |
webmaster@1
|
548 if ($data) { |
webmaster@1
|
549 $items[$item] += array($tag => ''); |
webmaster@1
|
550 $items[$item][$tag] .= $data; |
webmaster@1
|
551 } |
webmaster@1
|
552 break; |
webmaster@1
|
553 case 'CONTENT': |
webmaster@1
|
554 $items[$item] += array('CONTENT' => ''); |
webmaster@1
|
555 $items[$item]['CONTENT'] .= $data; |
webmaster@1
|
556 break; |
webmaster@1
|
557 case 'SUMMARY': |
webmaster@1
|
558 $items[$item] += array('SUMMARY' => ''); |
webmaster@1
|
559 $items[$item]['SUMMARY'] .= $data; |
webmaster@1
|
560 break; |
webmaster@1
|
561 case 'TAGLINE': |
webmaster@1
|
562 case 'SUBTITLE': |
webmaster@1
|
563 $channel += array('DESCRIPTION' => ''); |
webmaster@1
|
564 $channel['DESCRIPTION'] .= $data; |
webmaster@1
|
565 break; |
webmaster@1
|
566 case 'INFO': |
webmaster@1
|
567 case 'ID': |
webmaster@1
|
568 case 'TEXTINPUT': |
webmaster@1
|
569 // The sub-element is not supported. However, we must recognize |
webmaster@1
|
570 // it or its contents will end up in the item array. |
webmaster@1
|
571 break; |
webmaster@1
|
572 default: |
webmaster@1
|
573 $channel += array($tag => ''); |
webmaster@1
|
574 $channel[$tag] .= $data; |
webmaster@1
|
575 } |
webmaster@1
|
576 } |
webmaster@1
|
577 |
webmaster@1
|
578 /** |
webmaster@1
|
579 * Checks a news feed for new items. |
webmaster@1
|
580 * |
webmaster@1
|
581 * @param $feed |
webmaster@1
|
582 * An associative array describing the feed to be refreshed. |
webmaster@1
|
583 */ |
webmaster@1
|
584 function aggregator_refresh($feed) { |
webmaster@1
|
585 global $channel, $image; |
webmaster@1
|
586 |
webmaster@1
|
587 // Generate conditional GET headers. |
webmaster@1
|
588 $headers = array(); |
webmaster@1
|
589 if ($feed['etag']) { |
webmaster@1
|
590 $headers['If-None-Match'] = $feed['etag']; |
webmaster@1
|
591 } |
webmaster@1
|
592 if ($feed['modified']) { |
webmaster@1
|
593 $headers['If-Modified-Since'] = gmdate('D, d M Y H:i:s', $feed['modified']) .' GMT'; |
webmaster@1
|
594 } |
webmaster@1
|
595 |
webmaster@1
|
596 // Request feed. |
webmaster@1
|
597 $result = drupal_http_request($feed['url'], $headers); |
webmaster@1
|
598 |
webmaster@1
|
599 // Process HTTP response code. |
webmaster@1
|
600 switch ($result->code) { |
webmaster@1
|
601 case 304: |
webmaster@1
|
602 db_query('UPDATE {aggregator_feed} SET checked = %d WHERE fid = %d', time(), $feed['fid']); |
webmaster@1
|
603 drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed['title']))); |
webmaster@1
|
604 break; |
webmaster@1
|
605 case 301: |
webmaster@1
|
606 $feed['url'] = $result->redirect_url; |
webmaster@1
|
607 watchdog('aggregator', 'Updated URL for feed %title to %url.', array('%title' => $feed['title'], '%url' => $feed['url'])); |
webmaster@1
|
608 // Deliberate no break. |
webmaster@1
|
609 case 200: |
webmaster@1
|
610 case 302: |
webmaster@1
|
611 case 307: |
webmaster@1
|
612 // Filter the input data: |
webmaster@1
|
613 if (aggregator_parse_feed($result->data, $feed)) { |
webmaster@1
|
614 $modified = empty($result->headers['Last-Modified']) ? 0 : strtotime($result->headers['Last-Modified']); |
webmaster@1
|
615 |
webmaster@1
|
616 // Prepare the channel data. |
webmaster@1
|
617 foreach ($channel as $key => $value) { |
webmaster@1
|
618 $channel[$key] = trim($value); |
webmaster@1
|
619 } |
webmaster@1
|
620 |
webmaster@1
|
621 // Prepare the image data (if any). |
webmaster@1
|
622 foreach ($image as $key => $value) { |
webmaster@1
|
623 $image[$key] = trim($value); |
webmaster@1
|
624 } |
webmaster@1
|
625 |
webmaster@1
|
626 if (!empty($image['LINK']) && !empty($image['URL']) && !empty($image['TITLE'])) { |
webmaster@1
|
627 // Note, we should really use theme_image() here but that only works with local images it won't work with images fetched with a URL unless PHP version > 5 |
webmaster@1
|
628 $image = '<a href="'. check_url($image['LINK']) .'" class="feed-image"><img src="'. check_url($image['URL']) .'" alt="'. check_plain($image['TITLE']) .'" /></a>'; |
webmaster@1
|
629 } |
webmaster@1
|
630 else { |
webmaster@1
|
631 $image = NULL; |
webmaster@1
|
632 } |
webmaster@1
|
633 |
webmaster@1
|
634 $etag = empty($result->headers['ETag']) ? '' : $result->headers['ETag']; |
webmaster@1
|
635 // Update the feed data. |
webmaster@1
|
636 db_query("UPDATE {aggregator_feed} SET url = '%s', checked = %d, link = '%s', description = '%s', image = '%s', etag = '%s', modified = %d WHERE fid = %d", $feed['url'], time(), $channel['LINK'], $channel['DESCRIPTION'], $image, $etag, $modified, $feed['fid']); |
webmaster@1
|
637 |
webmaster@1
|
638 // Clear the cache. |
webmaster@1
|
639 cache_clear_all(); |
webmaster@1
|
640 |
webmaster@1
|
641 watchdog('aggregator', 'There is new syndicated content from %site.', array('%site' => $feed['title'])); |
webmaster@1
|
642 drupal_set_message(t('There is new syndicated content from %site.', array('%site' => $feed['title']))); |
webmaster@1
|
643 break; |
webmaster@1
|
644 } |
webmaster@1
|
645 $result->error = t('feed not parseable'); |
webmaster@1
|
646 // Deliberate no break. |
webmaster@1
|
647 default: |
webmaster@1
|
648 watchdog('aggregator', 'The feed from %site seems to be broken, due to "%error".', array('%site' => $feed['title'], '%error' => $result->code .' '. $result->error), WATCHDOG_WARNING); |
webmaster@1
|
649 drupal_set_message(t('The feed from %site seems to be broken, because of error "%error".', array('%site' => $feed['title'], '%error' => $result->code .' '. $result->error))); |
webmaster@1
|
650 module_invoke('system', 'check_http_request'); |
webmaster@1
|
651 } |
webmaster@1
|
652 } |
webmaster@1
|
653 |
webmaster@1
|
654 /** |
webmaster@1
|
655 * Parse the W3C date/time format, a subset of ISO 8601. PHP date parsing |
webmaster@1
|
656 * functions do not handle this format. |
webmaster@1
|
657 * See http://www.w3.org/TR/NOTE-datetime for more information. |
webmaster@1
|
658 * Originally from MagpieRSS (http://magpierss.sourceforge.net/). |
webmaster@1
|
659 * |
webmaster@1
|
660 * @param $date_str |
webmaster@1
|
661 * A string with a potentially W3C DTF date. |
webmaster@1
|
662 * @return |
webmaster@1
|
663 * A timestamp if parsed successfully or FALSE if not. |
webmaster@1
|
664 */ |
webmaster@1
|
665 function aggregator_parse_w3cdtf($date_str) { |
webmaster@1
|
666 if (preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/', $date_str, $match)) { |
webmaster@1
|
667 list($year, $month, $day, $hours, $minutes, $seconds) = array($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]); |
webmaster@1
|
668 // calc epoch for current date assuming GMT |
webmaster@1
|
669 $epoch = gmmktime($hours, $minutes, $seconds, $month, $day, $year); |
webmaster@1
|
670 if ($match[10] != 'Z') { // Z is zulu time, aka GMT |
webmaster@1
|
671 list($tz_mod, $tz_hour, $tz_min) = array($match[8], $match[9], $match[10]); |
webmaster@1
|
672 // zero out the variables |
webmaster@1
|
673 if (!$tz_hour) { |
webmaster@1
|
674 $tz_hour = 0; |
webmaster@1
|
675 } |
webmaster@1
|
676 if (!$tz_min) { |
webmaster@1
|
677 $tz_min = 0; |
webmaster@1
|
678 } |
webmaster@1
|
679 $offset_secs = (($tz_hour * 60) + $tz_min) * 60; |
webmaster@1
|
680 // is timezone ahead of GMT? then subtract offset |
webmaster@1
|
681 if ($tz_mod == '+') { |
webmaster@1
|
682 $offset_secs *= -1; |
webmaster@1
|
683 } |
webmaster@1
|
684 $epoch += $offset_secs; |
webmaster@1
|
685 } |
webmaster@1
|
686 return $epoch; |
webmaster@1
|
687 } |
webmaster@1
|
688 else { |
webmaster@1
|
689 return FALSE; |
webmaster@1
|
690 } |
webmaster@1
|
691 } |
webmaster@1
|
692 |
webmaster@1
|
693 /** |
webmaster@1
|
694 * Parse a feed and store its items. |
webmaster@1
|
695 * |
webmaster@1
|
696 * @param $data |
webmaster@1
|
697 * The feed data. |
webmaster@1
|
698 * @param $feed |
webmaster@1
|
699 * An associative array describing the feed to be parsed. |
webmaster@1
|
700 * @return |
webmaster@1
|
701 * 0 on error, 1 otherwise. |
webmaster@1
|
702 */ |
webmaster@1
|
703 function aggregator_parse_feed(&$data, $feed) { |
webmaster@1
|
704 global $items, $image, $channel; |
webmaster@1
|
705 |
webmaster@1
|
706 // Unset the global variables before we use them: |
webmaster@1
|
707 unset($GLOBALS['element'], $GLOBALS['item'], $GLOBALS['tag']); |
webmaster@1
|
708 $items = array(); |
webmaster@1
|
709 $image = array(); |
webmaster@1
|
710 $channel = array(); |
webmaster@1
|
711 |
webmaster@1
|
712 // parse the data: |
webmaster@1
|
713 $xml_parser = drupal_xml_parser_create($data); |
webmaster@1
|
714 xml_set_element_handler($xml_parser, 'aggregator_element_start', 'aggregator_element_end'); |
webmaster@1
|
715 xml_set_character_data_handler($xml_parser, 'aggregator_element_data'); |
webmaster@1
|
716 |
webmaster@1
|
717 if (!xml_parse($xml_parser, $data, 1)) { |
webmaster@1
|
718 watchdog('aggregator', 'The feed from %site seems to be broken, due to an error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser)), WATCHDOG_WARNING); |
webmaster@1
|
719 drupal_set_message(t('The feed from %site seems to be broken, because of error "%error" on line %line.', array('%site' => $feed['title'], '%error' => xml_error_string(xml_get_error_code($xml_parser)), '%line' => xml_get_current_line_number($xml_parser))), 'error'); |
webmaster@1
|
720 return 0; |
webmaster@1
|
721 } |
webmaster@1
|
722 xml_parser_free($xml_parser); |
webmaster@1
|
723 |
webmaster@1
|
724 // We reverse the array such that we store the first item last, and the last |
webmaster@1
|
725 // item first. In the database, the newest item should be at the top. |
webmaster@1
|
726 $items = array_reverse($items); |
webmaster@1
|
727 |
webmaster@1
|
728 // Initialize variables. |
webmaster@1
|
729 $title = $link = $author = $description = $guid = NULL; |
webmaster@1
|
730 foreach ($items as $item) { |
webmaster@1
|
731 unset($title, $link, $author, $description, $guid); |
webmaster@1
|
732 |
webmaster@1
|
733 // Prepare the item: |
webmaster@1
|
734 foreach ($item as $key => $value) { |
webmaster@1
|
735 $item[$key] = trim($value); |
webmaster@1
|
736 } |
webmaster@1
|
737 |
webmaster@1
|
738 // Resolve the item's title. If no title is found, we use up to 40 |
webmaster@1
|
739 // characters of the description ending at a word boundary but not |
webmaster@1
|
740 // splitting potential entities. |
webmaster@1
|
741 if (!empty($item['TITLE'])) { |
webmaster@1
|
742 $title = $item['TITLE']; |
webmaster@1
|
743 } |
webmaster@1
|
744 elseif (!empty($item['DESCRIPTION'])) { |
webmaster@1
|
745 $title = preg_replace('/^(.*)[^\w;&].*?$/', "\\1", truncate_utf8($item['DESCRIPTION'], 40)); |
webmaster@1
|
746 } |
webmaster@1
|
747 else { |
webmaster@1
|
748 $title = ''; |
webmaster@1
|
749 } |
webmaster@1
|
750 |
webmaster@1
|
751 // Resolve the items link. |
webmaster@1
|
752 if (!empty($item['LINK'])) { |
webmaster@1
|
753 $link = $item['LINK']; |
webmaster@1
|
754 } |
webmaster@1
|
755 else { |
webmaster@1
|
756 $link = $feed['link']; |
webmaster@1
|
757 } |
webmaster@1
|
758 $guid = isset($item['GUID']) ? $item['GUID'] : ''; |
webmaster@1
|
759 |
webmaster@1
|
760 // Atom feeds have a CONTENT and/or SUMMARY tag instead of a DESCRIPTION tag. |
webmaster@1
|
761 if (!empty($item['CONTENT:ENCODED'])) { |
webmaster@1
|
762 $item['DESCRIPTION'] = $item['CONTENT:ENCODED']; |
webmaster@1
|
763 } |
webmaster@1
|
764 else if (!empty($item['SUMMARY'])) { |
webmaster@1
|
765 $item['DESCRIPTION'] = $item['SUMMARY']; |
webmaster@1
|
766 } |
webmaster@1
|
767 else if (!empty($item['CONTENT'])) { |
webmaster@1
|
768 $item['DESCRIPTION'] = $item['CONTENT']; |
webmaster@1
|
769 } |
webmaster@1
|
770 |
webmaster@1
|
771 // Try to resolve and parse the item's publication date. If no date is |
webmaster@1
|
772 // found, we use the current date instead. |
webmaster@1
|
773 $date = 'now'; |
webmaster@1
|
774 foreach (array('PUBDATE', 'DC:DATE', 'DCTERMS:ISSUED', 'DCTERMS:CREATED', 'DCTERMS:MODIFIED', 'ISSUED', 'CREATED', 'MODIFIED', 'PUBLISHED', 'UPDATED') as $key) { |
webmaster@1
|
775 if (!empty($item[$key])) { |
webmaster@1
|
776 $date = $item[$key]; |
webmaster@1
|
777 break; |
webmaster@1
|
778 } |
webmaster@1
|
779 } |
webmaster@1
|
780 |
webmaster@1
|
781 $timestamp = strtotime($date); // As of PHP 5.1.0, strtotime returns FALSE on failure instead of -1. |
webmaster@1
|
782 if ($timestamp <= 0) { |
webmaster@1
|
783 $timestamp = aggregator_parse_w3cdtf($date); // Returns FALSE on failure |
webmaster@1
|
784 if (!$timestamp) { |
webmaster@1
|
785 $timestamp = time(); // better than nothing |
webmaster@1
|
786 } |
webmaster@1
|
787 } |
webmaster@1
|
788 |
webmaster@1
|
789 // Save this item. Try to avoid duplicate entries as much as possible. If |
webmaster@1
|
790 // we find a duplicate entry, we resolve it and pass along its ID is such |
webmaster@1
|
791 // that we can update it if needed. |
webmaster@1
|
792 if (!empty($guid)) { |
webmaster@1
|
793 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND guid = '%s'", $feed['fid'], $guid)); |
webmaster@1
|
794 } |
webmaster@1
|
795 else if ($link && $link != $feed['link'] && $link != $feed['url']) { |
webmaster@1
|
796 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND link = '%s'", $feed['fid'], $link)); |
webmaster@1
|
797 } |
webmaster@1
|
798 else { |
webmaster@1
|
799 $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND title = '%s'", $feed['fid'], $title)); |
webmaster@1
|
800 } |
webmaster@1
|
801 $item += array('AUTHOR' => '', 'DESCRIPTION' => ''); |
webmaster@1
|
802 aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid: ''), 'fid' => $feed['fid'], 'timestamp' => $timestamp, 'title' => $title, 'link' => $link, 'author' => $item['AUTHOR'], 'description' => $item['DESCRIPTION'], 'guid' => $guid)); |
webmaster@1
|
803 } |
webmaster@1
|
804 |
webmaster@1
|
805 // Remove all items that are older than flush item timer. |
webmaster@1
|
806 $age = time() - variable_get('aggregator_clear', 9676800); |
webmaster@1
|
807 $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age); |
webmaster@1
|
808 |
webmaster@1
|
809 $items = array(); |
webmaster@1
|
810 $num_rows = FALSE; |
webmaster@1
|
811 while ($item = db_fetch_object($result)) { |
webmaster@1
|
812 $items[] = $item->iid; |
webmaster@1
|
813 $num_rows = TRUE; |
webmaster@1
|
814 } |
webmaster@1
|
815 if ($num_rows) { |
webmaster@1
|
816 db_query('DELETE FROM {aggregator_category_item} WHERE iid IN ('. implode(', ', $items) .')'); |
webmaster@1
|
817 db_query('DELETE FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age); |
webmaster@1
|
818 } |
webmaster@1
|
819 |
webmaster@1
|
820 return 1; |
webmaster@1
|
821 } |
webmaster@1
|
822 |
webmaster@1
|
823 /** |
webmaster@1
|
824 * Add/edit/delete an aggregator item. |
webmaster@1
|
825 * |
webmaster@1
|
826 * @param $edit |
webmaster@1
|
827 * An associative array describing the item to be added/edited/deleted. |
webmaster@1
|
828 */ |
webmaster@1
|
829 function aggregator_save_item($edit) { |
webmaster@1
|
830 if ($edit['iid'] && $edit['title']) { |
webmaster@1
|
831 db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s', guid = '%s', timestamp = %d WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['guid'], $edit['timestamp'], $edit['iid']); |
webmaster@1
|
832 } |
webmaster@1
|
833 else if ($edit['iid']) { |
webmaster@1
|
834 db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']); |
webmaster@1
|
835 db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']); |
webmaster@1
|
836 } |
webmaster@1
|
837 else if ($edit['title'] && $edit['link']) { |
webmaster@1
|
838 db_query("INSERT INTO {aggregator_item} (fid, title, link, author, description, timestamp, guid) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp'], $edit['guid']); |
webmaster@1
|
839 $edit['iid'] = db_last_insert_id('aggregator_item', 'iid'); |
webmaster@1
|
840 // file the items in the categories indicated by the feed |
webmaster@1
|
841 $categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']); |
webmaster@1
|
842 while ($category = db_fetch_object($categories)) { |
webmaster@1
|
843 db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $edit['iid']); |
webmaster@1
|
844 } |
webmaster@1
|
845 } |
webmaster@1
|
846 } |
webmaster@1
|
847 |
webmaster@1
|
848 /** |
webmaster@1
|
849 * Load an aggregator feed. |
webmaster@1
|
850 * |
webmaster@1
|
851 * @param $fid |
webmaster@1
|
852 * The feed id. |
webmaster@1
|
853 * @return |
webmaster@1
|
854 * An associative array describing the feed. |
webmaster@1
|
855 */ |
webmaster@1
|
856 function aggregator_feed_load($fid) { |
webmaster@1
|
857 static $feeds; |
webmaster@1
|
858 if (!isset($feeds[$fid])) { |
webmaster@1
|
859 $feeds[$fid] = db_fetch_array(db_query('SELECT * FROM {aggregator_feed} WHERE fid = %d', $fid)); |
webmaster@1
|
860 } |
webmaster@1
|
861 return $feeds[$fid]; |
webmaster@1
|
862 } |
webmaster@1
|
863 |
webmaster@1
|
864 /** |
webmaster@1
|
865 * Load an aggregator category. |
webmaster@1
|
866 * |
webmaster@1
|
867 * @param $cid |
webmaster@1
|
868 * The category id. |
webmaster@1
|
869 * @return |
webmaster@1
|
870 * An associative array describing the category. |
webmaster@1
|
871 */ |
webmaster@1
|
872 function aggregator_category_load($cid) { |
webmaster@1
|
873 static $categories; |
webmaster@1
|
874 if (!isset($categories[$cid])) { |
webmaster@1
|
875 $categories[$cid] = db_fetch_array(db_query('SELECT * FROM {aggregator_category} WHERE cid = %d', $cid)); |
webmaster@1
|
876 } |
webmaster@1
|
877 return $categories[$cid]; |
webmaster@1
|
878 } |
webmaster@1
|
879 |
webmaster@1
|
880 /** |
webmaster@1
|
881 * Format an individual feed item for display in the block. |
webmaster@1
|
882 * |
webmaster@1
|
883 * @param $item |
webmaster@1
|
884 * The item to be displayed. |
webmaster@1
|
885 * @param $feed |
webmaster@1
|
886 * Not used. |
webmaster@1
|
887 * @return |
webmaster@1
|
888 * The item HTML. |
webmaster@1
|
889 * @ingroup themeable |
webmaster@1
|
890 */ |
webmaster@1
|
891 function theme_aggregator_block_item($item, $feed = 0) { |
webmaster@1
|
892 global $user; |
webmaster@1
|
893 |
webmaster@1
|
894 $output = ''; |
webmaster@1
|
895 if ($user->uid && module_exists('blog') && user_access('create blog entries')) { |
webmaster@1
|
896 if ($image = theme('image', 'misc/blog.png', t('blog it'), t('blog it'))) { |
webmaster@1
|
897 $output .= '<div class="icon">'. l($image, 'node/add/blog', array('attributes' => array('title' => t('Comment on this news item in your personal blog.'), 'class' => 'blog-it'), 'query' => "iid=$item->iid", 'html' => TRUE)) .'</div>'; |
webmaster@1
|
898 } |
webmaster@1
|
899 } |
webmaster@1
|
900 |
webmaster@1
|
901 // Display the external link to the item. |
webmaster@1
|
902 $output .= '<a href="'. check_url($item->link) .'">'. check_plain($item->title) ."</a>\n"; |
webmaster@1
|
903 |
webmaster@1
|
904 return $output; |
webmaster@1
|
905 } |
webmaster@1
|
906 |
webmaster@1
|
907 /** |
webmaster@1
|
908 * Safely render HTML content, as allowed. |
webmaster@1
|
909 * |
webmaster@1
|
910 * @param $value |
webmaster@1
|
911 * The content to be filtered. |
webmaster@1
|
912 * @return |
webmaster@1
|
913 * The filtered content. |
webmaster@1
|
914 */ |
webmaster@1
|
915 function aggregator_filter_xss($value) { |
webmaster@1
|
916 return filter_xss($value, preg_split('/\s+|<|>/', variable_get('aggregator_allowed_html_tags', '<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>'), -1, PREG_SPLIT_NO_EMPTY)); |
webmaster@1
|
917 } |
webmaster@1
|
918 |
webmaster@1
|
919 /** |
webmaster@1
|
920 * Helper function for drupal_map_assoc. |
webmaster@1
|
921 * |
webmaster@1
|
922 * @param $count |
webmaster@1
|
923 * Items count. |
webmaster@1
|
924 * @return |
webmaster@1
|
925 * Plural-formatted "@count items" |
webmaster@1
|
926 */ |
webmaster@1
|
927 function _aggregator_items($count) { |
webmaster@1
|
928 return format_plural($count, '1 item', '@count items'); |
webmaster@1
|
929 } |