qa-feed.php 12.3 KB
Newer Older
Gideon Greenspan committed
1 2 3 4 5 6 7
<?php

/*
	Question2Answer (c) Gideon Greenspan

	http://www.question2answer.org/

Scott Vivian committed
8

Gideon Greenspan committed
9 10 11 12 13 14 15 16 17
	File: qa-include/qa-feed.php
	Version: See define()s at top of qa-include/qa-base.php
	Description: Handles all requests to RSS feeds, first checking if they should be available


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
Scott Vivian committed
18

Gideon Greenspan committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

	if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
		header('Location: ../');
		exit;
	}

	@ini_set('display_errors', 0); // we don't want to show PHP errors to RSS readers

	qa_report_process_stage('init_feed');

	require_once QA_INCLUDE_DIR.'qa-app-options.php';


//	Functions used within this file

	function qa_feed_db_fail_handler($type, $errno=null, $error=null, $query=null)
/*
	Database failure handler function for RSS feeds - outputs HTTP and text errors
*/

	{
		header('HTTP/1.1 500 Internal Server Error');
		echo qa_lang_html('main/general_error');
		qa_exit('error');
	}

Scott Vivian committed
52

Gideon Greenspan committed
53 54 55 56 57 58 59 60 61 62
	function qa_feed_not_found()
/*
	Common function called when a non-existent feed is requested - outputs HTTP and text errors
*/
	{
		header('HTTP/1.0 404 Not Found');
		echo qa_lang_html('misc/feed_not_found');
		qa_exit();
	}

Scott Vivian committed
63

Gideon Greenspan committed
64 65 66 67 68 69 70
	function qa_feed_load_ifcategory($categoryslugs, $allkey, $catkey, &$title,
		$questionselectspec1=null, $questionselectspec2=null, $questionselectspec3=null, $questionselectspec4=null)
/*
	Common function to load appropriate set of questions for requested feed, check category exists, and set up page title
*/
	{
		$countslugs=@count($categoryslugs);
Scott Vivian committed
71

Gideon Greenspan committed
72
		list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid)=qa_db_select_with_pending(
Gideon Greenspan committed
73 74 75 76 77 78 79 80 81 82 83 84 85
			$questionselectspec1,
			$questionselectspec2,
			$questionselectspec3,
			$questionselectspec4,
			$countslugs ? qa_db_category_nav_selectspec($categoryslugs, false) : null,
			$countslugs ? qa_db_slugs_to_category_id_selectspec($categoryslugs) : null
		);

		if ($countslugs && !isset($categoryid))
			qa_feed_not_found();

		if (isset($allkey))
			$title=(isset($categoryid) && isset($catkey)) ? qa_lang_sub($catkey, $categories[$categoryid]['title']) : qa_lang($allkey);
Scott Vivian committed
86

Gideon Greenspan committed
87 88 89 90 91 92 93 94 95 96 97 98 99
		return array_merge(
			is_array($questions1) ? $questions1 : array(),
			is_array($questions2) ? $questions2 : array(),
			is_array($questions3) ? $questions3 : array(),
			is_array($questions4) ? $questions4 : array()
		);
	}


//	Connect to database and get the type of feed and category requested (in some cases these are overridden later)

	qa_db_connect('qa_feed_db_fail_handler');
	qa_preload_options();
Scott Vivian committed
100

Gideon Greenspan committed
101 102
	$requestlower=strtolower(qa_request());
	$foursuffix=substr($requestlower, -4);
Scott Vivian committed
103

Gideon Greenspan committed
104 105
	if ( ($foursuffix=='.rss') || ($foursuffix=='.xml') )
		$requestlower=substr($requestlower, 0, -4);
Scott Vivian committed
106

Gideon Greenspan committed
107 108 109 110
	$requestlowerparts=explode('/', $requestlower);

	$feedtype=@$requestlowerparts[1];
	$feedparams=array_slice($requestlowerparts, 2);
Scott Vivian committed
111

Gideon Greenspan committed
112 113 114 115 116

//	Choose which option needs to be checked to determine if this feed can be requested, and stop if no matches

	$feedoption=null;
	$categoryslugs=$feedparams;
Scott Vivian committed
117

