]> git.wh0rd.org - tt-rss.git/commitdiff
add plugin to cache images in starred articles; pass article_id to
authorAndrew Dolgov <fox@madoka.volgo-balt.ru>
Fri, 2 Aug 2013 10:04:14 +0000 (14:04 +0400)
committerAndrew Dolgov <fox@madoka.volgo-balt.ru>
Fri, 2 Aug 2013 10:04:14 +0000 (14:04 +0400)
sanitize

classes/feeds.php
classes/handler/public.php
include/functions.php
plugins/cache_starred_images/init.php [new file with mode: 0644]

index 9aa75bbe8c460bba20481193efb7d0374b1364a7..3b765d6bdbfb3c720d8eaeb1d6c9f89e05c10dcc 100644 (file)
@@ -510,7 +510,7 @@ class Feeds extends Handler_Protected {
                                                $tags = false;
 
                                        $line["content"] = sanitize($line["content"],
-                                                       sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words);
+                                                       sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words, $line["id"]);
 
                                        foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) {
                                                $line = $p->hook_render_article_cdm($line);
index de0ab66f8b678e5bdfbd906e988638ed684121b1..9c0359507614b1a4cc049bf2ffb11c50e28d966b 100644 (file)
@@ -390,6 +390,11 @@ class Handler_Public extends Handler {
                }
        }
 
+       function updateTask() {
+
+               PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
+       }
+
        function globalUpdateFeeds() {
                RPC::updaterandomfeed_real($this->dbh);
 
index 48111e4095a3f97738c9431c51e70b7a2b59e491..56361472ee5f4cc9b280fc6a5fce02932c89d7bf 100644 (file)
 
        }
 
-       function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false, $highlight_words = 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 '';
                $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];
 
                        $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);
diff --git a/plugins/cache_starred_images/init.php b/plugins/cache_starred_images/init.php
new file mode 100644 (file)
index 0000000..2366a1e
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+class Cache_Starred_Images extends Plugin {
+
+       private $host;
+       private $cache_dir;
+
+       function about() {
+               return array(1.0,
+                       "Automatically cache images in Starred articles",
+                       "fox",
+                       true);
+       }
+
+       function init($host) {
+               $this->host = $host;
+
+               $this->cache_dir = CACHE_DIR . "/starred-images/";
+
+               if (!is_dir($this->cache_dir)) {
+                       mkdir($this->cache_dir);
+               }
+
+               if (is_dir($this->cache_dir)) {
+                       chmod($this->cache_dir, 0777);
+
+                       if (is_writable($this->cache_dir)) {
+                               $host->add_hook($host::HOOK_UPDATE_TASK, $this);
+                               $host->add_hook($host::HOOK_SANITIZE, $this);
+                       } else {
+                               user_error("Starred cache directory is not writable.", E_USER_WARNING);
+                       }
+
+               } else {
+                       user_error("Unable to create starred cache directory.", E_USER_WARNING);
+               }
+       }
+
+       function image() {
+               $hash = basename($_REQUEST["hash"]);
+
+               if ($hash) {
+
+                       $filename = $this->cache_dir . "/" . $hash . '.png';
+
+                       if (file_exists($filename)) {
+                               /* See if we can use X-Sendfile */
+                               $xsendfile = false;
+                               if (function_exists('apache_get_modules') &&
+                                   array_search('mod_xsendfile', apache_get_modules()))
+                                       $xsendfile = true;
+
+                               if ($xsendfile) {
+                                       header("X-Sendfile: $filename");
+                                       header("Content-type: application/octet-stream");
+                                       header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
+                               } else {
+                                       header("Content-type: image/png");
+                                       $stamp = gmdate("D, d M Y H:i:s", filemtime($filename)). " GMT";
+                                       header("Last-Modified: $stamp", true);
+                                       ob_clean();   // discard any data in the output buffer (if possible)
+                                       flush();      // flush headers (if possible)
+                                       readfile($filename);
+                               }
+                       } else {
+                               header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
+                               echo "File not found.";
+                       }
+               }
+       }
+
+       function hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes, $article_id) {
+               $xpath = new DOMXpath($doc);
+
+               if ($article_id) {
+                       $entries = $xpath->query('(//img[@src])');
+
+                       foreach ($entries as $entry) {
+                               if ($entry->hasAttribute('src')) {
+                                       $src = rewrite_relative_url($site_url, $entry->getAttribute('src'));
+
+                                       $local_filename = $this->cache_dir . $article_id . "-" . sha1($src) . ".png";
+
+                                       if (file_exists($local_filename)) {
+                                               $entry->setAttribute("src", get_self_url_prefix() .
+                                                       "/backend.php?op=pluginhandler&plugin=cache_starred_images&method=image&hash=" .
+                                                       $article_id . "-" . sha1($src));
+                                       }
+
+                               }
+                       }
+               }
+
+               return $doc;
+       }
+
+       function hook_update_task() {
+               header("Content-type: text/plain");
+
+               $result = db_query("SELECT content, ttrss_user_entries.owner_uid, link, site_url, ttrss_entries.id, plugin_data
+                       FROM ttrss_entries, ttrss_user_entries LEFT JOIN ttrss_feeds ON
+                               (ttrss_user_entries.feed_id = ttrss_feeds.id)
+                       WHERE ref_id = ttrss_entries.id AND
+                               marked = true AND
+                               UPPER(content) LIKE '%<IMG%' AND
+                               site_url != '' AND
+                               plugin_data NOT LIKE '%starred_cache_images%'
+                       ORDER BY ".sql_random_function()." LIMIT 100");
+
+
+               while ($line = db_fetch_assoc($result)) {
+                       if ($line["site_url"]) {
+                               $success = $this->cache_article_images($line["content"], $line["site_url"], $line["owner_uid"], $line["id"]);
+
+                               if ($success) {
+                                       $plugin_data = db_escape_string("starred_cache_images,${line['owner_uid']}:" . $line["plugin_data"]);
+
+                                       db_query("UPDATE ttrss_entries SET plugin_data = '$plugin_data' WHERE id = " . $line["id"]);
+                               }
+                       }
+               }
+       }
+
+       function cache_article_images($content, $site_url, $owner_uid, $article_id) {
+               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 . $content);
+               $xpath = new DOMXPath($doc);
+
+               $entries = $xpath->query('(//img[@src])');
+
+               $success = false;
+               $has_images = false;
+
+               foreach ($entries as $entry) {
+                       if ($entry->hasAttribute('src')) {
+                               $has_images = true;
+                               $src = rewrite_relative_url($site_url, $entry->getAttribute('src'));
+
+                               $local_filename = $this->cache_dir . $article_id . "-" . sha1($src) . ".png";
+
+                               //_debug("cache_images: downloading: $src to $local_filename");
+
+                               if (!file_exists($local_filename)) {
+                                       $file_content = fetch_file_contents($src);
+
+                                       if ($file_content && strlen($file_content) > 0) {
+                                               file_put_contents($local_filename, $file_content);
+                                               $success = true;
+                                       }
+                               } else {
+                                       $success = true;
+                               }
+                       }
+               }
+
+               return $success || !$has_images;
+       }
+
+       function api_version() {
+               return 2;
+       }
+}
+?>