summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/feedbrowser.php106
-rw-r--r--[-rwxr-xr-x]include/functions.php147
-rwxr-xr-xinclude/login_form.php3
-rwxr-xr-xinclude/sanity_check.php11
-rw-r--r--include/sessions.php2
5 files changed, 90 insertions, 179 deletions
diff --git a/include/feedbrowser.php b/include/feedbrowser.php
deleted file mode 100644
index 77ae9d649..000000000
--- a/include/feedbrowser.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
- function make_feed_browser($search, $limit, $mode = 1) {
-
- if (defined('_DISABLE_FEED_BROWSER') && _DISABLE_FEED_BROWSER) return;
-
- $rv = '';
-
- $pdo = Db::pdo();
-
- if ($search) {
- $search = $pdo->quote($search);
-
- $search_qpart = "AND (UPPER(feed_url) LIKE UPPER('%$search%') OR
- UPPER(title) LIKE UPPER('%$search%'))";
- } else {
- $search_qpart = "";
- }
-
- if ($mode == 1) {
- $sth = $pdo->prepare("SELECT feed_url, site_url, title, SUM(subscribers) AS subscribers FROM
- (SELECT feed_url, site_url, title, subscribers FROM ttrss_feedbrowser_cache UNION ALL
- SELECT feed_url, site_url, title, subscribers FROM ttrss_linked_feeds) AS qqq
- WHERE
- (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf
- WHERE tf.feed_url = qqq.feed_url
- AND owner_uid = ?) $search_qpart
- GROUP BY feed_url, site_url, title ORDER BY subscribers DESC LIMIT " . (int)$limit);
- $sth->execute([$_SESSION['uid']]);
-
- } else if ($mode == 2) {
- $sth = $pdo->prepare("SELECT *,
- (SELECT COUNT(*) FROM ttrss_user_entries WHERE
- orig_feed_id = ttrss_archived_feeds.id) AS articles_archived
- FROM
- ttrss_archived_feeds
- WHERE
- (SELECT COUNT(*) FROM ttrss_feeds
- WHERE ttrss_feeds.feed_url = ttrss_archived_feeds.feed_url AND
- owner_uid = :uid) = 0 AND
- owner_uid = :uid $search_qpart
- ORDER BY id DESC LIMIT " . (int)$limit);
-
- $sth->execute([":uid" => $_SESSION['uid']]);
- }
-
- $feedctr = 0;
-
- while ($line = $sth->fetch()) {
-
- if ($mode == 1) {
-
- $feed_url = htmlspecialchars($line["feed_url"]);
- $site_url = htmlspecialchars($line["site_url"]);
- $subscribers = $line["subscribers"];
-
- $check_box = "<input onclick='Lists.onRowChecked(this)'
- dojoType=\"dijit.form.CheckBox\"
- type=\"checkbox\" \">";
-
- $site_url = "<a target=\"_blank\" rel=\"noopener noreferrer\"
- href=\"$site_url\">
- <span class=\"fb_feedTitle\">".
- htmlspecialchars($line["title"])."</span></a>";
-
- $feed_url = "<a target=\"_blank\" rel=\"noopener noreferrer\" class=\"fb_feedUrl\"
- href=\"$feed_url\"><i class='icon-syndicate material-icons'>rss_feed</i></a>";
-
- $rv .= "<li>$check_box $feed_url $site_url".
- "&nbsp;<span class='subscribers'>($subscribers)</span></li>";
-
- } else if ($mode == 2) {
- $feed_url = htmlspecialchars($line["feed_url"]);
- $site_url = htmlspecialchars($line["site_url"]);
-
- $check_box = "<input onclick='Lists.onRowChecked(this)' dojoType=\"dijit.form.CheckBox\"
- type=\"checkbox\">";
-
- if ($line['articles_archived'] > 0) {
- $archived = sprintf(_ngettext("%d archived article", "%d archived articles", (int) $line['articles_archived']), $line['articles_archived']);
- $archived = "&nbsp;<span class='subscribers'>($archived)</span>";
- } else {
- $archived = '';
- }
-
- $site_url = "<a target=\"_blank\" rel=\"noopener noreferrer\"
- href=\"$site_url\">
- <span class=\"fb_feedTitle\">".
- htmlspecialchars($line["title"])."</span></a>";
-
- $feed_url = "<a target=\"_blank\" rel=\"noopener noreferrer\" class=\"fb_feedUrl\"
- href=\"$feed_url\"><i class='icon-syndicate material-icons'>rss_feed</i></a>";
-
-
- $rv .= "<li id=\"FBROW-".$line["id"]."\">".
- "$check_box $feed_url $site_url $archived</li>";
- }
-
- ++$feedctr;
- }
-
- if ($feedctr == 0) {
- $rv .= "<li style=\"text-align : center\"><p>".__('No feeds found.')."</p></li>";
- }
-
- return $rv;
- }
diff --git a/include/functions.php b/include/functions.php
index a1aeb7135..6dc9990e8 100755..100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -1,6 +1,6 @@
<?php
define('EXPECTED_CONFIG_VERSION', 26);
- define('SCHEMA_VERSION', 135);
+ define('SCHEMA_VERSION', 138);
define('LABEL_BASE_INDEX', -1024);
define('PLUGIN_FEED_BASE_INDEX', -128);
@@ -141,7 +141,6 @@
}
_bindtextdomain("messages", "locale");
-
_textdomain("messages");
_bind_textdomain_codeset("messages", "UTF-8");
}
@@ -563,7 +562,7 @@
libxml_use_internal_errors(true);
$doc = new DOMDocument();
- $doc->loadHTML($html);
+ $doc->loadHTML('<?xml encoding="UTF-8">' . $html);
$xpath = new DOMXPath($doc);
$base = $xpath->query('/html/head/base[@href]');
@@ -738,21 +737,28 @@
}
}
- function make_password($length = 8) {
-
+ function make_password($length = 12) {
$password = "";
- $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ";
+ $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ*%+^";
- $i = 0;
+ $i = 0;
while ($i < $length) {
- $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
+
+ try {
+ $idx = function_exists("random_int") ? random_int(0, strlen($possible) - 1) : mt_rand(0, strlen($possible) - 1);
+ } catch (Exception $e) {
+ $idx = mt_rand(0, strlen($possible) - 1);
+ }
+
+ $char = substr($possible, $idx, 1);
if (!strstr($password, $char)) {
$password .= $char;
$i++;
}
}
+
return $password;
}
@@ -1197,6 +1203,7 @@
"goto_fresh" => __("Fresh"),
"goto_marked" => __("Starred"),
"goto_published" => __("Published"),
+ "goto_read" => __("Recently read"),
"goto_tagcloud" => __("Tag cloud"),
"goto_prefs" => __("Preferences")),
__("Other") => array(
@@ -1216,40 +1223,36 @@
function get_hotkeys_map() {
$hotkeys = array(
- // "navigation" => array(
"k" => "next_feed",
"j" => "prev_feed",
"n" => "next_article",
"p" => "prev_article",
- "(38)|up" => "prev_article",
- "(40)|down" => "next_article",
- // "^(38)|Ctrl-up" => "prev_article_noscroll",
- // "^(40)|Ctrl-down" => "next_article_noscroll",
- "(191)|/" => "search_dialog",
- // "article" => array(
+ "(38)|Up" => "prev_article",
+ "(40)|Down" => "next_article",
+ "*(38)|Shift+Up" => "article_scroll_up",
+ "*(40)|Shift+Down" => "article_scroll_down",
+ "^(38)|Ctrl+Up" => "prev_article_noscroll",
+ "^(40)|Ctrl+Down" => "next_article_noscroll",
+ "/" => "search_dialog",
"s" => "toggle_mark",
- "*s" => "toggle_publ",
+ "S" => "toggle_publ",
"u" => "toggle_unread",
- "*t" => "edit_tags",
+ "T" => "edit_tags",
"o" => "open_in_new_window",
"c p" => "catchup_below",
"c n" => "catchup_above",
- "*n" => "article_scroll_down",
- "*p" => "article_scroll_up",
- "*(38)|Shift+up" => "article_scroll_up",
- "*(40)|Shift+down" => "article_scroll_down",
- "a *w" => "toggle_widescreen",
+ "N" => "article_scroll_down",
+ "P" => "article_scroll_up",
+ "a W" => "toggle_widescreen",
"a e" => "toggle_embed_original",
"e" => "email_article",
"a q" => "close_article",
- // "article_selection" => array(
"a a" => "select_all",
"a u" => "select_unread",
- "a *u" => "select_marked",
+ "a U" => "select_marked",
"a p" => "select_published",
"a i" => "select_invert",
"a n" => "select_none",
- // "feed" => array(
"f r" => "feed_refresh",
"f a" => "feed_unhide_read",
"f s" => "feed_subscribe",
@@ -1257,31 +1260,27 @@
"f q" => "feed_catchup",
"f x" => "feed_reverse",
"f g" => "feed_toggle_vgroup",
- "f *d" => "feed_debug_update",
- "f *g" => "feed_debug_viewfeed",
- "f *c" => "toggle_combined_mode",
+ "f D" => "feed_debug_update",
+ "f G" => "feed_debug_viewfeed",
+ "f C" => "toggle_combined_mode",
"f c" => "toggle_cdm_expanded",
- "*q" => "catchup_all",
+ "Q" => "catchup_all",
"x" => "cat_toggle_collapse",
- // "goto" => array(
"g a" => "goto_all",
"g f" => "goto_fresh",
"g s" => "goto_marked",
"g p" => "goto_published",
+ "g r" => "goto_read",
"g t" => "goto_tagcloud",
- "g *p" => "goto_prefs",
- // "other" => array(
+ "g P" => "goto_prefs",
"r" => "select_article_cursor",
"c l" => "create_label",
"c f" => "create_filter",
"c s" => "collapse_sidebar",
- "a *n" => "toggle_night_mode",
- "^(191)|Ctrl+/" => "help_dialog",
+ "a N" => "toggle_night_mode",
+ "?" => "help_dialog",
);
- $hotkeys["^(38)|Ctrl-up"] = "prev_article_noscroll";
- $hotkeys["^(40)|Ctrl-down"] = "next_article_noscroll";
-
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HOTKEY_MAP) as $plugin) {
$hotkeys = $plugin->hook_hotkey_map($hotkeys);
}
@@ -1487,11 +1486,19 @@
}
if (count($search_query_leftover) > 0) {
- $search_query_leftover = $pdo->quote(implode(" & ", $search_query_leftover));
if (DB_TYPE == "pgsql") {
+
+ // if there's no joiners consider this a "simple" search and
+ // concatenate everything with &, otherwise don't try to mess with tsquery syntax
+ if (preg_match("/[&|]/", implode(" " , $search_query_leftover))) {
+ $tsquery = $pdo->quote(implode(" ", $search_query_leftover));
+ } else {
+ $tsquery = $pdo->quote(implode(" & ", $search_query_leftover));
+ }
+
array_push($query_keywords,
- "(tsvector_combined @@ to_tsquery($search_language, $search_query_leftover))");
+ "(tsvector_combined @@ to_tsquery($search_language, $tsquery))");
}
}
@@ -1521,17 +1528,13 @@
// plugins work on original source URLs used before caching
function rewrite_cached_urls($str) {
- $charset_hack = '<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- </head>';
-
$res = trim($str); if (!$res) return '';
$doc = new DOMDocument();
- $doc->loadHTML($charset_hack . $res);
+ $doc->loadHTML('<?xml encoding="UTF-8">' . $res);
$xpath = new DOMXPath($doc);
- $entries = $xpath->query('(//img[@src]|//video[@poster]|//video/source[@src]|//audio/source[@src])');
+ $entries = $xpath->query('(//img[@src]|//picture/source[@src]|//video[@poster]|//video/source[@src]|//audio/source[@src])');
$need_saving = false;
@@ -1548,6 +1551,8 @@
// this is strictly cosmetic
if ($entry->tagName == 'img') {
$suffix = ".png";
+ } else if ($entry->parentNode && $entry->parentNode->tagName == "picture") {
+ $suffix = ".png";
} else if ($entry->parentNode && $entry->parentNode->tagName == "video") {
$suffix = ".mp4";
} else if ($entry->parentNode && $entry->parentNode->tagName == "audio") {
@@ -1581,21 +1586,15 @@
$res = trim($str); if (!$res) return '';
- $charset_hack = '<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- </head>';
-
- $res = trim($res); if (!$res) return '';
-
libxml_use_internal_errors(true);
$doc = new DOMDocument();
- $doc->loadHTML($charset_hack . $res);
+ $doc->loadHTML('<?xml encoding="UTF-8">' . $res);
$xpath = new DOMXPath($doc);
$rewrite_base_url = $site_url ? $site_url : get_self_url_prefix();
- $entries = $xpath->query('(//a[@href]|//img[@src]|//video/source[@src]|//audio/source[@src])');
+ $entries = $xpath->query('(//a[@href]|//img[@src]|//video/source[@src]|//audio/source[@src]|//picture/source[@src])');
foreach ($entries as $entry) {
@@ -1689,7 +1688,7 @@
'dt', 'em', 'footer', 'figure', 'figcaption',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'html', 'i',
'img', 'ins', 'kbd', 'li', 'main', 'mark', 'nav', 'noscript',
- 'ol', 'p', 'pre', 'q', 'ruby', 'rp', 'rt', 's', 'samp', 'section',
+ 'ol', 'p', 'picture', 'pre', 'q', 'ruby', 'rp', 'rt', 's', 'samp', 'section',
'small', 'source', 'span', 'strike', 'strong', 'sub', 'summary',
'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time',
'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video', 'xml:namespace' );
@@ -1981,7 +1980,7 @@
return true;
}
- function add_feed_category($feed_cat, $parent_cat_id = false) {
+ function add_feed_category($feed_cat, $parent_cat_id = false, $order_id = 0) {
if (!$feed_cat) return false;
@@ -2004,9 +2003,9 @@
if (!$sth->fetch()) {
- $sth = $pdo->prepare("INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat)
- VALUES (?, ?, ?)");
- $sth->execute([$_SESSION['uid'], $feed_cat, $parent_cat_id]);
+ $sth = $pdo->prepare("INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat,order_id)
+ VALUES (?, ?, ?, ?)");
+ $sth->execute([$_SESSION['uid'], $feed_cat, $parent_cat_id, (int)$order_id]);
if (!$tr_in_progress) $pdo->commit();
@@ -2116,7 +2115,7 @@
libxml_use_internal_errors(true);
$doc = new DOMDocument();
- $doc->loadHTML($content);
+ $doc->loadHTML('<?xml encoding="UTF-8">' . $content);
$xpath = new DOMXPath($doc);
$entries = $xpath->query('/html/head/link[@rel="alternate" and '.
'(contains(@type,"rss") or contains(@type,"atom"))]|/html/head/link[@rel="feed"]');
@@ -2137,7 +2136,7 @@
}
function is_html($content) {
- return preg_match("/<html|DOCTYPE html/i", substr($content, 0, 100)) !== 0;
+ return preg_match("/<html|DOCTYPE html/i", substr($content, 0, 8192)) !== 0;
}
function url_is_html($url, $login = false, $pass = false) {
@@ -2217,7 +2216,8 @@
FROM ttrss_tags, ttrss_user_entries, ttrss_entries
WHERE post_int_id = int_id AND $interval_query AND
ref_id = ttrss_entries.id AND tag_cache != '' LIMIT ?");
- $sth->execute([$limit]);
+ $sth->bindValue(1, $limit_part, PDO::PARAM_INT);
+ $sth->execute();
$ids = array();
@@ -2403,18 +2403,23 @@
return __((parseInt(n) > 1) ? msg2 : msg1);
}';
- $l10n = _get_reader();
+ global $text_domains;
- for ($i = 0; $i < $l10n->total; $i++) {
- $orig = $l10n->get_original_string($i);
- if(strpos($orig, "\000") !== FALSE) { // Plural forms
- $key = explode(chr(0), $orig);
- print T_js_decl($key[0], _ngettext($key[0], $key[1], 1)); // Singular
- print T_js_decl($key[1], _ngettext($key[0], $key[1], 2)); // Plural
- } else {
- $translation = __($orig);
- print T_js_decl($orig, $translation);
+ foreach (array_keys($text_domains) as $domain) {
+ $l10n = _get_reader($domain);
+
+ for ($i = 0; $i < $l10n->total; $i++) {
+ $orig = $l10n->get_original_string($i);
+ if(strpos($orig, "\000") !== FALSE) { // Plural forms
+ $key = explode(chr(0), $orig);
+ print T_js_decl($key[0], _ngettext($key[0], $key[1], 1)); // Singular
+ print T_js_decl($key[1], _ngettext($key[0], $key[1], 2)); // Plural
+ } else {
+ $translation = _dgettext($domain,$orig);
+ print T_js_decl($orig, $translation);
+ }
}
+
}
}
diff --git a/include/login_form.php b/include/login_form.php
index 68ebcef29..6c6aaf8cf 100755
--- a/include/login_form.php
+++ b/include/login_form.php
@@ -1,4 +1,5 @@
<?php startup_gettext(); ?>
+<!DOCTYPE html>
<html>
<head>
<title>Tiny Tiny RSS : Login</title>
@@ -60,7 +61,7 @@ function bwLimitChange(elem) {
}
</script>
-<?php $return = urlencode($_SERVER["REQUEST_URI"]) ?>
+<?php $return = urlencode(make_self_url()) ?>
<div class="container">
diff --git a/include/sanity_check.php b/include/sanity_check.php
index c2ecee368..f06cf0a39 100755
--- a/include/sanity_check.php
+++ b/include/sanity_check.php
@@ -14,6 +14,12 @@
* If you come crying when stuff inevitably breaks, you will be mocked and told
* to get out. */
+ function make_self_url() {
+ $proto = is_server_https() ? 'https' : 'http';
+
+ return $proto . '://' . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
+ }
+
function make_self_url_path() {
$proto = is_server_https() ? 'https' : 'http';
$url_path = $proto . '://' . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
@@ -50,6 +56,10 @@
array_push($errors, "PHP version 5.6.0 or newer required. You're using " . PHP_VERSION . ".");
}
+ if (!class_exists("UConverter")) {
+ array_push($errors, "PHP UConverter class is missing, it's provided by the Internationalization (intl) module.");
+ }
+
if (CONFIG_VERSION != EXPECTED_CONFIG_VERSION) {
array_push($errors, "Configuration file (config.php) has incorrect version. Update it with new options from config.php-dist and set CONFIG_VERSION to the correct value.");
}
@@ -176,6 +186,7 @@
}
if (count($errors) > 0 && $_SERVER['REQUEST_URI']) { ?>
+ <!DOCTYPE html>
<html>
<head>
<title>Startup failed</title>
diff --git a/include/sessions.php b/include/sessions.php
index c27eb98b0..ca9f169d8 100644
--- a/include/sessions.php
+++ b/include/sessions.php
@@ -49,7 +49,7 @@
if ($_SESSION["uid"]) {
- if ($_SESSION["user_agent"] != sha1($_SERVER['HTTP_USER_AGENT'])) {
+ if (!defined('_SESSION_SKIP_UA_CHECKS') && $_SESSION["user_agent"] != sha1($_SERVER['HTTP_USER_AGENT'])) {
$_SESSION["login_error_msg"] = __("Session failed to validate (UA changed).");
return false;
}