PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/include/functions.php

https://github.com/krihal/Tiny-Tiny-RSS
PHP | 4073 lines | 3012 code | 886 blank | 175 comment | 748 complexity | 77e36cc88bc25237d05805388ee41014 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. define('EXPECTED_CONFIG_VERSION', 26);
  3. define('SCHEMA_VERSION', 106);
  4. $fetch_last_error = false;
  5. $pluginhost = false;
  6. function __autoload($class) {
  7. $class_file = str_replace("_", "/", strtolower(basename($class)));
  8. $file = dirname(__FILE__)."/../classes/$class_file.php";
  9. if (file_exists($file)) {
  10. require $file;
  11. }
  12. }
  13. mb_internal_encoding("UTF-8");
  14. date_default_timezone_set('UTC');
  15. if (defined('E_DEPRECATED')) {
  16. error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
  17. } else {
  18. error_reporting(E_ALL & ~E_NOTICE);
  19. }
  20. require_once 'config.php';
  21. if (DB_TYPE == "pgsql") {
  22. define('SUBSTRING_FOR_DATE', 'SUBSTRING_FOR_DATE');
  23. } else {
  24. define('SUBSTRING_FOR_DATE', 'SUBSTRING');
  25. }
  26. define('THEME_VERSION_REQUIRED', 1.1);
  27. /**
  28. * Return available translations names.
  29. *
  30. * @access public
  31. * @return array A array of available translations.
  32. */
  33. function get_translations() {
  34. $tr = array(
  35. "auto" => "Detect automatically",
  36. "ca_CA" => "Català",
  37. "en_US" => "English",
  38. "es_ES" => "Español",
  39. "de_DE" => "Deutsch",
  40. "fr_FR" => "Français",
  41. "hu_HU" => "Magyar (Hungarian)",
  42. "it_IT" => "Italiano",
  43. "ja_JP" => "日本語 (Japanese)",
  44. "lv_LV" => "Latviešu",
  45. "nb_NO" => "Norwegian bokmål",
  46. "pl_PL" => "Polski",
  47. "ru_RU" => "Русский",
  48. "pt_BR" => "Portuguese/Brazil",
  49. "zh_CN" => "Simplified Chinese");
  50. return $tr;
  51. }
  52. require_once "lib/accept-to-gettext.php";
  53. require_once "lib/gettext/gettext.inc";
  54. function startup_gettext() {
  55. # Get locale from Accept-Language header
  56. $lang = al2gt(array_keys(get_translations()), "text/html");
  57. if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
  58. $lang = _TRANSLATION_OVERRIDE_DEFAULT;
  59. }
  60. /* In login action of mobile version */
  61. if ($_POST["language"] && defined('MOBILE_VERSION')) {
  62. $lang = $_POST["language"];
  63. } else if ($_SESSION["language"] && $_SESSION["language"] != "auto") {
  64. $lang = $_SESSION["language"];
  65. }
  66. if ($lang) {
  67. if (defined('LC_MESSAGES')) {
  68. _setlocale(LC_MESSAGES, $lang);
  69. } else if (defined('LC_ALL')) {
  70. _setlocale(LC_ALL, $lang);
  71. }
  72. if (defined('MOBILE_VERSION')) {
  73. _bindtextdomain("messages", "../locale");
  74. } else {
  75. _bindtextdomain("messages", "locale");
  76. }
  77. _textdomain("messages");
  78. _bind_textdomain_codeset("messages", "UTF-8");
  79. }
  80. }
  81. startup_gettext();
  82. require_once 'db-prefs.php';
  83. require_once 'version.php';
  84. require_once 'ccache.php';
  85. require_once 'labels.php';
  86. define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . VERSION . ' (http://tt-rss.org/)');
  87. ini_set('user_agent', SELF_USER_AGENT);
  88. require_once 'lib/pubsubhubbub/publisher.php';
  89. $tz_offset = -1;
  90. $utc_tz = new DateTimeZone('UTC');
  91. $schema_version = false;
  92. /**
  93. * Print a timestamped debug message.
  94. *
  95. * @param string $msg The debug message.
  96. * @return void
  97. */
  98. function _debug($msg) {
  99. if (defined('QUIET') && QUIET) {
  100. return;
  101. }
  102. $ts = strftime("%H:%M:%S", time());
  103. if (function_exists('posix_getpid')) {
  104. $ts = "$ts/" . posix_getpid();
  105. }
  106. print "[$ts] $msg\n";
  107. } // function _debug
  108. /**
  109. * Purge a feed old posts.
  110. *
  111. * @param mixed $link A database connection.
  112. * @param mixed $feed_id The id of the purged feed.
  113. * @param mixed $purge_interval Olderness of purged posts.
  114. * @param boolean $debug Set to True to enable the debug. False by default.
  115. * @access public
  116. * @return void
  117. */
  118. function purge_feed($link, $feed_id, $purge_interval, $debug = false) {
  119. if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id);
  120. $rows = -1;
  121. $result = db_query($link,
  122. "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
  123. $owner_uid = false;
  124. if (db_num_rows($result) == 1) {
  125. $owner_uid = db_fetch_result($result, 0, "owner_uid");
  126. }
  127. if ($purge_interval == -1 || !$purge_interval) {
  128. if ($owner_uid) {
  129. ccache_update($link, $feed_id, $owner_uid);
  130. }
  131. return;
  132. }
  133. if (!$owner_uid) return;
  134. if (FORCE_ARTICLE_PURGE == 0) {
  135. $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES",
  136. $owner_uid, false);
  137. } else {
  138. $purge_unread = true;
  139. $purge_interval = FORCE_ARTICLE_PURGE;
  140. }
  141. if (!$purge_unread) $query_limit = " unread = false AND ";
  142. if (DB_TYPE == "pgsql") {
  143. $pg_version = get_pgsql_version($link);
  144. if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) {
  145. $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
  146. ttrss_entries.id = ref_id AND
  147. marked = false AND
  148. feed_id = '$feed_id' AND
  149. $query_limit
  150. ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
  151. } else {
  152. $result = db_query($link, "DELETE FROM ttrss_user_entries
  153. USING ttrss_entries
  154. WHERE ttrss_entries.id = ref_id AND
  155. marked = false AND
  156. feed_id = '$feed_id' AND
  157. $query_limit
  158. ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
  159. }
  160. $rows = pg_affected_rows($result);
  161. } else {
  162. /* $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
  163. marked = false AND feed_id = '$feed_id' AND
  164. (SELECT date_updated FROM ttrss_entries WHERE
  165. id = ref_id) < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); */
  166. $result = db_query($link, "DELETE FROM ttrss_user_entries
  167. USING ttrss_user_entries, ttrss_entries
  168. WHERE ttrss_entries.id = ref_id AND
  169. marked = false AND
  170. feed_id = '$feed_id' AND
  171. $query_limit
  172. ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)");
  173. $rows = mysql_affected_rows($link);
  174. }
  175. ccache_update($link, $feed_id, $owner_uid);
  176. if ($debug) {
  177. _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
  178. }
  179. return $rows;
  180. } // function purge_feed
  181. function feed_purge_interval($link, $feed_id) {
  182. $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds
  183. WHERE id = '$feed_id'");
  184. if (db_num_rows($result) == 1) {
  185. $purge_interval = db_fetch_result($result, 0, "purge_interval");
  186. $owner_uid = db_fetch_result($result, 0, "owner_uid");
  187. if ($purge_interval == 0) $purge_interval = get_pref($link,
  188. 'PURGE_OLD_DAYS', $owner_uid);
  189. return $purge_interval;
  190. } else {
  191. return -1;
  192. }
  193. }
  194. function purge_orphans($link, $do_output = false) {
  195. // purge orphaned posts in main content table
  196. $result = db_query($link, "DELETE FROM ttrss_entries WHERE
  197. (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
  198. if ($do_output) {
  199. $rows = db_affected_rows($link, $result);
  200. _debug("Purged $rows orphaned posts.");
  201. }
  202. }
  203. function get_feed_update_interval($link, $feed_id) {
  204. $result = db_query($link, "SELECT owner_uid, update_interval FROM
  205. ttrss_feeds WHERE id = '$feed_id'");
  206. if (db_num_rows($result) == 1) {
  207. $update_interval = db_fetch_result($result, 0, "update_interval");
  208. $owner_uid = db_fetch_result($result, 0, "owner_uid");
  209. if ($update_interval != 0) {
  210. return $update_interval;
  211. } else {
  212. return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
  213. }
  214. } else {
  215. return -1;
  216. }
  217. }
  218. function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false) {
  219. $login = urlencode($login);
  220. $pass = urlencode($pass);
  221. global $fetch_last_error;
  222. if (function_exists('curl_init') && !ini_get("open_basedir")) {
  223. if (ini_get("safe_mode")) {
  224. $ch = curl_init(geturl($url));
  225. } else {
  226. $ch = curl_init($url);
  227. }
  228. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15);
  229. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45);
  230. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode"));
  231. curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
  232. curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  233. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  234. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  235. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
  236. curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT);
  237. curl_setopt($ch, CURLOPT_ENCODING , "gzip");
  238. curl_setopt($ch, CURLOPT_REFERER, $url);
  239. if ($post_query) {
  240. curl_setopt($ch, CURLOPT_POST, true);
  241. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_query);
  242. }
  243. if ($login && $pass)
  244. curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
  245. $contents = @curl_exec($ch);
  246. if (curl_errno($ch) === 23 || curl_errno($ch) === 61) {
  247. curl_setopt($ch, CURLOPT_ENCODING, 'none');
  248. $contents = @curl_exec($ch);
  249. }
  250. if ($contents === false) {
  251. $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
  252. curl_close($ch);
  253. return false;
  254. }
  255. $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  256. $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
  257. if ($http_code != 200 || $type && strpos($content_type, "$type") === false) {
  258. if (curl_errno($ch) != 0) {
  259. $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
  260. } else {
  261. $fetch_last_error = "HTTP Code: $http_code";
  262. }
  263. curl_close($ch);
  264. return false;
  265. }
  266. curl_close($ch);
  267. return $contents;
  268. } else {
  269. if ($login && $pass ){
  270. $url_parts = array();
  271. preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts);
  272. if ($url_parts[1] && $url_parts[2]) {
  273. $url = $url_parts[1] . "://$login:$pass@" . $url_parts[2];
  274. }
  275. }
  276. $data = @file_get_contents($url);
  277. $gzdecoded = gzdecode($data);
  278. if ($gzdecoded) $data = $gzdecoded;
  279. if (!$data && function_exists('error_get_last')) {
  280. $error = error_get_last();
  281. $fetch_last_error = $error["message"];
  282. }
  283. return $data;
  284. }
  285. }
  286. /**
  287. * Try to determine the favicon URL for a feed.
  288. * adapted from wordpress favicon plugin by Jeff Minard (http://thecodepro.com/)
  289. * http://dev.wp-plugins.org/file/favatars/trunk/favatars.php
  290. *
  291. * @param string $url A feed or page URL
  292. * @access public
  293. * @return mixed The favicon URL, or false if none was found.
  294. */
  295. function get_favicon_url($url) {
  296. $favicon_url = false;
  297. if ($html = @fetch_file_contents($url)) {
  298. libxml_use_internal_errors(true);
  299. $doc = new DOMDocument();
  300. $doc->loadHTML($html);
  301. $xpath = new DOMXPath($doc);
  302. $base = $xpath->query('/html/head/base');
  303. foreach ($base as $b) {
  304. $url = $b->getAttribute("href");
  305. break;
  306. }
  307. $entries = $xpath->query('/html/head/link[@rel="shortcut icon" or @rel="icon"]');
  308. if (count($entries) > 0) {
  309. foreach ($entries as $entry) {
  310. $favicon_url = rewrite_relative_url($url, $entry->getAttribute("href"));
  311. break;
  312. }
  313. }
  314. }
  315. if (!$favicon_url)
  316. $favicon_url = rewrite_relative_url($url, "/favicon.ico");
  317. return $favicon_url;
  318. } // function get_favicon_url
  319. function check_feed_favicon($site_url, $feed, $link) {
  320. # print "FAVICON [$site_url]: $favicon_url\n";
  321. $icon_file = ICONS_DIR . "/$feed.ico";
  322. if (!file_exists($icon_file)) {
  323. $favicon_url = get_favicon_url($site_url);
  324. if ($favicon_url) {
  325. // Limiting to "image" type misses those served with text/plain
  326. $contents = fetch_file_contents($favicon_url); // , "image");
  327. if ($contents) {
  328. // Crude image type matching.
  329. // Patterns gleaned from the file(1) source code.
  330. if (preg_match('/^\x00\x00\x01\x00/', $contents)) {
  331. // 0 string \000\000\001\000 MS Windows icon resource
  332. //error_log("check_feed_favicon: favicon_url=$favicon_url isa MS Windows icon resource");
  333. }
  334. elseif (preg_match('/^GIF8/', $contents)) {
  335. // 0 string GIF8 GIF image data
  336. //error_log("check_feed_favicon: favicon_url=$favicon_url isa GIF image");
  337. }
  338. elseif (preg_match('/^\x89PNG\x0d\x0a\x1a\x0a/', $contents)) {
  339. // 0 string \x89PNG\x0d\x0a\x1a\x0a PNG image data
  340. //error_log("check_feed_favicon: favicon_url=$favicon_url isa PNG image");
  341. }
  342. elseif (preg_match('/^\xff\xd8/', $contents)) {
  343. // 0 beshort 0xffd8 JPEG image data
  344. //error_log("check_feed_favicon: favicon_url=$favicon_url isa JPG image");
  345. }
  346. else {
  347. //error_log("check_feed_favicon: favicon_url=$favicon_url isa UNKNOWN type");
  348. $contents = "";
  349. }
  350. }
  351. if ($contents) {
  352. $fp = @fopen($icon_file, "w");
  353. if ($fp) {
  354. fwrite($fp, $contents);
  355. fclose($fp);
  356. chmod($icon_file, 0644);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. function print_select($id, $default, $values, $attributes = "") {
  363. print "<select name=\"$id\" id=\"$id\" $attributes>";
  364. foreach ($values as $v) {
  365. if ($v == $default)
  366. $sel = "selected=\"1\"";
  367. else
  368. $sel = "";
  369. $v = trim($v);
  370. print "<option value=\"$v\" $sel>$v</option>";
  371. }
  372. print "</select>";
  373. }
  374. function print_select_hash($id, $default, $values, $attributes = "") {
  375. print "<select name=\"$id\" id='$id' $attributes>";
  376. foreach (array_keys($values) as $v) {
  377. if ($v == $default)
  378. $sel = 'selected="selected"';
  379. else
  380. $sel = "";
  381. $v = trim($v);
  382. print "<option $sel value=\"$v\">".$values[$v]."</option>";
  383. }
  384. print "</select>";
  385. }
  386. function print_radio($id, $default, $true_is, $values, $attributes = "") {
  387. foreach ($values as $v) {
  388. if ($v == $default)
  389. $sel = "checked";
  390. else
  391. $sel = "";
  392. if ($v == $true_is) {
  393. $sel .= " value=\"1\"";
  394. } else {
  395. $sel .= " value=\"0\"";
  396. }
  397. print "<input class=\"noborder\" dojoType=\"dijit.form.RadioButton\"
  398. type=\"radio\" $sel $attributes name=\"$id\">&nbsp;$v&nbsp;";
  399. }
  400. }
  401. function initialize_user_prefs($link, $uid, $profile = false) {
  402. $uid = db_escape_string($uid);
  403. if (!$profile) {
  404. $profile = "NULL";
  405. $profile_qpart = "AND profile IS NULL";
  406. } else {
  407. $profile_qpart = "AND profile = '$profile'";
  408. }
  409. if (get_schema_version($link) < 63) $profile_qpart = "";
  410. db_query($link, "BEGIN");
  411. $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs");
  412. $u_result = db_query($link, "SELECT pref_name
  413. FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart");
  414. $active_prefs = array();
  415. while ($line = db_fetch_assoc($u_result)) {
  416. array_push($active_prefs, $line["pref_name"]);
  417. }
  418. while ($line = db_fetch_assoc($result)) {
  419. if (array_search($line["pref_name"], $active_prefs) === FALSE) {
  420. // print "adding " . $line["pref_name"] . "<br>";
  421. if (get_schema_version($link) < 63) {
  422. db_query($link, "INSERT INTO ttrss_user_prefs
  423. (owner_uid,pref_name,value) VALUES
  424. ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')");
  425. } else {
  426. db_query($link, "INSERT INTO ttrss_user_prefs
  427. (owner_uid,pref_name,value, profile) VALUES
  428. ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)");
  429. }
  430. }
  431. }
  432. db_query($link, "COMMIT");
  433. }
  434. function get_ssl_certificate_id() {
  435. if ($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"]) {
  436. return sha1($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"] .
  437. $_SERVER["REDIRECT_SSL_CLIENT_V_START"] .
  438. $_SERVER["REDIRECT_SSL_CLIENT_V_END"] .
  439. $_SERVER["REDIRECT_SSL_CLIENT_S_DN"]);
  440. }
  441. return "";
  442. }
  443. function authenticate_user($link, $login, $password, $check_only = false) {
  444. if (!SINGLE_USER_MODE) {
  445. $user_id = false;
  446. global $pluginhost;
  447. foreach ($pluginhost->get_hooks($pluginhost::HOOK_AUTH_USER) as $plugin) {
  448. $user_id = (int) $plugin->authenticate($login, $password);
  449. if ($user_id) {
  450. $_SESSION["auth_module"] = strtolower(get_class($plugin));
  451. break;
  452. }
  453. }
  454. if ($user_id && !$check_only) {
  455. $_SESSION["uid"] = $user_id;
  456. $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users
  457. WHERE id = '$user_id'");
  458. $_SESSION["name"] = db_fetch_result($result, 0, "login");
  459. $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
  460. $_SESSION["csrf_token"] = sha1(uniqid(rand(), true));
  461. db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
  462. $_SESSION["uid"]);
  463. $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
  464. $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash");
  465. $_SESSION["last_version_check"] = time();
  466. initialize_user_prefs($link, $_SESSION["uid"]);
  467. return true;
  468. }
  469. return false;
  470. } else {
  471. $_SESSION["uid"] = 1;
  472. $_SESSION["name"] = "admin";
  473. $_SESSION["access_level"] = 10;
  474. $_SESSION["hide_hello"] = true;
  475. $_SESSION["hide_logout"] = true;
  476. $_SESSION["auth_module"] = false;
  477. if (!$_SESSION["csrf_token"]) {
  478. $_SESSION["csrf_token"] = sha1(uniqid(rand(), true));
  479. }
  480. $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
  481. initialize_user_prefs($link, $_SESSION["uid"]);
  482. return true;
  483. }
  484. }
  485. function make_password($length = 8) {
  486. $password = "";
  487. $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ";
  488. $i = 0;
  489. while ($i < $length) {
  490. $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
  491. if (!strstr($password, $char)) {
  492. $password .= $char;
  493. $i++;
  494. }
  495. }
  496. return $password;
  497. }
  498. // this is called after user is created to initialize default feeds, labels
  499. // or whatever else
  500. // user preferences are checked on every login, not here
  501. function initialize_user($link, $uid) {
  502. db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url)
  503. values ('$uid', 'Tiny Tiny RSS: New Releases',
  504. 'http://tt-rss.org/releases.rss')");
  505. db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url)
  506. values ('$uid', 'Tiny Tiny RSS: Forum',
  507. 'http://tt-rss.org/forum/rss.php')");
  508. }
  509. function logout_user() {
  510. session_destroy();
  511. if (isset($_COOKIE[session_name()])) {
  512. setcookie(session_name(), '', time()-42000, '/');
  513. }
  514. }
  515. function validate_csrf($csrf_token) {
  516. return $csrf_token == $_SESSION['csrf_token'];
  517. }
  518. function validate_session($link) {
  519. if (SINGLE_USER_MODE) return true;
  520. $check_ip = $_SESSION['ip_address'];
  521. switch (SESSION_CHECK_ADDRESS) {
  522. case 0:
  523. $check_ip = '';
  524. break;
  525. case 1:
  526. $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1);
  527. break;
  528. case 2:
  529. $check_ip = substr($check_ip, 0, strrpos($check_ip, '.'));
  530. $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1);
  531. break;
  532. };
  533. if ($check_ip && strpos($_SERVER['REMOTE_ADDR'], $check_ip) !== 0) {
  534. $_SESSION["login_error_msg"] =
  535. __("Session failed to validate (incorrect IP)");
  536. return false;
  537. }
  538. if ($_SESSION["ref_schema_version"] != get_schema_version($link, true))
  539. return false;
  540. if ($_SESSION["uid"]) {
  541. $result = db_query($link,
  542. "SELECT pwd_hash FROM ttrss_users WHERE id = '".$_SESSION["uid"]."'");
  543. $pwd_hash = db_fetch_result($result, 0, "pwd_hash");
  544. if ($pwd_hash != $_SESSION["pwd_hash"]) {
  545. return false;
  546. }
  547. }
  548. /* if ($_SESSION["cookie_lifetime"] && $_SESSION["uid"]) {
  549. //print_r($_SESSION);
  550. if (time() > $_SESSION["cookie_lifetime"]) {
  551. return false;
  552. }
  553. } */
  554. return true;
  555. }
  556. function load_user_plugins($link, $owner_uid) {
  557. if ($owner_uid) {
  558. $plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid);
  559. global $pluginhost;
  560. $pluginhost->load($plugins, $pluginhost::KIND_USER, $owner_uid);
  561. if (get_schema_version($link) > 100) {
  562. $pluginhost->load_data();
  563. }
  564. }
  565. }
  566. function login_sequence($link, $login_form = 0) {
  567. $_SESSION["prefs_cache"] = false;
  568. if (SINGLE_USER_MODE) {
  569. authenticate_user($link, "admin", null);
  570. cache_prefs($link);
  571. load_user_plugins($link, $_SESSION["uid"]);
  572. } else {
  573. if (!$_SESSION["uid"] || !validate_session($link)) {
  574. if (AUTH_AUTO_LOGIN && authenticate_user($link, null, null)) {
  575. $_SESSION["ref_schema_version"] = get_schema_version($link, true);
  576. } else {
  577. authenticate_user($link, null, null, true);
  578. }
  579. if (!$_SESSION["uid"]) render_login_form($link, $login_form);
  580. } else {
  581. /* bump login timestamp */
  582. db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
  583. $_SESSION["uid"]);
  584. }
  585. if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) {
  586. setcookie("ttrss_lang", $_SESSION["language"],
  587. time() + SESSION_COOKIE_LIFETIME);
  588. }
  589. if ($_SESSION["uid"]) {
  590. cache_prefs($link);
  591. load_user_plugins($link, $_SESSION["uid"]);
  592. }
  593. }
  594. }
  595. function truncate_string($str, $max_len, $suffix = '&hellip;') {
  596. if (mb_strlen($str, "utf-8") > $max_len - 3) {
  597. return mb_substr($str, 0, $max_len, "utf-8") . $suffix;
  598. } else {
  599. return $str;
  600. }
  601. }
  602. // Deprecated, TODO: remove
  603. function theme_image($link, $filename) {
  604. return $filename;
  605. }
  606. function convert_timestamp($timestamp, $source_tz, $dest_tz) {
  607. try {
  608. $source_tz = new DateTimeZone($source_tz);
  609. } catch (Exception $e) {
  610. $source_tz = new DateTimeZone('UTC');
  611. }
  612. try {
  613. $dest_tz = new DateTimeZone($dest_tz);
  614. } catch (Exception $e) {
  615. $dest_tz = new DateTimeZone('UTC');
  616. }
  617. $dt = new DateTime(date('Y-m-d H:i:s', $timestamp), $source_tz);
  618. return $dt->format('U') + $dest_tz->getOffset($dt);
  619. }
  620. function make_local_datetime($link, $timestamp, $long, $owner_uid = false,
  621. $no_smart_dt = false) {
  622. if (!$owner_uid) $owner_uid = $_SESSION['uid'];
  623. if (!$timestamp) $timestamp = '1970-01-01 0:00';
  624. global $utc_tz;
  625. global $tz_offset;
  626. # We store date in UTC internally
  627. $dt = new DateTime($timestamp, $utc_tz);
  628. if ($tz_offset == -1) {
  629. $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid);
  630. try {
  631. $user_tz = new DateTimeZone($user_tz_string);
  632. } catch (Exception $e) {
  633. $user_tz = $utc_tz;
  634. }
  635. $tz_offset = $user_tz->getOffset($dt);
  636. }
  637. $user_timestamp = $dt->format('U') + $tz_offset;
  638. if (!$no_smart_dt) {
  639. return smart_date_time($link, $user_timestamp,
  640. $tz_offset, $owner_uid);
  641. } else {
  642. if ($long)
  643. $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
  644. else
  645. $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
  646. return date($format, $user_timestamp);
  647. }
  648. }
  649. function smart_date_time($link, $timestamp, $tz_offset = 0, $owner_uid = false) {
  650. if (!$owner_uid) $owner_uid = $_SESSION['uid'];
  651. if (date("Y.m.d", $timestamp) == date("Y.m.d", time() + $tz_offset)) {
  652. return date("G:i", $timestamp);
  653. } else if (date("Y", $timestamp) == date("Y", time() + $tz_offset)) {
  654. $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
  655. return date($format, $timestamp);
  656. } else {
  657. $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
  658. return date($format, $timestamp);
  659. }
  660. }
  661. function sql_bool_to_bool($s) {
  662. if ($s == "t" || $s == "1" || strtolower($s) == "true") {
  663. return true;
  664. } else {
  665. return false;
  666. }
  667. }
  668. function bool_to_sql_bool($s) {
  669. if ($s) {
  670. return "true";
  671. } else {
  672. return "false";
  673. }
  674. }
  675. // Session caching removed due to causing wrong redirects to upgrade
  676. // script when get_schema_version() is called on an obsolete session
  677. // created on a previous schema version.
  678. function get_schema_version($link, $nocache = false) {
  679. global $schema_version;
  680. if (!$schema_version) {
  681. $result = db_query($link, "SELECT schema_version FROM ttrss_version");
  682. $version = db_fetch_result($result, 0, "schema_version");
  683. $schema_version = $version;
  684. return $version;
  685. } else {
  686. return $schema_version;
  687. }
  688. }
  689. function sanity_check($link) {
  690. require_once 'errors.php';
  691. $error_code = 0;
  692. $schema_version = get_schema_version($link, true);
  693. if ($schema_version != SCHEMA_VERSION) {
  694. $error_code = 5;
  695. }
  696. if (DB_TYPE == "mysql") {
  697. $result = db_query($link, "SELECT true", false);
  698. if (db_num_rows($result) != 1) {
  699. $error_code = 10;
  700. }
  701. }
  702. if (db_escape_string("testTEST") != "testTEST") {
  703. $error_code = 12;
  704. }
  705. return array("code" => $error_code, "message" => $ERRORS[$error_code]);
  706. }
  707. function file_is_locked($filename) {
  708. if (function_exists('flock')) {
  709. $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
  710. if ($fp) {
  711. if (flock($fp, LOCK_EX | LOCK_NB)) {
  712. flock($fp, LOCK_UN);
  713. fclose($fp);
  714. return false;
  715. }
  716. fclose($fp);
  717. return true;
  718. } else {
  719. return false;
  720. }
  721. }
  722. return true; // consider the file always locked and skip the test
  723. }
  724. function make_lockfile($filename) {
  725. $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
  726. if ($fp && flock($fp, LOCK_EX | LOCK_NB)) {
  727. if (function_exists('posix_getpid')) {
  728. fwrite($fp, posix_getpid() . "\n");
  729. }
  730. return $fp;
  731. } else {
  732. return false;
  733. }
  734. }
  735. function make_stampfile($filename) {
  736. $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
  737. if (flock($fp, LOCK_EX | LOCK_NB)) {
  738. fwrite($fp, time() . "\n");
  739. flock($fp, LOCK_UN);
  740. fclose($fp);
  741. return true;
  742. } else {
  743. return false;
  744. }
  745. }
  746. function sql_random_function() {
  747. if (DB_TYPE == "mysql") {
  748. return "RAND()";
  749. } else {
  750. return "RANDOM()";
  751. }
  752. }
  753. function catchup_feed($link, $feed, $cat_view, $owner_uid = false, $max_id = false) {
  754. if (!$owner_uid) $owner_uid = $_SESSION['uid'];
  755. //if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
  756. $ref_check_qpart = ($max_id &&
  757. !get_pref($link, 'REVERSE_HEADLINES')) ? "ref_id <= '$max_id'" : "true";
  758. if (is_numeric($feed)) {
  759. if ($cat_view) {
  760. if ($feed >= 0) {
  761. if ($feed > 0) {
  762. $children = getChildCategories($link, $feed, $owner_uid);
  763. array_push($children, $feed);
  764. $children = join(",", $children);
  765. $cat_qpart = "cat_id IN ($children)";
  766. } else {
  767. $cat_qpart = "cat_id IS NULL";
  768. }
  769. db_query($link, "UPDATE ttrss_user_entries
  770. SET unread = false,last_read = NOW()
  771. WHERE feed_id IN (SELECT id FROM ttrss_feeds WHERE $cat_qpart)
  772. AND $ref_check_qpart AND unread = true
  773. AND owner_uid = $owner_uid");
  774. } else if ($feed == -2) {
  775. db_query($link, "UPDATE ttrss_user_entries
  776. SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
  777. FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0
  778. AND $ref_check_qpart
  779. AND unread = true AND owner_uid = $owner_uid");
  780. }
  781. } else if ($feed > 0) {
  782. db_query($link, "UPDATE ttrss_user_entries
  783. SET unread = false,last_read = NOW()
  784. WHERE feed_id = '$feed'
  785. AND $ref_check_qpart AND unread = true
  786. AND owner_uid = $owner_uid");
  787. } else if ($feed < 0 && $feed > -10) { // special, like starred
  788. if ($feed == -1) {
  789. db_query($link, "UPDATE ttrss_user_entries
  790. SET unread = false,last_read = NOW()
  791. WHERE marked = true
  792. AND $ref_check_qpart AND unread = true
  793. AND owner_uid = $owner_uid");
  794. }
  795. if ($feed == -2) {
  796. db_query($link, "UPDATE ttrss_user_entries
  797. SET unread = false,last_read = NOW()
  798. WHERE published = true
  799. AND $ref_check_qpart AND unread = true
  800. AND owner_uid = $owner_uid");
  801. }
  802. if ($feed == -3) {
  803. $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE");
  804. if (DB_TYPE == "pgsql") {
  805. $match_part = "updated > NOW() - INTERVAL '$intl hour' ";
  806. } else {
  807. $match_part = "updated > DATE_SUB(NOW(),
  808. INTERVAL $intl HOUR) ";
  809. }
  810. $result = db_query($link, "SELECT id FROM ttrss_entries,
  811. ttrss_user_entries WHERE $match_part AND
  812. unread = true AND
  813. ttrss_user_entries.ref_id = ttrss_entries.id AND
  814. owner_uid = $owner_uid");
  815. $affected_ids = array();
  816. while ($line = db_fetch_assoc($result)) {
  817. array_push($affected_ids, $line["id"]);
  818. }
  819. catchupArticlesById($link, $affected_ids, 0);
  820. }
  821. if ($feed == -4) {
  822. db_query($link, "UPDATE ttrss_user_entries
  823. SET unread = false,last_read = NOW()
  824. WHERE $ref_check_qpart AND unread = true AND
  825. owner_uid = $owner_uid");
  826. }
  827. } else if ($feed < -10) { // label
  828. $label_id = -$feed - 11;
  829. db_query($link, "UPDATE ttrss_user_entries, ttrss_user_labels2
  830. SET unread = false, last_read = NOW()
  831. WHERE label_id = '$label_id' AND unread = true
  832. AND $ref_check_qpart
  833. AND owner_uid = '$owner_uid' AND ref_id = article_id");
  834. }
  835. ccache_update($link, $feed, $owner_uid, $cat_view);
  836. } else { // tag
  837. db_query($link, "BEGIN");
  838. $tag_name = db_escape_string($feed);
  839. $result = db_query($link, "SELECT post_int_id FROM ttrss_tags
  840. WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid");
  841. while ($line = db_fetch_assoc($result)) {
  842. db_query($link, "UPDATE ttrss_user_entries SET
  843. unread = false, last_read = NOW()
  844. WHERE $ref_check_qpart AND unread = true
  845. AND int_id = " . $line["post_int_id"]);
  846. }
  847. db_query($link, "COMMIT");
  848. }
  849. }
  850. function getAllCounters($link) {
  851. $data = getGlobalCounters($link);
  852. $data = array_merge($data, getVirtCounters($link));
  853. $data = array_merge($data, getLabelCounters($link));
  854. $data = array_merge($data, getFeedCounters($link, $active_feed));
  855. $data = array_merge($data, getCategoryCounters($link));
  856. return $data;
  857. }
  858. function getCategoryTitle($link, $cat_id) {
  859. if ($cat_id == -1) {
  860. return __("Special");
  861. } else if ($cat_id == -2) {
  862. return __("Labels");
  863. } else {
  864. $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE
  865. id = '$cat_id'");
  866. if (db_num_rows($result) == 1) {
  867. return db_fetch_result($result, 0, "title");
  868. } else {
  869. return __("Uncategorized");
  870. }
  871. }
  872. }
  873. function getCategoryCounters($link) {
  874. $ret_arr = array();
  875. /* Labels category */
  876. $cv = array("id" => -2, "kind" => "cat",
  877. "counter" => getCategoryUnread($link, -2));
  878. array_push($ret_arr, $cv);
  879. $result = db_query($link, "SELECT id AS cat_id, value AS unread,
  880. (SELECT COUNT(id) FROM ttrss_feed_categories AS c2
  881. WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children
  882. FROM ttrss_feed_categories, ttrss_cat_counters_cache
  883. WHERE ttrss_cat_counters_cache.feed_id = id AND
  884. ttrss_cat_counters_cache.owner_uid = ttrss_feed_categories.owner_uid AND
  885. ttrss_feed_categories.owner_uid = " . $_SESSION["uid"]);
  886. while ($line = db_fetch_assoc($result)) {
  887. $line["cat_id"] = (int) $line["cat_id"];
  888. if ($line["num_children"] > 0) {
  889. $child_counter = getCategoryChildrenUnread($link, $line["cat_id"], $_SESSION["uid"]);
  890. } else {
  891. $child_counter = 0;
  892. }
  893. $cv = array("id" => $line["cat_id"], "kind" => "cat",
  894. "counter" => $line["unread"] + $child_counter);
  895. array_push($ret_arr, $cv);
  896. }
  897. /* Special case: NULL category doesn't actually exist in the DB */
  898. $cv = array("id" => 0, "kind" => "cat",
  899. "counter" => (int) ccache_find($link, 0, $_SESSION["uid"], true));
  900. array_push($ret_arr, $cv);
  901. return $ret_arr;
  902. }
  903. // only accepts real cats (>= 0)
  904. function getCategoryChildrenUnread($link, $cat, $owner_uid = false) {
  905. if (!$owner_uid) $owner_uid = $_SESSION["uid"];
  906. $result = db_query($link, "SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat'
  907. AND owner_uid = $owner_uid");
  908. $unread = 0;
  909. while ($line = db_fetch_assoc($result)) {
  910. $unread += getCategoryUnread($link, $line["id"], $owner_uid);
  911. $unread += getCategoryChildrenUnread($link, $line["id"], $owner_uid);
  912. }
  913. return $unread;
  914. }
  915. function getCategoryUnread($link, $cat, $owner_uid = false) {
  916. if (!$owner_uid) $owner_uid = $_SESSION["uid"];
  917. if ($cat >= 0) {
  918. if ($cat != 0) {
  919. $cat_query = "cat_id = '$cat'";
  920. } else {
  921. $cat_query = "cat_id IS NULL";
  922. }
  923. $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query
  924. AND owner_uid = " . $owner_uid);
  925. $cat_feeds = array();
  926. while ($line = db_fetch_assoc($result)) {
  927. array_push($cat_feeds, "feed_id = " . $line["id"]);
  928. }
  929. if (count($cat_feeds) == 0) return 0;
  930. $match_part = implode(" OR ", $cat_feeds);
  931. $result = db_query($link, "SELECT COUNT(int_id) AS unread
  932. FROM ttrss_user_entries
  933. WHERE unread = true AND ($match_part)
  934. AND owner_uid = " . $owner_uid);
  935. $unread = 0;
  936. # this needs to be rewritten
  937. while ($line = db_fetch_assoc($result)) {
  938. $unread += $line["unread"];
  939. }
  940. return $unread;
  941. } else if ($cat == -1) {
  942. return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0);
  943. } else if ($cat == -2) {
  944. $result = db_query($link, "
  945. SELECT COUNT(unread) AS unread FROM
  946. ttrss_user_entries, ttrss_user_labels2
  947. WHERE article_id = ref_id AND unread = true
  948. AND ttrss_user_entries.owner_uid = '$owner_uid'");
  949. $unread = db_fetch_result($result, 0, "unread");
  950. return $unread;
  951. }
  952. }
  953. function getFeedUnread($link, $feed, $is_cat = false) {
  954. return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]);
  955. }
  956. function getLabelUnread($link, $label_id, $owner_uid = false) {
  957. if (!$owner_uid) $owner_uid = $_SESSION["uid"];
  958. $result = db_query($link, "SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2
  959. WHERE owner_uid = '$owner_uid' AND unread = true AND label_id = '$label_id' AND article_id = ref_id");
  960. if (db_num_rows($result) != 0) {
  961. return db_fetch_result($result, 0, "unread");
  962. } else {
  963. return 0;
  964. }
  965. }
  966. function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false,
  967. $owner_uid = false) {
  968. $n_feed = (int) $feed;
  969. $need_entries = false;
  970. if (!$owner_uid) $owner_uid = $_SESSION["uid"];
  971. if ($unread_only) {
  972. $unread_qpart = "unread = true";
  973. } else {
  974. $unread_qpart = "true";
  975. }
  976. if ($is_cat) {
  977. return getCategoryUnread($link, $n_feed, $owner_uid);
  978. } else if ($n_feed == -6) {
  979. return 0;
  980. } else if ($feed != "0" && $n_feed == 0) {
  981. $feed = db_escape_string($feed);
  982. $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id)
  983. FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
  984. AND ref_id = id AND $unread_qpart)) AS count FROM ttrss_tags
  985. WHERE owner_uid = $owner_uid AND tag_name = '$feed'");
  986. return db_fetch_result($result, 0, "count");
  987. } else if ($n_feed == -1) {
  988. $match_part = "marked = true";
  989. } else if ($n_feed == -2) {
  990. $match_part = "published = true";
  991. } else if ($n_feed == -3) {
  992. $match_part = "unread = true AND score >= 0";
  993. $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
  994. if (DB_TYPE == "pgsql") {
  995. $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
  996. } else {
  997. $match_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
  998. }
  999. $need_entries = true;
  1000. } else if ($n_feed == -4) {
  1001. $match_part = "true";
  1002. } else if ($n_feed >= 0) {
  1003. if ($n_feed != 0) {
  1004. $match_part = "feed_id = '$n_feed'";
  1005. } else {
  1006. $match_part = "feed_id IS NULL";
  1007. }
  1008. } else if ($feed < -10) {
  1009. $label_id = -$feed - 11;
  1010. return getLabelUnread($link, $label_id, $owner_uid);
  1011. }
  1012. if ($match_part) {
  1013. if ($need_entries) {
  1014. $from_qpart = "ttrss_user_entries,ttrss_entries";
  1015. $from_where = "ttrss_entries.id = ttrss_user_entries.ref_id AND";
  1016. } else {
  1017. $from_qpart = "ttrss_user_entries";
  1018. }
  1019. $query = "SELECT count(int_id) AS unread
  1020. FROM $from_qpart WHERE
  1021. $unread_qpart AND $from_where ($match_part) AND ttrss_user_entries.owner_uid = $owner_uid";
  1022. //echo "[$feed/$query]\n";
  1023. $result = db_query($link, $query);
  1024. } else {
  1025. $result = db_query($link, "SELECT COUNT(post_int_id) AS unread
  1026. FROM ttrss_tags,ttrss_user_entries,ttrss_entries
  1027. WHERE tag_name = '$feed' AND post_int_id = int_id AND ref_id = ttrss_entries.id
  1028. AND $unread_qpart AND ttrss_tags.owner_uid = " . $owner_uid);
  1029. }
  1030. $unread = db_fetch_result($result, 0, "unread");
  1031. return $unread;
  1032. }
  1033. function getGlobalUnread($link, $user_id = false) {
  1034. if (!$user_id) {
  1035. $user_id = $_SESSION["uid"];
  1036. }
  1037. $result = db_query($link, "SELECT SUM(value) AS c_id FROM ttrss_counters_cache
  1038. WHERE owner_uid = '$user_id' AND feed_id > 0");
  1039. $c_id = db_fetch_result($result, 0, "c_id");
  1040. return $c_id;
  1041. }
  1042. function getGlobalCounters($link, $global_unread = -1) {
  1043. $ret_arr = array();
  1044. if ($global_unread == -1) {
  1045. $global_unread = getGlobalUnread($link);
  1046. }
  1047. $cv = array("id" => "global-unread",
  1048. "counter" => (int) $global_unread);
  1049. array_push($ret_arr, $cv);
  1050. $result = db_query($link, "SELECT COUNT(id) AS fn FROM
  1051. ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
  1052. $subscribed_feeds = db_fetch_result($result, 0, "fn");
  1053. $cv = array("id" => "subscribed-feeds",
  1054. "counter" => (int) $subscribed_feeds);
  1055. array_push($ret_arr, $cv);
  1056. return $ret_arr;
  1057. }
  1058. function getVirtCounters($link) {
  1059. $ret_arr = array();
  1060. for ($i = 0; $i >= -4; $i--) {
  1061. $count = getFeedUnread($link, $i);
  1062. $cv = array("id" => $i,
  1063. "counter" => (int) $count);
  1064. // if (get_pref($link, 'EXTENDED_FEEDLIST'))
  1065. // $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total");
  1066. array_push($ret_arr, $cv);
  1067. }
  1068. return $ret_arr;
  1069. }
  1070. function getLabelCounters($link, $descriptions = false) {
  1071. $ret_arr = array();
  1072. $owner_uid = $_SESSION["uid"];
  1073. $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread
  1074. FROM ttrss_labels2 LEFT JOIN ttrss_user_labels2 ON
  1075. (ttrss_labels2.id = label_id)
  1076. LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true)
  1077. WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id,
  1078. ttrss_labels2.caption");
  1079. while ($line = db_fetch_assoc($result)) {
  1080. $id = -$line["id"] - 11;
  1081. $label_name = $line["caption"];
  1082. $count = $line["unread"];
  1083. $cv = array("id" => $id,
  1084. "counter" => (int) $count);
  1085. if ($descriptions)
  1086. $cv["description"] = $label_name;
  1087. // if (get_pref($link, 'EXTENDED_FEEDLIST'))
  1088. // $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
  1089. array_push($ret_arr, $cv);
  1090. }
  1091. return $ret_arr;
  1092. }
  1093. function getFeedCounters($link, $active_feed = false) {
  1094. $ret_arr = array();
  1095. $query = "SELECT ttrss_feeds.id,
  1096. ttrss_feeds.title,
  1097. ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
  1098. last_error, value AS count
  1099. FROM ttrss_feeds, ttrss_counters_cache
  1100. WHERE ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
  1101. AND ttrss_counters_cache.owner_uid = ttrss_feeds.owner_uid
  1102. AND ttrss_counters_cache.feed_id = id";
  1103. $result = db_query($link, $query);
  1104. $fctrs_modified = false;
  1105. while ($line = db_fetch_assoc($result)) {
  1106. $id = $line["id"];
  1107. $count = $line["count"];
  1108. $last_error = htmlspecialchars($line["last_error"]);
  1109. $last_updated = make_local_datetime($link, $line['last_updated'], false);
  1110. $has_img = feed_has_icon($id);
  1111. if (date('Y') - date('Y', strtotime($line['last_updated'])) > 2)
  1112. $last_updated = '';
  1113. $cv = array("id" => $id,
  1114. "updated" => $last_updated,
  1115. "counter" => (int) $count,
  1116. "has_img" => (int) $has_img);
  1117. if ($last_error)
  1118. $cv["error"] = $last_error;
  1119. // if (get_pref($link, 'EXTENDED_FEEDLIST'))
  1120. // $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
  1121. if ($active_feed && $id == $active_feed)
  1122. $cv["title"] = truncate_string($line["title"], 30);
  1123. array_push($ret_arr, $cv);
  1124. }
  1125. return $ret_arr;
  1126. }
  1127. function get_pgsql_version($link) {
  1128. $result = db_query($link, "SELECT version() AS version");
  1129. $version = explode(" ", db_fetch_result($result, 0, "version"));
  1130. return $version[1];
  1131. }
  1132. /**
  1133. * @return array (code => Status code, message => error message if available)
  1134. *
  1135. * 0 - OK, Feed already exists
  1136. * 1 - OK, Feed added
  1137. * 2 - Invalid URL
  1138. * 3 - URL content is HTML, no feeds available
  1139. * 4 - URL content is HTML which contains multiple feeds.
  1140. * Here you should call extractfeedurls in rpc-backend
  1141. * to get all possible feeds.
  1142. * 5 - Couldn't download the URL content.
  1143. */
  1144. function subscribe_to_feed($link, $url, $cat_id = 0,
  1145. $auth_login = '', $auth_pass = '', $need_auth = false) {
  1146. global $fetch_last_error;
  1147. require_once "include/rssfuncs.php";
  1148. $url = fix_url($url);
  1149. if (!$url || !validate_feed_url($url)) return array("code" => 2);
  1150. $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass);
  1151. if (!$contents) {
  1152. return array("code" => 5, "message" => $fetch_last_error);
  1153. }
  1154. if (is_html($contents)) {
  1155. $feedUrls = get_feeds_from_html($url, $contents);
  1156. if (count($feedUrls) == 0) {
  1157. return array("code" => 3);
  1158. } else if (count($feedUrls) > 1) {
  1159. return array("code" => 4, "feeds" => $feedUrls);
  1160. }
  1161. //use feed url as new URL
  1162. $url = key($feedUrls);
  1163. }
  1164. if ($cat_id == "0" || !$cat_id) {
  1165. $cat_qpart = "NULL";
  1166. } else {
  1167. $cat_qpart = "'$cat_id'";
  1168. }
  1169. $result = db_query($link,
  1170. "SELECT id FROM ttrss_feeds
  1171. WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]);
  1172. if (db_num_rows($result) == 0) {
  1173. $result = db_query($link,
  1174. "INSERT INTO ttrss_feeds
  1175. (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method)
  1176. VALUES ('".$_SESSION["uid"]."', '$url',
  1177. '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0)");
  1178. $result = db_query($link,
  1179. "SELECT id FROM ttrss_feeds WHERE feed_url = '$url'
  1180. AND owner_uid = " . $_SESSION["uid"]);
  1181. $feed_id = db_fetch_result($result, 0, "id");
  1182. if ($feed_id) {
  1183. update_rss_feed($link, $feed_id, true);
  1184. }
  1185. return array("code" => 1);
  1186. } else {
  1187. return array("code" => 0);
  1188. }
  1189. }
  1190. function print_feed_select($link, $id, $default_id = "",
  1191. $attributes = "", $include_all_feeds = true,
  1192. $root_id = false, $nest_level = 0) {
  1193. if (!$root_id) {
  1194. print "<select id=\"$id\" name=\"$id\" $attributes>";
  1195. if ($include_all_feeds) {
  1196. $is_selected = ("0" == $default_id) ? "selected=\"1\"" : "";
  1197. print "<option $is_selected value=\"0\">".__('All feeds')."</option>";
  1198. }
  1199. }
  1200. if (get_pref($link, 'ENABLE_FEED_CATS')) {
  1201. if ($root_id)
  1202. $parent_qpart = "parent_cat = '$root_id'";
  1203. else
  1204. $parent_qpart = "parent_cat IS NULL";
  1205. $result = db_query($link, "SELECT id,title,
  1206. (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
  1207. c2.parent_cat = ttrss_feed_categories.id) AS num_children
  1208. FROM ttrss_feed_categories
  1209. WHERE owner_uid = ".$_SESSION["uid"]." AND $parent_qpart ORDER BY title");
  1210. while ($line = db_fetch_assoc($result)) {
  1211. for ($i = 0; $i < $nest_level; $i++)
  1212. $line["title"] = " - " . $line["title"];
  1213. $is_selected = ("CAT:".$line["id"] == $default_id) ? "selected=\"1\"" : "";
  1214. printf("<option $is_selected value='CAT:%d'>%s</option>",
  1215. $line["id"], htmlspecialchars($line["title"]));
  1216. if ($line["num_children"] > 0)
  1217. print_feed_select($link, $id, $default_id, $attributes,
  1218. $include_all_feeds, $line["id"], $nest_level+1);
  1219. $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds
  1220. WHERE cat_id = '".$line["id"]."' AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title");
  1221. while ($fline = db_fetch_assoc($feed_result)) {
  1222. $is_selected = ($fline["id"] == $default_id) ? "selected=\"1\"" : "";
  1223. $fline["title"] = " + " . $fline["title"];
  1224. for ($i = 0; $i < $nest_level; $i++)
  1225. $fline["title"] = " - " . $fline["title"];
  1226. printf("<option $is_selected value='%d'>%s</option>",
  1227. $fline["id"], htmlspecialchars($fline["title"]));
  1228. }
  1229. }
  1230. if (!$root_id) {
  1231. $is_selected = ($default_id == "CAT:0") ? "selected=\"1\"" : "";
  1232. printf("<option $is_selected value='CAT:0'>%s</option>",
  1233. __("Uncategorized"));
  1234. $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds
  1235. WHERE cat_id IS NULL AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title");
  1236. while ($fline = db_fetch_assoc($feed_result)) {
  1237. $is_selected = ($fline["id"] == $default_id && !$default_is_cat) ? "selected=\"1\"" : "";
  1238. $fline["title"] = " + " . $fline["title"];
  1239. for ($i = 0; $i < $nest_level; $i++)
  1240. $fline["title"] = " - " . $fline["title"];
  1241. printf("<option $is_selected value='%d'>%s</option>",
  1242. $fline["id"], htmlspecialchars($fline["title"]));
  1243. }
  1244. }
  1245. } else {
  1246. $result = db_query($link, "SELECT id,title FROM ttrss_feeds
  1247. WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
  1248. while ($line = db_fetch_assoc($result)) {
  1249. $is_selected = ($line["id"] == $default_id) ? "selected=\"1\"" : "";
  1250. printf("<option $is_selected value='%d'>%s</option>",
  1251. $line["id"], htmlspecialchars($line["title"]));
  1252. }
  1253. }
  1254. if (!$root_id) {
  1255. print "</select>";
  1256. }
  1257. }
  1258. function print_feed_cat_select($link, $id, $default_id,
  1259. $attributes, $include_all_cats = true, $root_id = false, $nest_level = 0) {
  1260. if (!$root_id) {
  1261. print "<select id=\"$id\" name=\"$id\" default=\"$default_id\" onchange=\"catSelectOnChange(this)\" $attributes>";
  1262. }
  1263. if ($root_id)
  1264. $parent_qpart = "parent_cat = '$root_id'";
  1265. else
  1266. $parent_qpart = "parent_cat IS NULL";
  1267. $result = db_query($link, "SELECT id,title,
  1268. (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
  1269. c2.parent_cat = ttrss_feed_categories.id) AS num_children
  1270. FROM ttrss_feed_categories
  1271. WHERE owner_uid = ".$_SESSION["uid"]." AND $parent_qpart ORDER BY title");
  1272. while ($line = db_fetch_assoc($result)) {
  1273. if ($line["id"] == $default_id) {
  1274. $is_selected = "selected=\"1\"";
  1275. } else {
  1276. $is_selected = "";
  1277. }
  1278. for ($i = 0; $i < $nest_level; $i++)
  1279. $line["title"] = " - " . $line["title"];
  1280. if ($line["title"])
  1281. printf("<option $is_selected value='%d'>%s</option>",
  1282. $line["id"], htmlspecialchars($line["title"]));
  1283. if ($line["num_children"] > 0)
  1284. print_feed_cat_select($link, $id, $default_id, $attributes,
  1285. $include_all_cats, $line["id"], $nest_level+1);
  1286. }
  1287. if (!$root_id) {
  1288. if ($include_all_cats) {
  1289. if (db_num_rows($result) > 0) {
  1290. print "<option disabled=\"1\">--------</option>";
  1291. }
  1292. if ($default_id == 0) {
  1293. $is_selected = "selected=\"1\"";
  1294. } else {
  1295. $is_selected = "";
  1296. }
  1297. print "<option $is_selected value=\"0\">".__('Uncategorized')."</option>";
  1298. }
  1299. print "</select>";
  1300. }
  1301. }
  1302. function checkbox_to_sql_bool($val) {
  1303. return ($val == "on") ? "true" : "false";
  1304. }
  1305. function getFeedCatTitle($link, $id) {
  1306. if ($id == -1) {
  1307. return __("Special");
  1308. } else if ($id < -10) {
  1309. return __("Labels");
  1310. } else if ($id > 0) {
  1311. $result = db_query($link, "SELECT ttrss_feed_categories.title
  1312. FROM ttrss_feeds, ttrss_feed_categories WHERE ttrss_feeds.id = '$id' AND
  1313. cat_id = ttrss_feed_categories.id");
  1314. if (db_num_rows($result) == 1) {
  1315. return db_fetch_result($result, 0, "title");
  1316. } else {
  1317. return __("Uncategorized");
  1318. }
  1319. } else {
  1320. return "getFeedCatTitle($id) failed";
  1321. }
  1322. }
  1323. function getFeedIcon($id) {
  1324. switch ($id) {
  1325. case 0:
  1326. return "images/archive.png";
  1327. break;
  1328. case -1:
  1329. return "images/mark_set.svg";
  1330. break;
  1331. case -2:
  1332. return "images/pub_set.svg";
  1333. break;
  1334. case -3:
  1335. return "images/fresh.png";
  1336. break;
  1337. case -4:
  1338. return "images/tag.png";
  1339. break;
  1340. case -6:
  1341. return "images/recently_read.png";
  1342. break;
  1343. default:
  1344. if ($id < -10) {
  1345. return "images/label.png";
  1346. } else {
  1347. if (file_exists(ICONS_DIR . "/$id.ico"))
  1348. return ICONS_URL . "/$id.ico";
  1349. }
  1350. break;
  1351. }
  1352. }
  1353. function getFeedTitle($link, $id, $cat = false) {
  1354. if ($cat) {
  1355. return getCategoryTitle($link, $id);
  1356. } else if ($id == -1) {
  1357. return __("Starred articles");
  1358. } else if ($id == -2) {
  1359. return __("Published articles");
  1360. } else if ($id == -3) {
  1361. return __("Fresh articles");
  1362. } else if ($id == -4) {
  1363. return __("All articles");
  1364. } else if ($id === 0 || $id === "0") {
  1365. return __("Archived articles");
  1366. } else if ($id == -6) {
  1367. return __("Recently read");
  1368. } else if ($id < -10) {
  1369. $label_id = -$id - 11;
  1370. $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'");
  1371. if (db_num_rows($result) == 1) {
  1372. return db_fetch_result($result, 0, "caption");
  1373. } else {
  1374. return "Unknown label ($label_id)";
  1375. }
  1376. } else if (is_numeric($id) && $id > 0) {
  1377. $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'");
  1378. if (db_num_rows($result) == 1) {
  1379. return db_fetch_result($result, 0, "title");
  1380. } else {
  1381. return "Unknown feed ($id)";
  1382. }
  1383. } else {
  1384. return $id;
  1385. }
  1386. }
  1387. function make_init_params($link) {
  1388. $params = array();
  1389. $params["sign_progress"] = theme_image($link, "images/indicator_white.gif");
  1390. $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif");
  1391. $params["sign_excl"] = theme_image($link, "images/sign_excl.svg");
  1392. $params["sign_info"] = theme_image($link, "images/sign_info.svg");
  1393. foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS",
  1394. "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP",
  1395. "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT",
  1396. "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) {
  1397. $params[strtolower($param)] = (int) get_pref($link, $param);
  1398. }
  1399. $params["icons_url"] = ICONS_URL;
  1400. $params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME;
  1401. $params["default_view_mode"] = get_pref($link, "_DEFAULT_VIEW_MODE");
  1402. $params["default_view_limit"] = (int) get_pref($link, "_DEFAULT_VIEW_LIMIT");
  1403. $params["default_view_order_by"] = get_pref($link, "_DEFAULT_VIEW_ORDER_BY");
  1404. $params["bw_limit"] = (int) $_SESSION["bw_limit"];
  1405. $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
  1406. ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
  1407. $max_feed_id = db_fetch_result($result, 0, "mid");
  1408. $num_feeds = db_fetch_result($result, 0, "nf");
  1409. $params["max_feed_id"] = (int) $max_feed_id;
  1410. $params["num_feeds"] = (int) $num_feeds;
  1411. $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
  1412. $params["hotkeys"] = get_hotkeys_map($link);
  1413. $params["csrf_token"] = $_SESSION["csrf_token"];
  1414. $params["widescreen"] = (int) $_COOKIE["ttrss_widescreen"];
  1415. $params['simple_update'] = defined('SIMPLE_UPDATE_MODE') && SIMPLE_UPDATE_MODE;
  1416. return $params;
  1417. }
  1418. function get_hotkeys_info($link) {
  1419. $hotkeys = array(
  1420. __("Navigation") => a

Large files files are truncated, but you can click here to view the full file