backend.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <?php
  2. /* remove ill effects of magic quotes */
  3. if (get_magic_quotes_gpc()) {
  4. function stripslashes_deep($value) {
  5. $value = is_array($value) ?
  6. array_map('stripslashes_deep', $value) : stripslashes($value);
  7. return $value;
  8. }
  9. $_POST = array_map('stripslashes_deep', $_POST);
  10. $_GET = array_map('stripslashes_deep', $_GET);
  11. $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
  12. $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
  13. }
  14. $op = $_REQUEST["op"];
  15. require_once "functions.php";
  16. if ($op != "share") require_once "sessions.php";
  17. require_once "modules/backend-rpc.php";
  18. require_once "sanity_check.php";
  19. require_once "config.php";
  20. require_once "db.php";
  21. require_once "db-prefs.php";
  22. no_cache_incantation();
  23. startup_gettext();
  24. $script_started = getmicrotime();
  25. $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
  26. if (!$link) {
  27. if (DB_TYPE == "mysql") {
  28. print mysql_error();
  29. }
  30. // PG seems to display its own errors just fine by default.
  31. return;
  32. }
  33. init_connection($link);
  34. $subop = $_REQUEST["subop"];
  35. $mode = $_REQUEST["mode"];
  36. if ((!$op || $op == "rss" || $op == "dlg") && !$_REQUEST["noxml"]) {
  37. header("Content-Type: application/xml; charset=utf-8");
  38. } else {
  39. header("Content-Type: text/plain; charset=utf-8");
  40. }
  41. if (ENABLE_GZIP_OUTPUT) {
  42. ob_start("ob_gzhandler");
  43. }
  44. if (SINGLE_USER_MODE) {
  45. authenticate_user($link, "admin", null);
  46. }
  47. $public_calls = array("globalUpdateFeeds", "rss", "getUnread", "getProfiles", "share",
  48. "fbexport", "logout", "pubsub");
  49. if (array_search($op, $public_calls) !== false) {
  50. handle_public_request($link, $op);
  51. return;
  52. } else if (!($_SESSION["uid"] && validate_session($link))) {
  53. if ($op == 'pref-feeds' && $_REQUEST['subop'] == 'add') {
  54. header("Content-Type: text/html");
  55. login_sequence($link);
  56. render_login_form($link);
  57. } else {
  58. header("Content-Type: text/plain");
  59. print json_encode(array("error" => array("code" => 6)));
  60. }
  61. return;
  62. }
  63. $purge_intervals = array(
  64. 0 => __("Use default"),
  65. -1 => __("Never purge"),
  66. 5 => __("1 week old"),
  67. 14 => __("2 weeks old"),
  68. 31 => __("1 month old"),
  69. 60 => __("2 months old"),
  70. 90 => __("3 months old"));
  71. $update_intervals = array(
  72. 0 => __("Default interval"),
  73. -1 => __("Disable updates"),
  74. 15 => __("Each 15 minutes"),
  75. 30 => __("Each 30 minutes"),
  76. 60 => __("Hourly"),
  77. 240 => __("Each 4 hours"),
  78. 720 => __("Each 12 hours"),
  79. 1440 => __("Daily"),
  80. 10080 => __("Weekly"));
  81. $update_intervals_nodefault = array(
  82. -1 => __("Disable updates"),
  83. 15 => __("Each 15 minutes"),
  84. 30 => __("Each 30 minutes"),
  85. 60 => __("Hourly"),
  86. 240 => __("Each 4 hours"),
  87. 720 => __("Each 12 hours"),
  88. 1440 => __("Daily"),
  89. 10080 => __("Weekly"));
  90. $update_methods = array(
  91. 0 => __("Default"),
  92. 1 => __("Magpie"),
  93. 2 => __("SimplePie"),
  94. 3 => __("Twitter OAuth"));
  95. if (DEFAULT_UPDATE_METHOD == "1") {
  96. $update_methods[0] .= ' (SimplePie)';
  97. } else {
  98. $update_methods[0] .= ' (Magpie)';
  99. }
  100. $access_level_names = array(
  101. 0 => __("User"),
  102. 5 => __("Power User"),
  103. 10 => __("Administrator"));
  104. require_once "modules/pref-prefs.php";
  105. require_once "modules/popup-dialog.php";
  106. require_once "modules/help.php";
  107. require_once "modules/pref-feeds.php";
  108. require_once "modules/pref-filters.php";
  109. require_once "modules/pref-labels.php";
  110. require_once "modules/pref-users.php";
  111. require_once "modules/pref-instances.php";
  112. $error = sanity_check($link);
  113. if ($error['code'] != 0 && $op != "logout") {
  114. print json_encode(array("error" => $error));
  115. return;
  116. }
  117. switch($op) { // Select action according to $op value.
  118. case "rpc":
  119. // Handle remote procedure calls.
  120. handle_rpc_request($link);
  121. break; // rpc
  122. case "feeds":
  123. $subop = $_REQUEST["subop"];
  124. $root = (bool)$_REQUEST["root"];
  125. switch($subop) {
  126. case "catchupAll":
  127. db_query($link, "UPDATE ttrss_user_entries SET
  128. last_read = NOW(),unread = false WHERE owner_uid = " . $_SESSION["uid"]);
  129. ccache_zero_all($link, $_SESSION["uid"]);
  130. break;
  131. case "collapse":
  132. $cat_id = db_escape_string($_REQUEST["cid"]);
  133. $mode = (int) db_escape_string($_REQUEST['mode']);
  134. toggle_collapse_cat($link, $cat_id, $mode);
  135. return;
  136. break;
  137. }
  138. if (!$root) {
  139. print json_encode(outputFeedList($link));
  140. } else {
  141. $feeds = outputFeedList($link, false);
  142. $root = array();
  143. $root['id'] = 'root';
  144. $root['name'] = __('Feeds');
  145. $root['items'] = $feeds['items'];
  146. $fl = array();
  147. $fl['identifier'] = 'id';
  148. $fl['label'] = 'name';
  149. $fl['items'] = array($root);
  150. print json_encode($fl);
  151. }
  152. break; // feeds
  153. case "la":
  154. $id = db_escape_string($_REQUEST['id']);
  155. $result = db_query($link, "SELECT link FROM ttrss_entries, ttrss_user_entries
  156. WHERE id = '$id' AND id = ref_id AND owner_uid = '".$_SESSION['uid']."'
  157. LIMIT 1");
  158. if (db_num_rows($result) == 1) {
  159. $article_url = db_fetch_result($result, 0, 'link');
  160. $article_url = str_replace("\n", "", $article_url);
  161. header("Location: $article_url");
  162. return;
  163. } else {
  164. print_error(__("Article not found."));
  165. }
  166. break;
  167. case "view":
  168. $id = db_escape_string($_REQUEST["id"]);
  169. $cids = explode(",", db_escape_string($_REQUEST["cids"]));
  170. $mode = db_escape_string($_REQUEST["mode"]);
  171. $omode = db_escape_string($_REQUEST["omode"]);
  172. // in prefetch mode we only output requested cids, main article
  173. // just gets marked as read (it already exists in client cache)
  174. $articles = array();
  175. if ($mode == "") {
  176. array_push($articles, format_article($link, $id, false));
  177. } else if ($mode == "zoom") {
  178. array_push($articles, format_article($link, $id, true, true));
  179. } else if ($mode == "raw") {
  180. if ($_REQUEST['html']) {
  181. header("Content-Type: text/html");
  182. print '<link rel="stylesheet" type="text/css" href="tt-rss.css"/>';
  183. }
  184. $article = format_article($link, $id, false);
  185. print $article['content'];
  186. return;
  187. }
  188. catchupArticleById($link, $id, 0);
  189. if (!$_SESSION["bw_limit"]) {
  190. foreach ($cids as $cid) {
  191. if ($cid) {
  192. array_push($articles, format_article($link, $cid, false, false));
  193. }
  194. }
  195. }
  196. print json_encode($articles);
  197. break; // view
  198. case "viewfeed":
  199. $timing_info = getmicrotime();
  200. $reply = array();
  201. if ($_REQUEST["debug"]) $timing_info = print_checkpoint("0", $timing_info);
  202. $omode = db_escape_string($_REQUEST["omode"]);
  203. $feed = db_escape_string($_REQUEST["feed"]);
  204. $subop = db_escape_string($_REQUEST["subop"]);
  205. $view_mode = db_escape_string($_REQUEST["view_mode"]);
  206. $limit = (int) get_pref($link, "DEFAULT_ARTICLE_LIMIT");
  207. @$cat_view = db_escape_string($_REQUEST["cat"]) == "true";
  208. @$next_unread_feed = db_escape_string($_REQUEST["nuf"]);
  209. @$offset = db_escape_string($_REQUEST["skip"]);
  210. @$vgroup_last_feed = db_escape_string($_REQUEST["vgrlf"]);
  211. $order_by = db_escape_string($_REQUEST["order_by"]);
  212. if (is_numeric($feed)) $feed = (int) $feed;
  213. /* Feed -5 is a special case: it is used to display auxiliary information
  214. * when there's nothing to load - e.g. no stuff in fresh feed */
  215. if ($feed == -5) {
  216. print json_encode(generate_dashboard_feed($link));
  217. return;
  218. }
  219. $result = false;
  220. if ($feed < -10) {
  221. $label_feed = -11-$feed;
  222. $result = db_query($link, "SELECT id FROM ttrss_labels2 WHERE
  223. id = '$label_feed' AND owner_uid = " . $_SESSION['uid']);
  224. } else if (!$cat_view && is_numeric($feed) && $feed > 0) {
  225. $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE
  226. id = '$feed' AND owner_uid = " . $_SESSION['uid']);
  227. } else if ($cat_view && is_numeric($feed) && $feed > 0) {
  228. $result = db_query($link, "SELECT id FROM ttrss_feed_categories WHERE
  229. id = '$feed' AND owner_uid = " . $_SESSION['uid']);
  230. }
  231. if ($result && db_num_rows($result) == 0) {
  232. print json_encode(generate_error_feed($link, __("Feed not found.")));
  233. return;
  234. }
  235. /* Updating a label ccache means recalculating all of the caches
  236. * so for performance reasons we don't do that here */
  237. if ($feed >= 0) {
  238. ccache_update($link, $feed, $_SESSION["uid"], $cat_view);
  239. }
  240. set_pref($link, "_DEFAULT_VIEW_MODE", $view_mode);
  241. set_pref($link, "_DEFAULT_VIEW_LIMIT", $limit);
  242. set_pref($link, "_DEFAULT_VIEW_ORDER_BY", $order_by);
  243. if (!$cat_view && preg_match("/^[0-9][0-9]*$/", $feed)) {
  244. db_query($link, "UPDATE ttrss_feeds SET last_viewed = NOW()
  245. WHERE id = '$feed' AND owner_uid = ".$_SESSION["uid"]);
  246. }
  247. $reply['headlines'] = array();
  248. if (!$next_unread_feed)
  249. $reply['headlines']['id'] = $feed;
  250. else
  251. $reply['headlines']['id'] = $next_unread_feed;
  252. $reply['headlines']['is_cat'] = (bool) $cat_view;
  253. $override_order = false;
  254. if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) {
  255. $date_sort_field = "updated";
  256. } else {
  257. $date_sort_field = "date_entered";
  258. }
  259. switch ($order_by) {
  260. case "date":
  261. if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) {
  262. $override_order = "$date_sort_field";
  263. } else {
  264. $override_order = "$date_sort_field DESC";
  265. }
  266. break;
  267. case "title":
  268. if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) {
  269. $override_order = "title DESC, $date_sort_field";
  270. } else {
  271. $override_order = "title, $date_sort_field DESC";
  272. }
  273. break;
  274. case "score":
  275. if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) {
  276. $override_order = "score, $date_sort_field";
  277. } else {
  278. $override_order = "score DESC, $date_sort_field DESC";
  279. }
  280. break;
  281. }
  282. if ($_REQUEST["debug"]) $timing_info = print_checkpoint("04", $timing_info);
  283. $ret = format_headlines_list($link, $feed, $subop,
  284. $view_mode, $limit, $cat_view, $next_unread_feed, $offset,
  285. $vgroup_last_feed, $override_order);
  286. $topmost_article_ids = $ret[0];
  287. $headlines_count = $ret[1];
  288. $returned_feed = $ret[2];
  289. $disable_cache = $ret[3];
  290. $vgroup_last_feed = $ret[4];
  291. // if ($_REQUEST["debug"]) print_r($ret);
  292. $reply['headlines']['content'] =& $ret[5]['content'];
  293. $reply['headlines']['toolbar'] =& $ret[5]['toolbar'];
  294. if ($_REQUEST["debug"]) $timing_info = print_checkpoint("05", $timing_info);
  295. $reply['headlines-info'] = array("count" => (int) $headlines_count,
  296. "vgroup_last_feed" => $vgroup_last_feed,
  297. "disable_cache" => (bool) $disable_cache);
  298. if ($_REQUEST["debug"]) $timing_info = print_checkpoint("20", $timing_info);
  299. if (is_array($topmost_article_ids) && !get_pref($link, 'COMBINED_DISPLAY_MODE') && !$_SESSION["bw_limit"]) {
  300. $articles = array();
  301. foreach ($topmost_article_ids as $id) {
  302. array_push($articles, format_article($link, $id, false));
  303. }
  304. $reply['articles'] = $articles;
  305. }
  306. // if ($subop) {
  307. // $reply['counters'] = getAllCounters($link, $omode, $feed);
  308. // }
  309. if ($_REQUEST["debug"]) $timing_info = print_checkpoint("30", $timing_info);
  310. $reply['runtime-info'] = make_runtime_info($link);
  311. print json_encode($reply);
  312. break; // viewfeed
  313. case "pref-feeds":
  314. module_pref_feeds($link);
  315. break; // pref-feeds
  316. case "pref-filters":
  317. module_pref_filters($link);
  318. break; // pref-filters
  319. case "pref-labels":
  320. module_pref_labels($link);
  321. break; // pref-labels
  322. case "pref-prefs":
  323. module_pref_prefs($link);
  324. break; // pref-prefs
  325. case "pref-users":
  326. module_pref_users($link);
  327. break; // prefs-users
  328. case "help":
  329. module_help($link);
  330. break; // help
  331. case "dlg":
  332. module_popup_dialog($link);
  333. break; // dlg
  334. case "pref-pub-items":
  335. module_pref_pub_items($link);
  336. break; // pref-pub-items
  337. case "pref-feed-browser":
  338. module_pref_feed_browser($link);
  339. break; // pref-feed-browser
  340. case "pref-instances":
  341. module_pref_instances($link);
  342. break; // pref-instances
  343. case "digestTest":
  344. print_r(prepare_headlines_digest($link, $_SESSION["uid"]));
  345. break; // digestTest
  346. case "digestSend":
  347. send_headlines_digests($link);
  348. break; // digestSend
  349. case "loading":
  350. header("Content-type: text/html");
  351. print __("Loading, please wait...") . " " .
  352. "<img src='images/indicator_tiny.gif'>";
  353. break; // loading
  354. default:
  355. header("Content-Type: text/plain");
  356. print json_encode(array("error" => array("code" => 7)));
  357. break; // fallback
  358. } // Select action according to $op value.
  359. // We close the connection to database.
  360. db_close($link);
  361. ?>