PageRenderTime 179ms CodeModel.GetById 43ms app.highlight 66ms RepoModel.GetById 56ms app.codeStats 0ms

/forum/gym_sitemaps/includes/gym_rss.php

https://github.com/GreyTeardrop/socionicasys-forum
PHP | 714 lines | 549 code | 5 blank | 160 comment | 128 complexity | 85f02cc21660749a1bfddf4fd8e01b78 MD5 | raw file
  1<?php
  2/**
  3*
  4* @package phpBB SEO GYM Sitemaps
  5* @version $Id: gym_rss.php 314 2011-06-27 08:21:34Z dcz $
  6* @copyright (c) 2006 - 2010 www.phpbb-seo.com
  7* @license http://opensource.org/osi3.0/licenses/lgpl-license.php GNU Lesser General Public License
  8*
  9*/
 10// First basic security
 11if ( !defined('IN_PHPBB') ) {
 12	exit;
 13}
 14require_once($phpbb_root_path . 'gym_sitemaps/includes/gym_sitemaps.' . $phpEx);
 15/**
 16* gym_rss Class
 17* www.phpBB-SEO.com
 18* @package phpBB SEO
 19*/
 20class gym_rss extends gym_sitemaps {
 21	var	$rss_config = array();
 22	/**
 23	* constuctor
 24	*/
 25	function gym_rss() {
 26		global $phpbb_seo, $phpEx, $config, $user;
 27		global $db, $auth;
 28		$this->gym_sitemaps('rss');
 29		// init output
 30		$this->output_data['showstats'] = (boolean) ($this->gym_config['gym_showstats'] || $this->gym_config['rss_showstats']);
 31		// Check the main vars
 32		$this->init_get_vars();
 33		// url without IDs like forum feed url in case the phpBB SEO mod are used and set so
 34		// and basic parameter for url such as blabla/news/digest/long/module-rss.xml => gymrss.php?module=blabla&news&digest&long
 35		if ( isset($_GET['nametoid']) && !empty($_GET['nametoid']) && isset($_GET['modulename']) && !empty($_GET['modulename']) &&  empty($this->actions['module_main']) && empty($this->actions['module_sub']) ) {
 36			$module_name = trim(strtolower($_GET['modulename']));
 37			// is the module available ?
 38			if (in_array($module_name, $this->actions['action_modules'])) {
 39				$this->actions['module_main'] = $module_name;
 40				// Do we get an id (?module=id)
 41				if ($id = @array_search(trim($_GET['nametoid']), $phpbb_seo->cache_config[$module_name]) ) {
 42					$this->actions['module_sub'] = intval($id);
 43				} else { // Pass the variable to the script ?module_name=$_GET['nametoid']
 44					$this->actions['module_sub'] = trim(utf8_htmlspecialchars(str_replace(array("\n", "\r"), '', $_GET['nametoid'])));
 45				}
 46			}
 47
 48		}
 49		if (empty($this->actions['action_modules'])) {
 50			$this->gym_error(404, '', __FILE__, __LINE__);
 51		}
 52		// Set last mod time from DB, will only be used as his for general feeds and channel lists
 53		// put it into phpbb config for the dynamic property.
 54		$config_name = $this->actions['action_type'] . '_' . (!empty($this->actions['module_main']) ? $this->actions['module_main'] . '_' : '') . 'last_mod_time';
 55		if (@$config[$config_name] < $config['board_startdate']) {
 56			set_config($config_name, $user->time_now, 1);
 57		}
 58		$this->output_data['last_mod_time'] = intval($config[$config_name]);
 59		// Init the output class
 60		$this->gym_init_output();
 61		// Setup the output
 62		$this->cache_config = array_merge(
 63			// Global
 64			$this->cache_config,
 65			// Other stuff required here
 66			array(
 67				'cache_enable' => (boolean) $this->set_module_option('cache_on', $this->override['cache']),
 68				'cache_auto_regen' => (boolean) $this->set_module_option('cache_auto_regen', $this->override['cache']),
 69				'cache_force_gzip' => (boolean) $this->set_module_option('cache_force_gzip', $this->override['cache']),
 70				'cache_born' => $this->output_data['last_mod_time'],
 71				'cache_max_age' => round($this->set_module_option('cache_max_age', $this->override['cache']),2) * 3600,
 72				'cache_file_ext' => ( $this->gym_output->gzip_config['gzip'] || $this->gym_config['rss_cache_force_gzip'] ) ? '.xml.gz' : '.xml',
 73			)
 74		);
 75		// Can you believe it, sprintf is faster than straight parsing.
 76		$this->style_config	= array(
 77			'rss_header' => '<'.'?xml version="1.0" encoding="utf-8"?'.'>%s' . "\n" . '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"' . "\n\t" . 'xmlns:content="http://purl.org/rss/1.0/modules/content/"' . "\n\t" . 'xmlns:atom="http://www.w3.org/2005/Atom">' . "\n" . '<!-- Generated by Google Yahoo MSN Sitemaps and RSS %s - &#169; 2006, ' . date('Y') . ' www.phpBB-SEO.com -->',
 78			'rss_footer' => "\n\t" . '</channel>' . "\n" . '</rss>',
 79			'rss_item_tpl' => "\n\t\t" . '<item>' . "\n\t\t\t" . '<title>%1$s</title>'. "\n\t\t\t" . '<link>%2$s</link>%3$s' . "\n\t\t\t" . '<description>%4$s</description>%8$s' . "\n\t\t\t" . '<source url="%5$s">%6$s</source>' . "\n\t\t\t" . '<guid isPermaLink="true">%7$s</guid>' . "\n\t\t" . '</item>',
 80			'rsschan_tpl' => "\n\t" . '<channel>' . "\n\t\t" . '<title>%1$s</title>' . "\n\t\t" . '<link>%2$s</link>' . "\n\t\t" . '<description>%3$s</description>%4$s' . "\n\t\t" . '%5$s' . "\n\t\t" . '<docs>http://blogs.law.harvard.edu/tech/rss</docs>' . "\n\t\t" . '<generator>Google Yahoo MSN Sitemaps and RSS ' . $this->gym_config['gym_version'] . ' - &#169; 2006, ' . date('Y') . ' www.phpBB-SEO.com</generator>%6$s' . "\n\t\t" . '<atom:link href="%7$s" rel="self" type="application/rss+xml" />%8$s',
 81			'rsschan_input_tpl' => "\n\t\t" . '<textInput>' . "\n\t\t\t" . '<title>%1$s</title>' . "\n\t\t\t" . '<description>%2$s</description>' . "\n\t\t\t" . '<link>%3$s</link>' . "\n\t\t\t" . '<name>%4$s</name>' . "\n\t\t" . '</textInput>' . "\n",
 82			'rsschan_img_tpl' => '<image>' . "\n\t\t\t" . '<title>%1$s</title>' . "\n\t\t\t" . '<url>%2$s</url>' . "\n\t\t\t" . '<link>%3$s</link>' . "\n\t\t" . '</image>',
 83			'chan_lastbuildate_tpl' => "\n\t\t" . '<lastBuildDate>%1$s</lastBuildDate>',
 84			'chan_ttl_tpl' => "\n\t\t" . '<ttl>%1$s</ttl>',
 85			'item_pubdate_tpl' => "\n\t\t\t" . '<pubDate>%1$s</pubDate>',
 86			'item_creator_tpl' => "\n\t\t\t" . '<dc:creator>%1$s</dc:creator>',
 87			'xslt_style' => '',
 88			'stats_genlist'	=> "\n" . '<!-- URL list generated in  %s s %s - %s sql - %s URLs listed -->',
 89			'stats_start' => "\n" . '<!--  Output started from cache after %s s - %s sql -->',
 90			'stats_nocache'	=> "\n" . '<!--  Output ended after %s s %s -->',
 91			'stats_end' => "\n" . '<!--  Output from cache ended up after %s s - %s sql -->',
 92		);
 93		$rss_limit_time = (int) $this->set_module_option('limit_time', $this->override['limit']);
 94		$rss_lang = trim($this->set_module_option('lang', $this->gym_config['rss_override']));
 95		$this->rss_config = array( 'rss_c_info' => ( !empty($this->gym_config['rss_c_info'])) ? "\n\t\t" . '<copyright>' . $this->xml_encode($this->gym_config['rss_c_info']) . '</copyright>' : '',
 96			'rss_xslt' => ( $this->gym_config['rss_xslt'] ) ? true : false,
 97			'rss_force_xslt' => ( $this->gym_config['rss_xslt'] && $this->gym_config['rss_force_xslt'] ) ? true : false,
 98			'rss_lang' => ( !empty($rss_lang) ) ? "\n\t\t" . '<language>' . $this->xml_encode($rss_lang) . '</language>' : '',
 99			'rss_url' => $phpbb_seo->sslify($this->gym_config['rss_url'], $phpbb_seo->ssl['use'], false),
100			'rss_yahoo_appid' => ( !empty($this->gym_config['rss_yahoo_appid']) ) ? trim($this->gym_config['rss_yahoo_appid']) : '',
101			// module specific settings we should often need in module
102			// Some are used here to filter the allowed actions, will go to main default if unset in the module
103			'rss_url_limit' => (int) $this->set_module_option('url_limit', $this->override['limit']),
104			'rss_sql_limit' => (int) $this->set_module_option('sql_limit', $this->override['limit']),
105			'rss_limit_time' => ( $rss_limit_time >= 0 ) ? $rss_limit_time*3600*24 : 0,
106			'rss_modrewrite' => (int) $this->set_module_option('modrewrite', $this->override['modrewrite']),
107			'rss_modrtype' => (int) $this->set_module_option('modrtype', $this->override['modrewrite']),
108			'rss_sitename' => $this->set_module_option('sitename'),
109			'rss_site_desc' => $this->set_module_option('site_desc'),
110			'rss_logo_url' => $this->path_config['gym_img_url'] . trim($this->set_module_option('logo_url'), '/'),
111			'rss_image_url' => $this->path_config['gym_img_url'] . trim($this->set_module_option('image_url'), '/'),
112			'rss_sort' => $this->set_module_option('sort', $this->override['sort']),
113			'rss_allow_auth' => (boolean) $this->set_module_option('allow_auth', $this->gym_config['rss_override']),
114			'rss_cache_auth' => (boolean) $this->set_module_option('cache_auth', $this->gym_config['rss_override']),
115			'rss_allow_content' => (boolean) $this->set_module_option('allow_content', $this->gym_config['rss_override']),
116			'rss_allow_news' => (boolean) $this->set_module_option('allow_news', $this->gym_config['rss_override']),
117			'rss_news_update' => round($this->set_module_option('news_update', $this->gym_config['rss_override']), 2) * 3600,
118			'rss_allow_profile' => (boolean) $this->set_module_option('allow_profile', $this->gym_config['rss_override']),
119			'rss_allow_profile_links' => (boolean) $this->set_module_option('allow_profile_links', $this->gym_config['rss_override']),
120			'rss_sumarize' => (int) $this->set_module_option('sumarize', $this->gym_config['rss_override']),
121			'rss_sumarize_method' => trim($this->set_module_option('sumarize_method', $this->gym_config['rss_override'])),
122			'rss_allow_short' => (boolean) $this->set_module_option('allow_short', $this->gym_config['rss_override']),
123			'rss_allow_long' => (boolean) $this->set_module_option('allow_long', $this->gym_config['rss_override']),
124			'rss_allow_bbcode' => (boolean) $this->set_module_option('allow_bbcode', $this->gym_config['rss_override']),
125			'rss_strip_bbcode' => trim($this->set_module_option('strip_bbcode', $this->gym_config['rss_override'])),
126			'rss_allow_links' => (boolean) $this->set_module_option('allow_links', $this->gym_config['rss_override']),
127			'rss_allow_emails' => (boolean) $this->set_module_option('allow_emails', $this->gym_config['rss_override']),
128			'rss_allow_smilies' => (boolean) $this->set_module_option('allow_smilies', $this->gym_config['rss_override']),
129			'rss_yahoo_notify' => (boolean) $this->set_module_option('yahoo_notify', $this->gym_config['rss_override']),
130			'rss_nohtml' => (boolean) $this->set_module_option('nohtml', $this->gym_config['rss_override']),
131			//@TODO add acp option for this ?
132			'rss_display_author' => /*(boolean) $this->set_module_option('display_author', $this->gym_config['rss_override'])*/ true,
133			'rss_yahoo_notify_url' => '',
134			'rss_msg_filters' => array(),
135			'rss_auth_msg' => '',
136			'rss_do_explain' => false,
137		);
138		$this->rss_config['rss_auth_guest'] = ($this->rss_config['rss_allow_auth'] && $user->data['is_registered']) ? false : true;
139		$this->cache_config['do_cache'] = $this->rss_config['rss_auth_guest'] ? true :  $this->rss_config['rss_cache_auth'];
140		// remind for later
141		$this->rss_config['rss_profile_mode'] = $this->rss_config['rss_allow_profile_links'] ? 'full' : 'no_profile';
142		// Check the rss specific vars and do basic set_up for msg output
143		$this->init_rss_vars();
144
145		if (!$this->rss_config['rss_auth_guest']) {
146			$this->rss_config['rss_auth_msg'] =  "\n" . ( ($this->actions['rss_channel_list'] || empty($this->actions['module_sub']) || $this->actions['module_sub'] == 'channels') ? sprintf($user->lang['RSS_AUTH_SOME_USER'], $user->data['username'] ) : sprintf($user->lang['RSS_AUTH_THIS_USER'], $user->data['username'] ) ) . "\n";
147		}
148		// Are we going to explain ?
149		if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report')) {
150			$this->rss_config['rss_do_explain'] = true;
151			$this->cache_config['do_cache'] = false;
152		}
153		$this->rss_output();
154		if ($this->rss_config['rss_do_explain']) {
155			$db->sql_report('display');
156		} else {
157			$this->gym_output->do_output();
158		}
159		return;
160	}
161	/**
162	* init_rss_vars()
163	* Set up the specific rss modules GET vars.
164	* @access private
165	*/
166	function init_rss_vars() {
167		global $user, $phpEx, $phpbb_seo;
168		// Let's now check out if it's a GYM 1.x URL
169		if ($this->gym_config['rss_1xredir'] && !empty($_GET['gym1x'])) {
170			$this->actions['gym1x_newurl'] = '/' . (isset($_GET['m']) ? 'digest/' : '' ) . (isset($_GET['l']) ? 'long/' : (isset($_GET['s']) ? 'short/' : '' ) );
171			$this->actions['gym1x_newurl'] = empty($this->actions['module_main']) ? 'rss' . $this->actions['gym1x_newurl'] . 'rss.xml' : (empty($_GET['gymtitle']) ? 'rss' .  $this->actions['gym1x_newurl'] . (!empty($this->actions['module_sub']) ? $this->actions['module_sub'] . '/' : '' ) . $this->actions['module_main'] . '.xml' : $phpbb_seo->set_url($_GET['gymtitle'], (int) $this->actions['module_sub'], 'forum') . $this->actions['gym1x_newurl'] . $this->actions['module_main'] . '.xml');
172			// nothing else needed for this
173			return;
174
175		}
176		$this->actions['rss_content'] = $this->actions['rss_short_list'] = $this->actions['rss_long_list'] = $this->actions['rss_channel_list'] = $this->actions['rss_news_list'] = false;
177		$this->rss_config['extra_title'] = $this->url_config['extra_params_full'] = $this->url_config['extra_params'] = '';
178		$this->url_config['rss_announces_path'] = $phpbb_seo->seo_static['global_announce'] . '/';
179		// Channel list
180		if ( ( $module_sub_chan = ($this->actions['module_sub'] === 'channels' ? true : false) ) || (isset($_GET['channels']) && empty($this->actions['module_main']) ) ) {
181			$this->actions['rss_channel_list'] = true;
182			$this->rss_config['extra_title'] = ' - ' . $user->lang['RSS_CHAN_LIST_TITLE'];
183			if ($this->rss_config['rss_modrewrite'] || !$module_sub_chan) {
184				$this->url_config['extra_params_full'] .= 'channels/';
185			}
186		}
187		// News = first message only
188		if ( isset($_GET['news']) && $this->rss_config['rss_allow_news']) {
189			$this->actions['rss_news_list'] = true;
190			$this->rss_config['extra_title'] .= ' - ' . $user->lang['RSS_NEWS'];
191			$this->url_config['extra_params_full'] .= 'news/';
192			$this->url_config['extra_params'] .= 'news/';
193			if (!empty($this->rss_config['rss_news_update'])) {
194				$this->cache_config['cache_max_age'] = $this->rss_config['rss_news_update'];
195			}
196			unset($_GET['channels']); // no channel listing
197		}
198		// Do we output text ?
199		if ( isset($_GET['digest']) && $this->rss_config['rss_allow_content'] ) {
200			$this->actions['rss_content'] = true;
201			$this->rss_config['extra_title'] .= ' - ' . $user->lang['RSS_CONTENT'];
202			$this->url_config['extra_params_full'] .= 'digest/';
203			$this->url_config['extra_params'] .= 'digest/';
204			$this->rss_config['rss_url_limit'] = intval($this->set_module_option('url_limit_msg', $this->gym_config['rss_override']));
205			$this->rss_config['rss_sql_limit'] = intval($this->set_module_option('sql_limit_msg', $this->gym_config['rss_override']));
206		}
207		// Custom limits short
208		if ( isset($_GET['short']) && $this->rss_config['rss_allow_short'] ) {
209			$this->actions['rss_short_list'] = true;
210			$this->rss_config['extra_title'] .= ' - ' . $user->lang['RSS_SHORT'];
211			$this->url_config['extra_params_full'] .= 'short/';
212			$this->url_config['extra_params'] .= 'short/';
213			$this->rss_config['rss_url_limit'] = $this->actions['rss_content'] ? intval($this->rss_config['rss_url_limit']/3) : intval($this->set_module_option('url_limit_short', $this->gym_config['rss_override']));
214			$this->rss_config['rss_sql_limit'] = $this->actions['rss_content'] ? intval($this->rss_config['rss_url_limit']/2) : intval($this->set_module_option('sql_limit_short', $this->gym_config['rss_override']));
215		}
216		// Custom limits long
217		if ( isset($_GET['long']) && !$this->actions['rss_short_list'] && $this->rss_config['rss_allow_long'] ) {
218			$this->actions['rss_long_list'] = true;
219			$this->rss_config['extra_title'] .= ' - ' . $user->lang['RSS_LONG'];
220			$this->url_config['extra_params_full'] .= 'long/';
221			$this->url_config['extra_params'] .= 'long/';
222			$this->rss_config['rss_url_limit'] = $this->actions['rss_content'] ? intval($this->rss_config['rss_url_limit']*3) : intval($this->set_module_option('url_limit_long', $this->gym_config['rss_override']));
223			$this->rss_config['rss_sql_limit'] = $this->actions['rss_content'] ? intval($this->rss_config['rss_url_limit']*2) : intval($this->set_module_option('sql_limit_long', $this->gym_config['rss_override']));
224		}
225		// Adjust variable a bit
226		if ($this->actions['rss_content'] ) { // requested and auth
227			$this->rss_config['rss_msg_filters'] = $this->set_msg_strip($this->rss_config['rss_strip_bbcode']);
228		}
229		$this->url_config['extra_params_delimE'] = $this->url_config['extra_paramsE'] = '';
230		$this->url_config['extra_params_delimQ'] = $this->url_config['extra_paramsQ'] = '';
231		$this->url_config['rss_vpath'] = '';
232		if ($this->rss_config['rss_modrewrite']) {
233			$this->actions['extra_params'] = $this->url_config['extra_params'];
234			$this->actions['extra_params_full'] = $this->url_config['extra_params_full'];
235			$this->url_config['extra_params_delimE'] = '/';
236			$this->url_config['extra_params_delimQ'] = '?';
237			$this->url_config['rss_vpath'] = 'rss/'; // virtual rss path for forum RSS feed URLs etc ...
238			$this->url_config['rss_default'] = 'rss.xml' . $this->url_config['gzip_ext_out'] ;
239			if (!empty($this->url_config['extra_params'])) {
240				$this->url_config['extra_paramsE'] = $this->url_config['extra_params'];
241				$this->url_config['extra_paramsQ'] = $this->url_config['extra_params_delimQ'] . $this->url_config['extra_params'];
242			}
243		} else {
244			$this->url_config['extra_params'] = str_replace('/', '&amp;', trim($this->url_config['extra_params'], '/'));
245			$this->actions['extra_params_full'] = str_replace('/', '&amp;', trim($this->url_config['extra_params_full'], '/'));
246			$this->url_config['extra_params_delimE'] = '&amp;';
247			$this->url_config['extra_params_delimQ'] = '?';
248			if (!empty($this->url_config['extra_params'])) {
249				$this->url_config['extra_paramsE'] = $this->url_config['extra_params_delimE'] . $this->url_config['extra_params'];
250				$this->url_config['extra_paramsQ'] = $this->url_config['extra_params_delimQ'] . $this->url_config['extra_params'];
251			}
252		}
253	}
254	/**
255	* forum_rss_url() builds rss forum url with proper options
256	* Suffixe is not added here, to properly deal with pagination
257	*/
258	function forum_rss_url($forum_name, $forum_id) {
259		global $phpbb_seo;
260		return !empty($phpbb_seo->cache_config['forum'][$forum_id]) ? $phpbb_seo->cache_config['forum'][$forum_id] : $phpbb_seo->format_url( $forum_name, 'forum' ) . $this->url_config['rss_forum_delim'] . $forum_id;
261	}
262	/**
263	* rss_output() will build all rss output
264	* @access private
265	*/
266	function rss_output() {
267		global $phpEx, $db, $config, $phpbb_root_path, $user, $phpbb_seo;
268		// Initialize SQL cycling : do not query for more than required
269		$this->rss_config['rss_sql_limit'] = ($this->rss_config['rss_sql_limit'] > $this->rss_config['rss_url_limit']) ? $this->rss_config['rss_url_limit'] : $this->rss_config['rss_sql_limit'];
270		// XSLT styling
271		if ($this->rss_config['rss_xslt']) {
272			// here we could go further and allow user style to be used, would need to parse the cache a bit,
273			// but, unlike Google sitemaps, RSS feeds are decently small for that.
274			$this->style_config['xslt_style'] = "\n" . '<'.'?xml-stylesheet type="text/xsl" href="' . $phpbb_seo->seo_path['phpbb_url'] . 'gym_sitemaps/gym_style.' . $phpEx . '?action-rss,type-xsl,lang-' . $config['default_lang'] . ',theme_id-' . $config['default_style'] . '" media="screen, projection" ?'.'>';
275			$blanc_fix = '';
276			if ($this->rss_config['rss_force_xslt']) {
277				// FF 2 and IE7 only look for the first 500 chars to decide if it's rss or not
278				// and impose their private styling
279				for ($i=0; $i<550; $i++) {
280					$blanc_fix .= ' ';
281				}
282				$blanc_fix = "\n" . '<!-- Some spaces ' . $blanc_fix . ' to force xlst -->';
283			}
284			$this->style_config['xslt_style'] .= $blanc_fix;
285		}
286		// Remove guid for channels
287		if ($this->actions['rss_channel_list']) {
288			$this->style_config['rss_item_tpl'] = str_replace("\n\t\t\t" . '<guid isPermaLink="true">%s</guid>', '', $this->style_config['rss_item_tpl']);
289		}
290		// custom url transition message
291		if (!empty($this->actions['gym1x_newurl'])) {
292			$chan_title = $user->lang['RSS_1XREDIR'] . ' - ' . $this->gym_config['rss_sitename'];
293			$chan_desc = $user->lang['RSS_1XREDIR_MSG'] . ' : ' . $this->parse_link($this->actions['gym1x_newurl']) . "\n" . $this->gym_config['rss_site_desc'];
294			$rss_new_url = $this->rss_config['rss_url'] . $this->actions['gym1x_newurl'];
295			$this->output_data['data'] = sprintf($this->style_config['rss_header'], $this->style_config['xslt_style'], $this->gym_config['gym_version'] );
296			$this->parse_channel($chan_title, $chan_desc, $rss_new_url, $this->output_data['last_mod_time'], $this->rss_config['rss_image_url'], $rss_new_url);
297			$this->parse_item($chan_title, $chan_desc, $rss_new_url, $rss_new_url, '', $this->output_data['last_mod_time']);
298			$this->output_data['data'] .= $this->style_config['rss_footer'];
299			return;
300		}
301		// module action
302		if (in_array($this->actions['module_main'], $this->actions['action_modules'])) { // List item from the module
303			$module_class = $this->actions['action_type'] . '_' . $this->actions['module_main'];
304			$this->load_module($module_class, 'rss_module');
305			if ( empty($this->output_data['url_sofar']) ) {
306				$this->gym_error(404, 'GYM_TOO_FEW_ITEMS', __FILE__, __LINE__);
307			}
308			$this->output_data['data'] = sprintf($this->style_config['rss_header'], $this->style_config['xslt_style'], $this->gym_config['gym_version'] ) . $this->output_data['data'] . $this->style_config['rss_footer'];
309		} else { // Add items from installed modules
310			$site_title = $this->gym_config['rss_sitename'];
311			$site_desc = $this->gym_config['rss_site_desc'] . "\n";
312			if ($this->actions['rss_channel_list']) {
313				$chan_source = $this->rss_config['rss_url'] . $this->url_config['rss_vpath'] . (($this->rss_config['rss_modrewrite']) ? (!empty($this->url_config['extra_params']) ? $this->url_config['extra_params'] : '') : $this->url_config['rss_default'] . $this->url_config['extra_params_delimQ'] . $this->actions['extra_params_full']);
314				$site_title_full = $site_title . $this->rss_config['extra_title'];
315				$site_desc .= $user->lang['RSS_CHAN_LIST_DESC'] . "\n";
316			} else {
317				$chan_source = $this->rss_config['rss_url'] . $this->url_config['rss_vpath'] . (($this->rss_config['rss_modrewrite']) ? (!empty($this->url_config['extra_params']) ? $this->url_config['extra_params'] : '') . $this->url_config['rss_default'] : $this->url_config['rss_default'] . $this->url_config['extra_paramsQ']);
318				$site_title_full = $site_title . $this->rss_config['extra_title'];
319			}
320			$this->seo_kill_dupes($chan_source);
321			$this->parse_channel($site_title_full, $site_desc, $this->rss_config['rss_url'], $this->output_data['last_mod_time'], $this->rss_config['rss_image_url'], $chan_source);
322			// Since we are going to cycle through modules, we need to ajust URL limit and counting a bit
323			// URL limit, we take the last xx items from each feed
324			// where xx is the URL limit divided by the number of feeds
325			$this->rss_config['rss_url_limit'] = !empty($this->actions['action_modules']) ? intval($this->rss_config['rss_url_limit'] / count($this->actions['action_modules'])) : 0;
326			if ( empty($this->rss_config['rss_url_limit']) ) {
327				$this->gym_error(404, 'GYM_TOO_FEW_ITEMS', __FILE__, __LINE__);
328			}
329			// start the modules
330			// We are working on all available modules
331			$this->load_modules('rss_main');
332			$this->output_data['url_sofar'] = $this->output_data['url_sofar_total'];
333			if ( empty($this->output_data['url_sofar']) ) {
334				$this->gym_error(404, 'GYM_TOO_FEW_ITEMS', __FILE__, __LINE__);
335			}
336			$this->output_data['data'] = sprintf($this->style_config['rss_header'], $this->style_config['xslt_style'], $this->gym_config['gym_version'] ) . $this->output_data['data'] . $this->style_config['rss_footer'];
337		}
338		if ( $this->rss_config['rss_yahoo_notify'] && ($this->output_data['time'] >= ($this->cache_config['cache_born'] + $this->cache_config['cache_max_age'])) ) {
339			$this->rss_yahoo_notify();
340		}
341		return;
342	}
343	/**
344	* parse_channel() adds the channel info to the output
345	*/
346	function parse_channel($chan_title, $chan_desc, $chan_link, $lastBuildDate = 0, $chan_image = '', $chan_source = '') {
347		global $config, $user;
348		// Misc SQL Explain
349		global $auth;
350		if ( !empty($chan_source) && $auth->acl_get('a_') && defined('DEBUG_EXTRA')) {
351			if (!empty($_REQUEST['explain'])) {
352				return;
353			}
354			if (empty($user->lang['GYM_SQLEXPLAIN_MSG'])) {
355				$user->add_lang('gym_sitemaps/gym_common');
356			}
357			$report_url =  $chan_source . (strpos($chan_source, '?') !== false ? '&amp;' : '?') . 'explain=1';
358			$this->actions['sql_report_msg'] = "\n<i style=\"color:#CC0000\">" . sprintf($user->lang['GYM_SQLEXPLAIN_MSG'], $this->parse_link($report_url , $user->lang['GYM_SQLEXPLAIN'])) . '</i>';
359		}
360		$lastBuildDate = intval($lastBuildDate);
361		if ( $lastBuildDate > $config['board_startdate']) {
362			$this->output_data['last_mod_time'] = $lastBuildDate;
363			if (( $this->cache_config['cache_max_age'] + $lastBuildDate) <= $this->output_data['time']) {
364				$ttl_time = (int) ($this->cache_config['cache_max_age'] / 60);
365			} else {
366				$ttl_time = ( $this->cache_config['cache_max_age'] + $lastBuildDate) - $this->output_data['time'];
367			}
368			$ttl = sprintf($this->style_config['chan_ttl_tpl'], intval( ( $ttl_time / 60)) );
369			$lastBuildDate = sprintf($this->style_config['chan_lastbuildate_tpl'], gmdate('D, d M Y H:i:s \G\M\T', intval($lastBuildDate)));
370		} else {
371			$lastBuildDate = '';
372			$ttl = '';
373		}
374		$chan_image = !empty($chan_image) ? sprintf($this->style_config['rsschan_img_tpl'], $this->xml_encode($chan_title), $chan_image, $chan_link) : '';
375		$input = !empty($chan_source) ? sprintf($this->style_config['rsschan_input_tpl'], $this->xml_encode($user->lang['RSS_2_LINK'] . ' : ' . $chan_title), $this->xml_encode($chan_desc . $user->lang['RSS_2_LINK']), $chan_source, 'gym_sitemaps') :  '';
376
377		$this->output_data['data'] .= sprintf($this->style_config['rsschan_tpl'], $this->xml_encode($chan_title), $chan_link, $this->xml_encode($chan_desc . $this->rss_config['rss_auth_msg'] . $this->actions['sql_report_msg']), $lastBuildDate, $chan_image, $ttl, $chan_source, $input);
378	}
379	/**
380	* parse_item() adds the item info to the output
381	*/
382	function parse_item($item_title, $item_desc, $item_link, $item_source, $item_source_title = '', $pubDate = 0, $author = false) {
383		global $config;
384		$pubDate = $pubDate > $config['board_startdate'] ? sprintf($this->style_config['item_pubdate_tpl'], gmdate('D, d M Y H:i:s \G\M\T', intval($pubDate))) : '';
385		$item_desc = $this->rss_config['rss_nohtml'] ? strip_tags($item_desc) : $item_desc;
386		$item_source_title = !empty($item_source_title) ? $item_source_title : $item_title;
387		$author = $author ? sprintf($this->style_config['item_creator_tpl'], $this->xml_encode($author)) : '';
388		$this->output_data['data'] .= sprintf($this->style_config['rss_item_tpl'], $this->xml_encode($item_title), $item_link, $pubDate, $this->xml_encode($item_desc . $this->rss_config['rss_auth_msg']), $item_source, $this->xml_encode($item_source_title), $item_link, $author);
389		$this->output_data['url_sofar']++;
390	}
391	/**
392	* prepare_for_output($topic, $key = '')
393	* will put together BBcodes and smilies before the output
394	* @param array $topic
395	* @access private
396	*/
397	function prepare_for_output($topic, $key = '') {
398		global $config, $user, $phpbb_seo;
399		static $bbcode;
400		static $patterns;
401		static $replaces;
402		$bbcode_uid = $topic['bbcode_uid' . $key];
403		$bitfield = $topic['bbcode_bitfield' . $key];
404		$message_title = !empty($topic['post_subject' . $key]) ? $topic['post_subject' . $key] : $topic['topic_title'];
405		$message_title = censor_text($message_title);
406		$message = '<b>' . $message_title . '</b>' . "\n\n" . $topic['post_text' . $key];
407		if (!isset($patterns)) {
408			if ( !empty($this->rss_config['rss_msg_filters']['pattern']) ) {
409				$patterns = $this->rss_config['rss_msg_filters']['pattern'];
410				$replaces = $this->rss_config['rss_msg_filters']['replace'];
411			} else {
412				$patterns = $replaces = array();
413			}
414		}
415		if (!empty($patterns)) {
416			$message = preg_replace($patterns, $replaces, $message);
417		}
418		if ($this->rss_config['rss_sumarize'] > 0 ) {
419			$message = $this->summarize( $message, $this->rss_config['rss_sumarize'], $this->rss_config['rss_sumarize_method'] );
420			// Clean broken tag at the end of the message
421			$message = preg_replace('`\<[^\<\>]*$`i', ' ...', $message);
422			// Close broken bbcode tags requiring it
423			$this->close_bbcode_tags($message, $bbcode_uid);
424		}
425		$message = censor_text($message);
426		if (!$this->rss_config['rss_nohtml']) {
427			if ($bitfield && $this->rss_config['rss_allow_bbcode']) {
428				if (!class_exists('bbcode')) {
429					global $phpbb_root_path, $phpEx;
430					include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
431				}
432				if (empty($bbcode)) {
433					$bbcode = new bbcode($bitfield);
434				} else {
435					$bbcode->bbcode($bitfield);
436				}
437				if ( !$this->rss_config['rss_allow_links'] ) {
438					$message = preg_replace("`\[/?url(=.*)?\]`i", "", $message);
439				}
440				$bbcode->bbcode_second_pass($message, $bbcode_uid);
441			}
442			// Parse smilies
443			$message = $this->smiley_text($message, !($this->rss_config['rss_allow_smilies'] && $topic['enable_smilies' . $key]));
444			if ($this->rss_config['rss_sumarize'] > 0 ) {
445				// last clean up
446				static $_find = array('`\<\!--[^\<\>]+--\>`Ui', '`\[\/?[^\]\[]*\]`Ui');
447				$message = preg_replace($_find, '', $message);
448				$message .= "\n\n" . '<a href="' . $topic['topic_url' . $key] . '"><b>' . $user->lang['RSS_MORE'] . ' ...</b></a>'. "\n\n";
449			}
450		} else {
451			$message = strip_tags(preg_replace('`\[\/?[^\]\[]*\]`Ui', '', $message));
452		}
453		return "\n" . $message;
454	}
455	/**
456	* close_bbcode_tags(&$message, $uid, $bbcodelist)
457	* will tend to do it nicely ;-)
458	* Will close the bbcode tags requiring it in the list (quote|b|u|i|color|*|list)
459	* Beware, bo not reduce $bbcodelist without knowing what you are doing
460	*/
461	function close_bbcode_tags(&$message, $uid, $bbcodelist = 'quote|b|u|i|color|*|list') {
462		$open_lists = $close_lists = array();
463		$bbcodelist = str_replace('|*', '|\*', $bbcodelist);
464		$open_count = preg_match_all('`\[(' . $bbcodelist . ')(\=([a-z0-9]{1}))?[^\]\[]*\:' . $uid . '\]`i', $message, $open_matches);
465		$close_count = preg_match_all('`\[/(' . $bbcodelist . ')(\:([a-z]{1}))?[^\]\[]*\:' . $uid . '\]`i', $message, $close_matches);
466		if ($open_count == $close_count) { // No need to go further
467			return;
468		}
469		if (!empty($open_matches[1])) {
470			$open_list = array_count_values($open_matches[1]);
471			$close_list = !empty($close_matches[1]) ? array_count_values($close_matches[1]) : array();
472			$list_to_close = array();
473			if (isset($open_list['list'])) {
474				foreach ($open_matches[1] as $k => $v) {
475					if ($v == 'list') {
476						$open_lists[] = !empty($open_matches[3][$k]) ? 'o' : 'u';
477					}
478				}
479				if (!empty($close_matches[1])) {
480					foreach ($close_matches[1] as $k => $v) {
481						if ($v == 'list') {
482							$close_lists[] = !empty($close_matches[3][$k]) ? 'o' : 'u';
483						}
484					}
485				}
486				$list_to_close = array_reverse(array_diff_assoc($open_lists, $close_lists));
487			}
488			unset($open_list['*'], $open_list['list']);
489			foreach ($open_list as $bbcode => $total) {
490				if (empty($close_list[$bbcode]) || $close_list[$bbcode] < $total) {
491					// close the tags
492					$diff = empty($close_list[$bbcode]) ? $total : $total - $close_list[$bbcode];
493					$message .= str_repeat("[/$bbcode:$uid]", $diff);
494				}
495			}
496			// Close the lists if required
497			foreach ($list_to_close as $ltype) {
498				$message .= "[/*:m:$uid][/list:$ltype:$uid]";
499			}
500		}
501		return;
502	}
503	/**
504	* set_msg_strip($bbcode_list) will build up the unauthed bbcode list
505	* $bbcode_list = 'code:0,img:1,quote';
506	* $bbcode_list = 'all';
507	* 1 means the bbcode and it's content will be striped.
508	* all means all bbcodes.
509	* $returned_list = array('patern' => $matching_patterns, 'replace' => $replace_patterns);
510	* @access private
511	*/
512	function set_msg_strip($bbcode_list) {
513		$patterns = $replaces = array();
514		// Now the bbcodes
515		if (!$this->rss_config['rss_allow_bbcode'] || preg_match('`all\:?([0-1]*)`i', $bbcode_list, $matches)) {
516			if ( (@$matches[1] != 1 ) ) {
517				$patterns[] = '`\[\/?[a-z0-9\*\+\-]+(?:=(?:&quot;.*&quot;|[^\]]*))?(?::[a-z])?(\:[0-9a-z]{5,})\]`i';
518				$replaces[] = '';
519			} else {
520				$patterns[] = '`\[([a-z0-9\*\+\-]+)((=|:)[^\:\]]*)?\:[0-9a-z]{5,}\].*\[/(?1)(:?[^\:\]]*)?\:[0-9a-z]{5,}\]`Usi';
521				$replaces[] = "{ \\1 }";
522			}
523			$patterns[] = '`<[^>]*>(.*<[^>]*>)?`Usi'; // All html
524			$replaces[] = '';
525		} else {
526			// Take care about links & emails
527			if ( !$this->rss_config['rss_allow_links'] ) {
528				if ( !$this->rss_config['rss_allow_emails'] ) { // Saves couple RegEx
529					$email_find = '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+';
530					$email_replace = 'str_replace(array("@", "."), array("  AT  ", " DOT "),"\\1")';
531					$email_option = 'e';
532				} else {
533					$email_find = '.*?';
534					$email_replace = "\\1";
535					$email_option = '';
536				}
537				$patterns[] = '`<!\-\- ([lmw]+) \-\-><a (?:class="[\w-]+" )?href="(.*?)">.*?</a><!\-\- \1 \-\->`i';
538				$replaces[] = "\\2";
539				$patterns[] = '`\[/?url[^\]\[]*\]`i';
540				$replaces[] = '';
541				$patterns[] = '`<!\-\- e \-\-><a href="mailto:(' . $email_find . ')">.*?</a><!\-\- e \-\->`i' . $email_option;
542				$replaces[] = $email_replace;
543			}
544			if ( !$this->rss_config['rss_allow_emails'] && $this->rss_config['rss_allow_links'] ) {
545				$patterns[] = '`<!\-\- e \-\-><a href="mailto:([a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+)">.*?</a><!\-\- e \-\->`ei';
546				$replaces[] = 'str_replace(array("@", "."), array("  AT  ", " DOT "),"\\1")';
547			}
548			$exclude_list =  ( empty($bbcode_list) ? array() : explode(',', $bbcode_list) );
549			$RegEx_unset = $RegEx_remove = '';
550			foreach ($exclude_list as $key => $value ) { // Group the RegEx
551				$value = trim($value);
552				if (preg_match("`[a-z0-9]+(\:([0-1]*))?`i", $value, $matches) ) {
553					$values = (strpos($value, ':') !== false) ?  explode(':', $value) : array($value);
554					if ( (@$matches[2] != 1 ) ) {
555						$RegEx_unset .= (!empty($RegEx_unset) ? '|' : '' ) . $values[0];
556					} else {
557						$RegEx_remove .= (!empty($RegEx_remove) ? '|' : '' ) . $values[0];
558					}
559				}
560			}
561			if (!empty($RegEx_remove) ) {
562				$patterns[] =  '`\[(' . $RegEx_remove . ')((=|:)[^\:\]]*)?\:[0-9a-z]{5,}\].*\[/(?1)(:?[^\:\]]*)?\:[0-9a-z]{5,}\]`Usi';
563				$replaces[] = "{ \\1 }";
564			}
565			if (!empty($RegEx_unset) ) {
566				$patterns[] =  '`\[/?(' . $RegEx_unset . ')(?:=(?:&quot;.*&quot;|[^\]]*))?(?::[a-z])?(\:[0-9a-z]{5,})\]`i';
567				$replaces[] = '';
568			}
569		}
570		return  array('pattern' => $patterns, 'replace' => $replaces);
571	}
572	/**
573	* Some text formating functions for text output
574	* un_htmlspecialchars()
575	* @access private
576	*/
577	function un_htmlspecialchars($text) {
578		return preg_replace(array('#&gt;#', '#&lt;#', '#&quot;#', '#&amp;#'), array('>', '<', '"', '&'), $text);
579	}
580	/**
581	* Summarize method selector
582	* @access private
583	*/
584	function summarize($string, $limit, $method = 'lines') {
585		switch ($method) {
586			case 'words':
587				return $this->word_limit($string, $limit);
588				break;
589			case 'chars':
590				return $this->char_limit($string, $limit);
591				break;
592			case 'lines':
593			default:
594				return $this->line_limit($string, $limit);
595				break;
596		}
597	}
598	/**
599	* Cut the text by lines
600	* @access private
601	*/
602	function line_limit($string, $limit = 10, $ellipsis = ' ...') {
603		return count($lines = preg_split("`[\n\r]+`", ltrim($string), $limit + 1)) > $limit ? rtrim(utf8_substr($string, 0, utf8_strlen($string) - utf8_strlen(end($lines)))) . $ellipsis : $string;
604	}
605	/**
606	* Cut the text according to the number of words.
607	* Borrowed from www.php.net http://www.php.net/preg_replace
608	* @access private
609	*/
610	function word_limit($string, $limit = 50, $ellipsis = ' ...') {
611		return count($words = preg_split('`\s+`', ltrim($string), $limit + 1)) > $limit ? rtrim(utf8_substr($string, 0, utf8_strlen($string) - utf8_strlen(end($words)))) . $ellipsis : $string;
612	}
613	/**
614	* Cut the text according to the number of characters.
615	* Borrowed from www.php.net http://www.php.net/preg_replace
616	* @access private
617	*/
618	function char_limit($string, $limit = 100, $ellipsis = ' ...') {
619		return utf8_strlen($fragment = utf8_substr($string, 0, $limit + 1 - utf8_strlen($ellipsis))) < utf8_strlen($string) + 1 ? preg_replace('`\s*\S*$`', '', $fragment) . $ellipsis : $string;
620	}
621
622	// --> Yahoo! Notification functions <--
623	/**
624	* rss_yahoo_notify($url) will handle yahoo notification of new content
625	* @access private
626	*/
627	function rss_yahoo_notify($url = '') {
628		global $user, $config, $phpbb_seo;
629		$url = !empty($url) ? str_replace('&amp;', '&', $url) : (!empty($this->url_config['rss_yahoo_notify_url']) ? $this->url_config['rss_yahoo_notify_url'] : '');
630		$url = trim($url);
631		if (empty($url) || !$this->rss_config['rss_yahoo_notify'] || empty($this->rss_config['yahoo_appid'])) {
632			return;
633		}
634		// No more than 200 pings a day!
635		if (@$config['gym_pinged_today'] > 200) {
636			// @TODO add logs about this ?
637			return;
638		}
639		$skip = array('://localhost', '://127.0.0.1', '://192.168.', '://169.254.');
640		foreach ($skip as $_skip) {
641			if (utf8_strpos($url, $_skip) !== false) {
642				// @TODO add logs about this ?
643				return;
644			}
645		}
646		// If ssl is not forced, always ping with http urls
647		$url = $phpbb_seo->sslify($url, $phpbb_seo->ssl['forced']);
648		$not_curl= true;
649		$timout = 3;
650		// The Yahoo! Web Services request
651		// Based on the Yahoo! developper hints : http://developer.yahoo.com/php/
652		$request = "http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=" . urlencode($this->rss_config['yahoo_appid']) . '&url=' . urlencode($url);
653		if (function_exists('curl_exec')) {
654			$not_curl= false;
655			// Initialize the session
656			$session = curl_init($request);
657			// Set curl options
658			curl_setopt($session, CURLOPT_HEADER, false);
659			curl_setopt($session, CURLOPT_USERAGENT, 'GYM Sitemaps &amp; RSS / www.phpBB-SEO.com');
660			curl_setopt($session, CURLOPT_TIMEOUT, $timout);
661			curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
662			// Make the request
663			$response = curl_exec($session);
664			// Close the curl session
665			curl_close($session);
666			// Get HTTP Status code from the response
667			$status_codes = array();
668			preg_match('/\d\d\d/', $response, $status_code);
669			$status_code = $status_codes[0];
670			// Get the XML from the response, bypassing the header
671			if (!($xml = strstr($response, '<?xml'))) {
672				$xml = null;
673				$not_curl= true;
674			}
675		} else if ( $not_curl && function_exists('file_get_contents') ) {
676			ini_set('user_agent','GYM Sitemaps &amp; RSS / www.phpBB-SEO.com');
677			ini_set('default_socket_timeout', $timout);
678			// Make the request
679			if ($xml = file_get_contents($request)) {
680				// Retrieve HTTP status code
681				list($version,$status_code,$msg) = explode(' ',$http_response_header[0], 3);
682			} else {
683			//	$user->lang['RSS_YAHOO_NO_METHOD'] = sprintf($user->lang['RSS_YAHOO_NO_METHOD'], $request, $xml);
684				$this->gym_error(503, 'RSS_YAHOO_NO_METHOD',  __FILE__, __LINE__);
685			}
686		}
687		// Check the XML return message
688		// Do it this way here in case curl actually returned no header
689		// but did get the proper answer.
690		if (!strpos($xml, 'success')) {
691			// Check the HTTP Status code
692			switch( $status_code ) {
693				case 200: // Success
694					set_config('gym_pinged_today', @$config['gym_pinged_today'] + 1, 1);
695					break;
696				case 503:
697					$this->gym_error(500, 'RSS_YAHOO_503', __FILE__, __LINE__);
698					break;
699				case 403:
700					$this->gym_error(500, 'RSS_YAHOO_403', __FILE__, __LINE__);
701					break;
702				case 400:
703				//	$user->lang['RSS_YAHOO_400_MSG'] = sprintf($user->lang['RSS_YAHOO_400_MSG'], $request, $xml);
704					$this->gym_error(500,'RSS_YAHOO_400',  __FILE__, __LINE__);
705					break;
706				default:
707				//	$user->lang['RSS_YAHOO_ERROR_MSG'] = sprintf($user->lang['RSS_YAHOO_400_MSG'], $status_code, $request, $xml);
708					$this->gym_error(500, 'RSS_YAHOO_500', __FILE__, __LINE__);
709			}
710		}
711		return;
712	}
713}
714?>