]> git.wh0rd.org - tt-rss.git/blobdiff - include/functions.php
Merge branch 'hookhead' of git://github.com/justauserx/Tiny-Tiny-RSS into justauserx...
[tt-rss.git] / include / functions.php
index 8a414aec2efc991d5300af25b85e02b1a62fb113..8c25d9008be8df86243d08abc09617bea668091d 100644 (file)
@@ -1,10 +1,12 @@
 <?php
        define('EXPECTED_CONFIG_VERSION', 26);
-       define('SCHEMA_VERSION', 118);
+       define('SCHEMA_VERSION', 121);
 
        define('LABEL_BASE_INDEX', -1024);
        define('PLUGIN_FEED_BASE_INDEX', -128);
 
+       define('COOKIE_LIFETIME_LONG', 86400*365);
+
        $fetch_last_error = false;
        $fetch_last_error_code = false;
        $fetch_last_content_type = false;
                        $lang = _TRANSLATION_OVERRIDE_DEFAULT;
                }
 
-               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 && $pref_lang != 'auto') {
+                               $lang = $pref_lang;
+                       }
                }
 
                if ($lang) {
                }
        }
 
-       startup_gettext();
-
        require_once 'db-prefs.php';
        require_once 'version.php';
        require_once 'ccache.php';
 
        require_once 'lib/pubsubhubbub/publisher.php';
 
