]> git.wh0rd.org - tt-rss.git/blobdiff - include/functions.php
add ttrss_feeds.last_unconditional (schema bump)
[tt-rss.git] / include / functions.php
index f290560778467dae1c91f7f3d778fb150d1e8714..6c7a6de5f378f0b434bd1bffa607911bc3bc22a2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
        define('EXPECTED_CONFIG_VERSION', 26);
-       define('SCHEMA_VERSION', 131);
+       define('SCHEMA_VERSION', 133);
 
        define('LABEL_BASE_INDEX', -1024);
        define('PLUGIN_FEED_BASE_INDEX', -128);
                global $fetch_last_error_code;
                global $fetch_last_error_content;
                global $fetch_last_content_type;
+               global $fetch_last_modified;
                global $fetch_curl_used;
 
                $fetch_last_error = false;
                $fetch_last_error_content = "";
                $fetch_last_content_type = "";
                $fetch_curl_used = false;
+               $fetch_last_modified = "";
 
                if (!is_array($options)) {
 
                        // falling back on compatibility shim
-                       $option_names = [ "url", "type", "login", "pass", "post_query", "timeout", "timestamp", "useragent" ];
+                       $option_names = [ "url", "type", "login", "pass", "post_query", "timeout", "last_modified", "useragent" ];
                        $tmp = [];
 
                        for ($i = 0; $i < func_num_args(); $i++) {
                $pass = isset($options["pass"]) ? $options["pass"] : false;
                $post_query = isset($options["post_query"]) ? $options["post_query"] : false;
                $timeout = isset($options["timeout"]) ? $options["timeout"] : false;
-               $timestamp = isset($options["timestamp"]) ? $options["timestamp"] : 0;
+               $last_modified = isset($options["last_modified"]) ? $options["last_modified"] : "";
                $useragent = isset($options["useragent"]) ? $options["useragent"] : false;
                $followlocation = isset($options["followlocation"]) ? $options["followlocation"] : true;
 
 
                        $ch = curl_init($url);
 
-                       if ($timestamp && !$post_query) {
+                       if ($last_modified && !$post_query) {
                                curl_setopt($ch, CURLOPT_HTTPHEADER,
-                                       array("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $timestamp)));
+                                       array("If-Modified-Since: $last_modified"));
                        }
 
                        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : FILE_FETCH_CONNECT_TIMEOUT);
                        curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
                        curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+                       curl_setopt($ch, CURLOPT_HEADER, true);
                        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
                        curl_setopt($ch, CURLOPT_USERAGENT, $useragent ? $useragent :
                                SELF_USER_AGENT);
                        if ($login && $pass)
                                curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
 
-                       $contents = @curl_exec($ch);
+                       $ret = @curl_exec($ch);
+
+                       $headers_length = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+                       $headers = explode("\r\n", substr($ret, 0, $headers_length));
+                       $contents = substr($ret, $headers_length);
+
+                       foreach ($headers as $header) {
+                if (strstr($header, ": ") !== FALSE) {
+                    list ($key, $value) = explode(": ", $header);
+
+                    if (strtolower($key) == "last-modified") {
+                        $fetch_last_modified = $value;
+                    }
+                }
+
+                if (substr(strtolower($header), 0, 7) == 'http/1.') {
+                    $fetch_last_error_code = (int) substr($header, 9, 3);
+                    $fetch_last_error = $header;
+                }
+                       }
 
                        if (curl_errno($ch) === 23 || curl_errno($ch) === 61) {
                                curl_setopt($ch, CURLOPT_ENCODING, 'none');
                                $contents = @curl_exec($ch);
                        }
 
-                       if ($contents === false) {
-                               $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
-                               curl_close($ch);
-                               return false;
-                       }
-
                        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                        $fetch_last_content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
 
                        $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 {
-                                       $fetch_last_error = "HTTP Code: $http_code";
+                                       $fetch_last_error .=  "; " . curl_errno($ch) . " " . curl_error($ch);
                                }
+
                                $fetch_last_error_content = $contents;
                                curl_close($ch);
                                return false;
                        }
 
+                       if (!$contents) {
+                               $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
+                               curl_close($ch);
+                               return false;
+                       }
+
                        curl_close($ch);
 
                        return $contents;
 
                        // TODO: should this support POST requests or not? idk
 
-                       if (!$post_query && $timestamp) {
+                       if (!$post_query && $last_modified) {
                                 $context = stream_context_create(array(
                                          'http' => array(
                                                        'method' => 'GET',
                                                    'ignore_errors' => true,
                                                    'timeout' => $timeout ? $timeout : FILE_FETCH_TIMEOUT,
                                                        'protocol_version'=> 1.1,
-                                                       'header' => "If-Modified-Since: ".gmdate("D, d M Y H:i:s \\G\\M\\T\r\n", $timestamp)
-                                         )));
+                                                       'header' => "If-Modified-Since: $last_modified\r\n")
+                                         ));
                        } else {
                                 $context = stream_context_create(array(
                                          'http' => array(
                        $data = @file_get_contents($url, false, $context);
 
                        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
-                                       }
+                               foreach ($http_response_header as $header) {
+                                   if (strstr($header, ": ") !== FALSE) {
+                        list ($key, $value) = explode(": ", $header);
+
+                        $key = strtolower($key);
+
+                        if ($key == 'content-type') {
+                            $fetch_last_content_type = $value;
+                            // 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
+                        } else if ($key == 'last-modified') {
+                            $fetch_last_modified = $value;
+                        }
+                    }
 
-                                       if (substr(strtolower($h), 0, 7) == 'http/1.') {
-                                               $fetch_last_error_code = (int) substr($h, 9, 3);
+                                       if (substr(strtolower($header), 0, 7) == 'http/1.') {
+                                               $fetch_last_error_code = (int) substr($header, 9, 3);
+                                               $fetch_last_error = $header;
                                        }
                                }
                        }
                                $error = error_get_last();
 
                                if ($error['message'] != $old_error['message']) {
-                                       $fetch_last_error = $error["message"];
-                               } else {
-                                       $fetch_last_error = "HTTP Code: $fetch_last_error_code";
+                                       $fetch_last_error .= "; " . $error["message"];
                                }
 
                                $fetch_last_error_content = $data;
                        $doc->loadHTML($html);
                        $xpath = new DOMXPath($doc);
 
-                       $base = $xpath->query('/html/head/base');
+                       $base = $xpath->query('/html/head/base[@href]');
                        foreach ($base as $b) {
-                               $url = $b->getAttribute("href");
+                               $url = rewrite_relative_url($url, $b->getAttribute("href"));
                                break;
                        }
 
                $params["icon_cross"] = base64_img("images/cross.png");
                $params["icon_indicator_white"] = base64_img("images/indicator_white.gif");
 
+               $params["labels"] = Labels::get_all_labels($_SESSION["uid"]);
+
                return $params;
        }
 
                $data['dep_ts'] = calculate_dep_timestamp();
                $data['reload_on_ts_change'] = !defined('_NO_RELOAD_ON_TS_CHANGE');
 
+               $data["labels"] = Labels::get_all_labels($_SESSION["uid"]);
 
                if (CHECK_FOR_UPDATES && !$disable_update_check && $_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) {
                        $update_result = @check_for_update();
                $doc->loadHTML($charset_hack . $res);
                $xpath = new DOMXPath($doc);
 
-               $ttrss_uses_https = parse_url(get_self_url_prefix(), PHP_URL_SCHEME) === 'https';
                $rewrite_base_url = $site_url ? $site_url : get_self_url_prefix();
 
                $entries = $xpath->query('(//a[@href]|//img[@src]|//video/source[@src]|//audio/source[@src])');
                                if ($entry->hasAttribute('src')) {
                                        $is_https_url = parse_url($entry->getAttribute('src'), PHP_URL_SCHEME) === 'https';
 
-                                       if ($ttrss_uses_https && !$is_https_url) {
+                                       if (is_prefix_https() && !$is_https_url) {
 
                                                if ($entry->hasAttribute('srcset')) {
                                                        $entry->removeAttribute('srcset');
                        if (!iframe_whitelisted($entry)) {
                                $entry->setAttribute('sandbox', 'allow-scripts');
                        } else {
-                               if ($_SERVER['HTTPS'] == "on") {
+                               if (is_prefix_https()) {
                                        $entry->setAttribute("src",
                                                str_replace("http://", "https://",
                                                        $entry->getAttribute("src")));
                        'caption', 'cite', 'center', 'code', 'col', 'colgroup',
                        'data', 'dd', 'del', 'details', 'description', 'dfn', 'div', 'dl', 'font',
                        'dt', 'em', 'footer', 'figure', 'figcaption',
-                       'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'html', 'i',
+                       'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', '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',
                return $tag;
        }
 
+       function is_server_https() {
+               return (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] != 'off')) || $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https';
+       }
+
+       function is_prefix_https() {
+               return parse_url(SELF_URL_PATH, PHP_URL_SCHEME) == 'https';
+       }
+
        // this returns SELF_URL_PATH sans ending slash
        function get_self_url_prefix() {
                if (strrpos(SELF_URL_PATH, "/") === strlen(SELF_URL_PATH)-1) {
                }
        }
 
+       /*      this is essentially a wrapper for readfile() which allows plugins to hook
+               output with httpd-specific "fast" implementation i.e. X-Sendfile or whatever else
+
+               hook function should return true if request was handled (or at least attempted to)
+
+               note that this can be called without user context so the plugin to handle this
+               should be loaded systemwide in config.php */
+       function send_local_file($filename) {
+               if (file_exists($filename)) {
+                       $tmppluginhost = new PluginHost();
+
+                       $tmppluginhost->load(PLUGINS, PluginHost::KIND_SYSTEM);
+                       $tmppluginhost->load_data();
+
+                       foreach ($tmppluginhost->get_hooks(PluginHost::HOOK_SEND_LOCAL_FILE) as $plugin) {
+                               if ($plugin->hook_send_local_file($filename)) return true;
+                       }
+
+                       $mimetype = mime_content_type($filename);
+                       header("Content-type: $mimetype");
+
+                       $stamp = gmdate("D, d M Y H:i:s", filemtime($filename)) . " GMT";
+                       header("Last-Modified: $stamp", true);
+
+                       return readfile($filename);
+               } else {
+                       return false;
+               }
+       }
+
+       function check_mysql_tables() {
+               $schema = db_escape_string(DB_NAME);
+
+               $result = db_query("SELECT engine, table_name FROM information_schema.tables WHERE
+                       table_schema = '$schema' AND table_name LIKE 'ttrss_%' AND engine != 'InnoDB'");
+
+               $bad_tables = [];
+
+               while ($line = db_fetch_assoc($result)) {
+                       array_push($bad_tables, $line);
+               }
+
+               return $bad_tables;
+       }
+