Gideon Greenspan committed
118 119 120 121
	switch ($feedtype) {
		case 'questions':
			$feedoption='feed_for_questions';
			break;
Scott Vivian committed
122

Gideon Greenspan committed
123 124 125 126 127
		case 'hot':
			$feedoption='feed_for_hot';
			if (!QA_ALLOW_UNINDEXED_QUERIES)
				$categoryslugs=null;
			break;
Scott Vivian committed
128

Gideon Greenspan committed
129 130 131 132 133
		case 'unanswered':
			$feedoption='feed_for_unanswered';
			if (!QA_ALLOW_UNINDEXED_QUERIES)
				$categoryslugs=null;
			break;
Scott Vivian committed
134

Gideon Greenspan committed
135 136 137 138 139
		case 'answers':
		case 'comments':
		case 'activity':
			$feedoption='feed_for_activity';
			break;
Scott Vivian committed
140

Gideon Greenspan committed
141 142 143
		case 'qa':
			$feedoption='feed_for_qa';
			break;
Scott Vivian committed
144

Gideon Greenspan committed
145 146 147 148 149 150
		case 'tag':
			if (strlen(@$feedparams[0])) {
				$feedoption='feed_for_tag_qs';
				$categoryslugs=null;
			}
			break;
Scott Vivian committed
151

Gideon Greenspan committed
152 153 154 155 156 157 158
		case 'search':
			if (strlen(@$feedparams[0])) {
				$feedoption='feed_for_search';
				$categoryslugs=null;
			}
			break;
	}
Scott Vivian committed
159

Gideon Greenspan committed
160 161 162 163
	$countslugs=@count($categoryslugs);

	if (!isset($feedoption))
		qa_feed_not_found();
Scott Vivian committed
164

Gideon Greenspan committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

//	Check that all the appropriate options are in place to allow this feed to be retrieved

	if (!(
		(qa_opt($feedoption)) &&
		($countslugs ? (qa_using_categories() && qa_opt('feed_per_category')) : true)
	))
		qa_feed_not_found();


//	Retrieve the appropriate questions and other information for this feed

	require_once QA_INCLUDE_DIR.'qa-db-selects.php';

	$sitetitle=qa_opt('site_title');
	$siteurl=qa_opt('site_url');
	$full=qa_opt('feed_full_text');
	$count=qa_opt('feed_number_items');
	$showurllinks=qa_opt('show_url_links');
Scott Vivian committed
184

Gideon Greenspan committed
185 186 187 188 189 190 191 192 193
	$linkrequest=$feedtype.($countslugs ? ('/'.implode('/', $categoryslugs)) : '');
	$linkparams=null;

	switch ($feedtype) {
		case 'questions':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_qs_title', 'main/recent_qs_in_x', $title,
				qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count)
			);
			break;
Scott Vivian committed
194

Gideon Greenspan committed
195 196 197 198 199
		case 'hot':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/hot_qs_title', 'main/hot_qs_in_x', $title,
				qa_db_qs_selectspec(null, 'hotness', 0, $categoryslugs, null, false, $full, $count)
			);
			break;
Scott Vivian committed
200

Gideon Greenspan committed
201 202 203 204 205
		case 'unanswered':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/unanswered_qs_title', 'main/unanswered_qs_in_x', $title,
				qa_db_unanswered_qs_selectspec(null, null, 0, $categoryslugs, false, $full, $count)
			);
			break;
Scott Vivian committed
206

Gideon Greenspan committed
207 208 209 210 211 212 213 214 215 216 217
		case 'answers':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_as_title', 'main/recent_as_in_x', $title,
				qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
			);
			break;

		case 'comments':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_cs_title', 'main/recent_cs_in_x', $title,
				qa_db_recent_c_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
			);
			break;
Scott Vivian committed
218

Gideon Greenspan committed
219 220 221 222 223 224
		case 'qa':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_qs_as_title', 'main/recent_qs_as_in_x', $title,
				qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count),
				qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
			);
			break;
Scott Vivian committed
225

Gideon Greenspan committed
226 227 228 229 230 231 232 233
		case 'activity':
			$questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_activity_title', 'main/recent_activity_in_x', $title,
				qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count),
				qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count),
				qa_db_recent_c_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count),
				qa_db_recent_edit_qs_selectspec(null, 0, $categoryslugs, null, true, $full, $count)
			);
			break;
Scott Vivian committed
234

Gideon Greenspan committed
235 236 237 238 239 240
		case 'tag':
			$tag=$feedparams[0];

			$questions=qa_feed_load_ifcategory(null, null, null, $title,
				qa_db_tag_recent_qs_selectspec(null, $tag, 0, $full, $count)
			);
Scott Vivian committed
241

Gideon Greenspan committed
242 243 244
			$title=qa_lang_sub('main/questions_tagged_x', $tag);
			$linkrequest='tag/'.$tag;
			break;
Scott Vivian committed
245