-       $tz_offset = -1;
-       $utc_tz = new DateTimeZone('UTC');
        $schema_version = false;
 
        /**
                        $fetch_curl_used = true;
 
                        if (ini_get("safe_mode") || ini_get("open_basedir")) {
-                               $ch = curl_init(geturl($url));
+                               $new_url = geturl($url);
+                               if (!$new_url) {
+                                   // geturl has already populated $fetch_last_error
+                                   return false;
+                               }
+                               $ch = curl_init($new_url);
                        } else {
                                $ch = curl_init($url);
                        }
 
-                       if ($timestamp) {
+                       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)));
                        }
                        $data = @file_get_contents($url, false, $context);
 
                        $fetch_last_content_type = false;  // reset if no type was sent from server
-                       if (is_array($http_response_header)) {
+                       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);
                                @session_start();
 
                                $_SESSION["uid"] = $user_id;
-                               $_SESSION["version"] = VERSION;
+                               $_SESSION["version"] = VERSION_STATIC;
 
                                $result = db_query("SELECT login,access_level,pwd_hash FROM ttrss_users
                                        WHERE id = '$user_id'");
                                $_SESSION["last_login_update"] = time();
                        }
 
-                       if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) {
-                               setcookie("ttrss_lang", $_SESSION["language"],
-                                       time() + SESSION_COOKIE_LIFETIME);
-                       }
-
                        if ($_SESSION["uid"]) {
+                               startup_gettext();
                                load_user_plugins($_SESSION["uid"]);
 
                                /* cleanup ccache */
                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('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;
        function get_schema_version($nocache = false) {
                global $schema_version;
 
-               if (!$schema_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;
        }
 
        function file_is_locked($filename) {
-               if (function_exists('flock')) {
-                       $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
-                       if ($fp) {
-                               if (flock($fp, LOCK_EX | LOCK_NB)) {
-                                       flock($fp, LOCK_UN);
+               if (file_exists(LOCK_DIRECTORY . "/$filename")) {
+                       if (function_exists('flock')) {
+                               $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
+                               if ($fp) {
+                                       if (flock($fp, LOCK_EX | LOCK_NB)) {
+                                               flock($fp, LOCK_UN);
+                                               fclose($fp);
+                                               return false;
+                                       }
                                        fclose($fp);
+                                       return true;
+                               } else {
                                        return false;
                                }
-                               fclose($fp);
-                               return true;
-                       } else {
-                               return false;
                        }
+                       return true; // consider the file always locked and skip the test
+               } else {
+                       return false;
                }
-               return true; // consider the file always locked and skip the test
        }
 
+
        function make_lockfile($filename) {
                $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
 
                if ($fp && flock($fp, LOCK_EX | LOCK_NB)) {
+                       $stat_h = fstat($fp);
+                       $stat_f = stat(LOCK_DIRECTORY . "/$filename");
+
+                       if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
+                               if ($stat_h["ino"] != $stat_f["ino"] ||
+                                               $stat_h["dev"] != $stat_f["dev"]) {
+
+                                       return false;
+                               }
+                       }
+
                        if (function_exists('posix_getpid')) {
                                fwrite($fp, posix_getpid() . "\n");
                        }
 
                $data = array_merge($data, getVirtCounters());
                $data = array_merge($data, getLabelCounters());
-               $data = array_merge($data, getFeedCounters($active_feed));
+               $data = array_merge($data, getFeedCounters());
                $data = array_merge($data, getCategoryCounters());
 
                return $data;
 
                        return $unread;
                } else if ($cat == -1) {
-                       return getFeedUnread(-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("
 
                        $count = getFeedUnread($i);
 
+                       if ($i == 0 || $i == -1 || $i == -2)
+                               $auxctr = getFeedArticles($i, false);
+                       else
+                               $auxctr = 0;
+
                        $cv = array("id" => $i,
-                               "counter" => (int) $count);
+                               "counter" => (int) $count,
+                               "auxcounter" => $auxctr);
 
 //                     if (get_pref('EXTENDED_FEEDLIST'))
 //                             $cv["xmsg"] = getFeedArticles($i)." ".__("total");
 
                $owner_uid = $_SESSION["uid"];
 
-               $result = db_query("SELECT id,caption,COUNT(unread) AS unread
+               $result = db_query("SELECT id,caption,COUNT(u1.unread) AS unread,COUNT(u2.unread) AS total
                        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
-                                       AND ttrss_user_entries.owner_uid = $owner_uid)
+                               LEFT JOIN ttrss_user_entries AS u1 ON (u1.ref_id = article_id AND u1.unread = true
+                                       AND u1.owner_uid = $owner_uid)
+                               LEFT JOIN ttrss_user_entries AS u2 ON (u2.ref_id = article_id AND u2.unread = false
+                                       AND u2.owner_uid = $owner_uid)
                                WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id,
                                        ttrss_labels2.caption");
 
 
                        $id = label_to_feed_id($line["id"]);
 
-                       $label_name = $line["caption"];
-                       $count = $line["unread"];
-
                        $cv = array("id" => $id,
-                               "counter" => (int) $count);
+                               "counter" => (int) $line["unread"],
+                               "auxcounter" => (int) $line["total"]);
 
                        if ($descriptions)
-                               $cv["description"] = $label_name;
-
-//                     if (get_pref('EXTENDED_FEEDLIST'))
-//                             $cv["xmsg"] = getFeedArticles($id)." ".__("total");
+                               $cv["description"] = $line["caption"];
 
                        array_push($ret_arr, $cv);
                }
                        }
 
                        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"));
                        return "images/archive.png";
                        break;
                case -1:
-                       return "images/mark_set.svg";
+                       return "images/star.png";
                        break;
                case -2:
-                       return "images/pub_set.svg";
+                       return "images/feed.png";
                        break;
                case -3:
                        return "images/fresh.png";
                        break;
                case -4:
-                       return "images/tag.png";
+                       return "images/folder.png";
                        break;
                case -6:
-                       return "images/recently_read.png";
+                       return "images/time.png";
                        break;
                default:
                        if ($id < LABEL_BASE_INDEX) {
                $params["max_feed_id"] = (int) $max_feed_id;
                $params["num_feeds"] = (int) $num_feeds;
 
-               $params["collapsed_feedlist"] = (int) get_pref("_COLLAPSED_FEEDLIST");
                $params["hotkeys"] = get_hotkeys_map();
 
                $params["csrf_token"] = $_SESSION["csrf_token"];
                                $filter_query_part = filter_to_sql($filter, $owner_uid);
 
                                // Try to check if SQL regexp implementation chokes on a valid regexp
+
+
                                $result = db_query("SELECT true AS true_val FROM ttrss_entries,
-                                       ttrss_user_entries, ttrss_feeds, ttrss_feed_categories
+                                       ttrss_user_entries, ttrss_feeds
                                        WHERE $filter_query_part LIMIT 1", false);
 
                                if ($result) {
                                        $feed_title = getCategoryTitle($feed);
                                } else {
                                        if (is_numeric($feed) && $feed > 0) {
-                                               $result = db_query("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($feed);
                                        }
                                }
                        }
 
-                       $content_query_part = "content as content_preview, cached_content, ";
+
+                       $content_query_part = "content, content AS content_preview, cached_content, ";
+
 
                        if (is_numeric($feed)) {
 
                                $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 strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) {
-               $entries = $doc->getElementsByTagName("*");
+               $xpath = new DOMXPath($doc);
+               $entries = $xpath->query('//*');
 
                foreach ($entries as $entry) {
                        if (!in_array($entry->nodeName, $allowed_elements)) {
                        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;
                                        }
                                }
                        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 */
        function format_warning($msg, $id = "") {
                global $link;
                return "<div class=\"warning\" id=\"$id\">
-                       <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>";
+                       <span><img src=\"images/alert.png\"></span><span>$msg</span></div>";
        }
 
        function format_notice($msg, $id = "") {
                global $link;
                return "<div class=\"notice\" id=\"$id\">
-                       <span><img src=\"images/sign_info.svg\"></span><span>$msg</span></div>";
+                       <span><img src=\"images/information.png\"></span><span>$msg</span></div>";
        }
 
        function format_error($msg, $id = "") {
                global $link;
                return "<div class=\"error\" id=\"$id\">
-                       <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>";
+                       <span><img src=\"images/alert.png\"></span><span>$msg</span></div>";
        }
 
        function print_notice($msg) {
                        if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false ||
                                $_SESSION["hasMp3"])) {
 
-                               $entry .= "<audio controls>
+                               $entry .= "<audio preload=\"none\" controls>
                                        <source type=\"$ctype\" src=\"$url\"></source>
                                        </audio>";
 
                        $line["tags"] = get_article_tags($id, $owner_uid, $line["tag_cache"]);
                        unset($line["tag_cache"]);
 
-                       $line["content"] = sanitize($line["content"], false, $owner_uid,        $line["site_url"]);
+                       $line["content"] = sanitize($line["content"],
+                               sql_bool_to_bool($line['hide_images']),
+                               $owner_uid, $line["site_url"]);
 
                        foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE) as $p) {
                                $line = $p->hook_render_article($line);
                                $rv['content'] .= "<html><head>
                                                <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\">
+                                               <link rel=\"stylesheet\" type=\"text/css\" href=\"css/tt-rss.css\">
                                        </head><body id=\"ttrssZoom\">";
                        }
 
 
        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;
        }
 
        }
 
        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);
-                       }
-
-                       $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>";
-
-                       array_push($formatted_tags, $tag_str);
-
-                       $tmp_tags_str = implode(", ", $formatted_tags);
-
-                       if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) {
-                               break;
+                       for ($i = 0; $i < $maxtags; $i++) {
+                               $tags_str .= "<a class=\"tag\" href=\"#\" onclick=\"viewfeed('".$tags[$i]."')\">" . $tags[$i] . "</a>, ";
                        }
-               }
 
-               $tags_str = implode(", ", $formatted_tags);
+                       $tags_str = mb_substr($tags_str, 0, mb_strlen($tags_str)-2);
 
-               if ($num_tags < count($tags)) {
-                       $tags_str .= ", &hellip;";
-               }
+                       if (count($tags) > $maxtags)
+                               $tags_str .= ", &hellip;";
 
-               if ($num_tags == 0) {
-                       $tags_str = __("no tags");
+                       return $tags_str;
                }
-
-               return $tags_str;
-
        }
 
        function format_article_labels($labels, $id) {
 
-               if (is_array($labels)) return '';
+               if (!is_array($labels)) return '';
 
                $labels_str = "";
 
         * @return string Absolute URL
         */
        function rewrite_relative_url($url, $rel_url) {
-               if (strpos($rel_url, "magnet:") === 0) {
+               if (strpos($rel_url, ":") !== false) {
                        return $rel_url;
                } else if (strpos($rel_url, "://") !== false) {
                        return $rel_url;
 
                $sphinxpair = explode(":", SPHINX_SERVER, 2);
 
-               $sphinxClient->SetServer($sphinxpair[0], $sphinxpair[1]);
+               $sphinxClient->SetServer($sphinxpair[0], (int)$sphinxpair[1]);
                $sphinxClient->SetConnectTimeout(1);
 
                $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
                        $reg_qpart = "REGEXP";
 
                foreach ($filter["rules"] AS $rule) {
+                       $rule['reg_exp'] = str_replace('/', '\/', $rule["reg_exp"]);
                        $regexp_valid = preg_match('/' . $rule['reg_exp'] . '/',
                                $rule['reg_exp']) !== FALSE;
 
                curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled...
                curl_setopt($curl, CURLOPT_TIMEOUT, 60);
+               curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
 
                $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) {
+                               curl_close($curl);
                                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, $referer):'';
+                               return (isset($url_parsed))? geturl($url):'';
                        }
+
+                       global $fetch_last_error;
+
+                       $fetch_last_error = curl_errno($curl) . " " . curl_error($curl);
+                       curl_close($curl);
+
                        $oline='';
                        foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';}
                        $line =$oline." \r\n ".$url."\r\n-----------------\r\n";
 #                      fwrite($handle, $line);
                        return FALSE;
                }
+               curl_close($curl);
                return $url;
        }
 
 
                foreach ($files as $js) {
                        if (!isset($_GET['debug'])) {
-                               $cached_file = CACHE_DIR . "/js/$js.js";
+                               $cached_file = CACHE_DIR . "/js/".basename($js).".js";
 
                                if (file_exists($cached_file) &&
                                                is_readable($cached_file) &&
        }
 
        function calculate_dep_timestamp() {
-               $files = array_merge(glob("js/*.js"), glob("*.css"));
+               $files = array_merge(glob("js/*.js"), glob("css/*.css"));
 
                $max_ts = -1;