]> git.wh0rd.org - tt-rss.git/blobdiff - include/functions.php
Merge branch 'master' of git.fakecake.org:tt-rss into pdo-experimental
[tt-rss.git] / include / functions.php
index 5667ac416ec7b3dd7469f8e1678ec641d93ea87e..1d7033c899b46e773d4677a4df9c62947b3630b1 100644 (file)
 
                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) . '?';
+    }