diff --git a/check_setup.php b/check_setup.php
index 1b3db7b..4fb89e1 100644
--- a/check_setup.php
+++ b/check_setup.php
@@ -62,6 +62,11 @@ if (! is_writable(DATA_DIRECTORY)) {
die('The data directory must be writeable by your web server user');
}
+// Check if favicon directory is writeable
+if (! is_writable(FAVICON_DIRECTORY)) {
+ die('The favicon directory must be writeable by your web server user');
+}
+
// Include password_compat for PHP < 5.5
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
require __DIR__.'/lib/password.php';
diff --git a/common.php b/common.php
index 632a69c..6adca5c 100644
--- a/common.php
+++ b/common.php
@@ -15,6 +15,9 @@ defined('BASE_URL_DIRECTORY') or define('BASE_URL_DIRECTORY', dirname($_SERVER['
defined('ROOT_DIRECTORY') or define('ROOT_DIRECTORY', __DIR__);
defined('DATA_DIRECTORY') or define('DATA_DIRECTORY', ROOT_DIRECTORY.DIRECTORY_SEPARATOR.'data');
+defined('FAVICON_DIRECTORY') or define('FAVICON_DIRECTORY', DATA_DIRECTORY.DIRECTORY_SEPARATOR.'favicons');
+defined('FAVICON_PUBLIC_DIRECTORY') or define('FAVICON_PUBLIC_DIRECTORY', 'data'.DIRECTORY_SEPARATOR.'favicons');
+
defined('ENABLE_MULTIPLE_DB') or define('ENABLE_MULTIPLE_DB', true);
defined('DB_FILENAME') or define('DB_FILENAME', 'db.sqlite');
diff --git a/config.default.php b/config.default.php
index af2183e..fb5cf8b 100644
--- a/config.default.php
+++ b/config.default.php
@@ -9,6 +9,12 @@ define('HTTP_MAX_RESPONSE_SIZE', 2097152);
// DATA_DIRECTORY => default is data (writable directory)
define('DATA_DIRECTORY', __DIR__.'/data');
+// FAVICON_DIRECTORY => default is favicons (writable directory)
+define('FAVICON_DIRECTORY', DATA_DIRECTORY.DIRECTORY_SEPARATOR.'favicons');
+
+// FAVICON_PUBLIC_DIRECTORY => default is data/favicons/
+define('FAVICON_PUBLIC_DIRECTORY', 'data'.DIRECTORY_SEPARATOR.'favicons');
+
// DB_FILENAME => default value is db.sqlite (default database filename)
define('DB_FILENAME', 'db.sqlite');
diff --git a/data/favicons/.htaccess b/data/favicons/.htaccess
new file mode 100644
index 0000000..605d2f4
--- /dev/null
+++ b/data/favicons/.htaccess
@@ -0,0 +1 @@
+Allow from all
diff --git a/fever/index.php b/fever/index.php
index 3453a33..c68ca08 100644
--- a/fever/index.php
+++ b/fever/index.php
@@ -122,7 +122,8 @@ route('favicons', function() {
->table('favicons')
->columns(
'feed_id',
- 'icon'
+ 'file',
+ 'type'
)
->findAll();
@@ -130,7 +131,7 @@ route('favicons', function() {
foreach ($favicons as $favicon) {
$response['favicons'][] = array(
'id' => (int) $favicon['feed_id'],
- 'data' => $favicon['icon']
+ 'data' => 'data:'.$favicon['type'].';base64,'.base64_encode(file_get_contents(FAVICON_DIRECTORY.DIRECTORY_SEPARATOR.$favicon['file']))
);
}
}
diff --git a/lib/helpers.php b/lib/helpers.php
index 1b0e864..b6c3786 100644
--- a/lib/helpers.php
+++ b/lib/helpers.php
@@ -29,10 +29,30 @@ function parse_app_version($refnames, $commithash)
return $version;
}
+/*
+ * get Image extension from mime type
+ */
+function favicon_extension($type)
+{
+ $types = array(
+ 'image/png' => '.png',
+ 'image/gif' => '.gif',
+ 'image/x-icon' => '.ico',
+ 'image/jpeg' => '.jpg',
+ 'image/jpg' => '.jpg'
+ );
+
+ if (in_array($type, $types)) {
+ return $types[$type];
+ } else {
+ return '.ico';
+ }
+}
+
function favicon(array $favicons, $feed_id)
{
if (! empty($favicons[$feed_id])) {
- return '';
+ return '';
}
return '';
diff --git a/models/feed.php b/models/feed.php
index bdf5a4e..0e2dc6e 100644
--- a/models/feed.php
+++ b/models/feed.php
@@ -6,6 +6,7 @@ use UnexpectedValueException;
use Model\Config;
use Model\Item;
use Model\Group;
+use Helper;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
use PicoDb\Database;
@@ -19,17 +20,40 @@ use PicoFeed\Client\InvalidUrlException;
const LIMIT_ALL = -1;
// Store the favicon
-function store_favicon($feed_id, $link, $icon)
+function store_favicon($feed_id, $link, $type, $icon)
{
+ $file = $feed_id.Helper\favicon_extension($type);
+
+ if (file_put_contents(FAVICON_DIRECTORY.DIRECTORY_SEPARATOR.$file, $icon) === false) {
+ return false;
+ }
+
return Database::getInstance('db')
->table('favicons')
->save(array(
'feed_id' => $feed_id,
'link' => $link,
- 'icon' => $icon,
+ 'file' => $file,
+ 'type' => $type
));
}
+// Delete the favicon
+function delete_favicon($feed_id)
+{
+ foreach (get_favicons(array ($feed_id)) as $favicon) {
+ unlink(FAVICON_DIRECTORY.DIRECTORY_SEPARATOR.$favicon);
+ }
+}
+
+// Delete all the favicons
+function delete_all_favicons()
+{
+ foreach (get_all_favicons() as $favicon) {
+ unlink(FAVICON_DIRECTORY.DIRECTORY_SEPARATOR.$favicon);
+ }
+}
+
// Download favicon
function fetch_favicon($feed_id, $site_url, $icon_link)
{
@@ -37,10 +61,11 @@ function fetch_favicon($feed_id, $site_url, $icon_link)
$favicon = new Favicon;
$link = $favicon->find($site_url, $icon_link);
- $icon = $favicon->getDataUri();
+ $icon = $favicon->getContent();
+ $type = $favicon->getType();
if ($icon !== '') {
- store_favicon($feed_id, $link, $icon);
+ store_favicon($feed_id, $link, $type, $icon);
}
}
}
@@ -61,7 +86,7 @@ function get_favicons(array $feed_ids)
$db = Database::getInstance('db')
->hashtable('favicons')
->columnKey('feed_id')
- ->columnValue('icon');
+ ->columnValue('file');
// pass $feeds_ids as argument list to hashtable::get(), use ... operator with php 5.6+
return call_user_func_array(array($db, 'get'), $feed_ids);
@@ -88,7 +113,7 @@ function get_all_favicons()
return Database::getInstance('db')
->hashtable('favicons')
- ->getAll('feed_id', 'icon');
+ ->getAll('feed_id', 'file');
}
// Update feed information
@@ -409,6 +434,7 @@ function update_cache($feed_id, $last_modified, $etag)
// Remove one feed
function remove($feed_id)
{
+ delete_favicon($feed_id);
// Items are removed by a sql constraint
return Database::getInstance('db')->table('feeds')->eq('id', $feed_id)->remove();
}
@@ -416,6 +442,7 @@ function remove($feed_id)
// Remove all feeds
function remove_all()
{
+ delete_all_favicons();
return Database::getInstance('db')->table('feeds')->remove();
}
diff --git a/models/schema.php b/models/schema.php
index 605649c..42019c0 100644
--- a/models/schema.php
+++ b/models/schema.php
@@ -5,7 +5,22 @@ namespace Schema;
use PDO;
use Model\Config;
-const VERSION = 41;
+const VERSION = 42;
+
+function version_42(PDO $pdo)
+{
+ $pdo->exec('DROP TABLE favicons');
+
+ $pdo->exec(
+ 'CREATE TABLE favicons (
+ feed_id INTEGER UNIQUE,
+ link TEXT,
+ file TEXT,
+ type TEXT,
+ FOREIGN KEY(feed_id) REFERENCES feeds(id) ON DELETE CASCADE
+ )'
+ );
+}
function version_41(PDO $pdo)
{