Gideon Greenspan committed
246 247
		case 'search':
			require_once QA_INCLUDE_DIR.'qa-app-search.php';
Scott Vivian committed
248

Gideon Greenspan committed
249 250 251
			$query=$feedparams[0];

			$results=qa_get_search_results($query, 0, $count, null, true, $full);
Scott Vivian committed
252

Gideon Greenspan committed
253 254 255 256 257
			$title=qa_lang_sub('main/results_for_x', $query);
			$linkrequest='search';
			$linkparams=array('q' => $query);

			$questions=array();
Scott Vivian committed
258

Gideon Greenspan committed
259 260 261 262 263
			foreach ($results as $result) {
				$setarray=array(
					'title' => $result['title'],
					'url' => $result['url'],
				);
Scott Vivian committed
264

Gideon Greenspan committed
265 266 267 268 269 270 271 272 273 274
				if (isset($result['question']))
					$questions[]=array_merge($result['question'], $setarray);
				elseif (isset($result['url']))
					$questions[]=$setarray;
			}
			break;
	}


//	Remove duplicate questions (perhaps referenced in an answer and a comment) and cut down to size
Scott Vivian committed
275

Gideon Greenspan committed
276 277 278 279 280 281
	require_once QA_INCLUDE_DIR.'qa-app-format.php';
	require_once QA_INCLUDE_DIR.'qa-app-updates.php';
	require_once QA_INCLUDE_DIR.'qa-util-string.php';

	if ( ($feedtype!='search') && ($feedtype!='hot') ) // leave search results and hot questions sorted by relevance
		$questions=qa_any_sort_and_dedupe($questions);
Scott Vivian committed
282

Gideon Greenspan committed
283 284 285 286 287 288 289 290
	$questions=array_slice($questions, 0, $count);
	$blockwordspreg=qa_get_block_words_preg();


//	Prepare the XML output

	$lines=array();

Gideon Greenspan committed
291
	$lines[]='<?xml version="1.0" encoding="utf-8"?>';
Gideon Greenspan committed
292 293 294
	$lines[]='<rss version="2.0">';
	$lines[]='<channel>';

Gideon Greenspan committed
295 296
	$lines[]='<title>'.qa_xml($sitetitle.' - '.$title).'</title>';
	$lines[]='<link>'.qa_xml(qa_path($linkrequest, $linkparams, $siteurl)).'</link>';
Gideon Greenspan committed
297
	$lines[]='<description>Powered by Question2Answer</description>';
Scott Vivian committed
298

