]> git.wh0rd.org - tt-rss.git/blobdiff - include/functions.php
pass logfile to child tasks if locking is possible, lock logfile before writing,...
[tt-rss.git] / include / functions.php
index 35edd8d1a116313c4813e381331349f469c3b137..8ede14a0bfa7a188b036d8ac704aff70dd7c22a9 100644 (file)
@@ -1,6 +1,6 @@
 <?php
        define('EXPECTED_CONFIG_VERSION', 26);
-       define('SCHEMA_VERSION', 121);
+       define('SCHEMA_VERSION', 122);
 
        define('LABEL_BASE_INDEX', -1024);
        define('PLUGIN_FEED_BASE_INDEX', -128);
@@ -87,6 +87,7 @@
        require_once "lib/accept-to-gettext.php";
        require_once "lib/gettext/gettext.inc";
 
+       require_once "lib/languagedetect/LanguageDetect.php";
 
        function startup_gettext() {
 
         * @return void
         */
        function _debug($msg, $show = true) {
+               if (defined('SUPPRESS_DEBUGGING'))
+                       return false;
 
                $ts = strftime("%H:%M:%S", time());
                if (function_exists('posix_getpid')) {
                        $fp = fopen(LOGFILE, 'a+');
 
                        if ($fp) {
+                               $locked = false;
+
+                               if (function_exists("flock")) {
+                                       $tries = 0;
+
+                                       // try to lock logfile for writing
+                                       while ($tries < 5 && !$locked = flock($fp, LOCK_EX | LOCK_NB)) {
+                                               sleep(1);
+                                               ++$tries;
+                                       }
+
+                                       if (!$locked) {
+                                               fclose($fp);
+                                               return;
+                                       }
+                               }
+
                                fputs($fp, "[$ts] $msg\n");
+
+                               if (function_exists("flock")) {
+                                       flock($fp, LOCK_UN);
+                               }
+
                                fclose($fp);
                        }
                }
                                curl_setopt($ch, CURLOPT_POSTFIELDS, $post_query);
                        }
 
+                       if ((OPENSSL_VERSION_NUMBER >= 0x0090808f) && (OPENSSL_VERSION_NUMBER < 0x10000000)) {
+                               curl_setopt($ch, CURLOPT_SSLVERSION, 3);
+                       }
+
                        if ($login && $pass)
                                curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
 
                                        $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 WEEK) ";
                                }
                                break;
-                       case "2weeks":
+                       case "2week":
                                if (DB_TYPE == "pgsql") {
                                        $date_qpart = "date_entered < NOW() - INTERVAL '2 week' ";
                                } else {
 
                $keywords = explode(" ", $search);
                $query_keywords = array();
+               $search_words = array();
 
                foreach ($keywords as $k) {
                        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%'))");
+                                       array_push($search_words, $k);
                                }
                                break;
                        case "author":
                                } else {
                                        array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                        OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
+                                       array_push($search_words, $k);
                                }
                                break;
                        case "note":
                                } else {
                                        array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                        OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
+                                       if (!$not) array_push($search_words, $k);
                                }
                                break;
                        case "star":
                                } else {
                                        array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                        OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
+                                       if (!$not) array_push($search_words, $k);
                                }
                                break;
                        case "pub":
                                } else {
                                        array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                        OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
+                                       if (!$not) array_push($search_words, $k);
                                }
                                break;
                        default:
                                } else {
                                        array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                        OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
+
+                                       if (!$not) array_push($search_words, $k);
                                }
                        }
                }
 
                $search_query_part = implode("AND", $query_keywords);
 
-               return $search_query_part;
+               return array($search_query_part, $search_words);
        }
 
        function getParentCategories($cat, $owner_uid) {
                if (!$owner_uid) $owner_uid = $_SESSION["uid"];
 
                $ext_tables_part = "";
+               $search_words = array();
 
                        if ($search) {
 
                                                $search_query_part = "ref_id = -1 AND ";
 
                                } else {
-                                       $search_query_part = search_to_sql($search);
+                                       list($search_query_part, $search_words) = search_to_sql($search);
                                        $search_query_part .= " AND ";
                                }
 
                                                num_comments,
                                                comments,
                                                int_id,
+                                               uuid,
+                                               lang,
                                                hide_images,
                                                unread,feed_id,marked,published,link,last_read,orig_feed_id,
                                                last_marked, last_published,
                                                                "tag_cache," .
                                                                "label_cache," .
                                                                "link," .
+                                                               "lang," .
+                                                               "uuid," .
                                                                "last_read," .
                                                                "(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," .
                                                                "last_marked, last_published, " .
                                $result = db_query($select_qpart . $from_qpart . $where_qpart);
                        }
 
