From fd028c6114ff7d66cf717f9964ae0b9702df46de Mon Sep 17 00:00:00 2001 From: Josh Lefler Date: Tue, 21 Mar 2017 16:32:22 +0000 Subject: Minor changes to english word choice/grammar to improve user experience for english-speaking users. --- app/i18n/en/admin.php | 22 +++++++++++----------- app/i18n/en/conf.php | 20 ++++++++++---------- app/i18n/en/feedback.php | 10 +++++----- app/i18n/en/gen.php | 2 +- app/i18n/en/index.php | 2 +- app/i18n/en/sub.php | 8 ++++---- 6 files changed, 32 insertions(+), 32 deletions(-) (limited to 'app') diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index e94d9fa80..f9761952c 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -21,11 +21,11 @@ return array( 'ok' => 'Permissions on cache directory are good.', ), 'categories' => array( - 'nok' => 'Category table is bad configured.', + 'nok' => 'Category table is improperly configured.', 'ok' => 'Category table is ok.', ), 'connection' => array( - 'nok' => 'Connection to the database cannot being established.', + 'nok' => 'Connection to the database cannot be established.', 'ok' => 'Connection to the database is ok.', ), 'ctype' => array( @@ -46,7 +46,7 @@ return array( 'ok' => 'You have the required library to browse the DOM.', ), 'entries' => array( - 'nok' => 'Entry table is bad configured.', + 'nok' => 'Entry table is improperly configured.', 'ok' => 'Entry table is ok.', ), 'favicons' => array( @@ -54,7 +54,7 @@ return array( 'ok' => 'Permissions on favicons directory are good.', ), 'feeds' => array( - 'nok' => 'Feed table is bad configured.', + 'nok' => 'Feed table is improperly configured.', 'ok' => 'Feed table is ok.', ), 'fileinfo' => array( @@ -84,8 +84,8 @@ return array( 'ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', ), 'tables' => array( - 'nok' => 'There is one or more lacking tables in the database.', - 'ok' => 'Tables are existing in the database.', + 'nok' => 'There are one or more missing tables in the database.', + 'ok' => 'The appropriate tables exist in the database.', ), 'title' => 'Installation checking', 'tokens' => array( @@ -103,7 +103,7 @@ return array( ), 'extensions' => array( 'disabled' => 'Disabled', - 'empty_list' => 'There is no installed extension', + 'empty_list' => 'There are no installed extensions', 'enabled' => 'Enabled', 'no_configure_view' => 'This extension cannot be configured.', 'system' => array( @@ -138,7 +138,7 @@ return array( 'number_entries' => '%d articles', 'percent_of_total' => '%% of total', 'repartition' => 'Articles repartition', - 'status_favorites' => 'Favourites', + 'status_favorites' => 'Favorites', 'status_read' => 'Read', 'status_total' => 'Total', 'status_unread' => 'Unread', @@ -160,7 +160,7 @@ return array( '_' => 'Update system', 'apply' => 'Apply', 'check' => 'Check for new updates', - 'current_version' => 'Your current version of FreshRSS is the %s.', + 'current_version' => 'Your current version of FreshRSS is %s.', 'last' => 'Last verification: %s', 'none' => 'No update to apply', 'title' => 'Update system', @@ -169,8 +169,8 @@ return array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Create new user', 'language' => 'Language', - 'number' => 'There is %d account created yet', - 'numbers' => 'There are %d accounts created yet', + 'number' => 'There is %d account created', + 'numbers' => 'There are %d accounts created', 'password_form' => 'Password
(for the Web-form login method)', 'password_format' => 'At least 7 characters', 'title' => 'Manage users', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index b5ab73510..4c4a003c4 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -8,7 +8,7 @@ return array( 'help' => 'More options are available in the individual feed settings', 'keep_history_by_feed' => 'Minimum number of articles to keep by feed', 'optimize' => 'Optimise database', - 'optimize_help' => 'To do occasionally to reduce the size of the database', + 'optimize_help' => 'Do occasionally to reduce the size of the database', 'purge_now' => 'Purge now', 'title' => 'Archiving', 'ttl' => 'Do not automatically refresh more often than', @@ -47,7 +47,7 @@ return array( 'get_favorite' => 'Display favorite articles', 'get_feed' => 'Display "%s" feed', 'no_filter' => 'No filter', - 'none' => 'You haven’t created any user query yet.', + 'none' => 'You haven’t created any user queries yet.', 'number' => 'Query n°%d', 'order_asc' => 'Display oldest articles first', 'order_desc' => 'Display newest articles first', @@ -74,7 +74,7 @@ return array( '_' => 'Profile management', 'delete' => array( '_' => 'Account deletion', - 'warn' => 'Your account and all the related data will be deleted.', + 'warn' => 'Your account and all related data will be deleted.', ), 'password_api' => 'API password
(e.g., for mobile apps)', 'password_form' => 'Password
(for the Web-form login method)', @@ -85,13 +85,13 @@ return array( '_' => 'Reading', 'after_onread' => 'After “mark all as read”,', 'articles_per_page' => 'Number of articles per page', - 'auto_load_more' => 'Load next articles at the page bottom', + 'auto_load_more' => 'Load more articles at the page bottom', 'auto_remove_article' => 'Hide articles after reading', 'mark_updated_article_unread' => 'Mark updated articles as unread', 'confirm_enabled' => 'Display a confirmation dialog on “mark all as read” actions', 'display_articles_unfolded' => 'Show articles unfolded by default', 'display_categories_unfolded' => 'Show categories folded by default', - 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', + 'hide_read_feeds' => 'Hide categories & feeds with no unread articles (does not work with “Show all articles” configuration)', 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', 'jump_next' => 'jump to next unread sibling (feed or category)', 'number_divided_when_reader' => 'Divided by 2 in the reading view.', @@ -99,7 +99,7 @@ return array( 'article_open_on_website' => 'when article is opened on its original website', 'article_viewed' => 'when article is viewed', 'scroll' => 'while scrolling', - 'upon_reception' => 'upon reception of the article', + 'upon_reception' => 'upon receiving the article', 'when' => 'Mark article as read…', ), 'show' => array( @@ -110,7 +110,7 @@ return array( ), 'sort' => array( '_' => 'Sort order', - 'newer_first' => 'Newer first', + 'newer_first' => 'Newest first', 'older_first' => 'Oldest first', ), 'sticky_post' => 'Stick the article to the top when opened', @@ -142,7 +142,7 @@ return array( '_' => 'Shortcuts', 'article_action' => 'Article actions', 'auto_share' => 'Share', - 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', + 'auto_share_help' => 'If there is only one sharing mode, it is used. Other modes are accessible by their number.', 'close_dropdown' => 'Close menus', 'collapse_article' => 'Collapse', 'first_article' => 'Skip to the first article', @@ -152,7 +152,7 @@ return array( 'last_article' => 'Skip to the last article', 'load_more' => 'Load more articles', 'mark_read' => 'Mark as read', - 'mark_favorite' => 'Mark as favourite', + 'mark_favorite' => 'Mark as favorite', 'navigation' => 'Navigation', 'navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
With the "Alt" modifier, navigation shortcuts apply on categories.', 'next_article' => 'Skip to the next article', @@ -162,7 +162,7 @@ return array( 'shift_for_all_read' => '+ shift to mark all articles as read', 'title' => 'Shortcuts', 'user_filter' => 'Access user filters', - 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', + 'user_filter_help' => 'If there is only one user filter, it is used. Other filters are accessible by their number.', ), 'user' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index e7f6b9f85..67c5fe97d 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -2,7 +2,7 @@ return array( 'admin' => array( - 'optimization_complete' => 'Optimisation complete', + 'optimization_complete' => 'Optimization complete', ), 'access' => array( 'denied' => 'You don’t have permission to access this page', @@ -39,26 +39,26 @@ return array( 'ok' => '%s is now enabled', ), 'no_access' => 'You have no access on %s', - 'not_enabled' => '%s is not enabled yet', + 'not_enabled' => '%s is not enabled', 'not_found' => '%s does not exist', ), 'import_export' => array( 'export_no_zip_extension' => 'ZIP extension is not present on your server. Please try to export files one by one.', 'feeds_imported' => 'Your feeds have been imported and will now be updated', - 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', + 'feeds_imported_with_errors' => 'Your feeds have been imported, but some errors occurred', 'file_cannot_be_uploaded' => 'File cannot be uploaded!', 'no_zip_extension' => 'ZIP extension is not present on your server.', 'zip_error' => 'An error occured during ZIP import.', ), 'sub' => array( - 'actualize' => 'Actualise', + 'actualize' => 'Updating', 'category' => array( 'created' => 'Category %s has been created.', 'deleted' => 'Category has been deleted.', 'emptied' => 'Category has been emptied', 'error' => 'Category cannot be updated', 'name_exists' => 'Category name already exists.', - 'no_id' => 'You must precise the id of the category.', + 'no_id' => 'You must specify the id of the category.', 'no_name' => 'Category name cannot be empty.', 'not_delete_default' => 'You cannot delete the default category!', 'not_exist' => 'The category does not exist!', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 1ee5336bd..2a5842157 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -2,7 +2,7 @@ return array( 'action' => array( - 'actualize' => 'Actualize', + 'actualize' => 'Updating', 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'cancel' => 'Cancel', 'create' => 'Create', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index eb6413e3c..dd07d3ac8 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -21,7 +21,7 @@ return array( 'rss_of' => 'RSS feed of %s', 'title' => 'Your RSS feeds', 'title_global' => 'Global view', - 'title_fav' => 'Your favourites', + 'title_fav' => 'Your favorites', ), 'log' => array( '_' => 'Logs', diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index 789433ee6..6a20f5a69 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -10,10 +10,10 @@ return array( 'feed' => array( 'add' => 'Add a RSS feed', 'advanced' => 'Advanced', - 'archiving' => 'Archivage', + 'archiving' => 'Archiving', 'auth' => array( 'configuration' => 'Login', - 'help' => 'Connection allows to access HTTP protected RSS feeds', + 'help' => 'Allows access to HTTP protected RSS feeds', 'http' => 'HTTP Authentication', 'password' => 'HTTP password', 'username' => 'HTTP username', @@ -22,7 +22,7 @@ return array( 'css_path' => 'Articles CSS path on original website', 'description' => 'Description', 'empty' => 'This feed is empty. Please verify that it is still maintained.', - 'error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', + 'error' => 'This feed has encountered a problem. Please verify that it is always reachable then update it.', 'in_main_stream' => 'Show in main stream', 'informations' => 'Information', 'keep_history' => 'Minimum number of articles to keep', @@ -47,7 +47,7 @@ return array( 'file_to_import' => 'File to import
(OPML, JSON or ZIP)', 'file_to_import_no_zip' => 'File to import
(OPML or JSON)', 'import' => 'Import', - 'starred_list' => 'List of favourite articles', + 'starred_list' => 'List of favorite articles', 'title' => 'Import / export', ), 'menu' => array( -- cgit v1.2.3 From 22b41f3bfcbd5a54d59789c2cebfda6dc23b7dde Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 00:01:11 +0100 Subject: Candidate implementation of defered insertion https://github.com/FreshRSS/FreshRSS/issues/530 --- app/Controllers/feedController.php | 8 +- app/Controllers/importExportController.php | 1 + app/Models/EntryDAO.php | 115 +++++++++++++++++++++-------- app/Models/EntryDAOPGSQL.php | 26 +++++++ app/Models/EntryDAOSQLite.php | 39 +++++++--- app/Models/UserDAO.php | 10 ++- app/SQL/install.sql.mysql.php | 23 ++++++ app/SQL/install.sql.pgsql.php | 24 +++++- app/SQL/install.sql.sqlite.php | 24 ++++++ app/install.php | 36 +++------ p/scripts/main.js | 1 + 11 files changed, 234 insertions(+), 73 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index f71f26a4e..a2d9d5c35 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -226,7 +226,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - public static function actualizeFeed($feed_id, $feed_url, $force, $simplePiePush = null, $isNewFeed = false) { + public static function actualizeFeed($feed_id, $feed_url, $force, $simplePiePush = null, $isNewFeed = false, $noCommit = false) { @set_time_limit(300); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -434,6 +434,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { break; } } + if (!$noCommit) { + $entryDAO->commitNewEntries(); + } return array($updated_feeds, reset($feeds)); } @@ -452,8 +455,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = Minz_Request::param('id'); $url = Minz_Request::param('url'); $force = Minz_Request::param('force'); + $noCommit = Minz_Session::param('isLastFeed', 1) != 1; - list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force); + list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); if (Minz_Request::param('ajax')) { // Most of the time, ajax request is for only one feed. But since diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 6ae89defb..ededfe506 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -475,6 +475,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } $this->entryDAO->commit(); + $entryDAO->commitNewEntries(); return !$error; } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index afcde3d7f..decae9307 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -88,6 +88,38 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return false; } + protected function createEntryTempTable() { + $ok = false; + $hadTransaction = $this->bd->inTransaction(); + if ($hadTransaction) { + $this->bd->commit(); + } + try { + $db = FreshRSS_Context::$system_conf->db; + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); + Minz_Log::warning('SQL CREATE TABLE entrytmp...'); + if (defined('SQL_CREATE_TABLE_ENTRYTMP')) { + $sql = sprintf(SQL_CREATE_TABLE_ENTRYTMP, $this->prefix); + $stm = $this->bd->prepare($sql); + $ok = $stm && $stm->execute(); + } else { + global $SQL_CREATE_TABLE_ENTRYTMP; + $ok = !empty($SQL_CREATE_TABLE_ENTRYTMP); + foreach ($SQL_CREATE_TABLE_ENTRYTMP as $instruction) { + $sql = sprintf($instruction, $this->prefix); + $stm = $this->bd->prepare($sql); + $ok &= $stm && $stm->execute(); + } + } + } catch (Exception $e) { + Minz_Log::error('FreshRSS_EntryDAO::createEntryTempTable error: ' . $e->getMessage()); + } + if ($hadTransaction) { + $this->bd->beginTransaction(); + } + return $ok; + } + protected function autoUpdateDb($errorInfo) { if (isset($errorInfo[0])) { if ($errorInfo[0] === '42S22') { //ER_BAD_FIELD_ERROR @@ -97,6 +129,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $this->addColumn($column); } } + } elseif ($errorInfo[0] === '42S02' && stripos($errorInfo[2], 'entrytmp') !== false) { //ER_BAD_TABLE_ERROR + return $this->createEntryTempTable(); //v1.7 } } if (isset($errorInfo[1])) { @@ -110,8 +144,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { private $addEntryPrepared = null; public function addEntry($valuesTmp) { - if ($this->addEntryPrepared === null) { - $sql = 'INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, ' + if ($this->addEntryPrepared == null) { + $sql = 'INSERT INTO `' . $this->prefix . 'entrytmp` (id, guid, title, author, ' . ($this->isCompressed() ? 'content_bin' : 'content') . ', link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) ' . 'VALUES(:id, :guid, :title, :author, ' @@ -121,41 +155,43 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . ', :is_read, :is_favorite, :id_feed, :tags)'; $this->addEntryPrepared = $this->bd->prepare($sql); } - $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); - $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); - $valuesTmp['guid'] = safe_ascii($valuesTmp['guid']); - $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); - $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); - $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); - $valuesTmp['author'] = substr($valuesTmp['author'], 0, 255); - $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); - $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); - $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); - $valuesTmp['link'] = safe_ascii($valuesTmp['link']); - $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); - $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); - $valuesTmp['lastSeen'] = time(); - $this->addEntryPrepared->bindParam(':last_seen', $valuesTmp['lastSeen'], PDO::PARAM_INT); - $valuesTmp['is_read'] = $valuesTmp['is_read'] ? 1 : 0; - $this->addEntryPrepared->bindParam(':is_read', $valuesTmp['is_read'], PDO::PARAM_INT); - $valuesTmp['is_favorite'] = $valuesTmp['is_favorite'] ? 1 : 0; - $this->addEntryPrepared->bindParam(':is_favorite', $valuesTmp['is_favorite'], PDO::PARAM_INT); - $this->addEntryPrepared->bindParam(':id_feed', $valuesTmp['id_feed'], PDO::PARAM_INT); - $valuesTmp['tags'] = substr($valuesTmp['tags'], 0, 1023); - $this->addEntryPrepared->bindParam(':tags', $valuesTmp['tags']); - - if ($this->hasNativeHex()) { - $this->addEntryPrepared->bindParam(':hash', $valuesTmp['hash']); - } else { - $valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']); //hex2bin() is PHP5.4+ - $this->addEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']); + if ($this->addEntryPrepared) { + $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); + $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); + $valuesTmp['guid'] = safe_ascii($valuesTmp['guid']); + $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); + $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); + $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); + $valuesTmp['author'] = substr($valuesTmp['author'], 0, 255); + $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); + $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); + $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); + $valuesTmp['link'] = safe_ascii($valuesTmp['link']); + $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); + $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); + $valuesTmp['lastSeen'] = time(); + $this->addEntryPrepared->bindParam(':last_seen', $valuesTmp['lastSeen'], PDO::PARAM_INT); + $valuesTmp['is_read'] = $valuesTmp['is_read'] ? 1 : 0; + $this->addEntryPrepared->bindParam(':is_read', $valuesTmp['is_read'], PDO::PARAM_INT); + $valuesTmp['is_favorite'] = $valuesTmp['is_favorite'] ? 1 : 0; + $this->addEntryPrepared->bindParam(':is_favorite', $valuesTmp['is_favorite'], PDO::PARAM_INT); + $this->addEntryPrepared->bindParam(':id_feed', $valuesTmp['id_feed'], PDO::PARAM_INT); + $valuesTmp['tags'] = substr($valuesTmp['tags'], 0, 1023); + $this->addEntryPrepared->bindParam(':tags', $valuesTmp['tags']); + + if ($this->hasNativeHex()) { + $this->addEntryPrepared->bindParam(':hash', $valuesTmp['hash']); + } else { + $valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']); //hex2bin() is PHP5.4+ + $this->addEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']); + } } - if ($this->addEntryPrepared && $this->addEntryPrepared->execute()) { return $this->bd->lastInsertId(); } else { $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo(); if ($this->autoUpdateDb($info)) { + $this->addEntryPrepared = null; return $this->addEntry($valuesTmp); } elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -165,6 +201,23 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } + public function commitNewEntries() { + $sql = 'SET @rank=SELECT MAX(id) - COUNT(*) FROM `' . $this->prefix . 'entrytmp`; ' . //MySQL-specific + 'INSERT IGNORE INTO `' . $this->prefix . 'entry` (id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) ' . + 'SELECT @rank:=@rank+1 AS id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags FROM `' . $this->prefix . 'entrytmp` ORDER BY date; ' . + 'DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= @rank;'; + $stm = $this->bd->prepare($sql); + $hadTransaction = $this->bd->inTransaction(); + if (!$hadTransaction) { + $this->bd->beginTransaction(); + } + $result = $stm ? $stm->execute() : false; + if (!$hadTransaction) { + $this->bd->commit(); + } + return $result; + } + private $updateEntryPrepared = null; public function updateEntry($valuesTmp) { diff --git a/app/Models/EntryDAOPGSQL.php b/app/Models/EntryDAOPGSQL.php index b96a62ebc..b25993c47 100644 --- a/app/Models/EntryDAOPGSQL.php +++ b/app/Models/EntryDAOPGSQL.php @@ -11,6 +11,11 @@ class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite { } protected function autoUpdateDb($errorInfo) { + if (isset($errorInfo[0])) { + if ($errorInfo[0] === '42P01' && stripos($errorInfo[2], 'entrytmp') !== false) { //undefined_table + return $this->createEntryTempTable(); + } + } return false; } @@ -18,6 +23,27 @@ class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite { return false; } + public function commitNewEntries() { + $sql = 'DO $$ +DECLARE +maxrank bigint := (SELECT MAX(id) FROM `' . $this->prefix . 'entrytmp`); +rank bigint := (SELECT maxrank - COUNT(*) FROM `' . $this->prefix . 'entrytmp`); +BEGIN + INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) + (SELECT rank + row_number() OVER(ORDER BY date) AS id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags FROM `' . $this->prefix . 'entrytmp` ORDER BY date); + DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= maxrank; +END $$;'; + $hadTransaction = $this->bd->inTransaction(); + if (!$hadTransaction) { + $this->bd->beginTransaction(); + } + $result = $this->bd->exec($sql) !== false; + if (!$hadTransaction) { + $this->bd->commit(); + } + return $result; + } + public function size($all = true) { $db = FreshRSS_Context::$system_conf->db; $sql = 'SELECT pg_size_pretty(pg_database_size(?))'; diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 34e854608..ad7bcd865 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -7,21 +7,42 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } protected function autoUpdateDb($errorInfo) { - if (empty($errorInfo[0]) || $errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR - //autoAddColumn - if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entry'")) { - $showCreate = $tableInfo->fetchColumn(); - Minz_Log::debug('FreshRSS_EntryDAOSQLite::autoUpdateDb: ' . $showCreate); - foreach (array('lastSeen', 'hash') as $column) { - if (stripos($showCreate, $column) === false) { - return $this->addColumn($column); - } + Minz_Log::error('FreshRSS_EntryDAO::autoUpdateDb error: ' . print_r($errorInfo, true)); + if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entrytmp'")) { + $showCreate = $tableInfo->fetchColumn(); + if (stripos($showCreate, 'entrytmp') === false) { + return $this->createEntryTempTable(); + } + } + if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entry'")) { + $showCreate = $tableInfo->fetchColumn(); + foreach (array('lastSeen', 'hash') as $column) { + if (stripos($showCreate, $column) === false) { + return $this->addColumn($column); } } } return false; } + public function commitNewEntries() { + $sql = ' +CREATE TEMP TABLE `tmp` AS SELECT id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags FROM `' . $this->prefix . 'entrytmp` ORDER BY date; +INSERT OR IGNORE INTO `' . $this->prefix . 'entry` (id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) + SELECT rowid + (SELECT MAX(id) - COUNT(*) FROM `tmp`) AS id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags FROM `tmp` ORDER BY date; +DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= (SELECT MAX(id) FROM `tmp`); +DROP TABLE `tmp`;'; + $hadTransaction = $this->bd->inTransaction(); + if (!$hadTransaction) { + $this->bd->beginTransaction(); + } + $result = $this->bd->exec($sql) !== false; + if (!$hadTransaction) { + $this->bd->commit(); + } + return $result; + } + protected function sqlConcat($s1, $s2) { return $s1 . '||' . $s2; } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index a60caf395..310c7c096 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -14,21 +14,23 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $ok = false; $bd_prefix_user = $db['prefix'] . $username . '_'; if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $bd_prefix_user, _t('gen.short.default_category')); + $sql = sprintf(SQL_CREATE_TABLES . SQL_CREATE_TABLE_ENTRYTMP, $bd_prefix_user, _t('gen.short.default_category')); $stm = $userPDO->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { //E.g. SQLite global $SQL_CREATE_TABLES; + global $SQL_CREATE_TABLE_ENTRYTMP; if (is_array($SQL_CREATE_TABLES)) { - $ok = true; - foreach ($SQL_CREATE_TABLES as $instruction) { + $instructions = array_merge($SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP); + $ok = !empty($instructions); + foreach ($instructions as $instruction) { $sql = sprintf($instruction, $bd_prefix_user, _t('gen.short.default_category')); $stm = $userPDO->bd->prepare($sql); $ok &= ($stm && $stm->execute()); } } } - if ($insertDefaultFeeds) { + if ($ok && $insertDefaultFeeds) { if (defined('SQL_INSERT_FEEDS')) { //E.g. MySQL $sql = sprintf(SQL_INSERT_FEEDS, $bd_prefix_user); $stm = $userPDO->bd->prepare($sql); diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index a454829d5..ceca07f93 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -61,6 +61,29 @@ ENGINE = INNODB; INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); '); +define('SQL_CREATE_TABLE_ENTRYTMP', ' +CREATE TABLE IF NOT EXISTS `%1$sentrytmp` ( -- v1.7 + `id` bigint NOT NULL, + `guid` varchar(760) CHARACTER SET latin1 NOT NULL, + `title` varchar(255) NOT NULL, + `author` varchar(255), + `content_bin` blob, + `link` varchar(1023) CHARACTER SET latin1 NOT NULL, + `date` int(11), + `lastSeen` INT(11) DEFAULT 0, + `hash` BINARY(16), + `is_read` boolean NOT NULL DEFAULT 0, + `is_favorite` boolean NOT NULL DEFAULT 0, + `id_feed` SMALLINT, + `tags` varchar(1023), + PRIMARY KEY (`id`), + FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE KEY (`id_feed`,`guid`), + INDEX (`date`), +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci +ENGINE = INNODB; +'); + define('SQL_INSERT_FEEDS', ' INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400); INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS @ GitHub", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400); diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 9f4240b98..1a666cb8a 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -32,7 +32,7 @@ $SQL_CREATE_TABLES = array( 'CREATE TABLE IF NOT EXISTS "%1$sentry" ( "id" BIGINT NOT NULL PRIMARY KEY, - "guid" VARCHAR(760) UNIQUE NOT NULL, + "guid" VARCHAR(760) NOT NULL, "title" VARCHAR(255) NOT NULL, "author" VARCHAR(255), "content" TEXT, @@ -54,6 +54,28 @@ $SQL_CREATE_TABLES = array( 'INSERT INTO "%1$scategory" (name) SELECT \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1);', ); +global $SQL_CREATE_TABLE_ENTRYTMP; +$SQL_CREATE_TABLE_ENTRYTMP = array( +'CREATE TABLE IF NOT EXISTS "%1$sentrytmp" ( -- v1.7 + "id" BIGINT NOT NULL PRIMARY KEY, + "guid" VARCHAR(760) NOT NULL, + "title" VARCHAR(255) NOT NULL, + "author" VARCHAR(255), + "content" TEXT, + "link" VARCHAR(1023) NOT NULL, + "date" INT, + "lastSeen" INT DEFAULT 0, + "hash" BYTEA, + "is_read" SMALLINT NOT NULL DEFAULT 0, + "is_favorite" SMALLINT NOT NULL DEFAULT 0, + "id_feed" SMALLINT, + "tags" VARCHAR(1023), + FOREIGN KEY ("id_feed") REFERENCES "%1$sfeed" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE ("id_feed","guid") +);', +'CREATE INDEX %1$sentrytmp_date_index ON "%1$sentrytmp" ("date");', +); + global $SQL_INSERT_FEEDS; $SQL_INSERT_FEEDS = array( 'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl) SELECT \'http://freshrss.org/feeds/all.atom.xml\', 1, \'FreshRSS.org\', \'http://freshrss.org/\', \'FreshRSS, a free, self-hostable aggregator…\', 86400 WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'http://freshrss.org/feeds/all.atom.xml\');', diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index 68d93ba92..ad7d525fd 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -57,6 +57,30 @@ $SQL_CREATE_TABLES = array( 'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");', ); +global $SQL_CREATE_TABLE_ENTRYTMP; +$SQL_CREATE_TABLE_ENTRYTMP = array( +'CREATE TABLE IF NOT EXISTS `entrytmp` ( -- v1.7 + `id` bigint NOT NULL, + `guid` varchar(760) NOT NULL, + `title` varchar(255) NOT NULL, + `author` varchar(255), + `content` text, + `link` varchar(1023) NOT NULL, + `date` int(11), + `lastSeen` INT(11) DEFAULT 0, + `hash` BINARY(16), + `is_read` boolean NOT NULL DEFAULT 0, + `is_favorite` boolean NOT NULL DEFAULT 0, + `id_feed` SMALLINT, + `tags` varchar(1023), + PRIMARY KEY (`id`), + FOREIGN KEY (`id_feed`) REFERENCES `feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE (`id_feed`,`guid`) +);', + +'CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);', +); + global $SQL_INSERT_FEEDS; $SQL_INSERT_FEEDS = array( 'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);', diff --git a/app/install.php b/app/install.php index 9a88e0f37..17037c384 100644 --- a/app/install.php +++ b/app/install.php @@ -342,35 +342,19 @@ function checkDbUser(&$dbOptions) { $driver_options = $dbOptions['options']; try { $c = new PDO($str, $dbOptions['user'], $dbOptions['password'], $driver_options); - if (defined('SQL_CREATE_TABLES')) { - $sql = sprintf(SQL_CREATE_TABLES, $dbOptions['prefix_user'], _t('gen.short.default_category')); - $stm = $c->prepare($sql); - $ok = $stm->execute(); - } else { - global $SQL_CREATE_TABLES; - if (is_array($SQL_CREATE_TABLES)) { - $ok = true; - foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, $dbOptions['prefix_user'], _t('gen.short.default_category')); - $stm = $c->prepare($sql); - $ok &= $stm->execute(); - } - } - } - - if (defined('SQL_INSERT_FEEDS')) { - $sql = sprintf(SQL_INSERT_FEEDS, $dbOptions['prefix_user']); + $sql = sprintf(SQL_CREATE_TABLES . SQL_CREATE_TABLE_ENTRYTMP . SQL_INSERT_FEEDS, + $dbOptions['prefix_user'], _t('gen.short.default_category')); $stm = $c->prepare($sql); - $ok &= $stm->execute(); + $ok = $stm && $stm->execute(); } else { - global $SQL_INSERT_FEEDS; - if (is_array($SQL_INSERT_FEEDS)) { - foreach ($SQL_INSERT_FEEDS as $instruction) { - $sql = sprintf($instruction, $dbOptions['prefix_user']); - $stm = $c->prepare($sql); - $ok &= $stm->execute(); - } + global $SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_INSERT_FEEDS; + $instructions = array_merge($SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_INSERT_FEEDS); + $ok = !empty($instructions); + foreach ($instructions as $instruction) { + $sql = sprintf($instruction, $dbOptions['prefix_user'], _t('gen.short.default_category')); + $stm = $c->prepare($sql); + $ok &= $stm && $stm->execute(); } } } catch (PDOException $e) { diff --git a/p/scripts/main.js b/p/scripts/main.js index 5dbb95c91..c2f60bf7f 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -809,6 +809,7 @@ function updateFeed(feeds, feeds_count) { url: feed.url, data : { _csrf: context.csrf, + isLastFeed: feeds.length <= 0 ? 1 : 0, }, }).always(function (data) { feed_processed++; -- cgit v1.2.3 From a20fd9db9f0ed0e27c65671bb10402ced10587b1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 01:41:08 +0100 Subject: Defered insertion MySQL bug The update of cached values remains to be optimized --- app/Controllers/feedController.php | 1 + app/Models/EntryDAO.php | 6 +++--- app/SQL/install.sql.mysql.php | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index a2d9d5c35..b565d0439 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -436,6 +436,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } if (!$noCommit) { $entryDAO->commitNewEntries(); + $feedDAO->updateCachedValues(); //TODO: Optimize } return array($updated_feeds, reset($feeds)); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index decae9307..9d11cec6a 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -121,6 +121,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } protected function autoUpdateDb($errorInfo) { + Minz_Log::warning('FreshRSS_EntryDAO::autoUpdateDb: ' . print_r($errorInfo, true)); if (isset($errorInfo[0])) { if ($errorInfo[0] === '42S22') { //ER_BAD_FIELD_ERROR //autoAddColumn @@ -202,16 +203,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } public function commitNewEntries() { - $sql = 'SET @rank=SELECT MAX(id) - COUNT(*) FROM `' . $this->prefix . 'entrytmp`; ' . //MySQL-specific + $sql = 'SET @rank=(SELECT MAX(id) - COUNT(*) FROM `' . $this->prefix . 'entrytmp`); ' . //MySQL-specific 'INSERT IGNORE INTO `' . $this->prefix . 'entry` (id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) ' . 'SELECT @rank:=@rank+1 AS id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags FROM `' . $this->prefix . 'entrytmp` ORDER BY date; ' . 'DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= @rank;'; - $stm = $this->bd->prepare($sql); $hadTransaction = $this->bd->inTransaction(); if (!$hadTransaction) { $this->bd->beginTransaction(); } - $result = $stm ? $stm->execute() : false; + $result = $this->bd->exec($sql) !== false; if (!$hadTransaction) { $this->bd->commit(); } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index ceca07f93..f42e08ad3 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -79,7 +79,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentrytmp` ( -- v1.7 PRIMARY KEY (`id`), FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE KEY (`id_feed`,`guid`), - INDEX (`date`), + INDEX (`date`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; '); -- cgit v1.2.3 From e956aee53d561fbdc11a78a50ad7cc041108e5b5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 14:07:06 +0200 Subject: More defered insertion. New SQL index New index entry_feed_read_index TODO: Auto add this index to existing version --- app/Controllers/feedController.php | 8 +++++- app/Models/EntryDAO.php | 1 - app/Models/Factory.php | 9 +----- app/Models/FeedDAO.php | 56 ++++++++++++++++++-------------------- app/Models/FeedDAOSQLite.php | 19 ------------- app/SQL/install.sql.mysql.php | 1 + app/SQL/install.sql.pgsql.php | 1 + app/SQL/install.sql.sqlite.php | 1 + 8 files changed, 37 insertions(+), 59 deletions(-) delete mode 100644 app/Models/FeedDAOSQLite.php (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index b565d0439..bfc8b2045 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -393,7 +393,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - $feedDAO->updateLastUpdate($feed->id(), false, $entryDAO->inTransaction(), $mtime); + $feedDAO->updateLastUpdate($feed->id(), false, $mtime); if ($entryDAO->inTransaction()) { $entryDAO->commit(); } @@ -435,8 +435,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } if (!$noCommit) { + if (!$entryDAO->inTransaction()) { + $entryDAO->beginTransaction(); + } $entryDAO->commitNewEntries(); $feedDAO->updateCachedValues(); //TODO: Optimize + if ($entryDAO->inTransaction()) { + $entryDAO->commit(); + } } return array($updated_feeds, reset($feeds)); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 9d11cec6a..39c00f01c 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -121,7 +121,6 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } protected function autoUpdateDb($errorInfo) { - Minz_Log::warning('FreshRSS_EntryDAO::autoUpdateDb: ' . print_r($errorInfo, true)); if (isset($errorInfo[0])) { if ($errorInfo[0] === '42S22') { //ER_BAD_FIELD_ERROR //autoAddColumn diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 6502c38b7..dfccc883e 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -3,14 +3,7 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { - $conf = Minz_Configuration::get('system'); - switch ($conf->db['type']) { - case 'sqlite': - case 'pgsql': - return new FreshRSS_FeedDAOSQLite($username); - default: - return new FreshRSS_FeedDAO($username); - } + return new FreshRSS_FeedDAO($username); } public static function createEntryDao($username = null) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 0168aebd9..d278122e3 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -92,29 +92,15 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function updateLastUpdate($id, $inError = false, $updateCache = true, $mtime = 0) { - if ($updateCache) { - $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE - . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' - . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0),' - . '`lastUpdate`=?, error=? ' - . 'WHERE id=?'; - } else { - $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET `lastUpdate`=?, error=? ' - . 'WHERE id=?'; - } - - if ($mtime <= 0) { - $mtime = time(); - } - + public function updateLastUpdate($id, $inError = false, $mtime = 0) { //See also updateCachedValue() + $sql = 'UPDATE `' . $this->prefix . 'feed` ' + . 'SET `lastUpdate`=?, error=? ' + . 'WHERE id=?'; $values = array( - $mtime, + $mtime <= 0 ? time() : $mtime, $inError ? 1 : 0, $id, ); - $stm = $this->bd->prepare($sql); if ($stm && $stm->execute($values)) { @@ -294,18 +280,28 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $res[0]['count']; } - public function updateCachedValues() { //For one single feed, call updateLastUpdate($id) - $sql = 'UPDATE `' . $this->prefix . 'feed` f ' - . 'INNER JOIN (' - . 'SELECT e.id_feed, ' - . 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, ' - . 'COUNT(e.id) AS nbEntries ' - . 'FROM `' . $this->prefix . 'entry` e ' - . 'GROUP BY e.id_feed' - . ') x ON x.id_feed=f.id ' - . 'SET f.`cache_nbEntries`=x.nbEntries, f.`cache_nbUnreads`=x.nbUnreads'; + public function updateCachedValue($id) { //For multiple feeds, call updateCachedValues() + $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE + . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' + . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0) ' + . 'WHERE id=?'; + $values = array($id); $stm = $this->bd->prepare($sql); + if ($stm && $stm->execute($values)) { + return $stm->rowCount(); + } else { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL error updateCachedValue: ' . $info[2]); + return false; + } + } + + public function updateCachedValues() { //For one single feed, call updateCachedValue($id) + $sql = 'UPDATE `' . $this->prefix . 'feed` ' + . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' + . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0)'; + $stm = $this->bd->prepare($sql); if ($stm && $stm->execute()) { return $stm->rowCount(); } else { @@ -343,7 +339,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $affected; } - public function cleanOldEntries($id, $date_min, $keep = 15) { //Remember to call updateLastUpdate($id) or updateCachedValues() just after + public function cleanOldEntries($id, $date_min, $keep = 15) { //Remember to call updateCachedValue($id) or updateCachedValues() just after $sql = 'DELETE FROM `' . $this->prefix . 'entry` ' . 'WHERE id_feed=:id_feed AND id<=:id_max ' . 'AND is_favorite=0 ' //Do not remove favourites diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php deleted file mode 100644 index 440ae74da..000000000 --- a/app/Models/FeedDAOSQLite.php +++ /dev/null @@ -1,19 +0,0 @@ -prefix . 'feed` ' - . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' - . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0)'; - $stm = $this->bd->prepare($sql); - if ($stm && $stm->execute()) { - return $stm->rowCount(); - } else { - $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::error('SQL error updateCachedValues: ' . $info[2]); - return false; - } - } - -} diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index f42e08ad3..3ad68173f 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -55,6 +55,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` ( INDEX (`is_favorite`), -- v0.7 INDEX (`is_read`), -- v0.7 INDEX `entry_lastSeen_index` (`lastSeen`) -- v1.1.1 + INDEX `entry_feed_read_index` (`id_feed`,`is_read`) -- v1.7 //TODO: Auto add this index to existing version ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 1a666cb8a..ca4dfa925 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -50,6 +50,7 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX %1$sis_favorite_index ON "%1$sentry" ("is_favorite");', 'CREATE INDEX %1$sis_read_index ON "%1$sentry" ("is_read");', 'CREATE INDEX %1$sentry_lastSeen_index ON "%1$sentry" ("lastSeen");', +'CREATE INDEX %1$sentry_feed_read_index ON "%1$sentry" ("id_feed","is_read");', //v1.7 //TODO: Auto add this index to existing version 'INSERT INTO "%1$scategory" (name) SELECT \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1);', ); diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index ad7d525fd..dcb7a351a 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -53,6 +53,7 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `entry`(`is_favorite`);', 'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `entry`(`is_read`);', 'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`);', //v1.1.1 +'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 //TODO: Auto add this index to existing version 'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");', ); -- cgit v1.2.3 From cc235c6af36e4cbfcdced1ee323559a32ca65114 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 15:02:35 +0200 Subject: SimplePie light manual update --- app/Models/EntryDAO.php | 2 +- lib/SimplePie/SimplePie.php | 86 ++++++----- lib/SimplePie/SimplePie/Author.php | 5 +- lib/SimplePie/SimplePie/Cache.php | 11 +- lib/SimplePie/SimplePie/Cache/Base.php | 5 +- lib/SimplePie/SimplePie/Cache/DB.php | 5 +- lib/SimplePie/SimplePie/Cache/File.php | 5 +- lib/SimplePie/SimplePie/Cache/Memcache.php | 5 +- lib/SimplePie/SimplePie/Cache/Memcached.php | 166 +++++++++++++++++++++ lib/SimplePie/SimplePie/Cache/MySQL.php | 23 ++- lib/SimplePie/SimplePie/Cache/Redis.php | 166 +++++++++++++++++++++ lib/SimplePie/SimplePie/Caption.php | 5 +- lib/SimplePie/SimplePie/Category.php | 5 +- lib/SimplePie/SimplePie/Content/Type/Sniffer.php | 5 +- lib/SimplePie/SimplePie/Copyright.php | 5 +- lib/SimplePie/SimplePie/Core.php | 5 +- lib/SimplePie/SimplePie/Credit.php | 5 +- lib/SimplePie/SimplePie/Decode/HTML/Entities.php | 5 +- lib/SimplePie/SimplePie/Enclosure.php | 7 +- lib/SimplePie/SimplePie/Exception.php | 5 +- lib/SimplePie/SimplePie/File.php | 16 +- lib/SimplePie/SimplePie/HTTP/Parser.php | 5 +- lib/SimplePie/SimplePie/IRI.php | 67 ++++++--- lib/SimplePie/SimplePie/Item.php | 37 ++--- lib/SimplePie/SimplePie/Locator.php | 60 +++++++- lib/SimplePie/SimplePie/Misc.php | 10 +- lib/SimplePie/SimplePie/Net/IPv6.php | 5 +- lib/SimplePie/SimplePie/Parse/Date.php | 11 +- lib/SimplePie/SimplePie/Parser.php | 5 +- lib/SimplePie/SimplePie/Rating.php | 5 +- lib/SimplePie/SimplePie/Registry.php | 5 +- lib/SimplePie/SimplePie/Restriction.php | 5 +- lib/SimplePie/SimplePie/Sanitize.php | 6 +- lib/SimplePie/SimplePie/Source.php | 5 +- lib/SimplePie/SimplePie/XML/Declaration/Parser.php | 5 +- lib/SimplePie/SimplePie/gzdecode.php | 5 +- 36 files changed, 587 insertions(+), 191 deletions(-) create mode 100644 lib/SimplePie/SimplePie/Cache/Memcached.php create mode 100644 lib/SimplePie/SimplePie/Cache/Redis.php (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index afcde3d7f..0167695ca 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -157,7 +157,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo(); if ($this->autoUpdateDb($info)) { return $this->addEntry($valuesTmp); - } elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries + } elseif ((int)((int)$info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); } diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 0f2fdbb87..7240fdf66 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -34,7 +34,7 @@ * * @package SimplePie * @version 1.4-dev-FreshRSS - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -614,6 +614,12 @@ class SimplePie */ public $item_limit = 0; + /** + * @var bool Stores if last-modified and/or etag headers were sent with the + * request when checking a feed. + */ + public $check_modified = false; + /** * @var array Stores the default attributes to be stripped by strip_attributes(). * @see SimplePie::strip_attributes() @@ -626,7 +632,7 @@ class SimplePie * @see SimplePie::add_attributes() * @access private */ - public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); //FreshRSS + public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); /** * @var array Stores the default tags to be stripped by strip_htmltags(). @@ -657,9 +663,9 @@ class SimplePie */ public function __construct() { - if (version_compare(PHP_VERSION, '5.2', '<')) + if (version_compare(PHP_VERSION, '5.3', '<')) { - trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.'); + trigger_error('Please upgrade to PHP 5.3 or newer.'); die(); } @@ -814,7 +820,7 @@ class SimplePie { $this->timeout = (int) $timeout; } - + /** * Set custom curl options * @@ -1169,7 +1175,7 @@ class SimplePie $this->sanitize->strip_attributes($attribs); } - public function add_attributes($attribs = '') //FreshRSS + public function add_attributes($attribs = '') { if ($attribs === '') { @@ -1191,11 +1197,11 @@ class SimplePie * * Allows you to override SimplePie's output to match that of your webpage. * This is useful for times when your webpages are not being served as - * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and + * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and * is similar to {@see set_input_encoding()}. * * It should be noted, however, that not all character encodings can support - * all characters. If your page is being served as ISO-8859-1 and you try + * all characters. If your page is being served as ISO-8859-1 and you try * to display a Japanese feed, you'll likely see garbled characters. * Because of this, it is highly recommended to ensure that your webpages * are served as UTF-8. @@ -1293,7 +1299,7 @@ class SimplePie /** * Initialize the feed object * - * This is what makes everything happen. Period. This is where all of the + * This is what makes everything happen. Period. This is where all of the * configuration options get processed, feeds are fetched, cached, and * parsed, and all of that other good stuff. * @@ -1361,6 +1367,7 @@ class SimplePie $this->error = null; $this->data = array(); + $this->check_modified = false; $this->multifeed_objects = array(); $cache = false; @@ -1380,6 +1387,7 @@ class SimplePie return $this->data['mtime']; } elseif ($fetched === false) { + $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); return false; } @@ -1486,11 +1494,19 @@ class SimplePie if (isset($parser)) { // We have an error, just set SimplePie_Misc::error to it and quit - $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d, encoding %s, URL: %s', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column(), $encoding, $this->feed_url); + $this->error = $this->feed_url; + $this->error .= sprintf(' is invalid XML, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column()); } else { - $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.'; + $this->error = 'The data could not be converted to UTF-8.'; + if (!extension_loaded('mbstring') && !extension_loaded('iconv')) { + $this->error .= ' You MUST have either the iconv or mbstring extension installed.'; + } elseif (!extension_loaded('mbstring')) { + $this->error .= ' Try installing the mbstring extension.'; + } elseif (!extension_loaded('iconv')) { + $this->error .= ' Try installing the iconv extension.'; + } } $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); @@ -1575,6 +1591,7 @@ class SimplePie } else { + $this->check_modified = false; $cache->touch(); $this->error = $file->error; return !empty($this->data); @@ -1669,7 +1686,7 @@ class SimplePie $locate = null; } - $file->body = trim($file->body); + $file->body = trim($file->body); //FreshRSS $this->raw_data = $file->body; $this->permanent_url = $file->permanent_url; $headers = $file->headers; @@ -1870,7 +1887,7 @@ class SimplePie * @todo Support * @todo Also, |atom:link|@rel=self * @param bool $permanent Permanent mode to return only the original URL or the first redirection - * iff it is a 301 redirection + * iff it is a 301 redirection * @return string|null */ public function subscribe_url($permanent = false) @@ -2169,7 +2186,7 @@ class SimplePie * Get a category for the feed * * @since Unknown - * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 + * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 * @return SimplePie_Category|null */ public function get_category($key = 0) @@ -2254,7 +2271,7 @@ class SimplePie * Get an author for the feed * * @since 1.1 - * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 + * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 * @return SimplePie_Author|null */ public function get_author($key = 0) @@ -2352,7 +2369,7 @@ class SimplePie * Get a contributor for the feed * * @since 1.1 - * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 + * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 * @return SimplePie_Author|null */ public function get_contributor($key = 0) @@ -2438,7 +2455,7 @@ class SimplePie * Get a single link for the feed * * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8) - * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 + * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 * @param string $rel The relationship of the link to return * @return string|null Link URL */ @@ -2949,7 +2966,7 @@ class SimplePie * * @see get_item_quantity() * @since Beta 2 - * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1 + * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1 * @return SimplePie_Item|null */ public function get_item($key = 0) @@ -2976,7 +2993,7 @@ class SimplePie * @since Beta 2 * @param int $start Index to start at * @param int $end Number of items to return. 0 for all items after `$start` - * @return array|null List of {@see SimplePie_Item} objects + * @return SimplePie_Item[]|null List of {@see SimplePie_Item} objects */ public function get_items($start = 0, $end = 0) { @@ -3147,7 +3164,19 @@ class SimplePie */ public static function sort_items($a, $b) { - return $a->get_date('U') <= $b->get_date('U'); + $a_date = $a->get_date('U'); + $b_date = $b->get_date('U'); + if ($a_date && $b_date) { + return $a_date > $b_date ? -1 : 1; + } + // Sort items without dates to the top. + if ($a_date) { + return 1; + } + if ($b_date) { + return -1; + } + return 0; } /** @@ -3180,20 +3209,7 @@ class SimplePie } } - $do_sort = true; - foreach ($items as $item) - { - if (!$item->get_date('U')) - { - $do_sort = false; - break; - } - } - $item = null; - if ($do_sort) - { - usort($items, array(get_class($urls[0]), 'sort_items')); - } + usort($items, array(get_class($urls[0]), 'sort_items')); if ($end === 0) { diff --git a/lib/SimplePie/SimplePie/Author.php b/lib/SimplePie/SimplePie/Author.php index 19563c5cc..e6768ff29 100644 --- a/lib/SimplePie/SimplePie/Author.php +++ b/lib/SimplePie/SimplePie/Author.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Cache.php b/lib/SimplePie/SimplePie/Cache.php index 86b618693..d98cc6511 100644 --- a/lib/SimplePie/SimplePie/Cache.php +++ b/lib/SimplePie/SimplePie/Cache.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -62,8 +61,10 @@ class SimplePie_Cache * @var array */ protected static $handlers = array( - 'mysql' => 'SimplePie_Cache_MySQL', - 'memcache' => 'SimplePie_Cache_Memcache', + 'mysql' => 'SimplePie_Cache_MySQL', + 'memcache' => 'SimplePie_Cache_Memcache', + 'memcached' => 'SimplePie_Cache_Memcached', + 'redis' => 'SimplePie_Cache_Redis' ); /** diff --git a/lib/SimplePie/SimplePie/Cache/Base.php b/lib/SimplePie/SimplePie/Cache/Base.php index d3f353961..333fb05cf 100644 --- a/lib/SimplePie/SimplePie/Cache/Base.php +++ b/lib/SimplePie/SimplePie/Cache/Base.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Cache/DB.php b/lib/SimplePie/SimplePie/Cache/DB.php index d728a9a6d..7e8f77532 100644 --- a/lib/SimplePie/SimplePie/Cache/DB.php +++ b/lib/SimplePie/SimplePie/Cache/DB.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Cache/File.php b/lib/SimplePie/SimplePie/Cache/File.php index 72e75a4b6..6ba6c5f6e 100644 --- a/lib/SimplePie/SimplePie/Cache/File.php +++ b/lib/SimplePie/SimplePie/Cache/File.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Cache/Memcache.php b/lib/SimplePie/SimplePie/Cache/Memcache.php index 23b1c9367..5190eef93 100644 --- a/lib/SimplePie/SimplePie/Cache/Memcache.php +++ b/lib/SimplePie/SimplePie/Cache/Memcache.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Cache/Memcached.php b/lib/SimplePie/SimplePie/Cache/Memcached.php new file mode 100644 index 000000000..1f73b3890 --- /dev/null +++ b/lib/SimplePie/SimplePie/Cache/Memcached.php @@ -0,0 +1,166 @@ +options = array( + 'host' => '127.0.0.1', + 'port' => 11211, + 'extras' => array( + 'timeout' => 3600, // one hour + 'prefix' => 'simplepie_', + ), + ); + $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location)); + + $this->name = $this->options['extras']['prefix'] . md5("$name:$type"); + + $this->cache = new Memcached(); + $this->cache->addServer($this->options['host'], (int)$this->options['port']); + } + + /** + * Save data to the cache + * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property + * @return bool Successfulness + */ + public function save($data) { + if ($data instanceof SimplePie) { + $data = $data->data; + } + + return $this->setData(serialize($data)); + } + + /** + * Retrieve the data saved to the cache + * @return array Data for SimplePie::$data + */ + public function load() { + $data = $this->cache->get($this->name); + + if ($data !== false) { + return unserialize($data); + } + return false; + } + + /** + * Retrieve the last modified time for the cache + * @return int Timestamp + */ + public function mtime() { + $data = $this->cache->get($this->name . '_mtime'); + return (int) $data; + } + + /** + * Set the last modified time to the current time + * @return bool Success status + */ + public function touch() { + $data = $this->cache->get($this->name); + return $this->setData($data); + } + + /** + * Remove the cache + * @return bool Success status + */ + public function unlink() { + return $this->cache->delete($this->name, 0); + } + + /** + * Set the last modified time and data to Memcached + * @return bool Success status + */ + private function setData($data) { + + if ($data !== false) { + $this->cache->set($this->name . '_mtime', time(), (int)$this->options['extras']['timeout']); + return $this->cache->set($this->name, $data, (int)$this->options['extras']['timeout']); + } + + return false; + } +} diff --git a/lib/SimplePie/SimplePie/Cache/MySQL.php b/lib/SimplePie/SimplePie/Cache/MySQL.php index 511ef6d3a..8686b6c67 100644 --- a/lib/SimplePie/SimplePie/Cache/MySQL.php +++ b/lib/SimplePie/SimplePie/Cache/MySQL.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -94,6 +93,7 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB 'path' => '', 'extras' => array( 'prefix' => '', + 'cache_purge_time' => 2592000 ), ); @@ -131,16 +131,20 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))'); if ($query === false) { + trigger_error("Can't create " . $this->options['extras']['prefix'] . "cache_data table, check permissions", E_USER_WARNING); $this->mysql = null; + return; } } if (!in_array($this->options['extras']['prefix'] . 'items', $db)) { - $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))'); + $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))'); if ($query === false) { + trigger_error("Can't create " . $this->options['extras']['prefix'] . "items table, check permissions", E_USER_WARNING); $this->mysql = null; + return; } } } @@ -158,6 +162,17 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB return false; } + $query = $this->mysql->prepare('DELETE i, cd FROM `' . $this->options['extras']['prefix'] . 'cache_data` cd, ' . + '`' . $this->options['extras']['prefix'] . 'items` i ' . + 'WHERE cd.id = i.feed_id ' . + 'AND cd.mtime < (unix_timestamp() - :purge_time)'); + $query->bindValue(':purge_time', $this->options['extras']['cache_purge_time']); + + if (!$query->execute()) + { + return false; + } + if ($data instanceof SimplePie) { $data = clone $data; diff --git a/lib/SimplePie/SimplePie/Cache/Redis.php b/lib/SimplePie/SimplePie/Cache/Redis.php new file mode 100644 index 000000000..04d72c79a --- /dev/null +++ b/lib/SimplePie/SimplePie/Cache/Redis.php @@ -0,0 +1,166 @@ + + * @link http://galvani.cz/ + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version 0.2.9 + */ + + +/** + * Caches data to redis + * + * Registered for URLs with the "redis" protocol + * + * For example, `redis://localhost:6379/?timeout=3600&prefix=sp_&dbIndex=0` will + * connect to redis on `localhost` on port 6379. All tables will be + * prefixed with `simple_primary-` and data will expire after 3600 seconds + * + * @package SimplePie + * @subpackage Caching + * @uses Redis + */ +class SimplePie_Cache_Redis implements SimplePie_Cache_Base { + /** + * Redis instance + * + * @var \Redis + */ + protected $cache; + + /** + * Options + * + * @var array + */ + protected $options; + + /** + * Cache name + * + * @var string + */ + protected $name; + + /** + * Cache Data + * + * @var type + */ + protected $data; + + /** + * Create a new cache object + * + * @param string $location Location string (from SimplePie::$cache_location) + * @param string $name Unique ID for the cache + * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data + */ + public function __construct($location, $name, $options = null) { + //$this->cache = \flow\simple\cache\Redis::getRedisClientInstance(); + $parsed = SimplePie_Cache::parse_URL($location); + $redis = new Redis(); + $redis->connect($parsed['host'], $parsed['port']); + $this->cache = $redis; + + if (!is_null($options) && is_array($options)) { + $this->options = $options; + } else { + $this->options = array ( + 'prefix' => 'rss:simple_primary:', + 'expire' => 0, + ); + } + + $this->name = $this->options['prefix'] . $name; + } + + /** + * @param \Redis $cache + */ + public function setRedisClient(\Redis $cache) { + $this->cache = $cache; + } + + /** + * Save data to the cache + * + * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property + * @return bool Successfulness + */ + public function save($data) { + if ($data instanceof SimplePie) { + $data = $data->data; + } + $response = $this->cache->set($this->name, serialize($data)); + if ($this->options['expire']) { + $this->cache->expire($this->name, $this->options['expire']); + } + + return $response; + } + + /** + * Retrieve the data saved to the cache + * + * @return array Data for SimplePie::$data + */ + public function load() { + $data = $this->cache->get($this->name); + + if ($data !== false) { + return unserialize($data); + } + return false; + } + + /** + * Retrieve the last modified time for the cache + * + * @return int Timestamp + */ + public function mtime() { + + $data = $this->cache->get($this->name); + + if ($data !== false) { + return time(); + } + + return false; + } + + /** + * Set the last modified time to the current time + * + * @return bool Success status + */ + public function touch() { + + $data = $this->cache->get($this->name); + + if ($data !== false) { + $return = $this->cache->set($this->name, $data); + if ($this->options['expire']) { + return $this->cache->expire($this->name, $this->ttl); + } + return $return; + } + + return false; + } + + /** + * Remove the cache + * + * @return bool Success status + */ + public function unlink() { + return $this->cache->set($this->name, null); + } + +} diff --git a/lib/SimplePie/SimplePie/Caption.php b/lib/SimplePie/SimplePie/Caption.php index a77b02ef1..abf07de1b 100644 --- a/lib/SimplePie/SimplePie/Caption.php +++ b/lib/SimplePie/SimplePie/Caption.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Category.php b/lib/SimplePie/SimplePie/Category.php index c6a273989..92d511e1a 100644 --- a/lib/SimplePie/SimplePie/Category.php +++ b/lib/SimplePie/SimplePie/Category.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Content/Type/Sniffer.php b/lib/SimplePie/SimplePie/Content/Type/Sniffer.php index ec0bf0952..b68b73134 100644 --- a/lib/SimplePie/SimplePie/Content/Type/Sniffer.php +++ b/lib/SimplePie/SimplePie/Content/Type/Sniffer.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Copyright.php b/lib/SimplePie/SimplePie/Copyright.php index 09f22f8df..3f3d07d3b 100644 --- a/lib/SimplePie/SimplePie/Copyright.php +++ b/lib/SimplePie/SimplePie/Copyright.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Core.php b/lib/SimplePie/SimplePie/Core.php index 7cf34876f..c856ba361 100644 --- a/lib/SimplePie/SimplePie/Core.php +++ b/lib/SimplePie/SimplePie/Core.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Credit.php b/lib/SimplePie/SimplePie/Credit.php index 50aef1c68..9bad9ef34 100644 --- a/lib/SimplePie/SimplePie/Credit.php +++ b/lib/SimplePie/SimplePie/Credit.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Decode/HTML/Entities.php b/lib/SimplePie/SimplePie/Decode/HTML/Entities.php index 46b3a1dff..de3f2cb53 100644 --- a/lib/SimplePie/SimplePie/Decode/HTML/Entities.php +++ b/lib/SimplePie/SimplePie/Decode/HTML/Entities.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Enclosure.php b/lib/SimplePie/SimplePie/Enclosure.php index fa0217800..15060e193 100644 --- a/lib/SimplePie/SimplePie/Enclosure.php +++ b/lib/SimplePie/SimplePie/Enclosure.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -451,7 +450,7 @@ class SimplePie_Enclosure /** * Get the duration of the enclosure * - * @param string $convert Convert seconds into hh:mm:ss + * @param bool $convert Convert seconds into hh:mm:ss * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found) */ public function get_duration($convert = false) diff --git a/lib/SimplePie/SimplePie/Exception.php b/lib/SimplePie/SimplePie/Exception.php index 73e104d69..53c015e77 100644 --- a/lib/SimplePie/SimplePie/Exception.php +++ b/lib/SimplePie/SimplePie/Exception.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/File.php b/lib/SimplePie/SimplePie/File.php index 45994d102..c1fab42dc 100644 --- a/lib/SimplePie/SimplePie/File.php +++ b/lib/SimplePie/SimplePie/File.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -64,7 +63,7 @@ class SimplePie_File var $redirects = 0; var $error; var $method = SIMPLEPIE_FILE_SOURCE_NONE; - var $permanent_url; //FreshRSS + var $permanent_url; public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false, $curl_options = array(), $syslog_enabled = SIMPLEPIE_SYSLOG) { @@ -108,6 +107,7 @@ class SimplePie_File curl_setopt($fp, CURLOPT_URL, $url); curl_setopt($fp, CURLOPT_HEADER, 1); curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($fp, CURLOPT_FAILONERROR, 1); curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($fp, CURLOPT_REFERER, $url); @@ -144,7 +144,7 @@ class SimplePie_File if ($parser->parse()) { $this->headers = $parser->headers; - $this->body = $parser->body; + $this->body = trim($parser->body); $this->status_code = $parser->status_code; if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) { @@ -237,7 +237,7 @@ class SimplePie_File $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); $previousStatusCode = $this->status_code; $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; //FreshRSS + $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; return; } if (isset($this->headers['content-encoding'])) @@ -255,7 +255,7 @@ class SimplePie_File } else { - $this->body = $decoder->data; + $this->body = trim($decoder->data); } break; @@ -298,7 +298,7 @@ class SimplePie_File else { $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; - if (empty($url) || !($this->body = file_get_contents($url))) + if (empty($url) || !($this->body = trim(file_get_contents($url)))) { $this->error = 'file_get_contents could not read the file'; $this->success = false; diff --git a/lib/SimplePie/SimplePie/HTTP/Parser.php b/lib/SimplePie/SimplePie/HTTP/Parser.php index 2fc3a6779..63ae1e03d 100644 --- a/lib/SimplePie/SimplePie/HTTP/Parser.php +++ b/lib/SimplePie/SimplePie/HTTP/Parser.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/IRI.php b/lib/SimplePie/SimplePie/IRI.php index ed0574701..2b3fbaf07 100644 --- a/lib/SimplePie/SimplePie/IRI.php +++ b/lib/SimplePie/SimplePie/IRI.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -259,6 +258,15 @@ class SimplePie_IRI $this->set_iri($iri); } + /** + * Clean up + */ + public function __destruct() { + $this->set_iri(null, true); + $this->set_path(null, true); + $this->set_authority(null, true); + } + /** * Create a new IRI object by resolving a relative IRI * @@ -768,24 +776,20 @@ class SimplePie_IRI */ public function is_valid() { - $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; - if ($this->ipath !== '' && - ( - $isauthority && ( - $this->ipath[0] !== '/' || - substr($this->ipath, 0, 2) === '//' - ) || - ( - $this->scheme === null && - !$isauthority && - strpos($this->ipath, ':') !== false && - (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) - ) - ) - ) - { - return false; - } + if ($this->ipath === '') return true; + + $isauthority = $this->iuserinfo !== null || $this->ihost !== null || + $this->port !== null; + if ($isauthority && $this->ipath[0] === '/') return true; + + if (!$isauthority && (substr($this->ipath, 0, 2) === '//')) return false; + + // Relative urls cannot have a colon in the first path segment (and the + // slashes themselves are not included so skip the first character). + if (!$this->scheme && !$isauthority && + strpos($this->ipath, ':') !== false && + strpos($this->ipath, '/', 1) !== false && + strpos($this->ipath, ':') < strpos($this->ipath, '/', 1)) return false; return true; } @@ -797,9 +801,14 @@ class SimplePie_IRI * @param string $iri * @return bool */ - public function set_iri($iri) + public function set_iri($iri, $clear_cache = false) { static $cache; + if ($clear_cache) + { + $cache = null; + return; + } if (!$cache) { $cache = array(); @@ -879,9 +888,14 @@ class SimplePie_IRI * @param string $authority * @return bool */ - public function set_authority($authority) + public function set_authority($authority, $clear_cache = false) { static $cache; + if ($clear_cache) + { + $cache = null; + return; + } if (!$cache) $cache = array(); @@ -1049,9 +1063,14 @@ class SimplePie_IRI * @param string $ipath * @return bool */ - public function set_path($ipath) + public function set_path($ipath, $clear_cache = false) { static $cache; + if ($clear_cache) + { + $cache = null; + return; + } if (!$cache) { $cache = array(); diff --git a/lib/SimplePie/SimplePie/Item.php b/lib/SimplePie/SimplePie/Item.php index 19ba7c8f4..daecf0a15 100644 --- a/lib/SimplePie/SimplePie/Item.php +++ b/lib/SimplePie/SimplePie/Item.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -203,14 +202,13 @@ class SimplePie_Item * * Uses ``, ``, `` or the `about` attribute * for RDF. If none of these are supplied (or `$hash` is true), creates an - * MD5 hash based on the permalink and title. If either of those are not - * supplied, creates a hash based on the full feed data. + * MD5 hash based on the permalink, title and content. * * @since Beta 2 * @param boolean $hash Should we force using a hash instead of the supplied ID? * @return string */ - public function get_id($hash = false) + public function get_id($hash = false, $fn = '') { if (!$hash) { @@ -238,23 +236,10 @@ class SimplePie_Item { return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT); } - elseif (($return = $this->get_permalink()) !== null) - { - return $return; - } - elseif (($return = $this->get_title()) !== null) - { - return $return; - } - } - if ($this->get_permalink() !== null || $this->get_title() !== null) - { - return md5($this->get_permalink() . $this->get_title()); - } - else - { - return md5(serialize($this->data)); } + if ($fn === '' || !is_callable($fn)) $fn = 'md5'; + return call_user_func($fn, + $this->get_permalink().$this->get_title().$this->get_content()); } /** @@ -457,7 +442,7 @@ class SimplePie_Item * Uses ``, `` or `` * * @since Beta 3 - * @return array|null List of {@see SimplePie_Category} objects + * @return SimplePie_Category[]|null List of {@see SimplePie_Category} objects */ public function get_categories() { @@ -1105,7 +1090,7 @@ class SimplePie_Item * @since Beta 2 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). * @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists). - * @return array|null List of SimplePie_Enclosure items + * @return SimplePie_Enclosure[]|null List of SimplePie_Enclosure items */ public function get_enclosures() { @@ -2682,7 +2667,9 @@ class SimplePie_Item // PLAYER if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) { - $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'])) { + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + } } else { diff --git a/lib/SimplePie/SimplePie/Locator.php b/lib/SimplePie/SimplePie/Locator.php index ba4a843b0..36bc02895 100644 --- a/lib/SimplePie/SimplePie/Locator.php +++ b/lib/SimplePie/SimplePie/Locator.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -226,7 +225,7 @@ class SimplePie_Locator } if ($link->hasAttribute('href') && $link->hasAttribute('rel')) { - $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel'))))); + $rel = array_unique($this->registry->call('Misc', 'space_separated_tokens', array(strtolower($link->getAttribute('rel'))))); $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1; if ($this->base_location < $line) @@ -275,7 +274,7 @@ class SimplePie_Locator { $href = trim($link->getAttribute('href')); $parsed = $this->registry->call('Misc', 'parse_url', array($href)); - if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) + if ($parsed['scheme'] === '' || preg_match('/^(https?|feed)?$/i', $parsed['scheme'])) { if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo()) { @@ -312,6 +311,57 @@ class SimplePie_Locator return null; } + public function get_rel_link($rel) + { + if ($this->dom === null) + { + throw new SimplePie_Exception('DOMDocument not found, unable to use '. + 'locator'); + } + if (!class_exists('DOMXpath')) + { + throw new SimplePie_Exception('DOMXpath not found, unable to use '. + 'get_rel_link'); + } + + $xpath = new DOMXpath($this->dom); + $query = '//a[@rel and @href] | //link[@rel and @href]'; + foreach ($xpath->query($query) as $link) + { + $href = trim($link->getAttribute('href')); + $parsed = $this->registry->call('Misc', 'parse_url', array($href)); + if ($parsed['scheme'] === '' || + preg_match('/^https?$/i', $parsed['scheme'])) + { + if (method_exists($link, 'getLineNo') && + $this->base_location < $link->getLineNo()) + { + $href = + $this->registry->call('Misc', 'absolutize_url', + array(trim($link->getAttribute('href')), + $this->base)); + } + else + { + $href = + $this->registry->call('Misc', 'absolutize_url', + array(trim($link->getAttribute('href')), + $this->http_base)); + } + if ($href === false) + { + return null; + } + $rel_values = explode(' ', strtolower($link->getAttribute('rel'))); + if (in_array($rel, $rel_values)) + { + return $href; + } + } + } + return null; + } + public function extension(&$array) { foreach ($array as $key => $value) diff --git a/lib/SimplePie/SimplePie/Misc.php b/lib/SimplePie/SimplePie/Misc.php index 2d154cbcb..ca2810611 100644 --- a/lib/SimplePie/SimplePie/Misc.php +++ b/lib/SimplePie/SimplePie/Misc.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -1947,7 +1946,7 @@ class SimplePie_Misc return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); } - public static function space_seperated_tokens($string) + public static function space_separated_tokens($string) { $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; $string_length = strlen($string); @@ -2178,7 +2177,8 @@ function embed_wmedia(width, height, link) { /** * Get the SimplePie build timestamp * - * Return SimplePie.php modification time. + * Uses the git index if it exists, otherwise uses the modification time + * of the newest file. */ public static function get_build() { diff --git a/lib/SimplePie/SimplePie/Net/IPv6.php b/lib/SimplePie/SimplePie/Net/IPv6.php index 2ff1afc90..47658aff2 100644 --- a/lib/SimplePie/SimplePie/Net/IPv6.php +++ b/lib/SimplePie/SimplePie/Net/IPv6.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Parse/Date.php b/lib/SimplePie/SimplePie/Parse/Date.php index 50bb5cffa..1f2156655 100644 --- a/lib/SimplePie/SimplePie/Parse/Date.php +++ b/lib/SimplePie/SimplePie/Parse/Date.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -331,8 +330,8 @@ class SimplePie_Parse_Date 'CCT' => 23400, 'CDT' => -18000, 'CEDT' => 7200, - 'CET' => 3600, 'CEST' => 7200, + 'CET' => 3600, 'CGST' => -7200, 'CGT' => -10800, 'CHADT' => 49500, @@ -631,7 +630,7 @@ class SimplePie_Parse_Date /** * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as * well as allowing any of upper or lower case "T", horizontal tabs, or - * spaces to be used as the time seperator (including more than one)) + * spaces to be used as the time separator (including more than one)) * * @access protected * @return int Timestamp @@ -691,7 +690,7 @@ class SimplePie_Parse_Date } // Convert the number of seconds to an integer, taking decimals into account - $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); + $second = round((int)$match[6] + (int)$match[7] / pow(10, strlen($match[7]))); return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; } diff --git a/lib/SimplePie/SimplePie/Parser.php b/lib/SimplePie/SimplePie/Parser.php index 7fb7bd9be..e3966218c 100644 --- a/lib/SimplePie/SimplePie/Parser.php +++ b/lib/SimplePie/SimplePie/Parser.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Rating.php b/lib/SimplePie/SimplePie/Rating.php index b5fe80516..eaf57080c 100644 --- a/lib/SimplePie/SimplePie/Rating.php +++ b/lib/SimplePie/SimplePie/Rating.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Registry.php b/lib/SimplePie/SimplePie/Registry.php index dac55e34e..e0909bb74 100755 --- a/lib/SimplePie/SimplePie/Registry.php +++ b/lib/SimplePie/SimplePie/Registry.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Restriction.php b/lib/SimplePie/SimplePie/Restriction.php index a1d59916d..001a5cd28 100644 --- a/lib/SimplePie/SimplePie/Restriction.php +++ b/lib/SimplePie/SimplePie/Restriction.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/Sanitize.php b/lib/SimplePie/SimplePie/Sanitize.php index bdc601100..49fe5dbd5 100644 --- a/lib/SimplePie/SimplePie/Sanitize.php +++ b/lib/SimplePie/SimplePie/Sanitize.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue @@ -348,6 +347,7 @@ class SimplePie_Sanitize } $document = new DOMDocument(); $document->encoding = 'UTF-8'; + $data = $this->preprocess($data, $type); set_error_handler(array('SimplePie_Misc', 'silence_errors')); diff --git a/lib/SimplePie/SimplePie/Source.php b/lib/SimplePie/SimplePie/Source.php index 2613798fd..1a66a392d 100644 --- a/lib/SimplePie/SimplePie/Source.php +++ b/lib/SimplePie/SimplePie/Source.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/XML/Declaration/Parser.php b/lib/SimplePie/SimplePie/XML/Declaration/Parser.php index 589e452a2..99e751672 100644 --- a/lib/SimplePie/SimplePie/XML/Declaration/Parser.php +++ b/lib/SimplePie/SimplePie/XML/Declaration/Parser.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue diff --git a/lib/SimplePie/SimplePie/gzdecode.php b/lib/SimplePie/SimplePie/gzdecode.php index 6e65f0811..0e8bc8fc6 100644 --- a/lib/SimplePie/SimplePie/gzdecode.php +++ b/lib/SimplePie/SimplePie/gzdecode.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors + * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version 1.4-dev - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue + * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue * @author Ryan Parman * @author Geoffrey Sneddon * @author Ryan McCue -- cgit v1.2.3 From a7064dc700f1a41129511866cb2fb36c522c0d6c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 18:29:10 +0200 Subject: SQLite create index if not exists --- app/SQL/install.sql.sqlite.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index dcb7a351a..1fac5fcf7 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -53,7 +53,7 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `entry`(`is_favorite`);', 'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `entry`(`is_read`);', 'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`);', //v1.1.1 -'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 //TODO: Auto add this index to existing version +'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");', ); @@ -80,6 +80,7 @@ $SQL_CREATE_TABLE_ENTRYTMP = array( );', 'CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);', +'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 //This line is used for auto-update ); global $SQL_INSERT_FEEDS; -- cgit v1.2.3 From 7a6751b50d9c809d2127a154bf811f576a24e4a4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 18:48:34 +0200 Subject: PDO fix PHP 7.1 http://php.net/manual/migration71.changed-functions.php#migration71.changed-functions.pdo --- app/Controllers/importExportController.php | 9 ++++----- app/Models/EntryDAO.php | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 6ae89defb..af3c0bf46 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -464,15 +464,14 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $values = $entry->toArray(); + $ok = false; if (isset($existingHashForGuids[$entry->guid()])) { - $id = $this->entryDAO->updateEntry($values); + $ok = $this->entryDAO->updateEntry($values); } else { - $id = $this->entryDAO->addEntry($values); + $ok = $this->entryDAO->addEntry($values); } + $error |= ($ok === false); - if (!$error && ($id === false)) { - $error = true; - } } $this->entryDAO->commit(); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 0167695ca..96790c69c 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -152,7 +152,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } if ($this->addEntryPrepared && $this->addEntryPrepared->execute()) { - return $this->bd->lastInsertId(); + return true; } else { $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo(); if ($this->autoUpdateDb($info)) { @@ -212,7 +212,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } if ($this->updateEntryPrepared && $this->updateEntryPrepared->execute()) { - return $this->bd->lastInsertId(); + return true; } else { $info = $this->updateEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->updateEntryPrepared->errorInfo(); if ($this->autoUpdateDb($info)) { -- cgit v1.2.3 From cae67808fed114d15700e2a9d2f2b556ffc0d63a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 19:25:17 +0200 Subject: Minor i18n English changes Add credits. Keep British spelling of favourites in the user interface, USA spelling in the code. --- CHANGELOG.md | 2 ++ CREDITS.md | 1 + app/i18n/en/admin.php | 2 +- app/i18n/en/conf.php | 2 +- app/i18n/en/gen.php | 2 +- app/i18n/en/index.php | 6 +++--- 6 files changed, 9 insertions(+), 6 deletions(-) (limited to 'app') diff --git a/CHANGELOG.md b/CHANGELOG.md index 77c3d6ffc..5d9ffe488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 2017-xx-xx FreshRSS 1.7.0-dev * Compatibility: * Add support for PHP 7.1 [#1471](https://github.com/FreshRSS/FreshRSS/issues/1471) +* I18n + * Improve English [#1465](https://github.com/FreshRSS/FreshRSS/pull/1465) ## 2017-03-11 FreshRSS 1.6.3 diff --git a/CREDITS.md b/CREDITS.md index 57635669a..c7aa808e3 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -21,6 +21,7 @@ People are sorted by name so please keep this order. * [Guillaume Hayot](https://github.com/postblue): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:postblue), [Web](https://postblue.info/) * [hckweb](https://github.com/hckweb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=hckweb) * [Jaussoin Timothée](https://github.com/edhelas): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=edhelas), [Web](http://edhelas.movim.eu/) +* [jlefler](https://github.com/jlefler): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jlefler) * [Julien Reichardt](https://github.com/j8r): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=j8r), [Web](https://blog.jrei.ch/) * [Kevin Papst](https://github.com/kevinpapst): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=kevinpapst), [Web](http://www.kevinpapst.de/) * [Luc Didry](https://github.com/ldidry): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ldidry), [Web](https://www.fiat-tux.fr/) diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index f9761952c..707627782 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -138,7 +138,7 @@ return array( 'number_entries' => '%d articles', 'percent_of_total' => '%% of total', 'repartition' => 'Articles repartition', - 'status_favorites' => 'Favorites', + 'status_favorites' => 'Favourites', 'status_read' => 'Read', 'status_total' => 'Total', 'status_unread' => 'Unread', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 4c4a003c4..5810d7c3a 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -142,7 +142,7 @@ return array( '_' => 'Shortcuts', 'article_action' => 'Article actions', 'auto_share' => 'Share', - 'auto_share_help' => 'If there is only one sharing mode, it is used. Other modes are accessible by their number.', + 'auto_share_help' => 'If there is only one sharing mode, it is used. Otherwise, modes are accessible by their number.', 'close_dropdown' => 'Close menus', 'collapse_article' => 'Collapse', 'first_article' => 'Skip to the first article', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 2a5842157..d6ae266b7 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -103,7 +103,7 @@ return array( 'js' => array( 'category_empty' => 'Empty category', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favourites and user queries. It cannot be cancelled!', 'feedback' => array( 'body_new_articles' => 'There are %%d new articles to read on FreshRSS.', 'request_failed' => 'A request has failed, it may have been caused by Internet connection problems.', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index dd07d3ac8..a4686de4e 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -21,7 +21,7 @@ return array( 'rss_of' => 'RSS feed of %s', 'title' => 'Your RSS feeds', 'title_global' => 'Global view', - 'title_fav' => 'Your favorites', + 'title_fav' => 'Your favourites', ), 'log' => array( '_' => 'Logs', @@ -41,7 +41,7 @@ return array( 'mark_cat_read' => 'Mark category as read', 'mark_feed_read' => 'Mark feed as read', 'newer_first' => 'Newer first', - 'non-starred' => 'Show all but favorites', + 'non-starred' => 'Show all but favourites', 'normal_view' => 'Normal view', 'older_first' => 'Oldest first', 'queries' => 'User queries', @@ -49,7 +49,7 @@ return array( 'reader_view' => 'Reading view', 'rss_view' => 'RSS feed', 'search_short' => 'Search', - 'starred' => 'Show only favorites', + 'starred' => 'Show only favourites', 'stats' => 'Statistics', 'subscription' => 'Subscriptions management', 'unread' => 'Show only unread', -- cgit v1.2.3 From b8cc4a4790cfe157465b7ba6776897674c8d5463 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 19:31:01 +0200 Subject: i18n: A few more favourites --- app/i18n/en/conf.php | 20 ++++++++++---------- app/i18n/en/sub.php | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'app') diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 5810d7c3a..7687db1d4 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -44,7 +44,7 @@ return array( 'filter' => 'Filter applied:', 'get_all' => 'Display all articles', 'get_category' => 'Display "%s" category', - 'get_favorite' => 'Display favorite articles', + 'get_favorite' => 'Display favourite articles', 'get_feed' => 'Display "%s" feed', 'no_filter' => 'No filter', 'none' => 'You haven’t created any user queries yet.', @@ -56,14 +56,14 @@ return array( 'state_1' => 'Display read articles', 'state_2' => 'Display unread articles', 'state_3' => 'Display all articles', - 'state_4' => 'Display favorite articles', - 'state_5' => 'Display read favorite articles', - 'state_6' => 'Display unread favorite articles', - 'state_7' => 'Display favorite articles', - 'state_8' => 'Display not favorite articles', - 'state_9' => 'Display read not favorite articles', - 'state_10' => 'Display unread not favorite articles', - 'state_11' => 'Display not favorite articles', + 'state_4' => 'Display favourite articles', + 'state_5' => 'Display read favourite articles', + 'state_6' => 'Display unread favourite articles', + 'state_7' => 'Display favourite articles', + 'state_8' => 'Display not favourite articles', + 'state_9' => 'Display read not favourite articles', + 'state_10' => 'Display unread not favourite articles', + 'state_11' => 'Display not favourite articles', 'state_12' => 'Display all articles', 'state_13' => 'Display read articles', 'state_14' => 'Display unread articles', @@ -152,7 +152,7 @@ return array( 'last_article' => 'Skip to the last article', 'load_more' => 'Load more articles', 'mark_read' => 'Mark as read', - 'mark_favorite' => 'Mark as favorite', + 'mark_favorite' => 'Mark as favourite', 'navigation' => 'Navigation', 'navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
With the "Alt" modifier, navigation shortcuts apply on categories.', 'next_article' => 'Skip to the next article', diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index 6a20f5a69..86600e882 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -47,7 +47,7 @@ return array( 'file_to_import' => 'File to import
(OPML, JSON or ZIP)', 'file_to_import_no_zip' => 'File to import
(OPML or JSON)', 'import' => 'Import', - 'starred_list' => 'List of favorite articles', + 'starred_list' => 'List of favourite articles', 'title' => 'Import / export', ), 'menu' => array( -- cgit v1.2.3 From 8a92bde940442bd58815573f26a7c328070589e8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 19:33:37 +0200 Subject: i18n English misc. --- app/i18n/en/conf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 7687db1d4..8f7b31278 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -162,7 +162,7 @@ return array( 'shift_for_all_read' => '+ shift to mark all articles as read', 'title' => 'Shortcuts', 'user_filter' => 'Access user filters', - 'user_filter_help' => 'If there is only one user filter, it is used. Other filters are accessible by their number.', + 'user_filter_help' => 'If there is only one user filter, it is used. Otherwise, filters are accessible by their number.', ), 'user' => array( 'articles_and_size' => '%s articles (%s)', -- cgit v1.2.3 From bc580c5905522143cb3d73a37641f7bf21225545 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Mar 2017 22:08:17 +0200 Subject: SQL index auto added At the same time as the new temp table --- app/SQL/install.sql.mysql.php | 4 +++- app/SQL/install.sql.pgsql.php | 3 ++- app/SQL/install.sql.sqlite.php | 7 ++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 3ad68173f..6b07f5965 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` ( INDEX (`is_favorite`), -- v0.7 INDEX (`is_read`), -- v0.7 INDEX `entry_lastSeen_index` (`lastSeen`) -- v1.1.1 - INDEX `entry_feed_read_index` (`id_feed`,`is_read`) -- v1.7 //TODO: Auto add this index to existing version + -- INDEX `entry_feed_read_index` (`id_feed`,`is_read`) -- v1.7 Located futher down ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; @@ -83,6 +83,8 @@ CREATE TABLE IF NOT EXISTS `%1$sentrytmp` ( -- v1.7 INDEX (`date`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; + +CREATE INDEX `entry_feed_read_index` ON `%1$sentry`(`id_feed`,`is_read`); -- v1.7 Located here to be auto-added '); define('SQL_INSERT_FEEDS', ' diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index ca4dfa925..74c6d1b79 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -50,7 +50,6 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX %1$sis_favorite_index ON "%1$sentry" ("is_favorite");', 'CREATE INDEX %1$sis_read_index ON "%1$sentry" ("is_read");', 'CREATE INDEX %1$sentry_lastSeen_index ON "%1$sentry" ("lastSeen");', -'CREATE INDEX %1$sentry_feed_read_index ON "%1$sentry" ("id_feed","is_read");', //v1.7 //TODO: Auto add this index to existing version 'INSERT INTO "%1$scategory" (name) SELECT \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1);', ); @@ -75,6 +74,8 @@ $SQL_CREATE_TABLE_ENTRYTMP = array( UNIQUE ("id_feed","guid") );', 'CREATE INDEX %1$sentrytmp_date_index ON "%1$sentrytmp" ("date");', + +'CREATE INDEX %1$sentry_feed_read_index ON "%1$sentry" ("id_feed","is_read");', //v1.7 ); global $SQL_INSERT_FEEDS; diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index 1fac5fcf7..bce9f5a95 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -26,7 +26,6 @@ $SQL_CREATE_TABLES = array( FOREIGN KEY (`category`) REFERENCES `category`(`id`) ON DELETE SET NULL ON UPDATE CASCADE, UNIQUE (`url`) );', - 'CREATE INDEX IF NOT EXISTS feed_name_index ON `feed`(`name`);', 'CREATE INDEX IF NOT EXISTS feed_priority_index ON `feed`(`priority`);', 'CREATE INDEX IF NOT EXISTS feed_keep_history_index ON `feed`(`keep_history`);', @@ -49,11 +48,9 @@ $SQL_CREATE_TABLES = array( FOREIGN KEY (`id_feed`) REFERENCES `feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE (`id_feed`,`guid`) );', - 'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `entry`(`is_favorite`);', 'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `entry`(`is_read`);', 'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`);', //v1.1.1 -'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");', ); @@ -78,9 +75,9 @@ $SQL_CREATE_TABLE_ENTRYTMP = array( FOREIGN KEY (`id_feed`) REFERENCES `feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE (`id_feed`,`guid`) );', - 'CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);', -'CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`);', //v1.7 //This line is used for auto-update + +'CREATE INDEX IF NOT EXISTS `entry_feed_read_index` ON `entry`(`id_feed`,`is_read`);', //v1.7 ); global $SQL_INSERT_FEEDS; -- cgit v1.2.3 From 5541e3951262bf93fc0eeb4938d6b93b01bfd1bd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Mar 2017 21:26:38 +0200 Subject: More defered insertion --- app/Controllers/feedController.php | 10 ++++++++-- app/Controllers/importExportController.php | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index bfc8b2045..5359ad198 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -321,6 +321,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { unset($newGuids); $oldGuids = array(); + $needFeedCacheRefresh = false; // Add entries in database if possible. foreach ($entries as $entry) { $entry_date = $entry->date(true); @@ -333,11 +334,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { //Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() . //', old hash ' . $existingHash . ', new hash ' . $entry->hash()); //TODO: Make an updated/is_read policy by feed, in addition to the global one. + $needFeedCacheRefresh = FreshRSS_Context::$user_conf->mark_updated_article_unread; $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy. if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); } - $entryDAO->updateEntry($entry->toArray()); + $entryDAO->updateEntry($entry->toArray()); //TODO: Need to refresh cache } } elseif ($feed_history == 0 && $entry_date < $date_min) { // This entry should not be added considering configuration and date. @@ -388,12 +390,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $date_min, max($feed_history, count($entries) + 10)); if ($nb > 0) { + $needFeedCacheRefresh = true; Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']'); } } $feedDAO->updateLastUpdate($feed->id(), false, $mtime); + if ($needFeedCacheRefresh) { + $feedDAO->updateCachedValue($feed->id()); + } if ($entryDAO->inTransaction()) { $entryDAO->commit(); } @@ -439,7 +445,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->beginTransaction(); } $entryDAO->commitNewEntries(); - $feedDAO->updateCachedValues(); //TODO: Optimize + $feedDAO->updateCachedValues(); if ($entryDAO->inTransaction()) { $entryDAO->commit(); } diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 82c49cc6a..2bc68848c 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -474,7 +474,11 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $this->entryDAO->commit(); - $entryDAO->commitNewEntries(); + + $this->entryDAO->beginTransaction(); + $this->entryDAO->commitNewEntries(); + $this->feedDAO->updateCachedValues(); + $this->entryDAO->commit(); return !$error; } -- cgit v1.2.3 From 282ea0cfd782a69e7a9ca774d9a9e0f4f1b5c401 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Mar 2017 22:09:18 +0200 Subject: Defered insertion: feedController bug --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 5359ad198..bfa0ae160 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -308,6 +308,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // -2 means we take the default value from configuration $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } + $needFeedCacheRefresh = false; // We want chronological order and SimplePie uses reverse order. $entries = array_reverse($feed->entries()); @@ -321,7 +322,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { unset($newGuids); $oldGuids = array(); - $needFeedCacheRefresh = false; // Add entries in database if possible. foreach ($entries as $entry) { $entry_date = $entry->date(true); -- cgit v1.2.3 From 56bbdc543d02ef1ca92fa26aa18413d27a833748 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Mar 2017 22:16:59 +0200 Subject: Removing TODO Done --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index bfa0ae160..f6668d228 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -339,7 +339,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); } - $entryDAO->updateEntry($entry->toArray()); //TODO: Need to refresh cache + $entryDAO->updateEntry($entry->toArray()); } } elseif ($feed_history == 0 && $entry_date < $date_min) { // This entry should not be added considering configuration and date. -- cgit v1.2.3 From 6c604bc1dd75cc67392ff37186855faea3c29d48 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Mar 2017 23:42:19 +0200 Subject: Minz param bug fix --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index f6668d228..07a763613 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -468,7 +468,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = Minz_Request::param('id'); $url = Minz_Request::param('url'); $force = Minz_Request::param('force'); - $noCommit = Minz_Session::param('isLastFeed', 1) != 1; + $noCommit = Minz_Request::fetchPOST('isLastFeed', 1) != 1; list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); -- cgit v1.2.3 From 0d4c26c673d548a1367a0f96f49546ca27619d90 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 29 Mar 2017 21:42:40 +0200 Subject: Add manual commit & refresh cache to deferred insertion --- app/Controllers/feedController.php | 15 +++++++++++++-- p/scripts/main.js | 15 +++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 07a763613..d1f0d3535 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -460,6 +460,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { * - id (default: false): Feed ID * - url (default: false): Feed URL * - force (default: false) + * - noCommit (default: 0): Set to 1 to prevent committing the new articles to the main database * If id and url are not specified, all the feeds are actualized. But if force is * false, process stops at 10 feeds to avoid time execution problem. */ @@ -468,9 +469,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = Minz_Request::param('id'); $url = Minz_Request::param('url'); $force = Minz_Request::param('force'); - $noCommit = Minz_Request::fetchPOST('isLastFeed', 1) != 1; + $noCommit = Minz_Request::fetchPOST('noCommit', 0) == 1; - list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); + if ($id == -1 && !$noCommit) { //Special request only to commit & refresh DB cache + $updated_feeds = 0; + $entryDAO = FreshRSS_Factory::createEntryDao(); + $feedDAO = FreshRSS_Factory::createFeedDao(); + $entryDAO->beginTransaction(); + $entryDAO->commitNewEntries(); + $feedDAO->updateCachedValues(); + $entryDAO->commit(); + } else { + list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); + } if (Minz_Request::param('ajax')) { // Most of the time, ajax request is for only one feed. But since diff --git a/p/scripts/main.js b/p/scripts/main.js index c2f60bf7f..9aca75b93 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -803,13 +803,12 @@ function updateFeed(feeds, feeds_count) { if (!feed) { return; } - $.ajax({ type: 'POST', url: feed.url, data : { _csrf: context.csrf, - isLastFeed: feeds.length <= 0 ? 1 : 0, + noCommit: feeds.length > 0 ? 1 : 0, }, }).always(function (data) { feed_processed++; @@ -831,7 +830,6 @@ function init_actualize() { if (ajax_loading) { return false; } - ajax_loading = true; $.getJSON('./?c=javascript&a=actualize').done(function (data) { @@ -842,7 +840,16 @@ function init_actualize() { } if (data.feeds.length === 0) { openNotification(data.feedback_no_refresh, "good"); - ajax_loading = false; + $.ajax({ //Empty request to force refresh server database cache + type: 'POST', + url: './?c=feed&a=actualize&id=-1', + data : { + _csrf: context.csrf, + noCommit: 0, + }, + }).always(function (data) { + ajax_loading = false; + }); return; } //Progress bar -- cgit v1.2.3 From 50fd3a359e1fb872859b12af2762e47a696ebcd3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Apr 2017 11:24:59 +0200 Subject: Fix PostgreSQL uniqueness And remove "experimental" warning --- CHANGELOG.md | 4 ++++ README.fr.md | 2 +- README.md | 2 +- app/SQL/install.sql.pgsql.php | 2 +- app/install.php | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d9ffe488..20cde81b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## 2017-xx-xx FreshRSS 1.7.0-dev * Compatibility: * Add support for PHP 7.1 [#1471](https://github.com/FreshRSS/FreshRSS/issues/1471) + * PostgreSQL is not experimental anymore [#1476](https://github.com/FreshRSS/FreshRSS/pull/1476) +* Bug fixing + * Fix SQL uniqueness bug with PostgreSQL [#1476](https://github.com/FreshRSS/FreshRSS/pull/1476) + * (Require manual update for existing installations) * I18n * Improve English [#1465](https://github.com/FreshRSS/FreshRSS/pull/1465) diff --git a/README.fr.md b/README.fr.md index b0b46bf65..da402c92e 100644 --- a/README.fr.md +++ b/README.fr.md @@ -35,7 +35,7 @@ Nous sommes une communauté amicale. * PHP 5.3.3+ (PHP 5.4+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) * Requis : [cURL](http://php.net/curl), [DOM](http://php.net/dom), [XML](http://php.net/xml), et [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite) ou [PDO_PGSQL](http://php.net/pdo-pgsql) * Recommandés : [JSON](http://php.net/json), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](http://php.net/mbstring) et/ou [iconv](http://php.net/iconv) (pour conversion d’encodages), [ZIP](http://php.net/zip) (pour import/export), [zlib](http://php.net/zlib) (pour les flux compressés) -* MySQL 5.5.3+ (recommandé), ou SQLite 3.7.4+, ou PostgreSQL (experimental) +* MySQL 5.5.3+ (recommandé), ou SQLite 3.7.4+, ou PostgreSQL 9.2+ * Un navigateur Web récent tel Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Fonctionne aussi sur mobile diff --git a/README.md b/README.md index d599afaa4..43faf1a73 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ We are a friendly community. * PHP 5.3.3+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) * Required extensions: [cURL](http://php.net/curl), [DOM](http://php.net/dom), [XML](http://php.net/xml), and [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite) or [PDO_PGSQL](http://php.net/pdo-pgsql) * Recommended extensions: [JSON](http://php.net/json), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names), [mbstring](http://php.net/mbstring) and/or [iconv](http://php.net/iconv) (for charset conversion), [ZIP](http://php.net/zip) (for import/export), [zlib](http://php.net/zlib) (for compressed feeds) -* MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL (experimental) +* MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL 9.2+ * A recent browser like Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Works on mobile diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 9f4240b98..2775dab5b 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -32,7 +32,7 @@ $SQL_CREATE_TABLES = array( 'CREATE TABLE IF NOT EXISTS "%1$sentry" ( "id" BIGINT NOT NULL PRIMARY KEY, - "guid" VARCHAR(760) UNIQUE NOT NULL, + "guid" VARCHAR(760) NOT NULL, "title" VARCHAR(255) NOT NULL, "author" VARCHAR(255), "content" TEXT, diff --git a/app/install.php b/app/install.php index 9a88e0f37..730942a5a 100644 --- a/app/install.php +++ b/app/install.php @@ -629,7 +629,7 @@ function printStep3() { -- cgit v1.2.3 From d9c0d25b85ef3df7ea2cdc261e274efcdd5cfce0 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Apr 2017 22:31:12 +0200 Subject: Improve search: intitle, author, inurl Allow multiple values of intitle: , author:, inurl: Note: Tests for UserQueryTest are broken due to https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-4.0.0#backwards-compatibility-issues --- app/Models/EntryDAO.php | 21 ++++-- app/Models/Search.php | 60 +++++++++------ tests/README.md | 7 ++ tests/app/Models/CategoryTest.php | 2 +- tests/app/Models/ContextTest.php | 5 -- tests/app/Models/SearchTest.php | 149 +++++++++++++++++++------------------ tests/app/Models/UserQueryTest.php | 2 +- 7 files changed, 134 insertions(+), 112 deletions(-) create mode 100644 tests/README.md delete mode 100644 tests/app/Models/ContextTest.php (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 61ec48d08..510755a2f 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -631,16 +631,22 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } if ($filter) { if ($filter->getIntitle()) { - $search .= 'AND ' . $alias . 'title LIKE ? '; - $values[] = "%{$filter->getIntitle()}%"; + foreach ($filter->getIntitle() as $title) { + $search .= 'AND ' . $alias . 'title LIKE ? '; + $values[] = "%{$title}%"; + } } if ($filter->getInurl()) { - $search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; - $values[] = "%{$filter->getInurl()}%"; + foreach ($filter->getInurl() as $url) { + $search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; + $values[] = "%{$url}%"; + } } if ($filter->getAuthor()) { - $search .= 'AND ' . $alias . 'author LIKE ? '; - $values[] = "%{$filter->getAuthor()}%"; + foreach ($filter->getAuthor() as $author) { + $search .= 'AND ' . $alias . 'author LIKE ? '; + $values[] = "%{$author}%"; + } } if ($filter->getMinDate()) { $search .= 'AND ' . $alias . 'id >= ? '; @@ -659,8 +665,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $values[] = $filter->getMaxPubdate(); } if ($filter->getTags()) { - $tags = $filter->getTags(); - foreach ($tags as $tag) { + foreach ($filter->getTags() as $tag) { $search .= 'AND ' . $alias . 'tags LIKE ? '; $values[] = "%{$tag}%"; } diff --git a/app/Models/Search.php b/app/Models/Search.php index 575a9a2cb..7b801f40b 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -81,6 +81,10 @@ class FreshRSS_Search { return $this->search; } + private static function removeEmptyValues($anArray) { + return is_array($anArray) ? array_filter($anArray, function($value) { return $value !== ''; }) : array(); + } + /** * Parse the search string to find intitle keyword and the search related * to it. @@ -90,14 +94,15 @@ class FreshRSS_Search { * @return string */ private function parseIntitleSearch($input) { - if (preg_match('/intitle:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + if (preg_match_all('/intitle:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { $this->intitle = $matches['search']; - return str_replace($matches[0], '', $input); + $input = str_replace($matches[0], '', $input); } - if (preg_match('/intitle:(?P\w*)/', $input, $matches)) { - $this->intitle = $matches['search']; - return str_replace($matches[0], '', $input); + if (preg_match_all('/intitle:(?P\w*)/', $input, $matches)) { + $this->intitle = array_merge($this->intitle ? $this->intitle : array(), $matches['search']); + $input = str_replace($matches[0], '', $input); } + $this->intitle = self::removeEmptyValues($this->intitle); return $input; } @@ -112,30 +117,32 @@ class FreshRSS_Search { * @return string */ private function parseAuthorSearch($input) { - if (preg_match('/author:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + if (preg_match_all('/author:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { $this->author = $matches['search']; - return str_replace($matches[0], '', $input); + $input = str_replace($matches[0], '', $input); } - if (preg_match('/author:(?P\w*)/', $input, $matches)) { - $this->author = $matches['search']; - return str_replace($matches[0], '', $input); + if (preg_match_all('/author:(?P\w*)/', $input, $matches)) { + $this->author = array_merge($this->author ? $this->author : array(), $matches['search']); + $input = str_replace($matches[0], '', $input); } + $this->author = self::removeEmptyValues($this->author); return $input; } /** * Parse the search string to find inurl keyword and the search related * to it. - * The search is the first word following the keyword except. + * The search is the first word following the keyword. * * @param string $input * @return string */ private function parseInurlSearch($input) { - if (preg_match('/inurl:(?P[^\s]*)/', $input, $matches)) { + if (preg_match_all('/inurl:(?P[^\s]*)/', $input, $matches)) { $this->inurl = $matches['search']; - return str_replace($matches[0], '', $input); + $input = str_replace($matches[0], '', $input); } + $this->inurl = self::removeEmptyValues($this->inurl); return $input; } @@ -148,9 +155,12 @@ class FreshRSS_Search { * @return string */ private function parseDateSearch($input) { - if (preg_match('/date:(?P[^\s]*)/', $input, $matches)) { - list($this->min_date, $this->max_date) = parseDateInterval($matches['search']); - return str_replace($matches[0], '', $input); + if (preg_match_all('/date:(?P[^\s]*)/', $input, $matches)) { + $input = str_replace($matches[0], '', $input); + $dates = self::removeEmptyValues($matches['search']); + if (!empty($dates[0])) { + list($this->min_date, $this->max_date) = parseDateInterval($dates[0]); + } } return $input; } @@ -164,9 +174,12 @@ class FreshRSS_Search { * @return string */ private function parsePubdateSearch($input) { - if (preg_match('/pubdate:(?P[^\s]*)/', $input, $matches)) { - list($this->min_pubdate, $this->max_pubdate) = parseDateInterval($matches['search']); - return str_replace($matches[0], '', $input); + if (preg_match_all('/pubdate:(?P[^\s]*)/', $input, $matches)) { + $input = str_replace($matches[0], '', $input); + $dates = self::removeEmptyValues($matches['search']); + if (!empty($dates[0])) { + list($this->min_pubdate, $this->max_pubdate) = parseDateInterval($dates[0]); + } } return $input; } @@ -182,8 +195,9 @@ class FreshRSS_Search { private function parseTagsSeach($input) { if (preg_match_all('/#(?P[^\s]+)/', $input, $matches)) { $this->tags = $matches['search']; - return str_replace($matches[0], '', $input); + $input = str_replace($matches[0], '', $input); } + $this->tags = self::removeEmptyValues($this->tags); return $input; } @@ -196,7 +210,7 @@ class FreshRSS_Search { * @return string */ private function parseSearch($input) { - $input = $this->cleanSearch($input); + $input = self::cleanSearch($input); if (strcmp($input, '') == 0) { return; } @@ -204,7 +218,7 @@ class FreshRSS_Search { $this->search = $matches['search']; $input = str_replace($matches[0], '', $input); } - $input = $this->cleanSearch($input); + $input = self::cleanSearch($input); if (strcmp($input, '') == 0) { return; } @@ -221,7 +235,7 @@ class FreshRSS_Search { * @param string $input * @return string */ - private function cleanSearch($input) { + private static function cleanSearch($input) { $input = preg_replace('/\s+/', ' ', $input); return trim($input); } diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..3dd9602be --- /dev/null +++ b/tests/README.md @@ -0,0 +1,7 @@ +# FreshRSS tests + +```sh +cd ./tests/ +wget https://phar.phpunit.de/phpunit.phar +php phpunit.phar --bootstrap bootstrap.php +``` diff --git a/tests/app/Models/CategoryTest.php b/tests/app/Models/CategoryTest.php index da439b785..2fd153aee 100644 --- a/tests/app/Models/CategoryTest.php +++ b/tests/app/Models/CategoryTest.php @@ -1,6 +1,6 @@ 'a'); -- cgit v1.2.3 From aadba9fb707d2d2bc6c05a84bb3a823895531137 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Apr 2017 23:41:19 +0200 Subject: Negative searches https://github.com/FreshRSS/FreshRSS/issues/1381 Possibility to exclude authors, titles, tags, urls, words by prefixing them by ! or - (like Google Search): * !intitle:unwanted * -intitle:unwanted * -author:unwanted * -#unwanted * -unwanted And one can use many of each and combine them with positive searches --- app/Models/EntryDAO.php | 72 +++++++++++++++++++++-------- app/Models/Search.php | 120 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 159 insertions(+), 33 deletions(-) (limited to 'app') diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 510755a2f..7e836097a 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -630,24 +630,6 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $search .= 'AND ' . $alias . 'id >= ' . $date_min . '000000 '; } if ($filter) { - if ($filter->getIntitle()) { - foreach ($filter->getIntitle() as $title) { - $search .= 'AND ' . $alias . 'title LIKE ? '; - $values[] = "%{$title}%"; - } - } - if ($filter->getInurl()) { - foreach ($filter->getInurl() as $url) { - $search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; - $values[] = "%{$url}%"; - } - } - if ($filter->getAuthor()) { - foreach ($filter->getAuthor() as $author) { - $search .= 'AND ' . $alias . 'author LIKE ? '; - $values[] = "%{$author}%"; - } - } if ($filter->getMinDate()) { $search .= 'AND ' . $alias . 'id >= ? '; $values[] = "{$filter->getMinDate()}000000"; @@ -664,19 +646,69 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $search .= 'AND ' . $alias . 'date <= ? '; $values[] = $filter->getMaxPubdate(); } + + if ($filter->getAuthor()) { + foreach ($filter->getAuthor() as $author) { + $search .= 'AND ' . $alias . 'author LIKE ? '; + $values[] = "%{$author}%"; + } + } + if ($filter->getIntitle()) { + foreach ($filter->getIntitle() as $title) { + $search .= 'AND ' . $alias . 'title LIKE ? '; + $values[] = "%{$title}%"; + } + } if ($filter->getTags()) { foreach ($filter->getTags() as $tag) { $search .= 'AND ' . $alias . 'tags LIKE ? '; $values[] = "%{$tag}%"; } } + if ($filter->getInurl()) { + foreach ($filter->getInurl() as $url) { + $search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; + $values[] = "%{$url}%"; + } + } + + if ($filter->getNotAuthor()) { + foreach ($filter->getNotAuthor() as $author) { + $search .= 'AND (NOT ' . $alias . 'author LIKE ?) '; + $values[] = "%{$author}%"; + } + } + if ($filter->getNotIntitle()) { + foreach ($filter->getNotIntitle() as $title) { + $search .= 'AND (NOT ' . $alias . 'title LIKE ?) '; + $values[] = "%{$title}%"; + } + } + if ($filter->getNotTags()) { + foreach ($filter->getNotTags() as $tag) { + $search .= 'AND (NOT ' . $alias . 'tags LIKE ?) '; + $values[] = "%{$tag}%"; + } + } + if ($filter->getNotInurl()) { + foreach ($filter->getNotInurl() as $url) { + $search .= 'AND (NOT CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ?) '; + $values[] = "%{$url}%"; + } + } + if ($filter->getSearch()) { - $search_values = $filter->getSearch(); - foreach ($search_values as $search_value) { + foreach ($filter->getSearch() as $search_value) { $search .= 'AND ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ? '; $values[] = "%{$search_value}%"; } } + if ($filter->getNotSearch()) { + foreach ($filter->getNotSearch() as $search_value) { + $search .= 'AND (NOT ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ?) '; + $values[] = "%{$search_value}%"; + } + } } return array($values, $search); } diff --git a/app/Models/Search.php b/app/Models/Search.php index 7b801f40b..2e89ea05b 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -23,18 +23,33 @@ class FreshRSS_Search { private $tags; private $search; + private $not_intitle; + private $not_inurl; + private $not_author; + private $not_tags; + private $not_search; + public function __construct($input) { - if (strcmp($input, '') == 0) { + if ($input == '') { return; } $this->raw_input = $input; + + $input = $this->parseNotIntitleSearch($input); + $input = $this->parseNotAuthorSearch($input); + $input = $this->parseNotInurlSearch($input); + $input = $this->parseNotTagsSeach($input); + + $input = $this->parsePubdateSearch($input); + $input = $this->parseDateSearch($input); + $input = $this->parseIntitleSearch($input); $input = $this->parseAuthorSearch($input); $input = $this->parseInurlSearch($input); - $input = $this->parsePubdateSearch($input); - $input = $this->parseDateSearch($input); $input = $this->parseTagsSeach($input); - $this->parseSearch($input); + + $input = $this->parseNotSearch($input); + $input = $this->parseSearch($input); } public function __toString() { @@ -48,6 +63,9 @@ class FreshRSS_Search { public function getIntitle() { return $this->intitle; } + public function getNotIntitle() { + return $this->not_intitle; + } public function getMinDate() { return $this->min_date; @@ -68,18 +86,30 @@ class FreshRSS_Search { public function getInurl() { return $this->inurl; } + public function getNotInurl() { + return $this->not_inurl; + } public function getAuthor() { return $this->author; } + public function getNotAuthor() { + return $this->not_author; + } public function getTags() { return $this->tags; } + public function getNotTags() { + return $this->not_tags; + } public function getSearch() { return $this->search; } + public function getNotSearch() { + return $this->not_search; + } private static function removeEmptyValues($anArray) { return is_array($anArray) ? array_filter($anArray, function($value) { return $value !== ''; }) : array(); @@ -94,11 +124,11 @@ class FreshRSS_Search { * @return string */ private function parseIntitleSearch($input) { - if (preg_match_all('/intitle:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + if (preg_match_all('/\bintitle:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { $this->intitle = $matches['search']; $input = str_replace($matches[0], '', $input); } - if (preg_match_all('/intitle:(?P\w*)/', $input, $matches)) { + if (preg_match_all('/\bintitle:(?P\w*)/', $input, $matches)) { $this->intitle = array_merge($this->intitle ? $this->intitle : array(), $matches['search']); $input = str_replace($matches[0], '', $input); } @@ -106,6 +136,19 @@ class FreshRSS_Search { return $input; } + private function parseNotIntitleSearch($input) { + if (preg_match_all('/[!-]intitle:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + $this->not_intitle = $matches['search']; + $input = str_replace($matches[0], '', $input); + } + if (preg_match_all('/[!-]intitle:(?P\w*)/', $input, $matches)) { + $this->not_intitle = array_merge($this->not_intitle ? $this->not_intitle : array(), $matches['search']); + $input = str_replace($matches[0], '', $input); + } + $this->not_intitle = self::removeEmptyValues($this->not_intitle); + return $input; + } + /** * Parse the search string to find author keyword and the search related * to it. @@ -117,11 +160,11 @@ class FreshRSS_Search { * @return string */ private function parseAuthorSearch($input) { - if (preg_match_all('/author:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + if (preg_match_all('/\bauthor:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { $this->author = $matches['search']; $input = str_replace($matches[0], '', $input); } - if (preg_match_all('/author:(?P\w*)/', $input, $matches)) { + if (preg_match_all('/\bauthor:(?P\w*)/', $input, $matches)) { $this->author = array_merge($this->author ? $this->author : array(), $matches['search']); $input = str_replace($matches[0], '', $input); } @@ -129,6 +172,19 @@ class FreshRSS_Search { return $input; } + private function parseNotAuthorSearch($input) { + if (preg_match_all('/[!-]author:(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + $this->not_author = $matches['search']; + $input = str_replace($matches[0], '', $input); + } + if (preg_match_all('/[!-]author:(?P\w*)/', $input, $matches)) { + $this->not_author = array_merge($this->not_author ? $this->not_author : array(), $matches['search']); + $input = str_replace($matches[0], '', $input); + } + $this->not_author = self::removeEmptyValues($this->not_author); + return $input; + } + /** * Parse the search string to find inurl keyword and the search related * to it. @@ -138,7 +194,7 @@ class FreshRSS_Search { * @return string */ private function parseInurlSearch($input) { - if (preg_match_all('/inurl:(?P[^\s]*)/', $input, $matches)) { + if (preg_match_all('/\binurl:(?P[^\s]*)/', $input, $matches)) { $this->inurl = $matches['search']; $input = str_replace($matches[0], '', $input); } @@ -146,6 +202,15 @@ class FreshRSS_Search { return $input; } + private function parseNotInurlSearch($input) { + if (preg_match_all('/[!-]inurl:(?P[^\s]*)/', $input, $matches)) { + $this->not_inurl = $matches['search']; + $input = str_replace($matches[0], '', $input); + } + $this->not_inurl = self::removeEmptyValues($this->not_inurl); + return $input; + } + /** * Parse the search string to find date keyword and the search related * to it. @@ -155,7 +220,7 @@ class FreshRSS_Search { * @return string */ private function parseDateSearch($input) { - if (preg_match_all('/date:(?P[^\s]*)/', $input, $matches)) { + if (preg_match_all('/\bdate:(?P[^\s]*)/', $input, $matches)) { $input = str_replace($matches[0], '', $input); $dates = self::removeEmptyValues($matches['search']); if (!empty($dates[0])) { @@ -174,7 +239,7 @@ class FreshRSS_Search { * @return string */ private function parsePubdateSearch($input) { - if (preg_match_all('/pubdate:(?P[^\s]*)/', $input, $matches)) { + if (preg_match_all('/\bpubdate:(?P[^\s]*)/', $input, $matches)) { $input = str_replace($matches[0], '', $input); $dates = self::removeEmptyValues($matches['search']); if (!empty($dates[0])) { @@ -201,6 +266,15 @@ class FreshRSS_Search { return $input; } + private function parseNotTagsSeach($input) { + if (preg_match_all('/[!-]#(?P[^\s]+)/', $input, $matches)) { + $this->not_tags = $matches['search']; + $input = str_replace($matches[0], '', $input); + } + $this->not_tags = self::removeEmptyValues($this->not_tags); + return $input; + } + /** * Parse the search string to find search values. * Every word is a distinct search value, except when using a delimiter. @@ -211,7 +285,7 @@ class FreshRSS_Search { */ private function parseSearch($input) { $input = self::cleanSearch($input); - if (strcmp($input, '') == 0) { + if ($input == '') { return; } if (preg_match_all('/(?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { @@ -219,7 +293,7 @@ class FreshRSS_Search { $input = str_replace($matches[0], '', $input); } $input = self::cleanSearch($input); - if (strcmp($input, '') == 0) { + if ($input == '') { return; } if (is_array($this->search)) { @@ -229,6 +303,26 @@ class FreshRSS_Search { } } + private function parseNotSearch($input) { + $input = self::cleanSearch($input); + if ($input == '') { + return; + } + if (preg_match_all('/[!-](?P[\'"])(?P.*)(?P=delim)/U', $input, $matches)) { + $this->not_search = $matches['search']; + $input = str_replace($matches[0], '', $input); + } + if ($input == '') { + return; + } + if (preg_match_all('/[!-](?P[^\s]+)/', $input, $matches)) { + $this->not_search = array_merge(is_array($this->not_search) ? $this->not_search : array(), $matches['search']); + $input = str_replace($matches[0], '', $input); + } + $this->not_search = self::removeEmptyValues($this->not_search); + return $input; + } + /** * Remove all unnecessary spaces in the search * -- cgit v1.2.3 From 3011bbc5e1360a6b01f3ea652eae509a0bb5f164 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 2 Apr 2017 11:55:20 +0200 Subject: Search allow double quotes `author:"some name"` --- app/Models/Search.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app') diff --git a/app/Models/Search.php b/app/Models/Search.php index 2e89ea05b..5cc7f8e8d 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -35,6 +35,8 @@ class FreshRSS_Search { } $this->raw_input = $input; + $input = preg_replace('/:"(.*?)"/', ':"\1"', $input); + $input = $this->parseNotIntitleSearch($input); $input = $this->parseNotAuthorSearch($input); $input = $this->parseNotInurlSearch($input); -- cgit v1.2.3 From d42a20506ba07ec72d2d618db095ec853e51f9c1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Apr 2017 14:44:18 +0200 Subject: Fallback when GUID is empty https://github.com/FreshRSS/FreshRSS/issues/1482 --- app/Models/Entry.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/Entry.php b/app/Models/Entry.php index a562a963a..2946e839d 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -22,7 +22,6 @@ class FreshRSS_Entry extends Minz_Model { public function __construct($feed = '', $guid = '', $title = '', $author = '', $content = '', $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { - $this->_guid($guid); $this->_title($title); $this->_author($author); $this->_content($content); @@ -32,6 +31,7 @@ class FreshRSS_Entry extends Minz_Model { $this->_isFavorite($is_favorite); $this->_feed($feed); $this->_tags(preg_split('/[\s#]/', $tags)); + $this->_guid($guid); } public function id() { @@ -101,6 +101,12 @@ class FreshRSS_Entry extends Minz_Model { $this->id = $value; } public function _guid($value) { + if ($value == '') { + $value = $this->title; + if ($value == '') { + $value = $this->hash(); + } + } $this->guid = $value; } public function _title($value) { -- cgit v1.2.3 From dadd6e7beed41b7a7f3473fda60f7fcb57a9f866 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Apr 2017 14:50:16 +0200 Subject: Use link instead of title fallback --- app/Models/Entry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 2946e839d..26cd24797 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -102,7 +102,7 @@ class FreshRSS_Entry extends Minz_Model { } public function _guid($value) { if ($value == '') { - $value = $this->title; + $value = $this->link; if ($value == '') { $value = $this->hash(); } -- cgit v1.2.3 From a542ab8fff7cd13ef54f5585f029b6c1d2244351 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 8 Apr 2017 18:12:12 +0200 Subject: Make fileinfo extension optional --- app/install.php | 2 +- lib/lib_install.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/install.php b/app/install.php index f598f6528..ebfffa47d 100644 --- a/app/install.php +++ b/app/install.php @@ -465,7 +465,7 @@ function printStep1() {

-

+

diff --git a/lib/lib_install.php b/lib/lib_install.php index 76871c98a..c625a670a 100644 --- a/lib/lib_install.php +++ b/lib/lib_install.php @@ -67,7 +67,7 @@ function checkRequirements($dbType = '') { 'favicons' => $favicons ? 'ok' : 'ko', 'http_referer' => $http_referer ? 'ok' : 'ko', 'message' => $message ?: 'ok', - 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $fileinfo && $dom && $xml && + 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && $data && $cache && $users && $favicons && $http_referer && $message == '' ? 'ok' : 'ko' ); -- cgit v1.2.3 From 1749a1072a4a0b09bbc535aa279814d74a7bccbf Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 8 Apr 2017 19:47:53 +0200 Subject: Revert i18n en: gen.action.actualize https://github.com/FreshRSS/FreshRSS/pull/1465/files#r109282131 https://github.com/FreshRSS/FreshRSS/pull/1465 https://github.com/FreshRSS/FreshRSS/issues/1464 --- app/i18n/en/gen.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index d6ae266b7..a502e829a 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -2,7 +2,7 @@ return array( 'action' => array( - 'actualize' => 'Updating', + 'actualize' => 'Actualize', 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'cancel' => 'Cancel', 'create' => 'Create', -- cgit v1.2.3 From 0ce43be9de5bf676ceffa2e419941863f98fa970 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 9 Apr 2017 00:25:04 +0200 Subject: Multi-user token https://github.com/FreshRSS/FreshRSS/issues/1390 https://github.com/FreshRSS/FreshRSS/issues/366 --- app/Controllers/authController.php | 9 ++------- app/Controllers/userController.php | 4 ++++ app/Models/Auth.php | 27 +++++++++++++++++++++++---- app/layout/nav_menu.phtml | 1 + app/views/auth/index.phtml | 13 ------------- app/views/user/profile.phtml | 13 +++++++++++++ lib/lib_rss.php | 3 +++ 7 files changed, 46 insertions(+), 24 deletions(-) (limited to 'app') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 1398e4e49..5ad1a51d9 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -27,11 +27,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $current_token = FreshRSS_Context::$user_conf->token; - $token = Minz_Request::param('token', $current_token); - FreshRSS_Context::$user_conf->token = $token; - $ok &= FreshRSS_Context::$user_conf->save(); - $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); $anon_refresh = Minz_Request::param('anon_refresh', false); @@ -123,7 +118,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $challenge = Minz_Request::param('challenge', ''); $conf = get_user_configuration($username); - if (is_null($conf)) { + if ($conf == null) { Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false); return; } @@ -164,7 +159,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { } $conf = get_user_configuration($username); - if (is_null($conf)) { + if ($conf == null) { return; } diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index f910cecd9..ee575fa09 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -74,6 +74,10 @@ class FreshRSS_user_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash; } + $current_token = FreshRSS_Context::$user_conf->token; + $token = Minz_Request::param('token', $current_token); + FreshRSS_Context::$user_conf->token = $token; + $ok &= FreshRSS_Context::$user_conf->save(); if ($ok) { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 476627e10..4de058999 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -74,6 +74,10 @@ class FreshRSS_Auth { public static function giveAccess() { $current_user = Minz_Session::param('currentUser'); $user_conf = get_user_configuration($current_user); + if ($user_conf == null) { + self::$login_ok = false; + return; + } $system_conf = Minz_Configuration::get('system'); switch ($system_conf->auth_type) { @@ -120,13 +124,28 @@ class FreshRSS_Auth { * Removes all accesses for the current user. */ public static function removeAccess() { - Minz_Session::_param('loginOk'); self::$login_ok = false; - $conf = Minz_Configuration::get('system'); - Minz_Session::_param('currentUser', $conf->default_user); + Minz_Session::_param('loginOk'); Minz_Session::_param('csrf'); + $system_conf = Minz_Configuration::get('system'); - switch ($conf->auth_type) { + $username = ''; + $token_param = Minz_Request::param('token', ''); + if ($token_param != '') { + $username = trim(Minz_Request::param('user', '')); + if ($username != '') { + $conf = get_user_configuration($username); + if ($conf == null) { + $username = ''; + } + } + } + if ($username == '') { + $username = $system_conf->default_user; + } + Minz_Session::_param('currentUser', $username); + + switch ($system_conf->auth_type) { case 'form': Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index f6d824d55..04ee03cd6 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -149,6 +149,7 @@ token) { + $url_output['params']['user'] = Minz_Session::param('currentUser'); $url_output['params']['token'] = FreshRSS_Context::$user_conf->token; } if (FreshRSS_Context::$user_conf->since_hours_posts_per_rss) { diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml index 010eae33f..20966f24e 100644 --- a/app/views/auth/index.phtml +++ b/app/views/auth/index.phtml @@ -52,19 +52,6 @@ - -
- - token; ?> -
- data-leave-validation=""/> - - 'rss', 'params' => array('token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true); ?> -
-
- -
+ +
+ + token; ?> +
+ data-leave-validation=""/> + + 'rss', 'params' => array('user' => Minz_Session::param('currentUser'), 'token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true); ?> +
+
+ +
diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 4298e90bf..247cc707b 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -334,6 +334,9 @@ function max_registrations_reached() { * @return a Minz_Configuration object, null if the configuration cannot be loaded. */ function get_user_configuration($username) { + if (!FreshRSS_user_Controller::checkUsername($username)) { + return null; + } $namespace = 'user_' . $username; try { Minz_Configuration::register($namespace, -- cgit v1.2.3 From 5d54e47ff4065167a07085df07a590372ac5d636 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 10 Apr 2017 00:43:18 +0200 Subject: Fix DROP tables for deferred insertion https://github.com/FreshRSS/FreshRSS/pull/1470 --- app/SQL/install.sql.mysql.php | 2 +- app/SQL/install.sql.pgsql.php | 2 +- app/SQL/install.sql.sqlite.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 6b07f5965..09defd452 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -92,7 +92,7 @@ INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) V INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS @ GitHub", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400); '); -define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS `%1$sentry`, `%1$sfeed`, `%1$scategory`'); +define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS `%1$sentrytmp`, `%1$sentry`, `%1$sfeed`, `%1$scategory`'); define('SQL_UPDATE_UTF8MB4', ' ALTER DATABASE `%2$s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 74c6d1b79..4cfeb2517 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -84,4 +84,4 @@ $SQL_INSERT_FEEDS = array( 'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl) SELECT \'https://github.com/FreshRSS/FreshRSS/releases.atom\', 1, \'FreshRSS @ GitHub\', \'https://github.com/FreshRSS/FreshRSS/\', \'FreshRSS releases @ GitHub\', 86400 WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'https://github.com/FreshRSS/FreshRSS/releases.atom\');', ); -define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS "%1$sentry", "%1$sfeed", "%1$scategory"'); +define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS "%1$sentrytmp", "%1$sentry", "%1$sfeed", "%1$scategory"'); diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index bce9f5a95..c4e4af006 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -86,4 +86,4 @@ $SQL_INSERT_FEEDS = array( 'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS releases", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);', ); -define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS entry, feed, category'); +define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS `entrytmp`, `entry`, `feed`, `category`'); -- cgit v1.2.3 From 535aa35ba70d8cc584f37388692022272ab883b2 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 10 Apr 2017 19:09:21 +0200 Subject: PSHB better unsubscribe Cases when a user is deleted, or when a feed is deleted. Removed random key do reduce the risk of subscribing several times to the same PSHB feed. --- app/Controllers/userController.php | 1 + app/Models/Feed.php | 15 ++++++++------- p/api/pshb.php | 39 +++++++++++++++++++++++++++++--------- 3 files changed, 39 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index f910cecd9..ddc0c6fe4 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -213,6 +213,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->deleteUser($username); $ok &= recursive_unlink($user_data); + array_map('unlink', glob(PSHB_PATH . '/feeds/*/' . $username . '.txt')); } return $ok; } diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 7a9cf8612..1bc6e48e8 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -429,7 +429,7 @@ class FreshRSS_Feed extends Minz_Model { } } else { @mkdir($path, 0777, true); - $key = sha1($path . FreshRSS_Context::$system_conf->salt . uniqid(mt_rand(), true)); + $key = sha1($path . FreshRSS_Context::$system_conf->salt); $hubJson = array( 'hub' => $this->hubUrl, 'key' => $key, @@ -451,15 +451,16 @@ class FreshRSS_Feed extends Minz_Model { //Parameter true to subscribe, false to unsubscribe. function pubSubHubbubSubscribe($state) { - if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl) { - $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl) . '/!hub.json'; + $url = $this->selfUrl ? $this->selfUrl : $this->url; + if (FreshRSS_Context::$system_conf->base_url && $url) { + $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json'; $hubFile = @file_get_contents($hubFilename); if ($hubFile === false) { Minz_Log::warning('JSON not found for PubSubHubbub: ' . $this->url); return false; } $hubJson = json_decode($hubFile, true); - if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) { + if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key']) || empty($hubJson['hub'])) { Minz_Log::warning('Invalid JSON for PubSubHubbub: ' . $this->url); return false; } @@ -474,13 +475,13 @@ class FreshRSS_Feed extends Minz_Model { } $ch = curl_init(); curl_setopt_array($ch, array( - CURLOPT_URL => $this->hubUrl, + CURLOPT_URL => $hubJson['hub'], CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => 'FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')', CURLOPT_POSTFIELDS => 'hub.verify=sync' . '&hub.mode=' . ($state ? 'subscribe' : 'unsubscribe') - . '&hub.topic=' . urlencode($this->selfUrl) + . '&hub.topic=' . urlencode($url) . '&hub.callback=' . urlencode($callbackUrl) ) ); @@ -488,7 +489,7 @@ class FreshRSS_Feed extends Minz_Model { $info = curl_getinfo($ch); file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . - 'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $this->selfUrl . + 'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $url . ' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response . "\n", FILE_APPEND); if (substr($info['http_code'], 0, 1) == '2') { diff --git a/p/api/pshb.php b/p/api/pshb.php index e9b66b167..378f43516 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -23,8 +23,13 @@ if (!ctype_xdigit($key)) { chdir(PSHB_PATH); $canonical64 = @file_get_contents('keys/' . $key . '.txt'); if ($canonical64 === false) { + if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'unsubscribe') { + logMe('Warning: Accept unknown unsubscribe'); + header('Connection: close'); + exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : ''); + } header('HTTP/1.1 404 Not Found'); - logMe('Error: Feed key not found!: ' . $key); + logMe('Warning: Feed key not found!: ' . $key); die('Feed key not found!'); } $canonical64 = trim($canonical64); @@ -36,7 +41,7 @@ if (!preg_match('/^[A-Za-z0-9_-]+$/D', $canonical64)) { $hubFile = @file_get_contents('feeds/' . $canonical64 . '/!hub.json'); if ($hubFile === false) { header('HTTP/1.1 404 Not Found'); - //@unlink('keys/' . $key . '.txt'); + unlink('keys/' . $key . '.txt'); logMe('Error: Feed info not found!: ' . $canonical64); die('Feed info not found!'); } @@ -50,8 +55,19 @@ chdir('feeds/' . $canonical64); $users = glob('*.txt', GLOB_NOSORT); if (empty($users)) { header('HTTP/1.1 410 Gone'); - logMe('Error: Nobody is subscribed to this feed anymore!: ' . $canonical64); - die('Nobody is subscribed to this feed anymore!'); + $url = base64url_decode($canonical64); + logMe('Warning: Nobody subscribes to this feed anymore!: ' . $url); + unlink('../../keys/' . $key . '.txt'); + Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); + FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); + $feed = new FreshRSS_Feed($url); + $feed->pubSubHubbubSubscribe(false); + unlink('!hub.json'); + chdir('..'); + recursive_unlink($canonical64); + die('Nobody subscribes to this feed anymore!'); } if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'subscribe') { @@ -108,7 +124,9 @@ $nb = 0; foreach ($users as $userFilename) { $username = basename($userFilename, '.txt'); if (!file_exists(USERS_PATH . '/' . $username . '/config.php')) { - break; + logMe('Warning: Removing broken user link: ' . $username . ' for ' . $self); + unlink($userFilename); + continue; } try { @@ -119,11 +137,14 @@ foreach ($users as $userFilename) { new Minz_ModelPdo($username); //TODO: FIXME: Quick-fix while waiting for a better FreshRSS() constructor/init FreshRSS_Context::init(); list($updated_feeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); - if ($updated_feeds > 0) { + if ($updated_feeds > 0 || $feed != false) { $nb++; + } else { + logMe('Warning: User ' . $username . ' does not subscribe anymore to ' . $self); + unlink($userFilename); } } catch (Exception $e) { - logMe('Error: ' . $e->getMessage()); + logMe('Error: ' . $e->getMessage() . ' for user ' . $username . ' and feed ' . $self); } } @@ -132,8 +153,8 @@ unset($simplePie); if ($nb === 0) { header('HTTP/1.1 410 Gone'); - logMe('Error: Nobody is subscribed to this feed anymore after all!: ' . $self); - die('Nobody is subscribed to this feed anymore after all!'); + logMe('Warning: Nobody subscribes to this feed anymore after all!: ' . $self); + die('Nobody subscribes to this feed anymore after all!'); } elseif (!empty($hubJson['error'])) { $hubJson['error'] = false; file_put_contents('./!hub.json', json_encode($hubJson)); -- cgit v1.2.3 From 9ce0bca45ff01be50bd254a85b0f51eff429c5da Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Apr 2017 22:47:19 +0200 Subject: fix: Fix update via ZIP archive Code from the update server was not loaded anymore before the update process. This commit brings back missing `require`. --- CHANGELOG.md | 1 + app/Controllers/updateController.php | 1 + 2 files changed, 2 insertions(+) (limited to 'app') diff --git a/CHANGELOG.md b/CHANGELOG.md index 504886a23..3b576aac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * (Require manual update for existing installations) * Do not require PHP extension `fileinfo` for favicons [#1461](https://github.com/FreshRSS/FreshRSS/issues/1461) * Fix UI lowest subscription popup hidden [#1479](https://github.com/FreshRSS/FreshRSS/issues/1479) + * Fix update system via ZIP archive [#1498](https://github.com/FreshRSS/FreshRSS/pull/1498) * I18n * Improve English [#1465](https://github.com/FreshRSS/FreshRSS/pull/1465) * Misc. diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index b4e8a0bff..35c7d1124 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -190,6 +190,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { if (self::isGit()) { $res = self::gitPull(); } else { + require(UPDATE_FILENAME); if (Minz_Request::isPost()) { save_info_update(); } -- cgit v1.2.3 From 1e5b151d88cfe25391a1daf77da99b81cf6f8414 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 27 Apr 2017 20:25:26 +0200 Subject: Work around for IE / Edge pattern bug Swap order of regex alternatives https://github.com/FreshRSS/FreshRSS/issues/1511 http://stackoverflow.com/questions/22360235/do-browsers-support-different-html5-pattern-regexp-features https://connect.microsoft.com/ie/feedback/details/836117/regex-bug-in-pattern-validator --- CHANGELOG.md | 1 + app/Controllers/userController.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb5155d3..13b980e9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * Do not require PHP extension `fileinfo` for favicons [#1461](https://github.com/FreshRSS/FreshRSS/issues/1461) * Fix UI lowest subscription popup hidden [#1479](https://github.com/FreshRSS/FreshRSS/issues/1479) * Fix update system via ZIP archive [#1498](https://github.com/FreshRSS/FreshRSS/pull/1498) + * Work around for IE / Edge bug in username pattern in version 1.6.3 [#1511](https://github.com/FreshRSS/FreshRSS/issues/1511) * I18n * Improve English [#1465](https://github.com/FreshRSS/FreshRSS/pull/1465) * Misc. diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index ed30eb69f..3cbbd8633 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -38,7 +38,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { * The username is also used as folder name, file name, and part of SQL table name. * '_' is a reserved internal username. */ - const USERNAME_PATTERN = '[0-9a-zA-Z]|[0-9a-zA-Z_]{2,38}'; + const USERNAME_PATTERN = '[0-9a-zA-Z_]{2,38}|[0-9a-zA-Z]'; public static function checkUsername($username) { return preg_match('/^' . self::USERNAME_PATTERN . '$/', $username) === 1; -- cgit v1.2.3 From 09787cfd7a68e994f248c0cad0ebe5ae68b7aaf3 Mon Sep 17 00:00:00 2001 From: Seokseong Jeon Date: Wed, 3 May 2017 22:52:31 +0900 Subject: actualizeFeed return number of new articles as 3rd --- app/Controllers/feedController.php | 4 +++- cli/actualize-user.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index f71f26a4e..eec3b92bc 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -254,6 +254,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration. $updated_feeds = 0; + $nb_new_articles = 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { $url = $feed->url(); //For detection of HTTP 301 @@ -372,6 +373,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->beginTransaction(); } $entryDAO->addEntry($entry->toArray()); + $nb_new_articles++; } } $entryDAO->updateLastSeen($feed->id(), $oldGuids, $mtime); @@ -434,7 +436,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { break; } } - return array($updated_feeds, reset($feeds)); + return array($updated_feeds, reset($feeds), $nb_new_articles); } /** diff --git a/cli/actualize-user.php b/cli/actualize-user.php index 29d51753a..932c6975c 100755 --- a/cli/actualize-user.php +++ b/cli/actualize-user.php @@ -14,9 +14,9 @@ $username = cliInitUser($options['user']); fwrite(STDERR, 'FreshRSS actualizing user “' . $username . "”…\n"); -list($nbUpdatedFeeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, '', true); +list($nbUpdatedFeeds, $feed, $nbNewArticles) = FreshRSS_feed_Controller::actualizeFeed(0, '', true); -echo "FreshRSS actualized $nbUpdatedFeeds feeds for $username\n"; +echo "FreshRSS actualized $nbUpdatedFeeds feeds for $username ($nbNewArticles new articles)\n"; invalidateHttpCache($username); -- cgit v1.2.3 From 0bc59ba140b19d8e0a1762e5ffed66b0c61bd322 Mon Sep 17 00:00:00 2001 From: Seokseong Jeon Date: Fri, 5 May 2017 17:16:39 +0900 Subject: Make actualizeFeed returns values consistent&safe --- app/Controllers/feedController.php | 2 +- p/api/pshb.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index b8679d86d..8e0e5dd6d 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -482,7 +482,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->updateCachedValues(); $entryDAO->commit(); } else { - list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); + list($updated_feeds, $feed, $nb_new_articles) = self::actualizeFeed($id, $url, $force, null, false, $noCommit); } if (Minz_Request::param('ajax')) { diff --git a/p/api/pshb.php b/p/api/pshb.php index 378f43516..a0b64ede1 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -136,7 +136,7 @@ foreach ($users as $userFilename) { join_path(USERS_PATH, '_', 'config.default.php')); new Minz_ModelPdo($username); //TODO: FIXME: Quick-fix while waiting for a better FreshRSS() constructor/init FreshRSS_Context::init(); - list($updated_feeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); + list($updated_feeds, $feed, $nb_new_articles) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); if ($updated_feeds > 0 || $feed != false) { $nb++; } else { -- cgit v1.2.3 From e9e6fc34833ce56b9728063b2afc3e56d4d9dff3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 7 May 2017 17:00:46 +0200 Subject: Download icon 💾 for other MIME types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/FreshRSS/FreshRSS/issues/1236#issuecomment-299627105 --- app/Models/Feed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 1bc6e48e8..f6059e9de 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -328,7 +328,7 @@ class FreshRSS_Feed extends Minz_Model { } elseif (strpos($mime, 'video/') === 0) { $content .= '

💾

'; } else { - unset($elinks[$elink]); + $content .= '

💾

'; } } } -- cgit v1.2.3 From 77e698617d27c3f8605be3af600bce87a636caa2 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 7 May 2017 22:38:29 +0200 Subject: Fix download regression https://github.com/FreshRSS/FreshRSS/issues/1236#issuecomment-299732610 --- app/Models/Feed.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index f6059e9de..78a78543a 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -318,7 +318,7 @@ class FreshRSS_Feed extends Minz_Model { $elinks = array(); foreach ($item->get_enclosures() as $enclosure) { $elink = $enclosure->get_link(); - if (empty($elinks[$elink])) { + if ($elink != '' && empty($elinks[$elink])) { $elinks[$elink] = '1'; $mime = strtolower($enclosure->get_type()); if (strpos($mime, 'image/') === 0) { @@ -327,8 +327,10 @@ class FreshRSS_Feed extends Minz_Model { $content .= '

💾

'; } elseif (strpos($mime, 'video/') === 0) { $content .= '

💾

'; - } else { + } elseif (strpos($mime, 'application/') === 0 || strpos($mime, 'text/') === 0) { $content .= '

💾

'; + } else { + unset($elinks[$elink]); } } } -- cgit v1.2.3 From af8960b8b3be3c78573d0319a8a537083fae2d4d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 12 May 2017 23:33:58 +0200 Subject: Move default configuration files https://github.com/FreshRSS/FreshRSS/issues/1531 --- README.fr.md | 2 +- README.md | 2 +- app/FreshRSS.php | 2 +- app/install.php | 4 +- cli/_cli.php | 2 +- config-user.default.php | 75 ++++++++++++++++++++ config.default.php | 152 ++++++++++++++++++++++++++++++++++++++++ data/config.default.php | 152 ---------------------------------------- data/users/_/config.default.php | 75 -------------------- lib/Minz/FrontController.php | 2 +- lib/lib_install.php | 4 +- lib/lib_rss.php | 2 +- p/api/greader.php | 2 +- p/api/index.php | 2 +- p/api/pshb.php | 6 +- 15 files changed, 242 insertions(+), 242 deletions(-) create mode 100644 config-user.default.php create mode 100644 config.default.php delete mode 100644 data/config.default.php delete mode 100644 data/users/_/config.default.php (limited to 'app') diff --git a/README.fr.md b/README.fr.md index 5e78ad803..b7a28fd91 100644 --- a/README.fr.md +++ b/README.fr.md @@ -52,7 +52,7 @@ Nous sommes une communauté amicale. 4. Accédez à FreshRSS à travers votre navigateur Web et suivez les instructions d’installation * ou utilisez [l’interface en ligne de commande](./cli/README.md) 5. Tout devrait fonctionner :) En cas de problème, n’hésitez pas à [nous contacter](https://github.com/FreshRSS/FreshRSS/issues). -6. Des paramètres de configuration avancée peuvent être accédés depuis [config.php](./data/config.default.php). +6. Des paramètres de configuration avancée peuvent être vues dans [config.default.php](./config.default.php) et modifiées dans `data/config.php`. ## Installation automatisée * [![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/gh-pages/img/deploy.png)](https://dfabric.github.io/DPlatform-ShellCore) diff --git a/README.md b/README.md index 4c50acdd7..8e0d8bac9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ We are a friendly community. 4. Access FreshRSS with your browser and follow the installation process * or use the [Command-Line Interface](./cli/README.md) 5. Everything should be working :) If you encounter any problem, feel free [contact us](https://github.com/FreshRSS/FreshRSS/issues). -6. Advanced configuration settings can be seen in [config.php](./data/config.default.php). +6. Advanced configuration settings can be seen in [config.default.php](./config.default.php) and modified in `data/config.php`. ## Automated install * [![Install on Cloudron](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=org.freshrss.cloudronapp) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index e4caf23d1..563393c90 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -41,7 +41,7 @@ class FreshRSS extends Minz_FrontController { $current_user = Minz_Session::param('currentUser', '_'); Minz_Configuration::register('user', join_path(USERS_PATH, $current_user, 'config.php'), - join_path(USERS_PATH, '_', 'config.default.php'), + join_path(FRESHRSS_PATH, 'config-user.default.php'), $configuration_setter); // Finish to initialize the other FreshRSS / Minz components. diff --git a/app/install.php b/app/install.php index ebfffa47d..9e474ca73 100644 --- a/app/install.php +++ b/app/install.php @@ -88,13 +88,13 @@ function saveStep1() { // First, we try to get previous configurations Minz_Configuration::register('system', join_path(DATA_PATH, 'config.php'), - join_path(DATA_PATH, 'config.default.php')); + join_path(FRESHRSS_PATH, 'config.default.php')); $system_conf = Minz_Configuration::get('system'); $current_user = $system_conf->default_user; Minz_Configuration::register('user', join_path(USERS_PATH, $current_user, 'config.php'), - join_path(USERS_PATH, '_', 'config.default.php')); + join_path(FRESHRSS_PATH, 'config-user.default.php')); $user_conf = Minz_Configuration::get('user'); // Then, we set $_SESSION vars diff --git a/cli/_cli.php b/cli/_cli.php index f5e36eabc..1b26ea738 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -8,7 +8,7 @@ require(LIB_PATH . '/lib_rss.php'); Minz_Configuration::register('system', DATA_PATH . '/config.php', - DATA_PATH . '/config.default.php'); + FRESHRSS_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); Minz_Translate::init('en'); diff --git a/config-user.default.php b/config-user.default.php new file mode 100644 index 000000000..f28ef9724 --- /dev/null +++ b/config-user.default.php @@ -0,0 +1,75 @@ + 'en', + 'old_entries' => 3, + 'keep_history_default' => 50, + 'ttl_default' => 3600, + 'mail_login' => '', + 'token' => '', + 'passwordHash' => '', + 'apiPasswordHash' => '', + 'posts_per_page' => 20, + 'since_hours_posts_per_rss' => 168, + 'min_posts_per_rss' => 2, + 'max_posts_per_rss' => 400, + 'view_mode' => 'normal', + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, + 'auto_load_more' => true, + 'display_posts' => false, + 'display_categories' => false, + 'hide_read_feeds' => true, + 'onread_jump_next' => true, + 'lazyload' => true, + 'sticky_post' => true, + 'reading_confirm' => false, + 'auto_remove_article' => false, + + # In the case an article has changed (e.g. updated content): + # Set to `true` to mark it unread, or `false` to leave it as-is. + 'mark_updated_article_unread' => false, //TODO: -1 => ignore, 0 => update, 1 => update and mark as unread + + 'sort_order' => 'DESC', + 'anon_access' => false, + 'mark_when' => array ( + 'article' => true, + 'site' => true, + 'scroll' => true, + 'reception' => false, + ), + 'theme' => 'Origine', + 'content_width' => 'thin', + 'shortcuts' => array ( + 'mark_read' => 'r', + 'mark_favorite' => 'f', + 'go_website' => 'space', + 'next_entry' => 'j', + 'prev_entry' => 'k', + 'first_entry' => 'home', + 'last_entry' => 'end', + 'collapse_entry' => 'c', + 'load_more' => 'm', + 'auto_share' => 's', + 'focus_search' => 'a', + 'user_filter' => 'u', + 'help' => 'f1', + 'close_dropdown' => 'escape', + ), + 'topline_read' => true, + 'topline_favorite' => true, + 'topline_date' => true, + 'topline_link' => true, + 'bottomline_read' => true, + 'bottomline_favorite' => true, + 'bottomline_sharing' => true, + 'bottomline_tags' => true, + 'bottomline_date' => true, + 'bottomline_link' => true, + 'sharing' => array ( + ), + 'queries' => array ( + ), + 'html5_notif_timeout' => 0, + 'extensions_enabled' => array(), +); diff --git a/config.default.php b/config.default.php new file mode 100644 index 000000000..748df1884 --- /dev/null +++ b/config.default.php @@ -0,0 +1,152 @@ + 'production', + + # Used to make crypto more unique. Generated during install. + 'salt' => '', + + # Specify address of the FreshRSS instance, + # used when building absolute URLs, e.g. for PubSubHubbub. + # Examples: + # https://example.net/FreshRSS/p/ + # https://freshrss.example.net/ + 'base_url' => '', + + # Specify address of the FreshRSS auto-update server. + 'auto_update_url' => 'https://update.freshrss.org', + + # Natural language of the user interface, e.g. `en`, `fr`. + 'language' => 'en', + + # Title of this FreshRSS instance in the Web user interface. + 'title' => 'FreshRSS', + + # Meta description used when `allow_robots` is true. + 'meta_description' => '', + + # Name of the user that has administration rights. + 'default_user' => '_', + + # Allow or not visitors without login to see the articles + # of the default user. + 'allow_anonymous' => false, + + # Allow or not anonymous users to start the refresh process. + 'allow_anonymous_refresh' => false, + + # Login method: + # `none` is without password and shows only the default user; + # `form` is a conventional Web login form; + # `http_auth` is an access controled by the HTTP Web server (e.g. `/FreshRSS/p/i/.htaccess` for Apache) + # if you use `http_auth`, remember to protect only `/FreshRSS/p/i/`, + # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). + 'auth_type' => 'form', + + # Allow or not the use of the API, used for mobile apps. + # End-point is http://example.net/FreshRSS/p/api/greader.php + # You need to set the user's API password. + 'api_enabled' => false, + + # Allow or not the use of an unsafe login, + # by providing username and password in the login URL: + # http://example.net/FreshRSS/p/i/?c=auth&a=login&u=alice&p=1234 + 'unsafe_autologin_enabled' => false, + + # Enable or not the use of syslog to log the activity of + # SimplePie, which is retrieving RSS feeds via HTTP requests. + 'simplepie_syslog_enabled' => true, + + # Enable or not support of PubSubHubbub. + # /!\ It should NOT be enabled if base_url is not reachable by an external server. + 'pubsubhubbub_enabled' => false, + + # Allow or not Web robots (e.g. search engines) in HTML headers. + 'allow_robots' => false, + + # If true does nothing, if false restricts HTTP Referer via: meta referrer origin + 'allow_referrer' => false, + + 'limits' => array( + + # Duration in seconds of the login cookie. + 'cookie_duration' => 2592000, + + # Duration in seconds of the SimplePie cache, + # during which a query to the RSS feed will return the local cached version. + # Especially important for multi-user setups. + 'cache_duration' => 800, + + # SimplePie HTTP request timeout in seconds. + 'timeout' => 15, + + # If a user has not used FreshRSS for more than x seconds, + # then its feeds are not refreshed anymore. + 'max_inactivity' => PHP_INT_MAX, + + # Max number of feeds for a user. + 'max_feeds' => 16384, + + # Max number of categories for a user. + 'max_categories' => 16384, + + # Max number of accounts that anonymous users can create + # 0 for an unlimited number of accounts + # 1 is to not allow user registrations (1 is corresponding to the admin account) + 'max_registrations' => 1, + ), + + # Options used by cURL when making HTTP requests, e.g. when the SimplePie library retrieves feeds. + # http://php.net/manual/function.curl-setopt + 'curl_options' => array( + # Options to disable SSL/TLS certificate check (e.g. for self-signed HTTPS) + //CURLOPT_SSL_VERIFYHOST => 0, + //CURLOPT_SSL_VERIFYPEER => false, + + # Options to use a proxy for retrieving feeds. + //CURLOPT_PROXYTYPE => CURLPROXY_HTTP, + //CURLOPT_PROXY => '127.0.0.1', + //CURLOPT_PROXYPORT => 8080, + //CURLOPT_PROXYAUTH => CURLAUTH_BASIC, + //CURLOPT_PROXYUSERPWD => 'user:password', + ), + + 'db' => array( + + # Type of database: `sqlite` or `mysql`. + 'type' => 'sqlite', + + # MySQL host. + 'host' => 'localhost', + + # MySQL user. + 'user' => '', + + # MySQL password. + 'password' => '', + + # MySQL database. + 'base' => '', + + # MySQL table prefix. + 'prefix' => 'freshrss_', + + 'pdo_options' => array( + //PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem', + //PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem', + //PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca-cert.pem', + ), + + ), + + # List of enabled FreshRSS extensions. + 'extensions_enabled' => array(), + + # Disable self-update, + 'disable_update' => false, +); diff --git a/data/config.default.php b/data/config.default.php deleted file mode 100644 index 748df1884..000000000 --- a/data/config.default.php +++ /dev/null @@ -1,152 +0,0 @@ - 'production', - - # Used to make crypto more unique. Generated during install. - 'salt' => '', - - # Specify address of the FreshRSS instance, - # used when building absolute URLs, e.g. for PubSubHubbub. - # Examples: - # https://example.net/FreshRSS/p/ - # https://freshrss.example.net/ - 'base_url' => '', - - # Specify address of the FreshRSS auto-update server. - 'auto_update_url' => 'https://update.freshrss.org', - - # Natural language of the user interface, e.g. `en`, `fr`. - 'language' => 'en', - - # Title of this FreshRSS instance in the Web user interface. - 'title' => 'FreshRSS', - - # Meta description used when `allow_robots` is true. - 'meta_description' => '', - - # Name of the user that has administration rights. - 'default_user' => '_', - - # Allow or not visitors without login to see the articles - # of the default user. - 'allow_anonymous' => false, - - # Allow or not anonymous users to start the refresh process. - 'allow_anonymous_refresh' => false, - - # Login method: - # `none` is without password and shows only the default user; - # `form` is a conventional Web login form; - # `http_auth` is an access controled by the HTTP Web server (e.g. `/FreshRSS/p/i/.htaccess` for Apache) - # if you use `http_auth`, remember to protect only `/FreshRSS/p/i/`, - # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). - 'auth_type' => 'form', - - # Allow or not the use of the API, used for mobile apps. - # End-point is http://example.net/FreshRSS/p/api/greader.php - # You need to set the user's API password. - 'api_enabled' => false, - - # Allow or not the use of an unsafe login, - # by providing username and password in the login URL: - # http://example.net/FreshRSS/p/i/?c=auth&a=login&u=alice&p=1234 - 'unsafe_autologin_enabled' => false, - - # Enable or not the use of syslog to log the activity of - # SimplePie, which is retrieving RSS feeds via HTTP requests. - 'simplepie_syslog_enabled' => true, - - # Enable or not support of PubSubHubbub. - # /!\ It should NOT be enabled if base_url is not reachable by an external server. - 'pubsubhubbub_enabled' => false, - - # Allow or not Web robots (e.g. search engines) in HTML headers. - 'allow_robots' => false, - - # If true does nothing, if false restricts HTTP Referer via: meta referrer origin - 'allow_referrer' => false, - - 'limits' => array( - - # Duration in seconds of the login cookie. - 'cookie_duration' => 2592000, - - # Duration in seconds of the SimplePie cache, - # during which a query to the RSS feed will return the local cached version. - # Especially important for multi-user setups. - 'cache_duration' => 800, - - # SimplePie HTTP request timeout in seconds. - 'timeout' => 15, - - # If a user has not used FreshRSS for more than x seconds, - # then its feeds are not refreshed anymore. - 'max_inactivity' => PHP_INT_MAX, - - # Max number of feeds for a user. - 'max_feeds' => 16384, - - # Max number of categories for a user. - 'max_categories' => 16384, - - # Max number of accounts that anonymous users can create - # 0 for an unlimited number of accounts - # 1 is to not allow user registrations (1 is corresponding to the admin account) - 'max_registrations' => 1, - ), - - # Options used by cURL when making HTTP requests, e.g. when the SimplePie library retrieves feeds. - # http://php.net/manual/function.curl-setopt - 'curl_options' => array( - # Options to disable SSL/TLS certificate check (e.g. for self-signed HTTPS) - //CURLOPT_SSL_VERIFYHOST => 0, - //CURLOPT_SSL_VERIFYPEER => false, - - # Options to use a proxy for retrieving feeds. - //CURLOPT_PROXYTYPE => CURLPROXY_HTTP, - //CURLOPT_PROXY => '127.0.0.1', - //CURLOPT_PROXYPORT => 8080, - //CURLOPT_PROXYAUTH => CURLAUTH_BASIC, - //CURLOPT_PROXYUSERPWD => 'user:password', - ), - - 'db' => array( - - # Type of database: `sqlite` or `mysql`. - 'type' => 'sqlite', - - # MySQL host. - 'host' => 'localhost', - - # MySQL user. - 'user' => '', - - # MySQL password. - 'password' => '', - - # MySQL database. - 'base' => '', - - # MySQL table prefix. - 'prefix' => 'freshrss_', - - 'pdo_options' => array( - //PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem', - //PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem', - //PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca-cert.pem', - ), - - ), - - # List of enabled FreshRSS extensions. - 'extensions_enabled' => array(), - - # Disable self-update, - 'disable_update' => false, -); diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php deleted file mode 100644 index f28ef9724..000000000 --- a/data/users/_/config.default.php +++ /dev/null @@ -1,75 +0,0 @@ - 'en', - 'old_entries' => 3, - 'keep_history_default' => 50, - 'ttl_default' => 3600, - 'mail_login' => '', - 'token' => '', - 'passwordHash' => '', - 'apiPasswordHash' => '', - 'posts_per_page' => 20, - 'since_hours_posts_per_rss' => 168, - 'min_posts_per_rss' => 2, - 'max_posts_per_rss' => 400, - 'view_mode' => 'normal', - 'default_view' => 'adaptive', - 'default_state' => FreshRSS_Entry::STATE_NOT_READ, - 'auto_load_more' => true, - 'display_posts' => false, - 'display_categories' => false, - 'hide_read_feeds' => true, - 'onread_jump_next' => true, - 'lazyload' => true, - 'sticky_post' => true, - 'reading_confirm' => false, - 'auto_remove_article' => false, - - # In the case an article has changed (e.g. updated content): - # Set to `true` to mark it unread, or `false` to leave it as-is. - 'mark_updated_article_unread' => false, //TODO: -1 => ignore, 0 => update, 1 => update and mark as unread - - 'sort_order' => 'DESC', - 'anon_access' => false, - 'mark_when' => array ( - 'article' => true, - 'site' => true, - 'scroll' => true, - 'reception' => false, - ), - 'theme' => 'Origine', - 'content_width' => 'thin', - 'shortcuts' => array ( - 'mark_read' => 'r', - 'mark_favorite' => 'f', - 'go_website' => 'space', - 'next_entry' => 'j', - 'prev_entry' => 'k', - 'first_entry' => 'home', - 'last_entry' => 'end', - 'collapse_entry' => 'c', - 'load_more' => 'm', - 'auto_share' => 's', - 'focus_search' => 'a', - 'user_filter' => 'u', - 'help' => 'f1', - 'close_dropdown' => 'escape', - ), - 'topline_read' => true, - 'topline_favorite' => true, - 'topline_date' => true, - 'topline_link' => true, - 'bottomline_read' => true, - 'bottomline_favorite' => true, - 'bottomline_sharing' => true, - 'bottomline_tags' => true, - 'bottomline_date' => true, - 'bottomline_link' => true, - 'sharing' => array ( - ), - 'queries' => array ( - ), - 'html5_notif_timeout' => 0, - 'extensions_enabled' => array(), -); diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index f9eff3db6..952d983c9 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -33,7 +33,7 @@ class Minz_FrontController { try { Minz_Configuration::register('system', DATA_PATH . '/config.php', - DATA_PATH . '/config.default.php'); + FRESHRSS_PATH . '/config.default.php'); $this->setReporting(); Minz_Request::init(); diff --git a/lib/lib_install.php b/lib/lib_install.php index c625a670a..bf81c15b4 100644 --- a/lib/lib_install.php +++ b/lib/lib_install.php @@ -2,8 +2,8 @@ define('BCRYPT_COST', 9); -Minz_Configuration::register('default_system', join_path(DATA_PATH, 'config.default.php')); -Minz_Configuration::register('default_user', join_path(USERS_PATH, '_', 'config.default.php')); +Minz_Configuration::register('default_system', join_path(FRESHRSS_PATH, 'config.default.php')); +Minz_Configuration::register('default_user', join_path(FRESHRSS_PATH, 'config-user.default.php')); function checkRequirements($dbType = '') { $php = version_compare(PHP_VERSION, '5.3.3') >= 0; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 247cc707b..1bf387712 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -341,7 +341,7 @@ function get_user_configuration($username) { try { Minz_Configuration::register($namespace, join_path(USERS_PATH, $username, 'config.php'), - join_path(USERS_PATH, '_', 'config.default.php')); + join_path(FRESHRSS_PATH, 'config-user.default.php')); } catch (Minz_ConfigurationNamespaceException $e) { // namespace already exists, do nothing. } catch (Minz_FileNotExistException $e) { diff --git a/p/api/greader.php b/p/api/greader.php index 01eca6d4f..e1f4202a7 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -695,7 +695,7 @@ $pathInfos = explode('/', $pathInfo); Minz_Configuration::register('system', DATA_PATH . '/config.php', - DATA_PATH . '/config.default.php'); + FRESHRSS_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); if (!FreshRSS_Context::$system_conf->api_enabled) { serviceUnavailable(); diff --git a/p/api/index.php b/p/api/index.php index 3ab4e02b3..580c90255 100644 --- a/p/api/index.php +++ b/p/api/index.php @@ -16,7 +16,7 @@
diff --git a/p/api/pshb.php b/p/api/pshb.php index a0b64ede1..4b546908a 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -60,7 +60,7 @@ if (empty($users)) { unlink('../../keys/' . $key . '.txt'); Minz_Configuration::register('system', DATA_PATH . '/config.php', - DATA_PATH . '/config.default.php'); + FRESHRSS_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); $feed = new FreshRSS_Feed($url); $feed->pubSubHubbubSubscribe(false); @@ -101,7 +101,7 @@ if ($ORIGINAL_INPUT == '') { die('Missing XML payload!'); } -Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php'); +Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php'); $system_conf = Minz_Configuration::get('system'); $system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) @@ -133,7 +133,7 @@ foreach ($users as $userFilename) { Minz_Session::_param('currentUser', $username); Minz_Configuration::register('user', join_path(USERS_PATH, $username, 'config.php'), - join_path(USERS_PATH, '_', 'config.default.php')); + join_path(FRESHRSS_PATH, 'config-user.default.php')); new Minz_ModelPdo($username); //TODO: FIXME: Quick-fix while waiting for a better FreshRSS() constructor/init FreshRSS_Context::init(); list($updated_feeds, $feed, $nb_new_articles) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); -- cgit v1.2.3 From 67dd80f84250f7e8b1b39693f5fef2ff27ffb85a Mon Sep 17 00:00:00 2001 From: Paulius Šukys Date: Mon, 22 May 2017 09:33:55 +0200 Subject: Added additional configuration setting for #1530 . This includes default settings and translation entry for English --- app/Controllers/configureController.php | 1 + app/Models/ConfigurationSetter.php | 4 ++++ app/i18n/en/conf.php | 1 + app/views/configure/reading.phtml | 10 ++++++++++ app/views/helpers/javascript_vars.phtml | 1 + data/users/_/config.default.php | 1 + p/scripts/main.js | 8 ++++++++ 7 files changed, 26 insertions(+) (limited to 'app') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index e73f106a6..155221d19 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -109,6 +109,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->hide_read_feeds = Minz_Request::param('hide_read_feeds', false); FreshRSS_Context::$user_conf->onread_jump_next = Minz_Request::param('onread_jump_next', false); FreshRSS_Context::$user_conf->lazyload = Minz_Request::param('lazyload', false); + FreshRSS_Context::$user_conf->sides_close_article = Minz_Request::param('sides_close_article', false); FreshRSS_Context::$user_conf->sticky_post = Minz_Request::param('sticky_post', false); FreshRSS_Context::$user_conf->reading_confirm = Minz_Request::param('reading_confirm', false); FreshRSS_Context::$user_conf->auto_remove_article = Minz_Request::param('auto_remove_article', false); diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 046f54955..70e1dea2e 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -197,6 +197,10 @@ class FreshRSS_ConfigurationSetter { $data['hide_read_feeds'] = $this->handleBool($value); } + private function _sides_close_article(&$data, $value) { + $data['sides_close_article'] = $this->handleBool($value); + } + private function _lazyload(&$data, $value) { $data['lazyload'] = $this->handleBool($value); } diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index b5ab73510..032c5fe4c 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -93,6 +93,7 @@ return array( 'display_categories_unfolded' => 'Show categories folded by default', 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', + 'sides_close_article' => 'Clicking outside of article text area closes the article', 'jump_next' => 'jump to next unread sibling (feed or category)', 'number_divided_when_reader' => 'Divided by 2 in the reading view.', 'read' => array( diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 07dabf15f..ebb00c97b 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -106,6 +106,16 @@
+
+
+ +
+
+