Gideon Greenspan committed
299 300 301
	foreach ($questions as $question) {

	//	Determine whether this is a question, answer or comment, and act accordingly
Scott Vivian committed
302

Gideon Greenspan committed
303
		$options=array('blockwordspreg' => @$blockwordspreg, 'showurllinks' => $showurllinks);
Scott Vivian committed
304

Gideon Greenspan committed
305 306 307 308 309
		$time=null;
		$htmlcontent=null;

		if (isset($question['opostid'])) {
			$time=$question['otime'];
Scott Vivian committed
310

Gideon Greenspan committed
311 312
			if ($full)
				$htmlcontent=qa_viewer_html($question['ocontent'], $question['oformat'], $options);
Scott Vivian committed
313

Gideon Greenspan committed
314 315
		} elseif (isset($question['postid'])) {
			$time=$question['created'];
Scott Vivian committed
316

Gideon Greenspan committed
317 318 319
			if ($full)
				$htmlcontent=qa_viewer_html($question['content'], $question['format'], $options);
		}
Scott Vivian committed
320

Gideon Greenspan committed
321 322
		if ($feedtype=='search') {
			$titleprefix='';
Gideon Greenspan committed
323
			$urlxml=qa_xml($question['url']);
Scott Vivian committed
324

Gideon Greenspan committed
325 326 327 328 329 330
		} else {
			switch (@$question['obasetype'].'-'.@$question['oupdatetype']) {
				case 'Q-':
				case '-':
					$langstring=null;
					break;
Scott Vivian committed
331

Gideon Greenspan committed
332 333 334
				case 'Q-'.QA_UPDATE_VISIBLE:
					$langstring=$question['hidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_reshown_prefix';
					break;
Scott Vivian committed
335

Gideon Greenspan committed
336 337 338
				case 'Q-'.QA_UPDATE_CLOSED:
					$langstring=isset($question['closedbyid']) ? 'misc/feed_closed_prefix' : 'misc/feed_reopened_prefix';
					break;
Scott Vivian committed
339

Gideon Greenspan committed
340 341 342
				case 'Q-'.QA_UPDATE_TAGS:
					$langstring='misc/feed_retagged_prefix';
					break;
Scott Vivian committed
343

Gideon Greenspan committed
344 345 346
				case 'Q-'.QA_UPDATE_CATEGORY:
					$langstring='misc/feed_recategorized_prefix';
					break;
Scott Vivian committed
347

Gideon Greenspan committed
348 349 350
				case 'A-':
					$langstring='misc/feed_a_prefix';
					break;
Scott Vivian committed
351

Gideon Greenspan committed
352 353 354
				case 'A-'.QA_UPDATE_SELECTED:
					$langstring='misc/feed_a_selected_prefix';
					break;
Scott Vivian committed
355

Gideon Greenspan committed
356 357 358
				case 'A-'.QA_UPDATE_VISIBLE:
					$langstring=$question['ohidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_a_reshown_prefix';
					break;
Scott Vivian committed
359

Gideon Greenspan committed
360 361 362
				case 'A-'.QA_UPDATE_CONTENT:
					$langstring='misc/feed_a_edited_prefix';
					break;
Scott Vivian committed
363

Gideon Greenspan committed
364 365 366
				case 'C-':
					$langstring='misc/feed_c_prefix';
					break;
Scott Vivian committed
367

Gideon Greenspan committed
368 369 370
				case 'C-'.QA_UPDATE_TYPE:
					$langstring='misc/feed_c_moved_prefix';
					break;
Scott Vivian committed
371

Gideon Greenspan committed
372 373 374
				case 'C-'.QA_UPDATE_VISIBLE:
					$langstring=$question['ohidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_c_reshown_prefix';
					break;
Scott Vivian committed
375

Gideon Greenspan committed
376 377 378
				case 'C-'.QA_UPDATE_CONTENT:
					$langstring='misc/feed_c_edited_prefix';
					break;
Scott Vivian committed
379

Gideon Greenspan committed
380 381 382 383
				case 'Q-'.QA_UPDATE_CONTENT:
				default:
					$langstring='misc/feed_edited_prefix';
					break;
Scott Vivian committed
384

Gideon Greenspan committed
385
			}
Scott Vivian committed
386

Gideon Greenspan committed
387
			$titleprefix=isset($langstring) ? qa_lang($langstring) : '';
Scott Vivian committed
388

Gideon Greenspan committed
389
			$urlxml=qa_xml(qa_q_path($question['postid'], $question['title'], true, @$question['obasetype'], @$question['opostid']));
Gideon Greenspan committed
390
		}
Scott Vivian committed
391

Gideon Greenspan committed
392 393
		if (isset($blockwordspreg))
			$question['title']=qa_block_words_replace($question['title'], $blockwordspreg);
Scott Vivian committed
394

Gideon Greenspan committed
395
	//	Build the inner XML structure for each item
Scott Vivian committed
396

Gideon Greenspan committed
397
		$lines[]='<item>';
Gideon Greenspan committed
398 399
		$lines[]='<title>'.qa_xml($titleprefix.$question['title']).'</title>';
		$lines[]='<link>'.$urlxml.'</link>';
Gideon Greenspan committed
400 401

		if (isset($htmlcontent))
Gideon Greenspan committed
402
			$lines[]='<description>'.qa_xml($htmlcontent).'</description>';
Scott Vivian committed
403

Gideon Greenspan committed
404
		if (isset($question['categoryname']))
Gideon Greenspan committed
405
			$lines[]='<category>'.qa_xml($question['categoryname']).'</category>';
Scott Vivian committed
406

Gideon Greenspan committed
407
		$lines[]='<guid isPermaLink="true">'.$urlxml.'</guid>';
Scott Vivian committed
408

Gideon Greenspan committed
409
		if (isset($time))
Gideon Greenspan committed
410
			$lines[]='<pubDate>'.qa_xml(gmdate('r', $time)).'</pubDate>';
Scott Vivian committed
411

Gideon Greenspan committed
412 413
		$lines[]='</item>';
	}
Scott Vivian committed
414

Gideon Greenspan committed
415 416 417 418 419 420 421 422 423 424
	$lines[]='</channel>';
	$lines[]='</rss>';


//	Disconnect here, once all output is ready to go

	qa_db_disconnect();


//	Output the XML - and we're done!
Scott Vivian committed
425

Gideon Greenspan committed
426 427
	header('Content-type: text/xml; charset=utf-8');
	echo implode("\n", $lines);
Scott Vivian committed
428

Gideon Greenspan committed
429 430 431 432

/*
	Omit PHP closing tag to help avoid accidental output
*/