PageRenderTime 95ms CodeModel.GetById 58ms RepoModel.GetById 1ms app.codeStats 0ms

/qa-include/qa-feed.php

https://bitbucket.org/harshjv/q2a-bootstrap
PHP | 432 lines | 272 code | 114 blank | 46 comment | 29 complexity | 665effd984b8f1187e85c26b8e5a9e3b MD5 | raw file
  1. <?php
  2. /*
  3. Question2Answer (c) Gideon Greenspan
  4. http://www.question2answer.org/
  5. File: qa-include/qa-feed.php
  6. Version: See define()s at top of qa-include/qa-base.php
  7. Description: Handles all requests to RSS feeds, first checking if they should be available
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License
  10. as published by the Free Software Foundation; either version 2
  11. of the License, or (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. More about this license: http://www.question2answer.org/license.php
  17. */
  18. if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
  19. header('Location: ../');
  20. exit;
  21. }
  22. @ini_set('display_errors', 0); // we don't want to show PHP errors to RSS readers
  23. qa_report_process_stage('init_feed');
  24. require_once QA_INCLUDE_DIR.'qa-app-options.php';
  25. // Functions used within this file
  26. function qa_feed_db_fail_handler($type, $errno=null, $error=null, $query=null)
  27. /*
  28. Database failure handler function for RSS feeds - outputs HTTP and text errors
  29. */
  30. {
  31. header('HTTP/1.1 500 Internal Server Error');
  32. echo qa_lang_html('main/general_error');
  33. qa_exit('error');
  34. }
  35. function qa_feed_not_found()
  36. /*
  37. Common function called when a non-existent feed is requested - outputs HTTP and text errors
  38. */
  39. {
  40. header('HTTP/1.0 404 Not Found');
  41. echo qa_lang_html('misc/feed_not_found');
  42. qa_exit();
  43. }
  44. function qa_feed_load_ifcategory($categoryslugs, $allkey, $catkey, &$title,
  45. $questionselectspec1=null, $questionselectspec2=null, $questionselectspec3=null, $questionselectspec4=null)
  46. /*
  47. Common function to load appropriate set of questions for requested feed, check category exists, and set up page title
  48. */
  49. {
  50. $countslugs=@count($categoryslugs);
  51. @list($questions1, $questions2, $questions3, $questions4, $categories, $categoryid)=qa_db_select_with_pending(
  52. $questionselectspec1,
  53. $questionselectspec2,
  54. $questionselectspec3,
  55. $questionselectspec4,
  56. $countslugs ? qa_db_category_nav_selectspec($categoryslugs, false) : null,
  57. $countslugs ? qa_db_slugs_to_category_id_selectspec($categoryslugs) : null
  58. );
  59. if ($countslugs && !isset($categoryid))
  60. qa_feed_not_found();
  61. if (isset($allkey))
  62. $title=(isset($categoryid) && isset($catkey)) ? qa_lang_sub($catkey, $categories[$categoryid]['title']) : qa_lang($allkey);
  63. return array_merge(
  64. is_array($questions1) ? $questions1 : array(),
  65. is_array($questions2) ? $questions2 : array(),
  66. is_array($questions3) ? $questions3 : array(),
  67. is_array($questions4) ? $questions4 : array()
  68. );
  69. }
  70. // Connect to database and get the type of feed and category requested (in some cases these are overridden later)
  71. qa_db_connect('qa_feed_db_fail_handler');
  72. qa_preload_options();
  73. $requestlower=strtolower(qa_request());
  74. $foursuffix=substr($requestlower, -4);
  75. if ( ($foursuffix=='.rss') || ($foursuffix=='.xml') )
  76. $requestlower=substr($requestlower, 0, -4);
  77. $requestlowerparts=explode('/', $requestlower);
  78. $feedtype=@$requestlowerparts[1];
  79. $feedparams=array_slice($requestlowerparts, 2);
  80. // Choose which option needs to be checked to determine if this feed can be requested, and stop if no matches
  81. $feedoption=null;
  82. $categoryslugs=$feedparams;
  83. switch ($feedtype) {
  84. case 'questions':
  85. $feedoption='feed_for_questions';
  86. break;
  87. case 'hot':
  88. $feedoption='feed_for_hot';
  89. if (!QA_ALLOW_UNINDEXED_QUERIES)
  90. $categoryslugs=null;
  91. break;
  92. case 'unanswered':
  93. $feedoption='feed_for_unanswered';
  94. if (!QA_ALLOW_UNINDEXED_QUERIES)
  95. $categoryslugs=null;
  96. break;
  97. case 'answers':
  98. case 'comments':
  99. case 'activity':
  100. $feedoption='feed_for_activity';
  101. break;
  102. case 'qa':
  103. $feedoption='feed_for_qa';
  104. break;
  105. case 'tag':
  106. if (strlen(@$feedparams[0])) {
  107. $feedoption='feed_for_tag_qs';
  108. $categoryslugs=null;
  109. }
  110. break;
  111. case 'search':
  112. if (strlen(@$feedparams[0])) {
  113. $feedoption='feed_for_search';
  114. $categoryslugs=null;
  115. }
  116. break;
  117. }
  118. $countslugs=@count($categoryslugs);
  119. if (!isset($feedoption))
  120. qa_feed_not_found();
  121. // Check that all the appropriate options are in place to allow this feed to be retrieved
  122. if (!(
  123. (qa_opt($feedoption)) &&
  124. ($countslugs ? (qa_using_categories() && qa_opt('feed_per_category')) : true)
  125. ))
  126. qa_feed_not_found();
  127. // Retrieve the appropriate questions and other information for this feed
  128. require_once QA_INCLUDE_DIR.'qa-db-selects.php';
  129. $sitetitle=qa_opt('site_title');
  130. $siteurl=qa_opt('site_url');
  131. $full=qa_opt('feed_full_text');
  132. $count=qa_opt('feed_number_items');
  133. $showurllinks=qa_opt('show_url_links');
  134. $linkrequest=$feedtype.($countslugs ? ('/'.implode('/', $categoryslugs)) : '');
  135. $linkparams=null;
  136. switch ($feedtype) {
  137. case 'questions':
  138. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_qs_title', 'main/recent_qs_in_x', $title,
  139. qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count)
  140. );
  141. break;
  142. case 'hot':
  143. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/hot_qs_title', 'main/hot_qs_in_x', $title,
  144. qa_db_qs_selectspec(null, 'hotness', 0, $categoryslugs, null, false, $full, $count)
  145. );
  146. break;
  147. case 'unanswered':
  148. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/unanswered_qs_title', 'main/unanswered_qs_in_x', $title,
  149. qa_db_unanswered_qs_selectspec(null, null, 0, $categoryslugs, false, $full, $count)
  150. );
  151. break;
  152. case 'answers':
  153. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_as_title', 'main/recent_as_in_x', $title,
  154. qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
  155. );
  156. break;
  157. case 'comments':
  158. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_cs_title', 'main/recent_cs_in_x', $title,
  159. qa_db_recent_c_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
  160. );
  161. break;
  162. case 'qa':
  163. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_qs_as_title', 'main/recent_qs_as_in_x', $title,
  164. qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count),
  165. qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count)
  166. );
  167. break;
  168. case 'activity':
  169. $questions=qa_feed_load_ifcategory($categoryslugs, 'main/recent_activity_title', 'main/recent_activity_in_x', $title,
  170. qa_db_qs_selectspec(null, 'created', 0, $categoryslugs, null, false, $full, $count),
  171. qa_db_recent_a_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count),
  172. qa_db_recent_c_qs_selectspec(null, 0, $categoryslugs, null, false, $full, $count),
  173. qa_db_recent_edit_qs_selectspec(null, 0, $categoryslugs, null, true, $full, $count)
  174. );
  175. break;
  176. case 'tag':
  177. $tag=$feedparams[0];
  178. $questions=qa_feed_load_ifcategory(null, null, null, $title,
  179. qa_db_tag_recent_qs_selectspec(null, $tag, 0, $full, $count)
  180. );
  181. $title=qa_lang_sub('main/questions_tagged_x', $tag);
  182. $linkrequest='tag/'.$tag;
  183. break;
  184. case 'search':
  185. require_once QA_INCLUDE_DIR.'qa-app-search.php';
  186. $query=$feedparams[0];
  187. $results=qa_get_search_results($query, 0, $count, null, true, $full);
  188. $title=qa_lang_sub('main/results_for_x', $query);
  189. $linkrequest='search';
  190. $linkparams=array('q' => $query);
  191. $questions=array();
  192. foreach ($results as $result) {
  193. $setarray=array(
  194. 'title' => $result['title'],
  195. 'url' => $result['url'],
  196. );
  197. if (isset($result['question']))
  198. $questions[]=array_merge($result['question'], $setarray);
  199. elseif (isset($result['url']))
  200. $questions[]=$setarray;
  201. }
  202. break;
  203. }
  204. // Remove duplicate questions (perhaps referenced in an answer and a comment) and cut down to size
  205. require_once QA_INCLUDE_DIR.'qa-app-format.php';
  206. require_once QA_INCLUDE_DIR.'qa-app-updates.php';
  207. require_once QA_INCLUDE_DIR.'qa-util-string.php';
  208. if ( ($feedtype!='search') && ($feedtype!='hot') ) // leave search results and hot questions sorted by relevance
  209. $questions=qa_any_sort_and_dedupe($questions);
  210. $questions=array_slice($questions, 0, $count);
  211. $blockwordspreg=qa_get_block_words_preg();
  212. // Prepare the XML output
  213. $lines=array();
  214. $lines[]='<?xml version="1.0" encoding="UTF-8"?>';
  215. $lines[]='<rss version="2.0">';
  216. $lines[]='<channel>';
  217. $lines[]='<title>'.qa_html($sitetitle.' - '.$title).'</title>';
  218. $lines[]='<link>'.qa_path_html($linkrequest, $linkparams, $siteurl).'</link>';
  219. $lines[]='<description>Feeds</description>';
  220. foreach ($questions as $question) {
  221. // Determine whether this is a question, answer or comment, and act accordingly
  222. $options=array('blockwordspreg' => @$blockwordspreg, 'showurllinks' => $showurllinks);
  223. $time=null;
  224. $htmlcontent=null;
  225. if (isset($question['opostid'])) {
  226. $time=$question['otime'];
  227. if ($full)
  228. $htmlcontent=qa_viewer_html($question['ocontent'], $question['oformat'], $options);
  229. } elseif (isset($question['postid'])) {
  230. $time=$question['created'];
  231. if ($full)
  232. $htmlcontent=qa_viewer_html($question['content'], $question['format'], $options);
  233. }
  234. if ($feedtype=='search') {
  235. $titleprefix='';
  236. $urlhtml=qa_html($question['url']);
  237. } else {
  238. switch (@$question['obasetype'].'-'.@$question['oupdatetype']) {
  239. case 'Q-':
  240. case '-':
  241. $langstring=null;
  242. break;
  243. case 'Q-'.QA_UPDATE_VISIBLE:
  244. $langstring=$question['hidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_reshown_prefix';
  245. break;
  246. case 'Q-'.QA_UPDATE_CLOSED:
  247. $langstring=isset($question['closedbyid']) ? 'misc/feed_closed_prefix' : 'misc/feed_reopened_prefix';
  248. break;
  249. case 'Q-'.QA_UPDATE_TAGS:
  250. $langstring='misc/feed_retagged_prefix';
  251. break;
  252. case 'Q-'.QA_UPDATE_CATEGORY:
  253. $langstring='misc/feed_recategorized_prefix';
  254. break;
  255. case 'A-':
  256. $langstring='misc/feed_a_prefix';
  257. break;
  258. case 'A-'.QA_UPDATE_SELECTED:
  259. $langstring='misc/feed_a_selected_prefix';
  260. break;
  261. case 'A-'.QA_UPDATE_VISIBLE:
  262. $langstring=$question['ohidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_a_reshown_prefix';
  263. break;
  264. case 'A-'.QA_UPDATE_CONTENT:
  265. $langstring='misc/feed_a_edited_prefix';
  266. break;
  267. case 'C-':
  268. $langstring='misc/feed_c_prefix';
  269. break;
  270. case 'C-'.QA_UPDATE_TYPE:
  271. $langstring='misc/feed_c_moved_prefix';
  272. break;
  273. case 'C-'.QA_UPDATE_VISIBLE:
  274. $langstring=$question['ohidden'] ? 'misc/feed_hidden_prefix' : 'misc/feed_c_reshown_prefix';
  275. break;
  276. case 'C-'.QA_UPDATE_CONTENT:
  277. $langstring='misc/feed_c_edited_prefix';
  278. break;
  279. case 'Q-'.QA_UPDATE_CONTENT:
  280. default:
  281. $langstring='misc/feed_edited_prefix';
  282. break;
  283. }
  284. $titleprefix=isset($langstring) ? qa_lang($langstring) : '';
  285. $urlhtml=qa_q_path_html($question['postid'], $question['title'], true, @$question['obasetype'], @$question['opostid']) ;
  286. }
  287. if (isset($blockwordspreg))
  288. $question['title']=qa_block_words_replace($question['title'], $blockwordspreg);
  289. // Build the inner XML structure for each item
  290. $lines[]='<item>';
  291. $lines[]='<title>'.qa_html($titleprefix.$question['title']).'</title>';
  292. $lines[]='<link>'.$urlhtml.'</link>';
  293. if (isset($htmlcontent))
  294. $lines[]='<description>'.qa_html($htmlcontent).'</description>'; // qa_html() a second time to put HTML code inside XML wrapper
  295. if (isset($question['categoryname']))
  296. $lines[]='<category>'.qa_html($question['categoryname']).'</category>';
  297. $lines[]='<guid isPermaLink="true">'.$urlhtml.'</guid>';
  298. if (isset($time))
  299. $lines[]='<pubDate>'.qa_html(gmdate('r', $time)).'</pubDate>';
  300. $lines[]='</item>';
  301. }
  302. $lines[]='</channel>';
  303. $lines[]='</rss>';
  304. // Disconnect here, once all output is ready to go
  305. qa_db_disconnect();
  306. // Output the XML - and we're done!
  307. header('Content-type: text/xml; charset=utf-8');
  308. echo implode("\n", $lines);
  309. /*
  310. Omit PHP closing tag to help avoid accidental output
  311. */