-                       return array($result, $feed_title, $feed_site_url, $last_error, $last_updated);
+                       return array($result, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words);
 
        }
 
-       function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false) {
+       function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false, $highlight_words = false, $article_id = false) {
                if (!$owner) $owner = $_SESSION["uid"];
 
                $res = trim($str); if (!$res) return '';
 
-               if (strpos($res, "href=") === false)
-                       $res = rewrite_urls($res);
-
                $charset_hack = '<head>
                        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                </head>';
                $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);
+                       $retval = $plugin->hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes, $article_id);
                        if (is_array($retval)) {
                                $doc = $retval[0];
                                $allowed_elements = $retval[1];
 
                $doc->removeChild($doc->firstChild); //remove doctype
                $doc = strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes);
+
+               if ($highlight_words) {
+                       foreach ($highlight_words as $word) {
+
+                               // http://stackoverflow.com/questions/4081372/highlight-keywords-in-a-paragraph
+
+                               $elements = $xpath->query("//*/text()");
+
+                               foreach ($elements as $child) {
+
+                                       $fragment = $doc->createDocumentFragment();
+                                       $text = $child->textContent;
+                                       $stubs = array();
+
+                                       while (($pos = mb_stripos($text, $word)) !== false) {
+                                               $fragment->appendChild(new DomText(mb_substr($text, 0, $pos)));
+                                               $word = mb_substr($text, $pos, mb_strlen($word));
+                                               $highlight = $doc->createElement('span');
+                                               $highlight->appendChild(new DomText($word));
+                                               $highlight->setAttribute('class', 'highlight');
+                                               $fragment->appendChild($highlight);
+                                               $text = mb_substr($text, $pos + mb_strlen($word));
+                                       }
+
+                                       if (!empty($text)) $fragment->appendChild(new DomText($text));
+
+                                       $child->parentNode->replaceChild($fragment, $child);
+                               }
+                       }
+               }
+
                $res = $doc->saveHTML();
+
                return $res;
        }
 
                if (preg_match("/^[0-9]*$/", $tag)) return false;
                if (mb_strlen($tag) > 250) return false;
 
-               if (function_exists('iconv')) {
-                       $tag = iconv("utf-8", "utf-8", $tag);
-               }
-
                if (!$tag) return false;
 
                return true;
                        ccache_update($feed_id, $owner_uid);
                }
 
-               $result = db_query("SELECT id,title,link,content,feed_id,comments,int_id,
+               $result = db_query("SELECT id,title,link,content,feed_id,comments,int_id,lang,
                        ".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,
 
                        $line["content"] = sanitize($line["content"],
                                sql_bool_to_bool($line['hide_images']),
-                               $owner_uid, $line["site_url"]);
+                               $owner_uid, $line["site_url"], false, $line["id"]);
 
                        foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE) as $p) {
                                $line = $p->hook_render_article($line);
                                                <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=\"css/tt-rss.css\">
+                                               <script type=\"text/javascript\">
+                                               function openSelectedAttachment(elem) {
+                                                       try {
+                                                               var url = elem[elem.selectedIndex].value;
+
+                                                               if (url) {
+                                                                       window.open(url);
+                                                                       elem.selectedIndex = 0;
+                                                               }
+
+                                                       } catch (e) {
+                                                               exception_error(\"openSelectedAttachment\", e);
+                                                       }
+                                               }
+                                       </script>
                                        </head><body id=\"ttrssZoom\">";
                        }
 
                        $parsed_updated = make_local_datetime($line["updated"], true,
                                $owner_uid, true);
 
-                       $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>";
+                       if (!$zoom_mode)
+                               $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>";
 
                        if ($line["link"]) {
                                $rv['content'] .= "<div class='postTitle'><a target='_blank'
                                $rv['content'] .= "<div class='postTitle'>" . $line["title"] . "$entry_author</div>";
                        }
 
+                       if ($zoom_mode)
+                               $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>";
+
                        $tags_str = format_tags_string($line["tags"], $id);
                        $tags_str_full = join(", ", $line["tags"]);
 
                                }
                        $rv['content'] .= "</div>";
 
