X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=classes%2Ffeeds.php;h=c8152b9e2f7898a446014c1ea30b608a38365e4c;hb=07fd4f8d9d4f301f5ad88ff9e80f042fc3eb0c36;hp=23571c3692a3bf5834d267ef2c4bfb93461c7536;hpb=2ed0d6c433c9ef5a6b9137725030f64b4b38392e;p=tt-rss.git diff --git a/classes/feeds.php b/classes/feeds.php index 23571c36..c8152b9e 100755 --- a/classes/feeds.php +++ b/classes/feeds.php @@ -39,7 +39,7 @@ class Feeds extends Handler_Protected { $search_q = ""; } - $reply .= ""; + $reply = ""; $rss_link = htmlspecialchars(get_self_url_prefix() . "/public.php?op=rss&id=$feed_id$cat_q$search_q"); @@ -64,7 +64,7 @@ class Feeds extends Handler_Protected { $target = "target=\"_blank\""; $reply .= "". - truncate_string($feed_title, 30).""; + truncate_string(strip_tags($feed_title), 30).""; if ($error) { $error = htmlspecialchars($error); @@ -72,7 +72,7 @@ class Feeds extends Handler_Protected { } } else { - $reply .= $feed_title; + $reply .= strip_tags($feed_title); } $reply .= ""; @@ -173,46 +173,10 @@ class Feeds extends Handler_Protected { $method_split = explode(":", $method); if ($method == "ForceUpdate" && $feed > 0 && is_numeric($feed)) { - // Update the feed if required with some basic flood control - - $any_needs_curl = false; - - if (ini_get("open_basedir")) { - $pluginhost = PluginHost::getInstance(); - foreach ($pluginhost->get_plugins() as $plugin) { - $flags = $plugin->flags(); - - if (isset($flags["needs_curl"]) && $flags["needs_curl"]) { - $any_needs_curl = true; - break; - } - } - } - - //if ($_REQUEST["debug"]) print ""; - - if (!$any_needs_curl) { - - $result = $this->dbh->query( - "SELECT cache_images," . SUBSTRING_FOR_DATE . "(last_updated,1,19) AS last_updated - FROM ttrss_feeds WHERE id = '$feed'"); - - if ($this->dbh->num_rows($result) != 0) { - $last_updated = strtotime($this->dbh->fetch_result($result, 0, "last_updated")); - $cache_images = sql_bool_to_bool($this->dbh->fetch_result($result, 0, "cache_images")); - - if (!$cache_images && time() - $last_updated > 120) { - include "rssfuncs.php"; - update_rss_feed($feed, true); - } else { - $this->dbh->query("UPDATE ttrss_feeds SET last_updated = '1970-01-01', last_update_started = '1970-01-01' - WHERE id = '$feed'"); - } - } - } else { - $this->dbh->query("UPDATE ttrss_feeds SET last_updated = '1970-01-01', last_update_started = '1970-01-01' - WHERE id = '$feed'"); - } + $sth = $this->pdo->prepare("UPDATE ttrss_feeds + SET last_updated = '1970-01-01', last_update_started = '1970-01-01' + WHERE id = ?"); + $sth->execute([$feed]); } if ($method_split[0] == "MarkAllReadGR") { @@ -222,16 +186,16 @@ class Feeds extends Handler_Protected { // FIXME: might break tag display? if (is_numeric($feed) && $feed > 0 && !$cat_view) { - $result = $this->dbh->query( - "SELECT id FROM ttrss_feeds WHERE id = '$feed' LIMIT 1"); + $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? LIMIT 1"); + $sth->execute([$feed]); - if ($this->dbh->num_rows($result) == 0) { + if (!$sth->fetch()) { $reply['content'] = "
".__('Feed not found.')."
"; } } - @$search = $this->dbh->escape_string($_REQUEST["query"]); - @$search_language = $this->dbh->escape_string($_REQUEST["search_language"]); // PGSQL only + @$search = $_REQUEST["query"]; + @$search_language = $_REQUEST["search_language"]; // PGSQL only if ($search) { $disable_cache = true; @@ -239,7 +203,6 @@ class Feeds extends Handler_Protected { if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H0", $timing_info); - if (!$cat_view && is_numeric($feed) && $feed < PLUGIN_FEED_BASE_INDEX && $feed > LABEL_BASE_INDEX) { $handler = PluginHost::getInstance()->get_feed_handler( PluginHost::feed_to_pfeed_id($feed)); @@ -284,7 +247,7 @@ class Feeds extends Handler_Protected { if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info); - $result = $qfh_ret[0]; + $result = $qfh_ret[0]; // this could be either a PDO query result or a -1 if first id changed $feed_title = $qfh_ret[1]; $feed_site_url = $qfh_ret[2]; $last_error = $qfh_ret[3]; @@ -301,8 +264,6 @@ class Feeds extends Handler_Protected { $feed, $cat_view, $search, $last_error, $last_updated); - $headlines_count = is_numeric($result) ? 0 : $this->dbh->num_rows($result); - if ($offset == 0) { foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINES_BEFORE) as $p) { $reply['content'] .= $p->hook_headlines_before($feed, $cat_view, $qfh_ret); @@ -311,18 +272,17 @@ class Feeds extends Handler_Protected { $reply['content'] = ''; - if ($headlines_count > 0) { - - $lnum = $offset; + $headlines_count = 0; - $num_unread = 0; - $cur_feed_title = ''; + $lnum = $offset; + $num_unread = 0; + if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info); - if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info); + if (is_object($result)) { - $expand_cdm = get_pref('CDM_EXPANDED'); + while ($line = $result->fetch()) { - while ($line = $this->dbh->fetch_assoc($result)) { + ++$headlines_count; $line["content_preview"] = "— " . truncate_string(strip_tags($line["content"]), 250); @@ -339,6 +299,8 @@ class Feeds extends Handler_Protected { $label_cache = $line["label_cache"]; $labels = false; + $mouseover_attrs = "onmouseover='postMouseIn(event, $id)' onmouseout='postMouseOut($id)'"; + if ($label_cache) { $label_cache = json_decode($label_cache, true); @@ -350,7 +312,7 @@ class Feeds extends Handler_Protected { } } - if (!is_array($labels)) $labels = get_article_labels($id); + if (!is_array($labels)) $labels = Article::get_article_labels($id); $labels_str = ""; $labels_str .= Article::format_article_labels($labels); @@ -362,45 +324,18 @@ class Feeds extends Handler_Protected { $class = ""; - if (sql_bool_to_bool($line["unread"])) { + if ($line["unread"]) { $class .= " Unread"; ++$num_unread; } - if (sql_bool_to_bool($line["marked"])) { - $marked_pic = "\"Unstar"; - $class .= " marked"; - } else { - $marked_pic = "\"Star"; - } - - if (sql_bool_to_bool($line["published"])) { - $published_pic = "\"Unpublish"; - $class .= " published"; - } else { - $published_pic = "\"Publish"; - } - -# $content_link = "" . -# $line["title"] . ""; - -# $content_link = "" . -# $line["title"] . ""; + $marked_pic_src = $line["marked"] ? "mark_set.png" : "mark_unset.png"; + $class .= $line["marked"] ? " marked" : ""; + $marked_pic = ""; -# $content_link = "" . -# $line["title"] . ""; + $published_pic_src = $line["published"] ? "pub_set.png" : "pub_unset.png"; + $class .= $line["published"] ? " published" : ""; + $published_pic = ""; $updated_fmt = make_local_datetime($line["updated"], false, false, false, true); $date_entered_fmt = T_sprintf("Imported at %s", @@ -410,12 +345,8 @@ class Feeds extends Handler_Protected { $score_pic = "images/" . get_score_pic($score); -/* $score_title = __("(Click to change)"); - $score_pic = ""; */ - - $score_pic = ""; + $score_pic = ""; if ($score > 500) { $hlc_suffix = "high"; @@ -431,9 +362,7 @@ class Feeds extends Handler_Protected { $entry_author = " — $entry_author"; } - $has_feed_icon = feed_has_icon($feed_id); - - if ($has_feed_icon) { + if (feeds::feedHasIcon($feed_id)) { $feed_icon_img = "\"\""; } else { $feed_icon_img = "\"\""; @@ -457,33 +386,27 @@ class Feeds extends Handler_Protected { if ($vfeed_group_enabled) { if ($feed_id != $vgroup_last_feed && $line["feed_title"]) { - $cur_feed_title = $line["feed_title"]; $vgroup_last_feed = $feed_id; - $cur_feed_title = htmlspecialchars($cur_feed_title); - $vf_catchup_link = "".__('mark feed as read').""; - $reply['content'] .= "
". + $reply['content'] .= "
". "
$feed_icon_img
". "". $line["feed_title"]." - $vf_catchup_link
"; + $vf_catchup_link
"; } } - $mouseover_attrs = "onmouseover='postMouseIn(event, $id)' - onmouseout='postMouseOut($id)'"; - $reply['content'] .= "
"; $reply['content'] .= "
"; $reply['content'] .= ""; + type=\"checkbox\" onclick=\"toggleSelectRow2(this)\" + class='rchk'>"; $reply['content'] .= "$marked_pic"; $reply['content'] .= "$published_pic"; @@ -491,14 +414,14 @@ class Feeds extends Handler_Protected { $reply['content'] .= "
"; $reply['content'] .= "
"; - $reply['content'] .= "" . + class=\"title\">"; + $reply['content'] .= "" . truncate_string($line["title"], 200); if (get_pref('SHOW_CONTENT_PREVIEW')) { - $reply['content'] .= "" . $line["content_preview"] . ""; + $reply['content'] .= "" . $line["content_preview"] . ""; } $reply['content'] .= ""; @@ -511,7 +434,7 @@ class Feeds extends Handler_Protected { if (@$line["feed_title"]) { $rgba = @$rgba_cache[$feed_id]; - $reply['content'] .= "". + $reply['content'] .= "". truncate_string($line["feed_title"],30).""; } } @@ -520,7 +443,7 @@ class Feeds extends Handler_Protected { $reply['content'] .= ""; $reply['content'] .= "
$updated_fmt
-
"; + "; $reply['content'] .= "
"; @@ -529,9 +452,9 @@ class Feeds extends Handler_Protected { if ($line["feed_title"] && !$vfeed_group_enabled) { $reply['content'] .= " - $feed_icon_img"; + style=\"cursor : pointer\" + title=\"".htmlspecialchars($line['feed_title'])."\"> + $feed_icon_img"; } $reply['content'] .= "
"; @@ -545,31 +468,25 @@ class Feeds extends Handler_Protected { $tags = false; $line["content"] = sanitize($line["content"], - sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words, $line["id"]); + $line['hide_images'], false, $entry_site_url, $highlight_words, $line["id"]); foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) { $line = $p->hook_render_article_cdm($line); } + $line['content'] = rewrite_cached_urls($line['content']); + if ($vfeed_group_enabled && $line["feed_title"]) { if ($feed_id != $vgroup_last_feed) { - $cur_feed_title = $line["feed_title"]; $vgroup_last_feed = $feed_id; - $cur_feed_title = htmlspecialchars($cur_feed_title); - $vf_catchup_link = "".__('mark feed as read').""; - $has_feed_icon = feed_has_icon($feed_id); - - if ($has_feed_icon) { - $feed_icon_img = "\"\""; - } else { - //$feed_icon_img = "\"\""; - } + $feed_icon_src = Feeds::getFeedIcon($feed_id); + $feed_icon_img = ""; - $reply['content'] .= "
". + $reply['content'] .= "
". "
$feed_icon_img
". "". $line["feed_title"]." $vf_catchup_link
"; @@ -577,159 +494,136 @@ class Feeds extends Handler_Protected { } } - $mouseover_attrs = "onmouseover='postMouseIn(event, $id)' - onmouseout='postMouseOut($id)'"; + $content_encoded = htmlspecialchars($line["content"]); - $expanded_class = $expand_cdm ? "expanded" : "expandable"; + $tmp_content = "
"; - $reply['content'] .= "
"; + $tmp_content .= "
"; + $tmp_content .= "
"; - $reply['content'] .= "
"; - $reply['content'] .= "
"; + $tmp_content .= ""; - $reply['content'] .= ""; - - $reply['content'] .= "$marked_pic"; - $reply['content'] .= "$published_pic"; + $tmp_content .= "$marked_pic"; + $tmp_content .= "$published_pic"; - $reply['content'] .= "
"; + $tmp_content .= "
"; - if ($highlight_words && count($highlight_words > 0)) { + if ($highlight_words && count($highlight_words) > 0) { foreach ($highlight_words as $word) { - $line["title"] = preg_replace("/(\Q$word\E)/i", + $word = preg_quote($word, "/"); + + $line["title"] = preg_replace("/($word)/i", "$1", $line["title"]); } } // data-article-id included for context menu - $reply['content'] .= " - + ". $line["title"] . " $entry_author"; - $reply['content'] .= $labels_str; + $tmp_content .= $labels_str; - $reply['content'] .= ""; - - if (!$expand_cdm) - $content_hidden = "style=\"display : none\""; - else - $excerpt_hidden = "style=\"display : none\""; - - $reply['content'] .= "" . $content_preview . ""; - - $reply['content'] .= ""; + $tmp_content .= ""; if (!$vfeed_group_enabled) { if (@$line["feed_title"]) { $rgba = @$rgba_cache[$feed_id]; - $reply['content'] .= ""; } } - $reply['content'] .= " - $updated_fmt"; + $tmp_content .= "$updated_fmt"; - $reply['content'] .= "
"; - $reply['content'] .= "$score_pic"; + $tmp_content .= "
"; + $tmp_content .= "$score_pic"; if (!get_pref("VFEED_GROUP_BY_FEED") && $line["feed_title"]) { - $reply['content'] .= "$feed_icon_img"; + $tmp_content .= "$feed_icon_img"; } - $reply['content'] .= "
"; + $tmp_content .= "
"; //score wrapper2 - $reply['content'] .= "
"; + $tmp_content .= "
"; //header - $reply['content'] .= "
"; + $tmp_content .= "
"; - $reply['content'] .= "
"; + $tmp_content .= "
"; if ($line['note']) { - $reply['content'] .= Article::format_article_note($id, $line['note']); + $tmp_content .= Article::format_article_note($id, $line['note']); } - $reply['content'] .= "
"; + $tmp_content .= "
"; //POSTNOTE if (!$line['lang']) $line['lang'] = 'en'; - $reply['content'] .= "
"; + // this is filled from RROW data-content + $tmp_content .= "
"; - if ($line["orig_feed_id"]) { + if ($line["orig_feed_id"]) { - $tmp_result = $this->dbh->query("SELECT * FROM ttrss_archived_feeds - WHERE id = ".$line["orig_feed_id"] . " AND owner_uid = " . $_SESSION["uid"]); + $ofgh = $this->pdo->prepare("SELECT * FROM ttrss_archived_feeds + WHERE id = ? AND owner_uid = ?"); + $ofgh->execute([$line["orig_feed_id"], $_SESSION['uid']]); - if ($this->dbh->num_rows($tmp_result) != 0) { + if ($tmp_line = $ofgh->fetch()) { - $reply['content'] .= "
"; - $reply['content'] .= __("Originally from:"); + $tmp_content .= "
"; + $tmp_content .= __("Originally from:"); - $reply['content'] .= " "; + $tmp_content .= " "; - $tmp_line = $this->dbh->fetch_assoc($tmp_result); - - $reply['content'] .= "" . + $tmp_content .= "" . $tmp_line['title'] . ""; - $reply['content'] .= " "; + $tmp_content .= " "; - $reply['content'] .= ""; - $reply['content'] .= ""; + $tmp_content .= ""; + $tmp_content .= ""; - $reply['content'] .= "
"; + $tmp_content .= "
"; } } - $reply['content'] .= ""; - - $reply['content'] .= ""; - $reply['content'] .= htmlspecialchars($line["content"]); - $reply['content'] .= ""; + $tmp_content .= "
"; //content-inner + $tmp_content .= "
"; - $reply['content'] .= ""; + $always_display_enclosures = $line["always_display_enclosures"]; + $tmp_content .= Article::format_article_enclosures($id, $always_display_enclosures, + $line["content"], $line["hide_images"]); - $reply['content'] .= "
"; + $tmp_content .= "
"; // cdmIntermediate - $reply['content'] .= "
"; - - $always_display_enclosures = sql_bool_to_bool($line["always_display_enclosures"]); - $reply['content'] .= Article::format_article_enclosures($id, $always_display_enclosures, $line["content"], sql_bool_to_bool($line["hide_images"])); - - $reply['content'] .= "
"; - - $reply['content'] .= "
"; + $tmp_content .= "
"; foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) { - $reply['content'] .= $p->hook_article_left_button($line); + $tmp_content .= $p->hook_article_left_button($line); } $tags_str = Article::format_tags_string($tags, $id); - $reply['content'] .= ""; + $tmp_content .= ""; - $reply['content'] .= "Tags - $tags_str - (+)"; + $tmp_content .= "Tags + $tags_str + (+)"; $num_comments = (int) $line["num_comments"]; $entry_comments = ""; @@ -740,91 +634,98 @@ class Feeds extends Handler_Protected { } else { $comments_url = htmlspecialchars($line["link"]); } - $entry_comments = "$num_comments ". + $entry_comments = "$num_comments ". _ngettext("comment", "comments", $num_comments).""; } else { if ($line["comments"] && $line["link"] != $line["comments"]) { - $entry_comments = "".__("comments").""; + $entry_comments = "".__("comments").""; } } - if ($entry_comments) $reply['content'] .= " ($entry_comments)"; - - $reply['content'] .= ""; - $reply['content'] .= "
"; + if ($entry_comments) $tmp_content .= " ($entry_comments)"; -// $reply['content'] .= "$marked_pic"; -// $reply['content'] .= "$published_pic"; + $tmp_content .= ""; + $tmp_content .= "
"; foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_BUTTON) as $p) { - $reply['content'] .= $p->hook_article_button($line); + $tmp_content .= $p->hook_article_button($line); } - $reply['content'] .= "
"; - $reply['content'] .= "
"; + $tmp_content .= "
"; // buttons - $reply['content'] .= "
"; + $tmp_content .= "
"; // cdm footer + $tmp_content .= "
"; // cdmContent + $tmp_content .= "
"; // RROW.cdm - $reply['content'] .= "
"; + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FORMAT_ARTICLE_CDM) as $p) { + $tmp_content = $p->hook_format_article_cdm($tmp_content, $line); + } + $reply['content'] .= $tmp_content; } ++$lnum; } + } - if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PE", $timing_info); - - } else if (!is_numeric($result)) { - $message = ""; - - switch ($view_mode) { - case "unread": - $message = __("No unread articles found to display."); - break; - case "updated": - $message = __("No updated articles found to display."); - break; - case "marked": - $message = __("No starred articles found to display."); - break; - default: - if ($feed < LABEL_BASE_INDEX) { - $message = __("No articles found to display. You can assign articles to labels manually from article header context menu (applies to all selected articles) or use a filter."); - } else { - $message = __("No articles found to display."); - } - } + if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PE", $timing_info); - if (!$offset && $message) { - $reply['content'] = "
$message"; + if (!$headlines_count) { - $reply['content'] .= "

"; + if (!is_numeric($result)) { - $result = $this->dbh->query("SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds - WHERE owner_uid = " . $_SESSION['uid']); + switch ($view_mode) { + case "unread": + $message = __("No unread articles found to display."); + break; + case "updated": + $message = __("No updated articles found to display."); + break; + case "marked": + $message = __("No starred articles found to display."); + break; + default: + if ($feed < LABEL_BASE_INDEX) { + $message = __("No articles found to display. You can assign articles to labels manually from article header context menu (applies to all selected articles) or use a filter."); + } else { + $message = __("No articles found to display."); + } + } - $last_updated = $this->dbh->fetch_result($result, 0, "last_updated"); - $last_updated = make_local_datetime($last_updated, false); + if (!$offset && $message) { + $reply['content'] = "

$message"; - $reply['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated); + $reply['content'] .= "

"; - $result = $this->dbh->query("SELECT COUNT(id) AS num_errors - FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]); + $sth = $this->pdo->prepare("SELECT " . SUBSTRING_FOR_DATE . "(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds + WHERE owner_uid = ?"); + $sth->execute([$_SESSION['uid']]); + $row = $sth->fetch(); - $num_errors = $this->dbh->fetch_result($result, 0, "num_errors"); + $last_updated = make_local_datetime($row["last_updated"], false); - if ($num_errors > 0) { - $reply['content'] .= "
"; - $reply['content'] .= "". - __('Some feeds have update errors (click for details)').""; - } - $reply['content'] .= "

"; + $reply['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated); + + $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors + FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); + $sth->execute([$_SESSION['uid']]); + $row = $sth->fetch(); + $num_errors = $row["num_errors"]; + + if ($num_errors > 0) { + $reply['content'] .= "
"; + $reply['content'] .= "" . + __('Some feeds have update errors (click for details)') . ""; + } + $reply['content'] .= "

"; + + } + } else if (is_numeric($result) && $result == -1) { + $reply['first_id_changed'] = true; } - } else if (is_numeric($result) && $result == -1) { - $reply['first_id_changed'] = true; } if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H2", $timing_info); @@ -834,8 +735,10 @@ class Feeds extends Handler_Protected { } function catchupAll() { - $this->dbh->query("UPDATE ttrss_user_entries SET - last_read = NOW(), unread = false WHERE unread = true AND owner_uid = " . $_SESSION["uid"]); + $sth = $this->pdo->prepare("UPDATE ttrss_user_entries SET + last_read = NOW(), unread = false WHERE unread = true AND owner_uid = ?"); + $sth->execute([$_SESSION['uid']]); + CCache::zero_all($_SESSION["uid"]); } @@ -846,16 +749,16 @@ class Feeds extends Handler_Protected { if ($_REQUEST["debug"]) $timing_info = print_checkpoint("0", $timing_info); - $feed = $this->dbh->escape_string($_REQUEST["feed"]); - $method = $this->dbh->escape_string($_REQUEST["m"]); - $view_mode = $this->dbh->escape_string($_REQUEST["view_mode"]); + $feed = $_REQUEST["feed"]; + $method = $_REQUEST["m"]; + $view_mode = $_REQUEST["view_mode"]; $limit = 30; @$cat_view = $_REQUEST["cat"] == "true"; - @$next_unread_feed = $this->dbh->escape_string($_REQUEST["nuf"]); - @$offset = $this->dbh->escape_string($_REQUEST["skip"]); - @$vgroup_last_feed = $this->dbh->escape_string($_REQUEST["vgrlf"]); - $order_by = $this->dbh->escape_string($_REQUEST["order_by"]); - $check_first_id = $this->dbh->escape_string($_REQUEST["fid"]); + @$next_unread_feed = $_REQUEST["nuf"]; + @$offset = $_REQUEST["skip"]; + @$vgroup_last_feed = $_REQUEST["vgrlf"]; + $order_by = $_REQUEST["order_by"]; + $check_first_id = $_REQUEST["fid"]; if (is_numeric($feed)) $feed = (int) $feed; @@ -867,21 +770,30 @@ class Feeds extends Handler_Protected { return; } - $result = false; - + $sth = false; if ($feed < LABEL_BASE_INDEX) { - $label_feed = feed_to_label_id($feed); - $result = $this->dbh->query("SELECT id FROM ttrss_labels2 WHERE - id = '$label_feed' AND owner_uid = " . $_SESSION['uid']); + + $label_feed = Labels::feed_to_label_id($feed); + + $sth = $this->pdo->prepare("SELECT id FROM ttrss_labels2 WHERE + id = ? AND owner_uid = ?"); + $sth->execute([$label_feed, $_SESSION['uid']]); + } else if (!$cat_view && is_numeric($feed) && $feed > 0) { - $result = $this->dbh->query("SELECT id FROM ttrss_feeds WHERE - id = '$feed' AND owner_uid = " . $_SESSION['uid']); + + $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE + id = ? AND owner_uid = ?"); + $sth->execute([$feed, $_SESSION['uid']]); + } else if ($cat_view && is_numeric($feed) && $feed > 0) { - $result = $this->dbh->query("SELECT id FROM ttrss_feed_categories WHERE - id = '$feed' AND owner_uid = " . $_SESSION['uid']); + + $sth = $this->pdo->prepare("SELECT id FROM ttrss_feed_categories WHERE + id = ? AND owner_uid = ?"); + + $sth->execute([$feed, $_SESSION['uid']]); } - if ($result && $this->dbh->num_rows($result) == 0) { + if ($sth && !$sth->fetch()) { print json_encode($this->generate_error_feed(__("Feed not found."))); return; } @@ -898,14 +810,16 @@ class Feeds extends Handler_Protected { /* bump login timestamp if needed */ if (time() - $_SESSION["last_login_update"] > 3600) { - $this->dbh->query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " . - $_SESSION["uid"]); + $sth = $this->pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?"); + $sth->execute([$_SESSION['uid']]); + $_SESSION["last_login_update"] = time(); } if (!$cat_view && is_numeric($feed) && $feed > 0) { - $this->dbh->query("UPDATE ttrss_feeds SET last_viewed = NOW() - WHERE id = '$feed' AND owner_uid = ".$_SESSION["uid"]); + $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET last_viewed = NOW() + WHERE id = ? AND owner_uid = ?"); + $sth->execute([$feed, $_SESSION['uid']]); } $reply['headlines'] = array(); @@ -915,7 +829,7 @@ class Feeds extends Handler_Protected { switch ($order_by) { case "title": - $override_order = "ttrss_entries.title"; + $override_order = "ttrss_entries.title, date_entered, updated"; break; case "date_reverse": $override_order = "score DESC, date_entered, updated"; @@ -976,18 +890,21 @@ class Feeds extends Handler_Protected { $reply['headlines']['content'] .= "

"; - $result = $this->dbh->query("SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds - WHERE owner_uid = " . $_SESSION['uid']); + $sth = $this->pdo->prepare("SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds + WHERE owner_uid = ?"); + $sth->execute([$_SESSION['uid']]); + $row = $sth->fetch(); - $last_updated = $this->dbh->fetch_result($result, 0, "last_updated"); - $last_updated = make_local_datetime($last_updated, false); + $last_updated = make_local_datetime($row["last_updated"], false); $reply['headlines']['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated); - $result = $this->dbh->query("SELECT COUNT(id) AS num_errors - FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]); + $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors + FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); + $sth->execute([$_SESSION['uid']]); + $row = $sth->fetch(); - $num_errors = $this->dbh->fetch_result($result, 0, "num_errors"); + $num_errors = $row["num_errors"]; if ($num_errors > 0) { $reply['headlines']['content'] .= "
"; @@ -1022,6 +939,8 @@ class Feeds extends Handler_Protected { } function quickAddFeed() { + print "

"; + print_hidden("op", "rpc"); print_hidden("method", "addfeed"); @@ -1086,10 +1005,8 @@ class Feeds extends Handler_Protected {
"; - print ""; - print "
- "; + "; if (!(defined('_DISABLE_FEED_BROWSER') && _DISABLE_FEED_BROWSER)) { print ""; @@ -1098,13 +1015,15 @@ class Feeds extends Handler_Protected { print "
"; + print ""; + //return; } function feedBrowser() { if (defined('_DISABLE_FEED_BROWSER') && _DISABLE_FEED_BROWSER) return; - $browser_search = $this->dbh->escape_string($_REQUEST["search"]); + $browser_search = $_REQUEST["search"]; print_hidden("op", "rpc"); print_hidden("method", "updateFeedBrowser"); @@ -1150,11 +1069,13 @@ class Feeds extends Handler_Protected { } function search() { - $this->params = explode(":", $this->dbh->escape_string($_REQUEST["param"]), 2); + $this->params = explode(":", $_REQUEST["param"], 2); $active_feed_id = sprintf("%d", $this->params[0]); $is_cat = $this->params[1] != "false"; + print "
"; + print "
".__('Look for')."
"; print "
"; @@ -1181,28 +1102,41 @@ class Feeds extends Handler_Protected {
"; } - print " + print "
"; + + print ""; } function update_debugger() { header("Content-type: text/html"); + Debug::set_enabled(true); + Debug::set_loglevel($_REQUEST["xdebug"]); + $feed_id = (int)$_REQUEST["feed_id"]; @$do_update = $_REQUEST["action"] == "do_update"; $csrf_token = $_REQUEST["csrf_token"]; + $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); + $sth->execute([$feed_id, $_SESSION['uid']]); + + if (!$sth->fetch()) { + print "Access denied."; + return; + } + $refetch_checked = isset($_REQUEST["force_refetch"]) ? "checked" : ""; $rehash_checked = isset($_REQUEST["force_rehash"]) ? "checked" : ""; ?> - + Feed Debugger - +

Feed Debugger: getFeedTitle($feed_id) ?>

@@ -1222,8 +1156,7 @@ class Feeds extends Handler_Protected {
@@ -1238,9 +1171,10 @@ class Feeds extends Handler_Protected { if (!$owner_uid) $owner_uid = $_SESSION['uid']; + $pdo = Db::pdo(); + // Todo: all this interval stuff needs some generic generator function - $date_qpart = "false"; $search_qpart = is_array($search) && $search[0] ? search_to_sql($search[0], $search[1])[0] : 'true'; switch ($mode) { @@ -1277,6 +1211,7 @@ class Feeds extends Handler_Protected { if ($feed > 0) { $children = Feeds::getChildCategories($feed, $owner_uid); array_push($children, $feed); + $children = array_map("intval", $children); $children = join(",", $children); @@ -1285,50 +1220,55 @@ class Feeds extends Handler_Protected { $cat_qpart = "cat_id IS NULL"; } - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND unread = true AND feed_id IN + AND owner_uid = ? AND unread = true AND feed_id IN (SELECT id FROM ttrss_feeds WHERE $cat_qpart) AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid]); } else if ($feed == -2) { - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*) FROM ttrss_user_labels2, ttrss_entries WHERE article_id = ref_id AND id = ref_id AND $date_qpart AND $search_qpart) > 0 - AND unread = true AND owner_uid = $owner_uid"); + AND unread = true AND owner_uid = ?"); + $sth->execute([$owner_uid]); } } else if ($feed > 0) { - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND unread = true AND feed_id = $feed AND $date_qpart AND $search_qpart) as tmp)"); + AND owner_uid = ? AND unread = true AND feed_id = ? AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid, $feed]); } else if ($feed < 0 && $feed > LABEL_BASE_INDEX) { // special, like starred if ($feed == -1) { - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND unread = true AND marked = true AND $date_qpart AND $search_qpart) as tmp)"); + AND owner_uid = ? AND unread = true AND marked = true AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid]); } if ($feed == -2) { - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND unread = true AND published = true AND $date_qpart AND $search_qpart) as tmp)"); + AND owner_uid = ? AND unread = true AND published = true AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid]); } if ($feed == -3) { - $intl = get_pref("FRESH_ARTICLE_MAX_AGE"); + $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE"); if (DB_TYPE == "pgsql") { $match_part = "date_entered > NOW() - INTERVAL '$intl hour' "; @@ -1337,43 +1277,47 @@ class Feeds extends Handler_Protected { INTERVAL $intl HOUR) "; } - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND score >= 0 AND unread = true AND $date_qpart AND $match_part AND $search_qpart) as tmp)"); + AND owner_uid = ? AND score >= 0 AND unread = true AND $date_qpart AND $match_part AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid]); } if ($feed == -4) { - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id - AND owner_uid = $owner_uid AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + AND owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$owner_uid]); } } else if ($feed < LABEL_BASE_INDEX) { // label - $label_id = feed_to_label_id($feed); + $label_id = Labels::feed_to_label_id($feed); - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_user_labels2 WHERE ref_id = id - AND label_id = '$label_id' AND ref_id = article_id - AND owner_uid = $owner_uid AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + AND label_id = ? AND ref_id = article_id + AND owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$label_id, $owner_uid]); } CCache::update($feed, $owner_uid, $cat_view); } else { // tag - db_query("UPDATE ttrss_user_entries + $sth = $pdo->prepare("UPDATE ttrss_user_entries SET unread = false, last_read = NOW() WHERE ref_id IN (SELECT id FROM (SELECT DISTINCT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_tags WHERE ref_id = ttrss_entries.id - AND post_int_id = int_id AND tag_name = '$feed' - AND ttrss_user_entries.owner_uid = $owner_uid AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + AND post_int_id = int_id AND tag_name = ? + AND ttrss_user_entries.owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); + $sth->execute([$feed, $owner_uid]); } } @@ -1384,6 +1328,8 @@ class Feeds extends Handler_Protected { $n_feed = (int) $feed; $need_entries = false; + $pdo = Db::pdo(); + if (!$owner_uid) $owner_uid = $_SESSION["uid"]; if ($unread_only) { @@ -1392,19 +1338,23 @@ class Feeds extends Handler_Protected { $unread_qpart = "true"; } + $match_part = ""; + if ($is_cat) { return Feeds::getCategoryUnread($n_feed, $owner_uid); } else if ($n_feed == -6) { return 0; } else if ($feed != "0" && $n_feed == 0) { - $feed = db_escape_string($feed); - - $result = db_query("SELECT SUM((SELECT COUNT(int_id) + $sth = $pdo->prepare("SELECT SUM((SELECT COUNT(int_id) FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id AND ref_id = id AND $unread_qpart)) AS count FROM ttrss_tags - WHERE owner_uid = $owner_uid AND tag_name = '$feed'"); - return db_fetch_result($result, 0, "count"); + WHERE owner_uid = ? AND tag_name = ?"); + + $sth->execute([$owner_uid, $feed]); + $row = $sth->fetch(); + + return $row["count"]; } else if ($n_feed == -1) { $match_part = "marked = true"; @@ -1413,7 +1363,7 @@ class Feeds extends Handler_Protected { } else if ($n_feed == -3) { $match_part = "unread = true AND score >= 0"; - $intl = get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); if (DB_TYPE == "pgsql") { $match_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' "; @@ -1428,17 +1378,16 @@ class Feeds extends Handler_Protected { } else if ($n_feed >= 0) { if ($n_feed != 0) { - $match_part = "feed_id = '$n_feed'"; + $match_part = "feed_id = " . (int)$n_feed; } else { $match_part = "feed_id IS NULL"; } } else if ($feed < LABEL_BASE_INDEX) { - $label_id = feed_to_label_id($feed); + $label_id = Labels::feed_to_label_id($feed); return Feeds::getLabelUnread($label_id, $owner_uid); - } if ($match_part) { @@ -1451,25 +1400,26 @@ class Feeds extends Handler_Protected { $from_where = ""; } - $query = "SELECT count(int_id) AS unread + $sth = $pdo->prepare("SELECT count(int_id) AS unread FROM $from_qpart WHERE - $unread_qpart AND $from_where ($match_part) AND ttrss_user_entries.owner_uid = $owner_uid"; - - //echo "[$feed/$query]\n"; + $unread_qpart AND $from_where ($match_part) AND ttrss_user_entries.owner_uid = ?"); + $sth->execute([$owner_uid]); + $row = $sth->fetch(); - $result = db_query($query); + return $row["unread"]; } else { - $result = db_query("SELECT COUNT(post_int_id) AS unread + $sth = $pdo->prepare("SELECT COUNT(post_int_id) AS unread FROM ttrss_tags,ttrss_user_entries,ttrss_entries - WHERE tag_name = '$feed' AND post_int_id = int_id AND ref_id = ttrss_entries.id - AND $unread_qpart AND ttrss_tags.owner_uid = " . $owner_uid); - } + WHERE tag_name = ? AND post_int_id = int_id AND ref_id = ttrss_entries.id + AND $unread_qpart AND ttrss_tags.owner_uid = ,"); - $unread = db_fetch_result($result, 0, "unread"); + $sth->execute([$feed, $owner_uid]); + $row = $sth->fetch(); - return $unread; + return $row["unread"]; + } } /** @@ -1491,7 +1441,7 @@ class Feeds extends Handler_Protected { global $fetch_last_error; global $fetch_last_error_content; - require_once "include/rssfuncs.php"; + $pdo = Db::pdo(); $url = fix_url($url); @@ -1499,6 +1449,10 @@ class Feeds extends Handler_Protected { $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass); + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SUBSCRIBE_FEED) as $plugin) { + $contents = $plugin->hook_subscribe_feed($contents, $url, $auth_login, $auth_pass); + } + if (!$contents) { if (preg_match("/cloudflare\.com/", $fetch_last_error_content)) { $fetch_last_error .= " (feed behind Cloudflare)"; @@ -1507,10 +1461,6 @@ class Feeds extends Handler_Protected { return array("code" => 5, "message" => $fetch_last_error); } - foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SUBSCRIBE_FEED) as $plugin) { - $contents = $plugin->hook_subscribe_feed($contents, $url, $auth_login, $auth_pass); - } - if (is_html($contents)) { $feedUrls = get_feeds_from_html($url, $contents); @@ -1523,42 +1473,46 @@ class Feeds extends Handler_Protected { $url = key($feedUrls); } - if ($cat_id == "0" || !$cat_id) { - $cat_qpart = "NULL"; - } else { - $cat_qpart = "'$cat_id'"; - } - - $result = db_query( - "SELECT id FROM ttrss_feeds - WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]); + if (!$cat_id) $cat_id = null; - $auth_pass_encrypted = 'false'; - $auth_pass = db_escape_string($auth_pass); + $sth = $pdo->prepare("SELECT id FROM ttrss_feeds + WHERE feed_url = ? AND owner_uid = ?"); + $sth->execute([$url, $_SESSION['uid']]); - if (db_num_rows($result) == 0) { - $result = db_query( + if ($row = $sth->fetch()) { + return array("code" => 0, "feed_id" => (int) $row["id"]); + } else { + $sth = $pdo->prepare( "INSERT INTO ttrss_feeds (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method,auth_pass_encrypted) - VALUES ('".$_SESSION["uid"]."', '$url', - '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0, $auth_pass_encrypted)"); + VALUES (?, ?, ?, ?, ?, ?, 0, false)"); + + $sth->execute([$_SESSION['uid'], $url, "[Unknown]", $cat_id, (string)$auth_login, (string)$auth_pass]); - $result = db_query( - "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' - AND owner_uid = " . $_SESSION["uid"]); + $sth = $pdo->prepare("SELECT id FROM ttrss_feeds WHERE feed_url = ? + AND owner_uid = ?"); + $sth->execute([$url, $_SESSION['uid']]); + $row = $sth->fetch(); - $feed_id = db_fetch_result($result, 0, "id"); + $feed_id = $row["id"]; if ($feed_id) { - set_basic_feed_info($feed_id); + RSSUtils::set_basic_feed_info($feed_id); } return array("code" => 1, "feed_id" => (int) $feed_id); - } else { - return array("code" => 0, "feed_id" => (int) db_fetch_result($result, 0, "id")); + } } + static function getIconFile($feed_id) { + return ICONS_DIR . "/$feed_id.ico"; + } + + static function feedHasIcon($id) { + return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0; + } + static function getFeedIcon($id) { switch ($id) { case 0: @@ -1583,8 +1537,11 @@ class Feeds extends Handler_Protected { if ($id < LABEL_BASE_INDEX) { return "images/label.png"; } else { - if (file_exists(ICONS_DIR . "/$id.ico")) - return ICONS_URL . "/$id.ico"; + $icon = self::getIconFile($id); + + if ($icon && file_exists($icon)) { + return ICONS_URL . "/" . basename($icon) . "?" . filemtime($icon); + } } break; } @@ -1593,6 +1550,8 @@ class Feeds extends Handler_Protected { } static function getFeedTitle($id, $cat = false) { + $pdo = Db::pdo(); + if ($cat) { return Feeds::getCategoryTitle($id); } else if ($id == -1) { @@ -1608,21 +1567,29 @@ class Feeds extends Handler_Protected { } else if ($id == -6) { return __("Recently read"); } else if ($id < LABEL_BASE_INDEX) { - $label_id = feed_to_label_id($id); - $result = db_query("SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'"); - if (db_num_rows($result) == 1) { - return db_fetch_result($result, 0, "caption"); + + $label_id = Labels::feed_to_label_id($id); + + $sth = $pdo->prepare("SELECT caption FROM ttrss_labels2 WHERE id = ?"); + $sth->execute([$label_id]); + + if ($row = $sth->fetch()) { + return $row["caption"]; } else { return "Unknown label ($label_id)"; } } else if (is_numeric($id) && $id > 0) { - $result = db_query("SELECT title FROM ttrss_feeds WHERE id = '$id'"); - if (db_num_rows($result) == 1) { - return db_fetch_result($result, 0, "title"); + + $sth = $pdo->prepare("SELECT title FROM ttrss_feeds WHERE id = ?"); + $sth->execute([$id]); + + if ($row = $sth->fetch()) { + return $row["title"]; } else { return "Unknown feed ($id)"; } + } else { return $id; } @@ -1632,35 +1599,37 @@ class Feeds extends Handler_Protected { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; + $pdo = Db::pdo(); + if ($cat >= 0) { - if ($cat != 0) { - $cat_query = "cat_id = '$cat'"; - } else { - $cat_query = "cat_id IS NULL"; - } + if (!$cat) $cat = null; + + $sth = $pdo->prepare("SELECT id FROM ttrss_feeds + WHERE (cat_id = :cat OR (:cat IS NULL AND cat_id IS NULL)) + AND owner_uid = :uid"); - $result = db_query("SELECT id FROM ttrss_feeds WHERE $cat_query - AND owner_uid = " . $owner_uid); + $sth->execute([":cat" => $cat, ":uid" => $owner_uid]); $cat_feeds = array(); - while ($line = db_fetch_assoc($result)) { - array_push($cat_feeds, "feed_id = " . $line["id"]); + while ($line = $sth->fetch()) { + array_push($cat_feeds, "feed_id = " . (int)$line["id"]); } if (count($cat_feeds) == 0) return 0; $match_part = implode(" OR ", $cat_feeds); - $result = db_query("SELECT COUNT(int_id) AS unread + $sth = $pdo->prepare("SELECT COUNT(int_id) AS unread FROM ttrss_user_entries WHERE unread = true AND ($match_part) - AND owner_uid = " . $owner_uid); + AND owner_uid = ?"); + $sth->execute([$owner_uid]); $unread = 0; # this needs to be rewritten - while ($line = db_fetch_assoc($result)) { + while ($line = $sth->fetch()) { $unread += $line["unread"]; } @@ -1669,16 +1638,14 @@ class Feeds extends Handler_Protected { return getFeedUnread(-1) + getFeedUnread(-2) + getFeedUnread(-3) + getFeedUnread(0); } else if ($cat == -2) { - $result = db_query(" - SELECT COUNT(unread) AS unread FROM + $sth = $pdo->prepare("SELECT COUNT(unread) AS unread FROM ttrss_user_entries, ttrss_user_labels2 WHERE article_id = ref_id AND unread = true - AND ttrss_user_entries.owner_uid = '$owner_uid'"); - - $unread = db_fetch_result($result, 0, "unread"); - - return $unread; + AND ttrss_user_entries.owner_uid = ?"); + $sth->execute([$owner_uid]); + $row = $sth->fetch(); + return $row["unread"]; } } @@ -1686,12 +1653,15 @@ class Feeds extends Handler_Protected { static function getCategoryChildrenUnread($cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query("SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' - AND owner_uid = $owner_uid"); + $pdo = Db::pdo(); + + $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories WHERE parent_cat = ? + AND owner_uid = ?"); + $sth->execute([$cat, $owner_uid]); $unread = 0; - while ($line = db_fetch_assoc($result)) { + while ($line = $sth->fetch()) { $unread += Feeds::getCategoryUnread($line["id"], $owner_uid); $unread += Feeds::getCategoryChildrenUnread($line["id"], $owner_uid); } @@ -1701,16 +1671,16 @@ class Feeds extends Handler_Protected { static function getGlobalUnread($user_id = false) { - if (!$user_id) { - $user_id = $_SESSION["uid"]; - } + if (!$user_id) $user_id = $_SESSION["uid"]; - $result = db_query("SELECT SUM(value) AS c_id FROM ttrss_counters_cache - WHERE owner_uid = '$user_id' AND feed_id > 0"); + $pdo = Db::pdo(); - $c_id = db_fetch_result($result, 0, "c_id"); + $sth = $pdo->prepare("SELECT SUM(value) AS c_id FROM ttrss_counters_cache + WHERE owner_uid = ? AND feed_id > 0"); + $sth->execute([$user_id]); + $row = $sth->fetch(); - return $c_id; + return $row["c_id"]; } static function getCategoryTitle($cat_id) { @@ -1721,11 +1691,14 @@ class Feeds extends Handler_Protected { return __("Labels"); } else { - $result = db_query("SELECT title FROM ttrss_feed_categories WHERE - id = '$cat_id'"); + $pdo = Db::pdo(); - if (db_num_rows($result) == 1) { - return db_fetch_result($result, 0, "title"); + $sth = $pdo->prepare("SELECT title FROM ttrss_feed_categories WHERE + id = ?"); + $sth->execute([$cat_id]); + + if ($row = $sth->fetch()) { + return $row["title"]; } else { return __("Uncategorized"); } @@ -1735,11 +1708,15 @@ class Feeds extends Handler_Protected { static function getLabelUnread($label_id, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query("SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 - WHERE owner_uid = '$owner_uid' AND unread = true AND label_id = '$label_id' AND article_id = ref_id"); + $pdo = Db::pdo(); + + $sth = $pdo->prepare("SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 + WHERE owner_uid = ? AND unread = true AND label_id = ? AND article_id = ref_id"); - if (db_num_rows($result) != 0) { - return db_fetch_result($result, 0, "unread"); + $sth->execute([$owner_uid, $label_id]); + + if ($row = $sth->fetch()) { + return $row["unread"]; } else { return 0; } @@ -1747,6 +1724,11 @@ class Feeds extends Handler_Protected { static function queryFeedHeadlines($params) { + $pdo = Db::pdo(); + + // WARNING: due to highly dynamic nature of this query its going to quote parameters + // right before adding them to SQL part + $feed = $params["feed"]; $limit = isset($params["limit"]) ? $params["limit"] : 30; $view_mode = $params["view_mode"]; @@ -1766,7 +1748,7 @@ class Feeds extends Handler_Protected { $skip_first_id_check = isset($params["skip_first_id_check"]) ? $params["skip_first_id_check"] : false; $ext_tables_part = ""; - $query_strategy_part = ""; + $limit_query_part = ""; $search_words = array(); @@ -1786,7 +1768,7 @@ class Feeds extends Handler_Protected { } if ($since_id) { - $since_id_part = "ttrss_entries.id > $since_id AND "; + $since_id_part = "ttrss_entries.id > ".$pdo->quote($since_id)." AND "; } else { $since_id_part = ""; } @@ -1826,7 +1808,7 @@ class Feeds extends Handler_Protected { } if ($limit > 0) { - $limit_query_part = "LIMIT " . $limit; + $limit_query_part = "LIMIT " . (int)$limit; } $allow_archived = false; @@ -1846,13 +1828,14 @@ class Feeds extends Handler_Protected { if ($include_children) { # sub-cats $subcats = Feeds::getChildCategories($feed, $owner_uid); - array_push($subcats, $feed); + $subcats = array_map("intval", $subcats); + $query_strategy_part = "cat_id IN (". implode(",", $subcats).")"; } else { - $query_strategy_part = "cat_id = '$feed'"; + $query_strategy_part = "cat_id = " . $pdo->quote($feed); } } else { @@ -1862,7 +1845,7 @@ class Feeds extends Handler_Protected { $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; } else { - $query_strategy_part = "feed_id = '$feed'"; + $query_strategy_part = "feed_id = " . $pdo->quote($feed); } } else if ($feed == 0 && !$cat_view) { // archive virtual feed $query_strategy_part = "feed_id IS NULL"; @@ -1917,7 +1900,7 @@ class Feeds extends Handler_Protected { } else if ($feed == -3) { // fresh virtual feed $query_strategy_part = "unread = true AND score >= 0"; - $intl = get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); if (DB_TYPE == "pgsql") { $query_strategy_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' "; @@ -1931,9 +1914,9 @@ class Feeds extends Handler_Protected { $query_strategy_part = "true"; $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; } else if ($feed <= LABEL_BASE_INDEX) { // labels - $label_id = feed_to_label_id($feed); + $label_id = Labels::feed_to_label_id($feed); - $query_strategy_part = "label_id = '$label_id' AND + $query_strategy_part = "label_id = ".$pdo->quote($label_id)." AND ttrss_labels2.id = ttrss_user_labels2.label_id AND ttrss_user_labels2.article_id = ref_id"; @@ -1959,8 +1942,6 @@ class Feeds extends Handler_Protected { $vfeed_query_part = $override_vfeed; } - $feed_title = ""; - if ($search) { $feed_title = T_sprintf("Search results: %s", $search); } else { @@ -1968,24 +1949,25 @@ class Feeds extends Handler_Protected { $feed_title = Feeds::getCategoryTitle($feed); } else { if (is_numeric($feed) && $feed > 0) { - $result = db_query("SELECT title,site_url,last_error,last_updated - FROM ttrss_feeds WHERE id = '$feed' AND owner_uid = $owner_uid"); - - $feed_title = db_fetch_result($result, 0, "title"); - $feed_site_url = db_fetch_result($result, 0, "site_url"); - $last_error = db_fetch_result($result, 0, "last_error"); - $last_updated = db_fetch_result($result, 0, "last_updated"); + $ssth = $pdo->prepare("SELECT title,site_url,last_error,last_updated + FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); + $ssth->execute([$feed, $owner_uid]); + $row = $ssth->fetch(); + + $feed_title = $row["title"]; + $feed_site_url = $row["site_url"]; + $last_error = $row["last_error"]; + $last_updated = $row["last_updated"]; } else { $feed_title = Feeds::getFeedTitle($feed); } } } - $content_query_part = "content, "; if ($limit_query_part) { - $offset_query_part = "OFFSET $offset"; + $offset_query_part = "OFFSET " . (int)$offset; } else { $offset_query_part = ""; } @@ -1994,9 +1976,9 @@ class Feeds extends Handler_Protected { // proper override_order applied above if ($vfeed_query_part && !$ignore_vfeed_group && get_pref('VFEED_GROUP_BY_FEED', $owner_uid)) { if (!$override_order) { - $order_by = "ttrss_feeds.title, $order_by"; + $order_by = "ttrss_feeds.title, ".$order_by; } else { - $order_by = "ttrss_feeds.title, $override_order"; + $order_by = "ttrss_feeds.title, ".$override_order; } } @@ -2049,20 +2031,21 @@ class Feeds extends Handler_Protected { $from_qpart WHERE $feed_check_qpart - ttrss_user_entries.owner_uid = '$owner_uid' AND + ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND $search_query_part $start_ts_query_part $since_id_part $sanity_interval_qpart $first_id_query_strategy_part ORDER BY $order_by LIMIT 1"; - if ($_REQUEST["debug"]) { + /*if ($_REQUEST["debug"]) { print $query; - } + }*/ - $result = db_query($query); - if ($result && db_num_rows($result) > 0) { - $first_id = (int)db_fetch_result($result, 0, "id"); + $res = $pdo->query($query); + + if ($row = $res->fetch()) { + $first_id = (int)$row["id"]; if ($offset > 0 && $first_id && $check_first_id && $first_id != $check_first_id) { return array(-1, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id); @@ -2095,7 +2078,7 @@ class Feeds extends Handler_Protected { $from_qpart WHERE $feed_check_qpart - ttrss_user_entries.owner_uid = '$owner_uid' AND + ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND $search_query_part $start_ts_query_part $view_query_part @@ -2103,9 +2086,9 @@ class Feeds extends Handler_Protected { $query_strategy_part ORDER BY $order_by $limit_query_part $offset_query_part"; - if ($_REQUEST["debug"]) print $query; + //if ($_REQUEST["debug"]) print $query; - $result = db_query($query); + $res = $pdo->query($query); } else { // browsing by tag @@ -2139,9 +2122,9 @@ class Feeds extends Handler_Protected { FROM ttrss_entries, ttrss_user_entries, ttrss_tags WHERE ref_id = ttrss_entries.id AND - ttrss_user_entries.owner_uid = $owner_uid AND + ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND post_int_id = int_id AND - tag_name = '$feed' AND + tag_name = ".$pdo->quote($feed)." AND $view_query_part $search_query_part $query_strategy_part ORDER BY $order_by @@ -2149,20 +2132,23 @@ class Feeds extends Handler_Protected { if ($_REQUEST["debug"]) print $query; - $result = db_query($query); + $res = $pdo->query($query); } - return array($result, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id); + return array($res, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id); } static function getParentCategories($cat, $owner_uid) { $rv = array(); - $result = db_query("SELECT parent_cat FROM ttrss_feed_categories - WHERE id = '$cat' AND parent_cat IS NOT NULL AND owner_uid = $owner_uid"); + $pdo = Db::pdo(); - while ($line = db_fetch_assoc($result)) { + $sth = $pdo->prepare("SELECT parent_cat FROM ttrss_feed_categories + WHERE id = ? AND parent_cat IS NOT NULL AND owner_uid = ?"); + $sth->execute([$cat, $owner_uid]); + + while ($line = $sth->fetch()) { array_push($rv, $line["parent_cat"]); $rv = array_merge($rv, Feeds::getParentCategories($line["parent_cat"], $owner_uid)); } @@ -2173,10 +2159,13 @@ class Feeds extends Handler_Protected { static function getChildCategories($cat, $owner_uid) { $rv = array(); - $result = db_query("SELECT id FROM ttrss_feed_categories - WHERE parent_cat = '$cat' AND owner_uid = $owner_uid"); + $pdo = Db::pdo(); + + $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories + WHERE parent_cat = ? AND owner_uid = ?"); + $sth->execute([$cat, $owner_uid]); - while ($line = db_fetch_assoc($result)) { + while ($line = $sth->fetch()) { array_push($rv, $line["id"]); $rv = array_merge($rv, Feeds::getChildCategories($line["id"], $owner_uid)); } @@ -2184,5 +2173,21 @@ class Feeds extends Handler_Protected { return $rv; } + static function getFeedCategory($feed) { + $pdo = Db::pdo(); + + $sth = $pdo->prepare("SELECT cat_id FROM ttrss_feeds + WHERE id = ?"); + $sth->execute([$feed]); + + if ($row = $sth->fetch()) { + return $row["cat_id"]; + } else { + return false; + } + + } + + }