diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/autoload.php | 14 | ||||
-rw-r--r-- | include/ccache.php | 78 | ||||
-rw-r--r-- | include/colors.php | 82 | ||||
-rw-r--r-- | include/crypt.php | 36 | ||||
-rw-r--r-- | include/db-prefs.php | 187 | ||||
-rw-r--r-- | include/db.php | 124 | ||||
-rw-r--r-- | include/digest.php | 64 | ||||
-rw-r--r-- | include/errorhandler.php | 39 | ||||
-rw-r--r-- | include/feedbrowser.php | 10 | ||||
-rw-r--r-- | include/functions.php | 1744 | ||||
-rw-r--r-- | include/labels.php | 89 | ||||
-rw-r--r-- | include/localized_schema.php | 65 | ||||
-rw-r--r-- | include/login_form.php | 44 | ||||
-rw-r--r-- | include/rssfuncs.php | 720 | ||||
-rw-r--r-- | include/sanity_check.php | 94 | ||||
-rw-r--r-- | include/sanity_config.php | 4 | ||||
-rw-r--r-- | include/sessions.php | 149 | ||||
-rw-r--r-- | include/version.php | 18 |
18 files changed, 1933 insertions, 1628 deletions
diff --git a/include/autoload.php b/include/autoload.php new file mode 100644 index 000000000..505b44477 --- /dev/null +++ b/include/autoload.php @@ -0,0 +1,14 @@ +<?php + require_once "functions.php"; + + function __autoload($class) { + $class_file = str_replace("_", "/", strtolower(basename($class))); + + $file = dirname(__FILE__)."/../classes/$class_file.php"; + + if (file_exists($file)) { + require $file; + } + + } +?> diff --git a/include/ccache.php b/include/ccache.php index c53b1a08c..d89b9efe0 100644 --- a/include/ccache.php +++ b/include/ccache.php @@ -1,19 +1,19 @@ <?php - /* function ccache_zero($link, $feed_id, $owner_uid) { - db_query($link, "UPDATE ttrss_counters_cache SET + /* function ccache_zero($feed_id, $owner_uid) { + db_query("UPDATE ttrss_counters_cache SET value = 0, updated = NOW() WHERE feed_id = '$feed_id' AND owner_uid = '$owner_uid'"); } */ - function ccache_zero_all($link, $owner_uid) { - db_query($link, "UPDATE ttrss_counters_cache SET + function ccache_zero_all($owner_uid) { + db_query("UPDATE ttrss_counters_cache SET value = 0 WHERE owner_uid = '$owner_uid'"); - db_query($link, "UPDATE ttrss_cat_counters_cache SET + db_query("UPDATE ttrss_cat_counters_cache SET value = 0 WHERE owner_uid = '$owner_uid'"); } - function ccache_remove($link, $feed_id, $owner_uid, $is_cat = false) { + function ccache_remove($feed_id, $owner_uid, $is_cat = false) { if (!$is_cat) { $table = "ttrss_counters_cache"; @@ -21,39 +21,39 @@ $table = "ttrss_cat_counters_cache"; } - db_query($link, "DELETE FROM $table WHERE + db_query("DELETE FROM $table WHERE feed_id = '$feed_id' AND owner_uid = '$owner_uid'"); } - function ccache_update_all($link, $owner_uid) { + function ccache_update_all($owner_uid) { - if (get_pref($link, 'ENABLE_FEED_CATS', $owner_uid)) { + if (get_pref('ENABLE_FEED_CATS', $owner_uid)) { - $result = db_query($link, "SELECT feed_id FROM ttrss_cat_counters_cache + $result = db_query("SELECT feed_id FROM ttrss_cat_counters_cache WHERE feed_id > 0 AND owner_uid = '$owner_uid'"); while ($line = db_fetch_assoc($result)) { - ccache_update($link, $line["feed_id"], $owner_uid, true); + ccache_update($line["feed_id"], $owner_uid, true); } /* We have to manually include category 0 */ - ccache_update($link, 0, $owner_uid, true); + ccache_update(0, $owner_uid, true); } else { - $result = db_query($link, "SELECT feed_id FROM ttrss_counters_cache + $result = db_query("SELECT feed_id FROM ttrss_counters_cache WHERE feed_id > 0 AND owner_uid = '$owner_uid'"); while ($line = db_fetch_assoc($result)) { - print ccache_update($link, $line["feed_id"], $owner_uid); + print ccache_update($line["feed_id"], $owner_uid); } } } - function ccache_find($link, $feed_id, $owner_uid, $is_cat = false, + function ccache_find($feed_id, $owner_uid, $is_cat = false, $no_update = false) { if (!is_numeric($feed_id)) return; @@ -61,7 +61,7 @@ if (!$is_cat) { $table = "ttrss_counters_cache"; /* if ($feed_id > 0) { - $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds + $tmp_result = db_query("SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid"); } */ @@ -75,7 +75,7 @@ $date_qpart = "updated > DATE_SUB(NOW(), INTERVAL 15 MINUTE)"; } - $result = db_query($link, "SELECT value FROM $table + $result = db_query("SELECT value FROM $table WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' LIMIT 1"); @@ -85,30 +85,30 @@ if ($no_update) { return -1; } else { - return ccache_update($link, $feed_id, $owner_uid, $is_cat); + return ccache_update($feed_id, $owner_uid, $is_cat); } } } - function ccache_update($link, $feed_id, $owner_uid, $is_cat = false, + function ccache_update($feed_id, $owner_uid, $is_cat = false, $update_pcat = true) { if (!is_numeric($feed_id)) return; /* if (!$is_cat && $feed_id > 0) { - $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds + $tmp_result = db_query("SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid"); } */ - $prev_unread = ccache_find($link, $feed_id, $owner_uid, $is_cat, true); + $prev_unread = ccache_find($feed_id, $owner_uid, $is_cat, true); /* When updating a label, all we need to do is recalculate feed counters * because labels are not cached */ if ($feed_id < 0) { - ccache_update_all($link, $owner_uid); + ccache_update_all($owner_uid); return; } @@ -127,14 +127,14 @@ /* Recalculate counters for child feeds */ - $result = db_query($link, "SELECT id FROM ttrss_feeds + $result = db_query("SELECT id FROM ttrss_feeds WHERE owner_uid = '$owner_uid' AND $cat_qpart"); while ($line = db_fetch_assoc($result)) { - ccache_update($link, $line["id"], $owner_uid, false, false); + ccache_update($line["id"], $owner_uid, false, false); } - $result = db_query($link, "SELECT SUM(value) AS sv + $result = db_query("SELECT SUM(value) AS sv FROM ttrss_counters_cache, ttrss_feeds WHERE id = feed_id AND $cat_qpart AND ttrss_feeds.owner_uid = '$owner_uid'"); @@ -142,27 +142,27 @@ $unread = (int) db_fetch_result($result, 0, "sv"); } else { - $unread = (int) getFeedArticles($link, $feed_id, $is_cat, true, $owner_uid); + $unread = (int) getFeedArticles($feed_id, $is_cat, true, $owner_uid); } - db_query($link, "BEGIN"); + db_query("BEGIN"); - $result = db_query($link, "SELECT feed_id FROM $table + $result = db_query("SELECT feed_id FROM $table WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' LIMIT 1"); if (db_num_rows($result) == 1) { - db_query($link, "UPDATE $table SET + db_query("UPDATE $table SET value = '$unread', updated = NOW() WHERE feed_id = '$feed_id' AND owner_uid = '$owner_uid'"); } else { - db_query($link, "INSERT INTO $table + db_query("INSERT INTO $table (feed_id, value, owner_uid, updated) VALUES ($feed_id, $unread, $owner_uid, NOW())"); } - db_query($link, "COMMIT"); + db_query("COMMIT"); if ($feed_id > 0 && $prev_unread != $unread) { @@ -172,36 +172,36 @@ if ($update_pcat) { - $result = db_query($link, "SELECT cat_id FROM ttrss_feeds + $result = db_query("SELECT cat_id FROM ttrss_feeds WHERE owner_uid = '$owner_uid' AND id = '$feed_id'"); $cat_id = (int) db_fetch_result($result, 0, "cat_id"); - ccache_update($link, $cat_id, $owner_uid, true); + ccache_update($cat_id, $owner_uid, true); } } } else if ($feed_id < 0) { - ccache_update_all($link, $owner_uid); + ccache_update_all($owner_uid); } return $unread; } - /* function ccache_cleanup($link, $owner_uid) { + /* function ccache_cleanup($owner_uid) { if (DB_TYPE == "pgsql") { - db_query($link, "DELETE FROM ttrss_counters_cache AS c1 WHERE + db_query("DELETE FROM ttrss_counters_cache AS c1 WHERE (SELECT count(*) FROM ttrss_counters_cache AS c2 WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1 AND owner_uid = '$owner_uid'"); - db_query($link, "DELETE FROM ttrss_cat_counters_cache AS c1 WHERE + db_query("DELETE FROM ttrss_cat_counters_cache AS c1 WHERE (SELECT count(*) FROM ttrss_cat_counters_cache AS c2 WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1 AND owner_uid = '$owner_uid'"); } else { - db_query($link, "DELETE c1 FROM + db_query("DELETE c1 FROM ttrss_counters_cache AS c1, ttrss_counters_cache AS c2 WHERE @@ -209,7 +209,7 @@ c1.owner_uid = c2.owner_uid AND c1.feed_id = c2.feed_id"); - db_query($link, "DELETE c1 FROM + db_query("DELETE c1 FROM ttrss_cat_counters_cache AS c1, ttrss_cat_counters_cache AS c2 WHERE diff --git a/include/colors.php b/include/colors.php index d1e970728..41bf7b819 100644 --- a/include/colors.php +++ b/include/colors.php @@ -1,5 +1,7 @@ <?php +require_once "lib/floIcon.php"; + function _resolve_htmlcolor($color) { $htmlcolors = array ("aliceblue" => "#f0f8ff", "antiquewhite" => "#faebd7", @@ -235,16 +237,16 @@ function rgb2hsl($arr) { } else { $s = $del_Max / $var_Max; - $del_R = ( ( ( $max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; - $del_G = ( ( ( $max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; - $del_B = ( ( ( $max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max; + $del_R = ((($var_Max - $var_R ) / 6 ) + ($del_Max / 2 ) ) / $del_Max; + $del_G = ((($var_Max - $var_G ) / 6 ) + ($del_Max / 2 ) ) / $del_Max; + $del_B = ((($var_Max - $var_B ) / 6 ) + ($del_Max / 2 ) ) / $del_Max; if ($var_R == $var_Max) $h = $del_B - $del_G; - else if ($var_G == $var_Max) $h = ( 1 / 3 ) + $del_R - $del_B; - else if ($var_B == $var_Max) $h = ( 2 / 3 ) + $del_G - $del_R; + else if ($var_G == $var_Max) $h = (1 / 3 ) + $del_R - $del_B; + else if ($var_B == $var_Max) $h = (2 / 3 ) + $del_G - $del_R; - if ($H < 0) $h++; - if ($H > 1) $h--; + if ($h < 0) $h++; + if ($h > 1) $h--; } return array($h, $s, $v); @@ -259,10 +261,10 @@ function hsl2rgb($arr) { $r = $g = $B = $v * 255; } else { $var_H = $h * 6; - $var_i = floor( $var_H ); - $var_1 = $v * ( 1 - $s ); - $var_2 = $v * ( 1 - $s * ( $var_H - $var_i ) ); - $var_3 = $v * ( 1 - $s * (1 - ( $var_H - $var_i ) ) ); + $var_i = floor($var_H ); + $var_1 = $v * (1 - $s ); + $var_2 = $v * (1 - $s * ($var_H - $var_i ) ); + $var_3 = $v * (1 - $s * (1 - ($var_H - $var_i ) ) ); if ($var_i == 0) { $var_R = $v ; $var_G = $var_3 ; $var_B = $var_1 ; } else if ($var_i == 1) { $var_R = $var_2 ; $var_G = $v ; $var_B = $var_1 ; } @@ -278,4 +280,62 @@ function hsl2rgb($arr) { return array($r, $g, $B); } + function colorPalette($imageFile, $numColors, $granularity = 5) { + $granularity = max(1, abs((int)$granularity)); + $colors = array(); + + $size = @getimagesize($imageFile); + + if (!defined('_DISABLE_FLOICON') && strtolower($size['mime']) == 'image/vnd.microsoft.icon') { + $ico = new floIcon(); + @$ico->readICO($imageFile); + + if(count($ico->images)==0) + return null; + else + $img = @$ico->images[count($ico->images)-1]->getImageResource(); + + } else { + $img = @imagecreatefromstring(file_get_contents($imageFile)); + } + + if (!$img) return false; + + for($x = 0; $x < $size[0]; $x += $granularity) { + for($y = 0; $y < $size[1]; $y += $granularity) { + $thisColor = imagecolorat($img, $x, $y); + $rgb = imagecolorsforindex($img, $thisColor); + $red = round(round(($rgb['red'] / 0x33)) * 0x33); + $green = round(round(($rgb['green'] / 0x33)) * 0x33); + $blue = round(round(($rgb['blue'] / 0x33)) * 0x33); + $thisRGB = sprintf('%02X%02X%02X', $red, $green, $blue); + if(array_key_exists($thisRGB, $colors)) { + $colors[$thisRGB]++; + } else{ + $colors[$thisRGB] = 1; + } + } + } + + arsort($colors); + return array_slice(array_keys($colors), 0, $numColors); + } + + function calculate_avg_color($iconFile) { + $palette = colorPalette($iconFile, 4, 4); + + if (is_array($palette)) { + foreach ($palette as $p) { + $hsl = rgb2hsl(_color_unpack("#$p")); + + if ($hsl[1] > 0.25 && $hsl[2] > 0.25 && + !($hsl[0] >= 0 && $hsl[0] < 0.01 && $hsl[1] < 0.01) && + !($hsl[0] >= 0 && $hsl[0] < 0.01 && $hsl[2] > 0.99)) { + + return _color_pack(hsl2rgb($hsl)); + } + } + } + return ''; + } ?> diff --git a/include/crypt.php b/include/crypt.php new file mode 100644 index 000000000..f06483ef1 --- /dev/null +++ b/include/crypt.php @@ -0,0 +1,36 @@ +<?php + function decrypt_string($str) { + $pair = explode(":", $str); + + if (count($pair) == 2) { + @$iv = base64_decode($pair[0]); + @$encstr = base64_decode($pair[1]); + + if ($iv && $encstr) { + $key = hash('SHA256', FEED_CRYPT_KEY, true); + + $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encstr, + MCRYPT_MODE_CBC, $iv); + + if ($str) return rtrim($str); + } + } + + return false; + } + + function encrypt_string($str) { + $key = hash('SHA256', FEED_CRYPT_KEY, true); + + $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, + MCRYPT_MODE_CBC), MCRYPT_RAND); + + $encstr = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, + MCRYPT_MODE_CBC, $iv); + + $iv_base64 = base64_encode($iv); + $encstr_base64 = base64_encode($encstr); + + return "$iv_base64:$encstr_base64"; + } +?> diff --git a/include/db-prefs.php b/include/db-prefs.php index 641e9d1dd..d122f3baf 100644 --- a/include/db-prefs.php +++ b/include/db-prefs.php @@ -1,190 +1,11 @@ <?php - require_once "config.php"; require_once "db.php"; - if (!defined('DISABLE_SESSIONS') && !defined('PREFS_NO_CACHE')) { - if (!$_SESSION["prefs_cache"]) - $_SESSION["prefs_cache"] = array(); + function get_pref($pref_name, $user_id = false, $die_on_error = false) { + return Db_Prefs::get()->read($pref_name, $user_id, $die_on_error); } - function cache_prefs($link) { - $profile = false; - - $user_id = $_SESSION["uid"]; - @$profile = $_SESSION["profile"]; - - if ($profile) { - $profile_qpart = "profile = '$profile' AND"; - } else { - $profile_qpart = "profile IS NULL AND"; - } - - if (get_schema_version($link) < 63) $profile_qpart = ""; - - $result = db_query($link, "SELECT - value,ttrss_prefs_types.type_name as type_name,ttrss_prefs.pref_name AS pref_name - FROM - ttrss_user_prefs,ttrss_prefs,ttrss_prefs_types - WHERE - $profile_qpart - ttrss_prefs.pref_name NOT LIKE '_MOBILE%' AND - ttrss_prefs_types.id = type_id AND - owner_uid = '$user_id' AND - ttrss_user_prefs.pref_name = ttrss_prefs.pref_name"); - - while ($line = db_fetch_assoc($result)) { - if ($user_id == $_SESSION["uid"]) { - $pref_name = $line["pref_name"]; - - $_SESSION["prefs_cache"][$pref_name]["type"] = $line["type_name"]; - $_SESSION["prefs_cache"][$pref_name]["value"] = $line["value"]; - } - } - } - - function get_pref($link, $pref_name, $user_id = false, $die_on_error = false) { - - $pref_name = db_escape_string($pref_name); - $prefs_cache = true; - $profile = false; - - if (!$user_id) { - $user_id = $_SESSION["uid"]; - @$profile = $_SESSION["profile"]; - } else { - $user_id = sprintf("%d", $user_id); - //$prefs_cache = false; - } - - if ($prefs_cache && !defined('DISABLE_SESSIONS') && !defined('PREFS_NO_CACHE')) { - if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) { - $tuple = $_SESSION["prefs_cache"][$pref_name]; - return convert_pref_type($tuple["value"], $tuple["type"]); - } - } - - if ($profile) { - $profile_qpart = "profile = '$profile' AND"; - } else { - $profile_qpart = "profile IS NULL AND"; - } - - if (get_schema_version($link) < 63) $profile_qpart = ""; - - $result = db_query($link, "SELECT - value,ttrss_prefs_types.type_name as type_name - FROM - ttrss_user_prefs,ttrss_prefs,ttrss_prefs_types - WHERE - $profile_qpart - ttrss_user_prefs.pref_name = '$pref_name' AND - ttrss_prefs_types.id = type_id AND - owner_uid = '$user_id' AND - ttrss_user_prefs.pref_name = ttrss_prefs.pref_name"); - - if (db_num_rows($result) > 0) { - $value = db_fetch_result($result, 0, "value"); - $type_name = db_fetch_result($result, 0, "type_name"); - - if (!defined('DISABLE_SESSIONS')) { - if ($user_id == $_SESSION["uid"]) { - $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name; - $_SESSION["prefs_cache"][$pref_name]["value"] = $value; - } - } - - return convert_pref_type($value, $type_name); - - } else { - if ($die_on_error) { - die("Fatal error, unknown preferences key: $pref_name"); - } else { - return null; - } - } - } - - function convert_pref_type($value, $type_name) { - if ($type_name == "bool") { - return $value == "true"; - } else if ($type_name == "integer") { - return sprintf("%d", $value); - } else { - return $value; - } - } - - function set_pref($link, $pref_name, $value, $user_id = false, $strip_tags = true) { - $pref_name = db_escape_string($pref_name); - $value = db_escape_string($value, $strip_tags); - - if (!$user_id) { - $user_id = $_SESSION["uid"]; - @$profile = $_SESSION["profile"]; - } else { - $user_id = sprintf("%d", $user_id); - $prefs_cache = false; - } - - if ($profile) { - $profile_qpart = "AND profile = '$profile'"; - } else { - $profile_qpart = "AND profile IS NULL"; - } - - if (get_schema_version($link) < 63) $profile_qpart = ""; - - $type_name = ""; - $current_value = ""; - - if (!defined('DISABLE_SESSIONS') && !defined('PREFS_NO_CACHE')) { - if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) { - $type_name = $_SESSION["prefs_cache"][$pref_name]["type"]; - $current_value = $_SESSION["prefs_cache"][$pref_name]["value"]; - } - } - - if (!$type_name) { - $result = db_query($link, "SELECT type_name - FROM ttrss_prefs,ttrss_prefs_types - WHERE pref_name = '$pref_name' AND type_id = ttrss_prefs_types.id"); - - if (db_num_rows($result) > 0) - $type_name = db_fetch_result($result, 0, "type_name"); - } else if ($current_value == $value) { - return; - } - - if ($type_name) { - if ($type_name == "bool") { - if ($value == "1" || $value == "true") { - $value = "true"; - } else { - $value = "false"; - } - } else if ($type_name == "integer") { - $value = sprintf("%d", $value); - } - - if ($pref_name == 'DEFAULT_ARTICLE_LIMIT' && $value == 0) { - $value = 30; - } - - if ($pref_name == 'USER_TIMEZONE' && $value == '') { - $value = 'UTC'; - } - - db_query($link, "UPDATE ttrss_user_prefs SET - value = '$value' WHERE pref_name = '$pref_name' - $profile_qpart - AND owner_uid = " . $_SESSION["uid"]); - - if (!defined('DISABLE_SESSIONS')) { - if ($user_id == $_SESSION["uid"]) { - $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name; - $_SESSION["prefs_cache"][$pref_name]["value"] = $value; - } - } - } + function set_pref($pref_name, $value, $user_id = false, $strip_tags = true) { + return Db_Prefs::get()->write($pref_name, $value, $user_id, $strip_tags); } ?> diff --git a/include/db.php b/include/db.php index f1a7af363..55d1d654e 100644 --- a/include/db.php +++ b/include/db.php @@ -1,138 +1,36 @@ <?php -require_once "config.php"; - -function db_connect($host, $user, $pass, $db) { - if (DB_TYPE == "pgsql") { - - $string = "dbname=$db user=$user"; - - if ($pass) { - $string .= " password=$pass"; - } - - if ($host) { - $string .= " host=$host"; - } - - if (defined('DB_PORT')) { - $string = "$string port=" . DB_PORT; - } - - $link = pg_connect($string); - - if (!$link) { - die("Unable to connect to database (as $user to $host, database $db):" . pg_last_error()); - } - - return $link; - - } else if (DB_TYPE == "mysql") { - $link = mysql_connect($host, $user, $pass); - if ($link) { - $result = mysql_select_db($db, $link); - if (!$result) { - die("Can't select DB: " . mysql_error($link)); - } - return $link; - } else { - die("Unable to connect to database (as $user to $host, database $db): " . mysql_error()); - } - } -} - function db_escape_string($s, $strip_tags = true) { - if ($strip_tags) $s = strip_tags($s); - - if (DB_TYPE == "pgsql") { - return pg_escape_string($s); - } else { - return mysql_real_escape_string($s); - } + return Db::get()->escape_string($s, $strip_tags); } -function db_query($link, $query, $die_on_error = true) { - if (DB_TYPE == "pgsql") { - $result = pg_query($link, $query); - if (!$result) { - $query = htmlspecialchars($query); // just in case - if ($die_on_error) { - die("Query <i>$query</i> failed [$result]: " . ($link ? pg_last_error($link) : "No connection")); - } - } - return $result; - } else if (DB_TYPE == "mysql") { - $result = mysql_query($query, $link); - if (!$result) { - $query = htmlspecialchars($query); - if ($die_on_error) { - die("Query <i>$query</i> failed: " . ($link ? mysql_error($link) : "No connection")); - } - } - return $result; - } +function db_query($query, $die_on_error = true) { + return Db::get()->query($query, $die_on_error); } function db_fetch_assoc($result) { - if (DB_TYPE == "pgsql") { - return pg_fetch_assoc($result); - } else if (DB_TYPE == "mysql") { - return mysql_fetch_assoc($result); - } + return Db::get()->fetch_assoc($result); } function db_num_rows($result) { - if (DB_TYPE == "pgsql") { - return pg_num_rows($result); - } else if (DB_TYPE == "mysql") { - return mysql_num_rows($result); - } + return Db::get()->num_rows($result); } function db_fetch_result($result, $row, $param) { - if (DB_TYPE == "pgsql") { - return pg_fetch_result($result, $row, $param); - } else if (DB_TYPE == "mysql") { - // I hate incoherent naming of PHP functions - return mysql_result($result, $row, $param); - } -} - -function db_unescape_string($str) { - $tmp = str_replace("\\\"", "\"", $str); - $tmp = str_replace("\\'", "'", $tmp); - return $tmp; -} - -function db_close($link) { - if (DB_TYPE == "pgsql") { - - return pg_close($link); - - } else if (DB_TYPE == "mysql") { - return mysql_close($link); - } + return Db::get()->fetch_result($result, $row, $param); } -function db_affected_rows($link, $result) { - if (DB_TYPE == "pgsql") { - return pg_affected_rows($result); - } else if (DB_TYPE == "mysql") { - return mysql_affected_rows($link); - } +function db_affected_rows($result) { + return Db::get()->affected_rows($result); } -function db_last_error($link) { - if (DB_TYPE == "pgsql") { - return pg_last_error($link); - } else if (DB_TYPE == "mysql") { - return mysql_error($link); - } +function db_last_error() { + return Db::get()->last_error(); } function db_quote($str){ - return("'$str'"); + return Db::get()->quote($str); } ?> diff --git a/include/digest.php b/include/digest.php index 93ce373a2..965fd1a79 100644 --- a/include/digest.php +++ b/include/digest.php @@ -6,9 +6,9 @@ * @param integer $limit The maximum number of articles by digest. * @return boolean Return false if digests are not enabled. */ - function send_headlines_digests($link, $debug = false) { + function send_headlines_digests($debug = false) { - require_once 'lib/phpmailer/class.phpmailer.php'; + require_once 'classes/ttrssmailer.php'; $user_limit = 15; // amount of users to process (e.g. emails to send out) $limit = 1000; // maximum amount of headlines to include @@ -21,28 +21,28 @@ $interval_query = "last_digest_sent < DATE_SUB(NOW(), INTERVAL 1 DAY)"; } - $result = db_query($link, "SELECT id,email FROM ttrss_users + $result = db_query("SELECT id,email FROM ttrss_users WHERE email != '' AND (last_digest_sent IS NULL OR $interval_query)"); while ($line = db_fetch_assoc($result)) { - if (get_pref($link, 'DIGEST_ENABLE', $line['id'], false)) { - $preferred_ts = strtotime(get_pref($link, 'DIGEST_PREFERRED_TIME', $line['id'], '00:00')); + if (get_pref('DIGEST_ENABLE', $line['id'], false)) { + $preferred_ts = strtotime(get_pref('DIGEST_PREFERRED_TIME', $line['id'], '00:00')); // try to send digests within 2 hours of preferred time if ($preferred_ts && time() >= $preferred_ts && time() - $preferred_ts <= 7200) { - if ($debug) print "Sending digest for UID:" . $line['id'] . " - " . $line["email"] . " ... "; + if ($debug) _debug("Sending digest for UID:" . $line['id'] . " - " . $line["email"]); - $do_catchup = get_pref($link, 'DIGEST_CATCHUP', $line['id'], false); + $do_catchup = get_pref('DIGEST_CATCHUP', $line['id'], false); global $tz_offset; // reset tz_offset global to prevent tz cache clash between users $tz_offset = -1; - $tuple = prepare_headlines_digest($link, $line["id"], 1, $limit); + $tuple = prepare_headlines_digest($line["id"], 1, $limit); $digest = $tuple[0]; $headlines_count = $tuple[1]; $affected_ids = $tuple[2]; @@ -50,45 +50,23 @@ if ($headlines_count > 0) { - $mail = new PHPMailer(); + $mail = new ttrssMailer(); - $mail->PluginDir = "lib/phpmailer/"; - $mail->SetLanguage("en", "lib/phpmailer/language/"); + $rc = $mail->quickMail($line["email"], $line["login"] , DIGEST_SUBJECT, $digest, $digest_text); - $mail->CharSet = "UTF-8"; + if (!$rc && $debug) _debug("ERROR: " . $mail->ErrorInfo); - $mail->From = SMTP_FROM_ADDRESS; - $mail->FromName = SMTP_FROM_NAME; - $mail->AddAddress($line["email"], $line["login"]); - - if (SMTP_HOST) { - $mail->Host = SMTP_HOST; - $mail->Mailer = "smtp"; - $mail->SMTPAuth = SMTP_LOGIN != ''; - $mail->Username = SMTP_LOGIN; - $mail->Password = SMTP_PASSWORD; - } - - $mail->IsHTML(true); - $mail->Subject = DIGEST_SUBJECT; - $mail->Body = $digest; - $mail->AltBody = $digest_text; - - $rc = $mail->Send(); - - if (!$rc && $debug) print "ERROR: " . $mail->ErrorInfo; - - if ($debug) print "RC=$rc\n"; + if ($debug) _debug("RC=$rc"); if ($rc && $do_catchup) { - if ($debug) print "Marking affected articles as read...\n"; - catchupArticlesById($link, $affected_ids, 0, $line["id"]); + if ($debug) _debug("Marking affected articles as read..."); + catchupArticlesById($affected_ids, 0, $line["id"]); } } else { - if ($debug) print "No headlines\n"; + if ($debug) _debug("No headlines"); } - db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW() + db_query("UPDATE ttrss_users SET last_digest_sent = NOW() WHERE id = " . $line["id"]); } @@ -99,7 +77,7 @@ } - function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 1000) { + function prepare_headlines_digest($user_id, $days = 1, $limit = 1000) { require_once "lib/MiniTemplator.class.php"; @@ -109,7 +87,7 @@ $tpl->readTemplateFromFile("templates/digest_template_html.txt"); $tpl_t->readTemplateFromFile("templates/digest_template.txt"); - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $user_id); + $user_tz_string = get_pref('USER_TIMEZONE', $user_id); $local_ts = convert_timestamp(time(), 'UTC', $user_tz_string); $tpl->setVariable('CUR_DATE', date('Y/m/d', $local_ts)); @@ -126,7 +104,7 @@ $interval_query = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)"; } - $result = db_query($link, "SELECT ttrss_entries.title, + $result = db_query("SELECT ttrss_entries.title, ttrss_feeds.title AS feed_title, COALESCE(ttrss_feed_categories.title, '".__('Uncategorized')."') AS cat_title, date_updated, @@ -165,7 +143,7 @@ array_push($affected_ids, $line["ref_id"]); - $updated = make_local_datetime($link, $line['last_updated'], false, + $updated = make_local_datetime($line['last_updated'], false, $user_id); /* if ($line["score"] != 0) { @@ -174,7 +152,7 @@ $line["title"] .= " (".$line['score'].")"; } */ - if (get_pref($link, 'ENABLE_FEED_CATS', $user_id)) { + if (get_pref('ENABLE_FEED_CATS', $user_id)) { $line['feed_title'] = $line['cat_title'] . " / " . $line['feed_title']; } diff --git a/include/errorhandler.php b/include/errorhandler.php new file mode 100644 index 000000000..52431c2de --- /dev/null +++ b/include/errorhandler.php @@ -0,0 +1,39 @@ +<?php +function ttrss_error_handler($errno, $errstr, $file, $line, $context) { + global $logger; + + if (error_reporting() == 0 || !$errno) return false; + + $file = substr(str_replace(dirname(dirname(__FILE__)), "", $file), 1); + + if (class_exists("Logger")) + return Logger::get()->log_error($errno, $errstr, $file, $line, $context); +} + +function ttrss_fatal_handler() { + global $logger; + + $error = error_get_last(); + + if ($error !== NULL) { + $errno = $error["type"]; + $file = $error["file"]; + $line = $error["line"]; + $errstr = $error["message"]; + + if (!$errno) return false; + + $context = debug_backtrace(); + + $file = substr(str_replace(dirname(dirname(__FILE__)), "", $file), 1); + + if (class_exists("Logger")) + return Logger::get()->log_error($errno, $errstr, $file, $line, $context); + } + + return false; +} + +register_shutdown_function('ttrss_fatal_handler'); +set_error_handler('ttrss_error_handler'); +?> diff --git a/include/feedbrowser.php b/include/feedbrowser.php index 5b33fb73c..6c245121f 100644 --- a/include/feedbrowser.php +++ b/include/feedbrowser.php @@ -1,5 +1,5 @@ <?php - function make_feed_browser($link, $search, $limit, $mode = 1) { + function make_feed_browser($search, $limit, $mode = 1) { $owner_uid = $_SESSION["uid"]; $rv = ''; @@ -12,13 +12,13 @@ } if ($mode == 1) { - /* $result = db_query($link, "SELECT feed_url, subscribers FROM + /* $result = db_query("SELECT feed_url, subscribers FROM ttrss_feedbrowser_cache WHERE (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf WHERE tf.feed_url = ttrss_feedbrowser_cache.feed_url AND owner_uid = '$owner_uid') $search_qpart ORDER BY subscribers DESC LIMIT $limit"); */ - $result = db_query($link, "SELECT feed_url, site_url, title, SUM(subscribers) AS subscribers FROM + $result = db_query("SELECT feed_url, site_url, title, SUM(subscribers) AS subscribers FROM (SELECT feed_url, site_url, title, subscribers FROM ttrss_feedbrowser_cache UNION ALL SELECT feed_url, site_url, title, subscribers FROM ttrss_linked_feeds) AS qqq WHERE @@ -28,7 +28,7 @@ GROUP BY feed_url, site_url, title ORDER BY subscribers DESC LIMIT $limit"); } else if ($mode == 2) { - $result = db_query($link, "SELECT *, + $result = db_query("SELECT *, (SELECT COUNT(*) FROM ttrss_user_entries WHERE orig_feed_id = ttrss_archived_feeds.id) AS articles_archived FROM @@ -80,7 +80,7 @@ $class = ($feedctr % 2) ? "even" : "odd"; if ($line['articles_archived'] > 0) { - $archived = sprintf(__("%d archived articles"), $line['articles_archived']); + $archived = sprintf(ngettext("%d archived article", "%d archived articles", $line['articles_archived']), $line['articles_archived']); $archived = " <span class='subscribers'>($archived)</span>"; } else { $archived = ''; diff --git a/include/functions.php b/include/functions.php index f17828d1d..149809a35 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1,20 +1,16 @@ <?php define('EXPECTED_CONFIG_VERSION', 26); - define('SCHEMA_VERSION', 104); + define('SCHEMA_VERSION', 120); - $fetch_last_error = false; - $pluginhost = false; - - function __autoload($class) { - $class_file = str_replace("_", "/", strtolower(basename($class))); - - $file = dirname(__FILE__)."/../classes/$class_file.php"; + define('LABEL_BASE_INDEX', -1024); + define('PLUGIN_FEED_BASE_INDEX', -128); - if (file_exists($file)) { - require $file; - } + define('COOKIE_LIFETIME_LONG', 86400*365); - } + $fetch_last_error = false; + $fetch_last_error_code = false; + $fetch_last_content_type = false; + $fetch_curl_used = false; mb_internal_encoding("UTF-8"); date_default_timezone_set('UTC'); @@ -26,14 +22,37 @@ require_once 'config.php'; + /** + * Define a constant if not already defined + * + * @param string $name The constant name. + * @param mixed $value The constant value. + * @access public + * @return boolean True if defined successfully or not. + */ + function define_default($name, $value) { + defined($name) or define($name, $value); + } + + ///// Some defaults that you can override in config.php ////// + + define_default('FEED_FETCH_TIMEOUT', 45); + // How may seconds to wait for response when requesting feed from a site + define_default('FEED_FETCH_NO_CACHE_TIMEOUT', 15); + // How may seconds to wait for response when requesting feed from a + // site when that feed wasn't cached before + define_default('FILE_FETCH_TIMEOUT', 45); + // Default timeout when fetching files from remote sites + define_default('FILE_FETCH_CONNECT_TIMEOUT', 15); + // How many seconds to wait for initial response from website when + // fetching files from remote sites + if (DB_TYPE == "pgsql") { define('SUBSTRING_FOR_DATE', 'SUBSTRING_FOR_DATE'); } else { define('SUBSTRING_FOR_DATE', 'SUBSTRING'); } - define('THEME_VERSION_REQUIRED', 1.1); - /** * Return available translations names. * @@ -44,6 +63,7 @@ $tr = array( "auto" => "Detect automatically", "ca_CA" => "Català", + "cs_CZ" => "Česky", "en_US" => "English", "es_ES" => "Español", "de_DE" => "Deutsch", @@ -51,11 +71,15 @@ "hu_HU" => "Magyar (Hungarian)", "it_IT" => "Italiano", "ja_JP" => "日本語 (Japanese)", + "lv_LV" => "Latviešu", "nb_NO" => "Norwegian bokmål", + "nl_NL" => "Dutch", "pl_PL" => "Polski", "ru_RU" => "Русский", "pt_BR" => "Portuguese/Brazil", - "zh_CN" => "Simplified Chinese"); + "zh_CN" => "Simplified Chinese", + "sv_SE" => "Svenska", + "fi_FI" => "Suomi"); return $tr; } @@ -73,11 +97,12 @@ $lang = _TRANSLATION_OVERRIDE_DEFAULT; } - /* In login action of mobile version */ - if ($_POST["language"] && defined('MOBILE_VERSION')) { - $lang = $_POST["language"]; - } else if ($_SESSION["language"] && $_SESSION["language"] != "auto") { - $lang = $_SESSION["language"]; + if ($_SESSION["uid"] && get_schema_version() >= 120) { + $pref_lang = get_pref("USER_LANGUAGE", $_SESSION["uid"]); + + if ($pref_lang) { + $lang = $pref_lang; + } } if ($lang) { @@ -87,19 +112,13 @@ _setlocale(LC_ALL, $lang); } - if (defined('MOBILE_VERSION')) { - _bindtextdomain("messages", "../locale"); - } else { - _bindtextdomain("messages", "locale"); - } + _bindtextdomain("messages", "locale"); _textdomain("messages"); _bind_textdomain_codeset("messages", "UTF-8"); } } - startup_gettext(); - require_once 'db-prefs.php'; require_once 'version.php'; require_once 'ccache.php'; @@ -109,10 +128,7 @@ ini_set('user_agent', SELF_USER_AGENT); require_once 'lib/pubsubhubbub/publisher.php'; - require_once 'lib/htmLawed.php'; - $tz_offset = -1; - $utc_tz = new DateTimeZone('UTC'); $schema_version = false; /** @@ -121,15 +137,26 @@ * @param string $msg The debug message. * @return void */ - function _debug($msg) { - if (defined('QUIET') && QUIET) { - return; - } + function _debug($msg, $show = true) { + $ts = strftime("%H:%M:%S", time()); if (function_exists('posix_getpid')) { $ts = "$ts/" . posix_getpid(); } - print "[$ts] $msg\n"; + + if ($show && !(defined('QUIET') && QUIET)) { + print "[$ts] $msg\n"; + } + + if (defined('LOGFILE')) { + $fp = fopen(LOGFILE, 'a+'); + + if ($fp) { + fputs($fp, "[$ts] $msg\n"); + fclose($fp); + } + } + } // function _debug /** @@ -142,13 +169,13 @@ * @access public * @return void */ - function purge_feed($link, $feed_id, $purge_interval, $debug = false) { + function purge_feed($feed_id, $purge_interval, $debug = false) { - if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id); + if (!$purge_interval) $purge_interval = feed_purge_interval($feed_id); $rows = -1; - $result = db_query($link, + $result = db_query( "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); $owner_uid = false; @@ -159,7 +186,7 @@ if ($purge_interval == -1 || !$purge_interval) { if ($owner_uid) { - ccache_update($link, $feed_id, $owner_uid); + ccache_update($feed_id, $owner_uid); } return; } @@ -167,7 +194,7 @@ if (!$owner_uid) return; if (FORCE_ARTICLE_PURGE == 0) { - $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES", + $purge_unread = get_pref("PURGE_UNREAD_ARTICLES", $owner_uid, false); } else { $purge_unread = true; @@ -177,11 +204,11 @@ if (!$purge_unread) $query_limit = " unread = false AND "; if (DB_TYPE == "pgsql") { - $pg_version = get_pgsql_version($link); + $pg_version = get_pgsql_version(); if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) { - $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE + $result = db_query("DELETE FROM ttrss_user_entries WHERE ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND @@ -190,7 +217,7 @@ } else { - $result = db_query($link, "DELETE FROM ttrss_user_entries + $result = db_query("DELETE FROM ttrss_user_entries USING ttrss_entries WHERE ttrss_entries.id = ref_id AND marked = false AND @@ -199,28 +226,25 @@ ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'"); } - $rows = pg_affected_rows($result); - } else { -/* $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE +/* $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($link, "DELETE FROM ttrss_user_entries + $result = db_query("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 $query_limit ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); - - $rows = mysql_affected_rows($link); - } - ccache_update($link, $feed_id, $owner_uid); + $rows = db_affected_rows($result); + + ccache_update($feed_id, $owner_uid); if ($debug) { _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles"); @@ -229,16 +253,16 @@ return $rows; } // function purge_feed - function feed_purge_interval($link, $feed_id) { + function feed_purge_interval($feed_id) { - $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds + $result = db_query("SELECT purge_interval, owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); if (db_num_rows($result) == 1) { $purge_interval = db_fetch_result($result, 0, "purge_interval"); $owner_uid = db_fetch_result($result, 0, "owner_uid"); - if ($purge_interval == 0) $purge_interval = get_pref($link, + if ($purge_interval == 0) $purge_interval = get_pref( 'PURGE_OLD_DAYS', $owner_uid); return $purge_interval; @@ -248,20 +272,20 @@ } } - function purge_orphans($link, $do_output = false) { + function purge_orphans($do_output = false) { // purge orphaned posts in main content table - $result = db_query($link, "DELETE FROM ttrss_entries WHERE + $result = db_query("DELETE FROM ttrss_entries WHERE (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0"); if ($do_output) { - $rows = db_affected_rows($link, $result); + $rows = db_affected_rows($result); _debug("Purged $rows orphaned posts."); } } - function get_feed_update_interval($link, $feed_id) { - $result = db_query($link, "SELECT owner_uid, update_interval FROM + 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) { @@ -271,7 +295,7 @@ if ($update_interval != 0) { return $update_interval; } else { - return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false); + return get_pref('DEFAULT_UPDATE_INTERVAL', $owner_uid, false); } } else { @@ -279,25 +303,40 @@ } } - function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false) { - $login = urlencode($login); - $pass = urlencode($pass); + function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false, $timestamp = 0) { global $fetch_last_error; + global $fetch_last_error_code; + global $fetch_last_content_type; + global $fetch_curl_used; + + $url = str_replace(' ', '%20', $url); - if (function_exists('curl_init') && !ini_get("open_basedir")) { - $ch = curl_init($url); + if (!defined('NO_CURL') && function_exists('curl_init')) { - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + $fetch_curl_used = true; + + if (ini_get("safe_mode") || ini_get("open_basedir")) { + $ch = curl_init(geturl($url)); + } else { + $ch = curl_init($url); + } + + if ($timestamp && !$post_query) { + curl_setopt($ch, CURLOPT_HTTPHEADER, + array("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $timestamp))); + } + + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : FILE_FETCH_CONNECT_TIMEOUT); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : FILE_FETCH_TIMEOUT); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode") && !ini_get("open_basedir")); curl_setopt($ch, CURLOPT_MAXREDIRS, 20); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT); - curl_setopt($ch, CURLOPT_ENCODING , "gzip"); + curl_setopt($ch, CURLOPT_ENCODING, ""); curl_setopt($ch, CURLOPT_REFERER, $url); if ($post_query) { @@ -322,9 +361,11 @@ } $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + $fetch_last_content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); - if ($http_code != 200 || $type && strpos($content_type, "$type") === false) { + $fetch_last_error_code = $http_code; + + if ($http_code != 200 || $type && strpos($fetch_last_content_type, "$type") === false) { if (curl_errno($ch) != 0) { $fetch_last_error = curl_errno($ch) . " " . curl_error($ch); } else { @@ -338,21 +379,58 @@ return $contents; } else { - if ($login && $pass ){ + + $fetch_curl_used = false; + + if ($login && $pass){ $url_parts = array(); preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts); + $pass = urlencode($pass); + if ($url_parts[1] && $url_parts[2]) { $url = $url_parts[1] . "://$login:$pass@" . $url_parts[2]; } } - $data = @file_get_contents($url); + if (!$post_query && $timestamp) { + $context = stream_context_create(array( + 'http' => array( + 'method' => 'GET', + 'header' => "If-Modified-Since: ".gmdate("D, d M Y H:i:s \\G\\M\\T\r\n", $timestamp) + ))); + } else { + $context = NULL; + } + + $old_error = error_get_last(); + + $data = @file_get_contents($url, false, $context); + + $fetch_last_content_type = false; // reset if no type was sent from server + if (isset($http_response_header) && is_array($http_response_header)) { + foreach ($http_response_header as $h) { + if (substr(strtolower($h), 0, 13) == 'content-type:') { + $fetch_last_content_type = substr($h, 14); + // don't abort here b/c there might be more than one + // e.g. if we were being redirected -- last one is the right one + } + + if (substr(strtolower($h), 0, 7) == 'http/1.') { + $fetch_last_error_code = (int) substr($h, 9, 3); + } + } + } - if (!$data && function_exists('error_get_last')) { + if (!$data) { $error = error_get_last(); - $fetch_last_error = $error["message"]; + + if ($error['message'] != $old_error['message']) { + $fetch_last_error = $error["message"]; + } else { + $fetch_last_error = "HTTP Code: $fetch_last_error_code"; + } } return $data; } @@ -401,7 +479,7 @@ return $favicon_url; } // function get_favicon_url - function check_feed_favicon($site_url, $feed, $link) { + function check_feed_favicon($site_url, $feed) { # print "FAVICON [$site_url]: $favicon_url\n"; $icon_file = ICONS_DIR . "/$feed.ico"; @@ -448,6 +526,7 @@ } } } + return $icon_file; } } @@ -459,6 +538,8 @@ else $sel = ""; + $v = trim($v); + print "<option value=\"$v\" $sel>$v</option>"; } print "</select>"; @@ -472,6 +553,8 @@ else $sel = ""; + $v = trim($v); + print "<option $sel value=\"$v\">".$values[$v]."</option>"; } @@ -498,7 +581,7 @@ } } - function initialize_user_prefs($link, $uid, $profile = false) { + function initialize_user_prefs($uid, $profile = false) { $uid = db_escape_string($uid); @@ -509,13 +592,13 @@ $profile_qpart = "AND profile = '$profile'"; } - if (get_schema_version($link) < 63) $profile_qpart = ""; + if (get_schema_version() < 63) $profile_qpart = ""; - db_query($link, "BEGIN"); + db_query("BEGIN"); - $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs"); + $result = db_query("SELECT pref_name,def_value FROM ttrss_prefs"); - $u_result = db_query($link, "SELECT pref_name + $u_result = db_query("SELECT pref_name FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart"); $active_prefs = array(); @@ -528,13 +611,16 @@ if (array_search($line["pref_name"], $active_prefs) === FALSE) { // print "adding " . $line["pref_name"] . "<br>"; - if (get_schema_version($link) < 63) { - db_query($link, "INSERT INTO ttrss_user_prefs + $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 (owner_uid,pref_name,value) VALUES ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')"); } else { - db_query($link, "INSERT INTO ttrss_user_prefs + db_query("INSERT INTO ttrss_user_prefs (owner_uid,pref_name,value, profile) VALUES ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)"); } @@ -542,7 +628,7 @@ } } - db_query($link, "COMMIT"); + db_query("COMMIT"); } @@ -556,14 +642,12 @@ return ""; } - function authenticate_user($link, $login, $password, $check_only = false) { + function authenticate_user($login, $password, $check_only = false) { if (!SINGLE_USER_MODE) { - $user_id = false; - global $pluginhost; - foreach ($pluginhost->get_hooks($pluginhost::HOOK_AUTH_USER) as $plugin) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_AUTH_USER) as $plugin) { $user_id = (int) $plugin->authenticate($login, $password); @@ -574,24 +658,28 @@ } if ($user_id && !$check_only) { + @session_start(); + $_SESSION["uid"] = $user_id; + $_SESSION["version"] = VERSION_STATIC; - $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users + $result = db_query("SELECT login,access_level,pwd_hash FROM ttrss_users WHERE id = '$user_id'"); $_SESSION["name"] = db_fetch_result($result, 0, "login"); $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level"); $_SESSION["csrf_token"] = sha1(uniqid(rand(), true)); - db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " . + db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " . $_SESSION["uid"]); $_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["last_version_check"] = time(); - initialize_user_prefs($link, $_SESSION["uid"]); + initialize_user_prefs($_SESSION["uid"]); return true; } @@ -615,7 +703,7 @@ $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"]; - initialize_user_prefs($link, $_SESSION["uid"]); + initialize_user_prefs($_SESSION["uid"]); return true; } @@ -644,13 +732,13 @@ // user preferences are checked on every login, not here - function initialize_user($link, $uid) { + function initialize_user($uid) { - db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url) + db_query("insert into ttrss_feeds (owner_uid,title,feed_url) values ('$uid', 'Tiny Tiny RSS: New Releases', 'http://tt-rss.org/releases.rss')"); - db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url) + db_query("insert into ttrss_feeds (owner_uid,title,feed_url) values ('$uid', 'Tiny Tiny RSS: Forum', 'http://tt-rss.org/forum/rss.php')"); } @@ -666,103 +754,67 @@ return $csrf_token == $_SESSION['csrf_token']; } - function validate_session($link) { - if (SINGLE_USER_MODE) return true; - - $check_ip = $_SESSION['ip_address']; - - switch (SESSION_CHECK_ADDRESS) { - case 0: - $check_ip = ''; - break; - case 1: - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); - break; - case 2: - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')); - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); - break; - }; - - if ($check_ip && strpos($_SERVER['REMOTE_ADDR'], $check_ip) !== 0) { - $_SESSION["login_error_msg"] = - __("Session failed to validate (incorrect IP)"); - return false; - } - - if ($_SESSION["ref_schema_version"] != get_schema_version($link, true)) - return false; - - if ($_SESSION["uid"]) { - - $result = db_query($link, - "SELECT pwd_hash FROM ttrss_users WHERE id = '".$_SESSION["uid"]."'"); - - $pwd_hash = db_fetch_result($result, 0, "pwd_hash"); - - if ($pwd_hash != $_SESSION["pwd_hash"]) { - return false; - } - } - -/* if ($_SESSION["cookie_lifetime"] && $_SESSION["uid"]) { - - //print_r($_SESSION); - - if (time() > $_SESSION["cookie_lifetime"]) { - return false; - } - } */ - - return true; - } - - function load_user_plugins($link, $owner_uid) { + function load_user_plugins($owner_uid) { if ($owner_uid) { - $plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid); + $plugins = get_pref("_ENABLED_PLUGINS", $owner_uid); - global $pluginhost; - $pluginhost->load($plugins, $pluginhost::KIND_USER, $owner_uid); + PluginHost::getInstance()->load($plugins, PluginHost::KIND_USER, $owner_uid); - if (get_schema_version($link) > 100) { - $pluginhost->load_data(); + if (get_schema_version() > 100) { + PluginHost::getInstance()->load_data(); } } } - function login_sequence($link, $login_form = 0) { - $_SESSION["prefs_cache"] = false; - + function login_sequence() { if (SINGLE_USER_MODE) { - authenticate_user($link, "admin", null); - cache_prefs($link); - load_user_plugins($link, $_SESSION["uid"]); + @session_start(); + authenticate_user("admin", null); + load_user_plugins($_SESSION["uid"]); } else { - if (!$_SESSION["uid"] || !validate_session($link)) { + if (!validate_session()) $_SESSION["uid"] = false; + + if (!$_SESSION["uid"]) { - if (AUTH_AUTO_LOGIN && authenticate_user($link, null, null)) { - $_SESSION["ref_schema_version"] = get_schema_version($link, true); + if (AUTH_AUTO_LOGIN && authenticate_user(null, null)) { + $_SESSION["ref_schema_version"] = get_schema_version(true); } else { - authenticate_user($link, null, null, true); + authenticate_user(null, null, true); } - if (!$_SESSION["uid"]) render_login_form($link, $login_form); + if (!$_SESSION["uid"]) { + @session_destroy(); + setcookie(session_name(), '', time()-42000, '/'); + + render_login_form(); + exit; + } } else { /* bump login timestamp */ - db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " . + db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " . $_SESSION["uid"]); - } - - if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) { - setcookie("ttrss_lang", $_SESSION["language"], - time() + SESSION_COOKIE_LIFETIME); + $_SESSION["last_login_update"] = time(); } if ($_SESSION["uid"]) { - cache_prefs($link); - load_user_plugins($link, $_SESSION["uid"]); + startup_gettext(); + load_user_plugins($_SESSION["uid"]); + + /* cleanup ccache */ + + db_query("DELETE FROM ttrss_counters_cache WHERE owner_uid = ". + $_SESSION["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 + (SELECT COUNT(id) FROM ttrss_feed_categories WHERE + ttrss_feed_categories.id = feed_id) = 0"); + } + } } @@ -774,11 +826,6 @@ } } - // Deprecated, TODO: remove - function theme_image($link, $filename) { - return $filename; - } - function convert_timestamp($timestamp, $source_tz, $dest_tz) { try { @@ -797,62 +844,68 @@ return $dt->format('U') + $dest_tz->getOffset($dt); } - function make_local_datetime($link, $timestamp, $long, $owner_uid = false, + function make_local_datetime($timestamp, $long, $owner_uid = false, $no_smart_dt = false) { if (!$owner_uid) $owner_uid = $_SESSION['uid']; if (!$timestamp) $timestamp = '1970-01-01 0:00'; global $utc_tz; - global $tz_offset; + global $user_tz; + + if (!$utc_tz) $utc_tz = new DateTimeZone('UTC'); + + $timestamp = substr($timestamp, 0, 19); # We store date in UTC internally $dt = new DateTime($timestamp, $utc_tz); - if ($tz_offset == -1) { + $user_tz_string = get_pref('USER_TIMEZONE', $owner_uid); - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid); + if ($user_tz_string != 'Automatic') { try { - $user_tz = new DateTimeZone($user_tz_string); + if (!$user_tz) $user_tz = new DateTimeZone($user_tz_string); } catch (Exception $e) { $user_tz = $utc_tz; } $tz_offset = $user_tz->getOffset($dt); + } else { + $tz_offset = (int) -$_SESSION["clientTzOffset"]; } $user_timestamp = $dt->format('U') + $tz_offset; if (!$no_smart_dt) { - return smart_date_time($link, $user_timestamp, + return smart_date_time($user_timestamp, $tz_offset, $owner_uid); } else { if ($long) - $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid); + $format = get_pref('LONG_DATE_FORMAT', $owner_uid); else - $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid); + $format = get_pref('SHORT_DATE_FORMAT', $owner_uid); return date($format, $user_timestamp); } } - function smart_date_time($link, $timestamp, $tz_offset = 0, $owner_uid = false) { + function smart_date_time($timestamp, $tz_offset = 0, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION['uid']; if (date("Y.m.d", $timestamp) == date("Y.m.d", time() + $tz_offset)) { return date("G:i", $timestamp); } else if (date("Y", $timestamp) == date("Y", time() + $tz_offset)) { - $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid); + $format = get_pref('SHORT_DATE_FORMAT', $owner_uid); return date($format, $timestamp); } else { - $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid); + $format = get_pref('LONG_DATE_FORMAT', $owner_uid); return date($format, $timestamp); } } function sql_bool_to_bool($s) { - if ($s == "t" || $s == "1" || $s == "true") { + if ($s == "t" || $s == "1" || strtolower($s) == "true") { return true; } else { return false; @@ -870,11 +923,11 @@ // Session caching removed due to causing wrong redirects to upgrade // script when get_schema_version() is called on an obsolete session // created on a previous schema version. - function get_schema_version($link, $nocache = false) { + function get_schema_version($nocache = false) { global $schema_version; - if (!$schema_version) { - $result = db_query($link, "SELECT schema_version FROM ttrss_version"); + if (!$schema_version && !$nocache) { + $result = db_query("SELECT schema_version FROM ttrss_version"); $version = db_fetch_result($result, 0, "schema_version"); $schema_version = $version; return $version; @@ -883,18 +936,18 @@ } } - function sanity_check($link) { + function sanity_check() { require_once 'errors.php'; $error_code = 0; - $schema_version = get_schema_version($link, true); + $schema_version = get_schema_version(true); if ($schema_version != SCHEMA_VERSION) { $error_code = 5; } if (DB_TYPE == "mysql") { - $result = db_query($link, "SELECT true", false); + $result = db_query("SELECT true", false); if (db_num_rows($result) != 1) { $error_code = 10; } @@ -959,14 +1012,41 @@ } } - function catchup_feed($link, $feed, $cat_view, $owner_uid = false, $max_id = false) { + function catchup_feed($feed, $cat_view, $owner_uid = false, $max_id = false, $mode = 'all') { if (!$owner_uid) $owner_uid = $_SESSION['uid']; //if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) { - $ref_check_qpart = ($max_id && - !get_pref($link, 'REVERSE_HEADLINES')) ? "ref_id <= '$max_id'" : "true"; + // Todo: all this interval stuff needs some generic generator function + + $date_qpart = "false"; + + switch ($mode) { + case "1day": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '1 day' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY) "; + } + break; + case "1week": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '1 week' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 WEEK) "; + } + break; + case "2weeks": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '2 week' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 2 WEEK) "; + } + break; + default: + $date_qpart = "true"; + } if (is_numeric($feed)) { if ($cat_view) { @@ -974,7 +1054,7 @@ if ($feed >= 0) { if ($feed > 0) { - $children = getChildCategories($link, $feed, $owner_uid); + $children = getChildCategories($feed, $owner_uid); array_push($children, $feed); $children = join(",", $children); @@ -984,124 +1064,111 @@ $cat_qpart = "cat_id IS NULL"; } - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE feed_id IN (SELECT id FROM ttrss_feeds WHERE $cat_qpart) - AND $ref_check_qpart AND unread = true - AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND feed_id IN + (SELECT id FROM ttrss_feeds WHERE $cat_qpart) AND $date_qpart) as tmp)"); } else if ($feed == -2) { - db_query($link, "UPDATE ttrss_user_entries + db_query("UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*) FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0 - AND $ref_check_qpart - AND unread = true AND owner_uid = $owner_uid"); + AND unread = true AND $date_qpart AND owner_uid = $owner_uid"); } } else if ($feed > 0) { - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE feed_id = '$feed' - AND $ref_check_qpart AND unread = true - AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT 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) as tmp)"); - } else if ($feed < 0 && $feed > -10) { // special, like starred + } else if ($feed < 0 && $feed > LABEL_BASE_INDEX) { // special, like starred if ($feed == -1) { - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE marked = true - AND $ref_check_qpart AND unread = true - AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT 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) as tmp)"); } if ($feed == -2) { - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE published = true - AND $ref_check_qpart AND unread = true - AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT 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) as tmp)"); } if ($feed == -3) { - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE"); + $intl = get_pref("FRESH_ARTICLE_MAX_AGE"); if (DB_TYPE == "pgsql") { - $match_part = "updated > NOW() - INTERVAL '$intl hour' "; + $match_part = "date_entered > NOW() - INTERVAL '$intl hour' "; } else { - $match_part = "updated > DATE_SUB(NOW(), + $match_part = "date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; } - $result = db_query($link, "SELECT id FROM ttrss_entries, - ttrss_user_entries WHERE $match_part AND - unread = true AND - ttrss_user_entries.ref_id = ttrss_entries.id AND - owner_uid = $owner_uid"); - - $affected_ids = array(); - - while ($line = db_fetch_assoc($result)) { - array_push($affected_ids, $line["id"]); - } - - catchupArticlesById($link, $affected_ids, 0); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND $date_qpart AND $match_part) as tmp)"); } if ($feed == -4) { - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE $ref_check_qpart AND unread = true AND - owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND $date_qpart) as tmp)"); } - } else if ($feed < -10) { // label + } else if ($feed < LABEL_BASE_INDEX) { // label - $label_id = -$feed - 11; + $label_id = feed_to_label_id($feed); - db_query($link, "UPDATE ttrss_user_entries, ttrss_user_labels2 - SET unread = false, last_read = NOW() - WHERE label_id = '$label_id' AND unread = true - AND $ref_check_qpart - AND owner_uid = '$owner_uid' AND ref_id = article_id"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT 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) as tmp)"); } - ccache_update($link, $feed, $owner_uid, $cat_view); + ccache_update($feed, $owner_uid, $cat_view); } else { // tag - db_query($link, "BEGIN"); - - $tag_name = db_escape_string($feed); - - $result = db_query($link, "SELECT post_int_id FROM ttrss_tags - WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT 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) as tmp)"); - while ($line = db_fetch_assoc($result)) { - db_query($link, "UPDATE ttrss_user_entries SET - unread = false, last_read = NOW() - WHERE $ref_check_qpart AND unread = true - AND int_id = " . $line["post_int_id"]); - } - db_query($link, "COMMIT"); } } - function getAllCounters($link) { - $data = getGlobalCounters($link); + function getAllCounters() { + $data = getGlobalCounters(); - $data = array_merge($data, getVirtCounters($link)); - $data = array_merge($data, getLabelCounters($link)); - $data = array_merge($data, getFeedCounters($link, $active_feed)); - $data = array_merge($data, getCategoryCounters($link)); + $data = array_merge($data, getVirtCounters()); + $data = array_merge($data, getLabelCounters()); + $data = array_merge($data, getFeedCounters()); + $data = array_merge($data, getCategoryCounters()); return $data; } - function getCategoryTitle($link, $cat_id) { + function getCategoryTitle($cat_id) { if ($cat_id == -1) { return __("Special"); @@ -1109,7 +1176,7 @@ return __("Labels"); } else { - $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE + $result = db_query("SELECT title FROM ttrss_feed_categories WHERE id = '$cat_id'"); if (db_num_rows($result) == 1) { @@ -1121,17 +1188,17 @@ } - function getCategoryCounters($link) { + function getCategoryCounters() { $ret_arr = array(); /* Labels category */ $cv = array("id" => -2, "kind" => "cat", - "counter" => getCategoryUnread($link, -2)); + "counter" => getCategoryUnread(-2)); array_push($ret_arr, $cv); - $result = db_query($link, "SELECT id AS cat_id, value AS unread, + $result = db_query("SELECT id AS cat_id, value AS unread, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories, ttrss_cat_counters_cache @@ -1143,7 +1210,7 @@ $line["cat_id"] = (int) $line["cat_id"]; if ($line["num_children"] > 0) { - $child_counter = getCategoryChildrenUnread($link, $line["cat_id"], $_SESSION["uid"]); + $child_counter = getCategoryChildrenUnread($line["cat_id"], $_SESSION["uid"]); } else { $child_counter = 0; } @@ -1157,7 +1224,7 @@ /* Special case: NULL category doesn't actually exist in the DB */ $cv = array("id" => 0, "kind" => "cat", - "counter" => (int) ccache_find($link, 0, $_SESSION["uid"], true)); + "counter" => (int) ccache_find(0, $_SESSION["uid"], true)); array_push($ret_arr, $cv); @@ -1165,23 +1232,23 @@ } // only accepts real cats (>= 0) - function getCategoryChildrenUnread($link, $cat, $owner_uid = false) { + function getCategoryChildrenUnread($cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' + $result = db_query("SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' AND owner_uid = $owner_uid"); $unread = 0; while ($line = db_fetch_assoc($result)) { - $unread += getCategoryUnread($link, $line["id"], $owner_uid); - $unread += getCategoryChildrenUnread($link, $line["id"], $owner_uid); + $unread += getCategoryUnread($line["id"], $owner_uid); + $unread += getCategoryChildrenUnread($line["id"], $owner_uid); } return $unread; } - function getCategoryUnread($link, $cat, $owner_uid = false) { + function getCategoryUnread($cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -1193,7 +1260,7 @@ $cat_query = "cat_id IS NULL"; } - $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query + $result = db_query("SELECT id FROM ttrss_feeds WHERE $cat_query AND owner_uid = " . $owner_uid); $cat_feeds = array(); @@ -1205,7 +1272,7 @@ $match_part = implode(" OR ", $cat_feeds); - $result = db_query($link, "SELECT COUNT(int_id) AS unread + $result = db_query("SELECT COUNT(int_id) AS unread FROM ttrss_user_entries WHERE unread = true AND ($match_part) AND owner_uid = " . $owner_uid); @@ -1219,10 +1286,10 @@ return $unread; } else if ($cat == -1) { - return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0); + return getFeedUnread(-1) + getFeedUnread(-2) + getFeedUnread(-3) + getFeedUnread(0); } else if ($cat == -2) { - $result = db_query($link, " + $result = db_query(" SELECT COUNT(unread) AS unread FROM ttrss_user_entries, ttrss_user_labels2 WHERE article_id = ref_id AND unread = true @@ -1235,14 +1302,14 @@ } } - function getFeedUnread($link, $feed, $is_cat = false) { - return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]); + function getFeedUnread($feed, $is_cat = false) { + return getFeedArticles($feed, $is_cat, true, $_SESSION["uid"]); } - function getLabelUnread($link, $label_id, $owner_uid = false) { + function getLabelUnread($label_id, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 + $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"); if (db_num_rows($result) != 0) { @@ -1252,7 +1319,7 @@ } } - function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false, + function getFeedArticles($feed, $is_cat = false, $unread_only = false, $owner_uid = false) { $n_feed = (int) $feed; @@ -1267,14 +1334,14 @@ } if ($is_cat) { - return getCategoryUnread($link, $n_feed, $owner_uid); + return 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($link, "SELECT SUM((SELECT COUNT(int_id) + $result = db_query("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'"); @@ -1287,7 +1354,7 @@ } else if ($n_feed == -3) { $match_part = "unread = true AND score >= 0"; - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); if (DB_TYPE == "pgsql") { $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' "; @@ -1307,11 +1374,11 @@ $match_part = "feed_id IS NULL"; } - } else if ($feed < -10) { + } else if ($feed < LABEL_BASE_INDEX) { - $label_id = -$feed - 11; + $label_id = feed_to_label_id($feed); - return getLabelUnread($link, $label_id, $owner_uid); + return getLabelUnread($label_id, $owner_uid); } @@ -1330,11 +1397,11 @@ //echo "[$feed/$query]\n"; - $result = db_query($link, $query); + $result = db_query($query); } else { - $result = db_query($link, "SELECT COUNT(post_int_id) AS unread + $result = db_query("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); @@ -1345,13 +1412,13 @@ return $unread; } - function getGlobalUnread($link, $user_id = false) { + function getGlobalUnread($user_id = false) { if (!$user_id) { $user_id = $_SESSION["uid"]; } - $result = db_query($link, "SELECT SUM(value) AS c_id FROM ttrss_counters_cache + $result = db_query("SELECT SUM(value) AS c_id FROM ttrss_counters_cache WHERE owner_uid = '$user_id' AND feed_id > 0"); $c_id = db_fetch_result($result, 0, "c_id"); @@ -1359,11 +1426,11 @@ return $c_id; } - function getGlobalCounters($link, $global_unread = -1) { + function getGlobalCounters($global_unread = -1) { $ret_arr = array(); if ($global_unread == -1) { - $global_unread = getGlobalUnread($link); + $global_unread = getGlobalUnread(); } $cv = array("id" => "global-unread", @@ -1371,7 +1438,7 @@ array_push($ret_arr, $cv); - $result = db_query($link, "SELECT COUNT(id) AS fn FROM + $result = db_query("SELECT COUNT(id) AS fn FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $subscribed_feeds = db_fetch_result($result, 0, "fn"); @@ -1384,42 +1451,53 @@ return $ret_arr; } - function getVirtCounters($link) { + function getVirtCounters() { $ret_arr = array(); for ($i = 0; $i >= -4; $i--) { - $count = getFeedUnread($link, $i); + $count = getFeedUnread($i); $cv = array("id" => $i, "counter" => (int) $count); -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($i)." ".__("total"); array_push($ret_arr, $cv); } + $feeds = PluginHost::getInstance()->get_feeds(-1); + + if (is_array($feeds)) { + foreach ($feeds as $feed) { + $cv = array("id" => PluginHost::pfeed_to_feed_id($feed['id']), + "counter" => $feed['sender']->get_unread($feed['id'])); + array_push($ret_arr, $cv); + } + } + return $ret_arr; } - function getLabelCounters($link, $descriptions = false) { + function getLabelCounters($descriptions = false) { $ret_arr = array(); $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread + $result = db_query("SELECT id,caption,COUNT(unread) AS unread FROM ttrss_labels2 LEFT JOIN ttrss_user_labels2 ON (ttrss_labels2.id = label_id) - LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true) + LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true + AND ttrss_user_entries.owner_uid = $owner_uid) WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id, ttrss_labels2.caption"); while ($line = db_fetch_assoc($result)) { - $id = -$line["id"] - 11; + $id = label_to_feed_id($line["id"]); $label_name = $line["caption"]; $count = $line["unread"]; @@ -1430,8 +1508,8 @@ if ($descriptions) $cv["description"] = $label_name; -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($id)." ".__("total"); array_push($ret_arr, $cv); } @@ -1439,7 +1517,7 @@ return $ret_arr; } - function getFeedCounters($link, $active_feed = false) { + function getFeedCounters($active_feed = false) { $ret_arr = array(); @@ -1452,7 +1530,7 @@ AND ttrss_counters_cache.owner_uid = ttrss_feeds.owner_uid AND ttrss_counters_cache.feed_id = id"; - $result = db_query($link, $query); + $result = db_query($query); $fctrs_modified = false; while ($line = db_fetch_assoc($result)) { @@ -1461,7 +1539,7 @@ $count = $line["count"]; $last_error = htmlspecialchars($line["last_error"]); - $last_updated = make_local_datetime($link, $line['last_updated'], false); + $last_updated = make_local_datetime($line['last_updated'], false); $has_img = feed_has_icon($id); @@ -1476,8 +1554,8 @@ if ($last_error) $cv["error"] = $last_error; -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($id)." ".__("total"); if ($active_feed && $id == $active_feed) $cv["title"] = truncate_string($line["title"], 30); @@ -1489,8 +1567,8 @@ return $ret_arr; } - function get_pgsql_version($link) { - $result = db_query($link, "SELECT version() AS version"); + function get_pgsql_version() { + $result = db_query("SELECT version() AS version"); $version = explode(" ", db_fetch_result($result, 0, "version")); return $version[1]; } @@ -1506,9 +1584,10 @@ * Here you should call extractfeedurls in rpc-backend * to get all possible feeds. * 5 - Couldn't download the URL content. + * 6 - Content is an invalid XML. */ - function subscribe_to_feed($link, $url, $cat_id = 0, - $auth_login = '', $auth_pass = '', $need_auth = false) { + function subscribe_to_feed($url, $cat_id = 0, + $auth_login = '', $auth_pass = '') { global $fetch_last_error; @@ -1536,31 +1615,53 @@ $url = key($feedUrls); } + /* libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadXML($contents); + $error = libxml_get_last_error(); + libxml_clear_errors(); + + if ($error) { + $error_message = format_libxml_error($error); + + return array("code" => 6, "message" => $error_message); + } */ + if ($cat_id == "0" || !$cat_id) { $cat_qpart = "NULL"; } else { $cat_qpart = "'$cat_id'"; } - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]); + if (strlen(FEED_CRYPT_KEY) > 0) { + require_once "crypt.php"; + $auth_pass = substr(encrypt_string($auth_pass), 0, 250); + $auth_pass_encrypted = 'true'; + } else { + $auth_pass_encrypted = 'false'; + } + + $auth_pass = db_escape_string($auth_pass); + if (db_num_rows($result) == 0) { - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_feeds - (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method) + (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)"); + '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0, $auth_pass_encrypted)"); - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' AND owner_uid = " . $_SESSION["uid"]); $feed_id = db_fetch_result($result, 0, "id"); if ($feed_id) { - update_rss_feed($link, $feed_id, true); + update_rss_feed($feed_id, true); } return array("code" => 1); @@ -1569,7 +1670,7 @@ } } - function print_feed_select($link, $id, $default_id = "", + function print_feed_select($id, $default_id = "", $attributes = "", $include_all_feeds = true, $root_id = false, $nest_level = 0) { @@ -1581,14 +1682,14 @@ } } - if (get_pref($link, 'ENABLE_FEED_CATS')) { + if (get_pref('ENABLE_FEED_CATS')) { if ($root_id) $parent_qpart = "parent_cat = '$root_id'"; else $parent_qpart = "parent_cat IS NULL"; - $result = db_query($link, "SELECT id,title, + $result = db_query("SELECT id,title, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories @@ -1605,10 +1706,10 @@ $line["id"], htmlspecialchars($line["title"])); if ($line["num_children"] > 0) - print_feed_select($link, $id, $default_id, $attributes, + print_feed_select($id, $default_id, $attributes, $include_all_feeds, $line["id"], $nest_level+1); - $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds + $feed_result = db_query("SELECT id,title FROM ttrss_feeds WHERE cat_id = '".$line["id"]."' AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title"); while ($fline = db_fetch_assoc($feed_result)) { @@ -1625,12 +1726,13 @@ } if (!$root_id) { - $is_selected = ($default_id == "CAT:0") ? "selected=\"1\"" : ""; + $default_is_cat = ($default_id == "CAT:0"); + $is_selected = $default_is_cat ? "selected=\"1\"" : ""; printf("<option $is_selected value='CAT:0'>%s</option>", __("Uncategorized")); - $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds + $feed_result = db_query("SELECT id,title FROM ttrss_feeds WHERE cat_id IS NULL AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title"); while ($fline = db_fetch_assoc($feed_result)) { @@ -1647,7 +1749,7 @@ } } else { - $result = db_query($link, "SELECT id,title FROM ttrss_feeds + $result = db_query("SELECT id,title FROM ttrss_feeds WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title"); while ($line = db_fetch_assoc($result)) { @@ -1664,7 +1766,7 @@ } } - function print_feed_cat_select($link, $id, $default_id, + function print_feed_cat_select($id, $default_id, $attributes, $include_all_cats = true, $root_id = false, $nest_level = 0) { if (!$root_id) { @@ -1676,7 +1778,7 @@ else $parent_qpart = "parent_cat IS NULL"; - $result = db_query($link, "SELECT id,title, + $result = db_query("SELECT id,title, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories @@ -1697,7 +1799,7 @@ $line["id"], htmlspecialchars($line["title"])); if ($line["num_children"] > 0) - print_feed_cat_select($link, $id, $default_id, $attributes, + print_feed_cat_select($id, $default_id, $attributes, $include_all_cats, $line["id"], $nest_level+1); } @@ -1723,13 +1825,13 @@ return ($val == "on") ? "true" : "false"; } - function getFeedCatTitle($link, $id) { + function getFeedCatTitle($id) { if ($id == -1) { return __("Special"); - } else if ($id < -10) { + } else if ($id < LABEL_BASE_INDEX) { return __("Labels"); } else if ($id > 0) { - $result = db_query($link, "SELECT ttrss_feed_categories.title + $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) { @@ -1764,7 +1866,7 @@ return "images/recently_read.png"; break; default: - if ($id < -10) { + if ($id < LABEL_BASE_INDEX) { return "images/label.png"; } else { if (file_exists(ICONS_DIR . "/$id.ico")) @@ -1772,11 +1874,13 @@ } break; } + + return false; } - function getFeedTitle($link, $id, $cat = false) { + function getFeedTitle($id, $cat = false) { if ($cat) { - return getCategoryTitle($link, $id); + return getCategoryTitle($id); } else if ($id == -1) { return __("Starred articles"); } else if ($id == -2) { @@ -1789,9 +1893,9 @@ return __("Archived articles"); } else if ($id == -6) { return __("Recently read"); - } else if ($id < -10) { - $label_id = -$id - 11; - $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'"); + } 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"); } else { @@ -1799,7 +1903,7 @@ } } else if (is_numeric($id) && $id > 0) { - $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'"); + $result = db_query("SELECT title FROM ttrss_feeds WHERE id = '$id'"); if (db_num_rows($result) == 1) { return db_fetch_result($result, 0, "title"); } else { @@ -1810,30 +1914,26 @@ } } - function make_init_params($link) { + function make_init_params() { $params = array(); - $params["sign_progress"] = theme_image($link, "images/indicator_white.gif"); - $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif"); - $params["sign_excl"] = theme_image($link, "images/sign_excl.svg"); - $params["sign_info"] = theme_image($link, "images/sign_info.svg"); - foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS", "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP", - "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT", + "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) { - $params[strtolower($param)] = (int) get_pref($link, $param); + $params[strtolower($param)] = (int) get_pref($param); } $params["icons_url"] = ICONS_URL; $params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME; - $params["default_view_mode"] = get_pref($link, "_DEFAULT_VIEW_MODE"); - $params["default_view_limit"] = (int) get_pref($link, "_DEFAULT_VIEW_LIMIT"); - $params["default_view_order_by"] = get_pref($link, "_DEFAULT_VIEW_ORDER_BY"); + $params["default_view_mode"] = get_pref("_DEFAULT_VIEW_MODE"); + $params["default_view_limit"] = (int) get_pref("_DEFAULT_VIEW_LIMIT"); + $params["default_view_order_by"] = get_pref("_DEFAULT_VIEW_ORDER_BY"); $params["bw_limit"] = (int) $_SESSION["bw_limit"]; + $params["label_base_index"] = (int) LABEL_BASE_INDEX; - $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM + $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $max_feed_id = db_fetch_result($result, 0, "mid"); @@ -1842,8 +1942,8 @@ $params["max_feed_id"] = (int) $max_feed_id; $params["num_feeds"] = (int) $num_feeds; - $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST"); - $params["hotkeys"] = get_hotkeys_map($link); + $params["collapsed_feedlist"] = (int) get_pref("_COLLAPSED_FEEDLIST"); + $params["hotkeys"] = get_hotkeys_map(); $params["csrf_token"] = $_SESSION["csrf_token"]; $params["widescreen"] = (int) $_COOKIE["ttrss_widescreen"]; @@ -1853,7 +1953,7 @@ return $params; } - function get_hotkeys_info($link) { + function get_hotkeys_info() { $hotkeys = array( __("Navigation") => array( "next_feed" => __("Open next feed"), @@ -1862,6 +1962,8 @@ "prev_article" => __("Open previous article"), "next_article_noscroll" => __("Open next article (don't scroll long articles)"), "prev_article_noscroll" => __("Open previous article (don't scroll long articles)"), + "next_article_noexpand" => __("Move to next article (don't expand or mark read)"), + "prev_article_noexpand" => __("Move to previous article (don't expand or mark read)"), "search_dialog" => __("Show search dialog")), __("Article") => array( "toggle_mark" => __("Toggle starred"), @@ -1877,8 +1979,10 @@ "article_scroll_up" => __("Scroll up"), "select_article_cursor" => __("Select article under cursor"), "email_article" => __("Email article"), - "close_article" => __("Close article"), - "toggle_widescreen" => __("Toggle widescreen mode")), + "close_article" => __("Close/collapse article"), + "toggle_expand" => __("Toggle article expansion (combined mode)"), + "toggle_widescreen" => __("Toggle widescreen mode"), + "toggle_embed_original" => __("Toggle embed original")), __("Article selection") => array( "select_all" => __("Select all articles"), "select_unread" => __("Select unread"), @@ -1896,7 +2000,8 @@ "feed_debug_update" => __("Debug feed update"), "catchup_all" => __("Mark all feeds as read"), "cat_toggle_collapse" => __("Un/collapse current category"), - "toggle_combined_mode" => __("Toggle combined mode")), + "toggle_combined_mode" => __("Toggle combined mode"), + "toggle_cdm_expanded" => __("Toggle auto expand in combined mode")), __("Go to") => array( "goto_all" => __("All articles"), "goto_fresh" => __("Fresh"), @@ -1911,10 +2016,14 @@ "help_dialog" => __("Show help dialog")) ); + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HOTKEY_INFO) as $plugin) { + $hotkeys = $plugin->hook_hotkey_info($hotkeys); + } + return $hotkeys; } - function get_hotkeys_map($link) { + function get_hotkeys_map() { $hotkeys = array( // "navigation" => array( "k" => "next_feed", @@ -1928,23 +2037,26 @@ "(191)|/" => "search_dialog", // "article" => array( "s" => "toggle_mark", - "S" => "toggle_publ", + "*s" => "toggle_publ", "u" => "toggle_unread", - "T" => "edit_tags", - "D" => "dismiss_selected", - "X" => "dismiss_read", + "*t" => "edit_tags", + "*d" => "dismiss_selected", + "*x" => "dismiss_read", "o" => "open_in_new_window", "c p" => "catchup_below", "c n" => "catchup_above", - "N" => "article_scroll_down", - "P" => "article_scroll_up", - "a W" => "toggle_widescreen", + "*n" => "article_scroll_down", + "*p" => "article_scroll_up", + "*(38)|Shift+up" => "article_scroll_up", + "*(40)|Shift+down" => "article_scroll_down", + "a *w" => "toggle_widescreen", + "a e" => "toggle_embed_original", "e" => "email_article", "a q" => "close_article", // "article_selection" => array( "a a" => "select_all", "a u" => "select_unread", - "a U" => "select_marked", + "a *u" => "select_marked", "a p" => "select_published", "a i" => "select_invert", "a n" => "select_none", @@ -1955,9 +2067,10 @@ "f e" => "feed_edit", "f q" => "feed_catchup", "f x" => "feed_reverse", - "f D" => "feed_debug_update", - "f C" => "toggle_combined_mode", - "Q" => "catchup_all", + "f *d" => "feed_debug_update", + "f *c" => "toggle_combined_mode", + "f c" => "toggle_cdm_expanded", + "*q" => "catchup_all", "x" => "cat_toggle_collapse", // "goto" => array( "g a" => "goto_all", @@ -1965,7 +2078,7 @@ "g s" => "goto_marked", "g p" => "goto_published", "g t" => "goto_tagcloud", - "g P" => "goto_prefs", + "g *p" => "goto_prefs", // "other" => array( "(9)|Tab" => "select_article_cursor", // tab "c l" => "create_label", @@ -1974,13 +2087,12 @@ "^(191)|Ctrl+/" => "help_dialog", ); - if (get_pref($link, 'COMBINED_DISPLAY_MODE')) { + if (get_pref('COMBINED_DISPLAY_MODE')) { $hotkeys["^(38)|Ctrl-up"] = "prev_article_noscroll"; $hotkeys["^(40)|Ctrl-down"] = "next_article_noscroll"; } - global $pluginhost; - foreach ($pluginhost->get_hooks($pluginhost::HOOK_HOTKEY_MAP) as $plugin) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HOTKEY_MAP) as $plugin) { $hotkeys = $plugin->hook_hotkey_map($hotkeys); } @@ -1997,10 +2109,10 @@ return array($prefixes, $hotkeys); } - function make_runtime_info($link) { + function make_runtime_info() { $data = array(); - $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM + $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $max_feed_id = db_fetch_result($result, 0, "mid"); @@ -2009,8 +2121,11 @@ $data["max_feed_id"] = (int) $max_feed_id; $data["num_feeds"] = (int) $num_feeds; - $data['last_article_id'] = getLastArticleId($link); - $data['cdm_expanded'] = get_pref($link, 'CDM_EXPANDED'); + $data['last_article_id'] = getLastArticleId(); + $data['cdm_expanded'] = get_pref('CDM_EXPANDED'); + + $data['dep_ts'] = calculate_dep_timestamp(); + $data['reload_on_ts_change'] = !defined('_NO_RELOAD_ON_TS_CHANGE'); if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) { @@ -2040,7 +2155,7 @@ } if ($_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) { - $new_version_details = @check_for_update($link); + $new_version_details = @check_for_update(); $data['new_version_available'] = (int) ($new_version_details != false); @@ -2051,7 +2166,7 @@ return $data; } - function search_to_sql($link, $search, $match_on) { + function search_to_sql($search) { $search_query_part = ""; @@ -2068,43 +2183,77 @@ $commandpair = explode(":", mb_strtolower($k), 2); - if ($commandpair[0] == "note" && $commandpair[1]) { - - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))"); - else - array_push($query_keywords, "($not (note IS NULL OR note = ''))"); - - } else if ($commandpair[0] == "star" && $commandpair[1]) { - - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (marked = true))"); - else - array_push($query_keywords, "($not (marked = false))"); - - } else if ($commandpair[0] == "pub" && $commandpair[1]) { + 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]))."%'))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "author": + if ($commandpair[1]) { + array_push($query_keywords, "($not (LOWER(author) LIKE '%". + db_escape_string(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%'))"); + } + break; + case "note": + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))"); + 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]))."%'))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "star": - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (published = true))"); - else - array_push($query_keywords, "($not (published = false))"); + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (marked = true))"); + 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%'))"); + } + break; + case "pub": + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (published = true))"); + else + array_push($query_keywords, "($not (published = false))"); - } else if (strpos($k, "@") === 0) { + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + default: + if (strpos($k, "@") === 0) { - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $_SESSION['uid']); - $orig_ts = strtotime(substr($k, 1)); - $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC')); + $user_tz_string = get_pref('USER_TIMEZONE', $_SESSION['uid']); + $orig_ts = strtotime(substr($k, 1)); + $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC')); - //$k = date("Y-m-d", strtotime(substr($k, 1))); + //$k = date("Y-m-d", strtotime(substr($k, 1))); - array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')"); - } else if ($match_on == "both") { - array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') - OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); - } else if ($match_on == "title") { - array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%'))"); - } else if ($match_on == "content") { - array_push($query_keywords, "(UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } } } @@ -2113,35 +2262,35 @@ return $search_query_part; } - function getParentCategories($link, $cat, $owner_uid) { + function getParentCategories($cat, $owner_uid) { $rv = array(); - $result = db_query($link, "SELECT parent_cat FROM ttrss_feed_categories + $result = db_query("SELECT parent_cat FROM ttrss_feed_categories WHERE id = '$cat' AND parent_cat IS NOT NULL AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { array_push($rv, $line["parent_cat"]); - $rv = array_merge($rv, getParentCategories($link, $line["parent_cat"], $owner_uid)); + $rv = array_merge($rv, getParentCategories($line["parent_cat"], $owner_uid)); } return $rv; } - function getChildCategories($link, $cat, $owner_uid) { + function getChildCategories($cat, $owner_uid) { $rv = array(); - $result = db_query($link, "SELECT id FROM ttrss_feed_categories + $result = db_query("SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { array_push($rv, $line["id"]); - $rv = array_merge($rv, getChildCategories($link, $line["id"], $owner_uid)); + $rv = array_merge($rv, getChildCategories($line["id"], $owner_uid)); } return $rv; } - function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $match_on, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) { + function queryFeedHeadlines($feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -2158,7 +2307,7 @@ $search_query_part = "ref_id = -1 AND "; } else { - $search_query_part = search_to_sql($link, $search, $match_on); + $search_query_part = search_to_sql($search); $search_query_part .= " AND "; } @@ -2176,10 +2325,10 @@ $override_order = "updated DESC"; - $filter_query_part = filter_to_sql($link, $filter, $owner_uid); + $filter_query_part = filter_to_sql($filter, $owner_uid); // Try to check if SQL regexp implementation chokes on a valid regexp - $result = db_query($link, "SELECT true AS true_val FROM ttrss_entries, + $result = db_query("SELECT true AS true_val FROM ttrss_entries, ttrss_user_entries, ttrss_feeds, ttrss_feed_categories WHERE $filter_query_part LIMIT 1", false); @@ -2207,18 +2356,19 @@ $view_query_part = ""; - if ($view_mode == "adaptive" || $view_query_part == "noscores") { + if ($view_mode == "adaptive") { if ($search) { $view_query_part = " "; } else if ($feed != -1) { - $unread = getFeedUnread($link, $feed, $cat_view); + + $unread = getFeedUnread($feed, $cat_view); if ($cat_view && $feed > 0 && $include_children) - $unread += getCategoryChildrenUnread($link, $feed); + $unread += getCategoryChildrenUnread($feed); + + if ($unread > 0) + $view_query_part = " unread = true AND "; - if ($unread > 0) { - $view_query_part = " unread = true AND "; - } } } @@ -2226,18 +2376,18 @@ $view_query_part = " marked = true AND "; } + if ($view_mode == "has_note") { + $view_query_part = " (note IS NOT NULL AND note != '') AND "; + } + if ($view_mode == "published") { $view_query_part = " published = true AND "; } - if ($view_mode == "unread") { + if ($view_mode == "unread" && $feed != -6) { $view_query_part = " unread = true AND "; } - if ($view_mode == "updated") { - $view_query_part = " (last_read is null and unread = false) AND "; - } - if ($limit > 0) { $limit_query_part = "LIMIT " . $limit; } @@ -2260,7 +2410,7 @@ if ($feed > 0) { if ($include_children) { - $subcats = getChildCategories($link, $feed, $owner_uid); + $subcats = getChildCategories($feed, $owner_uid); array_push($subcats, $feed); $cats_qpart = join(",", $subcats); } else { @@ -2280,7 +2430,7 @@ if ($feed > 0) { if ($include_children) { # sub-cats - $subcats = getChildCategories($link, $feed, $owner_uid); + $subcats = getChildCategories($feed, $owner_uid); array_push($subcats, $feed); $query_strategy_part = "cat_id IN (". @@ -2310,6 +2460,10 @@ $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; $allow_archived = true; + if (!$override_order) { + $override_order = "last_marked DESC, date_entered DESC, updated DESC"; + } + } else if ($feed == -2) { // published virtual feed OR labels category if (!$cat_view) { @@ -2317,7 +2471,10 @@ $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; $allow_archived = true; - if (!$override_order) $override_order = "last_read DESC, updated DESC"; + if (!$override_order) { + $override_order = "last_published DESC, date_entered DESC, updated DESC"; + } + } else { $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; @@ -2336,20 +2493,21 @@ } else if ($feed == -3) { // fresh virtual feed $query_strategy_part = "unread = true AND score >= 0"; - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); if (DB_TYPE == "pgsql") { - $query_strategy_part .= " AND updated > NOW() - INTERVAL '$intl hour' "; + $query_strategy_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' "; } else { - $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; + $query_strategy_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; } $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; } else if ($feed == -4) { // all articles virtual feed + $allow_archived = true; $query_strategy_part = "true"; $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; - } else if ($feed <= -10) { // labels - $label_id = -$feed - 11; + } else if ($feed <= LABEL_BASE_INDEX) { // labels + $label_id = feed_to_label_id($feed); $query_strategy_part = "label_id = '$label_id' AND ttrss_labels2.id = ttrss_user_labels2.label_id AND @@ -2363,20 +2521,10 @@ $query_strategy_part = "true"; } - if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) { - $date_sort_field = "updated"; - } else { - $date_sort_field = "date_entered"; - } - - if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) { - $order_by = "$date_sort_field"; - } else { - $order_by = "$date_sort_field DESC"; - } + $order_by = "score DESC, date_entered DESC, updated DESC"; - if ($view_mode != "noscores") { - $order_by = "score DESC, $order_by"; + if ($view_mode == "unread_first") { + $order_by = "unread DESC, $order_by"; } if ($override_order) { @@ -2389,17 +2537,18 @@ $feed_title = T_sprintf("Search results: %s", $search); } else { if ($cat_view) { - $feed_title = getCategoryTitle($link, $feed); + $feed_title = getCategoryTitle($feed); } else { if (is_numeric($feed) && $feed > 0) { - $result = db_query($link, "SELECT title,site_url,last_error + $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"); } else { - $feed_title = getFeedTitle($link, $feed); + $feed_title = getFeedTitle($feed); } } } @@ -2419,7 +2568,7 @@ } // proper override_order applied above - if ($vfeed_query_part && !$ignore_vfeed_group && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) { + 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"; } else { @@ -2436,6 +2585,9 @@ LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)"; } + if ($vfeed_query_part) + $vfeed_query_part .= "favicon_avg_color,"; + $query = "SELECT DISTINCT date_entered, guid, @@ -2449,11 +2601,11 @@ num_comments, comments, int_id, + hide_images, unread,feed_id,marked,published,link,last_read,orig_feed_id, - ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms, + last_marked, last_published, $vfeed_query_part $content_query_part - ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms, author,score FROM $from_qpart @@ -2470,7 +2622,7 @@ if ($_REQUEST["debug"]) print $query; - $result = db_query($link, $query); + $result = db_query($query); } else { // browsing by tag @@ -2492,11 +2644,11 @@ "label_cache," . "link," . "last_read," . - SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," . + "(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," . + "last_marked, last_published, " . $since_id_part . $vfeed_query_part . $content_query_part . - SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," . "score "; $feed_kind = "Tags"; @@ -2539,26 +2691,18 @@ // $tag_sql = "tag_name = '$feed'"; DEFAULT way // error_log("[". $select_qpart . "][" . $from_qpart . "][" .$where_qpart . "]"); - $result = db_query($link, $select_qpart . $from_qpart . $where_qpart); + $result = db_query($select_qpart . $from_qpart . $where_qpart); } - return array($result, $feed_title, $feed_site_url, $last_error); + return array($result, $feed_title, $feed_site_url, $last_error, $last_updated); } - function sanitize($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) { + function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false) { if (!$owner) $owner = $_SESSION["uid"]; $res = trim($str); if (!$res) return ''; - $config = array('safe' => 1, 'deny_attribute' => 'style, width, height, class, id', 'comment' => 1, 'cdata' => 1, 'balance' => 0); - $spec = 'img=width,height'; - $res = htmLawed($res, $config, $spec); - - if (get_pref($link, "STRIP_IMAGES", $owner)) { - $res = preg_replace('/<img[^>]+>/is', '', $res); - } - if (strpos($res, "href=") === false) $res = rewrite_urls($res); @@ -2584,10 +2728,35 @@ $entry->setAttribute('href', rewrite_relative_url($site_url, $entry->getAttribute('href'))); - if ($entry->hasAttribute('src')) - if (preg_match('/^image.php\?i=[a-z0-9]+$/', $entry->getAttribute('src')) == 0) - $entry->setAttribute('src', - rewrite_relative_url($site_url, $entry->getAttribute('src'))); + if ($entry->hasAttribute('src')) { + $src = rewrite_relative_url($site_url, $entry->getAttribute('src')); + + $cached_filename = CACHE_DIR . '/images/' . sha1($src) . '.png'; + + if (file_exists($cached_filename)) { + $src = SELF_URL_PATH . '/image.php?hash=' . sha1($src); + } + + $entry->setAttribute('src', $src); + } + + if ($entry->nodeName == 'img') { + if (($owner && get_pref("STRIP_IMAGES", $owner)) || + $force_remove_images || $_SESSION["bw_limit"]) { + + $p = $doc->createElement('p'); + + $a = $doc->createElement('a'); + $a->setAttribute('href', $entry->getAttribute('src')); + + $a->appendChild(new DOMText($entry->getAttribute('src'))); + $a->setAttribute('target', '_blank'); + + $p->appendChild($a); + + $entry->parentNode->replaceChild($p, $entry); + } + } } if (strtolower($entry->nodeName) == "a") { @@ -2595,12 +2764,78 @@ } } - $node = $doc->getElementsByTagName('body')->item(0); + $entries = $xpath->query('//iframe'); + foreach ($entries as $entry) { + $entry->setAttribute('sandbox', 'allow-scripts'); + + } + + $allowed_elements = array('a', 'address', 'audio', 'article', 'aside', + 'b', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', + 'caption', 'cite', 'center', 'code', 'col', 'colgroup', + 'data', 'dd', 'del', 'details', 'div', 'dl', 'font', + 'dt', 'em', 'footer', 'figure', 'figcaption', + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'html', 'i', + 'img', 'ins', 'kbd', 'li', 'main', 'mark', 'nav', 'noscript', + 'ol', 'p', 'pre', 'q', 'ruby', 'rp', 'rt', 's', 'samp', 'section', + 'small', 'source', 'span', 'strike', 'strong', 'sub', 'summary', + 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time', + 'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' ); + + if ($_SESSION['hasSandbox']) $allowed_elements[] = 'iframe'; + + $disallowed_attributes = array('id', 'style', 'class'); + + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SANITIZE) as $plugin) { + $retval = $plugin->hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes); + if (is_array($retval)) { + $doc = $retval[0]; + $allowed_elements = $retval[1]; + $disallowed_attributes = $retval[2]; + } else { + $doc = $retval; + } + } + + $doc->removeChild($doc->firstChild); //remove doctype + $doc = strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes); + $res = $doc->saveHTML(); + return $res; + } + + function strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) { + $xpath = new DOMXPath($doc); + $entries = $xpath->query('//*'); + + foreach ($entries as $entry) { + if (!in_array($entry->nodeName, $allowed_elements)) { + $entry->parentNode->removeChild($entry); + } + + if ($entry->hasAttributes()) { + $attrs_to_remove = array(); - return $doc->saveXML($node); + foreach ($entry->attributes as $attr) { + + if (strpos($attr->nodeName, 'on') === 0) { + array_push($attrs_to_remove, $attr); + } + + if (in_array($attr->nodeName, $disallowed_attributes)) { + array_push($attrs_to_remove, $attr); + } + } + + foreach ($attrs_to_remove as $attr) { + $entry->removeAttributeNode($attr); + } + } + } + + return $doc; } - function check_for_update($link) { + function check_for_update() { if (CHECK_FOR_NEW_VERSION && $_SESSION['access_level'] >= 10) { $version_url = "http://tt-rss.org/version.php?ver=" . VERSION . "&iid=" . sha1(SELF_URL_PATH); @@ -2610,8 +2845,7 @@ if ($version_data) { $version_data = json_decode($version_data, true); if ($version_data && $version_data['version']) { - - if (version_compare(VERSION, $version_data['version']) == -1) { + if (version_compare(VERSION_STATIC, $version_data['version']) == -1) { return $version_data; } } @@ -2620,7 +2854,7 @@ return false; } - function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) { + function catchupArticlesById($ids, $cmode, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; if (count($ids) == 0) return; @@ -2634,30 +2868,30 @@ $ids_qpart = join(" OR ", $tmp_ids); if ($cmode == 0) { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else if ($cmode == 1) { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("UPDATE ttrss_user_entries SET unread = true WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("UPDATE ttrss_user_entries SET unread = NOT unread,last_read = NOW() WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } /* update ccache */ - $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries + $result = db_query("SELECT DISTINCT feed_id FROM ttrss_user_entries WHERE ($ids_qpart) AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { - ccache_update($link, $line["feed_id"], $owner_uid); + ccache_update($line["feed_id"], $owner_uid); } } - function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) { + function get_article_tags($id, $owner_uid = 0, $tag_cache = false) { $a_id = db_escape_string($id); @@ -2668,13 +2902,12 @@ ttrss_tags WHERE post_int_id = (SELECT int_id FROM ttrss_user_entries WHERE ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1) ORDER BY tag_name"; - $obj_id = md5("TAGS:$owner_uid:$id"); $tags = array(); /* check cache first */ if ($tag_cache === false) { - $result = db_query($link, "SELECT tag_cache FROM ttrss_user_entries + $result = db_query("SELECT tag_cache FROM ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = $owner_uid"); $tag_cache = db_fetch_result($result, 0, "tag_cache"); @@ -2686,7 +2919,7 @@ /* do it the hard way */ - $tmp_result = db_query($link, $query); + $tmp_result = db_query($query); while ($tmp_line = db_fetch_assoc($tmp_result)) { array_push($tags, $tmp_line["tag_name"]); @@ -2696,7 +2929,7 @@ $tags_str = db_escape_string(join(",", $tags)); - db_query($link, "UPDATE ttrss_user_entries + db_query("UPDATE ttrss_user_entries SET tag_cache = '$tags_str' WHERE ref_id = '$id' AND owner_uid = $owner_uid"); } @@ -2724,43 +2957,29 @@ return true; } - function render_login_form($link, $form_id = 0) { - switch ($form_id) { - case 0: - require_once "login_form.php"; - break; - case 1: - require_once "mobile/login_form.php"; - break; - } - exit; - } + function render_login_form() { + header('Cache-Control: public'); - // from http://developer.apple.com/internet/safari/faq.html - function no_cache_incantation() { - header("Expires: Mon, 22 Dec 1980 00:00:00 GMT"); // Happy birthday to me :) - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified - header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1 - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); // HTTP/1.0 + require_once "login_form.php"; + exit; } function format_warning($msg, $id = "") { global $link; return "<div class=\"warning\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_excl.svg")."\">$msg</div>"; + <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>"; } function format_notice($msg, $id = "") { global $link; return "<div class=\"notice\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_info.svg")."\">$msg</div>"; + <span><img src=\"images/sign_info.svg\"></span><span>$msg</span></div>"; } function format_error($msg, $id = "") { global $link; return "<div class=\"error\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_excl.svg")."\">$msg</div>"; + <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>"; } function print_notice($msg) { @@ -2781,26 +3000,21 @@ return vsprintf(__(array_shift($args)), $args); } - function format_inline_player($link, $url, $ctype) { + function format_inline_player($url, $ctype) { $entry = ""; + $url = htmlspecialchars($url); + if (strpos($ctype, "audio/") === 0) { if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false || - strpos($_SERVER['HTTP_USER_AGENT'], "Chrome") !== false || - strpos($_SERVER['HTTP_USER_AGENT'], "Safari") !== false )) { - - $id = 'AUDIO-' . uniqid(); + $_SESSION["hasMp3"])) { - $entry .= "<audio id=\"$id\"\" controls style='display : none'> + $entry .= "<audio controls> <source type=\"$ctype\" src=\"$url\"></source> </audio>"; - $entry .= "<span onclick=\"player(this)\" - title=\"".__("Click to play")."\" status=\"0\" - class=\"player\" audio-id=\"$id\">".__("Play")."</span>"; - } else { $entry .= "<object type=\"application/x-shockwave-flash\" @@ -2811,7 +3025,8 @@ </object>"; } - if ($entry) $entry .= " " . basename($url); + if ($entry) $entry .= " <a target=\"_blank\" + href=\"$url\">" . basename($url) . "</a>"; return $entry; @@ -2826,7 +3041,7 @@ } - function format_article($link, $id, $mark_as_read = true, $zoom_mode = false, $owner_uid = false) { + function format_article($id, $mark_as_read = true, $zoom_mode = false, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $rv = array(); @@ -2834,9 +3049,9 @@ $rv['id'] = $id; /* we can figure out feed_id from article id anyway, why do we - * pass feed_id here? let's ignore the argument :( */ + * pass feed_id here? let's ignore the argument :(*/ - $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries + $result = db_query("SELECT feed_id FROM ttrss_user_entries WHERE ref_id = '$id'"); $feed_id = (int) db_fetch_result($result, 0, "feed_id"); @@ -2846,16 +3061,18 @@ //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; }; if ($mark_as_read) { - $result = db_query($link, "UPDATE ttrss_user_entries + $result = db_query("UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE ref_id = '$id' AND owner_uid = $owner_uid"); - ccache_update($link, $feed_id, $owner_uid); + ccache_update($feed_id, $owner_uid); } - $result = db_query($link, "SELECT id,title,link,content,feed_id,comments,int_id, + $result = db_query("SELECT id,title,link,content,feed_id,comments,int_id, ".SUBSTRING_FOR_DATE."(updated,1,16) as updated, (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url, + (SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) as hide_images, + (SELECT always_display_enclosures FROM ttrss_feeds WHERE id = feed_id) as always_display_enclosures, num_comments, tag_cache, author, @@ -2871,14 +3088,12 @@ $tag_cache = $line["tag_cache"]; - $line["tags"] = get_article_tags($link, $id, $owner_uid, $line["tag_cache"]); + $line["tags"] = get_article_tags($id, $owner_uid, $line["tag_cache"]); unset($line["tag_cache"]); - $line["content"] = sanitize($link, $line["content"], false, $owner_uid, $line["site_url"]); + $line["content"] = sanitize($line["content"], false, $owner_uid, $line["site_url"]); - global $pluginhost; - - foreach ($pluginhost->get_hooks($pluginhost::HOOK_RENDER_ARTICLE) as $p) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE) as $p) { $line = $p->hook_render_article($line); } @@ -2904,14 +3119,9 @@ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/> <title>Tiny Tiny RSS - ".$line["title"]."</title> <link rel=\"stylesheet\" type=\"text/css\" href=\"tt-rss.css\"> - </head><body>"; + </head><body id=\"ttrssZoom\">"; } - $title_escaped = htmlspecialchars($line['title']); - - $rv['content'] .= "<div id=\"PTITLE-FULL-$id\" style=\"display : none\">" . - strip_tags($line['title']) . "</div>"; - $rv['content'] .= "<div class=\"postReply\" id=\"POST-$id\">"; $rv['content'] .= "<div class=\"postHeader\" id=\"POSTHDR-$id\">"; @@ -2922,7 +3132,7 @@ $entry_author = __(" - ") . $entry_author; } - $parsed_updated = make_local_datetime($link, $line["updated"], true, + $parsed_updated = make_local_datetime($line["updated"], true, $owner_uid, true); $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>"; @@ -2932,8 +3142,8 @@ title=\"".htmlspecialchars($line['title'])."\" href=\"" . htmlspecialchars($line["link"]) . "\">" . - $line["title"] . - "<span class='author'>$entry_author</span></a></div>"; + $line["title"] . "</a>" . + "<span class='author'>$entry_author</span></div>"; } else { $rv['content'] .= "<div class='postTitle'>" . $line["title"] . "$entry_author</div>"; } @@ -2946,7 +3156,7 @@ if (!$entry_comments) $entry_comments = " "; # placeholder $rv['content'] .= "<div class='postTags' style='float : right'> - <img src='".theme_image($link, 'images/tag.png')."' + <img src='images/tag.png' class='tagsPic' alt='Tags' title='Tags'> "; if (!$zoom_mode) { @@ -2958,23 +3168,26 @@ id=\"ATSTRTIP-$id\" connectId=\"ATSTR-$id\" position=\"below\">$tags_str_full</div>"; - global $pluginhost; - - foreach ($pluginhost->get_hooks($pluginhost::HOOK_ARTICLE_BUTTON) as $p) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_BUTTON) as $p) { $rv['content'] .= $p->hook_article_button($line); } - } else { $tags_str = strip_tags($tags_str); $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>"; } $rv['content'] .= "</div>"; - $rv['content'] .= "<div clear='both'>$entry_comments</div>"; + $rv['content'] .= "<div clear='both'>"; + + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) { + $rv['content'] .= $p->hook_article_left_button($line); + } + + $rv['content'] .= "$entry_comments</div>"; if ($line["orig_feed_id"]) { - $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds + $tmp_result = db_query("SELECT * FROM ttrss_archived_feeds WHERE id = ".$line["orig_feed_id"]); if (db_num_rows($tmp_result) != 0) { @@ -3009,35 +3222,11 @@ $rv['content'] .= "<div class=\"postContent\">"; - // N-grams - - if (DB_TYPE == "pgsql" and defined('_NGRAM_TITLE_RELATED_THRESHOLD')) { - - $ngram_result = db_query($link, "SELECT id,title FROM - ttrss_entries,ttrss_user_entries - WHERE ref_id = id AND updated >= NOW() - INTERVAL '7 day' - AND similarity(title, '$title_escaped') >= "._NGRAM_TITLE_RELATED_THRESHOLD." - AND title != '$title_escaped' - AND owner_uid = $owner_uid"); - - if (db_num_rows($ngram_result) > 0) { - $rv['content'] .= "<div dojoType=\"dijit.form.DropDownButton\">". - "<span>" . __('Related')."</span>"; - $rv['content'] .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - - while ($nline = db_fetch_assoc($ngram_result)) { - $rv['content'] .= "<div onclick=\"hlOpenInNewTab(null,".$nline['id'].")\" - dojoType=\"dijit.MenuItem\">".$nline['title']."</div>"; - - } - $rv['content'] .= "</div></div><br/"; - } - } - $rv['content'] .= $line["content"]; - - $rv['content'] .= format_article_enclosures($link, $id, - $always_display_enclosures, $line["content"]); + $rv['content'] .= format_article_enclosures($id, + sql_bool_to_bool($line["always_display_enclosures"]), + $line["content"], + sql_bool_to_bool($line["hide_images"])); $rv['content'] .= "</div>"; @@ -3047,7 +3236,7 @@ if ($zoom_mode) { $rv['content'] .= " - <div style=\"text-align : center\"> + <div class='footer'> <button onclick=\"return window.close()\">". __("Close this window")."</button></div>"; $rv['content'] .= "</body></html>"; @@ -3059,7 +3248,7 @@ function print_checkpoint($n, $s) { $ts = microtime(true); - echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s); + echo sprintf("<!-- CP[$n] %.4f seconds -->\n", $ts - $s); return $ts; } @@ -3108,23 +3297,23 @@ } } // function encrypt_password - function load_filters($link, $feed_id, $owner_uid, $action_id = false) { + function load_filters($feed_id, $owner_uid, $action_id = false) { $filters = array(); - $cat_id = (int)getFeedCategory($link, $feed_id); + $cat_id = (int)getFeedCategory($feed_id); - $result = db_query($link, "SELECT * FROM ttrss_filters2 WHERE - owner_uid = $owner_uid AND enabled = true"); + $result = db_query("SELECT * FROM ttrss_filters2 WHERE + owner_uid = $owner_uid AND enabled = true ORDER BY order_id, title"); $check_cats = join(",", array_merge( - getParentCategories($link, $cat_id, $owner_uid), + getParentCategories($cat_id, $owner_uid), array($cat_id))); while ($line = db_fetch_assoc($result)) { $filter_id = $line["id"]; - $result2 = db_query($link, "SELECT - r.reg_exp, r.feed_id, r.cat_id, r.cat_filter, t.name AS type_name + $result2 = db_query("SELECT + r.reg_exp, r.inverse, r.feed_id, r.cat_id, r.cat_filter, t.name AS type_name FROM ttrss_filters2_rules AS r, ttrss_filter_types AS t WHERE @@ -3141,11 +3330,12 @@ $rule = array(); $rule["reg_exp"] = $rule_line["reg_exp"]; $rule["type"] = $rule_line["type_name"]; + $rule["inverse"] = sql_bool_to_bool($rule_line["inverse"]); array_push($rules, $rule); } - $result2 = db_query($link, "SELECT a.action_param,t.name AS type_name + $result2 = db_query("SELECT a.action_param,t.name AS type_name FROM ttrss_filters2_actions AS a, ttrss_filter_actions AS t WHERE @@ -3164,6 +3354,7 @@ $filter = array(); $filter["match_any_rule"] = sql_bool_to_bool($line["match_any_rule"]); + $filter["inverse"] = sql_bool_to_bool($line["inverse"]); $filter["rules"] = $rules; $filter["actions"] = $actions; @@ -3193,80 +3384,35 @@ return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0; } - function init_connection($link) { - if ($link) { - - if (DB_TYPE == "pgsql") { - pg_query($link, "set client_encoding = 'UTF-8'"); - pg_set_client_encoding("UNICODE"); - pg_query($link, "set datestyle = 'ISO, european'"); - pg_query($link, "set TIME ZONE 0"); - } else { - db_query($link, "SET time_zone = '+0:0'"); - - if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) { - db_query($link, "SET NAMES " . MYSQL_CHARSET); - } - } + function init_plugins() { + PluginHost::getInstance()->load(PLUGINS, PluginHost::KIND_ALL); - global $pluginhost; - - $pluginhost = new PluginHost($link); - $pluginhost->load(PLUGINS, $pluginhost::KIND_ALL); - - return true; - } else { - print "Unable to connect to database:" . db_last_error(); - return false; - } + return true; } function format_tags_string($tags, $id) { + if (!is_array($tags) || count($tags) == 0) { + return __("no tags"); + } else { + $maxtags = min(5, count($tags)); - $tags_str = ""; - $tags_nolinks_str = ""; - - $num_tags = 0; - - $tag_limit = 6; - - $formatted_tags = array(); - - foreach ($tags as $tag) { - $num_tags++; - $tag_escaped = str_replace("'", "\\'", $tag); - - if (mb_strlen($tag) > 30) { - $tag = truncate_string($tag, 30); + for ($i = 0; $i < $maxtags; $i++) { + $tags_str .= "<a class=\"tag\" href=\"#\" onclick=\"viewfeed('".$tags[$i]."'\")>" . $tags[$i] . "</a>, "; } - $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>"; - - array_push($formatted_tags, $tag_str); + $tags_str = mb_substr($tags_str, 0, mb_strlen($tags_str)-2); - $tmp_tags_str = implode(", ", $formatted_tags); + if (count($tags) > $maxtags) + $tags_str .= ", …"; - if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) { - break; - } + return $tags_str; } - - $tags_str = implode(", ", $formatted_tags); - - if ($num_tags < count($tags)) { - $tags_str .= ", …"; - } - - if ($num_tags == 0) { - $tags_str = __("no tags"); - } - - return $tags_str; - } function format_article_labels($labels, $id) { + if (!is_array($labels)) return ''; + $labels_str = ""; foreach ($labels as $l) { @@ -3289,7 +3435,7 @@ } - function get_feed_category($link, $feed_cat, $parent_cat_id = false) { + function get_feed_category($feed_cat, $parent_cat_id = false) { if ($parent_cat_id) { $parent_qpart = "parent_cat = '$parent_cat_id'"; $parent_insert = "'$parent_cat_id'"; @@ -3298,7 +3444,7 @@ $parent_insert = "NULL"; } - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feed_categories WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]); @@ -3309,11 +3455,11 @@ } } - function add_feed_category($link, $feed_cat, $parent_cat_id = false) { + function add_feed_category($feed_cat, $parent_cat_id = false) { if (!$feed_cat) return false; - db_query($link, "BEGIN"); + db_query("BEGIN"); if ($parent_cat_id) { $parent_qpart = "parent_cat = '$parent_cat_id'"; @@ -3323,17 +3469,19 @@ $parent_insert = "NULL"; } - $result = db_query($link, + $feed_cat = mb_substr($feed_cat, 0, 250); + + $result = db_query( "SELECT id FROM ttrss_feed_categories WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]); if (db_num_rows($result) == 0) { - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat) VALUES ('".$_SESSION["uid"]."', '$feed_cat', $parent_insert)"); - db_query($link, "COMMIT"); + db_query("COMMIT"); return true; } @@ -3341,8 +3489,8 @@ return false; } - function getArticleFeed($link, $id) { - $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries + function getArticleFeed($id) { + $result = db_query("SELECT feed_id FROM ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]); if (db_num_rows($result) != 0) { @@ -3387,14 +3535,14 @@ } - function get_article_enclosures($link, $id) { + function get_article_enclosures($id) { $query = "SELECT * FROM ttrss_enclosures WHERE post_id = '$id' AND content_url != ''"; $rv = array(); - $result = db_query($link, $query); + $result = db_query($query); if (db_num_rows($result) > 0) { while ($line = db_fetch_assoc($result)) { @@ -3405,7 +3553,7 @@ return $rv; } - function save_email_address($link, $email) { + function save_email_address($email) { // FIXME: implement persistent storage of emails if (!$_SESSION['stored_emails']) @@ -3416,13 +3564,13 @@ } - function get_feed_access_key($link, $feed_id, $is_cat, $owner_uid = false) { + function get_feed_access_key($feed_id, $is_cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $sql_is_cat = bool_to_sql_bool($is_cat); - $result = db_query($link, "SELECT access_key FROM ttrss_access_keys + $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); @@ -3431,7 +3579,7 @@ } else { $key = db_escape_string(sha1(uniqid(rand(), true))); - $result = db_query($link, "INSERT INTO ttrss_access_keys + $result = db_query("INSERT INTO ttrss_access_keys (access_key, feed_id, is_cat, owner_uid) VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')"); @@ -3475,9 +3623,9 @@ return is_html(fetch_file_contents($url, false, $login, $pass)); } - function print_label_select($link, $name, $value, $attributes = "") { + function print_label_select($name, $value, $attributes = "") { - $result = db_query($link, "SELECT caption FROM ttrss_labels2 + $result = db_query("SELECT caption FROM ttrss_labels2 WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption"); print "<select default=\"$value\" name=\"" . htmlspecialchars($name) . @@ -3499,10 +3647,10 @@ } - function format_article_enclosures($link, $id, $always_display_enclosures, - $article_content) { + function format_article_enclosures($id, $always_display_enclosures, + $article_content, $hide_images = false) { - $result = get_article_enclosures($link, $id); + $result = get_article_enclosures($id); $rv = ''; if (count($result) > 0) { @@ -3520,7 +3668,7 @@ $filename = substr($url, strrpos($url, "/")+1); - $player = format_inline_player($link, $url, $ctype); + $player = format_inline_player($url, $ctype); if ($player) array_push($entries_inline, $player); @@ -3541,7 +3689,7 @@ array_push($entries, $entry); } - if (!get_pref($link, "STRIP_IMAGES")) { + if ($_SESSION['uid'] && !get_pref("STRIP_IMAGES") && !$_SESSION["bw_limit"]) { if ($always_display_enclosures || !preg_match("/<img/i", $article_content)) { @@ -3550,10 +3698,16 @@ if (preg_match("/image/", $entry["type"]) || preg_match("/\.(jpg|png|gif|bmp)/i", $entry["filename"])) { - $rv .= "<p><img - alt=\"".htmlspecialchars($entry["filename"])."\" - src=\"" .htmlspecialchars($entry["url"]) . "\"/></p>"; + if (!$hide_images) { + $rv .= "<p><img + alt=\"".htmlspecialchars($entry["filename"])."\" + src=\"" .htmlspecialchars($entry["url"]) . "\"/></p>"; + } else { + $rv .= "<p><a target=\"_blank\" + href=\"".htmlspecialchars($entry["url"])."\" + >" .htmlspecialchars($entry["url"]) . "</a></p>"; + } } } } @@ -3565,20 +3719,22 @@ $rv .= "<hr clear='both'/>"; } - $rv .= "<br/><div dojoType=\"dijit.form.DropDownButton\">". - "<span>" . __('Attachments')."</span>"; - $rv .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; + $rv .= "<select class=\"attachments\" onchange=\"openSelectedAttachment(this)\">". + "<option value=''>" . __('Attachments')."</option>"; + + foreach ($entries as $entry) { + $rv .= "<option value=\"".htmlspecialchars($entry["url"])."\">" . htmlspecialchars($entry["filename"]) . "</option>"; - foreach ($entries_html as $entry) { $rv .= $entry; }; + }; - $rv .= "</div></div>"; + $rv .= "</select>"; } return $rv; } - function getLastArticleId($link) { - $result = db_query($link, "SELECT MAX(ref_id) AS id FROM ttrss_user_entries + function getLastArticleId() { + $result = db_query("SELECT MAX(ref_id) AS id FROM ttrss_user_entries WHERE owner_uid = " . $_SESSION["uid"]); if (db_num_rows($result) == 1) { @@ -3636,7 +3792,9 @@ $sphinxClient = new SphinxClient(); - $sphinxClient->SetServer('localhost', 9312); + $sphinxpair = explode(":", SPHINX_SERVER, 2); + + $sphinxClient->SetServer($sphinxpair[0], $sphinxpair[1]); $sphinxClient->SetConnectTimeout(1); $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30, @@ -3662,7 +3820,7 @@ return $ids; } - function cleanup_tags($link, $days = 14, $limit = 1000) { + function cleanup_tags($days = 14, $limit = 1000) { if (DB_TYPE == "pgsql") { $interval_query = "date_updated < NOW() - INTERVAL '$days days'"; @@ -3680,7 +3838,7 @@ WHERE post_int_id = int_id AND $interval_query AND ref_id = ttrss_entries.id AND tag_cache != '' LIMIT $limit_part"; - $result = db_query($link, $query); + $result = db_query($query); $ids = array(); @@ -3690,10 +3848,9 @@ if (count($ids) > 0) { $ids = join(",", $ids); - print "."; - $tmp_result = db_query($link, "DELETE FROM ttrss_tags WHERE id IN ($ids)"); - $tags_deleted += db_affected_rows($link, $tmp_result); + $tmp_result = db_query("DELETE FROM ttrss_tags WHERE id IN ($ids)"); + $tags_deleted += db_affected_rows($tmp_result); } else { break; } @@ -3701,13 +3858,11 @@ $limit -= $limit_part; } - print "\n"; - return $tags_deleted; } - function print_user_stylesheet($link) { - $value = get_pref($link, 'USER_STYLESHEET'); + function print_user_stylesheet() { + $value = get_pref('USER_STYLESHEET'); if ($value) { print "<style type=\"text/css\">"; @@ -3763,7 +3918,7 @@ return $html; } - function filter_to_sql($link, $filter, $owner_uid) { + function filter_to_sql($filter, $owner_uid) { $query = array(); if (DB_TYPE == "pgsql") @@ -3779,7 +3934,7 @@ $rule['reg_exp'] = db_escape_string($rule['reg_exp']); - switch ($rule["type"]) { + switch ($rule["type"]) { case "title": $qpart = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". $rule['reg_exp'] . "')"; @@ -3807,6 +3962,8 @@ break; } + 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"]); } @@ -3814,7 +3971,7 @@ if (isset($rule["cat_id"])) { if ($rule["cat_id"] > 0) { - $children = getChildCategories($link, $rule["cat_id"], $owner_uid); + $children = getChildCategories($rule["cat_id"], $owner_uid); array_push($children, $rule["cat_id"]); $children = join(",", $children); @@ -3833,10 +3990,14 @@ } if (count($query) > 0) { - return "(" . join($filter["match_any_rule"] ? "OR" : "AND", $query) . ")"; + $fullquery = "(" . join($filter["match_any_rule"] ? "OR" : "AND", $query) . ")"; } else { - return "(false)"; + $fullquery = "(false)"; } + + if ($filter['inverse']) $fullquery = "(NOT $fullquery)"; + + return $fullquery; } if (!function_exists('gzdecode')) { @@ -3884,8 +4045,8 @@ return $tempname; } - function getFeedCategory($link, $feed) { - $result = db_query($link, "SELECT cat_id FROM ttrss_feeds + function getFeedCategory($feed) { + $result = db_query("SELECT cat_id FROM ttrss_feeds WHERE id = '$feed'"); if (db_num_rows($result) > 0) { @@ -3900,4 +4061,167 @@ return in_array($interface, class_implements($class)); } + function geturl($url){ + + if (!function_exists('curl_init')) + return user_error('CURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini', E_USER_ERROR); + + $curl = curl_init(); + $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,"; + $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; + $header[] = "Cache-Control: max-age=0"; + $header[] = "Connection: keep-alive"; + $header[] = "Keep-Alive: 300"; + $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"; + $header[] = "Accept-Language: en-us,en;q=0.5"; + $header[] = "Pragma: "; + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0'); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_HEADER, true); + curl_setopt($curl, CURLOPT_REFERER, $url); + curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate'); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled... + curl_setopt($curl, CURLOPT_TIMEOUT, 60); + + $html = curl_exec($curl); + + $status = curl_getinfo($curl); + curl_close($curl); + + if($status['http_code']!=200){ + if($status['http_code'] == 301 || $status['http_code'] == 302) { + list($header) = explode("\r\n\r\n", $html, 2); + $matches = array(); + preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches); + $url = trim(str_replace($matches[1],"",$matches[0])); + $url_parsed = parse_url($url); + return (isset($url_parsed))? geturl($url):''; + } + $oline=''; + foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';} + $line =$oline." \r\n ".$url."\r\n-----------------\r\n"; +# $handle = @fopen('./curl.error.log', 'a'); +# fwrite($handle, $line); + return FALSE; + } + return $url; + } + + function get_minified_js($files) { + require_once 'lib/jshrink/Minifier.php'; + + $rv = ''; + + foreach ($files as $js) { + if (!isset($_GET['debug'])) { + $cached_file = CACHE_DIR . "/js/".basename($js).".js"; + + if (file_exists($cached_file) && + is_readable($cached_file) && + filemtime($cached_file) >= filemtime("js/$js.js")) { + + $rv .= file_get_contents($cached_file); + + } else { + $minified = JShrink\Minifier::minify(file_get_contents("js/$js.js")); + file_put_contents($cached_file, $minified); + $rv .= $minified; + } + } else { + $rv .= file_get_contents("js/$js.js"); + } + } + + return $rv; + } + + function stylesheet_tag($filename) { + $timestamp = filemtime($filename); + + echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$filename?$timestamp\"/>\n"; + } + + function javascript_tag($filename) { + $query = ""; + + if (!(strpos($filename, "?") === FALSE)) { + $query = substr($filename, strpos($filename, "?")+1); + $filename = substr($filename, 0, strpos($filename, "?")); + } + + $timestamp = filemtime($filename); + + if ($query) $timestamp .= "&$query"; + + echo "<script type=\"text/javascript\" charset=\"utf-8\" src=\"$filename?$timestamp\"></script>\n"; + } + + function calculate_dep_timestamp() { + $files = array_merge(glob("js/*.js"), glob("*.css")); + + $max_ts = -1; + + foreach ($files as $file) { + if (filemtime($file) > $max_ts) $max_ts = filemtime($file); + } + + return $max_ts; + } + + function T_js_decl($s1, $s2) { + if ($s1 && $s2) { + $s1 = preg_replace("/\n/", "", $s1); + $s2 = preg_replace("/\n/", "", $s2); + + $s1 = preg_replace("/\"/", "\\\"", $s1); + $s2 = preg_replace("/\"/", "\\\"", $s2); + + return "T_messages[\"$s1\"] = \"$s2\";\n"; + } + } + + function init_js_translations() { + + print 'var T_messages = new Object(); + + function __(msg) { + if (T_messages[msg]) { + return T_messages[msg]; + } else { + return msg; + } + } + + function ngettext(msg1, msg2, n) { + return (parseInt(n) > 1) ? msg2 : msg1; + }'; + + $l10n = _get_reader(); + + for ($i = 0; $i < $l10n->total; $i++) { + $orig = $l10n->get_original_string($i); + $translation = __($orig); + + print T_js_decl($orig, $translation); + } + } + + function label_to_feed_id($label) { + return LABEL_BASE_INDEX - 1 - abs($label); + } + + function feed_to_label_id($feed) { + return LABEL_BASE_INDEX - 1 + abs($feed); + } + + function format_libxml_error($error) { + return T_sprintf("LibXML error %s at line %d (column %d): %s", + $error->code, $error->line, $error->column, + $error->message); + } + ?> diff --git a/include/labels.php b/include/labels.php index da7e3f97b..c2a48a338 100644 --- a/include/labels.php +++ b/include/labels.php @@ -1,6 +1,6 @@ <?php - function label_find_id($link, $label, $owner_uid) { - $result = db_query($link, + function label_find_id($label, $owner_uid) { + $result = db_query( "SELECT id FROM ttrss_labels2 WHERE caption = '$label' AND owner_uid = '$owner_uid' LIMIT 1"); @@ -11,12 +11,12 @@ } } - function get_article_labels($link, $id, $owner_uid = false) { + function get_article_labels($id, $owner_uid = false) { $rv = array(); if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT label_cache FROM + $result = db_query("SELECT label_cache FROM ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = " . $owner_uid); @@ -33,7 +33,7 @@ } } - $result = db_query($link, + $result = db_query( "SELECT DISTINCT label_id,caption,fg_color,bg_color FROM ttrss_labels2, ttrss_user_labels2 WHERE id = label_id @@ -48,16 +48,16 @@ } if (count($rv) > 0) - label_update_cache($link, $owner_uid, $id, $rv); + label_update_cache($owner_uid, $id, $rv); else - label_update_cache($link, $owner_uid, $id, array("no-labels" => 1)); + label_update_cache($owner_uid, $id, array("no-labels" => 1)); return $rv; } - function label_find_caption($link, $label, $owner_uid) { - $result = db_query($link, + function label_find_caption($label, $owner_uid) { + $result = db_query( "SELECT caption FROM ttrss_labels2 WHERE id = '$label' AND owner_uid = '$owner_uid' LIMIT 1"); @@ -68,10 +68,10 @@ } } - function get_all_labels($link, $owner_uid) { + function get_all_labels($owner_uid) { $rv = array(); - $result = db_query($link, "SELECT fg_color, bg_color, caption FROM ttrss_labels2 WHERE owner_uid = " . $owner_uid); + $result = db_query("SELECT fg_color, bg_color, caption FROM ttrss_labels2 WHERE owner_uid = " . $owner_uid); while ($line = db_fetch_assoc($result)) { array_push($rv, $line); @@ -80,50 +80,50 @@ return $rv; } - function label_update_cache($link, $owner_uid, $id, $labels = false, $force = false) { + function label_update_cache($owner_uid, $id, $labels = false, $force = false) { if ($force) - label_clear_cache($link, $id); + label_clear_cache($id); if (!$labels) - $labels = get_article_labels($link, $id); + $labels = get_article_labels($id); $labels = db_escape_string(json_encode($labels)); - db_query($link, "UPDATE ttrss_user_entries SET + db_query("UPDATE ttrss_user_entries SET label_cache = '$labels' WHERE ref_id = '$id' AND owner_uid = '$owner_uid'"); } - function label_clear_cache($link, $id) { + function label_clear_cache($id) { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("UPDATE ttrss_user_entries SET label_cache = '' WHERE ref_id = '$id'"); } - function label_remove_article($link, $id, $label, $owner_uid) { + function label_remove_article($id, $label, $owner_uid) { - $label_id = label_find_id($link, $label, $owner_uid); + $label_id = label_find_id($label, $owner_uid); if (!$label_id) return; - $result = db_query($link, + $result = db_query( "DELETE FROM ttrss_user_labels2 WHERE label_id = '$label_id' AND article_id = '$id'"); - label_clear_cache($link, $id); + label_clear_cache($id); } - function label_add_article($link, $id, $label, $owner_uid) { + function label_add_article($id, $label, $owner_uid) { - $label_id = label_find_id($link, $label, $owner_uid); + $label_id = label_find_id($label, $owner_uid); if (!$label_id) return; - $result = db_query($link, + $result = db_query( "SELECT article_id FROM ttrss_labels2, ttrss_user_labels2 WHERE @@ -133,73 +133,66 @@ LIMIT 1"); if (db_num_rows($result) == 0) { - db_query($link, "INSERT INTO ttrss_user_labels2 + db_query("INSERT INTO ttrss_user_labels2 (label_id, article_id) VALUES ('$label_id', '$id')"); } - label_clear_cache($link, $id); + label_clear_cache($id); } - function label_remove($link, $id, $owner_uid) { + function label_remove($id, $owner_uid) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - db_query($link, "BEGIN"); + db_query("BEGIN"); - $result = db_query($link, "SELECT caption FROM ttrss_labels2 + $result = db_query("SELECT caption FROM ttrss_labels2 WHERE id = '$id'"); $caption = db_fetch_result($result, 0, "caption"); - $result = db_query($link, "DELETE FROM ttrss_labels2 WHERE id = '$id' + $result = db_query("DELETE FROM ttrss_labels2 WHERE id = '$id' AND owner_uid = " . $owner_uid); - if (db_affected_rows($link, $result) != 0 && $caption) { + if (db_affected_rows($result) != 0 && $caption) { /* Remove access key for the label */ - $ext_id = -11 - $id; + $ext_id = LABEL_BASE_INDEX - 1 - $id; - db_query($link, "DELETE FROM ttrss_access_keys WHERE + db_query("DELETE FROM ttrss_access_keys WHERE feed_id = '$ext_id' AND owner_uid = $owner_uid"); - /* Disable filters that reference label being removed */ - - db_query($link, "UPDATE ttrss_filters SET - enabled = false WHERE action_param = '$caption' - AND action_id = 7 - AND owner_uid = " . $owner_uid); - /* Remove cached data */ - db_query($link, "UPDATE ttrss_user_entries SET label_cache = '' + db_query("UPDATE ttrss_user_entries SET label_cache = '' WHERE label_cache LIKE '%$caption%' AND owner_uid = " . $owner_uid); } - db_query($link, "COMMIT"); + db_query("COMMIT"); } - function label_create($link, $caption, $fg_color = '', $bg_color = '', $owner_uid) { + function label_create($caption, $fg_color = '', $bg_color = '', $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION['uid']; - db_query($link, "BEGIN"); + db_query("BEGIN"); $result = false; - $result = db_query($link, "SELECT id FROM ttrss_labels2 + $result = db_query("SELECT id FROM ttrss_labels2 WHERE caption = '$caption' AND owner_uid = $owner_uid"); if (db_num_rows($result) == 0) { - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_labels2 (caption,owner_uid,fg_color,bg_color) VALUES ('$caption', '$owner_uid', '$fg_color', '$bg_color')"); - $result = db_affected_rows($link, $result) != 0; + $result = db_affected_rows($result) != 0; } - db_query($link, "COMMIT"); + db_query("COMMIT"); return $result; } diff --git a/include/localized_schema.php b/include/localized_schema.php deleted file mode 100644 index 3497c9c27..000000000 --- a/include/localized_schema.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php # This file has been generated at: Sun Feb 17 13:58:53 MSK 2013 - -__("Title"); -__("Title or Content"); -__("Link"); -__("Content"); -__("Article Date"); - -__("Delete article"); -__("Mark as read"); -__("Set starred"); -__("Publish article"); -__("Assign tags"); -__("Assign label"); -__("Modify score"); - -__("General"); -__("Interface"); -__("Advanced"); - -__('This option is useful when you are reading several planet-type aggregators with partially colliding userbase. When disabled, it forces same posts from different feeds to appear only once.'); -__('Display expanded list of feed articles, instead of separate displays for headlines and article content'); -__('Automatically open next feed with unread articles after marking one as read'); -__('This option enables sending daily digest of new (and unread) headlines on your configured e-mail address'); -__('This option enables marking articles as read automatically while you scroll article list.'); -__('Strip all but most common HTML tags when reading articles.'); -__('When auto-detecting tags in articles these tags will not be applied (comma-separated list).'); -__('When this option is enabled, headlines in Special feeds and Labels are grouped by feeds'); -__('Customize CSS stylesheet to your liking'); -__('Use feed-specified date to sort headlines instead of local import date.'); -__('Click to register your SSL client certificate with tt-rss'); -__('Uses UTC timezone'); -__('Purge articles after this number of days (0 - disables)'); -__('Default interval between feed updates'); -__('Amount of articles to display at once'); -__('Allow duplicate posts'); -__('Enable feed categories'); -__('Show content preview in headlines list'); -__('Short date format'); -__('Long date format'); -__('Combined feed display'); -__('Hide feeds with no unread messages'); -__('On catchup show next feed'); -__('Sort feeds by unread articles count'); -__('Reverse headline order (oldest first)'); -__('Enable e-mail digest'); -__('Confirm marking feed as read'); -__('Automatically mark articles as read'); -__('Strip unsafe tags from articles'); -__('Blacklisted tags'); -__('Maximum age of fresh articles (in hours)'); -__('Mark articles in e-mail digest as read'); -__('Automatically expand articles in combined mode'); -__('Purge unread articles'); -__('Show special feeds when hiding read feeds'); -__('Group headlines in virtual feeds'); -__('Do not show images in articles'); -__('Enable external API'); -__('User timezone'); -__('Customize stylesheet'); -__('Sort headlines by feed date'); -__('Login with an SSL certificate'); -__('Try to send digests around specified time'); -__('Assign articles to labels automatically'); -?> diff --git a/include/login_form.php b/include/login_form.php index 68df544e3..b7dae1016 100644 --- a/include/login_form.php +++ b/include/login_form.php @@ -65,6 +65,20 @@ font-size : 12px; } + a.forgotpass { + text-align : right; + font-size : 11px; + display : inline-block; + } + + a { + color : #4684ff; + } + + a:hover { + color : black; + } + div.footer a { color : gray; } @@ -108,7 +122,7 @@ function init() { function fetchProfiles() { try { - var query = "?op=getProfiles&login=" + param_escape(document.forms["loginForm"].login.value); + var query = "op=getProfiles&login=" + param_escape(document.forms["loginForm"].login.value); if (query) { new Ajax.Request("public.php", { @@ -174,20 +188,18 @@ function bwLimitChange(elem) { value="<?php echo $_SESSION["fake_login"] ?>" /> </div> + <?php if (strpos(PLUGINS, "auth_internal") !== FALSE) { ?> + <div class="row"> <label><?php echo __("Password:") ?></label> <input type="password" name="password" required="1" style="width : 220px" class="input" value="<?php echo $_SESSION["fake_password"] ?>"/> + <label></label> + <a class='forgotpass' href="public.php?op=forgotpass"><?php echo __("I forgot my password") ?></a> </div> - <div class="row"> - <label><?php echo __("Language:") ?></label> - <?php - print_select_hash("language", $_COOKIE["ttrss_lang"], get_translations(), - "style='width : 220px; margin : 0px' dojoType='dijit.form.Select'"); - ?> - </div> + <?php } ?> <div class="row"> <label><?php echo __("Profile:") ?></label> @@ -202,9 +214,23 @@ function bwLimitChange(elem) { <label> </label> <input dojoType="dijit.form.CheckBox" name="bw_limit" id="bw_limit" type="checkbox" onchange="bwLimitChange(this)"> - <label style='display : inline' for="bw_limit"><?php echo __("Use less traffic") ?></label> + <label id="bw_limit_label" style='display : inline' for="bw_limit"><?php echo __("Use less traffic") ?></label> + </div> + + <div dojoType="dijit.Tooltip" connectId="bw_limit_label" position="below"> +<?php echo __("Does not display images in articles, reduces automatic refreshes."); ?> + </div> + + <?php if (SESSION_COOKIE_LIFETIME > 0) { ?> + + <div class="row"> + <label> </label> + <input dojoType="dijit.form.CheckBox" name="remember_me" id="remember_me" type="checkbox"> + <label style='display : inline' for="remember_me"><?php echo __("Remember me") ?></label> </div> + <?php } ?> + <div class="row" style='text-align : right'> <button dojoType="dijit.form.Button" type="submit"><?php echo __('Log in') ?></button> <?php if (defined('ENABLE_REGISTRATION') && ENABLE_REGISTRATION) { ?> diff --git a/include/rssfuncs.php b/include/rssfuncs.php index 5c49008c5..612c914c0 100644 --- a/include/rssfuncs.php +++ b/include/rssfuncs.php @@ -1,19 +1,19 @@ <?php - define('DAEMON_UPDATE_LOGIN_LIMIT', 30); - define('DAEMON_FEED_LIMIT', 100); - define('DAEMON_SLEEP_INTERVAL', 60); + define_default('DAEMON_UPDATE_LOGIN_LIMIT', 30); + define_default('DAEMON_FEED_LIMIT', 500); + define_default('DAEMON_SLEEP_INTERVAL', 120); - function update_feedbrowser_cache($link) { + function update_feedbrowser_cache() { - $result = db_query($link, "SELECT feed_url, site_url, title, COUNT(id) AS subscribers + $result = db_query("SELECT feed_url, site_url, title, COUNT(id) AS subscribers FROM ttrss_feeds WHERE (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf WHERE tf.feed_url = ttrss_feeds.feed_url AND (private IS true OR auth_login != '' OR auth_pass != '' OR feed_url LIKE '%:%@%/%')) GROUP BY feed_url, site_url, title ORDER BY subscribers DESC LIMIT 1000"); - db_query($link, "BEGIN"); + db_query("BEGIN"); - db_query($link, "DELETE FROM ttrss_feedbrowser_cache"); + db_query("DELETE FROM ttrss_feedbrowser_cache"); $count = 0; @@ -23,12 +23,12 @@ $title = db_escape_string($line["title"]); $site_url = db_escape_string($line["site_url"]); - $tmp_result = db_query($link, "SELECT subscribers FROM + $tmp_result = db_query("SELECT subscribers FROM ttrss_feedbrowser_cache WHERE feed_url = '$feed_url'"); if (db_num_rows($tmp_result) == 0) { - db_query($link, "INSERT INTO ttrss_feedbrowser_cache + db_query("INSERT INTO ttrss_feedbrowser_cache (feed_url, site_url, title, subscribers) VALUES ('$feed_url', '$site_url', '$title', '$subscribers')"); @@ -38,7 +38,7 @@ } - db_query($link, "COMMIT"); + db_query("COMMIT"); return $count; @@ -57,9 +57,15 @@ * @param boolean $debug Set to false to disable debug output. Default to true. * @return void */ - function update_daemon_common($link, $limit = DAEMON_FEED_LIMIT, $from_http = false, $debug = true) { + function update_daemon_common($limit = DAEMON_FEED_LIMIT, $from_http = false, $debug = true) { // Process all other feeds using last_updated and interval parameters + $schema_version = get_schema_version(); + + if ($schema_version != SCHEMA_VERSION) { + die("Schema version is wrong, please upgrade the database.\n"); + } + define('PREFS_NO_CACHE', true); // Test if the user has loggued in recently. If not, it does not update its feeds. @@ -77,6 +83,7 @@ if (DB_TYPE == "pgsql") { $update_limit_qpart = "AND (( ttrss_feeds.update_interval = 0 + AND ttrss_user_prefs.value != '-1' AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_user_prefs.value || ' minutes') AS INTERVAL) ) OR ( ttrss_feeds.update_interval > 0 @@ -86,6 +93,7 @@ } else { $update_limit_qpart = "AND (( ttrss_feeds.update_interval = 0 + AND ttrss_user_prefs.value != '-1' AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL CONVERT(ttrss_user_prefs.value, SIGNED INTEGER) MINUTE) ) OR ( ttrss_feeds.update_interval > 0 @@ -96,21 +104,16 @@ // Test if feed is currently being updated by another process. if (DB_TYPE == "pgsql") { - $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '5 minutes')"; + $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '10 minutes')"; } else { - $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 5 MINUTE))"; + $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 10 MINUTE))"; } // Test if there is a limit to number of updated feeds $query_limit = ""; if($limit) $query_limit = sprintf("LIMIT %d", $limit); - $random_qpart = sql_random_function(); - - // We search for feed needing update. - $result = db_query($link, "SELECT ttrss_feeds.feed_url,ttrss_feeds.id, ttrss_feeds.owner_uid, - ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated, - ttrss_feeds.update_interval + $query = "SELECT DISTINCT ttrss_feeds.feed_url, ttrss_feeds.last_updated FROM ttrss_feeds, ttrss_users, ttrss_user_prefs WHERE @@ -118,187 +121,261 @@ AND ttrss_users.id = ttrss_user_prefs.owner_uid AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL' $login_thresh_qpart $update_limit_qpart - $updstart_thresh_qpart - ORDER BY $random_qpart $query_limit"); + $updstart_thresh_qpart + ORDER BY last_updated $query_limit"; - $user_prefs_cache = array(); + // We search for feed needing update. + $result = db_query($query); - if($debug) _debug(sprintf("Scheduled %d feeds to update...\n", db_num_rows($result))); + if($debug) _debug(sprintf("Scheduled %d feeds to update...", db_num_rows($result))); // Here is a little cache magic in order to minimize risk of double feed updates. $feeds_to_update = array(); while ($line = db_fetch_assoc($result)) { - $feeds_to_update[$line['id']] = $line; + array_push($feeds_to_update, db_escape_string($line['feed_url'])); } // We update the feed last update started date before anything else. // There is no lag due to feed contents downloads // It prevent an other process to update the same feed. - $feed_ids = array_keys($feeds_to_update); - if($feed_ids) { - db_query($link, sprintf("UPDATE ttrss_feeds SET last_update_started = NOW() - WHERE id IN (%s)", implode(',', $feed_ids))); - } - expire_cached_files($debug); - expire_lock_files($debug); + if(count($feeds_to_update) > 0) { + $feeds_quoted = array(); - // For each feed, we call the feed update function. - while ($line = array_pop($feeds_to_update)) { + foreach ($feeds_to_update as $feed) { + array_push($feeds_quoted, "'" . db_escape_string($feed) . "'"); + } - if($debug) _debug("Feed: " . $line["feed_url"] . ", " . $line["last_updated"]); + db_query(sprintf("UPDATE ttrss_feeds SET last_update_started = NOW() + WHERE feed_url IN (%s)", implode(',', $feeds_quoted))); + } - update_rss_feed($link, $line["id"], true); + $nf = 0; - sleep(1); // prevent flood (FIXME make this an option?) + // For each feed, we call the feed update function. + foreach ($feeds_to_update as $feed) { + if($debug) _debug("Base feed: $feed"); + + //update_rss_feed($line["id"], true); + + // since we have the data cached, we can deal with other feeds with the same url + + $tmp_result = db_query("SELECT DISTINCT ttrss_feeds.id,last_updated,ttrss_feeds.owner_uid + FROM ttrss_feeds, ttrss_users, ttrss_user_prefs WHERE + ttrss_user_prefs.owner_uid = ttrss_feeds.owner_uid AND + ttrss_users.id = ttrss_user_prefs.owner_uid AND + ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL' AND + feed_url = '".db_escape_string($feed)."' AND + (ttrss_feeds.update_interval > 0 OR + ttrss_user_prefs.value != '-1') + $login_thresh_qpart + ORDER BY ttrss_feeds.id $query_limit"); + + if (db_num_rows($tmp_result) > 0) { + while ($tline = db_fetch_assoc($tmp_result)) { + if($debug) _debug(" => " . $tline["last_updated"] . ", " . $tline["id"] . " " . $tline["owner_uid"]); + update_rss_feed($tline["id"], true); + ++$nf; + } + } } require_once "digest.php"; // Send feed digests by email if needed. - send_headlines_digests($link, $debug); + send_headlines_digests($debug); + + return $nf; } // function update_daemon_common // ignore_daemon is not used - function update_rss_feed($link, $feed, $ignore_daemon = false, $no_cache = false, + function update_rss_feed($feed, $ignore_daemon = false, $no_cache = false, $override_url = false) { - require_once "lib/simplepie/simplepie.inc"; - $debug_enabled = defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']; - if ($debug_enabled) { - _debug("update_rss_feed: start"); - } + _debug("start", $debug_enabled); - $result = db_query($link, "SELECT id,update_interval,auth_login, + $result = db_query("SELECT id,update_interval,auth_login, feed_url,auth_pass,cache_images,last_updated, mark_unread_on_update, owner_uid, - pubsub_state + pubsub_state, auth_pass_encrypted, + (SELECT max(date_entered) FROM + ttrss_entries, ttrss_user_entries where ref_id = id AND feed_id = '$feed') AS last_article_timestamp FROM ttrss_feeds WHERE id = '$feed'"); if (db_num_rows($result) == 0) { - if ($debug_enabled) { - _debug("update_rss_feed: feed $feed NOT FOUND/SKIPPED"); - } + _debug("feed $feed NOT FOUND/SKIPPED", $debug_enabled); return false; } $last_updated = db_fetch_result($result, 0, "last_updated"); + $last_article_timestamp = @strtotime(db_fetch_result($result, 0, "last_article_timestamp")); + + if (defined('_DISABLE_HTTP_304')) + $last_article_timestamp = 0; + $owner_uid = db_fetch_result($result, 0, "owner_uid"); $mark_unread_on_update = sql_bool_to_bool(db_fetch_result($result, 0, "mark_unread_on_update")); $pubsub_state = db_fetch_result($result, 0, "pubsub_state"); + $auth_pass_encrypted = sql_bool_to_bool(db_fetch_result($result, + 0, "auth_pass_encrypted")); - db_query($link, "UPDATE ttrss_feeds SET last_update_started = NOW() + db_query("UPDATE ttrss_feeds SET last_update_started = NOW() WHERE id = '$feed'"); $auth_login = db_fetch_result($result, 0, "auth_login"); $auth_pass = db_fetch_result($result, 0, "auth_pass"); + if ($auth_pass_encrypted) { + require_once "crypt.php"; + $auth_pass = decrypt_string($auth_pass); + } + $cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images")); $fetch_url = db_fetch_result($result, 0, "feed_url"); $feed = db_escape_string($feed); - /* if ($auth_login && $auth_pass ){ - $url_parts = array(); - preg_match("/(^[^:]*):\/\/(.*)/", $fetch_url, $url_parts); + if ($override_url) $fetch_url = $override_url; - if ($url_parts[1] && $url_parts[2]) { - $fetch_url = $url_parts[1] . "://$auth_login:$auth_pass@" . $url_parts[2]; - } - } */ + $date_feed_processed = date('Y-m-d H:i'); - if ($override_url) - $fetch_url = $override_url; + $cache_filename = CACHE_DIR . "/simplepie/" . sha1($fetch_url) . ".xml"; - if ($debug_enabled) { - _debug("update_rss_feed: fetching [$fetch_url]..."); - } + $rss = false; + $rss_hash = false; + $cache_timestamp = file_exists($cache_filename) ? filemtime($cache_filename) : 0; + + $force_refetch = isset($_REQUEST["force_refetch"]); - // Ignore cache if new feed or manual update. - $cache_age = (is_null($last_updated) || $last_updated == '1970-01-01 00:00:00') ? - -1 : get_feed_update_interval($link, $feed) * 60; + if (file_exists($cache_filename) && + is_readable($cache_filename) && + !$auth_login && !$auth_pass && + filemtime($cache_filename) > time() - 30) { - $simplepie_cache_dir = CACHE_DIR . "/simplepie"; + _debug("using local cache.", $debug_enabled); - if (!is_dir($simplepie_cache_dir)) { - mkdir($simplepie_cache_dir); + @$feed_data = file_get_contents($cache_filename); + + if ($feed_data) { + $rss_hash = sha1($feed_data); + } + + } else { + _debug("local cache will not be used for this feed", $debug_enabled); } - $feed_data = fetch_file_contents($fetch_url, false, - $auth_login, $auth_pass, false, $no_cache ? 15 : 45); + if (!$rss) { + + if (!$feed_data) { + _debug("fetching [$fetch_url]...", $debug_enabled); + _debug("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $last_article_timestamp), $debug_enabled); + + $feed_data = fetch_file_contents($fetch_url, false, + $auth_login, $auth_pass, false, + $no_cache ? FEED_FETCH_NO_CACHE_TIMEOUT : FEED_FETCH_TIMEOUT, + $force_refetch ? 0 : $last_article_timestamp); + + global $fetch_curl_used; + + if (!$fetch_curl_used) { + $tmp = @gzdecode($feed_data); + + if ($tmp) $feed_data = $tmp; + } + + $feed_data = trim($feed_data); + + _debug("fetch done.", $debug_enabled); + + if ($feed_data) { + $error = verify_feed_xml($feed_data); + + if ($error) { + _debug("error verifying XML, code: " . $error->code, $debug_enabled); + + if ($error->code == 26) { + _debug("got error 26, trying to decode entities...", $debug_enabled); - if (!$feed_data) { - global $fetch_last_error; + $feed_data = html_entity_decode($feed_data, ENT_COMPAT, 'UTF-8'); - if ($debug_enabled) { - _debug("update_rss_feed: unable to fetch: $fetch_last_error"); + $error = verify_feed_xml($feed_data); + + if ($error) $feed_data = ''; + } + } + } } - $error_escaped = db_escape_string($fetch_last_error); + if (!$feed_data) { + global $fetch_last_error; + global $fetch_last_error_code; - db_query($link, - "UPDATE ttrss_feeds SET last_error = '$error_escaped', - last_updated = NOW() WHERE id = '$feed'"); + _debug("unable to fetch: $fetch_last_error [$fetch_last_error_code]", $debug_enabled); + + $error_escaped = ''; - return; + // If-Modified-Since + if ($fetch_last_error_code != 304) { + $error_escaped = db_escape_string($fetch_last_error); + } else { + _debug("source claims data not modified, nothing to do.", $debug_enabled); + } + + db_query( + "UPDATE ttrss_feeds SET last_error = '$error_escaped', + last_updated = NOW() WHERE id = '$feed'"); + + return; + } } - $pluginhost = new PluginHost($link); + $pluginhost = new PluginHost(); $pluginhost->set_debug($debug_enabled); - $user_plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid); + $user_plugins = get_pref("_ENABLED_PLUGINS", $owner_uid); - $pluginhost->load(PLUGINS, $pluginhost::KIND_ALL); - $pluginhost->load($user_plugins, $pluginhost::KIND_USER, $owner_uid); + $pluginhost->load(PLUGINS, PluginHost::KIND_ALL); + $pluginhost->load($user_plugins, PluginHost::KIND_USER, $owner_uid); $pluginhost->load_data(); - foreach ($pluginhost->get_hooks($pluginhost::HOOK_FEED_FETCHED) as $plugin) { + foreach ($pluginhost->get_hooks(PluginHost::HOOK_FEED_FETCHED) as $plugin) { $feed_data = $plugin->hook_feed_fetched($feed_data); } - if ($debug_enabled) { - _debug("update_rss_feed: fetch done, parsing..."); - } + // set last update to now so if anything *simplepie* crashes later we won't be + // continuously failing on the same feed + //db_query("UPDATE ttrss_feeds SET last_updated = NOW() WHERE id = '$feed'"); - $rss = new SimplePie(); - $rss->set_sanitize_class("SanitizeDummy"); - // simplepie ignores the above and creates default sanitizer anyway, - // so let's override it... - $rss->sanitize = new SanitizeDummy(); - $rss->set_output_encoding('UTF-8'); - $rss->set_raw_data($feed_data); - - if ($debug_enabled) { - _debug("feed update interval (sec): " . - get_feed_update_interval($link, $feed)*60); + if (!$rss) { + $rss = new FeedParser($feed_data); + $rss->init(); } - $rss->enable_cache(!$no_cache); - - if (!$no_cache) { - $rss->set_cache_location($simplepie_cache_dir); - $rss->set_cache_duration($cache_age); - } - - @$rss->init(); - // print_r($rss); $feed = db_escape_string($feed); if (!$rss->error()) { - // We use local pluginhost here because we need to load different per-user feed plugins - $pluginhost->run_hooks($pluginhost::HOOK_FEED_PARSED, "hook_feed_parsed", $rss); + // cache data for later + if (!$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/simplepie")) { + $new_rss_hash = sha1($rss_data); - if ($debug_enabled) { - _debug("update_rss_feed: processing feed data..."); + if ($new_rss_hash != $rss_hash && count($rss->get_items()) > 0 ) { + _debug("saving $cache_filename", $debug_enabled); + @file_put_contents($cache_filename, $feed_data); + } } -// db_query($link, "BEGIN"); + // We use local pluginhost here because we need to load different per-user feed plugins + $pluginhost->run_hooks(PluginHost::HOOK_FEED_PARSED, "hook_feed_parsed", $rss); + + _debug("processing feed data...", $debug_enabled); + +// db_query("BEGIN"); if (DB_TYPE == "pgsql") { $favicon_interval_qpart = "favicon_last_checked < NOW() - INTERVAL '12 hour'"; @@ -306,7 +383,7 @@ $favicon_interval_qpart = "favicon_last_checked < DATE_SUB(NOW(), INTERVAL 12 HOUR)"; } - $result = db_query($link, "SELECT title,site_url,owner_uid, + $result = db_query("SELECT title,site_url,owner_uid,favicon_avg_color, (favicon_last_checked IS NULL OR $favicon_interval_qpart) AS favicon_needs_check FROM ttrss_feeds WHERE id = '$feed'"); @@ -315,19 +392,47 @@ $orig_site_url = db_fetch_result($result, 0, "site_url"); $favicon_needs_check = sql_bool_to_bool(db_fetch_result($result, 0, "favicon_needs_check")); + $favicon_avg_color = db_fetch_result($result, 0, "favicon_avg_color"); $owner_uid = db_fetch_result($result, 0, "owner_uid"); $site_url = db_escape_string(mb_substr(rewrite_relative_url($fetch_url, $rss->get_link()), 0, 245)); - if ($debug_enabled) { - _debug("update_rss_feed: checking favicon..."); - } + _debug("site_url: $site_url", $debug_enabled); + _debug("feed_title: " . $rss->get_title(), $debug_enabled); + + if ($favicon_needs_check || $force_refetch) { + + /* terrible hack: if we crash on floicon shit here, we won't check + * the icon avgcolor again (unless the icon got updated) */ + + $favicon_file = ICONS_DIR . "/$feed.ico"; + $favicon_modified = @filemtime($favicon_file); + + _debug("checking favicon...", $debug_enabled); + + check_feed_favicon($site_url, $feed); + $favicon_modified_new = @filemtime($favicon_file); + + if ($favicon_modified_new > $favicon_modified) + $favicon_avg_color = ''; + + if (file_exists($favicon_file) && function_exists("imagecreatefromstring") && $favicon_avg_color == '') { + require_once "colors.php"; + + db_query("UPDATE ttrss_feeds SET favicon_avg_color = 'fail' WHERE + id = '$feed'"); + + $favicon_color = db_escape_string( + calculate_avg_color($favicon_file)); - if ($favicon_needs_check) { - check_feed_favicon($site_url, $feed, $link); + $favicon_colorstring = ",favicon_avg_color = '".$favicon_color."'"; + } else if ($favicon_avg_color == 'fail') { + _debug("floicon failed on this file, not trying to recalculate avg color", $debug_enabled); + } - db_query($link, "UPDATE ttrss_feeds SET favicon_last_checked = NOW() + db_query("UPDATE ttrss_feeds SET favicon_last_checked = NOW() + $favicon_colorstring WHERE id = '$feed'"); } @@ -335,39 +440,32 @@ $feed_title = db_escape_string($rss->get_title()); - if ($debug_enabled) { - _debug("update_rss_feed: registering title: $feed_title"); - } + if ($feed_title) { + _debug("registering title: $feed_title", $debug_enabled); - db_query($link, "UPDATE ttrss_feeds SET - title = '$feed_title' WHERE id = '$feed'"); + db_query("UPDATE ttrss_feeds SET + title = '$feed_title' WHERE id = '$feed'"); + } } if ($site_url && $orig_site_url != $site_url) { - db_query($link, "UPDATE ttrss_feeds SET + db_query("UPDATE ttrss_feeds SET site_url = '$site_url' WHERE id = '$feed'"); } - if ($debug_enabled) { - _debug("update_rss_feed: loading filters & labels..."); - } + _debug("loading filters & labels...", $debug_enabled); - $filters = load_filters($link, $feed, $owner_uid); - $labels = get_all_labels($link, $owner_uid); + $filters = load_filters($feed, $owner_uid); + $labels = get_all_labels($owner_uid); - if ($debug_enabled) { - //print_r($filters); - _debug("update_rss_feed: " . count($filters) . " filters loaded."); - } + _debug("" . count($filters) . " filters loaded.", $debug_enabled); $items = $rss->get_items(); if (!is_array($items)) { - if ($debug_enabled) { - _debug("update_rss_feed: no articles found."); - } + _debug("no articles found.", $debug_enabled); - db_query($link, "UPDATE ttrss_feeds + db_query("UPDATE ttrss_feeds SET last_updated = NOW(), last_error = '' WHERE id = '$feed'"); return; // no articles @@ -375,7 +473,7 @@ if ($pubsub_state != 2 && PUBSUBHUBBUB_ENABLED) { - if ($debug_enabled) _debug("update_rss_feed: checking for PUSH hub..."); + _debug("checking for PUSH hub...", $debug_enabled); $feed_hub_url = false; @@ -388,7 +486,7 @@ } } - if ($debug_enabled) _debug("update_rss_feed: feed hub url: $feed_hub_url"); + _debug("feed hub url: $feed_hub_url", $debug_enabled); if ($feed_hub_url && function_exists('curl_init') && !ini_get("open_basedir")) { @@ -402,17 +500,14 @@ $rc = $s->subscribe($fetch_url); - if ($debug_enabled) - _debug("update_rss_feed: feed hub url found, subscribe request sent."); + _debug("feed hub url found, subscribe request sent.", $debug_enabled); - db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 1 + db_query("UPDATE ttrss_feeds SET pubsub_state = 1 WHERE id = '$feed'"); } } - if ($debug_enabled) { - _debug("update_rss_feed: processing articles..."); - } + _debug("processing articles...", $debug_enabled); foreach ($items as $item) { if ($_REQUEST['xdebug'] == 3) { @@ -423,19 +518,23 @@ if (!$entry_guid) $entry_guid = $item->get_link(); if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title()); - if ($debug_enabled) { - _debug("update_rss_feed: guid $entry_guid"); - } + _debug("f_guid $entry_guid", $debug_enabled); if (!$entry_guid) continue; $entry_guid = "$owner_uid,$entry_guid"; + $entry_guid_hashed = db_escape_string('SHA1:' . sha1($entry_guid)); + + _debug("guid $entry_guid / $entry_guid_hashed", $debug_enabled); + $entry_timestamp = ""; - $entry_timestamp = strtotime($item->get_date()); + $entry_timestamp = $item->get_date(); - if ($entry_timestamp == -1 || !$entry_timestamp) { + _debug("orig date: " . $item->get_date(), $debug_enabled); + + if ($entry_timestamp == -1 || !$entry_timestamp || $entry_timestamp > time()) { $entry_timestamp = time(); $no_orig_date = 'true'; } else { @@ -444,18 +543,16 @@ $entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp); - if ($debug_enabled) { - _debug("update_rss_feed: date $entry_timestamp [$entry_timestamp_fmt]"); - } + _debug("date $entry_timestamp [$entry_timestamp_fmt]", $debug_enabled); +// $entry_title = html_entity_decode($item->get_title(), ENT_COMPAT, 'UTF-8'); +// $entry_title = decode_numeric_entities($entry_title); $entry_title = $item->get_title(); $entry_link = rewrite_relative_url($site_url, $item->get_link()); - if ($debug_enabled) { - _debug("update_rss_feed: title $entry_title"); - _debug("update_rss_feed: link $entry_link"); - } + _debug("title $entry_title", $debug_enabled); + _debug("link $entry_link", $debug_enabled); if (!$entry_title) $entry_title = date("Y-m-d H:i:s", $entry_timestamp);; @@ -463,38 +560,24 @@ if (!$entry_content) $entry_content = $item->get_description(); if ($_REQUEST["xdebug"] == 2) { - print "update_rss_feed: content: "; + print "content: "; print $entry_content; print "\n"; } - $entry_comments = $item->data["comments"]; - - if ($item->get_author()) { - $entry_author_item = $item->get_author(); - $entry_author = $entry_author_item->get_name(); - if (!$entry_author) $entry_author = $entry_author_item->get_email(); - - $entry_author = db_escape_string($entry_author); - } + $entry_comments = $item->get_comments_url(); + $entry_author = $item->get_author(); $entry_guid = db_escape_string(mb_substr($entry_guid, 0, 245)); - $entry_comments = db_escape_string(mb_substr($entry_comments, 0, 245)); - $entry_author = db_escape_string(mb_substr($entry_author, 0, 245)); + $entry_comments = db_escape_string(mb_substr(trim($entry_comments), 0, 245)); + $entry_author = db_escape_string(mb_substr(trim($entry_author), 0, 245)); - $num_comments = $item->get_item_tags('http://purl.org/rss/1.0/modules/slash/', 'comments'); + $num_comments = (int) $item->get_comments_count(); - if (is_array($num_comments) && is_array($num_comments[0])) { - $num_comments = (int) $num_comments[0]["data"]; - } else { - $num_comments = 0; - } - - if ($debug_enabled) { - _debug("update_rss_feed: num_comments: $num_comments"); - _debug("update_rss_feed: looking for tags [1]..."); - } + _debug("author $entry_author", $debug_enabled); + _debug("num_comments: $num_comments", $debug_enabled); + _debug("looking for tags...", $debug_enabled); // parse <category> entries into tags @@ -504,42 +587,26 @@ if (is_array($additional_tags_src)) { foreach ($additional_tags_src as $tobj) { - array_push($additional_tags, $tobj->get_term()); + array_push($additional_tags, $tobj); } } - if ($debug_enabled) { - _debug("update_rss_feed: category tags:"); - print_r($additional_tags); - } - - if ($debug_enabled) { - _debug("update_rss_feed: looking for tags [2]..."); - } - $entry_tags = array_unique($additional_tags); for ($i = 0; $i < count($entry_tags); $i++) $entry_tags[$i] = mb_strtolower($entry_tags[$i], 'utf-8'); - if ($debug_enabled) { - //_debug("update_rss_feed: unfiltered tags found:"); - //print_r($entry_tags); - } + _debug("tags found: " . join(",", $entry_tags), $debug_enabled); - if ($debug_enabled) { - _debug("update_rss_feed: done collecting data."); - } + _debug("done collecting data.", $debug_enabled); // TODO: less memory-hungry implementation - if ($debug_enabled) { - _debug("update_rss_feed: applying plugin filters.."); - } + _debug("applying plugin filters..", $debug_enabled); // FIXME not sure if owner_uid is a good idea here, we may have a base entry without user entry (?) - $result = db_query($link, "SELECT plugin_data,title,content,link,tag_cache,author FROM ttrss_entries, ttrss_user_entries - WHERE ref_id = id AND guid = '".db_escape_string($entry_guid)."' AND owner_uid = $owner_uid"); + $result = db_query("SELECT plugin_data,title,content,link,tag_cache,author FROM ttrss_entries, ttrss_user_entries + WHERE ref_id = id AND (guid = '".db_escape_string($entry_guid)."' OR guid = '$entry_guid_hashed') AND owner_uid = $owner_uid"); if (db_num_rows($result) != 0) { $entry_plugin_data = db_fetch_result($result, 0, "plugin_data"); @@ -563,7 +630,7 @@ "author" => $entry_author, "stored" => $stored_article); - foreach ($pluginhost->get_hooks($pluginhost::HOOK_ARTICLE_FILTER) as $plugin) { + foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) { $article = $plugin->hook_article_filter($article); } @@ -573,32 +640,30 @@ $entry_author = db_escape_string($article["author"]); $entry_link = db_escape_string($article["link"]); $entry_plugin_data = db_escape_string($article["plugin_data"]); + $entry_content = $article["content"]; // escaped below - if ($debug_enabled) { - _debug("update_rss_feed: plugin data: $entry_plugin_data"); - } + + _debug("plugin data: $entry_plugin_data", $debug_enabled); if ($cache_images && is_writable(CACHE_DIR . '/images')) - $entry_content = cache_images($entry_content, $site_url, $debug_enabled); + cache_images($entry_content, $site_url, $debug_enabled); - $entry_content = db_escape_string($article["content"], false); + $entry_content = db_escape_string($entry_content, false); $content_hash = "SHA1:" . sha1($entry_content); - db_query($link, "BEGIN"); + db_query("BEGIN"); - $result = db_query($link, "SELECT id FROM ttrss_entries - WHERE guid = '$entry_guid'"); + $result = db_query("SELECT id FROM ttrss_entries + WHERE (guid = '$entry_guid' OR guid = '$entry_guid_hashed')"); if (db_num_rows($result) == 0) { - if ($debug_enabled) { - _debug("update_rss_feed: base guid [$entry_guid] not found"); - } + _debug("base guid [$entry_guid] not found", $debug_enabled); // base post entry does not exist, create it - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_entries (title, guid, @@ -616,7 +681,7 @@ author) VALUES ('$entry_title', - '$entry_guid', + '$entry_guid_hashed', '$entry_link', '$entry_timestamp_fmt', '$entry_content', @@ -624,7 +689,7 @@ '', $no_orig_date, NOW(), - NOW(), + '$date_feed_processed', '$entry_comments', '$num_comments', '$entry_plugin_data', @@ -640,31 +705,29 @@ $base_entry_id = db_fetch_result($result, 0, "id"); - db_query($link, "UPDATE ttrss_entries SET date_updated = NOW() + db_query("UPDATE ttrss_entries SET date_updated = NOW() WHERE id = '$base_entry_id'"); - $article_labels = get_article_labels($link, $base_entry_id, $owner_uid); + $article_labels = get_article_labels($base_entry_id, $owner_uid); } // now it should exist, if not - bad luck then - $result = db_query($link, "SELECT - id,content_hash,no_orig_date,title,plugin_data, + $result = db_query("SELECT + id,content_hash,no_orig_date,title,plugin_data,guid, ".SUBSTRING_FOR_DATE."(date_updated,1,19) as date_updated, ".SUBSTRING_FOR_DATE."(updated,1,19) as updated, num_comments FROM ttrss_entries - WHERE guid = '$entry_guid'"); + WHERE guid = '$entry_guid' OR guid = '$entry_guid_hashed'"); $entry_ref_id = 0; $entry_int_id = 0; if (db_num_rows($result) == 1) { - if ($debug_enabled) { - _debug("update_rss_feed: base guid [$entry_guid] found, checking for user record"); - } + _debug("base guid found, checking for user record", $debug_enabled); // this will be used below in update handler $orig_content_hash = db_fetch_result($result, 0, "content_hash"); @@ -677,10 +740,18 @@ $ref_id = db_fetch_result($result, 0, "id"); $entry_ref_id = $ref_id; + /* $stored_guid = db_fetch_result($result, 0, "guid"); + if ($stored_guid != $entry_guid_hashed) { + if ($debug_enabled) _debug("upgrading compat guid to hashed one", $debug_enabled); + + db_query("UPDATE ttrss_entries SET guid = '$entry_guid_hashed' WHERE + id = '$ref_id'"); + } */ + // check for user post link to main table // do we allow duplicate posts with same GUID in different feeds? - if (get_pref($link, "ALLOW_DUPLICATE_POSTS", $owner_uid, false)) { + if (get_pref("ALLOW_DUPLICATE_POSTS", $owner_uid, false)) { $dupcheck_qpart = "AND (feed_id = '$feed' OR feed_id IS NULL)"; } else { $dupcheck_qpart = ""; @@ -693,22 +764,20 @@ $entry_tags); if ($debug_enabled) { - _debug("update_rss_feed: article filters: "); + _debug("article filters: ", $debug_enabled); if (count($article_filters) != 0) { print_r($article_filters); } } if (find_article_filter($article_filters, "filter")) { - db_query($link, "COMMIT"); // close transaction in progress + db_query("COMMIT"); // close transaction in progress continue; } $score = calculate_article_score($article_filters); - if ($debug_enabled) { - _debug("update_rss_feed: initial score: $score"); - } + _debug("initial score: $score", $debug_enabled); $query = "SELECT ref_id, int_id FROM ttrss_user_entries WHERE ref_id = '$ref_id' AND owner_uid = '$owner_uid' @@ -716,14 +785,12 @@ // if ($_REQUEST["xdebug"]) print "$query\n"; - $result = db_query($link, $query); + $result = db_query($query); // okay it doesn't exist - create user entry if (db_num_rows($result) == 0) { - if ($debug_enabled) { - _debug("update_rss_feed: user record not found, creating..."); - } + _debug("user record not found, creating...", $debug_enabled); if ($score >= -500 && !find_article_filter($article_filters, 'catchup')) { $unread = 'true'; @@ -749,7 +816,7 @@ if (DB_TYPE == "pgsql" and defined('_NGRAM_TITLE_DUPLICATE_THRESHOLD')) { - $result = db_query($link, "SELECT COUNT(*) AS similar FROM + $result = db_query("SELECT COUNT(*) AS similar FROM ttrss_entries,ttrss_user_entries WHERE ref_id = id AND updated >= NOW() - INTERVAL '7 day' AND similarity(title, '$entry_title') >= "._NGRAM_TITLE_DUPLICATE_THRESHOLD." @@ -757,33 +824,36 @@ $ngram_similar = db_fetch_result($result, 0, "similar"); - if ($debug_enabled) { - _debug("update_rss_feed: N-gram similar results: $ngram_similar"); - } + _debug("N-gram similar results: $ngram_similar", $debug_enabled); if ($ngram_similar > 0) { $unread = 'false'; } } - $result = db_query($link, + $last_marked = ($marked == 'true') ? 'NOW()' : 'NULL'; + $last_published = ($published == 'true') ? 'NOW()' : 'NULL'; + + $result = db_query( "INSERT INTO ttrss_user_entries (ref_id, owner_uid, feed_id, unread, last_read, marked, - published, score, tag_cache, label_cache, uuid) + published, score, tag_cache, label_cache, uuid, + last_marked, last_published) VALUES ('$ref_id', '$owner_uid', '$feed', $unread, - $last_read_qpart, $marked, $published, '$score', '', '', '')"); + $last_read_qpart, $marked, $published, '$score', '', '', + '', $last_marked, $last_published)"); if (PUBSUBHUBBUB_HUB && $published == 'true') { $rss_link = get_self_url_prefix() . "/public.php?op=rss&id=-2&key=" . - get_feed_access_key($link, -2, false, $owner_uid); + get_feed_access_key(-2, false, $owner_uid); $p = new Publisher(PUBSUBHUBBUB_HUB); $pubsub_result = $p->publish_update($rss_link); } - $result = db_query($link, + $result = db_query( "SELECT int_id FROM ttrss_user_entries WHERE ref_id = '$ref_id' AND owner_uid = '$owner_uid' AND feed_id = '$feed' LIMIT 1"); @@ -792,17 +862,13 @@ $entry_int_id = db_fetch_result($result, 0, "int_id"); } } else { - if ($debug_enabled) { - _debug("update_rss_feed: user record FOUND"); - } + _debug("user record FOUND", $debug_enabled); $entry_ref_id = db_fetch_result($result, 0, "ref_id"); $entry_int_id = db_fetch_result($result, 0, "int_id"); } - if ($debug_enabled) { - _debug("update_rss_feed: RID: $entry_ref_id, IID: $entry_int_id"); - } + _debug("RID: $entry_ref_id, IID: $entry_int_id", $debug_enabled); $post_needs_update = false; $update_insignificant = false; @@ -832,12 +898,12 @@ if ($post_needs_update) { if (defined('DAEMON_EXTENDED_DEBUG')) { - _debug("update_rss_feed: post $entry_guid needs update..."); + _debug("post $entry_guid_hashed needs update...", $debug_enabled); } // print "<!-- post $orig_title needs update : $post_needs_update -->"; - db_query($link, "UPDATE ttrss_entries + db_query("UPDATE ttrss_entries SET title = '$entry_title', content = '$entry_content', content_hash = '$content_hash', updated = '$entry_timestamp_fmt', @@ -847,25 +913,21 @@ if (!$update_insignificant) { if ($mark_unread_on_update) { - db_query($link, "UPDATE ttrss_user_entries + db_query("UPDATE ttrss_user_entries SET last_read = null, unread = true WHERE ref_id = '$ref_id'"); } } } } - db_query($link, "COMMIT"); + db_query("COMMIT"); - if ($debug_enabled) { - _debug("update_rss_feed: assigning labels..."); - } + _debug("assigning labels...", $debug_enabled); - assign_article_to_label_filters($link, $entry_ref_id, $article_filters, + assign_article_to_label_filters($entry_ref_id, $article_filters, $owner_uid, $article_labels); - if ($debug_enabled) { - _debug("update_rss_feed: looking for enclosures..."); - } + _debug("looking for enclosures...", $debug_enabled); // enclosures @@ -882,28 +944,28 @@ } if ($debug_enabled) { - _debug("update_rss_feed: article enclosures:"); + _debug("article enclosures:", $debug_enabled); print_r($enclosures); } - db_query($link, "BEGIN"); + db_query("BEGIN"); foreach ($enclosures as $enc) { $enc_url = db_escape_string($enc[0]); $enc_type = db_escape_string($enc[1]); $enc_dur = db_escape_string($enc[2]); - $result = db_query($link, "SELECT id FROM ttrss_enclosures + $result = db_query("SELECT id FROM ttrss_enclosures WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'"); if (db_num_rows($result) == 0) { - db_query($link, "INSERT INTO ttrss_enclosures + db_query("INSERT INTO ttrss_enclosures (content_url, content_type, title, duration, post_id) VALUES ('$enc_url', '$enc_type', '', '$enc_dur', '$entry_ref_id')"); } } - db_query($link, "COMMIT"); + db_query("COMMIT"); // check for manual tags (we have to do it here since they're loaded from filters) @@ -922,7 +984,7 @@ // Skip boring tags - $boring_tags = trim_array(explode(",", mb_strtolower(get_pref($link, + $boring_tags = trim_array(explode(",", mb_strtolower(get_pref( 'BLACKLISTED_TAGS', $owner_uid, ''), 'utf-8'))); $filtered_tags = array(); @@ -939,7 +1001,7 @@ $filtered_tags = array_unique($filtered_tags); if ($debug_enabled) { - _debug("update_rss_feed: filtered article tags:"); + _debug("filtered article tags:", $debug_enabled); print_r($filtered_tags); } @@ -947,7 +1009,7 @@ if (count($filtered_tags) > 0) { - db_query($link, "BEGIN"); + db_query("BEGIN"); foreach ($filtered_tags as $tag) { @@ -956,13 +1018,13 @@ if (!tag_is_valid($tag)) continue; - $result = db_query($link, "SELECT id FROM ttrss_tags + $result = db_query("SELECT id FROM ttrss_tags WHERE tag_name = '$tag' AND post_int_id = '$entry_int_id' AND owner_uid = '$owner_uid' LIMIT 1"); if ($result && db_num_rows($result) == 0) { - db_query($link, "INSERT INTO ttrss_tags + db_query("INSERT INTO ttrss_tags (owner_uid,tag_name,post_int_id) VALUES ('$owner_uid','$tag', '$entry_int_id')"); } @@ -976,71 +1038,58 @@ $tags_str = db_escape_string(join(",", $tags_to_cache)); - db_query($link, "UPDATE ttrss_user_entries + db_query("UPDATE ttrss_user_entries SET tag_cache = '$tags_str' WHERE ref_id = '$entry_ref_id' AND owner_uid = $owner_uid"); - db_query($link, "COMMIT"); + db_query("COMMIT"); } - if (get_pref($link, "AUTO_ASSIGN_LABELS", $owner_uid, false)) { - if ($debug_enabled) { - _debug("update_rss_feed: auto-assigning labels..."); - } + if (get_pref("AUTO_ASSIGN_LABELS", $owner_uid, false)) { + _debug("auto-assigning labels...", $debug_enabled); foreach ($labels as $label) { - $caption = $label["caption"]; + $caption = preg_quote($label["caption"]); - if (preg_match("/\b$caption\b/i", "$tags_str " . strip_tags($entry_content) . " $entry_title")) { + if ($caption && preg_match("/\b$caption\b/i", "$tags_str " . strip_tags($entry_content) . " $entry_title")) { if (!labels_contains_caption($article_labels, $caption)) { - label_add_article($link, $entry_ref_id, $caption, $owner_uid); + label_add_article($entry_ref_id, $caption, $owner_uid); } } } } - if ($debug_enabled) { - _debug("update_rss_feed: article processed"); - } + _debug("article processed", $debug_enabled); } if (!$last_updated) { - if ($debug_enabled) { - _debug("update_rss_feed: new feed, catching it up..."); - } - catchup_feed($link, $feed, false, $owner_uid); + _debug("new feed, catching it up...", $debug_enabled); + catchup_feed($feed, false, $owner_uid); } - if ($debug_enabled) { - _debug("purging feed..."); - } + _debug("purging feed...", $debug_enabled); - purge_feed($link, $feed, 0, $debug_enabled); + purge_feed($feed, 0, $debug_enabled); - db_query($link, "UPDATE ttrss_feeds + db_query("UPDATE ttrss_feeds SET last_updated = NOW(), last_error = '' WHERE id = '$feed'"); -// db_query($link, "COMMIT"); +// db_query("COMMIT"); } else { $error_msg = db_escape_string(mb_substr($rss->error(), 0, 245)); - if ($debug_enabled) { - _debug("update_rss_feed: error fetching feed: $error_msg"); - } + _debug("error fetching feed: $error_msg", $debug_enabled); - db_query($link, + db_query( "UPDATE ttrss_feeds SET last_error = '$error_msg', last_updated = NOW() WHERE id = '$feed'"); } unset($rss); - if ($debug_enabled) { - _debug("update_rss_feed: done"); - } - + _debug("done", $debug_enabled); } function cache_images($html, $site_url, $debug) { @@ -1086,8 +1135,21 @@ return $doc->saveXML($node); } + function expire_error_log($debug) { + if ($debug) _debug("Removing old error log entries..."); + + if (DB_TYPE == "pgsql") { + db_query("DELETE FROM ttrss_error_log + WHERE created_at < NOW() - INTERVAL '7 days'"); + } else { + db_query("DELETE FROM ttrss_error_log + WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)"); + } + + } + function expire_lock_files($debug) { - if ($debug) _debug("Removing old lock files..."); + //if ($debug) _debug("Removing old lock files..."); $num_deleted = 0; @@ -1096,7 +1158,7 @@ if ($files) { foreach ($files as $file) { - if (!file_is_locked($file) && time() - filemtime($file) > 86400*2) { + if (!file_is_locked(basename($file)) && time() - filemtime($file) > 86400*2) { unlink($file); ++$num_deleted; } @@ -1104,14 +1166,14 @@ } } - if ($debug) _debug("Removed $num_deleted files."); + if ($debug) _debug("Removed $num_deleted old lock files."); } function expire_cached_files($debug) { - foreach (array("simplepie", "images", "export") as $dir) { + foreach (array("simplepie", "images", "export", "upload") as $dir) { $cache_dir = CACHE_DIR . "/$dir"; - if ($debug) _debug("Expiring $cache_dir"); +// if ($debug) _debug("Expiring $cache_dir"); $num_deleted = 0; @@ -1129,7 +1191,7 @@ } } - if ($debug) _debug("Removed $num_deleted files."); + if ($debug) _debug("$cache_dir: removed $num_deleted files."); } } @@ -1158,11 +1220,13 @@ foreach ($filters as $filter) { $match_any_rule = $filter["match_any_rule"]; + $inverse = $filter["inverse"]; $filter_match = false; foreach ($filter["rules"] as $rule) { $match = false; - $reg_exp = $rule["reg_exp"]; + $reg_exp = str_replace('/', '\/', $rule["reg_exp"]); + $rule_inverse = $rule["inverse"]; if (!$reg_exp) continue; @@ -1190,11 +1254,17 @@ $match = @preg_match("/$reg_exp/i", $author); break; case "tag": - $tag_string = join(",", $tags); - $match = @preg_match("/$reg_exp/i", $tag_string); + foreach ($tags as $tag) { + if (@preg_match("/$reg_exp/i", $tag)) { + $match = true; + break; + } + } break; } + if ($rule_inverse) $match = !$match; + if ($match_any_rule) { if ($match) { $filter_match = true; @@ -1208,9 +1278,14 @@ } } + if ($inverse) $filter_match = !$filter_match; + if ($filter_match) { foreach ($filter["actions"] AS $action) { array_push($matches, $action); + + // if Stop action encountered, perform no further processing + if ($action["type"] == "stop") return $matches; } } } @@ -1259,11 +1334,11 @@ return false; } - function assign_article_to_label_filters($link, $id, $filters, $owner_uid, $article_labels) { + function assign_article_to_label_filters($id, $filters, $owner_uid, $article_labels) { foreach ($filters as $f) { if ($f["type"] == "label") { if (!labels_contains_caption($article_labels, $f["param"])) { - label_add_article($link, $id, $f["param"], $owner_uid); + label_add_article($id, $f["param"], $owner_uid); } } } @@ -1274,5 +1349,26 @@ mb_strtolower(strip_tags($title), 'utf-8')); } + function verify_feed_xml($feed_data) { + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadXML($feed_data); + $error = libxml_get_last_error(); + libxml_clear_errors(); + return $error; + } + + function housekeeping_common($debug) { + expire_cached_files($debug); + expire_lock_files($debug); + expire_error_log($debug); + + $count = update_feedbrowser_cache(); + _debug("Feedbrowser updated, $count feeds processed."); + purge_orphans( true); + $rc = cleanup_tags( 14, 50000); + + _debug("Cleaned $rc cached tags."); + } ?> diff --git a/include/sanity_check.php b/include/sanity_check.php index 5cb556746..b2888b1d7 100644 --- a/include/sanity_check.php +++ b/include/sanity_check.php @@ -1,8 +1,27 @@ <?php - // WARNING: Don't ask for help on tt-rss.org forums or the bugtracker if you have - // modified this file. + /* + * WARNING! + * + * If you modify this file, you are ON YOUR OWN! + * + * Believe it or not, all of the checks below are required to succeed for + * tt-rss to actually function properly. + * + * If you think you have a better idea about what is or isn't required, feel + * free to modify the file, note though that you are therefore automatically + * disqualified from any further support by official channels, e.g. tt-rss.org + * issue tracker or the forums. + * + * If you come crying when stuff inevitably breaks, you will be mocked and told + * to get out. */ + + function make_self_url_path() { + $url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); + + return $url_path; + } - function initial_sanity_check($link) { + function initial_sanity_check() { $errors = array(); @@ -12,6 +31,10 @@ require_once "sanity_config.php"; + if (file_exists("install") && !file_exists("config.php")) { + array_push($errors, "Please copy config.php-dist to config.php or run the installer in install/"); + } + if (strpos(PLUGINS, "auth_") === FALSE) { array_push($errors, "Please enable at least one authentication module via PLUGINS constant in config.php"); } @@ -32,10 +55,26 @@ array_push($errors, "Image cache is not writable (chmod -R 777 ".CACHE_DIR."/images)"); } + if (!is_writable(CACHE_DIR . "/upload")) { + array_push($errors, "Upload cache is not writable (chmod -R 777 ".CACHE_DIR."/upload)"); + } + if (!is_writable(CACHE_DIR . "/export")) { array_push($errors, "Data export cache is not writable (chmod -R 777 ".CACHE_DIR."/export)"); } + if (!is_writable(CACHE_DIR . "/js")) { + array_push($errors, "Javascript cache is not writable (chmod -R 777 ".CACHE_DIR."/js)"); + } + + if (strlen(FEED_CRYPT_KEY) > 0 && strlen(FEED_CRYPT_KEY) != 24) { + array_push($errors, "FEED_CRYPT_KEY should be exactly 24 characters in length."); + } + + if (strlen(FEED_CRYPT_KEY) > 0 && !function_exists("mcrypt_decrypt")) { + array_push($errors, "FEED_CRYPT_KEY requires mcrypt functions which are not found."); + } + if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) { array_push($errors, "Configuration option checker sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh"); @@ -48,33 +87,19 @@ } } - if (SESSION_EXPIRE_TIME < 60) { - array_push($errors, "SESSION_EXPIRE_TIME set in config.php is too low, please set it to an integer value >= 60"); - } - - if (SESSION_EXPIRE_TIME < SESSION_COOKIE_LIFETIME) { - array_push($errors, "SESSION_EXPIRE_TIME set in config.php should be >= to SESSION_COOKIE_LIFETIME"); - } - if (SINGLE_USER_MODE) { - $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME); + $result = db_query("SELECT id FROM ttrss_users WHERE id = 1"); - if ($link) { - $result = db_query($link, "SELECT id FROM ttrss_users WHERE id = 1"); - - if (db_num_rows($result) != 1) { - array_push($errors, "SINGLE_USER_MODE is enabled in config.php but default admin account is not found."); - } + if (db_num_rows($result) != 1) { + array_push($errors, "SINGLE_USER_MODE is enabled in config.php but default admin account is not found."); } } if (SELF_URL_PATH == "http://yourserver/tt-rss/") { - if ($_SERVER['HTTP_REFERER']) { - array_push($errors, - "Please set SELF_URL_PATH to the correct value for your server (possible value: <b>" . $_SERVER['HTTP_REFERER'] . "</b>)"); - } else { - array_push($errors, "Please set SELF_URL_PATH to the correct value for your server."); - } + $urlpath = preg_replace("/\w+\.php$/", "", make_self_url_path()); + + array_push($errors, + "Please set SELF_URL_PATH to the correct value for your server (possible value: <b>$urlpath</b>)"); } if (!is_writable(ICONS_DIR)) { @@ -85,10 +110,6 @@ array_push($errors, "LOCK_DIRECTORY defined in config.php is not writable (chmod -R 777 ".LOCK_DIRECTORY.").\n"); } - if (ini_get("open_basedir")) { - array_push($errors, "PHP configuration option open_basedir is not supported. Please disable this in PHP settings file (php.ini)."); - } - if (!function_exists("curl_init") && !ini_get("allow_url_fopen")) { array_push($errors, "PHP configuration option allow_url_fopen is disabled, and CURL functions are not present. Either enable allow_url_fopen or install PHP extension for CURL."); } @@ -97,7 +118,7 @@ array_push($errors, "PHP support for JSON is required, but was not found."); } - if (DB_TYPE == "mysql" && !function_exists("mysql_connect")) { + if (DB_TYPE == "mysql" && !function_exists("mysql_connect") && !function_exists("mysqli_connect")) { array_push($errors, "PHP support for MySQL is required for configured DB_TYPE in config.php."); } @@ -117,10 +138,14 @@ array_push($errors, "PHP support for ctype functions are required by HTMLPurifier."); } - if (ini_get("safe_mode")) { - array_push($errors, "PHP safe mode setting is not supported."); + if (!function_exists("iconv")) { + array_push($errors, "PHP support for iconv is required to handle multiple charsets."); } + /* if (ini_get("safe_mode")) { + array_push($errors, "PHP safe mode setting is not supported."); + } */ + if ((PUBSUBHUBBUB_HUB || PUBSUBHUBBUB_ENABLED) && !function_exists("curl_init")) { array_push($errors, "PHP support for CURL is required for PubSubHubbub."); } @@ -138,7 +163,8 @@ <link rel="stylesheet" type="text/css" href="utility.css"> </head> <body> - <div class="floatingLogo"><img src="images/logo_wide.png"></div> + <div class="floatingLogo"><img src="images/logo_small.png"></div> + <div class="content"> <h1>Startup failed</h1> @@ -150,6 +176,8 @@ <p>You might want to check tt-rss <a href="http://tt-rss.org/wiki">wiki</a> or the <a href="http://tt-rss.org/forum">forums</a> for more information. Please search the forums before creating new topic for your question.</p> + + </div> </body> </html> @@ -170,6 +198,6 @@ } } - initial_sanity_check($link); + initial_sanity_check(); ?> diff --git a/include/sanity_config.php b/include/sanity_config.php index d4a468f6d..7d8afe102 100644 --- a/include/sanity_config.php +++ b/include/sanity_config.php @@ -1,3 +1,3 @@ -<?php # This file has been generated at: Sat Feb 9 22:34:30 MSK 2013 +<?php # This file has been generated at: Fri Apr 19 09:22:33 MSK 2013 define('GENERATED_CONFIG_CHECK', 26); -$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_EXPIRE_TIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_HOST', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'CONFIG_VERSION'); ?> +$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_SERVER', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_SERVER', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?> diff --git a/include/sessions.php b/include/sessions.php index 2cef1d91b..423ef0eda 100644 --- a/include/sessions.php +++ b/include/sessions.php @@ -2,9 +2,14 @@ // Original from http://www.daniweb.com/code/snippet43.html require_once "config.php"; - require_once "db.php"; - - $session_expire = SESSION_EXPIRE_TIME; //seconds + require_once "classes/db.php"; + require_once "autoload.php"; + require_once "errorhandler.php"; + require_once "lib/accept-to-gettext.php"; + require_once "lib/gettext/gettext.inc"; + require_once "version.php"; + + $session_expire = max(SESSION_COOKIE_LIFETIME, 86400); $session_name = (!defined('TTRSS_SESSION_NAME')) ? "ttrss_sid" : TTRSS_SESSION_NAME; if (@$_SERVER['HTTPS'] == "on") { @@ -12,99 +17,135 @@ ini_set("session.cookie_secure", true); } - ini_set("session.gc_probability", 50); + ini_set("session.gc_probability", 75); ini_set("session.name", $session_name); ini_set("session.use_only_cookies", true); - ini_set("session.gc_maxlifetime", SESSION_EXPIRE_TIME); + ini_set("session.gc_maxlifetime", $session_expire); + ini_set("session.cookie_lifetime", min(0, SESSION_COOKIE_LIFETIME)); - function ttrss_open ($s, $n) { + function session_get_schema_version($nocache = false) { + global $schema_version; + + if (!$schema_version) { + $result = Db::get()->query("SELECT schema_version FROM ttrss_version"); + $version = Db::get()->fetch_result($result, 0, "schema_version"); + $schema_version = $version; + return $version; + } else { + return $schema_version; + } + } + + function validate_session() { + if (SINGLE_USER_MODE) return true; + + if (VERSION_STATIC != $_SESSION["version"]) return false; + + $check_ip = $_SESSION['ip_address']; + + switch (SESSION_CHECK_ADDRESS) { + case 0: + $check_ip = ''; + break; + case 1: + $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); + break; + case 2: + $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')); + $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); + break; + }; + + if ($check_ip && strpos($_SERVER['REMOTE_ADDR'], $check_ip) !== 0) { + $_SESSION["login_error_msg"] = + __("Session failed to validate (incorrect IP)"); + return false; + } + + if ($_SESSION["ref_schema_version"] != session_get_schema_version(true)) + return false; + + if (sha1($_SERVER['HTTP_USER_AGENT']) != $_SESSION["user_agent"]) + return false; + + if ($_SESSION["uid"]) { + $result = Db::get()->query( + "SELECT pwd_hash FROM ttrss_users WHERE id = '".$_SESSION["uid"]."'"); + + // user not found + if (Db::get()->num_rows($result) == 0) { + return false; + } else { + $pwd_hash = Db::get()->fetch_result($result, 0, "pwd_hash"); - global $session_connection; + if ($pwd_hash != $_SESSION["pwd_hash"]) { + return false; + } + } + } - $session_connection = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME); + return true; + } + + function ttrss_open ($s, $n) { return true; } function ttrss_read ($id){ + global $session_expire; - global $session_connection,$session_read; + $res = Db::get()->query("SELECT data FROM ttrss_sessions WHERE id='$id'"); - $query = "SELECT data FROM ttrss_sessions WHERE id='$id'"; + if (Db::get()->num_rows($res) != 1) { - $res = db_query($session_connection, $query); + $expire = time() + $session_expire; + + Db::get()->query("INSERT INTO ttrss_sessions (id, data, expire) + VALUES ('$id', '', '$expire')"); - if (db_num_rows($res) != 1) { return ""; } else { - $session_read = db_fetch_assoc($res); - $session_read["data"] = base64_decode($session_read["data"]); - return $session_read["data"]; + return base64_decode(Db::get()->fetch_result($res, 0, "data")); } + } function ttrss_write ($id, $data) { + global $session_expire; - if (! $data) { - return false; - } - - global $session_connection, $session_read, $session_expire; - + $data = base64_encode($data); $expire = time() + $session_expire; - $data = db_escape_string(base64_encode($data), $session_connection); + Db::get()->query("UPDATE ttrss_sessions SET data='$data', expire='$expire' WHERE id='$id'"); - if ($session_read) { - $query = "UPDATE ttrss_sessions SET data='$data', - expire='$expire' WHERE id='$id'"; - } else { - $query = "INSERT INTO ttrss_sessions (id, data, expire) - VALUES ('$id', '$data', '$expire')"; - } - - db_query($session_connection, $query); return true; } function ttrss_close () { - - global $session_connection; - - db_close($session_connection); - return true; } - function ttrss_destroy ($id) { - - global $session_connection; - - $query = "DELETE FROM ttrss_sessions WHERE id = '$id'"; - - db_query($session_connection, $query); + function ttrss_destroy($id) { + Db::get()->query("DELETE FROM ttrss_sessions WHERE id = '$id'"); return true; } function ttrss_gc ($expire) { - - global $session_connection; - - $query = "DELETE FROM ttrss_sessions WHERE expire < " . time(); - - db_query($session_connection, $query); + Db::get()->query("DELETE FROM ttrss_sessions WHERE expire < " . time()); } - if (!SINGLE_USER_MODE && DB_TYPE == "pgsql") { + if (!SINGLE_USER_MODE /* && DB_TYPE == "pgsql" */) { session_set_save_handler("ttrss_open", "ttrss_close", "ttrss_read", "ttrss_write", "ttrss_destroy", "ttrss_gc"); + register_shutdown_function('session_write_close'); } - session_set_cookie_params(SESSION_COOKIE_LIFETIME); - - if (!defined('TTRSS_SESSION_NAME') || TTRSS_SESSION_NAME != 'ttrss_api_sid') { - @session_start(); + if (!defined('NO_SESSION_AUTOSTART')) { + if (isset($_COOKIE[session_name()])) { + @session_start(); + } } ?> diff --git a/include/version.php b/include/version.php index 65af7f452..7396f81e0 100644 --- a/include/version.php +++ b/include/version.php @@ -1,3 +1,19 @@ <?php - define('VERSION', "1.7.4"); + define('VERSION_STATIC', '1.7.9'); + + function get_version() { + date_default_timezone_set('UTC'); + $root_dir = dirname(dirname(__FILE__)); + + if (is_dir("$root_dir/.git") && file_exists("$root_dir/.git/ORIG_HEAD")) { + + $suffix = substr(trim(file_get_contents("$root_dir/.git/ORIG_HEAD")), 0, 7); + + return VERSION_STATIC . ".$suffix"; + } else { + return VERSION_STATIC; + } + } + + define('VERSION', get_version()); ?> |