-                       $rv['content'] .= "<div class=\"postContent\">";
+                       if (!$line['lang']) $line['lang'] = 'en';
+
+                       $rv['content'] .= "<div class=\"postContent\" lang=\"".$line['lang']."\">";
 
                        $rv['content'] .= $line["content"];
                        $rv['content'] .= format_article_enclosures($id,
 
                $cat_id = (int)getFeedCategory($feed_id);
 
+               if ($cat_id == 0)
+                       $null_cat_qpart = "cat_id IS NULL OR";
+               else
+                       $null_cat_qpart = "";
+
                $result = db_query("SELECT * FROM ttrss_filters2 WHERE
                        owner_uid = $owner_uid AND enabled = true ORDER BY order_id, title");
 
                                FROM ttrss_filters2_rules AS r,
                                ttrss_filter_types AS t
                                WHERE
-                                       (cat_id IS NULL OR cat_id IN ($check_cats)) AND
+                                       ($null_cat_qpart (cat_id IS NULL AND cat_filter = false) OR cat_id IN ($check_cats)) AND
                                        (feed_id IS NULL OR feed_id = '$feed_id') AND
                                        filter_type = t.id AND filter_id = '$filter_id'");
 
 
                                $url = $line["content_url"];
                                $ctype = $line["content_type"];
+                               $title = $line["title"];
 
                                if (!$ctype) $ctype = __("unknown type");
 
                                $entry["type"] = $ctype;
                                $entry["filename"] = $filename;
                                $entry["url"] = $url;
+                               $entry["title"] = $title;
 
                                array_push($entries, $entry);
                        }
                                                                        $rv .= "<p><a target=\"_blank\"
                                                                        href=\"".htmlspecialchars($entry["url"])."\"
                                                                        >" .htmlspecialchars($entry["url"]) . "</a></p>";
+                                                               }
 
+                                                               if ($entry['title']) {
+                                                                       $rv.= "<div class=\"enclosure_title\">${entry['title']}</div>";
                                                                }
                                                }
                                        }
                                "<option value=''>" . __('Attachments')."</option>";
 
                        foreach ($entries as $entry) {
-                               $rv .= "<option value=\"".htmlspecialchars($entry["url"])."\">" . htmlspecialchars($entry["filename"]) . "</option>";
+                               if ($entry["title"])
+                                       $title = "&mdash; " . truncate_string($entry["title"], 30);
+                               else
+                                       $title = "";
+
+                               $rv .= "<option value=\"".htmlspecialchars($entry["url"])."\">" . htmlspecialchars($entry["filename"]) . "$title</option>";
 
                        };
 
 
        }
 
-       function rewrite_urls($html) {
-               libxml_use_internal_errors(true);
-
-               $charset_hack = '<head>
-                       <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-               </head>';
-
-               $doc = new DOMDocument();
-               $doc->loadHTML($charset_hack . $html);
-               $xpath = new DOMXPath($doc);
-
-               $entries = $xpath->query('//*/text()');
-
-               foreach ($entries as $entry) {
-                       if (strstr($entry->wholeText, "://") !== false) {
-                               $text = preg_replace("/((?<!=.)((http|https|ftp)+):\/\/[^ ,!]+)/i",
-                                       "<a target=\"_blank\" href=\"\\1\">\\1</a>", $entry->wholeText);
-
-                               if ($text != $entry->wholeText) {
-                                       $cdoc = new DOMDocument();
-                                       $cdoc->loadHTML($charset_hack . $text);
-
-
-                                       foreach ($cdoc->childNodes as $cnode) {
-                                               $cnode = $doc->importNode($cnode, true);
-
-                                               if ($cnode) {
-                                                       $entry->parentNode->insertBefore($cnode);
-                                               }
-                                       }
-
-                                       $entry->parentNode->removeChild($entry);
-
-                               }
-                       }
-               }
-
-               $node = $doc->getElementsByTagName('body')->item(0);
-
-               // http://tt-rss.org/forum/viewtopic.php?f=1&t=970
-               if ($node)
-                       return $doc->saveXML($node);
-               else
-                       return $html;
-       }
-
        function filter_to_sql($filter, $owner_uid) {
                $query = array();
 
                                        $qpart .= " AND $cat_qpart";
                                }
 
+                               $qpart .= " AND feed_id IS NOT NULL";
+
                                array_push($query, "($qpart)");
 
                        }
                curl_setopt($curl, CURLOPT_TIMEOUT, 60);
                curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
 
+               if ((OPENSSL_VERSION_NUMBER >= 0x0090808f) && (OPENSSL_VERSION_NUMBER < 0x10000000)) {
+                       curl_setopt($curl, CURLOPT_SSLVERSION, 3);
+               }
+
                $html = curl_exec($curl);
 
                $status = curl_getinfo($curl);
                }
 
                function ngettext(msg1, msg2, n) {
-                       return (parseInt(n) > 1) ? msg2 : msg1;
+                       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);
+                       if(strpos($orig, "\000") !== FALSE) { // Plural forms
+                               $key = explode(chr(0), $orig);
+                               print T_js_decl($key[0], _ngettext($key[0], $key[1], 1)); // Singular
+                               print T_js_decl($key[1], _ngettext($key[0], $key[1], 2)); // Plural
+                       } else {
+                               $translation = __($orig);
+                               print T_js_decl($orig, $translation);
+                       }
                }
        }