Simpletest Coverage - modules/aggregator/aggregator.module

1 <?php
2 // $Id: aggregator.module,v 1.416 2009/07/30 19:24:20 dries Exp $
3
4 /**
5 * @file
6 * Used to aggregate syndicated content (RSS, RDF, and Atom).
7 */
8
9 /**
10 * Denotes that a feed's items should never expire.
11 */
12 define('AGGREGATOR_CLEAR_NEVER', 0);
13
14 /**
15 * Implement hook_help().
16 */
17 function aggregator_help($path, $arg) {
18 switch ($path) {
19 case 'admin/help#aggregator':
20 $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>';
21 $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/settings/aggregator'), '@admin-block' => url('admin/structure/block'), '@aggregator-opml' => url('aggregator/opml'), '@cron' => url('admin/reports/status'))) . '</p>';
22 $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>';
23 return $output;
24 case 'admin/settings/aggregator':
25 $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>';
26 $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/settings/aggregator/add/feed'), '@block' => url('admin/structure/block'))) . '</p>';
27 return $output;
28 case 'admin/settings/aggregator/add/feed':
29 return '<p>' . t('Add a feed in RSS, RDF or Atom format. A feed may only have one entry.') . '</p>';
30 case 'admin/settings/aggregator/add/category':
31 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>';
32 case 'admin/settings/aggregator/add/opml':
33 return '<p>' . t('<acronym title="Outline Processor Markup Language">OPML</acronym> is an XML format used to exchange multiple feeds between aggregators. A single OPML document may contain a collection of many feeds. Drupal can parse such a file and import all feeds at once, saving you the effort of adding them manually. You may either upload a local file from your computer or enter a URL where Drupal can download it.') . '</p>';
34 }
35 }
36
37 /**
38 * Implement hook_theme().
39 */
40 function aggregator_theme() {
41 return array(
42 'aggregator_wrapper' => array(
43 'arguments' => array('content' => NULL),
44 'file' => 'aggregator.pages.inc',
45 'template' => 'aggregator-wrapper',
46 ),
47 'aggregator_categorize_items' => array(
48 'arguments' => array('form' => NULL),
49 'file' => 'aggregator.pages.inc',
50 ),
51 'aggregator_feed_source' => array(
52 'arguments' => array('feed' => NULL),
53 'file' => 'aggregator.pages.inc',
54 'template' => 'aggregator-feed-source',
55 ),
56 'aggregator_block_item' => array(
57 'arguments' => array('item' => NULL, 'feed' => 0),
58 ),
59 'aggregator_summary_items' => array(
60 'arguments' => array('summary_items' => NULL, 'source' => NULL),
61 'file' => 'aggregator.pages.inc',
62 'template' => 'aggregator-summary-items',
63 ),
64 'aggregator_summary_item' => array(
65 'arguments' => array('item' => NULL),
66 'file' => 'aggregator.pages.inc',
67 'template' => 'aggregator-summary-item',
68 ),
69 'aggregator_item' => array(
70 'arguments' => array('item' => NULL),
71 'file' => 'aggregator.pages.inc',
72 'template' => 'aggregator-item',
73 ),
74 'aggregator_page_opml' => array(
75 'arguments' => array('feeds' => NULL),
76 'file' => 'aggregator.pages.inc',
77 ),
78 'aggregator_page_rss' => array(
79 'arguments' => array('feeds' => NULL, 'category' => NULL),
80 'file' => 'aggregator.pages.inc',
81 ),
82 );
83 }
84
85 /**
86 * Implement hook_menu().
87 */
88 function aggregator_menu() {
89 $items['admin/settings/aggregator'] = array(
90 'title' => 'Feed aggregator',
91 'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.",
92 'page callback' => 'aggregator_admin_overview',
93 'access arguments' => array('administer news feeds'),
94 );
95 $items['admin/settings/aggregator/add/feed'] = array(
96 'title' => 'Add feed',
97 'page callback' => 'drupal_get_form',
98 'page arguments' => array('aggregator_form_feed'),
99 'access arguments' => array('administer news feeds'),
100 'type' => MENU_LOCAL_TASK,
101 'parent' => 'admin/settings/aggregator',
102 );
103 $items['admin/settings/aggregator/add/category'] = array(
104 'title' => 'Add category',
105 'page callback' => 'drupal_get_form',
106 'page arguments' => array('aggregator_form_category'),
107 'access arguments' => array('administer news feeds'),
108 'type' => MENU_LOCAL_TASK,
109 'parent' => 'admin/settings/aggregator',
110 );
111 $items['admin/settings/aggregator/add/opml'] = array(
112 'title' => 'Import OPML',
113 'page callback' => 'drupal_get_form',
114 'page arguments' => array('aggregator_form_opml'),
115 'access arguments' => array('administer news feeds'),
116 'type' => MENU_LOCAL_TASK,
117 'parent' => 'admin/settings/aggregator',
118 );
119 $items['admin/settings/aggregator/remove/%aggregator_feed'] = array(
120 'title' => 'Remove items',
121 'page callback' => 'drupal_get_form',
122 'page arguments' => array('aggregator_admin_remove_feed', 4),
123 'access arguments' => array('administer news feeds'),
124 'type' => MENU_CALLBACK,
125 );
126 $items['admin/settings/aggregator/update/%aggregator_feed'] = array(
127 'title' => 'Update items',
128 'page callback' => 'aggregator_admin_refresh_feed',
129 'page arguments' => array(4),
130 'access arguments' => array('administer news feeds'),
131 'type' => MENU_CALLBACK,
132 );
133 $items['admin/settings/aggregator/list'] = array(
134 'title' => 'List',
135 'type' => MENU_DEFAULT_LOCAL_TASK,
136 'weight' => -10,
137 );
138 $items['admin/settings/aggregator'] = array(
139 'title' => 'Aggregator',
140 'description' => 'Configure the behavior of the feed aggregator, including when to discard feed items and how to present feed items and categories.',
141 'page callback' => 'drupal_get_form',
142 'page arguments' => array('aggregator_admin_form'),
143 'access arguments' => array('administer news feeds'),
144 );
145 $items['aggregator'] = array(
146 'title' => 'Feed aggregator',
147 'page callback' => 'aggregator_page_last',
148 'access arguments' => array('access news feeds'),
149 'weight' => 5,
150 );
151 $items['aggregator/sources'] = array(
152 'title' => 'Sources',
153 'page callback' => 'aggregator_page_sources',
154 'access arguments' => array('access news feeds'),
155 );
156 $items['aggregator/categories'] = array(
157 'title' => 'Categories',
158 'page callback' => 'aggregator_page_categories',
159 'access callback' => '_aggregator_has_categories',
160 );
161 $items['aggregator/rss'] = array(
162 'title' => 'RSS feed',
163 'page callback' => 'aggregator_page_rss',
164 'access arguments' => array('access news feeds'),
165 'type' => MENU_CALLBACK,
166 );
167 $items['aggregator/opml'] = array(
168 'title' => 'OPML feed',
169 'page callback' => 'aggregator_page_opml',
170 'access arguments' => array('access news feeds'),
171 'type' => MENU_CALLBACK,
172 );
173 $items['aggregator/categories/%aggregator_category'] = array(
174 'title callback' => '_aggregator_category_title',
175 'title arguments' => array(2),
176 'page callback' => 'aggregator_page_category',
177 'page arguments' => array(2),
178 'access callback' => 'user_access',
179 'access arguments' => array('access news feeds'),
180 );
181 $items['aggregator/categories/%aggregator_category/view'] = array(
182 'title' => 'View',
183 'type' => MENU_DEFAULT_LOCAL_TASK,
184 'weight' => -10,
185 );
186 $items['aggregator/categories/%aggregator_category/categorize'] = array(
187 'title' => 'Categorize',
188 'page callback' => 'drupal_get_form',
189 'page arguments' => array('aggregator_page_category', 2),
190 'access arguments' => array('administer news feeds'),
191 'type' => MENU_LOCAL_TASK,
192 );
193 $items['aggregator/categories/%aggregator_category/configure'] = array(
194 'title' => 'Configure',
195 'page callback' => 'drupal_get_form',
196 'page arguments' => array('aggregator_form_category', 2),
197 'access arguments' => array('administer news feeds'),
198 'type' => MENU_LOCAL_TASK,
199 'weight' => 1,
200 );
201 $items['aggregator/sources/%aggregator_feed'] = array(
202 'page callback' => 'aggregator_page_source',
203 'page arguments' => array(2),
204 'access arguments' => array('access news feeds'),
205 'type' => MENU_CALLBACK,
206 );
207 $items['aggregator/sources/%aggregator_feed/view'] = array(
208 'title' => 'View',
209 'type' => MENU_DEFAULT_LOCAL_TASK,
210 'weight' => -10,
211 );
212 $items['aggregator/sources/%aggregator_feed/categorize'] = array(
213 'title' => 'Categorize',
214 'page callback' => 'drupal_get_form',
215 'page arguments' => array('aggregator_page_source', 2),
216 'access arguments' => array('administer news feeds'),
217 'type' => MENU_LOCAL_TASK,
218 );
219 $items['aggregator/sources/%aggregator_feed/configure'] = array(
220 'title' => 'Configure',
221 'page callback' => 'drupal_get_form',
222 'page arguments' => array('aggregator_form_feed', 2),
223 'access arguments' => array('administer news feeds'),
224 'type' => MENU_LOCAL_TASK,
225 'weight' => 1,
226 );
227 $items['admin/settings/aggregator/edit/feed/%aggregator_feed'] = array(
228 'title' => 'Edit feed',
229 'page callback' => 'drupal_get_form',
230 'page arguments' => array('aggregator_form_feed', 5),
231 'access arguments' => array('administer news feeds'),
232 'type' => MENU_CALLBACK,
233 );
234 $items['admin/settings/aggregator/edit/category/%aggregator_category'] = array(
235 'title' => 'Edit category',
236 'page callback' => 'drupal_get_form',
237 'page arguments' => array('aggregator_form_category', 5),
238 'access arguments' => array('administer news feeds'),
239 'type' => MENU_CALLBACK,
240 );
241
242 return $items;
243 }
244
245 /**
246 * Menu callback.
247 *
248 * @return
249 * An aggregator category title.
250 */
251 function _aggregator_category_title($category) {
252 return $category['title'];
253 }
254
255 /**
256 * Implement hook_init().
257 */
258 function aggregator_init() {
259 drupal_add_css(drupal_get_path('module', 'aggregator') . '/aggregator.css');
260 }
261
262 /**
263 * Find out whether there are any aggregator categories.
264 *
265 * @return
266 * TRUE if there is at least one category and the user has access to them, FALSE otherwise.
267 */
268 function _aggregator_has_categories() {
269 return user_access('access news feeds') && db_query('SELECT COUNT(*) FROM {aggregator_category}')->fetchField();
270 }
271
272 /**
273 * Implement hook_permission().
274 */
275 function aggregator_permission() {
276 return array(
277 'administer news feeds' => array(
278 'title' => t('Administer news feeds'),
279 'description' => t('Add, edit or delete news feeds that are aggregated to your site.'),
280 ),
281 'access news feeds' => array(
282 'title' => t('Access news feeds'),
283 'description' => t('View aggregated news feed items.'),
284 ),
285 );
286 }
287
288 /**
289 * Implement hook_cron().
290 *
291 * Checks news feeds for updates once their refresh interval has elapsed.
292 */
293 function aggregator_cron() {
294 $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh != :never', array(
295 ':time' => REQUEST_TIME,
296 ':never' => AGGREGATOR_CLEAR_NEVER
297 ));
298 foreach ($result as $feed) {
299 aggregator_refresh($feed);
300 }
301 }
302
303 /**
304 * Implement hook_block_list().
305 */
306 function aggregator_block_list() {
307 $block = array();
308 $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title');
309 foreach ($result as $category) {
310 $block['category-' . $category->cid]['info'] = t('!title category latest items', array('!title' => $category->title));
311 }
312 $result = db_query('SELECT fid, title FROM {aggregator_feed} WHERE block <> 0 ORDER BY fid');
313 foreach ($result as $feed) {
314 $block['feed-' . $feed->fid]['info'] = t('!title feed latest items', array('!title' => $feed->title));
315 }
316 return $block;
317 }
318
319 /**
320 * Implement hook_block_configure().
321 */
322 function aggregator_block_configure($delta = '') {
323 list($type, $id) = explode('-', $delta);
324 if ($type == 'category') {
325 $value = db_query('SELECT block FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $id))->fetchField();
326 $form['block'] = array(
327 '#type' => 'select',
328 '#title' => t('Number of news items in block'),
329 '#default_value' => $value,
330 '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20))
331 );
332 return $form;
333 }
334 }
335
336 /**
337 * Implement hook_block_save().
338 */
339 function aggregator_block_save($delta = '', $edit = array()) {
340 list($type, $id) = explode('-', $delta);
341 if ($type == 'category') {
342 db_update('aggregator_category')
343 ->fields(array('block' => $edit['block']))
344 ->condition('cid', $id)
345 ->execute();
346 }
347 }
348
349 /**
350 * Implement hook_block_view().
351 *
352 * Generates blocks for the latest news items in each category and feed.
353 */
354 function aggregator_block_view($delta = '') {
355 if (user_access('access news feeds')) {
356 $block = array();
357 list($type, $id) = explode('-', $delta);
358 switch ($type) {
359 case 'feed':
360 if ($feed = db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE block <> 0 AND fid = :fid', array(':fid' => $id))->fetchObject()) {
361 $block['subject'] = check_plain($feed->title);
362 $result = db_query_range("SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC", array(':fid' => $id), 0, $feed->block);
363 $read_more = theme('more_link', url('aggregator/sources/' . $feed->fid), t("View this feed's recent news."));
364 }
365 break;
366
367 case 'category':
368 if ($category = db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $id))->fetchObject()) {
369 $block['subject'] = check_plain($category->title);
370 $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = :cid ORDER BY i.timestamp DESC, i.iid DESC', array(':cid' => $category->cid), 0, $category->block);
371 $read_more = theme('more_link', url('aggregator/categories/' . $category->cid), t("View this category's recent news."));
372 }
373 break;
374 }
375 $items = array();
376 foreach ($result as $item) {
377 $items[] = theme('aggregator_block_item', $item);
378 }
379
380 // Only display the block if there are items to show.
381 if (count($items) > 0) {
382 $block['content'] = theme('item_list', $items) . $read_more;
383 }
384 return $block;
385 }
386 }
387
388 /**
389 * Add/edit/delete aggregator categories.
390 *
391 * @param $edit
392 * An associative array describing the category to be added/edited/deleted.
393 */
394 function aggregator_save_category($edit) {
395 $link_path = 'aggregator/categories/';
396 if (!empty($edit['cid'])) {
397 $link_path .= $edit['cid'];
398 if (!empty($edit['title'])) {
399 db_merge('aggregator_category')
400 ->key(array('cid' => $edit['cid']))
401 ->fields(array(
402 'title' => $edit['title'],
403 'description' => $edit['description'],
404 ))
405 ->execute();
406 $op = 'update';
407 }
408 else {
409 db_delete('aggregator_category')
410 ->condition('cid', $edit['cid'])
411 ->execute();
412 // Make sure there is no active block for this category.
413 db_delete('block')
414 ->condition('module', 'aggregator')
415 ->condition('delta', 'category-' . $edit['cid'])
416 ->execute();
417 $edit['title'] = '';
418 $op = 'delete';
419 }
420 }
421 elseif (!empty($edit['title'])) {
422 // A single unique id for bundles and feeds, to use in blocks.
423 $link_path .= db_insert('aggregator_category')
424 ->fields(array(
425 'title' => $edit['title'],
426 'description' => $edit['description'],
427 'block' => 5,
428 ))
429 ->execute();
430 $op = 'insert';
431 }
432 if (isset($op)) {
433 menu_link_maintain('aggregator', $op, $link_path, $edit['title']);
434 }
435 }
436
437 /**
438 * Add/edit/delete an aggregator feed.
439 *
440 * @param $edit
441 * An associative array describing the feed to be added/edited/deleted.
442 */
443 function aggregator_save_feed($edit) {
444 if (!empty($edit['fid'])) {
445 // An existing feed is being modified, delete the category listings.
446 db_delete('aggregator_category_feed')
447 ->condition('fid', $edit['fid'])
448 ->execute();
449 }
450 if (!empty($edit['fid']) && !empty($edit['title'])) {
451 db_update('aggregator_feed')
452 ->condition('fid', $edit['fid'])
453 ->fields(array(
454 'title' => $edit['title'],
455 'url' => $edit['url'],
456 'refresh' => $edit['refresh'],
457 'block' => $edit['block'],
458 ))
459 ->execute();
460 }
461 elseif (!empty($edit['fid'])) {
462 $iids = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $edit['fid']))->fetchCol();
463 if ($iids) {
464 db_delete('aggregator_category_item')
465 ->condition('iid', $iids, 'IN')
466 ->execute();
467 }
468 db_delete('aggregator_feed')->
469 condition('fid', $edit['fid'])
470 ->execute();
471 db_delete('aggregator_item')
472 ->condition('fid', $edit['fid'])
473 ->execute();
474 // Make sure there is no active block for this feed.
475 db_delete('block')
476 ->condition('module', 'aggregator')
477 ->condition('delta', 'feed-' . $edit['fid'])
478 ->execute();
479 }
480 elseif (!empty($edit['title'])) {
481 $edit['fid'] = db_insert('aggregator_feed')
482 ->fields(array(
483 'title' => $edit['title'],
484 'url' => $edit['url'],
485 'refresh' => $edit['refresh'],
486 'block' => $edit['block'],
487 'description' => '',
488 'image' => '',
489 ))
490 ->execute();
491
492 }
493 if (!empty($edit['title'])) {
494 // The feed is being saved, save the categories as well.
495 if (!empty($edit['category'])) {
496 foreach ($edit['category'] as $cid => $value) {
497 if ($value) {
498 db_merge('aggregator_category_feed')
499 ->key(array('fid' => $edit['fid']))
500 ->fields(array(
501 'cid' => $cid,
502 ))
503 ->execute();
504 }
505 }
506 }
507 }
508 }
509
510 /**
511 * Removes all items from a feed.
512 *
513 * @param $feed
514 * An object describing the feed to be cleared.
515 */
516 function aggregator_remove($feed) {
517 // Call hook_aggregator_remove() on all modules.
518 module_invoke_all('aggregator_remove', $feed);
519 // Reset feed.
520 db_merge('aggregator_feed')
521 ->key(array('fid' => $feed->fid))
522 ->fields(array(
523 'checked' => 0,
524 'hash' => '',
525 'etag' => '',
526 'modified' => 0,
527 'description' => $feed->description,
528 'image' => $feed->image,
529 ))
530 ->execute();
531 }
532
533 /**
534 * Checks a news feed for new items.
535 *
536 * @param $feed
537 * An object describing the feed to be refreshed.
538 */
539 function aggregator_refresh($feed) {
540 // Fetch the feed.
541 $fetcher = variable_get('aggregator_fetcher', 'aggregator');
542 module_invoke($fetcher, 'aggregator_fetch', $feed);
543
544 if ($feed->source_string !== FALSE) {
545 // Parse the feed.
546 $parser = variable_get('aggregator_parser', 'aggregator');
547 module_invoke($parser, 'aggregator_parse', $feed);
548
549 // If there are items on the feed, let all enabled processors do their work on it.
550 if (@count($feed->items)) {
551 $processors = variable_get('aggregator_processors', array('aggregator'));
552 foreach ($processors as $processor) {
553 module_invoke($processor, 'aggregator_process', $feed);
554 }
555 }
556 }
557 // Expire old feed items.
558 if (drupal_function_exists('aggregator_expire')) {
559 aggregator_expire($feed);
560 }
561 }
562
563 /**
564 * Load an aggregator feed.
565 *
566 * @param $fid
567 * The feed id.
568 * @return
569 * An object describing the feed.
570 */
571 function aggregator_feed_load($fid) {
572 $feeds = &drupal_static(__FUNCTION__);
573 if (!isset($feeds[$fid])) {
574 $feeds[$fid] = db_query('SELECT * FROM {aggregator_feed} WHERE fid = :fid', array(':fid' => $fid))->fetchObject();
575 }
576
577 return $feeds[$fid];
578 }
579
580 /**
581 * Load an aggregator category.
582 *
583 * @param $cid
584 * The category id.
585 * @return
586 * An associative array describing the category.
587 */
588 function aggregator_category_load($cid) {
589 $categories = &drupal_static(__FUNCTION__);
590 if (!isset($categories[$cid])) {
591 $categories[$cid] = db_query('SELECT * FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $cid))->fetchAssoc();
592 }
593
594 return $categories[$cid];
595 }
596
597 /**
598 * Format an individual feed item for display in the block.
599 *
600 * @param $item
601 * The item to be displayed.
602 * @param $feed
603 * Not used.
604 * @return
605 * The item HTML.
606 * @ingroup themeable
607 */
608 function theme_aggregator_block_item($item, $feed = 0) {
609
610 // Display the external link to the item.
611 return '<a href="' . check_url($item->link) . '">' . check_plain($item->title) . "</a>\n";
612
613 }
614
615 /**
616 * Safely render HTML content, as allowed.
617 *
618 * @param $value
619 * The content to be filtered.
620 * @return
621 * The filtered content.
622 */
623 function aggregator_filter_xss($value) {
624 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));
625 }
626
627 /**
628 * Check and sanitize aggregator configuration.
629 *
630 * Goes through all fetchers, parsers and processors and checks whether they are available.
631 * If one is missing resets to standard configuration.
632 *
633 * @return
634 * TRUE if this function reset the configuration FALSE if not.
635 */
636 function aggregator_sanitize_configuration() {
637 $reset = FALSE;
638 $fetcher = variable_get('aggregator_fetcher', 'aggregator');
639 if (!module_exists($fetcher)) {
640 $reset = TRUE;
641 }
642 $parser = variable_get('aggregator_parser', 'aggregator');
643 if (!module_exists($parser)) {
644 $reset = TRUE;
645 }
646 $processors = variable_get('aggregator_processors', array('aggregator'));
647 foreach ($processors as $processor) {
648 if (!module_exists($processor)) {
649 $reset = TRUE;
650 break;
651 }
652 }
653 if ($reset) {
654 variable_del('aggregator_fetcher');
655 variable_del('aggregator_parser');
656 variable_del('aggregator_processors');
657 return TRUE;
658 }
659 return FALSE;
660 }
661
662 /**
663 * Helper function for drupal_map_assoc.
664 *
665 * @param $count
666 * Items count.
667 * @return
668 * Plural-formatted "@count items"
669 */
670 function _aggregator_items($count) {
671 return format_plural($count, '1 item', '@count items');
672 }
673

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.