]> git.wh0rd.org - tt-rss.git/commitdiff
Merge branch 'master' of git.fakecake.org:tt-rss into pdo-experimental
authorAndrew Dolgov <noreply@fakecake.org>
Sat, 2 Dec 2017 20:13:49 +0000 (23:13 +0300)
committerAndrew Dolgov <noreply@fakecake.org>
Sat, 2 Dec 2017 20:13:49 +0000 (23:13 +0300)
1  2 
include/functions.php

diff --combined include/functions.php
index f1b016de7ecf67e9c9f6353eb91680d63ab78006,5667ac416ec7b3dd7469f8e1678ec641d93ea87e..1d7033c899b46e773d4677a4df9c62947b3630b1
@@@ -57,7 -57,7 +57,7 @@@
        // do not cache files smaller than that (bytes)
        define_default('CACHE_MAX_DAYS', 7);
        // max age in days for various automatically cached (temporary) files
-     define_default('MAX_CONDITIONAL_INTERVAL', 3600*6);
+     define_default('MAX_CONDITIONAL_INTERVAL', 3600*12);
      // max interval between forced unconditional updates for servers
      // not complying with http if-modified-since (seconds)
  
  
                if (!$purge_interval) $purge_interval = feed_purge_interval($feed_id);
  
 -              $rows = -1;
 +              $pdo = Db::pdo();
  
 -              $result = db_query(
 -                      "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
 +              $sth = $pdo->prepare("SELECT owner_uid FROM ttrss_feeds WHERE id = ?");
 +              $sth->execute([$feed_id]);
  
                $owner_uid = false;
  
 -              if (db_num_rows($result) == 1) {
 -                      $owner_uid = db_fetch_result($result, 0, "owner_uid");
 +              if ($row = $sth->fetch()) {
 +                      $owner_uid = $row["owner_uid"];
                }
  
                if ($purge_interval == -1 || !$purge_interval) {
                        $purge_interval = FORCE_ARTICLE_PURGE;
                }
  
 -              if (!$purge_unread) $query_limit = " unread = false AND ";
 +              if (!$purge_unread)
 +                  $query_limit = " unread = false AND ";
 +              else
 +                  $query_limit = "";
 +
 +              $purge_interval = (int) $purge_interval;
  
                if (DB_TYPE == "pgsql") {
 -                      $result = db_query("DELETE FROM ttrss_user_entries
 +                      $sth = $pdo->prepare("DELETE FROM ttrss_user_entries
                                USING ttrss_entries
                                WHERE ttrss_entries.id = ref_id AND
                                marked = false AND
 -                              feed_id = '$feed_id' AND
 +                              feed_id = ? AND
                                $query_limit
                                ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
 +                      $sth->execute([$feed_id]);
  
                } else {
 -
 -/*                    $result = db_query("DELETE FROM ttrss_user_entries WHERE
 -                              marked = false AND feed_id = '$feed_id' AND
 -                              (SELECT date_updated FROM ttrss_entries WHERE
 -                                      id = ref_id) < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); */
 -
 -                      $result = db_query("DELETE FROM ttrss_user_entries
 +            $sth  = $pdo->prepare("DELETE FROM ttrss_user_entries
                                USING ttrss_user_entries, ttrss_entries
                                WHERE ttrss_entries.id = ref_id AND
                                marked = false AND
 -                              feed_id = '$feed_id' AND
 +                              feed_id = ? AND
                                $query_limit
                                ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)");
 +            $sth->execute([$feed_id]);
 +
                }
  
 -              $rows = db_affected_rows($result);
 +              $rows = $sth->rowCount();
  
                CCache::update($feed_id, $owner_uid);
  
  
        function feed_purge_interval($feed_id) {
  
 -              $result = db_query("SELECT purge_interval, owner_uid FROM ttrss_feeds
 -                      WHERE id = '$feed_id'");
 +          $pdo = DB::pdo();
  
 -              if (db_num_rows($result) == 1) {
 -                      $purge_interval = db_fetch_result($result, 0, "purge_interval");
 -                      $owner_uid = db_fetch_result($result, 0, "owner_uid");
 +              $sth = $pdo->prepare("SELECT purge_interval, owner_uid FROM ttrss_feeds
 +                      WHERE id = ?");
 +              $sth->execute([$feed_id]);
 +
 +              if ($row = $sth->fetch()) {
 +                      $purge_interval = $row["purge_interval"];
 +                      $owner_uid = $row["owner_uid"];
  
                        if ($purge_interval == 0) $purge_interval = get_pref(
                                'PURGE_OLD_DAYS', $owner_uid);
                }
        }
  
 -      /*function get_feed_update_interval($feed_id) {
 -              $result = db_query("SELECT owner_uid, update_interval FROM
 -                      ttrss_feeds WHERE id = '$feed_id'");
 -
 -              if (db_num_rows($result) == 1) {
 -                      $update_interval = db_fetch_result($result, 0, "update_interval");
 -                      $owner_uid = db_fetch_result($result, 0, "owner_uid");
 -
 -                      if ($update_interval != 0) {
 -                              return $update_interval;
 -                      } else {
 -                              return get_pref('DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
 -                      }
 -
 -              } else {
 -                      return -1;
 -              }
 -      }*/
 -
        // TODO: multiple-argument way is deprecated, first parameter is a hash now
        function fetch_file_contents($options /* previously: 0: $url , 1: $type = false, 2: $login = false, 3: $pass = false,
                                4: $post_query = false, 5: $timeout = false, 6: $timestamp = 0, 7: $useragent = false*/) {
  
        function initialize_user_prefs($uid, $profile = false) {
  
 -              $uid = db_escape_string($uid);
 +              if (get_schema_version() < 63) $profile_qpart = "";
  
 -              if (!$profile) {
 -                      $profile = "NULL";
 -                      $profile_qpart = "AND profile IS NULL";
 -              } else {
 -                      $profile_qpart = "AND profile = '$profile'";
 -              }
 +        $pdo = DB::pdo();
 +        $in_nested_tr = false;
  
 -              if (get_schema_version() < 63) $profile_qpart = "";
 +        try {
 +                      $pdo->beginTransaction();
 +              } catch (Exception $e) {
 +              $in_nested_tr = true;
 +              }
  
 -              db_query("BEGIN");
 +              $sth = $pdo->query("SELECT pref_name,def_value FROM ttrss_prefs");
  
 -              $result = db_query("SELECT pref_name,def_value FROM ttrss_prefs");
 +        $profile = $profile ? $profile : null;
  
 -              $u_result = db_query("SELECT pref_name
 -                      FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart");
 +              $u_sth = $pdo->prepare("SELECT pref_name
 +                      FROM ttrss_user_prefs WHERE owner_uid = :uid AND 
 +                              (profile = :profile OR (:profile IS NULL AND profile IS NULL))");
 +              $u_sth->execute([':uid' => $uid, ':profile' => $profile]);
  
                $active_prefs = array();
  
 -              while ($line = db_fetch_assoc($u_result)) {
 +              while ($line = $u_sth->fetch()) {
                        array_push($active_prefs, $line["pref_name"]);
                }
  
 -              while ($line = db_fetch_assoc($result)) {
 +              while ($line = $sth->fetch()) {
                        if (array_search($line["pref_name"], $active_prefs) === FALSE) {
  //                            print "adding " . $line["pref_name"] . "<br>";
  
 -                              $line["def_value"] = db_escape_string($line["def_value"]);
 -                              $line["pref_name"] = db_escape_string($line["pref_name"]);
 -
                                if (get_schema_version() < 63) {
 -                                      db_query("INSERT INTO ttrss_user_prefs
 +                                      $i_sth = $pdo->prepare("INSERT INTO ttrss_user_prefs
                                                (owner_uid,pref_name,value) VALUES
 -                                              ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')");
 +                                              (?, ?, ?)");
 +                                      $i_sth->execute([$uid, $line["pref_name"], $line["def_value"]]);
  
                                } else {
 -                                      db_query("INSERT INTO ttrss_user_prefs
 +                                      $i_sth = $pdo->prepare("INSERT INTO ttrss_user_prefs
                                                (owner_uid,pref_name,value, profile) VALUES
 -                                              ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)");
 +                                              (?, ?, ?, ?)");
 +                    $i_sth->execute([$uid, $line["pref_name"], $line["def_value"], $profile]);
                                }
  
                        }
                }
  
 -              db_query("COMMIT");
 +              if (!$in_nested_tr) $pdo->commit();
  
        }
  
                                $_SESSION["uid"] = $user_id;
                                $_SESSION["version"] = VERSION_STATIC;
  
 -                              $result = db_query("SELECT login,access_level,pwd_hash FROM ttrss_users
 -                                      WHERE id = '$user_id'");
 +                              $pdo = DB::pdo();
 +                              $sth = $pdo->prepare("SELECT login,access_level,pwd_hash FROM ttrss_users
 +                                      WHERE id = ?");
 +                              $sth->execute([$user_id]);
 +                              $row = $sth->fetch();
  
 -                              $_SESSION["name"] = db_fetch_result($result, 0, "login");
 -                              $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
 +                              $_SESSION["name"] = $row["login"];
 +                              $_SESSION["access_level"] = $row["access_level"];
                                $_SESSION["csrf_token"] = uniqid_short();
  
 -                              db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
 -                                      $_SESSION["uid"]);
 +                              $usth = $pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?");
 +                              $usth->execute([$user_id]);
  
                                $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
                                $_SESSION["user_agent"] = sha1($_SERVER['HTTP_USER_AGENT']);
 -                              $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash");
 +                              $_SESSION["pwd_hash"] = $row["pwd_hash"];
  
                                $_SESSION["last_version_check"] = time();
  
  
        function initialize_user($uid) {
  
 -              db_query("insert into ttrss_feeds (owner_uid,title,feed_url)
 -                      values ('$uid', 'Tiny Tiny RSS: Forum',
 +          $pdo = DB::pdo();
 +
 +              $sth = $pdo->prepare("insert into ttrss_feeds (owner_uid,title,feed_url)
 +                      values (?, 'Tiny Tiny RSS: Forum',
                                'http://tt-rss.org/forum/rss.php')");
 +              $sth->execute([$uid]);
        }
  
        function logout_user() {
        }
  
        function login_sequence() {
 +        $pdo = Db::pdo();
 +
                if (SINGLE_USER_MODE) {
                        @session_start();
                        authenticate_user("admin", null);
  
                        } else {
                                /* bump login timestamp */
 -                              db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
 -                                      $_SESSION["uid"]);
 +                              $sth = $pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?");
 +                              $sth->execute([$_SESSION['uid']]);
 +
                                $_SESSION["last_login_update"] = time();
                        }
  
  
                                /* cleanup ccache */
  
 -                              db_query("DELETE FROM ttrss_counters_cache WHERE owner_uid = ".
 -                                      $_SESSION["uid"] . " AND
 +                              $sth = $pdo->prepare("DELETE FROM ttrss_counters_cache WHERE owner_uid = ? 
 +                    AND
                                                (SELECT COUNT(id) FROM ttrss_feeds WHERE
                                                        ttrss_feeds.id = feed_id) = 0");
  
 -                              db_query("DELETE FROM ttrss_cat_counters_cache WHERE owner_uid = ".
 -                                      $_SESSION["uid"] . " AND
 +                              $sth->execute([$_SESSION['uid']]);
 +
 +                              $sth = $pdo->prepare("DELETE FROM ttrss_cat_counters_cache WHERE owner_uid = ? 
 +                    AND
                                                (SELECT COUNT(id) FROM ttrss_feed_categories WHERE
                                                        ttrss_feed_categories.id = feed_id) = 0");
  
 +                $sth->execute([$_SESSION['uid']]);
                        }
  
                }
        }
  
        function sql_bool_to_bool($s) {
 -              if ($s == "t" || $s == "1" || strtolower($s) == "true") {
 -                      return true;
 -              } else {
 -                      return false;
 -              }
 +              return $s && ($s !== "f" && $s !== "false"); //no-op for PDO, backwards compat for legacy layer
        }
  
        function bool_to_sql_bool($s) {
 -              if ($s) {
 -                      return "true";
 -              } else {
 -                      return "false";
 -              }
 +              return (bool)$s; //no-op for PDO
        }
  
        // Session caching removed due to causing wrong redirects to upgrade
        function get_schema_version($nocache = false) {
                global $schema_version;
  
 +              $pdo = DB::pdo();
 +
                if (!$schema_version && !$nocache) {
 -                      $result = db_query("SELECT schema_version FROM ttrss_version");
 -                      $version = db_fetch_result($result, 0, "schema_version");
 +                      $row = $pdo->query("SELECT schema_version FROM ttrss_version")->fetch();
 +                      $version = $row["schema_version"];
                        $schema_version = $version;
                        return $version;
                } else {
                        $error_code = 5;
                }
  
 -              if (DB_TYPE == "mysql") {
 -                      $result = db_query("SELECT true", false);
 -                      if (db_num_rows($result) != 1) {
 -                              $error_code = 10;
 -                      }
 -              }
 -
 -              if (db_escape_string("testTEST") != "testTEST") {
 -                      $error_code = 12;
 -              }
 -
                return array("code" => $error_code, "message" => $ERRORS[$error_code]);
        }
  
                return Feeds::getFeedArticles($feed, $is_cat, true, $_SESSION["uid"]);
        }
  
 -
 -      /*function get_pgsql_version() {
 -              $result = db_query("SELECT version() AS version");
 -              $version = explode(" ", db_fetch_result($result, 0, "version"));
 -              return $version[1];
 -      }*/
 -
        function checkbox_to_sql_bool($val) {
 -              return ($val == "on") ? "true" : "false";
 -      }
 -
 -      /*function getFeedCatTitle($id) {
 -              if ($id == -1) {
 -                      return __("Special");
 -              } else if ($id < LABEL_BASE_INDEX) {
 -                      return __("Labels");
 -              } else if ($id > 0) {
 -                      $result = db_query("SELECT ttrss_feed_categories.title
 -                              FROM ttrss_feeds, ttrss_feed_categories WHERE ttrss_feeds.id = '$id' AND
 -                                      cat_id = ttrss_feed_categories.id");
 -                      if (db_num_rows($result) == 1) {
 -                              return db_fetch_result($result, 0, "title");
 -                      } else {
 -                              return __("Uncategorized");
 -                      }
 -              } else {
 -                      return "getFeedCatTitle($id) failed";
 -              }
 -
 -      }*/
 +              return ($val == "on") ? true : false;
 +      }
  
        function uniqid_short() {
                return uniqid(base_convert(rand(), 10, 36));
  
                $params["sanity_checksum"] = sha1(file_get_contents("include/sanity_check.php"));
  
 -              $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
 -                              ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
 +              $pdo = Db::pdo();
  
 -              $max_feed_id = db_fetch_result($result, 0, "mid");
 -              $num_feeds = db_fetch_result($result, 0, "nf");
 +              $sth = $pdo->prepare("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
 +                              ttrss_feeds WHERE owner_uid = ?");
 +              $sth->execute([$_SESSION['uid']]);
 +              $row = $sth->fetch();
 +
 +              $max_feed_id = $row["mid"];
 +              $num_feeds = $row["nf"];
  
                $params["max_feed_id"] = (int) $max_feed_id;
                $params["num_feeds"] = (int) $num_feeds;
        function make_runtime_info($disable_update_check = false) {
                $data = array();
  
 -              $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
 -                              ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
 +              $pdo = Db::pdo();
 +
 +              $sth = $pdo->prepare("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
 +                              ttrss_feeds WHERE owner_uid = ?");
 +              $sth->execute([$_SESSION['uid']]);
 +              $row = $sth->fetch();
  
 -              $max_feed_id = db_fetch_result($result, 0, "mid");
 -              $num_feeds = db_fetch_result($result, 0, "nf");
 +              $max_feed_id = $row['mid'];
 +              $num_feeds = $row['nf'];
  
                $data["max_feed_id"] = (int) $max_feed_id;
                $data["num_feeds"] = (int) $num_feeds;
                $search_words = array();
                $search_query_leftover = array();
  
 +              $pdo = Db::pdo();
 +              
                if ($search_language)
 -                      $search_language = db_escape_string(mb_strtolower($search_language));
 +                      $search_language = $pdo->quote(mb_strtolower($search_language));
                else
                        $search_language = "english";
  
                        switch ($commandpair[0]) {
                                case "title":
                                        if ($commandpair[1]) {
 -                                              array_push($query_keywords, "($not (LOWER(ttrss_entries.title) LIKE '%".
 -                                                      db_escape_string(mb_strtolower($commandpair[1]))."%'))");
 +                                              array_push($query_keywords, "($not (LOWER(ttrss_entries.title) LIKE ".
 +                                                      $pdo->quote('%' . mb_strtolower($commandpair[1]) . '%') ."))");
                                        } else {
                                                array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                array_push($search_words, $k);
                                        }
                                        break;
                                case "author":
                                        if ($commandpair[1]) {
 -                                              array_push($query_keywords, "($not (LOWER(author) LIKE '%".
 -                                                      db_escape_string(mb_strtolower($commandpair[1]))."%'))");
 +                                              array_push($query_keywords, "($not (LOWER(author) LIKE ".
 +                                                      $pdo->quote('%' . mb_strtolower($commandpair[1]) . '%')."))");
                                        } else {
                                                array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                array_push($search_words, $k);
                                        }
                                        break;
                                                else if ($commandpair[1] == "false")
                                                        array_push($query_keywords, "($not (note IS NULL OR note = ''))");
                                                else
 -                                                      array_push($query_keywords, "($not (LOWER(note) LIKE '%".
 -                                                              db_escape_string(mb_strtolower($commandpair[1]))."%'))");
 +                                                      array_push($query_keywords, "($not (LOWER(note) LIKE ".
 +                                                              $pdo->quote('%' . mb_strtolower($commandpair[1]) . '%')."))");
                                        } else {
 -                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").")
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                if (!$not) array_push($search_words, $k);
                                        }
                                        break;
                                                else
                                                        array_push($query_keywords, "($not (marked = false))");
                                        } else {
 -                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").")
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                if (!$not) array_push($search_words, $k);
                                        }
                                        break;
  
                                        } else {
                                                array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                if (!$not) array_push($search_words, $k);
                                        }
                                        break;
                                                        array_push($query_keywords, "($not (unread = false))");
  
                                        } else {
 -                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                              array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").")
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                if (!$not) array_push($search_words, $k);
                                        }
                                        break;
                                                        $k = mb_strtolower($k);
                                                        array_push($search_query_leftover, $not ? "!$k" : $k);
                                                } else {
 -                                                      array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
 -                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
 +                                                      array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").")
 +                                                              OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))");
                                                }
  
                                                if (!$not) array_push($search_words, $k);
                }
  
                if (count($search_query_leftover) > 0) {
 -                      $search_query_leftover = db_escape_string(implode(" & ", $search_query_leftover));
 +                      $search_query_leftover = $pdo->quote(implode(" & ", $search_query_leftover));
  
                        if (DB_TYPE == "pgsql") {
                                array_push($query_keywords,
 -                                      "(tsvector_combined @@ to_tsquery('$search_language', '$search_query_leftover'))");
 +                                      "(tsvector_combined @@ to_tsquery($search_language, $search_query_leftover))");
                        }
  
                }
        function load_filters($feed_id, $owner_uid) {
                $filters = array();
  
 +              $feed_id = (int) $feed_id;
                $cat_id = (int)Feeds::getFeedCategory($feed_id);
  
                if ($cat_id == 0)
                else
                        $null_cat_qpart = "";
  
 -              $result = db_query("SELECT * FROM ttrss_filters2 WHERE
 -                              owner_uid = $owner_uid AND enabled = true ORDER BY order_id, title");
 +              $pdo = Db::pdo();
 +
 +              $sth = $pdo->prepare("SELECT * FROM ttrss_filters2 WHERE
 +                              owner_uid = ? AND enabled = true ORDER BY order_id, title");
 +              $sth->execute([$owner_uid]);
  
                $check_cats = array_merge(
                        Feeds::getParentCategories($cat_id, $owner_uid),
                $check_cats_str = join(",", $check_cats);
                $check_cats_fullids = array_map(function($a) { return "CAT:$a"; }, $check_cats);
  
 -              while ($line = db_fetch_assoc($result)) {
 +              while ($line = $sth->fetch()) {
                        $filter_id = $line["id"];
  
              $match_any_rule = sql_bool_to_bool($line["match_any_rule"]);
  
 -                      $result2 = db_query("SELECT
 +                      $sth2 = $pdo->prepare("SELECT
                                        r.reg_exp, r.inverse, r.feed_id, r.cat_id, r.cat_filter, r.match_on, t.name AS type_name
                                        FROM ttrss_filters2_rules AS r,
                                        ttrss_filter_types AS t
                                        WHERE
                                            (match_on IS NOT NULL OR
                                                  (($null_cat_qpart (cat_id IS NULL AND cat_filter = false) OR cat_id IN ($check_cats_str)) AND
 -                                                (feed_id IS NULL OR feed_id = '$feed_id'))) AND
 -                                              filter_type = t.id AND filter_id = '$filter_id'");
 +                                                (feed_id IS NULL OR feed_id = ?))) AND
 +                                              filter_type = t.id AND filter_id = ?");
 +                      $sth2->execute([$feed_id, $filter_id]);
  
                        $rules = array();
                        $actions = array();
  
 -                      while ($rule_line = db_fetch_assoc($result2)) {
 +                      while ($rule_line = $sth2->fetch()) {
        #                               print_r($rule_line);
  
                  if ($rule_line["match_on"]) {
                        }
  
                        if (count($rules) > 0) {
 -                $result2 = db_query("SELECT a.action_param,t.name AS type_name
 +                $sth2 = $pdo->prepare("SELECT a.action_param,t.name AS type_name
                          FROM ttrss_filters2_actions AS a,
                          ttrss_filter_actions AS t
                          WHERE
 -                            action_id = t.id AND filter_id = '$filter_id'");
 +                            action_id = t.id AND filter_id = ?");
 +                $sth2->execute([$filter_id]);
  
 -                while ($action_line = db_fetch_assoc($result2)) {
 +                while ($action_line = $sth2->fetch()) {
                      #                         print_r($action_line);
  
                      $action = array();
  
                if (!$feed_cat) return false;
  
 -              db_query("BEGIN");
 +              $feed_cat = mb_substr($feed_cat, 0, 250);
 +              if (!$parent_cat_id) $parent_cat_id = null;
  
 -              if ($parent_cat_id) {
 -                      $parent_qpart = "parent_cat = '$parent_cat_id'";
 -                      $parent_insert = "'$parent_cat_id'";
 -              } else {
 -                      $parent_qpart = "parent_cat IS NULL";
 -                      $parent_insert = "NULL";
 -              }
 +              $pdo = Db::pdo();
 +              $tr_in_progress = false;
  
 -              $feed_cat = mb_substr($feed_cat, 0, 250);
 +              try {
 +                      $pdo->beginTransaction();
 +              } catch (Exception $e) {
 +                      $tr_in_progress = true;
 +              }
  
 -              $result = db_query(
 -                      "SELECT id FROM ttrss_feed_categories
 -                              WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]);
 +              $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories
 +                              WHERE (parent_cat = :parent OR (:parent IS NULL AND parent_cat IS NULL)) 
 +                              AND title = :title AND owner_uid = :uid");
 +              $sth->execute([':parent' => $parent_cat_id, ':title' => $feed_cat, ':uid' => $_SESSION['uid']]);
  
 -              if (db_num_rows($result) == 0) {
 +              if (!$sth->fetch()) {
  
 -                      $result = db_query(
 -                              "INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat)
 -                                      VALUES ('".$_SESSION["uid"]."', '$feed_cat', $parent_insert)");
 +                      $sth = $pdo->prepare("INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat)
 +                                      VALUES (?, ?, ?)");
 +                      $sth->execute([$_SESSION['uid'], $feed_cat, $parent_cat_id]);
  
 -                      db_query("COMMIT");
 +                      if (!$tr_in_progress) $pdo->commit();
  
                        return true;
                }
  
 +        $pdo->commit();
 +
                return false;
        }
  
  
                if (!$owner_uid) $owner_uid = $_SESSION["uid"];
  
 -              $sql_is_cat = bool_to_sql_bool($is_cat);
 +              $is_cat = bool_to_sql_bool($is_cat);
 +
 +              $pdo = Db::pdo();
  
 -              $result = db_query("SELECT access_key FROM ttrss_access_keys
 -                              WHERE feed_id = '$feed_id'      AND is_cat = $sql_is_cat
 -                              AND owner_uid = " . $owner_uid);
 +              $sth = $pdo->prepare("SELECT access_key FROM ttrss_access_keys
 +                              WHERE feed_id = ? AND is_cat = ?
 +                              AND owner_uid = ?");
 +              $sth->execute([$feed_id, $is_cat, $owner_uid]);
  
 -              if (db_num_rows($result) == 1) {
 -                      return db_fetch_result($result, 0, "access_key");
 +              if ($row = $sth->fetch()) {
 +                      return $row["access_key"];
                } else {
 -                      $key = db_escape_string(uniqid_short());
 +                      $key = uniqid_short();
  
 -                      $result = db_query("INSERT INTO ttrss_access_keys
 +                      $sth = $pdo->prepare("INSERT INTO ttrss_access_keys
                                        (access_key, feed_id, is_cat, owner_uid)
 -                                      VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')");
 +                                      VALUES (?, ?, ?, ?)");
 +
 +                      $sth->execute([$key, $feed_id, $is_cat, $owner_uid]);
  
                        return $key;
                }
 -              return false;
        }
  
        function get_feeds_from_html($url, $content)
  
        function cleanup_tags($days = 14, $limit = 1000) {
  
 +          $days = (int) $days;
 +
                if (DB_TYPE == "pgsql") {
                        $interval_query = "date_updated < NOW() - INTERVAL '$days days'";
                } else if (DB_TYPE == "mysql") {
  
                $tags_deleted = 0;
  
 -              while ($limit > 0) {
 +        $pdo = Db::pdo();
 +
 +        while ($limit > 0) {
                        $limit_part = 500;
  
 -                      $query = "SELECT ttrss_tags.id AS id
 +                      $sth = $pdo->prepare("SELECT ttrss_tags.id AS id
                                        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 $limit_part";
 -
 -                      $result = db_query($query);
 +                                      ref_id = ttrss_entries.id AND tag_cache != '' LIMIT ?");
 +                      $sth->execute([$limit]);
  
                        $ids = array();
  
 -                      while ($line = db_fetch_assoc($result)) {
 +                      while ($line = $sth->fetch()) {
                                array_push($ids, $line['id']);
                        }
  
                        if (count($ids) > 0) {
                                $ids = join(",", $ids);
  
 -                              $tmp_result = db_query("DELETE FROM ttrss_tags WHERE id IN ($ids)");
 -                              $tags_deleted += db_affected_rows($tmp_result);
 +                              $usth = $pdo->query("DELETE FROM ttrss_tags WHERE id IN ($ids)");
 +                              $tags_deleted = $usth->rowCount();
                        } else {
                                break;
                        }
        function filter_to_sql($filter, $owner_uid) {
                $query = array();
  
 +              $pdo = Db::pdo();
 +
                if (DB_TYPE == "pgsql")
                        $reg_qpart = "~";
                else
  
                        if ($regexp_valid) {
  
 -                              $rule['reg_exp'] = db_escape_string($rule['reg_exp']);
 +                              $rule['reg_exp'] = $pdo->quote($rule['reg_exp']);
  
                                switch ($rule["type"]) {
                                        case "title":
                                if (isset($rule['inverse'])) $qpart = "NOT ($qpart)";
  
                                if (isset($rule["feed_id"]) && $rule["feed_id"] > 0) {
 -                                      $qpart .= " AND feed_id = " . db_escape_string($rule["feed_id"]);
 +                                      $qpart .= " AND feed_id = " . $pdo->quote($rule["feed_id"]);
                                }
  
                                if (isset($rule["cat_id"])) {
        }
  
        function check_mysql_tables() {
 -              $schema = db_escape_string(DB_NAME);
 +              $pdo = Db::pdo();
  
 -              $result = db_query("SELECT engine, table_name FROM information_schema.tables WHERE
 -                      table_schema = '$schema' AND table_name LIKE 'ttrss_%' AND engine != 'InnoDB'");
 +              $sth = $pdo->prepare("SELECT engine, table_name FROM information_schema.tables WHERE
 +                      table_schema = ? AND table_name LIKE 'ttrss_%' AND engine != 'InnoDB'");
 +              $sth->execute([DB_NAME]);
  
                $bad_tables = [];
  
 -              while ($line = db_fetch_assoc($result)) {
 +              while ($line = $sth->fetch()) {
                        array_push($bad_tables, $line);
                }
  
                return $bad_tables;
        }
  
 +    function arr_qmarks($arr) {
 +        return str_repeat('?,', count($arr) - 1) . '?';
 +    }