1<?php
2/*
3 * e107 website system
4 *
5 * Copyright (C) 2008-2009 e107 Inc (e107.org)
6 * Released under the terms and conditions of the
7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
8 *
9 * Plugin - newsfeeds
10 *
11 * $Source: /cvs_backup/e107_0.8/e107_plugins/newsfeed/newsfeed_functions.php,v $
12 * $Revision$
13 * $Date$
14 * $Author$
15 *
16*/
17
18/*
19If cache is disabled, first call to this object reads the complete database of active feeds, including the actual news feed. So all data is available for
20the rest of the page.
21
22If cache is enabled, only the feed list (excluding the news feed data) is loaded. Individual news feeds are stored in separate cache files, and loaded on demand. If the
23feed refresh time has expired, the cache is updated.
24*/
25
26if (!defined('e107_INIT')) { exit; }
27if (!e107::isInstalled('newsfeed'))
28{
29	return;
30}
31
32define('NEWSFEED_LIST_CACHE_TAG', 'newsfeeds'.e_LAN."_");
33define('NEWSFEED_NEWS_CACHE_TAG', 'newsfeeds_news_'.e_LAN."_");
34
35define('NEWSFEED_DEBUG', false);
36
37
38class newsfeedClass
39{
40	var $validFeedList;					// True once feeds read
41	var	$feedList = array();			// List of available feeds read from DB - everything from DB apart from the actual news
42	var $feedIcon = array();			// Pre-calculated link to each feed's icon
43	var $newsList = array();			// Actual news element for each feed
44	var $lastProcessed;					// Note time when processFeeds() last run
45	var $truncateCount;					// Number of characters to show in feeds in menus
46	var $truncateMore;					// '...more' string
47	var	$useCache;						// Set if cache is available
48
49	// Constructor
50	function __construct()
51	{
52		$this->validFeedList = FALSE;
53		$this->newsList = array();
54		$this->feedList = array();
55		$this->feedIcon = array();
56		$this->lastProcessed = 0;
57		$this->truncateCount = 150;			// Set a pref for these two later
58		$this->truncateMore = '...';
59		$this->useCache = true; // e107::getCache()->UserCacheActive;		// Have our own local copy - should be faster to access
60	}
61
62	// Ensures the feed list is loaded - uses cache if available
63	function readFeedList($force=FALSE)
64	{
65		$sql = e107::getDb();
66
67		if ($this->validFeedList && !$force)
68		{
69			return;		// Already got list
70		}
71		if($this->useCache) // Cache enabled - try to read from that first
72		{
73
74			if (!$force && $temp = e107::getCache()->retrieve(NEWSFEED_LIST_CACHE_TAG))
75			{
76				$this->feedList = e107::unserialize($temp);
77				return;
78			}
79		}
80
81		$fieldList = '*';
82
83		if ($this->useCache)
84		{	// Get all fields except the actual news
85			$fieldList = 'newsfeed_id, newsfeed_name, newsfeed_url, newsfeed_timestamp, newsfeed_description, newsfeed_image, newsfeed_active, newsfeed_updateint';
86		}
87
88		if ($sql->select("newsfeed", $fieldList, '`newsfeed_active` > 0'))		// Read in all the newsfeed info on the first go
89		{
90			while ($row = $sql->fetch())
91			{
92				$nfID = $row['newsfeed_id'];
93
94				if (!empty($row['newsfeed_data']))
95				{
96					$this->newsList[$nfID]['newsfeed_data'] = $row['newsfeed_data'];		// Pull out the actual news - might as well since we're here
97
98
99					unset($row['newsfeed_data']);			// Don't keep this in memory twice!
100				}
101
102				$this->newsList[$nfID]['newsfeed_timestamp'] = $row['newsfeed_timestamp'];
103
104				$this->feedList[$nfID] = $row;						// Put the rest into the feed data
105			}
106			$this->validFeedList = TRUE;
107		}
108
109		if ($this->useCache) // Cache enabled - we need to save some updated info
110		{
111			$temp = e107::serialize($this->feedList, FALSE);
112			e107::getCache()->set(NEWSFEED_LIST_CACHE_TAG,$temp);
113		}
114	}
115
116
117	// Returns the info for a single feed - from cache or memory as appropriate. If time expired, updates the feed.
118	function getFeed($feedID, $force = FALSE)
119	{
120		$tp = e107::getParser();
121		$sql = e107::getDb();
122
123		$this->readFeedList();				// Make sure we've got the feed data.
124
125		if (!isset($this->feedList[$feedID]))
126		{
127			if (NEWSFEED_DEBUG) echo "Invalid feed number: {$feedID}<br />";
128			return FALSE;
129		}
130
131		$maxAge =  ($this->feedList[$feedID]['newsfeed_updateint']/60);
132
133		if($maxAge < 1){ $maxAge = 1; }
134
135	//	e107::getDebug()->log("NewsFeed #".$feedID." MaxAge: ".$maxAge);
136
137		$cachedData  = e107::getCache()->retrieve(NEWSFEED_NEWS_CACHE_TAG.$feedID,$maxAge, true);
138
139		if(empty($this->newsList[$feedID]['newsfeed_timestamp']) || empty($cachedData) || strpos($this->newsList[$feedID]['newsfeed_data'],'MagpieRSS')) //BC Fix to update newsfeed_data from v1 to v2 spec.
140		{
141			$force = true;
142			// e107::getDebug()->log("NewsFeed Force");
143		}
144
145		if($cachedData !== false && $force === false)
146		{
147			e107::getDebug()->log("NewsFeed Cache Used");
148			$this->newsList[$feedID]['newsfeed_data'] = $cachedData;
149		}
150
151		if ($force === true) // Need to re-read from source - either no cached data yet, or cache expired
152		{
153				e107::getDebug()->log("NewsFeed Update: Item #".$feedID." ".NEWSFEED_NEWS_CACHE_TAG);
154
155				if (NEWSFEED_DEBUG)
156				{
157					 e107::getLog()->e_log_event(10,debug_backtrace(),"DEBUG","Newsfeed update","Refresh item: ".$feedID,FALSE,LOG_TO_ROLLING);
158				}
159
160				require_once(e_HANDLER.'xml_class.php');
161				$xml = new xmlClass;
162				require_once(e_HANDLER.'magpie_rss.php');
163
164				$dbData = array();		// In case we need to update DB
165
166				if($rawData = $xml->getRemoteFile($this->feedList[$feedID]['newsfeed_url'])) // Need to update feed
167				{
168					$rss = new MagpieRSS( $rawData );
169					list($newsfeed_image, $newsfeed_showmenu, $newsfeed_showmain) = explode("::", $this->feedList[$feedID]['newsfeed_image']);
170
171					$temp['channel'] = $rss->channel;
172
173					if (($newsfeed_showmenu == 0) || ($newsfeed_showmain == 0))
174					{
175						$temp['items'] = $rss->items;		// Unlimited items
176					}
177					else
178					{
179						$temp['items'] = array_slice($rss->items, 0, max($newsfeed_showmenu, $newsfeed_showmain));		// Limited items
180					}
181
182					$newsfeed_des = FALSE;
183
184					if($this->feedList[$feedID]['newsfeed_description'] == 'default')
185					{
186						$temp['newsfeed_description'] = 'default';		// This prevents db writes if no better data found
187
188						if($rss->channel['description'])
189						{
190							$newsfeed_des = $tp -> toDB($rss->channel['description']);
191							$temp['newsfeed_description'] = $newsfeed_des;
192						}
193						elseif($rss->channel['tagline'])
194						{
195							$newsfeed_des = $tp -> toDB($rss -> channel['tagline']);
196							$temp['newsfeed_description'] = $newsfeed_des;
197						}
198
199						if ($temp['newsfeed_description'] != $this->feedList[$feedID]['newsfeed_description'])
200						{	// Need to write updated feed name to DB
201							$this->feedList[$feedID]['newsfeed_description'] = $temp['newsfeed_description'];
202							$dbData['newsfeed_description'] = $temp['newsfeed_description'];
203							if ($this->useCache)
204							{
205								e107::getCache()->clear(NEWSFEED_LIST_CACHE_TAG);		// Clear the newsfeed cache so its re-read next time
206							}
207						}
208					}
209
210					if ($newsfeed_image == 'default')
211					{
212						$temp['newsfeed_image_link'] =  "<a href='".$rss->image['link']."' rel='external'><img src='".$rss->image['url']."' alt='".$rss->image['title']."' style='vertical-align: middle;' /></a>";
213					}
214					else
215					{
216						$temp['newsfeed_image_link'] = !empty($newsfeed_image) ? "<img src='".$newsfeed_image."' alt='' />" : '';
217					}
218
219					$serializedArray = e107::serialize($temp, false);
220
221					$now = time();
222					$this->newsList[$feedID]['newsfeed_data'] = $serializedArray;
223					$this->newsList[$feedID]['newsfeed_timestamp'] = $now;
224
225					if ($this->useCache)
226					{
227					//	e107::getDebug()->log("Saving Cache");
228						e107::getCache()->set(NEWSFEED_NEWS_CACHE_TAG.$feedID, $serializedArray, true);
229					}
230
231					$dbData['newsfeed_data'] = $serializedArray;
232					$dbData['newsfeed_timestamp'] = $now;
233
234
235					if (count($dbData)) // Only write the feed data to DB if not using cache. Write description if changed
236					{
237
238						$dbData['WHERE'] = "newsfeed_id=".$feedID;
239
240
241
242						if(FALSE === $sql->update('newsfeed', $dbData))
243						{
244							// e107::getDebug()->log("NewsFeed DB Update Failed");
245							if (NEWSFEED_DEBUG) echo NFLAN_48."<br /><br />".var_dump($dbData);
246						}
247					}
248					unset($rss);
249				}
250				else
251				{
252					if (NEWSFEED_DEBUG) echo $xml -> error;
253					return FALSE;
254				}
255		}
256
257		return  e107::unserialize($this->newsList[$feedID]['newsfeed_data']);
258	}
259
260
261
262
263	// Return text for the required news feeds (loads info as necessary)
264	// Uses different templates for main and menu areas
265	function newsfeedInfo($which, $where = 'main')
266	{
267
268		$tp = e107::getParser();
269
270		global $NEWSFEED_MAIN_START, $NEWSFEED_MAIN, $NEWSFEED_MAIN_END;
271		global $NEWSFEED_MENU_START, $NEWSFEED_MENU, $NEWSFEED_MENU_END;
272
273		if($which == 'all')
274		{
275			$filter = 0;
276		}
277		else
278		{
279			$filter = intval($which);
280		}
281
282		$text = "";
283		$this->readFeedList();			// Make sure we've got all the news feeds loaded
284
285		/* get template */
286
287		if(file_exists(THEME."templates/newsfeed/newsfeed_menu_template.php")) //v2.x
288		{
289			include(THEME."templates/newsfeed/newsfeed_menu_template.php");
290		}
291		elseif(file_exists(THEME."newsfeed_menu_template.php")) //v1.x
292		{
293			include(THEME."newsfeed_menu_template.php");
294		}
295		else
296		{
297			include(e_PLUGIN."newsfeed/templates/newsfeed_menu_template.php");
298		}
299
300		$vars = array();
301
302		foreach($this->feedList as $nfID => $feed)
303		{
304
305			$feed['newsfeed_sef'] = eHelper::title2sef($feed['newsfeed_name'], 'dashl');
306
307			if (($filter == 0) || ($filter == $feed['newsfeed_id']))
308			{
309				if (($rss = $this->getFeed($nfID)))	// Call ensures that feed is updated if necessary
310				{
311					list($newsfeed_image, $newsfeed_showmenu, $newsfeed_showmain) = explode("::", $feed['newsfeed_image']);
312
313					$numtoshow = intval($where == 'main' ? $newsfeed_showmain : $newsfeed_showmenu);
314					$numtoshow = ($numtoshow > 0 ? $numtoshow : 999);
315
316					// $url = e_PLUGIN_ABS."newsfeed/newsfeed.php?show.".$feed['newsfeed_id'];
317					$url = e107::url('newsfeed','source',$feed);
318
319					$vars['FEEDNAME'] = "<a href='".$url."'>".$tp->toHTML($feed['newsfeed_name'],false,'TITLE')."</a>";
320					$vars['FEEDDESCRIPTION'] = $feed['newsfeed_description'];
321					$vars['FEEDIMAGE'] = $rss['newsfeed_image_link'];
322					$vars['FEEDLANGUAGE'] = $rss['channel']['language'];
323
324					if($rss['channel']['lastbuilddate'])
325					{
326						$pubbed = $rss['channel']['lastbuilddate'];
327					}
328					else if($rss['channel']['dc']['date'])
329					{
330						$pubbed = $rss['channel']['dc']['date'];
331					}
332					else
333					{
334						$pubbed = NFLAN_34;
335					}
336
337					if(empty($rss['channel']['link']) || ($rss['channel']['link'] === '/'))
338					{
339					    $rss['channel']['link'] = $feed['newsfeed_url'];
340					}
341
342					$vars['FEEDLASTBUILDDATE']  = NFLAN_33.$pubbed;
343					$vars['FEEDCOPYRIGHT']      = $tp -> toHTML(vartrue($rss['channel']['copyright']), FALSE);
344					$vars['FEEDTITLE']          = "<a href='".$rss['channel']['link']."' rel='external'>".vartrue($rss['channel']['title'])."</a>";
345					$vars['FEEDLINK']           = $rss['channel']['link'] ;
346
347
348					if($feed['newsfeed_active'] == 2 or $feed['newsfeed_active'] == 3)
349					{
350						$vars['LINKTOMAIN'] = "<a href='".$url."'>".NFLAN_39."</a>";
351					}
352					else
353					{
354						$vars['LINKTOMAIN'] = "";
355					}
356
357					$data = "";
358
359					$numtoshow = min($numtoshow, count($rss['items']));
360					$i = 0;
361					while($i < $numtoshow)
362					{
363						$item = $rss['items'][$i];
364
365
366
367						$vars['FEEDITEMLINK']       = "<a href='".$item['link']."' rel='external'>".$tp -> toHTML($item['title'], FALSE)."</a>\n";
368						$vars['FEEDITEMLINK']       = str_replace('&', '&amp;', $vars['FEEDITEMLINK']);
369						$feeditemtext               = preg_replace("#\[[a-z0-9=]+\]|\[\/[a-z]+\]|\{[A-Z_]+\}#si", "", strip_tags($item['description']));
370						$vars['FEEDITEMCREATOR']    = $tp -> toHTML(vartrue($item['author']), FALSE);
371
372						if ($where == 'main')
373						{
374							if(!empty($NEWSFEED_COLLAPSE))
375							{
376								$vars['FEEDITEMLINK'] = "<a href='#' onclick='expandit(this)'>".$tp -> toHTML($item['title'], FALSE)."</a>
377								<div style='display:none' >
378								";
379
380								$vars['FEEDITEMTEXT'] = preg_replace("/&#091;.*]/", "", $tp -> toHTML($item['description'], FALSE))."
381								<br /><br /><a href='".$item['link']."' rel='external'>".LAN_CLICK_TO_VIEW."</a><br /><br />
382								</div>";
383							}
384							else
385							{
386								$vars['FEEDITEMLINK']   = "<a href='".$item['link']."' rel='external'>".$tp -> toHTML($item['title'], FALSE)."</a>\n";
387								$vars['FEEDITEMLINK']   = str_replace('&', '&amp;', $vars['FEEDITEMLINK']);
388								$feeditemtext           = preg_replace("#\[[a-z0-9=]+\]|\[\/[a-z]+\]|\{[A-Z_]+\}#si", "", $item['description']);
389								$vars['FEEDITEMTEXT']   = $tp -> toHTML($feeditemtext, FALSE)."\n";
390							}
391							$data .= $tp->simpleParse( $NEWSFEED_MAIN, $vars);
392						}
393						else
394						{
395							if ($this->truncateCount)
396							{
397								$vars['FEEDITEMTEXT'] = $tp->text_truncate($feeditemtext, $this->truncateCount, $this->truncateMore);
398							}
399							else
400							{
401								$vars['FEEDITEMTEXT'] = '';			// Might just want title
402							}
403							$data .= $tp->simpleParse($NEWSFEED_MENU, $vars);
404						}
405						$i++;
406					}
407				}
408			}
409
410			if ($where == 'main')
411			{
412				$vars['BACKLINK'] = "<a href='".e_SELF."'>".NFLAN_31."</a>";
413				$text = $tp->simpleParse($NEWSFEED_MAIN_START, $vars).$data.$tp->simpleParse( $NEWSFEED_MAIN_END, $vars);
414			}
415			else
416			{
417				$text .= $tp->simpleParse($NEWSFEED_MENU_START, $vars) . $data . $tp->simpleParse($NEWSFEED_MENU_END, $vars);
418			}
419
420			//TODO Move the $vars into their own shortcode class and change simpleParse to parseTemplate();
421		}
422
423		if($which == 'all')
424		{
425			$ret['title'] = (!empty($NEWSFEED_MENU_CAPTION)) ? $NEWSFEED_MENU_CAPTION : '';
426		}
427		else
428		{
429			$ret['title'] = $feed['newsfeed_name']." ".varset($NEWSFEED_MAIN_CAPTION);
430		}
431		$ret['text'] = $text;
432
433		return $ret;
434	}
435}
436
437
438
439