summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Controllers/apiController.php10
-rw-r--r--app/Controllers/authController.php63
-rw-r--r--app/Controllers/categoryController.php34
-rw-r--r--app/Controllers/configureController.php171
-rw-r--r--app/Controllers/entryController.php2
-rw-r--r--app/Controllers/extensionController.php10
-rw-r--r--app/Controllers/feedController.php43
-rw-r--r--app/Controllers/importExportController.php8
-rw-r--r--app/Controllers/indexController.php16
-rw-r--r--app/Controllers/javascriptController.php11
-rw-r--r--app/Controllers/subscriptionController.php28
-rw-r--r--app/Controllers/tagController.php6
-rw-r--r--app/Controllers/updateController.php6
-rw-r--r--app/Controllers/userController.php61
-rw-r--r--app/FreshRSS.php34
-rw-r--r--app/Mailers/UserMailer.php4
-rw-r--r--app/Models/AttributesTrait.php60
-rw-r--r--app/Models/Auth.php38
-rw-r--r--app/Models/BooleanSearch.php12
-rw-r--r--app/Models/Category.php4
-rw-r--r--app/Models/CategoryDAO.php25
-rw-r--r--app/Models/Context.php82
-rw-r--r--app/Models/DatabaseDAO.php4
-rw-r--r--app/Models/DatabaseDAOPGSQL.php4
-rw-r--r--app/Models/DatabaseDAOSQLite.php6
-rw-r--r--app/Models/Entry.php53
-rw-r--r--app/Models/EntryDAO.php84
-rw-r--r--app/Models/EntryDAOSQLite.php2
-rw-r--r--app/Models/Factory.php12
-rw-r--r--app/Models/Feed.php74
-rw-r--r--app/Models/FeedDAO.php16
-rw-r--r--app/Models/FilterAction.php2
-rw-r--r--app/Models/FilterActionsTrait.php18
-rw-r--r--app/Models/FormAuth.php8
-rw-r--r--app/Models/StatsDAO.php2
-rw-r--r--app/Models/SystemConfiguration.php5
-rw-r--r--app/Models/TagDAO.php6
-rw-r--r--app/Models/Themes.php5
-rw-r--r--app/Models/UserConfiguration.php42
-rw-r--r--app/Services/ImportService.php8
-rw-r--r--app/Utils/feverUtil.php5
-rwxr-xr-xapp/actualize_script.php23
-rw-r--r--app/install.php43
-rw-r--r--app/layout/aside_configure.phtml6
-rw-r--r--app/layout/aside_feed.phtml16
-rw-r--r--app/layout/header.phtml14
-rw-r--r--app/layout/layout.phtml14
-rw-r--r--app/layout/nav_menu.phtml21
-rw-r--r--app/layout/simple.phtml8
-rw-r--r--app/views/auth/index.phtml28
-rw-r--r--app/views/category/update.phtml2
-rw-r--r--app/views/configure/archiving.phtml52
-rw-r--r--app/views/configure/display.phtml94
-rw-r--r--app/views/configure/integration.phtml5
-rw-r--r--app/views/configure/reading.phtml148
-rw-r--r--app/views/configure/shortcut.phtml2
-rw-r--r--app/views/configure/system.phtml40
-rw-r--r--app/views/feed/add.phtml2
-rw-r--r--app/views/feed/contentSelectorPreview.phtml2
-rw-r--r--app/views/helpers/category/update.phtml28
-rw-r--r--app/views/helpers/configure/query.phtml3
-rw-r--r--app/views/helpers/export/opml.phtml10
-rw-r--r--app/views/helpers/extension/configure.phtml3
-rw-r--r--app/views/helpers/extension/details.phtml3
-rw-r--r--app/views/helpers/feed/update.phtml97
-rw-r--r--app/views/helpers/index/normal/entry_bottom.phtml18
-rw-r--r--app/views/helpers/index/normal/entry_header.phtml23
-rw-r--r--app/views/helpers/javascript_vars.phtml22
-rw-r--r--app/views/helpers/stream-footer.phtml4
-rw-r--r--app/views/index/about.phtml4
-rw-r--r--app/views/index/global.phtml6
-rw-r--r--app/views/index/normal.phtml35
-rw-r--r--app/views/index/reader.phtml28
-rw-r--r--app/views/index/rss.phtml2
-rw-r--r--app/views/stats/idle.phtml6
-rw-r--r--app/views/subscription/index.phtml6
-rw-r--r--app/views/user/manage.phtml2
-rw-r--r--app/views/user/profile.phtml8
-rw-r--r--app/views/user/validateEmail.phtml4
-rw-r--r--cli/_cli.php9
-rw-r--r--cli/_update-or-create-user.php2
-rwxr-xr-xcli/actualize-user.php4
-rwxr-xr-xcli/create-user.php2
-rwxr-xr-xcli/db-optimize.php2
-rwxr-xr-xcli/delete-user.php6
-rwxr-xr-xcli/do-install.php4
-rwxr-xr-xcli/export-opml-for-user.php2
-rwxr-xr-xcli/export-sqlite-for-user.php2
-rwxr-xr-xcli/export-zip-for-user.php2
-rw-r--r--cli/i18n/I18nData.php2
-rw-r--r--cli/i18n/I18nValue.php2
-rwxr-xr-xcli/import-for-user.php2
-rwxr-xr-xcli/import-sqlite-for-user.php2
-rwxr-xr-xcli/list-users.php6
-rwxr-xr-xcli/reconfigure.php67
-rwxr-xr-xcli/user-info.php12
-rw-r--r--composer.json2
-rw-r--r--composer.lock107
-rw-r--r--config-user.default.php5
-rw-r--r--config.default.php2
-rw-r--r--lib/Minz/Configuration.php4
-rw-r--r--lib/Minz/Extension.php100
-rw-r--r--lib/Minz/ExtensionManager.php14
-rw-r--r--lib/Minz/Helper.php6
-rw-r--r--lib/Minz/ModelPdo.php2
-rw-r--r--lib/Minz/Request.php10
-rw-r--r--lib/Minz/Session.php2
-rw-r--r--lib/Minz/Translate.php7
-rw-r--r--lib/Minz/Url.php10
-rw-r--r--lib/Minz/View.php2
-rw-r--r--lib/favicons.php5
-rw-r--r--lib/lib_install.php9
-rw-r--r--lib/lib_rss.php33
-rw-r--r--p/api/fever.php21
-rw-r--r--p/api/greader.php46
-rw-r--r--p/api/pshb.php10
-rw-r--r--p/ext.php4
-rw-r--r--phpstan.neon9
-rw-r--r--tests/phpstan-next.txt66
119 files changed, 1347 insertions, 1173 deletions
diff --git a/app/Controllers/apiController.php b/app/Controllers/apiController.php
index 7568f9831..2d9fad535 100644
--- a/app/Controllers/apiController.php
+++ b/app/Controllers/apiController.php
@@ -13,18 +13,20 @@ class FreshRSS_api_Controller extends FreshRSS_ActionController {
*/
public static function updatePassword(string $apiPasswordPlain) {
$username = Minz_User::name();
- $userConfig = FreshRSS_Context::$user_conf;
+ if ($username == null) {
+ return _t('feedback.api.password.failed');
+ }
$apiPasswordHash = FreshRSS_password_Util::hash($apiPasswordPlain);
- $userConfig->apiPasswordHash = $apiPasswordHash;
+ FreshRSS_Context::userConf()->apiPasswordHash = $apiPasswordHash;
$feverKey = FreshRSS_fever_Util::updateKey($username, $apiPasswordPlain);
if (!$feverKey) {
return _t('feedback.api.password.failed');
}
- $userConfig->feverKey = $feverKey;
- if ($userConfig->save()) {
+ FreshRSS_Context::userConf()->feverKey = $feverKey;
+ if (FreshRSS_Context::userConf()->save()) {
return false;
} else {
return _t('feedback.api.password.failed');
diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php
index 06eca7d9e..85a722761 100644
--- a/app/Controllers/authController.php
+++ b/app/Controllers/authController.php
@@ -28,23 +28,26 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
$anon = Minz_Request::paramBoolean('anon_access');
$anon_refresh = Minz_Request::paramBoolean('anon_refresh');
- $auth_type = Minz_Request::paramString('auth_type') ?: 'none';
+ $auth_type = Minz_Request::paramString('auth_type') ?: 'form';
$unsafe_autologin = Minz_Request::paramBoolean('unsafe_autologin');
$api_enabled = Minz_Request::paramBoolean('api_enabled');
- if ($anon !== FreshRSS_Context::$system_conf->allow_anonymous ||
- $auth_type !== FreshRSS_Context::$system_conf->auth_type ||
- $anon_refresh !== FreshRSS_Context::$system_conf->allow_anonymous_refresh ||
- $unsafe_autologin !== FreshRSS_Context::$system_conf->unsafe_autologin_enabled ||
- $api_enabled !== FreshRSS_Context::$system_conf->api_enabled) {
-
- // TODO: test values from form
- FreshRSS_Context::$system_conf->auth_type = $auth_type;
- FreshRSS_Context::$system_conf->allow_anonymous = $anon;
- FreshRSS_Context::$system_conf->allow_anonymous_refresh = $anon_refresh;
- FreshRSS_Context::$system_conf->unsafe_autologin_enabled = $unsafe_autologin;
- FreshRSS_Context::$system_conf->api_enabled = $api_enabled;
-
- $ok &= FreshRSS_Context::$system_conf->save();
+ if ($anon !== FreshRSS_Context::systemConf()->allow_anonymous ||
+ $auth_type !== FreshRSS_Context::systemConf()->auth_type ||
+ $anon_refresh !== FreshRSS_Context::systemConf()->allow_anonymous_refresh ||
+ $unsafe_autologin !== FreshRSS_Context::systemConf()->unsafe_autologin_enabled ||
+ $api_enabled !== FreshRSS_Context::systemConf()->api_enabled) {
+
+ if (in_array($auth_type, ['form', 'http_auth', 'none'], true)) {
+ FreshRSS_Context::systemConf()->auth_type = $auth_type;
+ } else {
+ FreshRSS_Context::systemConf()->auth_type = 'form';
+ }
+ FreshRSS_Context::systemConf()->allow_anonymous = $anon;
+ FreshRSS_Context::systemConf()->allow_anonymous_refresh = $anon_refresh;
+ FreshRSS_Context::systemConf()->unsafe_autologin_enabled = $unsafe_autologin;
+ FreshRSS_Context::systemConf()->api_enabled = $api_enabled;
+
+ $ok &= FreshRSS_Context::systemConf()->save();
}
invalidateHttpCache();
@@ -69,7 +72,7 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
Minz_Request::forward(['c' => 'index', 'a' => 'index'], true);
}
- $auth_type = FreshRSS_Context::$system_conf->auth_type;
+ $auth_type = FreshRSS_Context::systemConf()->auth_type;
FreshRSS_Context::initUser(Minz_User::INTERNAL_USER, false);
switch ($auth_type) {
case 'form':
@@ -114,7 +117,7 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
FreshRSS_View::prependTitle(_t('gen.auth.login') . ' · ');
FreshRSS_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$this->view->cookie_days = (int)round($limits['cookie_duration'] / 86400, 1);
$isPOST = Minz_Request::isPost() && !Minz_Session::paramBoolean('POST_to_GET');
@@ -128,39 +131,39 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
usleep(random_int(100, 10000)); //Primitive mitigation of timing attacks, in μs
FreshRSS_Context::initUser($username);
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
// Initialise the default user to be able to display the error page
- FreshRSS_Context::initUser(FreshRSS_Context::$system_conf->default_user);
+ FreshRSS_Context::initUser(FreshRSS_Context::systemConf()->default_user);
Minz_Error::error(403, _t('feedback.auth.login.invalid'), false);
return;
}
- if (!FreshRSS_Context::$user_conf->enabled || FreshRSS_Context::$user_conf->passwordHash == '') {
+ if (!FreshRSS_Context::userConf()->enabled || FreshRSS_Context::userConf()->passwordHash == '') {
usleep(random_int(100, 5000)); //Primitive mitigation of timing attacks, in μs
Minz_Error::error(403, _t('feedback.auth.login.invalid'), false);
return;
}
$ok = FreshRSS_FormAuth::checkCredentials(
- $username, FreshRSS_Context::$user_conf->passwordHash, $nonce, $challenge
+ $username, FreshRSS_Context::userConf()->passwordHash, $nonce, $challenge
);
if ($ok) {
// Set session parameter to give access to the user.
Minz_Session::_params([
Minz_User::CURRENT_USER => $username,
- 'passwordHash' => FreshRSS_Context::$user_conf->passwordHash,
+ 'passwordHash' => FreshRSS_Context::userConf()->passwordHash,
'csrf' => false,
]);
FreshRSS_Auth::giveAccess();
// Set cookie parameter if needed.
if (Minz_Request::paramBoolean('keep_logged_in')) {
- FreshRSS_FormAuth::makeCookie($username, FreshRSS_Context::$user_conf->passwordHash);
+ FreshRSS_FormAuth::makeCookie($username, FreshRSS_Context::userConf()->passwordHash);
} else {
FreshRSS_FormAuth::deleteCookie();
}
- Minz_Translate::init(FreshRSS_Context::$user_conf->language);
+ Minz_Translate::init(FreshRSS_Context::userConf()->language);
// All is good, go back to the original request or the index.
$url = Minz_Url::unserialize(Minz_Request::paramString('original_request'));
@@ -176,7 +179,7 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
Minz_Request::setBadNotification(_t('feedback.auth.login.invalid'));
Minz_Request::forward(['c' => 'auth', 'a' => 'login'], false);
}
- } elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) {
+ } elseif (FreshRSS_Context::systemConf()->unsafe_autologin_enabled) {
$username = Minz_Request::paramString('u');
$password = Minz_Request::paramString('p');
Minz_Request::_param('p');
@@ -188,11 +191,11 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
FreshRSS_FormAuth::deleteCookie();
FreshRSS_Context::initUser($username);
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
return;
}
- $s = FreshRSS_Context::$user_conf->passwordHash;
+ $s = FreshRSS_Context::userConf()->passwordHash;
$ok = password_verify($password, $s);
unset($password);
if ($ok) {
@@ -203,7 +206,7 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
]);
FreshRSS_Auth::giveAccess();
- Minz_Translate::init(FreshRSS_Context::$user_conf->language);
+ Minz_Translate::init(FreshRSS_Context::userConf()->language);
Minz_Request::good(_t('feedback.auth.login.success'), ['c' => 'index', 'a' => 'index']);
} else {
@@ -242,8 +245,8 @@ class FreshRSS_auth_Controller extends FreshRSS_ActionController {
}
$this->view->show_tos_checkbox = file_exists(TOS_FILENAME);
- $this->view->show_email_field = FreshRSS_Context::$system_conf->force_email_validation;
- $this->view->preferred_language = Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), FreshRSS_Context::$system_conf->language);
+ $this->view->show_email_field = FreshRSS_Context::systemConf()->force_email_validation;
+ $this->view->preferred_language = Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), FreshRSS_Context::systemConf()->language);
FreshRSS_View::prependTitle(_t('gen.auth.registration.title') . ' · ');
}
diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php
index daee1666a..780f03f02 100644
--- a/app/Controllers/categoryController.php
+++ b/app/Controllers/categoryController.php
@@ -33,7 +33,7 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
$url_redirect = ['c' => 'subscription', 'a' => 'add'];
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$this->view->categories = $catDAO->listCategories(false) ?: [];
if (count($this->view->categories) >= $limits['max_categories']) {
@@ -61,10 +61,10 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
$opml_url = checkUrl(Minz_Request::paramString('opml_url'));
if ($opml_url != '') {
$cat->_kind(FreshRSS_Category::KIND_DYNAMIC_OPML);
- $cat->_attributes('opml_url', $opml_url);
+ $cat->_attribute('opml_url', $opml_url);
} else {
$cat->_kind(FreshRSS_Category::KIND_NORMAL);
- $cat->_attributes('opml_url', null);
+ $cat->_attribute('opml_url', null);
}
if ($catDAO->addCategoryObject($cat)) {
@@ -102,7 +102,7 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
$category->_filtersAction('read', Minz_Request::paramTextToArray('filteractions_read'));
if (Minz_Request::paramBoolean('use_default_purge_options')) {
- $category->_attributes('archiving', null);
+ $category->_attribute('archiving', null);
} else {
if (!Minz_Request::paramBoolean('enable_keep_max')) {
$keepMax = false;
@@ -117,7 +117,7 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
} else {
$keepPeriod = false;
}
- $category->_attributes('archiving', [
+ $category->_attribute('archiving', [
'keep_period' => $keepPeriod,
'keep_max' => $keepMax,
'keep_min' => Minz_Request::paramInt('keep_min'),
@@ -128,15 +128,15 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
}
$position = Minz_Request::paramInt('position') ?: null;
- $category->_attributes('position', $position);
+ $category->_attribute('position', $position);
$opml_url = checkUrl(Minz_Request::paramString('opml_url'));
if ($opml_url != '') {
$category->_kind(FreshRSS_Category::KIND_DYNAMIC_OPML);
- $category->_attributes('opml_url', $opml_url);
+ $category->_attribute('opml_url', $opml_url);
} else {
$category->_kind(FreshRSS_Category::KIND_NORMAL);
- $category->_attributes('opml_url', null);
+ $category->_attribute('opml_url', null);
}
$values = [
@@ -190,9 +190,10 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
}
// Remove related queries.
- FreshRSS_Context::$user_conf->queries = remove_query_by_get(
- 'c_' . $id, FreshRSS_Context::$user_conf->queries);
- FreshRSS_Context::$user_conf->save();
+ /** @var array<array{'get'?:string,'name'?:string,'order'?:string,'search'?:string,'state'?:int,'url'?:string}> $queries */
+ $queries = remove_query_by_get('c_' . $id, FreshRSS_Context::userConf()->queries);
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.sub.category.deleted'), $url_redirect);
}
@@ -230,10 +231,11 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
// Remove related queries
foreach ($feeds as $feed) {
- FreshRSS_Context::$user_conf->queries = remove_query_by_get(
- 'f_' . $feed->id(), FreshRSS_Context::$user_conf->queries);
+ /** @var array<array{'get'?:string,'name'?:string,'order'?:string,'search'?:string,'state'?:int,'url'?:string}> */
+ $queries = remove_query_by_get('f_' . $feed->id(), FreshRSS_Context::userConf()->queries);
+ FreshRSS_Context::userConf()->queries = $queries;
}
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.sub.category.emptied'), $url_redirect);
} else {
@@ -258,11 +260,13 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
$id = Minz_Request::paramInt('id');
if ($id === 0) {
Minz_Request::bad(_t('feedback.sub.category.no_id'), $url_redirect);
+ return;
}
$category = $catDAO->searchById($id);
if ($category === null) {
Minz_Request::bad(_t('feedback.sub.category.not_exist'), $url_redirect);
+ return;
}
invalidateHttpCache();
@@ -288,7 +292,7 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
$successes = 0;
$errors = 0;
$catDAO = FreshRSS_Factory::createCategoryDao();
- $categories = $catDAO->listCategoriesOrderUpdate(FreshRSS_Context::$user_conf->dynamic_opml_ttl_default ?? 86400);
+ $categories = $catDAO->listCategoriesOrderUpdate(FreshRSS_Context::userConf()->dynamic_opml_ttl_default ?? 86400);
foreach ($categories as $category) {
if ($category->refreshDynamicOpml()) {
$successes++;
diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php
index d7c087620..c52a5d23c 100644
--- a/app/Controllers/configureController.php
+++ b/app/Controllers/configureController.php
@@ -44,32 +44,32 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
*/
public function displayAction(): void {
if (Minz_Request::isPost()) {
- FreshRSS_Context::$user_conf->language = Minz_Request::paramString('language') ?: 'en';
- FreshRSS_Context::$user_conf->timezone = Minz_Request::paramString('timezone');
- FreshRSS_Context::$user_conf->theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme;
- FreshRSS_Context::$user_conf->darkMode = Minz_Request::paramString('darkMode') ?: 'no';
- FreshRSS_Context::$user_conf->content_width = Minz_Request::paramString('content_width') ?: 'thin';
- FreshRSS_Context::$user_conf->topline_read = Minz_Request::paramBoolean('topline_read');
- FreshRSS_Context::$user_conf->topline_favorite = Minz_Request::paramBoolean('topline_favorite');
- FreshRSS_Context::$user_conf->topline_date = Minz_Request::paramBoolean('topline_date');
- FreshRSS_Context::$user_conf->topline_link = Minz_Request::paramBoolean('topline_link');
- FreshRSS_Context::$user_conf->topline_website = Minz_Request::paramString('topline_website');
- FreshRSS_Context::$user_conf->topline_thumbnail = Minz_Request::paramString('topline_thumbnail');
- FreshRSS_Context::$user_conf->topline_summary = Minz_Request::paramBoolean('topline_summary');
- FreshRSS_Context::$user_conf->topline_display_authors = Minz_Request::paramBoolean('topline_display_authors');
- FreshRSS_Context::$user_conf->bottomline_read = Minz_Request::paramBoolean('bottomline_read');
- FreshRSS_Context::$user_conf->bottomline_favorite = Minz_Request::paramBoolean('bottomline_favorite');
- FreshRSS_Context::$user_conf->bottomline_sharing = Minz_Request::paramBoolean('bottomline_sharing');
- FreshRSS_Context::$user_conf->bottomline_tags = Minz_Request::paramBoolean('bottomline_tags');
- FreshRSS_Context::$user_conf->bottomline_myLabels = Minz_Request::paramBoolean('bottomline_myLabels');
- FreshRSS_Context::$user_conf->bottomline_date = Minz_Request::paramBoolean('bottomline_date');
- FreshRSS_Context::$user_conf->bottomline_link = Minz_Request::paramBoolean('bottomline_link');
- FreshRSS_Context::$user_conf->show_nav_buttons = Minz_Request::paramBoolean('show_nav_buttons');
- FreshRSS_Context::$user_conf->html5_notif_timeout = Minz_Request::paramInt('html5_notif_timeout');
- FreshRSS_Context::$user_conf->save();
-
- Minz_Session::_param('language', FreshRSS_Context::$user_conf->language);
- Minz_Translate::reset(FreshRSS_Context::$user_conf->language);
+ FreshRSS_Context::userConf()->language = Minz_Request::paramString('language') ?: 'en';
+ FreshRSS_Context::userConf()->timezone = Minz_Request::paramString('timezone');
+ FreshRSS_Context::userConf()->theme = Minz_Request::paramString('theme') ?: FreshRSS_Themes::$defaultTheme;
+ FreshRSS_Context::userConf()->darkMode = Minz_Request::paramString('darkMode') ?: 'no';
+ FreshRSS_Context::userConf()->content_width = Minz_Request::paramString('content_width') ?: 'thin';
+ FreshRSS_Context::userConf()->topline_read = Minz_Request::paramBoolean('topline_read');
+ FreshRSS_Context::userConf()->topline_favorite = Minz_Request::paramBoolean('topline_favorite');
+ FreshRSS_Context::userConf()->topline_date = Minz_Request::paramBoolean('topline_date');
+ FreshRSS_Context::userConf()->topline_link = Minz_Request::paramBoolean('topline_link');
+ FreshRSS_Context::userConf()->topline_website = Minz_Request::paramString('topline_website');
+ FreshRSS_Context::userConf()->topline_thumbnail = Minz_Request::paramString('topline_thumbnail');
+ FreshRSS_Context::userConf()->topline_summary = Minz_Request::paramBoolean('topline_summary');
+ FreshRSS_Context::userConf()->topline_display_authors = Minz_Request::paramBoolean('topline_display_authors');
+ FreshRSS_Context::userConf()->bottomline_read = Minz_Request::paramBoolean('bottomline_read');
+ FreshRSS_Context::userConf()->bottomline_favorite = Minz_Request::paramBoolean('bottomline_favorite');
+ FreshRSS_Context::userConf()->bottomline_sharing = Minz_Request::paramBoolean('bottomline_sharing');
+ FreshRSS_Context::userConf()->bottomline_tags = Minz_Request::paramBoolean('bottomline_tags');
+ FreshRSS_Context::userConf()->bottomline_myLabels = Minz_Request::paramBoolean('bottomline_myLabels');
+ FreshRSS_Context::userConf()->bottomline_date = Minz_Request::paramBoolean('bottomline_date');
+ FreshRSS_Context::userConf()->bottomline_link = Minz_Request::paramBoolean('bottomline_link');
+ FreshRSS_Context::userConf()->show_nav_buttons = Minz_Request::paramBoolean('show_nav_buttons');
+ FreshRSS_Context::userConf()->html5_notif_timeout = Minz_Request::paramInt('html5_notif_timeout');
+ FreshRSS_Context::userConf()->save();
+
+ Minz_Session::_param('language', FreshRSS_Context::userConf()->language);
+ Minz_Translate::reset(FreshRSS_Context::userConf()->language);
invalidateHttpCache();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'display' ]);
@@ -111,27 +111,31 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
*/
public function readingAction(): void {
if (Minz_Request::isPost()) {
- FreshRSS_Context::$user_conf->posts_per_page = Minz_Request::paramInt('posts_per_page') ?: 10;
- FreshRSS_Context::$user_conf->view_mode = Minz_Request::paramString('view_mode', true) ?: 'normal';
- FreshRSS_Context::$user_conf->default_view = Minz_Request::paramString('default_view') ?: 'adaptive';
- FreshRSS_Context::$user_conf->show_fav_unread = Minz_Request::paramBoolean('show_fav_unread');
- FreshRSS_Context::$user_conf->auto_load_more = Minz_Request::paramBoolean('auto_load_more');
- FreshRSS_Context::$user_conf->display_posts = Minz_Request::paramBoolean('display_posts');
- FreshRSS_Context::$user_conf->display_categories = Minz_Request::paramString('display_categories') ?: 'active';
- FreshRSS_Context::$user_conf->show_tags = Minz_Request::paramString('show_tags') ?: '0';
- FreshRSS_Context::$user_conf->show_tags_max = Minz_Request::paramInt('show_tags_max');
- FreshRSS_Context::$user_conf->show_author_date = Minz_Request::paramString('show_author_date') ?: '0';
- FreshRSS_Context::$user_conf->show_feed_name = Minz_Request::paramString('show_feed_name') ?: 't';
- FreshRSS_Context::$user_conf->hide_read_feeds = Minz_Request::paramBoolean('hide_read_feeds');
- FreshRSS_Context::$user_conf->onread_jump_next = Minz_Request::paramBoolean('onread_jump_next');
- FreshRSS_Context::$user_conf->lazyload = Minz_Request::paramBoolean('lazyload');
- FreshRSS_Context::$user_conf->sides_close_article = Minz_Request::paramBoolean('sides_close_article');
- FreshRSS_Context::$user_conf->sticky_post = Minz_Request::paramBoolean('sticky_post');
- FreshRSS_Context::$user_conf->reading_confirm = Minz_Request::paramBoolean('reading_confirm');
- FreshRSS_Context::$user_conf->auto_remove_article = Minz_Request::paramBoolean('auto_remove_article');
- FreshRSS_Context::$user_conf->mark_updated_article_unread = Minz_Request::paramBoolean('mark_updated_article_unread');
- FreshRSS_Context::$user_conf->sort_order = Minz_Request::paramString('sort_order') ?: 'DESC';
- FreshRSS_Context::$user_conf->mark_when = [
+ FreshRSS_Context::userConf()->posts_per_page = Minz_Request::paramInt('posts_per_page') ?: 10;
+ FreshRSS_Context::userConf()->view_mode = Minz_Request::paramString('view_mode', true) ?: 'normal';
+ FreshRSS_Context::userConf()->default_view = Minz_Request::paramString('default_view') ?: 'adaptive';
+ FreshRSS_Context::userConf()->show_fav_unread = Minz_Request::paramBoolean('show_fav_unread');
+ FreshRSS_Context::userConf()->auto_load_more = Minz_Request::paramBoolean('auto_load_more');
+ FreshRSS_Context::userConf()->display_posts = Minz_Request::paramBoolean('display_posts');
+ FreshRSS_Context::userConf()->display_categories = Minz_Request::paramString('display_categories') ?: 'active';
+ FreshRSS_Context::userConf()->show_tags = Minz_Request::paramString('show_tags') ?: '0';
+ FreshRSS_Context::userConf()->show_tags_max = Minz_Request::paramInt('show_tags_max');
+ FreshRSS_Context::userConf()->show_author_date = Minz_Request::paramString('show_author_date') ?: '0';
+ FreshRSS_Context::userConf()->show_feed_name = Minz_Request::paramString('show_feed_name') ?: 't';
+ FreshRSS_Context::userConf()->hide_read_feeds = Minz_Request::paramBoolean('hide_read_feeds');
+ FreshRSS_Context::userConf()->onread_jump_next = Minz_Request::paramBoolean('onread_jump_next');
+ FreshRSS_Context::userConf()->lazyload = Minz_Request::paramBoolean('lazyload');
+ FreshRSS_Context::userConf()->sides_close_article = Minz_Request::paramBoolean('sides_close_article');
+ FreshRSS_Context::userConf()->sticky_post = Minz_Request::paramBoolean('sticky_post');
+ FreshRSS_Context::userConf()->reading_confirm = Minz_Request::paramBoolean('reading_confirm');
+ FreshRSS_Context::userConf()->auto_remove_article = Minz_Request::paramBoolean('auto_remove_article');
+ FreshRSS_Context::userConf()->mark_updated_article_unread = Minz_Request::paramBoolean('mark_updated_article_unread');
+ if (in_array(Minz_Request::paramString('sort_order'), ['ASC', 'DESC'], true)) {
+ FreshRSS_Context::userConf()->sort_order = Minz_Request::paramString('sort_order');
+ } else {
+ FreshRSS_Context::userConf()->sort_order = 'DESC';
+ }
+ FreshRSS_Context::userConf()->mark_when = [
'article' => Minz_Request::paramBoolean('mark_open_article'),
'gone' => Minz_Request::paramBoolean('read_upon_gone'),
'max_n_unread' => Minz_Request::paramBoolean('enable_keep_max_n_unread') ? Minz_Request::paramInt('keep_max_n_unread') : false,
@@ -142,8 +146,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
'site' => Minz_Request::paramBoolean('mark_open_site'),
'focus' => Minz_Request::paramBoolean('mark_focus'),
];
- FreshRSS_Context::$user_conf->_filtersAction('read', Minz_Request::paramTextToArray('filteractions_read'));
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->_filtersAction('read', Minz_Request::paramTextToArray('filteractions_read'));
+ FreshRSS_Context::userConf()->save();
invalidateHttpCache();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'reading' ]);
@@ -168,8 +172,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
if (Minz_Request::isPost()) {
$params = $_POST;
- FreshRSS_Context::$user_conf->sharing = $params['share'];
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->sharing = $params['share'];
+ FreshRSS_Context::userConf()->save();
invalidateHttpCache();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'integration' ]);
@@ -199,8 +203,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$default = Minz_Configuration::load(FRESHRSS_PATH . '/config-user.default.php');
$shortcuts = $default['shortcuts'];
}
- FreshRSS_Context::$user_conf->shortcuts = array_map('trim', $shortcuts);
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->shortcuts = array_map('trim', $shortcuts);
+ FreshRSS_Context::userConf()->save();
invalidateHttpCache();
Minz_Request::good(_t('feedback.conf.shortcuts_updated'), ['c' => 'configure', 'a' => 'shortcut']);
@@ -237,8 +241,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$keepPeriod = false;
}
- FreshRSS_Context::$user_conf->ttl_default = Minz_Request::paramInt('ttl_default') ?: FreshRSS_Feed::TTL_DEFAULT;
- FreshRSS_Context::$user_conf->archiving = [
+ FreshRSS_Context::userConf()->ttl_default = Minz_Request::paramInt('ttl_default') ?: FreshRSS_Feed::TTL_DEFAULT;
+ FreshRSS_Context::userConf()->archiving = [
'keep_period' => $keepPeriod,
'keep_max' => $keepMax,
'keep_min' => Minz_Request::paramInt('keep_min_default'),
@@ -246,9 +250,9 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
'keep_labels' => Minz_Request::paramBoolean('keep_labels'),
'keep_unreads' => Minz_Request::paramBoolean('keep_unreads'),
];
- FreshRSS_Context::$user_conf->keep_history_default = null; //Legacy < FreshRSS 1.15
- FreshRSS_Context::$user_conf->old_entries = null; //Legacy < FreshRSS 1.15
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->keep_history_default = null; //Legacy < FreshRSS 1.15
+ FreshRSS_Context::userConf()->old_entries = null; //Legacy < FreshRSS 1.15
+ FreshRSS_Context::userConf()->save();
invalidateHttpCache();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'archiving' ]);
@@ -259,8 +263,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
'keep_period_count' => '3',
'keep_period_unit' => 'P1M',
];
- if (!empty(FreshRSS_Context::$user_conf->archiving['keep_period'])) {
- $keepPeriod = FreshRSS_Context::$user_conf->archiving['keep_period'];
+ if (!empty(FreshRSS_Context::userConf()->archiving['keep_period'])) {
+ $keepPeriod = FreshRSS_Context::userConf()->archiving['keep_period'];
if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $keepPeriod, $matches)) {
$volatile = [
'enable_keep_period' => true,
@@ -269,7 +273,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
];
}
}
- FreshRSS_Context::$user_conf->volatile = $volatile;
+ FreshRSS_Context::userConf()->volatile = $volatile;
$entryDAO = FreshRSS_Factory::createEntryDao();
$this->view->nb_total = $entryDAO->count();
@@ -316,13 +320,13 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
}
$queries[$key] = (new FreshRSS_UserQuery($query, $feed_dao, $category_dao, $tag_dao))->toArray();
}
- FreshRSS_Context::$user_conf->queries = $queries;
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'queries' ]);
} else {
$this->view->queries = [];
- foreach (FreshRSS_Context::$user_conf->queries as $key => $query) {
+ foreach (FreshRSS_Context::userConf()->queries as $key => $query) {
$this->view->queries[intval($key)] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao, $tag_dao);
}
}
@@ -354,7 +358,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
}
$id = Minz_Request::paramInt('id');
- if (Minz_Request::paramTernary('id') === null || empty(FreshRSS_Context::$user_conf->queries[$id])) {
+ if (Minz_Request::paramTernary('id') === null || empty(FreshRSS_Context::userConf()->queries[$id])) {
Minz_Error::error(404);
return;
}
@@ -363,7 +367,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$feed_dao = FreshRSS_Factory::createFeedDao();
$tag_dao = FreshRSS_Factory::createTagDao();
- $query = new FreshRSS_UserQuery(FreshRSS_Context::$user_conf->queries[$id], $feed_dao, $category_dao, $tag_dao);
+ $query = new FreshRSS_UserQuery(FreshRSS_Context::userConf()->queries[$id], $feed_dao, $category_dao, $tag_dao);
$this->view->query = $query;
$this->view->queryId = $id;
$this->view->categories = $category_dao->listCategories(false) ?: [];
@@ -371,7 +375,6 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$this->view->tags = $tag_dao->listTags() ?: [];
if (Minz_Request::isPost()) {
- /** @var array<string,string|array<string,string>> $params */
$params = array_filter(Minz_Request::paramArray('query'));
$queryParams = [];
if (!empty($params['get']) && is_string($params['get'])) {
@@ -393,10 +396,10 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$queryParams['name'] = $name;
$queryParams['url'] = Minz_Url::display(['params' => $queryParams]);
- $queries = FreshRSS_Context::$user_conf->queries;
+ $queries = FreshRSS_Context::userConf()->queries;
$queries[$id] = (new FreshRSS_UserQuery($queryParams, $feed_dao, $category_dao, $tag_dao))->toArray();
- FreshRSS_Context::$user_conf->queries = $queries;
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'queries', 'params' => ['id' => (string)$id] ]);
}
@@ -409,15 +412,15 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
*/
public function deleteQueryAction(): void {
$id = Minz_Request::paramInt('id');
- if (Minz_Request::paramTernary('id') === null || empty(FreshRSS_Context::$user_conf->queries[$id])) {
+ if (Minz_Request::paramTernary('id') === null || empty(FreshRSS_Context::userConf()->queries[$id])) {
Minz_Error::error(404);
return;
}
- $queries = FreshRSS_Context::$user_conf->queries;
+ $queries = FreshRSS_Context::userConf()->queries;
unset($queries[$id]);
- FreshRSS_Context::$user_conf->queries = $queries;
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.conf.updated'), [ 'c' => 'configure', 'a' => 'queries' ]);
}
@@ -434,7 +437,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$feed_dao = FreshRSS_Factory::createFeedDao();
$tag_dao = FreshRSS_Factory::createTagDao();
$queries = [];
- foreach (FreshRSS_Context::$user_conf->queries as $key => $query) {
+ foreach (FreshRSS_Context::userConf()->queries as $key => $query) {
$queries[$key] = (new FreshRSS_UserQuery($query, $feed_dao, $category_dao, $tag_dao))->toArray();
}
$params = $_GET;
@@ -443,8 +446,8 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
$params['name'] = _t('conf.query.number', count($queries) + 1);
$queries[] = (new FreshRSS_UserQuery($params, $feed_dao, $category_dao, $tag_dao))->toArray();
- FreshRSS_Context::$user_conf->queries = $queries;
- FreshRSS_Context::$user_conf->save();
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
Minz_Request::good(_t('feedback.conf.query_created', $params['name']), [ 'c' => 'configure', 'a' => 'queries' ]);
}
@@ -473,17 +476,17 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
}
if (Minz_Request::isPost()) {
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$limits['max_registrations'] = Minz_Request::paramInt('max-registrations') ?: 1;
$limits['max_feeds'] = Minz_Request::paramInt('max-feeds') ?: 16384;
$limits['max_categories'] = Minz_Request::paramInt('max-categories') ?: 16384;
$limits['cookie_duration'] = Minz_Request::paramInt('cookie-duration') ?: FreshRSS_Auth::DEFAULT_COOKIE_DURATION;
- FreshRSS_Context::$system_conf->limits = $limits;
- FreshRSS_Context::$system_conf->title = Minz_Request::paramString('instance-name') ?: 'FreshRSS';
- FreshRSS_Context::$system_conf->auto_update_url = Minz_Request::paramString('auto-update-url');
- FreshRSS_Context::$system_conf->force_email_validation = Minz_Request::paramBoolean('force-email-validation');
- FreshRSS_Context::$system_conf->base_url = Minz_Request::paramString('base-url');
- FreshRSS_Context::$system_conf->save();
+ FreshRSS_Context::systemConf()->limits = $limits;
+ FreshRSS_Context::systemConf()->title = Minz_Request::paramString('instance-name') ?: 'FreshRSS';
+ FreshRSS_Context::systemConf()->auto_update_url = Minz_Request::paramString('auto-update-url');
+ FreshRSS_Context::systemConf()->force_email_validation = Minz_Request::paramBoolean('force-email-validation');
+ FreshRSS_Context::systemConf()->base_url = Minz_Request::paramString('base-url');
+ FreshRSS_Context::systemConf()->save();
invalidateHttpCache();
diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php
index 1ce490ea1..c30c6b6fa 100644
--- a/app/Controllers/entryController.php
+++ b/app/Controllers/entryController.php
@@ -209,7 +209,7 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController {
$feedDAO->beginTransaction();
foreach ($feeds as $feed) {
- $nb_total += $feed->cleanOldEntries();
+ $nb_total += ($feed->cleanOldEntries() ?: 0);
}
$feedDAO->updateCachedValues();
diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php
index 0158b2f76..9cfc6ff68 100644
--- a/app/Controllers/extensionController.php
+++ b/app/Controllers/extensionController.php
@@ -54,7 +54,7 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController {
// fetch the list as an array
/** @var array<string,mixed> $list*/
$list = json_decode($json, true);
- if (empty($list)) {
+ if (empty($list) || !is_array($list)) {
Minz_Log::warning('Failed to convert extension file list');
return [];
}
@@ -136,9 +136,9 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController {
$conf = null;
if ($type === 'system') {
- $conf = FreshRSS_Context::$system_conf;
+ $conf = FreshRSS_Context::systemConf();
} elseif ($type === 'user') {
- $conf = FreshRSS_Context::$user_conf;
+ $conf = FreshRSS_Context::userConf();
}
$res = $ext->install();
@@ -198,9 +198,9 @@ class FreshRSS_extension_Controller extends FreshRSS_ActionController {
$conf = null;
if ($type === 'system') {
- $conf = FreshRSS_Context::$system_conf;
+ $conf = FreshRSS_Context::systemConf();
} elseif ($type === 'user') {
- $conf = FreshRSS_Context::$user_conf;
+ $conf = FreshRSS_Context::userConf();
}
$res = $ext->uninstall();
diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php
index aec39587e..cc560a224 100644
--- a/app/Controllers/feedController.php
+++ b/app/Controllers/feedController.php
@@ -15,11 +15,11 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
// Token is useful in the case that anonymous refresh is forbidden
// and CRON task cannot be used with php command so the user can
// set a CRON task to refresh his feeds by using token inside url
- $token = FreshRSS_Context::$user_conf->token;
+ $token = FreshRSS_Context::userConf()->token;
$token_param = Minz_Request::paramString('token');
$token_is_ok = ($token != '' && $token == $token_param);
$action = Minz_Request::actionName();
- $allow_anonymous_refresh = FreshRSS_Context::$system_conf->allow_anonymous_refresh;
+ $allow_anonymous_refresh = FreshRSS_Context::systemConf()->allow_anonymous_refresh;
if ($action !== 'actualize' ||
!($allow_anonymous_refresh || $token_is_ok)) {
Minz_Error::error(403);
@@ -45,7 +45,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$url = trim($url);
- /** @var string|null $url */
+ /** @var string|null $urlHooked */
$urlHooked = Minz_ExtensionManager::callHook('check_url_before_add', $url);
if ($urlHooked === null) {
throw new FreshRSS_FeedNotAdded_Exception($url);
@@ -72,7 +72,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$feed->_name($title);
}
$feed->_kind($kind);
- $feed->_attributes('', $attributes);
+ $feed->_attributes($attributes);
$feed->_httpAuth($http_auth);
$feed->_categoryId($cat_id);
switch ($kind) {
@@ -151,7 +151,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
'params' => [],
];
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$this->view->feeds = $feedDAO->listFeeds();
if (count($this->view->feeds) >= $limits['max_feeds']) {
Minz_Request::bad(_t('feedback.sub.feed.over_max', $limits['max_feeds']), $url_redirect);
@@ -377,7 +377,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
}
// WebSub (PubSubHubbub) support
- $pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled;
+ $pubsubhubbubEnabledGeneral = FreshRSS_Context::systemConf()->pubsubhubbub_enabled;
$pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration.
$updated_feeds = 0;
@@ -406,14 +406,14 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$mtime = $feed->cacheModifiedTime() ?: 0;
$ttl = $feed->ttl();
if ($ttl === FreshRSS_Feed::TTL_DEFAULT) {
- $ttl = FreshRSS_Context::$user_conf->ttl_default;
+ $ttl = FreshRSS_Context::userConf()->ttl_default;
}
if ($simplePiePush === null && $feed_id === null && (time() <= $feed->lastUpdate() + $ttl)) {
//Too early to refresh from source, but check whether the feed was updated by another user
$ε = 10; // negligible offset errors in seconds
if ($mtime <= 0 ||
$feed->lastUpdate() + $ε >= $mtime ||
- time() + $ε >= $mtime + FreshRSS_Context::$system_conf->limits['cache_duration']) { // is cache still valid?
+ time() + $ε >= $mtime + FreshRSS_Context::systemConf()->limits['cache_duration']) { // is cache still valid?
continue; //Nothing newer from other users
}
Minz_Log::debug('Feed ' . $feed->url(false) . ' was updated at ' . date('c', $feed->lastUpdate()) .
@@ -475,17 +475,20 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$nbMarkedUnread = 0;
if (count($newGuids) > 0) {
- $titlesAsRead = [];
- $readWhenSameTitleInFeed = $feed->attributes('read_when_same_title_in_feed');
- if ($readWhenSameTitleInFeed == false) {
- $readWhenSameTitleInFeed = FreshRSS_Context::$user_conf->mark_when['same_title_in_feed'];
+ if ($feed->attributeBoolean('read_when_same_title_in_feed') === null) {
+ $readWhenSameTitleInFeed = (int)FreshRSS_Context::userConf()->mark_when['same_title_in_feed'];
+ } elseif ($feed->attributeBoolean('read_when_same_title_in_feed') === false) {
+ $readWhenSameTitleInFeed = 0;
+ } else {
+ $readWhenSameTitleInFeed = $feed->attributeInt('read_when_same_title_in_feed') ?? 0;
}
if ($readWhenSameTitleInFeed > 0) {
- /** @var array<string,bool> $titlesAsRead*/
- $titlesAsRead = array_flip($feedDAO->listTitles($feed->id(), (int)$readWhenSameTitleInFeed));
+ $titlesAsRead = array_flip($feedDAO->listTitles($feed->id(), $readWhenSameTitleInFeed));
+ } else {
+ $titlesAsRead = [];
}
- $mark_updated_article_unread = $feed->attributes('mark_updated_article_unread') ?? FreshRSS_Context::$user_conf->mark_updated_article_unread;
+ $mark_updated_article_unread = $feed->attributeBoolean('mark_updated_article_unread') ?? FreshRSS_Context::userConf()->mark_updated_article_unread;
// For this feed, check existing GUIDs already in database.
$existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids) ?: [];
@@ -828,10 +831,10 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
// TODO: Delete old favicon
// Remove related queries
- FreshRSS_Context::$user_conf->queries = remove_query_by_get(
- 'f_' . $feed_id, FreshRSS_Context::$user_conf->queries);
- FreshRSS_Context::$user_conf->save();
-
+ /** @var array<array{'get'?:string,'name'?:string,'order'?:string,'search'?:string,'state'?:int,'url'?:string}> $queries */
+ $queries = remove_query_by_get('f_' . $feed_id, FreshRSS_Context::userConf()->queries);
+ FreshRSS_Context::userConf()->queries = $queries;
+ FreshRSS_Context::userConf()->save();
return true;
}
return false;
@@ -939,7 +942,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
//We need another DB connection in parallel for unbuffered streaming
Minz_ModelPdo::$usesSharedPdo = false;
- if (FreshRSS_Context::$system_conf->db['type'] === 'mysql') {
+ if (FreshRSS_Context::systemConf()->db['type'] === 'mysql') {
// Second parallel connection for unbuffered streaming: MySQL
$entryDAO2 = FreshRSS_Factory::createEntryDao();
} else {
diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php
index 6d37cc465..0de75d0ff 100644
--- a/app/Controllers/importExportController.php
+++ b/app/Controllers/importExportController.php
@@ -289,7 +289,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController {
*/
private function importJson(string $article_file, bool $starred = false): bool {
$article_object = json_decode($article_file, true);
- if ($article_object == null) {
+ if (!is_array($article_object)) {
if (FreshRSS_Context::$isCli) {
fwrite(STDERR, 'FreshRSS error trying to import a non-JSON file' . "\n");
} else {
@@ -299,14 +299,14 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController {
}
$items = $article_object['items'] ?? $article_object;
- $mark_as_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
+ $mark_as_read = FreshRSS_Context::userConf()->mark_when['reception'] ? 1 : 0;
$error = false;
$article_to_feed = [];
$nb_feeds = count($this->feedDAO->listFeeds());
$newFeedGuids = [];
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
// First, we check feeds of articles are in DB (and add them if needed).
foreach ($items as &$item) {
@@ -601,7 +601,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController {
return;
}
- $username = Minz_User::name();
+ $username = Minz_User::name() ?? '_';
$export_service = new FreshRSS_Export_Service($username);
$export_opml = Minz_Request::paramBoolean('export_opml');
diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php
index a1c25e649..a83307714 100644
--- a/app/Controllers/indexController.php
+++ b/app/Controllers/indexController.php
@@ -10,7 +10,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
* This action only redirect on the default view mode (normal or global)
*/
public function indexAction(): void {
- $preferred_output = FreshRSS_Context::$user_conf->view_mode;
+ $preferred_output = FreshRSS_Context::userConf()->view_mode;
Minz_Request::forward([
'c' => 'index',
'a' => $preferred_output,
@@ -21,7 +21,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
* This action displays the normal view of FreshRSS.
*/
public function normalAction(): void {
- $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous;
+ $allow_anonymous = FreshRSS_Context::systemConf()->allow_anonymous;
if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) {
Minz_Request::forward(['c' => 'auth', 'a' => 'login']);
return;
@@ -107,7 +107,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
* This action displays the global view of FreshRSS.
*/
public function globalAction(): void {
- $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous;
+ $allow_anonymous = FreshRSS_Context::systemConf()->allow_anonymous;
if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) {
Minz_Request::forward(['c' => 'auth', 'a' => 'login']);
return;
@@ -143,8 +143,8 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
* This action displays the RSS feed of FreshRSS.
*/
public function rssAction(): void {
- $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous;
- $token = FreshRSS_Context::$user_conf->token;
+ $allow_anonymous = FreshRSS_Context::systemConf()->allow_anonymous;
+ $token = FreshRSS_Context::userConf()->token;
$token_param = Minz_Request::paramString('token');
$token_is_ok = ($token != '' && $token === $token_param);
@@ -176,8 +176,8 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
}
public function opmlAction(): void {
- $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous;
- $token = FreshRSS_Context::$user_conf->token;
+ $allow_anonymous = FreshRSS_Context::systemConf()->allow_anonymous;
+ $token = FreshRSS_Context::userConf()->token;
$token_param = Minz_Request::paramString('token');
$token_is_ok = ($token != '' && $token === $token_param);
@@ -259,7 +259,7 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
$date_min = 0;
if (FreshRSS_Context::$sinceHours) {
$date_min = time() - (FreshRSS_Context::$sinceHours * 3600);
- $limit = FreshRSS_Context::$user_conf->max_posts_per_rss;
+ $limit = FreshRSS_Context::userConf()->max_posts_per_rss;
}
foreach ($entryDAO->listWhere(
diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php
index 6dd36dd72..a9c4993df 100644
--- a/app/Controllers/javascriptController.php
+++ b/app/Controllers/javascriptController.php
@@ -21,10 +21,10 @@ class FreshRSS_javascript_Controller extends FreshRSS_ActionController {
Minz_Session::_param('actualize_feeds', false);
$catDAO = FreshRSS_Factory::createCategoryDao();
- $this->view->categories = $catDAO->listCategoriesOrderUpdate(FreshRSS_Context::$user_conf->dynamic_opml_ttl_default);
+ $this->view->categories = $catDAO->listCategoriesOrderUpdate(FreshRSS_Context::userConf()->dynamic_opml_ttl_default);
$feedDAO = FreshRSS_Factory::createFeedDao();
- $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default);
+ $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::userConf()->ttl_default);
}
public function nbUnreadsPerFeedAction(): void {
@@ -48,10 +48,11 @@ class FreshRSS_javascript_Controller extends FreshRSS_ActionController {
header('Pragma: no-cache');
$user = $_GET['user'] ?? '';
- if (FreshRSS_Context::initUser($user)) {
+ FreshRSS_Context::initUser($user);
+ if (!FreshRSS_Context::hasUserConf()) {
try {
- $salt = FreshRSS_Context::$system_conf->salt;
- $s = FreshRSS_Context::$user_conf->passwordHash;
+ $salt = FreshRSS_Context::systemConf()->salt;
+ $s = FreshRSS_Context::userConf()->passwordHash;
if (strlen($s) >= 60) {
//CRYPT_BLOWFISH Salt: "$2a$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z".
$this->view->salt1 = substr($s, 0, 29);
diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php
index 21c5abb30..07e0fdcf8 100644
--- a/app/Controllers/subscriptionController.php
+++ b/app/Controllers/subscriptionController.php
@@ -118,13 +118,13 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
$feed->_ttl(Minz_Request::paramInt('ttl') ?: FreshRSS_Feed::TTL_DEFAULT);
$feed->_mute(Minz_Request::paramBoolean('mute'));
- $feed->_attributes('read_upon_gone', Minz_Request::paramTernary('read_upon_gone'));
- $feed->_attributes('mark_updated_article_unread', Minz_Request::paramTernary('mark_updated_article_unread'));
- $feed->_attributes('read_upon_reception', Minz_Request::paramTernary('read_upon_reception'));
- $feed->_attributes('clear_cache', Minz_Request::paramTernary('clear_cache'));
+ $feed->_attribute('read_upon_gone', Minz_Request::paramTernary('read_upon_gone'));
+ $feed->_attribute('mark_updated_article_unread', Minz_Request::paramTernary('mark_updated_article_unread'));
+ $feed->_attribute('read_upon_reception', Minz_Request::paramTernary('read_upon_reception'));
+ $feed->_attribute('clear_cache', Minz_Request::paramTernary('clear_cache'));
$keep_max_n_unread = Minz_Request::paramTernary('keep_max_n_unread') === true ? Minz_Request::paramInt('keep_max_n_unread') : null;
- $feed->_attributes('keep_max_n_unread', $keep_max_n_unread >= 0 ? $keep_max_n_unread : null);
+ $feed->_attribute('keep_max_n_unread', $keep_max_n_unread >= 0 ? $keep_max_n_unread : null);
$read_when_same_title_in_feed = Minz_Request::paramString('read_when_same_title_in_feed');
if ($read_when_same_title_in_feed === '') {
@@ -135,7 +135,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
$read_when_same_title_in_feed = false;
}
}
- $feed->_attributes('read_when_same_title_in_feed', $read_when_same_title_in_feed);
+ $feed->_attribute('read_when_same_title_in_feed', $read_when_same_title_in_feed);
$cookie = Minz_Request::paramString('curl_params_cookie');
$cookie_file = Minz_Request::paramBoolean('curl_params_cookiefile');
@@ -163,16 +163,16 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
if ($useragent !== '') {
$opts[CURLOPT_USERAGENT] = $useragent;
}
- $feed->_attributes('curl_params', empty($opts) ? null : $opts);
+ $feed->_attribute('curl_params', empty($opts) ? null : $opts);
- $feed->_attributes('content_action', Minz_Request::paramString('content_action', true) ?: 'replace');
+ $feed->_attribute('content_action', Minz_Request::paramString('content_action', true) ?: 'replace');
- $feed->_attributes('ssl_verify', Minz_Request::paramTernary('ssl_verify'));
+ $feed->_attribute('ssl_verify', Minz_Request::paramTernary('ssl_verify'));
$timeout = Minz_Request::paramInt('timeout');
- $feed->_attributes('timeout', $timeout > 0 ? $timeout : null);
+ $feed->_attribute('timeout', $timeout > 0 ? $timeout : null);
if (Minz_Request::paramBoolean('use_default_purge_options')) {
- $feed->_attributes('archiving', null);
+ $feed->_attribute('archiving', null);
} else {
if (Minz_Request::paramBoolean('enable_keep_max')) {
$keepMax = Minz_Request::paramInt('keep_max') ?: FreshRSS_Feed::ARCHIVING_RETENTION_COUNT_LIMIT;
@@ -187,7 +187,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
} else {
$keepPeriod = false;
}
- $feed->_attributes('archiving', [
+ $feed->_attribute('archiving', [
'keep_period' => $keepPeriod,
'keep_max' => $keepMax,
'keep_min' => Minz_Request::paramInt('keep_min'),
@@ -223,10 +223,10 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
if (Minz_Request::paramString('xPathItemUid') != '')
$xPathSettings['itemUid'] = Minz_Request::paramString('xPathItemUid', true);
if (!empty($xPathSettings))
- $feed->_attributes('xpath', $xPathSettings);
+ $feed->_attribute('xpath', $xPathSettings);
}
- $feed->_attributes('path_entries_filter', Minz_Request::paramString('path_entries_filter', true));
+ $feed->_attribute('path_entries_filter', Minz_Request::paramString('path_entries_filter', true));
$values = [
'name' => Minz_Request::paramString('name'),
diff --git a/app/Controllers/tagController.php b/app/Controllers/tagController.php
index 13909d522..190df32b1 100644
--- a/app/Controllers/tagController.php
+++ b/app/Controllers/tagController.php
@@ -36,7 +36,7 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
$id_tag = Minz_Request::paramInt('id_tag');
$name_tag = Minz_Request::paramString('name_tag');
$id_entry = Minz_Request::paramString('id_entry');
- $checked = Minz_Request::paramTernary('checked');
+ $checked = Minz_Request::paramBoolean('checked');
if ($id_entry != '') {
$tagDAO = FreshRSS_Factory::createTagDao();
if ($id_tag == 0 && $name_tag !== '' && $checked) {
@@ -85,7 +85,7 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
}
public function getTagsForEntryAction(): void {
- if (!FreshRSS_Auth::hasAccess() && !FreshRSS_Context::$system_conf->allow_anonymous) {
+ if (!FreshRSS_Auth::hasAccess() && !FreshRSS_Context::systemConf()->allow_anonymous) {
Minz_Error::error(403);
}
$this->view->_layout(null);
@@ -136,7 +136,7 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
$tagDAO = FreshRSS_Factory::createTagDao();
$sourceTag = $tagDAO->searchById($sourceId);
- $sourceName = $sourceTag === null ? null : $sourceTag->name();
+ $sourceName = $sourceTag === null ? '' : $sourceTag->name();
$targetTag = $tagDAO->searchByName($targetName);
if ($targetTag === null) {
// There is no existing tag with the same target name
diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php
index 43860a50c..78f28e493 100644
--- a/app/Controllers/updateController.php
+++ b/app/Controllers/updateController.php
@@ -194,7 +194,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController {
return;
}
} else {
- $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '/?v=' . FRESHRSS_VERSION;
+ $auto_update_url = FreshRSS_Context::systemConf()->auto_update_url . '/?v=' . FRESHRSS_VERSION;
Minz_Log::debug('HTTP GET ' . $auto_update_url);
$curlResource = curl_init($auto_update_url);
@@ -257,7 +257,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController {
}
public function applyAction(): void {
- if (FreshRSS_Context::$system_conf->disable_update || !file_exists(UPDATE_FILENAME) || !touch(FRESHRSS_PATH . '/index.html')) {
+ if (FreshRSS_Context::systemConf()->disable_update || !file_exists(UPDATE_FILENAME) || !touch(FRESHRSS_PATH . '/index.html')) {
Minz_Request::forward(['c' => 'update'], true);
}
@@ -270,7 +270,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController {
$res = do_post_update();
}
- Minz_ExtensionManager::callHook('post_update');
+ Minz_ExtensionManager::callHookVoid('post_update');
if ($res === true) {
@unlink(UPDATE_FILENAME);
diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php
index 6766182c1..b3fccac24 100644
--- a/app/Controllers/userController.php
+++ b/app/Controllers/userController.php
@@ -29,8 +29,8 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
if ($email !== null && $userConfig->mail_login !== $email) {
$userConfig->mail_login = $email;
- if (FreshRSS_Context::$system_conf->force_email_validation) {
- $salt = FreshRSS_Context::$system_conf->salt;
+ if (FreshRSS_Context::systemConf()->force_email_validation) {
+ $salt = FreshRSS_Context::systemConf()->salt;
$userConfig->email_validation_token = sha1($salt . uniqid('' . mt_rand(), true));
$mailer = new FreshRSS_User_Mailer();
$mailer->send_email_need_validation($user, $userConfig);
@@ -88,7 +88,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
Minz_Error::error(403);
}
- $email_not_verified = FreshRSS_Context::$user_conf->email_validation_token != '';
+ $email_not_verified = FreshRSS_Context::userConf()->email_validation_token != '';
$this->view->disable_aside = false;
if ($email_not_verified) {
$this->view->_layout('simple');
@@ -99,17 +99,15 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
FreshRSS_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
- if (Minz_Request::isPost()) {
- $system_conf = FreshRSS_Context::$system_conf;
- $user_config = FreshRSS_Context::$user_conf;
- $old_email = $user_config->mail_login;
+ if (Minz_Request::isPost() && Minz_User::name() != null) {
+ $old_email = FreshRSS_Context::userConf()->mail_login;
$email = Minz_Request::paramString('email');
$passwordPlain = Minz_Request::paramString('newPasswordPlain', true);
Minz_Request::_param('newPasswordPlain'); //Discard plain-text password ASAP
$_POST['newPasswordPlain'] = '';
- if ($system_conf->force_email_validation && empty($email)) {
+ if (FreshRSS_Context::systemConf()->force_email_validation && empty($email)) {
Minz_Request::bad(
_t('user.email.feedback.required'),
['c' => 'user', 'a' => 'profile']
@@ -132,10 +130,10 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
]
);
- Minz_Session::_param('passwordHash', FreshRSS_Context::$user_conf->passwordHash);
+ Minz_Session::_param('passwordHash', FreshRSS_Context::userConf()->passwordHash);
if ($ok) {
- if ($system_conf->force_email_validation && $email !== $old_email) {
+ if (FreshRSS_Context::systemConf()->force_email_validation && $email !== $old_email) {
Minz_Request::good(_t('feedback.profile.updated'), ['c' => 'user', 'a' => 'validateEmail']);
} elseif ($passwordPlain == '') {
Minz_Request::good(_t('feedback.profile.updated'), ['c' => 'user', 'a' => 'profile']);
@@ -202,7 +200,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
}
}
- $this->view->show_email_field = FreshRSS_Context::$system_conf->force_email_validation;
+ $this->view->show_email_field = FreshRSS_Context::systemConf()->force_email_validation;
$this->view->current_user = Minz_Request::paramString('u');
foreach (listUsers() as $user) {
@@ -286,8 +284,6 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
}
if (Minz_Request::isPost()) {
- $system_conf = FreshRSS_Context::$system_conf;
-
$new_user_name = Minz_Request::paramString('new_user_name');
$email = Minz_Request::paramString('new_user_email');
$passwordPlain = Minz_Request::paramString('new_user_passwordPlain', true);
@@ -320,7 +316,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
$tos_enabled = file_exists(TOS_FILENAME);
$accept_tos = Minz_Request::paramBoolean('accept_tos');
- if ($system_conf->force_email_validation && empty($email)) {
+ if (FreshRSS_Context::systemConf()->force_email_validation && empty($email)) {
Minz_Request::bad(
_t('user.email.feedback.required'),
$badRedirectUrl
@@ -342,7 +338,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
}
$ok = self::createUser($new_user_name, $email, $passwordPlain, [
- 'language' => Minz_Request::paramString('new_user_language') ?: FreshRSS_Context::$user_conf->language,
+ 'language' => Minz_Request::paramString('new_user_language') ?: FreshRSS_Context::userConf()->language,
'timezone' => Minz_Request::paramString('new_user_timezone'),
'is_admin' => Minz_Request::paramBoolean('new_user_is_admin'),
'enabled' => true,
@@ -357,12 +353,16 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
// get started immediately.
if ($ok && !FreshRSS_Auth::hasAccess('admin')) {
$user_conf = get_user_configuration($new_user_name);
- Minz_Session::_params([
- Minz_User::CURRENT_USER => $new_user_name,
- 'passwordHash' => $user_conf->passwordHash,
- 'csrf' => false,
- ]);
- FreshRSS_Auth::giveAccess();
+ if ($user_conf !== null) {
+ Minz_Session::_params([
+ Minz_User::CURRENT_USER => $new_user_name,
+ 'passwordHash' => $user_conf->passwordHash,
+ 'csrf' => false,
+ ]);
+ FreshRSS_Auth::giveAccess();
+ } else {
+ $ok = false;
+ }
}
if ($ok) {
@@ -379,7 +379,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
public static function deleteUser(string $username): bool {
$ok = self::checkUsername($username);
if ($ok) {
- $default_user = FreshRSS_Context::$system_conf->default_user;
+ $default_user = FreshRSS_Context::systemConf()->default_user;
$ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user
}
$user_data = join_path(DATA_PATH, 'users', $username);
@@ -415,7 +415,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
* It returns 403 if user isn’t logged in and `username` param isn’t passed.
*/
public function validateEmailAction(): void {
- if (!FreshRSS_Context::$system_conf->force_email_validation) {
+ if (!FreshRSS_Context::systemConf()->force_email_validation) {
Minz_Error::error(404);
}
@@ -428,7 +428,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
if ($username !== '') {
$user_config = get_user_configuration($username);
} elseif (FreshRSS_Auth::hasAccess()) {
- $user_config = FreshRSS_Context::$user_conf;
+ $user_config = FreshRSS_Context::userConf();
} else {
Minz_Error::error(403);
return;
@@ -489,9 +489,8 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
}
$username = Minz_User::name();
- $user_config = FreshRSS_Context::$user_conf;
- if ($user_config->email_validation_token === '') {
+ if (FreshRSS_Context::userConf()->email_validation_token === '') {
Minz_Request::forward([
'c' => 'index',
'a' => 'index',
@@ -499,7 +498,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
}
$mailer = new FreshRSS_User_Mailer();
- $ok = $mailer->send_email_need_validation($username, $user_config);
+ $ok = $username != null && $mailer->send_email_need_validation($username, FreshRSS_Context::userConf());
$redirect_url = ['c' => 'user', 'a' => 'validateEmail'];
if ($ok) {
@@ -541,7 +540,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
$challenge = Minz_Request::paramString('challenge');
$ok &= FreshRSS_FormAuth::checkCredentials(
- $username, FreshRSS_Context::$user_conf->passwordHash,
+ $username, FreshRSS_Context::userConf()->passwordHash,
$nonce, $challenge
);
}
@@ -596,6 +595,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
if (null === $userConfig = get_user_configuration($username)) {
Minz_Error::error(500);
+ return;
}
$userConfig->_param($field, $value);
@@ -639,6 +639,9 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
$databaseDAO = FreshRSS_Factory::createDatabaseDAO($username);
$userConfiguration = get_user_configuration($username);
+ if ($userConfiguration === null) {
+ throw new Exception('Error loading user configuration!');
+ }
return [
'feed_count' => $feedDAO->count(),
@@ -649,7 +652,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
'enabled' => $userConfiguration->enabled,
'is_admin' => $userConfiguration->is_admin,
'last_user_activity' => date('c', FreshRSS_UserDAO::mtime($username)) ?: '',
- 'is_default' => FreshRSS_Context::$system_conf->default_user === $username,
+ 'is_default' => FreshRSS_Context::systemConf()->default_user === $username,
];
}
}
diff --git a/app/FreshRSS.php b/app/FreshRSS.php
index c4eaaec1b..264d8ff1a 100644
--- a/app/FreshRSS.php
+++ b/app/FreshRSS.php
@@ -27,13 +27,13 @@ class FreshRSS extends Minz_FrontController {
Minz_ActionController::$defaultViewType = FreshRSS_View::class;
FreshRSS_Context::initSystem();
- if (FreshRSS_Context::$system_conf == null) {
+ if (!FreshRSS_Context::hasSystemConf()) {
$message = 'Error during context system init!';
Minz_Error::error(500, $message, false);
die($message);
}
- if (FreshRSS_Context::$system_conf->logo_html != '') {
+ if (FreshRSS_Context::systemConf()->logo_html != '') {
// Relax Content Security Policy to allow external images if a custom logo HTML is used
Minz_ActionController::_defaultCsp([
'default-src' => "'self'",
@@ -47,10 +47,10 @@ class FreshRSS extends Minz_FrontController {
// Auth has to be initialized before using currentUser session parameter
// because it’s this part which create this parameter.
self::initAuth();
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
FreshRSS_Context::initUser();
}
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
$message = 'Error during context user init!';
Minz_Error::error(500, $message, false);
die($message);
@@ -60,28 +60,28 @@ class FreshRSS extends Minz_FrontController {
self::initI18n();
self::loadNotifications();
// Enable extensions for the current (logged) user.
- if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) {
- $ext_list = FreshRSS_Context::$user_conf->extensions_enabled;
+ if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::systemConf()->allow_anonymous) {
+ $ext_list = FreshRSS_Context::userConf()->extensions_enabled;
Minz_ExtensionManager::enableByList($ext_list, 'user');
}
- if (FreshRSS_Context::$system_conf->force_email_validation && !FreshRSS_Auth::hasAccess('admin')) {
+ if (FreshRSS_Context::systemConf()->force_email_validation && !FreshRSS_Auth::hasAccess('admin')) {
self::checkEmailValidated();
}
- Minz_ExtensionManager::callHook('freshrss_init');
+ Minz_ExtensionManager::callHookVoid('freshrss_init');
}
private static function initAuth(): void {
FreshRSS_Auth::init();
if (Minz_Request::isPost()) {
- if (FreshRSS_Context::$system_conf == null || !(FreshRSS_Auth::isCsrfOk() ||
+ if (!FreshRSS_Context::hasSystemConf() || !(FreshRSS_Auth::isCsrfOk() ||
(Minz_Request::controllerName() === 'auth' && Minz_Request::actionName() === 'login') ||
(Minz_Request::controllerName() === 'user' && Minz_Request::actionName() === 'create' && !FreshRSS_Auth::hasAccess('admin')) ||
(Minz_Request::controllerName() === 'feed' && Minz_Request::actionName() === 'actualize'
- && FreshRSS_Context::$system_conf->allow_anonymous_refresh) ||
+ && FreshRSS_Context::systemConf()->allow_anonymous_refresh) ||
(Minz_Request::controllerName() === 'javascript' && Minz_Request::actionName() === 'actualize'
- && FreshRSS_Context::$system_conf->allow_anonymous)
+ && FreshRSS_Context::systemConf()->allow_anonymous)
)) {
// Token-based protection against XSRF attacks, except for the login or self-create user forms
self::initI18n();
@@ -91,14 +91,14 @@ class FreshRSS extends Minz_FrontController {
}
private static function initI18n(): void {
- $userLanguage = isset(FreshRSS_Context::$user_conf) ? FreshRSS_Context::$user_conf->language : null;
- $systemLanguage = isset(FreshRSS_Context::$system_conf) ? FreshRSS_Context::$system_conf->language : null;
+ $userLanguage = FreshRSS_Context::hasUserConf() ? FreshRSS_Context::userConf()->language : null;
+ $systemLanguage = FreshRSS_Context::hasSystemConf() ? FreshRSS_Context::systemConf()->language : null;
$language = Minz_Translate::getLanguage($userLanguage, Minz_Request::getPreferredLanguages(), $systemLanguage);
Minz_Session::_param('language', $language);
Minz_Translate::init($language);
- $timezone = isset(FreshRSS_Context::$user_conf) ? FreshRSS_Context::$user_conf->timezone : '';
+ $timezone = FreshRSS_Context::hasUserConf() ? FreshRSS_Context::userConf()->timezone : '';
if ($timezone == '') {
$timezone = FreshRSS_Context::defaultTimeZone();
}
@@ -111,10 +111,10 @@ class FreshRSS extends Minz_FrontController {
}
public static function loadStylesAndScripts(): void {
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
return;
}
- $theme = FreshRSS_Themes::load(FreshRSS_Context::$user_conf->theme);
+ $theme = FreshRSS_Themes::load(FreshRSS_Context::userConf()->theme);
if ($theme) {
foreach(array_reverse($theme['files']) as $file) {
switch (substr($file, -3)) {
@@ -167,7 +167,7 @@ class FreshRSS extends Minz_FrontController {
private static function checkEmailValidated(): void {
$email_not_verified = FreshRSS_Auth::hasAccess() &&
- FreshRSS_Context::$user_conf !== null && FreshRSS_Context::$user_conf->email_validation_token !== '';
+ FreshRSS_Context::hasUserConf() && FreshRSS_Context::userConf()->email_validation_token !== '';
$action_is_allowed = (
Minz_Request::is('user', 'validateEmail') ||
Minz_Request::is('user', 'sendValidationEmail') ||
diff --git a/app/Mailers/UserMailer.php b/app/Mailers/UserMailer.php
index a78ab9b32..3e4b67d18 100644
--- a/app/Mailers/UserMailer.php
+++ b/app/Mailers/UserMailer.php
@@ -17,7 +17,7 @@ class FreshRSS_User_Mailer extends Minz_Mailer {
$this->view->_path('user_mailer/email_need_validation.txt.php');
$this->view->username = $username;
- $this->view->site_title = FreshRSS_Context::$system_conf->title;
+ $this->view->site_title = FreshRSS_Context::systemConf()->title;
$this->view->validation_url = Minz_Url::display(
[
'c' => 'user',
@@ -31,7 +31,7 @@ class FreshRSS_User_Mailer extends Minz_Mailer {
true
);
- $subject_prefix = '[' . FreshRSS_Context::$system_conf->title . ']';
+ $subject_prefix = '[' . FreshRSS_Context::systemConf()->title . ']';
return $this->mail(
$user_config->mail_login,
$subject_prefix . ' ' ._t('user.mailer.email_need_validation.title')
diff --git a/app/Models/AttributesTrait.php b/app/Models/AttributesTrait.php
index 39154182b..e94a973d9 100644
--- a/app/Models/AttributesTrait.php
+++ b/app/Models/AttributesTrait.php
@@ -10,28 +10,54 @@ trait FreshRSS_AttributesTrait {
*/
private array $attributes = [];
+ /** @return array<string,mixed> */
+ public function attributes(): array {
+ return $this->attributes;
+ }
+
/**
- * @phpstan-return ($key is non-empty-string ? mixed : array<string,mixed>)
- * @return array<string,mixed>|mixed|null
+ * @param non-empty-string $key
+ * @return array<int|string,mixed>|null
*/
- public function attributes(string $key = '') {
- if ($key === '') {
- return $this->attributes;
- } else {
- return $this->attributes[$key] ?? null;
+ public function attributeArray(string $key): ?array {
+ $a = $this->attributes[$key] ?? null;
+ return is_array($a) ? $a : null;
+ }
+
+ /** @param non-empty-string $key */
+ public function attributeBoolean(string $key): ?bool {
+ $a = $this->attributes[$key] ?? null;
+ return is_bool($a) ? $a : null;
+ }
+
+ /** @param non-empty-string $key */
+ public function attributeInt(string $key): ?int {
+ $a = $this->attributes[$key] ?? null;
+ return is_int($a) ? $a : null;
+ }
+
+ /** @param non-empty-string $key */
+ public function attributeString(string $key): ?string {
+ $a = $this->attributes[$key] ?? null;
+ return is_string($a) ? $a : null;
+ }
+
+ /** @param string|array<string,mixed> $values Values, not HTML-encoded */
+ public function _attributes($values): void {
+ if (is_string($values)) {
+ $values = json_decode($values, true);
+ }
+ if (is_array($values)) {
+ $this->attributes = $values;
}
}
- /** @param string|array<mixed>|bool|int|null $value Value, not HTML-encoded */
- public function _attributes(string $key, $value = null): void {
- if ($key == '') {
- if (is_string($value)) {
- $value = json_decode($value, true);
- }
- if (is_array($value)) {
- $this->attributes = $value;
- }
- } elseif ($value === null) {
+ /**
+ * @param non-empty-string $key
+ * @param array<string,mixed>|mixed|null $value Value, not HTML-encoded
+ */
+ public function _attribute(string $key, $value = null): void {
+ if ($value === null) {
unset($this->attributes[$key]);
} else {
$this->attributes[$key] = $value;
diff --git a/app/Models/Auth.php b/app/Models/Auth.php
index e5f7fc0b9..c66bb5016 100644
--- a/app/Models/Auth.php
+++ b/app/Models/Auth.php
@@ -24,7 +24,7 @@ class FreshRSS_Auth {
self::$login_ok = Minz_Session::paramBoolean('loginOk');
$current_user = Minz_User::name();
if ($current_user === null) {
- $current_user = FreshRSS_Context::$system_conf->default_user;
+ $current_user = FreshRSS_Context::systemConf()->default_user;
Minz_Session::_params([
Minz_User::CURRENT_USER => $current_user,
'csrf' => false,
@@ -51,7 +51,7 @@ class FreshRSS_Auth {
* @return bool true if user can be connected, false otherwise.
*/
private static function accessControl(): bool {
- $auth_type = FreshRSS_Context::$system_conf->auth_type;
+ $auth_type = FreshRSS_Context::systemConf()->auth_type;
switch ($auth_type) {
case 'form':
$credentials = FreshRSS_FormAuth::getCredentialsFromCookie();
@@ -71,13 +71,13 @@ class FreshRSS_Auth {
return false;
}
$login_ok = FreshRSS_UserDAO::exists($current_user);
- if (!$login_ok && FreshRSS_Context::$system_conf->http_auth_auto_register) {
+ if (!$login_ok && FreshRSS_Context::systemConf()->http_auth_auto_register) {
$email = null;
- if (FreshRSS_Context::$system_conf->http_auth_auto_register_email_field !== '' &&
- isset($_SERVER[FreshRSS_Context::$system_conf->http_auth_auto_register_email_field])) {
- $email = (string)$_SERVER[FreshRSS_Context::$system_conf->http_auth_auto_register_email_field];
+ if (FreshRSS_Context::systemConf()->http_auth_auto_register_email_field !== '' &&
+ isset($_SERVER[FreshRSS_Context::systemConf()->http_auth_auto_register_email_field])) {
+ $email = (string)$_SERVER[FreshRSS_Context::systemConf()->http_auth_auto_register_email_field];
}
- $language = Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), FreshRSS_Context::$system_conf->language);
+ $language = Minz_Translate::getLanguage(null, Minz_Request::getPreferredLanguages(), FreshRSS_Context::systemConf()->language);
Minz_Translate::init($language);
$login_ok = FreshRSS_user_Controller::createUser($current_user, $email, '', [
'language' => $language,
@@ -103,17 +103,17 @@ class FreshRSS_Auth {
*/
public static function giveAccess(): bool {
FreshRSS_Context::initUser();
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
self::$login_ok = false;
return false;
}
- switch (FreshRSS_Context::$system_conf->auth_type) {
+ switch (FreshRSS_Context::systemConf()->auth_type) {
case 'form':
- self::$login_ok = Minz_Session::paramString('passwordHash') === FreshRSS_Context::$user_conf->passwordHash;
+ self::$login_ok = Minz_Session::paramString('passwordHash') === FreshRSS_Context::userConf()->passwordHash;
break;
case 'http_auth':
- $current_user = Minz_User::name();
+ $current_user = Minz_User::name() ?? '';
self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0;
break;
case 'none':
@@ -138,12 +138,12 @@ class FreshRSS_Auth {
* @return bool true if user has corresponding access, false else.
*/
public static function hasAccess(string $scope = 'general'): bool {
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
return false;
}
$currentUser = Minz_User::name();
- $isAdmin = FreshRSS_Context::$user_conf->is_admin;
- $default_user = FreshRSS_Context::$system_conf->default_user;
+ $isAdmin = FreshRSS_Context::userConf()->is_admin;
+ $default_user = FreshRSS_Context::systemConf()->default_user;
$ok = self::$login_ok;
switch ($scope) {
case 'general':
@@ -180,11 +180,11 @@ class FreshRSS_Auth {
}
}
if ($username == '') {
- $username = FreshRSS_Context::$system_conf->default_user;
+ $username = FreshRSS_Context::systemConf()->default_user;
}
Minz_User::change($username);
- switch (FreshRSS_Context::$system_conf->auth_type) {
+ switch (FreshRSS_Context::systemConf()->auth_type) {
case 'form':
Minz_Session::_param('passwordHash');
FreshRSS_FormAuth::deleteCookie();
@@ -202,20 +202,20 @@ class FreshRSS_Auth {
* Return if authentication is enabled on this instance of FRSS.
*/
public static function accessNeedsLogin(): bool {
- return FreshRSS_Context::$system_conf->auth_type !== 'none';
+ return FreshRSS_Context::systemConf()->auth_type !== 'none';
}
/**
* Return if authentication requires a PHP action.
*/
public static function accessNeedsAction(): bool {
- return FreshRSS_Context::$system_conf->auth_type === 'form';
+ return FreshRSS_Context::systemConf()->auth_type === 'form';
}
public static function csrfToken(): string {
$csrf = Minz_Session::paramString('csrf');
if ($csrf == '') {
- $salt = FreshRSS_Context::$system_conf->salt;
+ $salt = FreshRSS_Context::systemConf()->salt;
$csrf = sha1($salt . uniqid('' . random_int(0, mt_getrandmax()), true));
Minz_Session::_param('csrf', $csrf);
}
diff --git a/app/Models/BooleanSearch.php b/app/Models/BooleanSearch.php
index 8a750a713..78b7593b2 100644
--- a/app/Models/BooleanSearch.php
+++ b/app/Models/BooleanSearch.php
@@ -19,14 +19,20 @@ class FreshRSS_BooleanSearch {
public function __construct(string $input, int $level = 0, string $operator = 'AND') {
$this->operator = $operator;
$input = trim($input);
- if ($input == '') {
+ if ($input === '') {
return;
}
$this->raw_input = $input;
if ($level === 0) {
$input = preg_replace('/:&quot;(.*?)&quot;/', ':"\1"', $input);
+ if (!is_string($input)) {
+ return;
+ }
$input = preg_replace('/(?<=[\s!-]|^)&quot;(.*?)&quot;/', '"\1"', $input);
+ if (!is_string($input)) {
+ return;
+ }
$input = $this->parseUserQueryNames($input);
$input = $this->parseUserQueryIds($input);
@@ -53,7 +59,7 @@ class FreshRSS_BooleanSearch {
if (!empty($all_matches)) {
/** @var array<string,FreshRSS_UserQuery> */
$queries = [];
- foreach (FreshRSS_Context::$user_conf->queries as $raw_query) {
+ foreach (FreshRSS_Context::userConf()->queries as $raw_query) {
$query = new FreshRSS_UserQuery($raw_query);
$queries[$query->getName()] = $query;
}
@@ -95,7 +101,7 @@ class FreshRSS_BooleanSearch {
/** @var array<string,FreshRSS_UserQuery> */
$queries = [];
- foreach (FreshRSS_Context::$user_conf->queries as $raw_query) {
+ foreach (FreshRSS_Context::userConf()->queries as $raw_query) {
$query = new FreshRSS_UserQuery($raw_query, $feed_dao, $category_dao, $tag_dao);
$queries[] = $query;
}
diff --git a/app/Models/Category.php b/app/Models/Category.php
index b1e35650a..cc25a1ec0 100644
--- a/app/Models/Category.php
+++ b/app/Models/Category.php
@@ -169,8 +169,8 @@ class FreshRSS_Category extends Minz_Model {
}
public function refreshDynamicOpml(): bool {
- $url = $this->attributes('opml_url');
- if ($url == '') {
+ $url = $this->attributeString('opml_url');
+ if ($url == null) {
return false;
}
$ok = true;
diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php
index 20347e4f2..417ff7a6c 100644
--- a/app/Models/CategoryDAO.php
+++ b/app/Models/CategoryDAO.php
@@ -30,8 +30,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
} elseif ('attributes' === $name) { //v1.15.0
$ok = $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN attributes TEXT') !== false;
- /** @var array<array{'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
- * 'priority':int,'pathEntries':string,'httpAuth':string,'error':int,'ttl':int,'attributes':string}> $feeds */
+ /** @var array<array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'lastUpdate':int,
+ * 'priority':int,'pathEntries':string,'httpAuth':string,'error':int,'keep_history':?int,'ttl':int,'attributes':string}> $feeds */
$feeds = $this->fetchAssoc('SELECT * FROM `_feed`') ?? [];
$stm = $this->pdo->prepare('UPDATE `_feed` SET attributes = :attributes WHERE id = :id');
@@ -153,7 +153,7 @@ SQL;
}
/**
- * @param array{'name':string,'kind':int,'attributes'?:string|array<string,mixed>} $valuesTmp
+ * @param array{'name':string,'kind':int,'attributes'?:array<string,mixed>|mixed|null} $valuesTmp
* @return int|false
* @throws JsonException
*/
@@ -230,6 +230,7 @@ SQL;
$stm = $this->pdo->query($sql);
if ($stm !== false) {
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ /** @var array{'id':int,'name':string,'kind':int,'lastUpdate':int,'error':int,'attributes'?:array<string,mixed>} $row */
yield $row;
}
} else {
@@ -245,7 +246,7 @@ SQL;
public function searchById(int $id): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE id=:id';
$res = $this->fetchAssoc($sql, ['id' => $id]) ?? [];
- /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate':int,'error':int|bool,'attributes':string}> $res */
$cat = self::daoToCategory($res);
return $cat[0] ?? null;
}
@@ -253,7 +254,7 @@ SQL;
public function searchByName(string $name): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE name=:name';
$res = $this->fetchAssoc($sql, ['name' => $name]) ?? [];
- /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
+ /** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate':int,'error':int|bool,'attributes':string}> $res */
$cat = self::daoToCategory($res);
return $cat[0] ?? null;
}
@@ -263,8 +264,8 @@ SQL;
$categories = $this->listCategories($prePopulateFeeds, $details);
uasort($categories, static function (FreshRSS_Category $a, FreshRSS_Category $b) {
- $aPosition = $a->attributes('position');
- $bPosition = $b->attributes('position');
+ $aPosition = $a->attributeInt('position');
+ $bPosition = $b->attributeInt('position');
if ($aPosition === $bPosition) {
return ($a->name() < $b->name()) ? -1 : 1;
} elseif (null === $aPosition) {
@@ -332,9 +333,9 @@ SQL;
public function getDefault(): ?FreshRSS_Category {
$sql = 'SELECT * FROM `_category` WHERE id=:id';
- $res = $this->fetchAssoc($sql, [':id' => self::DEFAULTCATEGORYID]);
+ $res = $this->fetchAssoc($sql, [':id' => self::DEFAULTCATEGORYID]) ?? [];
/** @var array<array{'name':string,'id':int,'kind':int,'lastUpdate'?:int,'error'?:int|bool,'attributes'?:string}> $res */
- $cat = self::daoToCategory($res ?? []);
+ $cat = self::daoToCategory($res);
if (isset($cat[0])) {
return $cat[0];
} else {
@@ -444,7 +445,7 @@ SQL;
$feedDao::daoToFeed($feedsDao, $previousLine['c_id'])
);
$cat->_kind($previousLine['c_kind']);
- $cat->_attributes('', $previousLine['c_attributes'] ?? '[]');
+ $cat->_attributes($previousLine['c_attributes'] ?? '[]');
$list[(int)$previousLine['c_id']] = $cat;
$feedsDao = []; //Prepare for next category
@@ -464,7 +465,7 @@ SQL;
$cat->_kind($previousLine['c_kind']);
$cat->_lastUpdate($previousLine['c_last_update'] ?? 0);
$cat->_error($previousLine['c_error'] ?? 0);
- $cat->_attributes('', $previousLine['c_attributes'] ?? []);
+ $cat->_attributes($previousLine['c_attributes'] ?? []);
$list[(int)$previousLine['c_id']] = $cat;
}
@@ -487,7 +488,7 @@ SQL;
$cat->_kind($dao['kind']);
$cat->_lastUpdate($dao['lastUpdate'] ?? 0);
$cat->_error($dao['error'] ?? 0);
- $cat->_attributes('', $dao['attributes'] ?? '');
+ $cat->_attributes($dao['attributes'] ?? '');
$list[] = $cat;
}
diff --git a/app/Models/Context.php b/app/Models/Context.php
index ac5547aa1..3ea5a29eb 100644
--- a/app/Models/Context.php
+++ b/app/Models/Context.php
@@ -7,8 +7,6 @@ declare(strict_types=1);
*/
final class FreshRSS_Context {
- public static ?FreshRSS_UserConfiguration $user_conf = null;
- public static ?FreshRSS_SystemConfiguration $system_conf = null;
/**
* @var array<int,FreshRSS_Category>
*/
@@ -57,21 +55,42 @@ final class FreshRSS_Context {
public static bool $isCli = false;
/**
+ * @deprecated Will be made `private`; use `FreshRSS_Context::systemConf()` instead.
+ * @internal
+ */
+ public static ?FreshRSS_SystemConfiguration $system_conf = null;
+ /**
+ * @deprecated Will be made `private`; use `FreshRSS_Context::userConf()` instead.
+ * @internal
+ */
+ public static ?FreshRSS_UserConfiguration $user_conf = null;
+
+ /**
* Initialize the context for the global system.
*/
- public static function initSystem(bool $reload = false): FreshRSS_SystemConfiguration {
- if ($reload || FreshRSS_Context::$system_conf == null) {
+ public static function initSystem(bool $reload = false): void {
+ if ($reload || FreshRSS_Context::$system_conf === null) {
//TODO: Keep in session what we need instead of always reloading from disk
FreshRSS_Context::$system_conf = FreshRSS_SystemConfiguration::init(DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php');
}
+ }
+
+ public static function &systemConf(): FreshRSS_SystemConfiguration {
+ if (FreshRSS_Context::$system_conf === null) {
+ throw new FreshRSS_Context_Exception('System configuration not initialised!');
+ }
return FreshRSS_Context::$system_conf;
}
+ public static function hasSystemConf(): bool {
+ return FreshRSS_Context::$system_conf !== null;
+ }
+
/**
* Initialize the context for the current user.
* @throws Minz_ConfigurationParamException
*/
- public static function initUser(string $username = '', bool $userMustExist = true): ?FreshRSS_UserConfiguration {
+ public static function initUser(string $username = '', bool $userMustExist = true): void {
FreshRSS_Context::$user_conf = null;
if (!isset($_SESSION)) {
Minz_Session::init('FreshRSS');
@@ -103,14 +122,16 @@ final class FreshRSS_Context {
Minz_Session::unlock();
if (FreshRSS_Context::$user_conf == null) {
- return null;
+ return;
}
FreshRSS_Context::$search = new FreshRSS_BooleanSearch('');
//Legacy
- $oldEntries = (int)FreshRSS_Context::$user_conf->param('old_entries', 0);
- $keepMin = (int)FreshRSS_Context::$user_conf->param('keep_history_default', -5);
+ $oldEntries = FreshRSS_Context::$user_conf->param('old_entries', 0);
+ $oldEntries = is_numeric($oldEntries) ? (int)$oldEntries : 0;
+ $keepMin = FreshRSS_Context::$user_conf->param('keep_history_default', -5);
+ $keepMin = is_numeric($keepMin) ? (int)$keepMin : -5;
if ($oldEntries > 0 || $keepMin > -5) { //Freshrss < 1.15
$archiving = FreshRSS_Context::$user_conf->archiving;
$archiving['keep_max'] = false;
@@ -130,10 +151,23 @@ final class FreshRSS_Context {
if (!in_array(FreshRSS_Context::$user_conf->display_categories, [ 'active', 'remember', 'all', 'none' ], true)) {
FreshRSS_Context::$user_conf->display_categories = FreshRSS_Context::$user_conf->display_categories === true ? 'all' : 'active';
}
+ }
+ public static function &userConf(): FreshRSS_UserConfiguration {
+ if (FreshRSS_Context::$user_conf === null) {
+ throw new FreshRSS_Context_Exception('User configuration not initialised!');
+ }
return FreshRSS_Context::$user_conf;
}
+ public static function hasUserConf(): bool {
+ return FreshRSS_Context::$user_conf !== null;
+ }
+
+ public static function clearUserConf(): void {
+ FreshRSS_Context::$user_conf = null;
+ }
+
/**
* This action updates the Context object by using request parameters.
*
@@ -162,28 +196,28 @@ final class FreshRSS_Context {
self::_get(Minz_Request::paramString('get') ?: 'a');
- self::$state = Minz_Request::paramInt('state') ?: self::$user_conf->default_state;
+ self::$state = Minz_Request::paramInt('state') ?: FreshRSS_Context::userConf()->default_state;
$state_forced_by_user = Minz_Request::paramString('state') !== '';
if (!$state_forced_by_user && !self::isStateEnabled(FreshRSS_Entry::STATE_READ)) {
- if (self::$user_conf->default_view === 'all') {
+ if (FreshRSS_Context::userConf()->default_view === 'all') {
self::$state |= FreshRSS_Entry::STATE_ALL;
- } elseif (self::$user_conf->default_view === 'adaptive' && self::$get_unread <= 0) {
+ } elseif (FreshRSS_Context::userConf()->default_view === 'adaptive' && self::$get_unread <= 0) {
self::$state |= FreshRSS_Entry::STATE_READ;
}
- if (self::$user_conf->show_fav_unread &&
+ if (FreshRSS_Context::userConf()->show_fav_unread &&
(self::isCurrentGet('s') || self::isCurrentGet('T') || self::isTag())) {
self::$state |= FreshRSS_Entry::STATE_READ;
}
}
self::$search = new FreshRSS_BooleanSearch(Minz_Request::paramString('search'));
- $order = Minz_Request::paramString('order') ?: self::$user_conf->sort_order;
+ $order = Minz_Request::paramString('order') ?: FreshRSS_Context::userConf()->sort_order;
self::$order = in_array($order, ['ASC', 'DESC'], true) ? $order : 'DESC';
- self::$number = Minz_Request::paramInt('nb') ?: self::$user_conf->posts_per_page;
- if (self::$number > self::$user_conf->max_posts_per_rss) {
+ self::$number = Minz_Request::paramInt('nb') ?: FreshRSS_Context::userConf()->posts_per_page;
+ if (self::$number > FreshRSS_Context::userConf()->max_posts_per_rss) {
self::$number = max(
- self::$user_conf->max_posts_per_rss,
- self::$user_conf->posts_per_page);
+ FreshRSS_Context::userConf()->max_posts_per_rss,
+ FreshRSS_Context::userConf()->posts_per_page);
}
self::$first_id = Minz_Request::paramString('next');
self::$sinceHours = Minz_Request::paramInt('hours');
@@ -335,19 +369,19 @@ final class FreshRSS_Context {
case 'a':
self::$current_get['all'] = true;
self::$name = _t('index.feed.title');
- self::$description = self::$system_conf->meta_description;
+ self::$description = FreshRSS_Context::systemConf()->meta_description;
self::$get_unread = self::$total_unread;
break;
case 'i':
self::$current_get['important'] = true;
self::$name = _t('index.menu.important');
- self::$description = self::$system_conf->meta_description;
+ self::$description = FreshRSS_Context::systemConf()->meta_description;
self::$get_unread = self::$total_unread;
break;
case 's':
self::$current_get['starred'] = true;
self::$name = _t('index.feed.title_fav');
- self::$description = self::$system_conf->meta_description;
+ self::$description = FreshRSS_Context::systemConf()->meta_description;
self::$get_unread = self::$total_starred['unread'];
// Update state if favorite is not yet enabled.
@@ -355,7 +389,7 @@ final class FreshRSS_Context {
break;
case 'f':
// We try to find the corresponding feed. When allowing robots, always retrieve the full feed including description
- $feed = FreshRSS_Context::$system_conf->allow_robots ? null : FreshRSS_CategoryDAO::findFeed(self::$categories, $id);
+ $feed = FreshRSS_Context::systemConf()->allow_robots ? null : FreshRSS_CategoryDAO::findFeed(self::$categories, $id);
if ($feed === null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
$feed = $feedDAO->searchById($id);
@@ -427,7 +461,7 @@ final class FreshRSS_Context {
self::$categories = $catDAO->listCategories();
}
- if (self::$user_conf->onread_jump_next && strlen($get) > 2) {
+ if (FreshRSS_Context::userConf()->onread_jump_next && strlen($get) > 2) {
$another_unread_id = '';
$found_current_get = false;
switch ($get[0]) {
@@ -491,7 +525,7 @@ final class FreshRSS_Context {
* - the "unread" state is enable
*/
public static function isAutoRemoveAvailable(): bool {
- if (!self::$user_conf->auto_remove_article) {
+ if (!FreshRSS_Context::userConf()->auto_remove_article) {
return false;
}
if (self::isStateEnabled(FreshRSS_Entry::STATE_READ)) {
@@ -510,7 +544,7 @@ final class FreshRSS_Context {
* are read.
*/
public static function isStickyPostEnabled(): bool {
- if (self::$user_conf->sticky_post) {
+ if (FreshRSS_Context::userConf()->sticky_post) {
return true;
}
if (self::isAutoRemoveAvailable()) {
diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php
index 7dbe1db3f..cdc74fa12 100644
--- a/app/Models/DatabaseDAO.php
+++ b/app/Models/DatabaseDAO.php
@@ -22,7 +22,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
public function create(): string {
require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
- $db = FreshRSS_Context::$system_conf->db;
+ $db = FreshRSS_Context::systemConf()->db;
try {
$sql = sprintf($GLOBALS['SQL_CREATE_DB'], empty($db['base']) ? '' : $db['base']);
@@ -174,7 +174,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
}
public function size(bool $all = false): int {
- $db = FreshRSS_Context::$system_conf->db;
+ $db = FreshRSS_Context::systemConf()->db;
// MariaDB does not refresh size information automatically
$sql = <<<'SQL'
diff --git a/app/Models/DatabaseDAOPGSQL.php b/app/Models/DatabaseDAOPGSQL.php
index 4a92dd184..fe3d6149d 100644
--- a/app/Models/DatabaseDAOPGSQL.php
+++ b/app/Models/DatabaseDAOPGSQL.php
@@ -11,7 +11,7 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
public const UNDEFINED_TABLE = '42P01';
public function tablesAreCorrect(): bool {
- $db = FreshRSS_Context::$system_conf->db;
+ $db = FreshRSS_Context::systemConf()->db;
$sql = 'SELECT * FROM pg_catalog.pg_tables where tableowner=:tableowner';
$res = $this->fetchAssoc($sql, [':tableowner' => $db['user']]);
if ($res == null) {
@@ -58,7 +58,7 @@ SQL;
public function size(bool $all = false): int {
if ($all) {
- $db = FreshRSS_Context::$system_conf->db;
+ $db = FreshRSS_Context::systemConf()->db;
$res = $this->fetchColumn('SELECT pg_database_size(:base)', 0, [':base' => $db['base']]);
} else {
$sql = <<<SQL
diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php
index 787380637..e72cc74e8 100644
--- a/app/Models/DatabaseDAOSQLite.php
+++ b/app/Models/DatabaseDAOSQLite.php
@@ -65,12 +65,12 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
$sum = 0;
if ($all) {
foreach (glob(DATA_PATH . '/users/*/db.sqlite') ?: [] as $filename) {
- $sum += @filesize($filename);
+ $sum += (@filesize($filename) ?: 0);
}
} else {
- $sum = @filesize(DATA_PATH . '/users/' . $this->current_user . '/db.sqlite');
+ $sum = (@filesize(DATA_PATH . '/users/' . $this->current_user . '/db.sqlite') ?: 0);
}
- return intval($sum);
+ return $sum;
}
public function optimize(): bool {
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index 186b1f166..62ba91db3 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -90,7 +90,7 @@ class FreshRSS_Entry extends Minz_Model {
$entry->_lastSeen($dao['lastSeen']);
}
if (!empty($dao['attributes'])) {
- $entry->_attributes('', $dao['attributes']);
+ $entry->_attributes($dao['attributes']);
}
if (!empty($dao['hash'])) {
$entry->_hash($dao['hash']);
@@ -145,7 +145,7 @@ class FreshRSS_Entry extends Minz_Model {
* Provides the original content without additional content potentially added by loadCompleteContent().
*/
public function originalContent(): string {
- return preg_replace('#<!-- FULLCONTENT start //-->.*<!-- FULLCONTENT end //-->#s', '', $this->content);
+ return preg_replace('#<!-- FULLCONTENT start //-->.*<!-- FULLCONTENT end //-->#s', '', $this->content) ?? '';
}
/**
@@ -160,7 +160,7 @@ class FreshRSS_Entry extends Minz_Model {
$content = $this->content;
- $thumbnailAttribute = $this->attributes('thumbnail');
+ $thumbnailAttribute = $this->attributeArray('thumbnail') ?? [];
if (!empty($thumbnailAttribute['url'])) {
$elink = $thumbnailAttribute['url'];
if ($allowDuplicateEnclosures || !self::containsLink($content, $elink)) {
@@ -174,12 +174,15 @@ HTML;
}
}
- $attributeEnclosures = $this->attributes('enclosures');
+ $attributeEnclosures = $this->attributeArray('enclosures');
if (empty($attributeEnclosures)) {
return $content;
}
foreach ($attributeEnclosures as $enclosure) {
+ if (!is_array($enclosure)) {
+ continue;
+ }
$elink = $enclosure['url'] ?? '';
if ($elink == '') {
continue;
@@ -192,7 +195,10 @@ HTML;
$length = $enclosure['length'] ?? 0;
$medium = $enclosure['medium'] ?? '';
$mime = $enclosure['type'] ?? '';
- $thumbnails = $enclosure['thumbnails'] ?? [];
+ $thumbnails = $enclosure['thumbnails'] ?? null;
+ if (!is_array($thumbnails)) {
+ $thumbnails = [];
+ }
$etitle = $enclosure['title'] ?? '';
$content .= "\n";
@@ -235,7 +241,7 @@ HTML;
/** @return Traversable<array{'url':string,'type'?:string,'medium'?:string,'length'?:int,'title'?:string,'description'?:string,'credit'?:string,'height'?:int,'width'?:int,'thumbnails'?:array<string>}> */
public function enclosures(bool $searchBodyImages = false): Traversable {
- $attributeEnclosures = $this->attributes('enclosures');
+ $attributeEnclosures = $this->attributeArray('enclosures');
if (is_iterable($attributeEnclosures)) {
// FreshRSS 1.20.1+: The enclosures are saved as attributes
yield from $attributeEnclosures;
@@ -249,7 +255,7 @@ HTML;
$dom->loadHTML('<?xml version="1.0" encoding="UTF-8" ?>' . $this->content, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new DOMXPath($dom);
}
- if ($searchEnclosures) {
+ if ($searchEnclosures && $xpath !== null) {
// Legacy code for database entries < FreshRSS 1.20.1
$enclosures = $xpath->query('//div[@class="enclosure"]/p[@class="enclosure-content"]/*[@src]');
if (!empty($enclosures)) {
@@ -272,7 +278,7 @@ HTML;
}
}
}
- if ($searchBodyImages) {
+ if ($searchBodyImages && $xpath !== null) {
$images = $xpath->query('//img');
if (!empty($images)) {
/** @var DOMElement $img */
@@ -300,7 +306,7 @@ HTML;
* @return array{'url':string,'type'?:string,'medium'?:string,'length'?:int,'title'?:string,'description'?:string,'credit'?:string,'height'?:int,'width'?:int,'thumbnails'?:array<string>}|null
*/
public function thumbnail(bool $searchEnclosures = true): ?array {
- $thumbnail = $this->attributes('thumbnail');
+ $thumbnail = $this->attributeArray('thumbnail') ?? [];
// First, use the provided thumbnail, if any
if (!empty($thumbnail['url'])) {
return $thumbnail;
@@ -558,7 +564,7 @@ HTML;
$ok &= in_array($this->feedId, $filter->getFeedIds(), true);
}
if ($ok && $filter->getNotFeedIds()) {
- $ok &= !in_array($this->feedId, $filter->getFeedIds(), true);
+ $ok &= !in_array($this->feedId, $filter->getNotFeedIds(), true);
}
if ($ok && $filter->getAuthor()) {
foreach ($filter->getAuthor() as $author) {
@@ -630,14 +636,15 @@ HTML;
return (bool)$ok;
}
- /** @param array<string,bool> $titlesAsRead */
+ /** @param array<string,bool|int> $titlesAsRead */
public function applyFilterActions(array $titlesAsRead = []): void {
- if ($this->feed === null) {
+ $feed = $this->feed;
+ if ($feed === null) {
return;
}
if (!$this->isRead()) {
- if ($this->feed->attributes('read_upon_reception') ||
- ($this->feed->attributes('read_upon_reception') === null && FreshRSS_Context::$user_conf->mark_when['reception'])) {
+ if ($feed->attributeBoolean('read_upon_reception') ||
+ ($feed->attributeBoolean('read_upon_reception') === null && FreshRSS_Context::userConf()->mark_when['reception'])) {
$this->_isRead(true);
Minz_ExtensionManager::callHook('entry_auto_read', $this, 'upon_reception');
}
@@ -647,11 +654,11 @@ HTML;
Minz_ExtensionManager::callHook('entry_auto_read', $this, 'same_title_in_feed');
}
}
- FreshRSS_Context::$user_conf->applyFilterActions($this);
- if ($this->feed->category() !== null) {
- $this->feed->category()->applyFilterActions($this);
+ FreshRSS_Context::userConf()->applyFilterActions($this);
+ if ($feed->category() !== null) {
+ $feed->category()->applyFilterActions($this);
}
- $this->feed->applyFilterActions($this);
+ $feed->applyFilterActions($this);
}
public function isDay(int $day, int $today): bool {
@@ -684,10 +691,9 @@ HTML;
if ($maxRedirs > 0) {
//Follow any HTML redirection
- $metas = $xpath->query('//meta[@content]');
- /** @var array<DOMElement> $metas */
+ $metas = $xpath->query('//meta[@content]') ?: [];
foreach ($metas as $meta) {
- if (strtolower(trim($meta->getAttribute('http-equiv'))) === 'refresh') {
+ if ($meta instanceof DOMElement && strtolower(trim($meta->getAttribute('http-equiv'))) === 'refresh') {
$refresh = preg_replace('/^[0-9.; ]*\s*(url\s*=)?\s*/i', '', trim($meta->getAttribute('content')));
$refresh = SimplePie_Misc::absolutize_url($refresh, $url);
if ($refresh != false && $refresh !== $url) {
@@ -712,6 +718,9 @@ HTML;
if (!empty($attributes['path_entries_filter'])) {
$filterednodes = $xpath->query((new Gt\CssXPath\Translator($attributes['path_entries_filter']))->asXPath(), $node) ?: [];
foreach ($filterednodes as $filterednode) {
+ if ($filterednode->parentNode === null) {
+ continue;
+ }
$filterednode->parentNode->removeChild($filterednode);
}
}
@@ -747,7 +756,7 @@ HTML;
if ('' !== $fullContent) {
$fullContent = "<!-- FULLCONTENT start //-->{$fullContent}<!-- FULLCONTENT end //-->";
$originalContent = $this->originalContent();
- switch ($feed->attributes('content_action')) {
+ switch ($feed->attributeString('content_action')) {
case 'prepend':
$this->content = $fullContent . $originalContent;
break;
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 23ac3c918..232db8521 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -315,7 +315,7 @@ SQL;
$affected = 0;
$idsChunks = array_chunk($ids, FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER);
foreach ($idsChunks as $idsChunk) {
- $affected += $this->markFavorite($idsChunk, $is_favorite);
+ $affected += ($this->markFavorite($idsChunk, $is_favorite) ?: 0);
}
return $affected;
}
@@ -387,7 +387,7 @@ SQL;
if (count($ids) < 6) { //Speed heuristics
$affected = 0;
foreach ($ids as $id) {
- $affected += $this->markRead($id, $is_read);
+ $affected += ($this->markRead($id, $is_read) ?: 0);
}
return $affected;
} elseif (count($ids) > FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER) {
@@ -395,7 +395,7 @@ SQL;
$affected = 0;
$idsChunks = array_chunk($ids, FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER);
foreach ($idsChunks as $idsChunk) {
- $affected += $this->markRead($idsChunk, $is_read);
+ $affected += ($this->markRead($idsChunk, $is_read) ?: 0);
}
return $affected;
}
@@ -630,7 +630,7 @@ SQL;
/**
* Remember to call updateCachedValue($id_feed) or updateCachedValues() just after.
- * @param array<string,int|bool|string> $options
+ * @param array<string,bool|int|string> $options
* @return int|false
*/
public function cleanOldEntries(int $id_feed, array $options = []) {
@@ -704,6 +704,8 @@ SQL;
$stm = $this->pdo->query($sql);
if ($stm != false) {
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ /** @var array{'id':string,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,'lastSeen':int,
+ * 'hash':string,'is_read':?bool,'is_favorite':?bool,'id_feed':int,'tags':string,'attributes':array<string,mixed>} $row */
yield $row;
}
} else {
@@ -777,7 +779,7 @@ SQL;
}
// Searches are combined by OR and are not recursive
$sub_search = '';
- if ($filter->getEntryIds()) {
+ if ($filter->getEntryIds() !== null) {
$sub_search .= 'AND ' . $alias . 'id IN (';
foreach ($filter->getEntryIds() as $entry_id) {
$sub_search .= '?,';
@@ -786,7 +788,7 @@ SQL;
$sub_search = rtrim($sub_search, ',');
$sub_search .= ') ';
}
- if ($filter->getNotEntryIds()) {
+ if ($filter->getNotEntryIds() !== null) {
$sub_search .= 'AND ' . $alias . 'id NOT IN (';
foreach ($filter->getNotEntryIds() as $entry_id) {
$sub_search .= '?,';
@@ -796,56 +798,56 @@ SQL;
$sub_search .= ') ';
}
- if ($filter->getMinDate()) {
+ if ($filter->getMinDate() !== null) {
$sub_search .= 'AND ' . $alias . 'id >= ? ';
$values[] = "{$filter->getMinDate()}000000";
}
- if ($filter->getMaxDate()) {
+ if ($filter->getMaxDate() !== null) {
$sub_search .= 'AND ' . $alias . 'id <= ? ';
$values[] = "{$filter->getMaxDate()}000000";
}
- if ($filter->getMinPubdate()) {
+ if ($filter->getMinPubdate() !== null) {
$sub_search .= 'AND ' . $alias . 'date >= ? ';
$values[] = $filter->getMinPubdate();
}
- if ($filter->getMaxPubdate()) {
+ if ($filter->getMaxPubdate() !== null) {
$sub_search .= 'AND ' . $alias . 'date <= ? ';
$values[] = $filter->getMaxPubdate();
}
//Negation of date intervals must be combined by OR
- if ($filter->getNotMinDate() || $filter->getNotMaxDate()) {
+ if ($filter->getNotMinDate() !== null || $filter->getNotMaxDate() !== null) {
$sub_search .= 'AND (';
- if ($filter->getNotMinDate()) {
+ if ($filter->getNotMinDate() !== null) {
$sub_search .= $alias . 'id < ?';
$values[] = "{$filter->getNotMinDate()}000000";
if ($filter->getNotMaxDate()) {
$sub_search .= ' OR ';
}
}
- if ($filter->getNotMaxDate()) {
+ if ($filter->getNotMaxDate() !== null) {
$sub_search .= $alias . 'id > ?';
$values[] = "{$filter->getNotMaxDate()}000000";
}
$sub_search .= ') ';
}
- if ($filter->getNotMinPubdate() || $filter->getNotMaxPubdate()) {
+ if ($filter->getNotMinPubdate() !== null || $filter->getNotMaxPubdate() !== null) {
$sub_search .= 'AND (';
- if ($filter->getNotMinPubdate()) {
+ if ($filter->getNotMinPubdate() !== null) {
$sub_search .= $alias . 'date < ?';
$values[] = $filter->getNotMinPubdate();
if ($filter->getNotMaxPubdate()) {
$sub_search .= ' OR ';
}
}
- if ($filter->getNotMaxPubdate()) {
+ if ($filter->getNotMaxPubdate() !== null) {
$sub_search .= $alias . 'date > ?';
$values[] = $filter->getNotMaxPubdate();
}
$sub_search .= ') ';
}
- if ($filter->getFeedIds()) {
+ if ($filter->getFeedIds() !== null) {
$sub_search .= 'AND ' . $alias . 'id_feed IN (';
foreach ($filter->getFeedIds() as $feed_id) {
$sub_search .= '?,';
@@ -854,7 +856,7 @@ SQL;
$sub_search = rtrim($sub_search, ',');
$sub_search .= ') ';
}
- if ($filter->getNotFeedIds()) {
+ if ($filter->getNotFeedIds() !== null) {
$sub_search .= 'AND ' . $alias . 'id_feed NOT IN (';
foreach ($filter->getNotFeedIds() as $feed_id) {
$sub_search .= '?,';
@@ -864,7 +866,7 @@ SQL;
$sub_search .= ') ';
}
- if ($filter->getLabelIds()) {
+ if ($filter->getLabelIds() !== null) {
if ($filter->getLabelIds() === '*') {
$sub_search .= 'AND EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
} else {
@@ -877,7 +879,7 @@ SQL;
$sub_search .= ')) ';
}
}
- if ($filter->getNotLabelIds()) {
+ if ($filter->getNotLabelIds() !== null) {
if ($filter->getNotLabelIds() === '*') {
$sub_search .= 'AND NOT EXISTS (SELECT et.id_tag FROM `_entrytag` et WHERE et.id_entry = ' . $alias . 'id) ';
} else {
@@ -891,7 +893,7 @@ SQL;
}
}
- if ($filter->getLabelNames()) {
+ if ($filter->getLabelNames() !== null) {
$sub_search .= 'AND ' . $alias . 'id IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
foreach ($filter->getLabelNames() as $label_name) {
$sub_search .= '?,';
@@ -900,7 +902,7 @@ SQL;
$sub_search = rtrim($sub_search, ',');
$sub_search .= ')) ';
}
- if ($filter->getNotLabelNames()) {
+ if ($filter->getNotLabelNames() !== null) {
$sub_search .= 'AND ' . $alias . 'id NOT IN (SELECT et.id_entry FROM `_entrytag` et, `_tag` t WHERE et.id_tag = t.id AND t.name IN (';
foreach ($filter->getNotLabelNames() as $label_name) {
$sub_search .= '?,';
@@ -910,57 +912,57 @@ SQL;
$sub_search .= ')) ';
}
- if ($filter->getAuthor()) {
+ if ($filter->getAuthor() !== null) {
foreach ($filter->getAuthor() as $author) {
$sub_search .= 'AND ' . $alias . 'author LIKE ? ';
$values[] = "%{$author}%";
}
}
- if ($filter->getIntitle()) {
+ if ($filter->getIntitle() !== null) {
foreach ($filter->getIntitle() as $title) {
$sub_search .= 'AND ' . $alias . 'title LIKE ? ';
$values[] = "%{$title}%";
}
}
- if ($filter->getTags()) {
+ if ($filter->getTags() !== null) {
foreach ($filter->getTags() as $tag) {
$sub_search .= 'AND ' . static::sqlConcat('TRIM(' . $alias . 'tags) ', " ' #'") . ' LIKE ? ';
$values[] = "%{$tag} #%";
}
}
- if ($filter->getInurl()) {
+ if ($filter->getInurl() !== null) {
foreach ($filter->getInurl() as $url) {
$sub_search .= 'AND ' . $alias . 'link LIKE ? ';
$values[] = "%{$url}%";
}
}
- if ($filter->getNotAuthor()) {
+ if ($filter->getNotAuthor() !== null) {
foreach ($filter->getNotAuthor() as $author) {
$sub_search .= 'AND ' . $alias . 'author NOT LIKE ? ';
$values[] = "%{$author}%";
}
}
- if ($filter->getNotIntitle()) {
+ if ($filter->getNotIntitle() !== null) {
foreach ($filter->getNotIntitle() as $title) {
$sub_search .= 'AND ' . $alias . 'title NOT LIKE ? ';
$values[] = "%{$title}%";
}
}
- if ($filter->getNotTags()) {
+ if ($filter->getNotTags() !== null) {
foreach ($filter->getNotTags() as $tag) {
$sub_search .= 'AND ' . static::sqlConcat('TRIM(' . $alias . 'tags) ', " ' #'") . ' NOT LIKE ? ';
$values[] = "%{$tag} #%";
}
}
- if ($filter->getNotInurl()) {
+ if ($filter->getNotInurl() !== null) {
foreach ($filter->getNotInurl() as $url) {
$sub_search .= 'AND ' . $alias . 'link NOT LIKE ? ';
$values[] = "%{$url}%";
}
}
- if ($filter->getSearch()) {
+ if ($filter->getSearch() !== null) {
foreach ($filter->getSearch() as $search_value) {
if (static::isCompressed()) { // MySQL-only
$sub_search .= 'AND CONCAT(' . $alias . 'title, UNCOMPRESS(' . $alias . 'content_bin)) LIKE ? ';
@@ -972,7 +974,7 @@ SQL;
}
}
}
- if ($filter->getNotSearch()) {
+ if ($filter->getNotSearch() !== null) {
foreach ($filter->getNotSearch() as $search_value) {
if (static::isCompressed()) { // MySQL-only
$sub_search .= 'AND CONCAT(' . $alias . 'title, UNCOMPRESS(' . $alias . 'content_bin)) NOT LIKE ? ';
@@ -1163,9 +1165,11 @@ SQL;
$stm = $this->listWhereRaw($type, $id, $state, $order, $limit, $firstId, $filters, $date_min);
if ($stm) {
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
- /** @var array{'id':string,'id_feed':int,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
- * 'hash':string,'is_read':int,'is_favorite':int,'tags':string,'attributes'?:string} $row */
- yield FreshRSS_Entry::fromArray($row);
+ if (is_array($row)) {
+ /** @var array{'id':string,'id_feed':int,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
+ * 'hash':string,'is_read':int,'is_favorite':int,'tags':string,'attributes'?:string} $row */
+ yield FreshRSS_Entry::fromArray($row);
+ }
}
}
}
@@ -1206,9 +1210,11 @@ SQL;
return;
}
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
- /** @var array{'id':string,'id_feed':int,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
- * 'hash':string,'is_read':int,'is_favorite':int,'tags':string,'attributes'?:string} $row */
- yield FreshRSS_Entry::fromArray($row);
+ if (is_array($row)) {
+ /** @var array{'id':string,'id_feed':int,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,
+ * 'hash':string,'is_read':int,'is_favorite':int,'tags':string,'attributes'?:string} $row */
+ yield FreshRSS_Entry::fromArray($row);
+ }
}
}
@@ -1283,7 +1289,7 @@ SQL;
$affected = 0;
$guidsChunks = array_chunk($guids, FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER);
foreach ($guidsChunks as $guidsChunk) {
- $affected += $this->updateLastSeen($id_feed, $guidsChunk, $mtime);
+ $affected += ($this->updateLastSeen($id_feed, $guidsChunk, $mtime) ?: 0);
}
return $affected;
}
diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php
index 66feb567b..1a87d03be 100644
--- a/app/Models/EntryDAOSQLite.php
+++ b/app/Models/EntryDAOSQLite.php
@@ -80,7 +80,7 @@ SQL;
//if (true) { //Speed heuristics //TODO: Not implemented yet for SQLite (so always call IDs one by one)
$affected = 0;
foreach ($ids as $id) {
- $affected += $this->markRead($id, $is_read);
+ $affected += ($this->markRead($id, $is_read) ?: 0);
}
return $affected;
//}
diff --git a/app/Models/Factory.php b/app/Models/Factory.php
index eef3c81f5..f69c7f6aa 100644
--- a/app/Models/Factory.php
+++ b/app/Models/Factory.php
@@ -14,7 +14,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createCategoryDao(?string $username = null): FreshRSS_CategoryDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_CategoryDAOSQLite($username);
default:
@@ -26,7 +26,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createFeedDao(?string $username = null): FreshRSS_FeedDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_FeedDAOSQLite($username);
default:
@@ -38,7 +38,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createEntryDao(?string $username = null): FreshRSS_EntryDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_EntryDAOSQLite($username);
case 'pgsql':
@@ -52,7 +52,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createTagDao(?string $username = null): FreshRSS_TagDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_TagDAOSQLite($username);
case 'pgsql':
@@ -66,7 +66,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createStatsDAO(?string $username = null): FreshRSS_StatsDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_StatsDAOSQLite($username);
case 'pgsql':
@@ -80,7 +80,7 @@ class FreshRSS_Factory {
* @throws Minz_ConfigurationNamespaceException|Minz_PDOConnectionException
*/
public static function createDatabaseDAO(?string $username = null): FreshRSS_DatabaseDAO {
- switch (FreshRSS_Context::$system_conf->db['type'] ?? '') {
+ switch (FreshRSS_Context::systemConf()->db['type'] ?? '') {
case 'sqlite':
return new FreshRSS_DatabaseDAOSQLite($username);
case 'pgsql':
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index dbe6aaa73..024a7841a 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -82,7 +82,7 @@ class FreshRSS_Feed extends Minz_Model {
public function hash(): string {
if ($this->hash == '') {
- $salt = FreshRSS_Context::$system_conf->salt;
+ $salt = FreshRSS_Context::systemConf()->salt;
$this->hash = hash('crc32b', $salt . $this->url);
}
return $this->hash;
@@ -126,7 +126,7 @@ class FreshRSS_Feed extends Minz_Model {
return $simplePie == null ? [] : iterator_to_array($this->loadEntries($simplePie));
}
public function name(bool $raw = false): string {
- return $raw || $this->name != '' ? $this->name : preg_replace('%^https?://(www[.])?%i', '', $this->url);
+ return $raw || $this->name != '' ? $this->name : (preg_replace('%^https?://(www[.])?%i', '', $this->url) ?? '');
}
/** @return string HTML-encoded URL of the Web site of the feed */
public function website(): string {
@@ -179,7 +179,7 @@ class FreshRSS_Feed extends Minz_Model {
if ($raw) {
$ttl = $this->ttl;
if ($this->mute && FreshRSS_Feed::TTL_DEFAULT === $ttl) {
- $ttl = FreshRSS_Context::$user_conf ? FreshRSS_Context::$user_conf->ttl_default : 3600;
+ $ttl = FreshRSS_Context::userConf()->ttl_default;
}
return $ttl * ($this->mute ? -1 : 1);
}
@@ -331,7 +331,7 @@ class FreshRSS_Feed extends Minz_Model {
} else {
$url = htmlspecialchars_decode($this->url, ENT_QUOTES);
if ($this->httpAuth != '') {
- $url = preg_replace('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url);
+ $url = preg_replace('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url) ?? '';
}
$simplePie = customSimplePie($this->attributes());
if (substr($url, -11) === '#force_feed') {
@@ -342,7 +342,7 @@ class FreshRSS_Feed extends Minz_Model {
if (!$loadDetails) { //Only activates auto-discovery when adding a new feed
$simplePie->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE);
}
- if ($this->attributes('clear_cache')) {
+ if ($this->attributeBoolean('clear_cache')) {
// Do not use `$simplePie->enable_cache(false);` as it would prevent caching in multiuser context
$this->clearCache();
}
@@ -370,7 +370,7 @@ class FreshRSS_Feed extends Minz_Model {
if ($loadDetails) {
// si on a utilisé l’auto-discover, notre url va avoir changé
- $subscribe_url = $simplePie->subscribe_url(false);
+ $subscribe_url = $simplePie->subscribe_url(false) ?? '';
if ($this->name(true) === '') {
//HTML to HTML-PRE //ENT_COMPAT except '&'
@@ -385,11 +385,11 @@ class FreshRSS_Feed extends Minz_Model {
}
} else {
//The case of HTTP 301 Moved Permanently
- $subscribe_url = $simplePie->subscribe_url(true);
+ $subscribe_url = $simplePie->subscribe_url(true) ?? '';
}
$clean_url = SimplePie_Misc::url_remove_credentials($subscribe_url);
- if ($subscribe_url !== null && $subscribe_url !== $url) {
+ if ($subscribe_url !== '' && $subscribe_url !== $url) {
$this->_url($clean_url);
}
@@ -411,7 +411,7 @@ class FreshRSS_Feed extends Minz_Model {
$testGuids = [];
$guids = [];
$links = [];
- $hadBadGuids = $this->attributes('hasBadGuids');
+ $hadBadGuids = $this->attributeBoolean('hasBadGuids');
$items = $simplePie->get_items();
if (empty($items)) {
@@ -426,7 +426,10 @@ class FreshRSS_Feed extends Minz_Model {
$hasUniqueGuids &= empty($testGuids['_' . $guid]);
$testGuids['_' . $guid] = true;
$guids[] = $guid;
- $links[] = $item->get_permalink();
+ $permalink = $item->get_permalink();
+ if ($permalink != null) {
+ $links[] = $permalink;
+ }
}
if ($hadBadGuids != !$hasUniqueGuids) {
@@ -444,7 +447,7 @@ class FreshRSS_Feed extends Minz_Model {
/** @return Traversable<FreshRSS_Entry> */
public function loadEntries(SimplePie $simplePie): Traversable {
- $hasBadGuids = $this->attributes('hasBadGuids');
+ $hasBadGuids = $this->attributeBoolean('hasBadGuids');
$items = $simplePie->get_items();
if (empty($items)) {
@@ -560,15 +563,15 @@ class FreshRSS_Feed extends Minz_Model {
$title == '' ? '' : $title,
$authorNames,
$content == '' ? '' : $content,
- $link == '' ? '' : $link,
+ $link == null ? '' : $link,
$date ?: time()
);
$entry->_tags($tags);
$entry->_feed($this);
if (!empty($attributeThumbnail['url'])) {
- $entry->_attributes('thumbnail', $attributeThumbnail);
+ $entry->_attribute('thumbnail', $attributeThumbnail);
}
- $entry->_attributes('enclosures', $attributeEnclosures);
+ $entry->_attribute('enclosures', $attributeEnclosures);
$entry->hash(); //Must be computed before loading full content
$entry->loadCompleteContent(); // Optionally load full content for truncated feeds
@@ -587,11 +590,14 @@ class FreshRSS_Feed extends Minz_Model {
if ($this->httpAuth != '') {
$feedSourceUrl = preg_replace('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $feedSourceUrl);
}
+ if ($feedSourceUrl == null) {
+ return null;
+ }
// Same naming conventions than https://rss-bridge.github.io/rss-bridge/Bridge_API/XPathAbstract.html
// https://rss-bridge.github.io/rss-bridge/Bridge_API/BridgeAbstract.html#collectdata
/** @var array<string,string> $xPathSettings */
- $xPathSettings = $this->attributes('xpath');
+ $xPathSettings = $this->attributeArray('xpath');
$xPathFeedTitle = $xPathSettings['feedTitle'] ?? '';
$xPathItem = $xPathSettings['item'] ?? '';
$xPathItemTitle = $xPathSettings['itemTitle'] ?? '';
@@ -725,9 +731,9 @@ class FreshRSS_Feed extends Minz_Model {
* @throws JsonException
*/
public function keepMaxUnread() {
- $keepMaxUnread = $this->attributes('keep_max_n_unread');
+ $keepMaxUnread = $this->attributeInt('keep_max_n_unread');
if ($keepMaxUnread === null) {
- $keepMaxUnread = FreshRSS_Context::$user_conf->mark_when['max_n_unread'];
+ $keepMaxUnread = FreshRSS_Context::userConf()->mark_when['max_n_unread'];
}
return is_int($keepMaxUnread) && $keepMaxUnread >= 0 ? $keepMaxUnread : null;
}
@@ -754,9 +760,9 @@ class FreshRSS_Feed extends Minz_Model {
* @return int|false the number of lines affected, or false if not applicable
*/
public function markAsReadUponGone(bool $upstreamIsEmpty, int $maxTimestamp = 0) {
- $readUponGone = $this->attributes('read_upon_gone');
+ $readUponGone = $this->attributeBoolean('read_upon_gone');
if ($readUponGone === null) {
- $readUponGone = FreshRSS_Context::$user_conf->mark_when['gone'];
+ $readUponGone = FreshRSS_Context::userConf()->mark_when['gone'];
}
if (!$readUponGone) {
return false;
@@ -782,13 +788,15 @@ class FreshRSS_Feed extends Minz_Model {
* @return int|false
*/
public function cleanOldEntries() {
- $archiving = $this->attributes('archiving');
- if ($archiving == null) {
+ /** @var array<string,bool|int|string>|null $archiving */
+ $archiving = $this->attributeArray('archiving');
+ if ($archiving === null) {
$catDAO = FreshRSS_Factory::createCategoryDao();
$category = $catDAO->searchById($this->categoryId);
- $archiving = $category == null ? null : $category->attributes('archiving');
- if ($archiving == null) {
- $archiving = FreshRSS_Context::$user_conf->archiving;
+ $archiving = $category === null ? null : $category->attributeArray('archiving');
+ /** @var array<string,bool|int|string>|null $archiving */
+ if ($archiving === null) {
+ $archiving = FreshRSS_Context::userConf()->archiving;
}
}
if (is_array($archiving)) {
@@ -850,7 +858,7 @@ class FreshRSS_Feed extends Minz_Model {
$hubFilename = PSHB_PATH . '/feeds/' . sha1($url) . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
- if ($hubJson && empty($hubJson['error']) &&
+ if (is_array($hubJson) && empty($hubJson['error']) &&
(empty($hubJson['lease_end']) || $hubJson['lease_end'] > time())) {
return true;
}
@@ -862,8 +870,8 @@ class FreshRSS_Feed extends Minz_Model {
$url = $this->selfUrl ?: $this->url;
$hubFilename = PSHB_PATH . '/feeds/' . sha1($url) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
- $hubJson = $hubFile ? json_decode($hubFile, true) : [];
- if (!isset($hubJson['error']) || $hubJson['error'] !== $error) {
+ $hubJson = is_string($hubFile) ? json_decode($hubFile, true) : null;
+ if (is_array($hubJson) && !isset($hubJson['error']) || $hubJson['error'] !== $error) {
$hubJson['error'] = $error;
file_put_contents($hubFilename, json_encode($hubJson));
Minz_Log::warning('Set error to ' . ($error ? 1 : 0) . ' for ' . $url, PSHB_LOG);
@@ -876,13 +884,13 @@ class FreshRSS_Feed extends Minz_Model {
*/
public function pubSubHubbubPrepare() {
$key = '';
- if (Minz_Request::serverIsPublic(FreshRSS_Context::$system_conf->base_url) &&
+ if (Minz_Request::serverIsPublic(FreshRSS_Context::systemConf()->base_url) &&
$this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) {
$path = PSHB_PATH . '/feeds/' . sha1($this->selfUrl);
$hubFilename = $path . '/!hub.json';
if ($hubFile = @file_get_contents($hubFilename)) {
$hubJson = json_decode($hubFile, true);
- if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
+ if (!is_array($hubJson) || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
$text = 'Invalid JSON for WebSub: ' . $this->url;
Minz_Log::warning($text);
Minz_Log::warning($text, PSHB_LOG);
@@ -901,7 +909,7 @@ class FreshRSS_Feed extends Minz_Model {
}
} else {
@mkdir($path, 0770, true);
- $key = sha1($path . FreshRSS_Context::$system_conf->salt);
+ $key = sha1($path . FreshRSS_Context::systemConf()->salt);
$hubJson = [
'hub' => $this->hubUrl,
'key' => $key,
@@ -913,7 +921,7 @@ class FreshRSS_Feed extends Minz_Model {
Minz_Log::debug($text);
Minz_Log::debug($text, PSHB_LOG);
}
- $currentUser = Minz_User::name();
+ $currentUser = Minz_User::name() ?? '';
if (FreshRSS_user_Controller::checkUsername($currentUser) && !file_exists($path . '/' . $currentUser . '.txt')) {
touch($path . '/' . $currentUser . '.txt');
}
@@ -928,7 +936,7 @@ class FreshRSS_Feed extends Minz_Model {
} else {
$url = $this->url; //Always use current URL during unsubscribe
}
- if ($url && (Minz_Request::serverIsPublic(FreshRSS_Context::$system_conf->base_url) || !$state)) {
+ if ($url && (Minz_Request::serverIsPublic(FreshRSS_Context::systemConf()->base_url) || !$state)) {
$hubFilename = PSHB_PATH . '/feeds/' . sha1($url) . '/!hub.json';
$hubFile = @file_get_contents($hubFilename);
if ($hubFile === false) {
@@ -936,7 +944,7 @@ class FreshRSS_Feed extends Minz_Model {
return false;
}
$hubJson = json_decode($hubFile, true);
- if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key']) || empty($hubJson['hub'])) {
+ if (!is_array($hubJson) || empty($hubJson['key']) || !ctype_xdigit($hubJson['key']) || empty($hubJson['hub'])) {
Minz_Log::warning('Invalid JSON for WebSub: ' . $this->url);
return false;
}
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index ac844217a..895d2d333 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -118,7 +118,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
// Merge existing and import attributes
$existingAttributes = $feed_search->attributes();
$importAttributes = $feed->attributes();
- $feed->_attributes('', array_replace_recursive($existingAttributes, $importAttributes));
+ $feed->_attributes(array_replace_recursive($existingAttributes, $importAttributes));
// Update some values of the existing feed using the import
$values = [
@@ -190,11 +190,12 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
}
/**
+ * @param non-empty-string $key
* @param string|array<mixed>|bool|int|null $value
* @return int|false
*/
public function updateFeedAttribute(FreshRSS_Feed $feed, string $key, $value) {
- $feed->_attributes($key, $value);
+ $feed->_attribute($key, $value);
return $this->updateFeed(
$feed->id(),
['attributes' => $feed->attributes()]
@@ -236,6 +237,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
if ($newCat === null) {
$newCat = $catDAO->getDefault();
}
+ if ($newCat === null) {
+ return false;
+ }
$sql = 'UPDATE `_feed` SET category=? WHERE category=?';
$stm = $this->pdo->prepare($sql);
@@ -305,6 +309,8 @@ SQL;
return;
}
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ /** @var array{'id':int,'url':string,'kind':int,'category':int,'name':string,'website':string,'description':string,'lastUpdate':int,'priority'?:int,
+ * 'pathEntries'?:string,'httpAuth':string,'error':int|bool,'ttl'?:int,'attributes'?:string} $row */
yield $row;
}
}
@@ -393,12 +399,12 @@ SQL;
}
}
- /** @return array<string> */
+ /** @return array<int,string> */
public function listTitles(int $id, int $limit = 0): array {
$sql = 'SELECT title FROM `_entry` WHERE id_feed=:id_feed ORDER BY id DESC'
. ($limit < 1 ? '' : ' LIMIT ' . intval($limit));
$res = $this->fetchColumn($sql, 0, [':id_feed' => $id]) ?? [];
- /** @var array<string> $res */
+ /** @var array<int,string> $res */
return $res;
}
@@ -609,7 +615,7 @@ SQL;
$myFeed->_httpAuth(base64_decode($dao['httpAuth'] ?? '', true) ?: '');
$myFeed->_error($dao['error'] ?? 0);
$myFeed->_ttl($dao['ttl'] ?? FreshRSS_Feed::TTL_DEFAULT);
- $myFeed->_attributes('', $dao['attributes'] ?? '');
+ $myFeed->_attributes($dao['attributes'] ?? '');
$myFeed->_nbNotRead($dao['cache_nbUnreads'] ?? -1);
$myFeed->_nbEntries($dao['cache_nbEntries'] ?? -1);
if (isset($dao['id'])) {
diff --git a/app/Models/FilterAction.php b/app/Models/FilterAction.php
index 6487d5100..bf5a79fe7 100644
--- a/app/Models/FilterAction.php
+++ b/app/Models/FilterAction.php
@@ -44,7 +44,7 @@ class FreshRSS_FilterAction {
/** @param array|mixed|null $json */
public static function fromJSON($json): ?FreshRSS_FilterAction {
- if (!empty($json['search']) && !empty($json['actions']) && is_array($json['actions'])) {
+ if (is_array($json) && !empty($json['search']) && !empty($json['actions']) && is_array($json['actions'])) {
return new FreshRSS_FilterAction(new FreshRSS_BooleanSearch($json['search']), $json['actions']);
}
return null;
diff --git a/app/Models/FilterActionsTrait.php b/app/Models/FilterActionsTrait.php
index 869992b21..aefb549af 100644
--- a/app/Models/FilterActionsTrait.php
+++ b/app/Models/FilterActionsTrait.php
@@ -15,13 +15,11 @@ trait FreshRSS_FilterActionsTrait {
private function filterActions(): array {
if (empty($this->filterActions)) {
$this->filterActions = [];
- $filters = $this->attributes('filters');
- if (is_array($filters)) {
- foreach ($filters as $filter) {
- $filterAction = FreshRSS_FilterAction::fromJSON($filter);
- if ($filterAction != null) {
- $this->filterActions[] = $filterAction;
- }
+ $filters = $this->attributeArray('filters') ?? [];
+ foreach ($filters as $filter) {
+ $filterAction = FreshRSS_FilterAction::fromJSON($filter);
+ if ($filterAction != null) {
+ $this->filterActions[] = $filterAction;
}
}
}
@@ -33,12 +31,12 @@ trait FreshRSS_FilterActionsTrait {
*/
private function _filterActions(?array $filterActions): void {
$this->filterActions = $filterActions;
- if (is_array($this->filterActions) && !empty($this->filterActions)) {
- $this->_attributes('filters', array_map(static function (?FreshRSS_FilterAction $af) {
+ if ($this->filterActions !== null && !empty($this->filterActions)) {
+ $this->_attribute('filters', array_map(static function (?FreshRSS_FilterAction $af) {
return $af == null ? null : $af->toJSON();
}, $this->filterActions));
} else {
- $this->_attributes('filters', null);
+ $this->_attribute('filters', null);
}
}
diff --git a/app/Models/FormAuth.php b/app/Models/FormAuth.php
index 83fb60e3c..a8b4dab8a 100644
--- a/app/Models/FormAuth.php
+++ b/app/Models/FormAuth.php
@@ -23,7 +23,7 @@ class FreshRSS_FormAuth {
$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
$mtime = @filemtime($token_file) ?: 0;
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$cookie_duration = empty($limits['cookie_duration']) ? FreshRSS_Auth::DEFAULT_COOKIE_DURATION : $limits['cookie_duration'];
if ($mtime + $cookie_duration < time()) {
// Token has expired (> cookie_duration) or does not exist.
@@ -42,7 +42,7 @@ class FreshRSS_FormAuth {
private static function renewCookie(string $token) {
$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
if (touch($token_file)) {
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$cookie_duration = empty($limits['cookie_duration']) ? FreshRSS_Auth::DEFAULT_COOKIE_DURATION : $limits['cookie_duration'];
$expire = time() + $cookie_duration;
Minz_Session::setLongTermCookie('FreshRSS_login', $token, $expire);
@@ -54,7 +54,7 @@ class FreshRSS_FormAuth {
/** @return string|false */
public static function makeCookie(string $username, string $password_hash) {
do {
- $token = sha1(FreshRSS_Context::$system_conf->salt . $username . uniqid('' . mt_rand(), true));
+ $token = sha1(FreshRSS_Context::systemConf()->salt . $username . uniqid('' . mt_rand(), true));
$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
} while (file_exists($token_file));
@@ -78,7 +78,7 @@ class FreshRSS_FormAuth {
}
public static function purgeTokens(): void {
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$cookie_duration = empty($limits['cookie_duration']) ? FreshRSS_Auth::DEFAULT_COOKIE_DURATION : $limits['cookie_duration'];
$oldest = time() - $cookie_duration;
foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) {
diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php
index 0e0bad623..9bdc255e3 100644
--- a/app/Models/StatsDAO.php
+++ b/app/Models/StatsDAO.php
@@ -248,8 +248,8 @@ WHERE c.id = f.category
GROUP BY label
ORDER BY data DESC
SQL;
- $res = $this->fetchAssoc($sql);
/** @var array<array{'label':string,'data':int}>|null @res */
+ $res = $this->fetchAssoc($sql);
return $res == null ? [] : $res;
}
diff --git a/app/Models/SystemConfiguration.php b/app/Models/SystemConfiguration.php
index 294ca1e3a..3efe33b15 100644
--- a/app/Models/SystemConfiguration.php
+++ b/app/Models/SystemConfiguration.php
@@ -5,7 +5,7 @@ declare(strict_types=1);
* @property bool $allow_anonymous
* @property bool $allow_anonymous_refresh
* @property-read bool $allow_referrer
- * @property-read bool $allow_robots
+ * @property bool $allow_robots
* @property bool $api_enabled
* @property string $archiving
* @property 'form'|'http_auth'|'none' $auth_type
@@ -16,7 +16,7 @@ declare(strict_types=1);
* @property bool $force_email_validation
* @property-read bool $http_auth_auto_register
* @property-read string $http_auth_auto_register_email_field
- * @property-read string $language
+ * @property string $language
* @property array<string,int> $limits
* @property-read string $logo_html
* @property-read string $meta_description
@@ -25,6 +25,7 @@ declare(strict_types=1);
* @property-read bool $simplepie_syslog_enabled
* @property bool $unsafe_autologin_enabled
* @property array<string> $trusted_sources
+ * @property array<string,array<string,mixed>> $extensions
*/
final class FreshRSS_SystemConfiguration extends Minz_Configuration {
diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php
index 8587e576f..fba27dc7b 100644
--- a/app/Models/TagDAO.php
+++ b/app/Models/TagDAO.php
@@ -96,11 +96,12 @@ SQL;
}
/**
+ * @param non-empty-string $key
* @param mixed $value
* @return int|false
*/
public function updateTagAttribute(FreshRSS_Tag $tag, string $key, $value) {
- $tag->_attributes($key, $value);
+ $tag->_attribute($key, $value);
return $this->updateTagAttributes($tag->id(), $tag->attributes());
}
@@ -134,6 +135,7 @@ SQL;
return;
}
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ /** @var array{'id':int,'name':string,'attributes'?:array<string,mixed>} $row */
yield $row;
}
}
@@ -410,7 +412,7 @@ SQL;
$tag = new FreshRSS_Tag($dao['name']);
$tag->_id($dao['id']);
if (!empty($dao['attributes'])) {
- $tag->_attributes('', $dao['attributes']);
+ $tag->_attributes($dao['attributes']);
}
if (isset($dao['unreads'])) {
$tag->_nbUnread($dao['unreads']);
diff --git a/app/Models/Themes.php b/app/Models/Themes.php
index 53ae1dc27..fab29e986 100644
--- a/app/Models/Themes.php
+++ b/app/Models/Themes.php
@@ -38,11 +38,12 @@ class FreshRSS_Themes extends Minz_Model {
if (file_exists($json_filename)) {
$content = file_get_contents($json_filename) ?: '';
$res = json_decode($content, true);
- if ($res &&
+ if (is_array($res) &&
!empty($res['name']) &&
isset($res['files']) &&
is_array($res['files'])) {
$res['id'] = $theme_id;
+ /** @var array{'id':string,'name':string,'author':string,'description':string,'version':float|string,'files':array<string>,'theme-color'?:string|array{'dark'?:string,'light'?:string,'default'?:string}} */
return $res;
}
}
@@ -155,7 +156,7 @@ class FreshRSS_Themes extends Minz_Model {
}
if ($type == self::ICON_DEFAULT) {
- if ((FreshRSS_Context::$user_conf && FreshRSS_Context::$user_conf->icons_as_emojis)
+ if ((FreshRSS_Context::hasUserConf() && FreshRSS_Context::userConf()->icons_as_emojis)
// default to emoji alternate for some icons
) {
$type = self::ICON_EMOJI;
diff --git a/app/Models/UserConfiguration.php b/app/Models/UserConfiguration.php
index 0aec3a05f..a1e0dbbaa 100644
--- a/app/Models/UserConfiguration.php
+++ b/app/Models/UserConfiguration.php
@@ -70,6 +70,7 @@ declare(strict_types=1);
* @property-read bool $unsafe_autologin_enabled
* @property string $view_mode
* @property array<string,mixed> $volatile
+ * @property array<string,array<string,mixed>> $extensions
*/
final class FreshRSS_UserConfiguration extends Minz_Configuration {
use FreshRSS_FilterActionsTrait;
@@ -81,22 +82,37 @@ final class FreshRSS_UserConfiguration extends Minz_Configuration {
}
/**
- * @phpstan-return ($key is non-empty-string ? mixed : array<string,mixed>)
- * @return array<string,mixed>|mixed|null
+ * @param non-empty-string $key
+ * @return array<int|string,mixed>|null
*/
- public function attributes(string $key = '') {
- if ($key === '') {
- return []; // Not implemented for user configuration
- } else {
- return parent::param($key, null);
- }
+ public function attributeArray(string $key): ?array {
+ $a = parent::param($key, null);
+ return is_array($a) ? $a : null;
}
- /** @param string|array<mixed>|bool|int|null $value Value, not HTML-encoded */
- public function _attributes(string $key, $value = null): void {
- if ($key == '') {
- return; // Not implemented for user configuration
- }
+ /** @param non-empty-string $key */
+ public function attributeBool(string $key): ?bool {
+ $a = parent::param($key, null);
+ return is_bool($a) ? $a : null;
+ }
+
+ /** @param non-empty-string $key */
+ public function attributeInt(string $key): ?int {
+ $a = parent::param($key, null);
+ return is_numeric($a) ? (int)$a : null;
+ }
+
+ /** @param non-empty-string $key */
+ public function attributeString(string $key): ?string {
+ $a = parent::param($key, null);
+ return is_string($a) ? $a : null;
+ }
+
+ /**
+ * @param non-empty-string $key
+ * @param array<string,mixed>|mixed|null $value Value, not HTML-encoded
+ */
+ public function _attribute(string $key, $value = null): void {
parent::_param($key, $value);
}
}
diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php
index f33ebed96..278fa4cec 100644
--- a/app/Services/ImportService.php
+++ b/app/Services/ImportService.php
@@ -68,7 +68,7 @@ class FreshRSS_Import_Service {
// verify the user can import its categories/feeds.
$nb_categories = count($categories);
$nb_feeds = count($this->feedDAO->listFeeds());
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
// Process the OPML outlines to get a list of categories and a list of
// feeds elements indexed by their categories names.
@@ -173,7 +173,7 @@ class FreshRSS_Import_Service {
}
if (isset($feed_elt['frss:cssFullContentFilter'])) {
- $feed->_attributes('path_entries_filter', $feed_elt['frss:cssFullContentFilter']);
+ $feed->_attribute('path_entries_filter', $feed_elt['frss:cssFullContentFilter']);
}
if (isset($feed_elt['frss:filtersActionRead'])) {
@@ -216,7 +216,7 @@ class FreshRSS_Import_Service {
}
if (!empty($xPathSettings)) {
- $feed->_attributes('xpath', $xPathSettings);
+ $feed->_attribute('xpath', $xPathSettings);
}
// Call the extension hook
@@ -263,7 +263,7 @@ class FreshRSS_Import_Service {
$opml_url = checkUrl($category_element['frss:opmlUrl']);
if ($opml_url != '') {
$category->_kind(FreshRSS_Category::KIND_DYNAMIC_OPML);
- $category->_attributes('opml_url', $opml_url);
+ $category->_attribute('opml_url', $opml_url);
}
}
diff --git a/app/Utils/feverUtil.php b/app/Utils/feverUtil.php
index 3c2b8bd2e..571c2bc00 100644
--- a/app/Utils/feverUtil.php
+++ b/app/Utils/feverUtil.php
@@ -29,10 +29,7 @@ class FreshRSS_fever_Util {
* @throws FreshRSS_Context_Exception
*/
public static function getKeyPath(string $feverKey): string {
- if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
- }
- $salt = sha1(FreshRSS_Context::$system_conf->salt);
+ $salt = sha1(FreshRSS_Context::systemConf()->salt);
return self::FEVER_PATH . '/.key-' . $salt . '-' . $feverKey . '.txt';
}
diff --git a/app/actualize_script.php b/app/actualize_script.php
index 5eb76b3ec..df3327e10 100755
--- a/app/actualize_script.php
+++ b/app/actualize_script.php
@@ -19,11 +19,8 @@ $_SERVER['HTTP_HOST'] = '';
$app = new FreshRSS();
FreshRSS_Context::initSystem();
-if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
-}
-FreshRSS_Context::$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!)
-define('SIMPLEPIE_SYSLOG_ENABLED', FreshRSS_Context::$system_conf->simplepie_syslog_enabled);
+FreshRSS_Context::systemConf()->auth_type = 'none'; // avoid necessity to be logged in (not saved!)
+define('SIMPLEPIE_SYSLOG_ENABLED', FreshRSS_Context::systemConf()->simplepie_syslog_enabled);
/**
* Writes to FreshRSS admin log, and if it is not already done by default,
@@ -62,7 +59,7 @@ notice('FreshRSS starting feeds actualization at ' . $begin_date->format('c'));
// make sure the PHP setup of the CLI environment is compatible with FreshRSS as well
echo 'Failed requirements!', "\n";
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
ob_clean();
echo 'Results: ', "\n"; //Buffered
@@ -71,24 +68,24 @@ echo 'Results: ', "\n"; //Buffered
// Users are processed in a random order but always start with default user
$users = listUsers();
shuffle($users);
-if (FreshRSS_Context::$system_conf->default_user !== '') {
- array_unshift($users, FreshRSS_Context::$system_conf->default_user);
+if (FreshRSS_Context::systemConf()->default_user !== '') {
+ array_unshift($users, FreshRSS_Context::systemConf()->default_user);
$users = array_unique($users);
}
-$limits = FreshRSS_Context::$system_conf->limits;
+$limits = FreshRSS_Context::systemConf()->limits;
$min_last_activity = time() - $limits['max_inactivity'];
foreach ($users as $user) {
FreshRSS_Context::initUser($user);
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
notice('Invalid user ' . $user);
continue;
}
- if (!FreshRSS_Context::$user_conf->enabled) {
+ if (!FreshRSS_Context::userConf()->enabled) {
notice('FreshRSS skip disabled user ' . $user);
continue;
}
- if (($user !== FreshRSS_Context::$system_conf->default_user) &&
+ if (($user !== FreshRSS_Context::systemConf()->default_user) &&
(FreshRSS_UserDAO::mtime($user) < $min_last_activity)) {
notice('FreshRSS skip inactive user ' . $user);
continue;
@@ -106,7 +103,7 @@ foreach ($users as $user) {
notice('FreshRSS actualize ' . $user . '…');
echo $user, ' '; //Buffered
- Minz_ExtensionManager::callHook('freshrss_user_maintenance');
+ Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance');
$app->run();
if (!invalidateHttpCache()) {
diff --git a/app/install.php b/app/install.php
index 348ba079b..b4da2911f 100644
--- a/app/install.php
+++ b/app/install.php
@@ -70,20 +70,20 @@ function saveStep1(): void {
// First, we try to get previous configurations
FreshRSS_Context::initSystem();
- FreshRSS_Context::initUser(FreshRSS_Context::$system_conf->default_user, false);
+ FreshRSS_Context::initUser(FreshRSS_Context::systemConf()->default_user, false);
// Then, we set $_SESSION vars
Minz_Session::_params([
- 'title' => FreshRSS_Context::$system_conf->title,
- 'auth_type' => FreshRSS_Context::$system_conf->auth_type,
- 'default_user' => Minz_User::name(),
- 'passwordHash' => FreshRSS_Context::$user_conf->passwordHash,
- 'bd_type' => FreshRSS_Context::$system_conf->db['type'] ?? '',
- 'bd_host' => FreshRSS_Context::$system_conf->db['host'] ?? '',
- 'bd_user' => FreshRSS_Context::$system_conf->db['user'] ?? '',
- 'bd_password' => FreshRSS_Context::$system_conf->db['password'] ?? '',
- 'bd_base' => FreshRSS_Context::$system_conf->db['base'] ?? '',
- 'bd_prefix' => FreshRSS_Context::$system_conf->db['prefix'] ?? '',
+ 'title' => FreshRSS_Context::systemConf()->title,
+ 'auth_type' => FreshRSS_Context::systemConf()->auth_type,
+ 'default_user' => Minz_User::name() ?? '',
+ 'passwordHash' => FreshRSS_Context::userConf()->passwordHash,
+ 'bd_type' => FreshRSS_Context::systemConf()->db['type'] ?? '',
+ 'bd_host' => FreshRSS_Context::systemConf()->db['host'] ?? '',
+ 'bd_user' => FreshRSS_Context::systemConf()->db['user'] ?? '',
+ 'bd_password' => FreshRSS_Context::systemConf()->db['password'] ?? '',
+ 'bd_base' => FreshRSS_Context::systemConf()->db['base'] ?? '',
+ 'bd_prefix' => FreshRSS_Context::systemConf()->db['prefix'] ?? '',
'bd_error' => false,
]);
@@ -191,33 +191,34 @@ function saveStep3(): bool {
Minz_Translate::init(Minz_Session::paramString('language'));
if (!empty($_POST)) {
- if (param('auth_type', 'form') != '') {
- FreshRSS_Context::$system_conf->auth_type = param('auth_type', 'form');
- Minz_Session::_param('auth_type', FreshRSS_Context::$system_conf->auth_type);
+ $auth_type = param('auth_type', 'form');
+ if (in_array($auth_type, ['form', 'http_auth', 'none'], true)) {
+ FreshRSS_Context::systemConf()->auth_type = $auth_type;
+ Minz_Session::_param('auth_type', FreshRSS_Context::systemConf()->auth_type);
} else {
return false;
}
$password_plain = param('passwordPlain', '');
- if (FreshRSS_Context::$system_conf->auth_type === 'form' && $password_plain == '') {
+ if (FreshRSS_Context::systemConf()->auth_type === 'form' && $password_plain == '') {
return false;
}
if (FreshRSS_user_Controller::checkUsername(param('default_user', ''))) {
- FreshRSS_Context::$system_conf->default_user = param('default_user', '');
- Minz_Session::_param('default_user', FreshRSS_Context::$system_conf->default_user);
+ FreshRSS_Context::systemConf()->default_user = param('default_user', '');
+ Minz_Session::_param('default_user', FreshRSS_Context::systemConf()->default_user);
} else {
return false;
}
- if (FreshRSS_Context::$system_conf->auth_type === 'http_auth' &&
+ if (FreshRSS_Context::systemConf()->auth_type === 'http_auth' &&
connectionRemoteAddress() !== '' &&
empty($_SERVER['REMOTE_USER']) && empty($_SERVER['REDIRECT_REMOTE_USER']) && // No safe authentication HTTP headers
(!empty($_SERVER['HTTP_REMOTE_USER']) || !empty($_SERVER['HTTP_X_WEBAUTH_USER'])) // but has unsafe authentication HTTP headers
) {
// Trust by default the remote IP address (e.g. last proxy) used during install to provide remote user name via unsafe HTTP header
- FreshRSS_Context::$system_conf->trusted_sources[] = connectionRemoteAddress();
- FreshRSS_Context::$system_conf->trusted_sources = array_unique(FreshRSS_Context::$system_conf->trusted_sources);
+ FreshRSS_Context::systemConf()->trusted_sources[] = connectionRemoteAddress();
+ FreshRSS_Context::systemConf()->trusted_sources = array_unique(FreshRSS_Context::systemConf()->trusted_sources);
}
// Create default user files but first, we delete previous data to
@@ -244,7 +245,7 @@ function saveStep3(): bool {
return false;
}
- FreshRSS_Context::$system_conf->save();
+ FreshRSS_Context::systemConf()->save();
header('Location: index.php?step=4');
}
diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml
index b59293f21..729b61f5c 100644
--- a/app/layout/aside_configure.phtml
+++ b/app/layout/aside_configure.phtml
@@ -48,7 +48,7 @@
<a href="<?= _url('index', 'logs') ?>"><?= _t('gen.menu.logs') ?></a>
</li>
<?php } ?>
- <?= Minz_ExtensionManager::callHook('menu_configuration_entry') ?>
+ <?= Minz_ExtensionManager::callHookString('menu_configuration_entry') ?>
</ul>
</li>
@@ -68,7 +68,7 @@
<li class="item<?= Minz_Request::controllerName() === 'update' && Minz_Request::actionName() === 'checkInstall' ? ' active' : '' ?>">
<a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a>
</li>
- <?php if (!FreshRSS_Context::$system_conf->disable_update) { ?>
+ <?php if (!FreshRSS_Context::systemConf()->disable_update) { ?>
<li class="item<?= Minz_Request::controllerName() === 'update' && Minz_Request::actionName() === 'index' ? ' active' : '' ?>">
<a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a>
</li>
@@ -76,7 +76,7 @@
<li class="item<?= Minz_Request::actionName() === 'logs' ? ' active' : '' ?>">
<a href="<?= _url('index', 'logs') ?>"><?= _t('gen.menu.logs') ?></a>
</li>
- <?= Minz_ExtensionManager::callHook('menu_admin_entry') ?>
+ <?= Minz_ExtensionManager::callHookString('menu_admin_entry') ?>
</ul>
</li>
<?php } ?>
diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml
index 1d491ad79..29b110647 100644
--- a/app/layout/aside_feed.phtml
+++ b/app/layout/aside_feed.phtml
@@ -3,7 +3,7 @@
/** @var FreshRSS_View $this */
$actual_view = Minz_Request::actionName();
$class = '';
- if (FreshRSS_Context::$user_conf->hide_read_feeds &&
+ if (FreshRSS_Context::userConf()->hide_read_feeds &&
FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) &&
!FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) {
$class = ' state_unread';
@@ -54,7 +54,7 @@
<?php
$t_active = FreshRSS_Context::isCurrentGet('T');
- $t_show = ($t_active && in_array(FreshRSS_Context::$user_conf->display_categories, ['active', 'remember'], true)) || FreshRSS_Context::$user_conf->display_categories === 'all';
+ $t_show = ($t_active && in_array(FreshRSS_Context::userConf()->display_categories, ['active', 'remember'], true)) || FreshRSS_Context::userConf()->display_categories === 'all';
?>
<li id="tags" class="tree-folder category tags<?= $t_active ? ' active' : '' ?>" data-unread="<?= format_number($this->nbUnreadTags) ?>">
<div class="tree-folder-title">
@@ -85,11 +85,11 @@
foreach ($this->categories as $cat):
$feeds = $cat->feeds();
- $position = $cat->attributes('position');
+ $position = $cat->attributeInt('position');
if (!empty($feeds)) {
$c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id());
- $c_show = ($c_active && in_array(FreshRSS_Context::$user_conf->display_categories, ['active', 'remember'], true))
- || FreshRSS_Context::$user_conf->display_categories === 'all';
+ $c_show = ($c_active && in_array(FreshRSS_Context::userConf()->display_categories, ['active', 'remember'], true))
+ || FreshRSS_Context::userConf()->display_categories === 'all';
?>
<li id="c_<?= $cat->id() ?>" class="tree-folder category<?= $c_active ? ' active' : '' ?>"<?=
null === $position ? '' : " data-position='$position'" ?> data-unread="<?= $cat->nbNotRead() ?>">
@@ -124,11 +124,11 @@
?>
<li id="f_<?= $feed->id() ?>" class="item feed<?= $f_active_class, $mute_class, $error_class, $empty_class ?>" title="<?= $error_title, $empty_title ?>"
data-unread="<?= $feed->nbNotRead() ?>" data-priority="<?= $feed->priority() ?>"><?php
- if ($f_active || $nbFeedsTotal < FreshRSS_Context::$user_conf->simplify_over_n_feeds):
+ if ($f_active || $nbFeedsTotal < FreshRSS_Context::userConf()->simplify_over_n_feeds):
?><div class="dropdown no-mobile">
<div class="dropdown-target"></div><a class="dropdown-toggle" data-fweb="<?= $feed->website() ?>"><?= _i('configure') ?></a><?php /* feed_config_template */ ?>
</div><?php
- if (FreshRSS_Context::$user_conf->show_favicons) { ?><img class="favicon test" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php }
+ if (FreshRSS_Context::userConf()->show_favicons) { ?><img class="favicon test" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php }
endif;
?><a class="item-title" data-unread="<?= format_number($feed->nbNotRead()) ?>" href="<?=
_url('index', $actual_view, 'get', 'f_' . $feed->id()) . $state_filter_manual ?>"><?= $feed->name() ?></a></li>
@@ -179,7 +179,7 @@
<li class="item"><a class="configure open-slider" href="<?= $url ?>"><?= _t('gen.action.manage') ?></a></li>
<li class="item"><a href="<?= _url('feed', 'actualize', 'id', '------') ?>"><?= _t('gen.action.actualize') ?></a></li>
<li class="item">
- <?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
+ <?php $confirm = FreshRSS_Context::userConf()->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
<button class="read_all as-link <?= $confirm ?>"
form="mark-read-aside"
formaction="<?= _url('entry', 'read', 'get', 'f_------') ?>"
diff --git a/app/layout/header.phtml b/app/layout/header.phtml
index e5722abb6..18e67fd2d 100644
--- a/app/layout/header.phtml
+++ b/app/layout/header.phtml
@@ -4,18 +4,18 @@
<header class="header">
<div class="item title">
<a href="<?= _url('index', 'index') ?>">
- <?php if (FreshRSS_Context::$system_conf->logo_html == '') { ?>
+ <?php if (FreshRSS_Context::systemConf()->logo_html == '') { ?>
<img class="logo" src="<?= _i('FreshRSS-logo', FreshRSS_Themes::ICON_URL) ?>" alt="FreshRSS" loading="lazy" />
<?php
} else {
- echo FreshRSS_Context::$system_conf->logo_html;
+ echo FreshRSS_Context::systemConf()->logo_html;
}
?>
</a>
</div>
<div class="item search">
- <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) { ?>
+ <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::systemConf()->allow_anonymous) { ?>
<form action="<?= _url('index', 'index') ?>" method="get">
<div class="stick">
<input type="search" name="search" id="search"
@@ -81,7 +81,7 @@
<li class="item"><a href="<?= _url('configure', 'shortcut') ?>"><?= _t('gen.menu.shortcuts') ?></a></li>
<li class="item"><a href="<?= _url('configure', 'queries') ?>"><?= _t('gen.menu.queries') ?></a></li>
<li class="item"><a href="<?= _url('extension', 'index') ?>"><?= _t('gen.menu.extensions') ?></a></li>
- <?= Minz_ExtensionManager::callHook('menu_configuration_entry') ?>
+ <?= Minz_ExtensionManager::callHookString('menu_configuration_entry') ?>
</ul>
</li>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
@@ -94,10 +94,10 @@
<li class="item"><a href="<?= _url('user', 'manage') ?>"><?= _t('gen.menu.user_management') ?></a></li>
<li class="item"><a href="<?= _url('auth', 'index') ?>"><?= _t('gen.menu.authentication') ?></a></li>
<li class="item"><a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a></li>
- <?php if (!FreshRSS_Context::$system_conf->disable_update) { ?>
+ <?php if (!FreshRSS_Context::systemConf()->disable_update) { ?>
<li class="item"><a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a></li>
<?php } ?>
- <?= Minz_ExtensionManager::callHook('menu_admin_entry') ?>
+ <?= Minz_ExtensionManager::callHookString('menu_admin_entry') ?>
</ul>
</li>
<?php } ?>
@@ -111,7 +111,7 @@
<a href="<?= _url('index', 'tos') ?>"><?= _t('index.tos.title')?></a>
</li>
<?php } ?>
- <?= Minz_ExtensionManager::callHook('menu_other_entry') ?>
+ <?= Minz_ExtensionManager::callHookString('menu_other_entry') ?>
</ul>
</li>
</ul>
diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml
index 49cf85a02..adbd52327 100644
--- a/app/layout/layout.phtml
+++ b/app/layout/layout.phtml
@@ -4,13 +4,13 @@
FreshRSS::preLayout();
?>
<!DOCTYPE html>
-<html lang="<?= FreshRSS_Context::$user_conf->language ?>" xml:lang="<?= FreshRSS_Context::$user_conf->language ?>"<?php
+<html lang="<?= FreshRSS_Context::userConf()->language ?>" xml:lang="<?= FreshRSS_Context::userConf()->language ?>"<?php
$class = '';
if (_t('gen.dir') === 'rtl') {
echo ' dir="rtl"';
$class = 'rtl ';
}
-?> class="<?= $class ?><?= (FreshRSS_Context::$user_conf->darkMode === 'no') ? '' : 'darkMode_' . FreshRSS_Context::$user_conf->darkMode ?>">
+?> class="<?= $class ?><?= (FreshRSS_Context::userConf()->darkMode === 'no') ? '' : 'darkMode_' . FreshRSS_Context::userConf()->darkMode ?>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
@@ -26,10 +26,10 @@ if (_t('gen.dir') === 'rtl') {
<link rel="apple-touch-icon" href="<?= Minz_Url::display('/themes/icons/apple-touch-icon.png') ?>" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
- <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::$system_conf->title ?>">
+ <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::systemConf()->title ?>">
<meta name="msapplication-TileColor" content="#FFF" />
<meta name="theme-color" content="#FFF" />
-<?php if (!FreshRSS_Context::$system_conf->allow_referrer) { ?>
+<?php if (!FreshRSS_Context::systemConf()->allow_referrer) { ?>
<meta name="referrer" content="never" />
<?php } ?>
<?= FreshRSS_View::headTitle() ?>
@@ -39,8 +39,8 @@ if (_t('gen.dir') === 'rtl') {
$url_rss = $url_base;
$url_rss['a'] = 'rss';
unset($url_rss['params']['rid']);
- if (FreshRSS_Context::$user_conf->since_hours_posts_per_rss) {
- $url_rss['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss;
+ if (FreshRSS_Context::userConf()->since_hours_posts_per_rss) {
+ $url_rss['params']['hours'] = FreshRSS_Context::userConf()->since_hours_posts_per_rss;
}
?>
<link rel="alternate" type="application/rss+xml" title="<?= $this->rss_title ?>" href="<?= Minz_Url::display($url_rss) ?>" />
@@ -50,7 +50,7 @@ if (_t('gen.dir') === 'rtl') {
unset($opml_rss['params']['rid']);
?>
<link rel="outline" type="text/x-opml" title="OPML" href="<?= Minz_Url::display($opml_rss) ?>" />
-<?php } if (FreshRSS_Context::$system_conf->allow_robots) { ?>
+<?php } if (FreshRSS_Context::systemConf()->allow_robots) { ?>
<meta name="description" content="<?= htmlspecialchars(FreshRSS_Context::$name . ' | ' . FreshRSS_Context::$description, ENT_COMPAT, 'UTF-8') ?>" />
<?php } else { ?>
<meta name="robots" content="noindex,nofollow" />
diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml
index 72838094f..3d0027f17 100644
--- a/app/layout/nav_menu.phtml
+++ b/app/layout/nav_menu.phtml
@@ -84,7 +84,7 @@
<a href="<?= _url('configure', 'queries') ?>"><?= _i('configure') ?></a>
</li>
- <?php foreach (FreshRSS_Context::$user_conf->queries as $raw_query): ?>
+ <?php foreach (FreshRSS_Context::userConf()->queries as $raw_query): ?>
<li class="item query">
<?php if (!empty($raw_query['url'])): ?>
<a href="<?= $raw_query['url'] ?>"><?= $raw_query['name'] ?? $raw_query['url'] ?></a>
@@ -97,7 +97,7 @@
<?php
$classSeparator = '';
- if (count(FreshRSS_Context::$user_conf->queries) > 0) {
+ if (count(FreshRSS_Context::userConf()->queries) > 0) {
$classSeparator = ' separator';
}
@@ -140,7 +140,7 @@
<div class="group stick" id="nav_menu_read_all">
<form id="mark-read-menu" method="post">
- <?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
+ <?php $confirm = FreshRSS_Context::userConf()->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
<button class="read_all btn <?= $confirm ?>"
form="mark-read-menu"
formaction="<?= Minz_Url::display($mark_read_url) ?>"
@@ -196,6 +196,9 @@
<?php
$readingModes = FreshRSS_ReadingMode::getReadingModes();
$readingModes = Minz_ExtensionManager::callHook('nav_reading_modes', $readingModes);
+ if (!is_iterable($readingModes)) {
+ $readingModes = FreshRSS_ReadingMode::getReadingModes();
+ }
/** @var FreshRSS_ReadingMode $mode */
foreach ($readingModes as $mode) {
@@ -210,12 +213,12 @@
<?php
$url_output['a'] = 'rss';
- if (FreshRSS_Context::$user_conf->token) {
+ if (FreshRSS_Context::userConf()->token) {
$url_output['params']['user'] = Minz_User::name();
- $url_output['params']['token'] = FreshRSS_Context::$user_conf->token;
+ $url_output['params']['token'] = FreshRSS_Context::userConf()->token;
}
- if (FreshRSS_Context::$user_conf->since_hours_posts_per_rss) {
- $url_output['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss;
+ if (FreshRSS_Context::userConf()->since_hours_posts_per_rss) {
+ $url_output['params']['hours'] = FreshRSS_Context::userConf()->since_hours_posts_per_rss;
}
?>
<a class="view-rss btn" target="_blank" rel="noreferrer" title="<?= _t('index.menu.rss_view') ?>" href="<?= Minz_Url::display($url_output) ?>">
@@ -223,7 +226,7 @@
</a>
</div>
- <?php $nav_menu_hooks = Minz_ExtensionManager::callHook('nav_menu'); ?>
+ <?php $nav_menu_hooks = Minz_ExtensionManager::callHookString('nav_menu'); ?>
<?php if ($nav_menu_hooks != '') { ?>
<div class="group" id="nav_menu_hooks">
<?= $nav_menu_hooks ?>
@@ -249,7 +252,7 @@
</a>
</div>
- <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous_refresh) { ?>
+ <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::systemConf()->allow_anonymous_refresh) { ?>
<div class="group">
<a id="actualize" class="btn" href="<?= _url('feed', 'actualize') ?>" title="<?= _t('gen.action.actualize') ?>"><?= _i('refresh') ?></a>
</div>
diff --git a/app/layout/simple.phtml b/app/layout/simple.phtml
index b9f74cf59..f2e6bbd25 100644
--- a/app/layout/simple.phtml
+++ b/app/layout/simple.phtml
@@ -4,7 +4,7 @@
FreshRSS::preLayout();
?>
<!DOCTYPE html>
-<html lang="<?= FreshRSS_Context::$user_conf->language ?>" xml:lang="<?= FreshRSS_Context::$user_conf->language ?>">
+<html lang="<?= FreshRSS_Context::userConf()->language ?>" xml:lang="<?= FreshRSS_Context::userConf()->language ?>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
@@ -18,7 +18,7 @@
<link rel="apple-touch-icon" href="<?= Minz_Url::display('/themes/icons/apple-touch-icon.png') ?>" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
- <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::$system_conf->title ?>">
+ <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::systemConf()->title ?>">
<meta name="msapplication-TileColor" content="#FFF" />
<meta name="referrer" content="never" />
<meta name="robots" content="noindex,nofollow" />
@@ -31,11 +31,11 @@
<div class="header">
<div class="item title">
<a href="<?= _url('index', 'index') ?>">
- <?php if (FreshRSS_Context::$system_conf->logo_html == '') { ?>
+ <?php if (FreshRSS_Context::systemConf()->logo_html == '') { ?>
<img class="logo" src="<?= _i('FreshRSS-logo', FreshRSS_Themes::ICON_URL) ?>" alt="FreshRSS" loading="lazy" />
<?php
} else {
- echo FreshRSS_Context::$system_conf->logo_html;
+ echo FreshRSS_Context::systemConf()->logo_html;
}
?>
</a>
diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml
index 78762c19e..f82adaaae 100644
--- a/app/views/auth/index.phtml
+++ b/app/views/auth/index.phtml
@@ -15,15 +15,15 @@
<div class="form-group">
<label class="group-name" for="auth_type"><?= _t('admin.auth.type') ?></label>
<div class="group-controls">
- <select id="auth_type" name="auth_type" required="required" data-leave-validation="<?= FreshRSS_Context::$system_conf->auth_type ?>">
- <?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, ['form', 'http_auth', 'none'], true)) { ?>
+ <select id="auth_type" name="auth_type" required="required" data-leave-validation="<?= FreshRSS_Context::systemConf()->auth_type ?>">
+ <?php if (!in_array(FreshRSS_Context::systemConf()->auth_type, ['form', 'http_auth', 'none'], true)) { ?>
<option selected="selected"></option>
<?php } ?>
- <option value="form"<?= FreshRSS_Context::$system_conf->auth_type === 'form' ? ' selected="selected"' : '',
+ <option value="form"<?= FreshRSS_Context::systemConf()->auth_type === 'form' ? ' selected="selected"' : '',
cryptAvailable() ? '' : ' disabled="disabled"' ?>><?= _t('admin.auth.form') ?></option>
- <option value="http_auth"<?= FreshRSS_Context::$system_conf->auth_type === 'http_auth' ? ' selected="selected"' : '',
+ <option value="http_auth"<?= FreshRSS_Context::systemConf()->auth_type === 'http_auth' ? ' selected="selected"' : '',
httpAuthUser() == '' ? ' disabled="disabled"' : '' ?>><?= _t('admin.auth.http') ?> (REMOTE_USER = '<?= httpAuthUser() ?>')</option>
- <option value="none"<?= FreshRSS_Context::$system_conf->auth_type === 'none' ? ' selected="selected"' : '' ?>><?= _t('admin.auth.none') ?></option>
+ <option value="none"<?= FreshRSS_Context::systemConf()->auth_type === 'none' ? ' selected="selected"' : '' ?>><?= _t('admin.auth.none') ?></option>
</select>
</div>
</div>
@@ -32,9 +32,9 @@
<div class="group-controls">
<label class="checkbox" for="anon_access">
<input type="checkbox" name="anon_access" id="anon_access" value="1"<?=
- FreshRSS_Context::$system_conf->allow_anonymous ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->allow_anonymous ?>"/>
- <?= _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user) ?>
+ FreshRSS_Context::systemConf()->allow_anonymous ? ' checked="checked"' : '',
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::systemConf()->allow_anonymous ?>"/>
+ <?= _t('admin.auth.allow_anonymous', FreshRSS_Context::systemConf()->default_user) ?>
</label>
</div>
</div>
@@ -43,8 +43,8 @@
<div class="group-controls">
<label class="checkbox" for="anon_refresh">
<input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?=
- FreshRSS_Context::$system_conf->allow_anonymous_refresh ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->allow_anonymous_refresh ?>"/>
+ FreshRSS_Context::systemConf()->allow_anonymous_refresh ? ' checked="checked"' : '',
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::systemConf()->allow_anonymous_refresh ?>"/>
<?= _t('admin.auth.allow_anonymous_refresh') ?>
</label>
</div>
@@ -54,8 +54,8 @@
<div class="group-controls">
<label class="checkbox" for="unsafe_autologin">
<input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?=
- FreshRSS_Context::$system_conf->unsafe_autologin_enabled ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->unsafe_autologin_enabled ?>"/>
+ FreshRSS_Context::systemConf()->unsafe_autologin_enabled ? ' checked="checked"' : '',
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::systemConf()->unsafe_autologin_enabled ?>"/>
<?= _t('admin.auth.unsafe_autologin') ?>
<kbd><?= Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true) ?></kbd>
</label>
@@ -66,8 +66,8 @@
<div class="group-controls">
<label class="checkbox" for="api_enabled">
<input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?=
- FreshRSS_Context::$system_conf->api_enabled ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->api_enabled ?>"/>
+ FreshRSS_Context::systemConf()->api_enabled ? ' checked="checked"' : '',
+ FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"' ?> data-leave-validation="<?= FreshRSS_Context::systemConf()->api_enabled ?>"/>
<?= _t('admin.auth.api_enabled') ?>
</label>
</div>
diff --git a/app/views/category/update.phtml b/app/views/category/update.phtml
index daf4523bb..2ef42d207 100644
--- a/app/views/category/update.phtml
+++ b/app/views/category/update.phtml
@@ -5,6 +5,6 @@ declare(strict_types=1);
if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('aside_subscription');
}
-if ($this->category) {
+if ($this->category !== null) {
$this->renderHelper('category/update');
}
diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml
index 6004cec1b..86b8246e3 100644
--- a/app/views/configure/archiving.phtml
+++ b/app/views/configure/archiving.phtml
@@ -17,21 +17,21 @@
<div class="form-group">
<label class="group-name" for="ttl_default"><?= _t('conf.archiving.ttl') ?></label>
<div class="group-controls">
- <select class="number" name="ttl_default" id="ttl_default" required="required" data-leave-validation="<?= FreshRSS_Context::$user_conf->ttl_default ?>"><?php
+ <select class="number" name="ttl_default" id="ttl_default" required="required" data-leave-validation="<?= FreshRSS_Context::userConf()->ttl_default ?>"><?php
$found = false;
foreach (array(1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min',
3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h',
36000 => '10h', 43200 => '12h', 64800 => '18h',
86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d',
604800 => '1wk') as $v => $t) {
- echo '<option value="' . $v . (FreshRSS_Context::$user_conf->ttl_default == $v ? '" selected="selected' : '') . '">' . $t . '</option>';
- if (FreshRSS_Context::$user_conf->ttl_default == $v) {
+ echo '<option value="' . $v . (FreshRSS_Context::userConf()->ttl_default == $v ? '" selected="selected' : '') . '">' . $t . '</option>';
+ if (FreshRSS_Context::userConf()->ttl_default == $v) {
$found = true;
}
}
if (!$found) {
- echo '<option value="' . intval(FreshRSS_Context::$user_conf->ttl_default) . '" selected="selected">'
- . intval(FreshRSS_Context::$user_conf->ttl_default) . 's</option>';
+ echo '<option value="' . intval(FreshRSS_Context::userConf()->ttl_default) . '" selected="selected">'
+ . intval(FreshRSS_Context::userConf()->ttl_default) . 's</option>';
}
?></select> (<?= _t('gen.short.by_default') ?>)
</div>
@@ -46,10 +46,10 @@
<div class="group-controls">
<label class="checkbox" for="enable_keep_max">
<input type="checkbox" name="enable_keep_max" id="enable_keep_max" value="1"<?=
- empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? '' : ' checked="checked"' ?>
- data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? 0 : 1 ?>"/>
+ empty(FreshRSS_Context::userConf()->archiving['keep_max']) ? '' : ' checked="checked"' ?>
+ data-leave-validation="<?= empty(FreshRSS_Context::userConf()->archiving['keep_max']) ? 0 : 1 ?>"/>
<?= _t('conf.archiving.keep_max') ?>
- <?php $keepMax = empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? 200 : FreshRSS_Context::$user_conf->archiving['keep_max']; ?>
+ <?php $keepMax = empty(FreshRSS_Context::userConf()->archiving['keep_max']) ? 200 : FreshRSS_Context::userConf()->archiving['keep_max']; ?>
<input type="number" id="keep_max" name="keep_max" min="0" value="<?= $keepMax ?>" data-leave-validation="<?= $keepMax ?>"/>
</label>
</div>
@@ -59,18 +59,18 @@
<div class="group-controls">
<label class="checkbox" for="enable_keep_period">
<input type="checkbox" name="enable_keep_period" id="enable_keep_period" value="1"<?=
- FreshRSS_Context::$user_conf->volatile['enable_keep_period'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['enable_keep_period'] ? 1 : 0 ?>"/>
+ FreshRSS_Context::userConf()->volatile['enable_keep_period'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->volatile['enable_keep_period'] ? 1 : 0 ?>"/>
<?= _t('conf.archiving.keep_period') ?>
- <input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= FreshRSS_Context::$user_conf->volatile['keep_period_count'] ?>"
- data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['keep_period_count'] ?>"/>
- <select class="number" name="keep_period_unit" id="keep_period_unit" data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ?>">
+ <input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= FreshRSS_Context::userConf()->volatile['keep_period_count'] ?>"
+ data-leave-validation="<?= FreshRSS_Context::userConf()->volatile['keep_period_count'] ?>"/>
+ <select class="number" name="keep_period_unit" id="keep_period_unit" data-leave-validation="<?= FreshRSS_Context::userConf()->volatile['keep_period_unit'] ?>">
<option></option>
- <option value="P1Y" <?= 'P1Y' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
- <option value="P1M" <?= 'P1M' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
- <option value="P1W" <?= 'P1W' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
- <option value="P1D" <?= 'P1D' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
- <option value="PT1H" <?= 'PT1H' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
+ <option value="P1Y" <?= 'P1Y' === FreshRSS_Context::userConf()->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
+ <option value="P1M" <?= 'P1M' === FreshRSS_Context::userConf()->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
+ <option value="P1W" <?= 'P1W' === FreshRSS_Context::userConf()->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
+ <option value="P1D" <?= 'P1D' === FreshRSS_Context::userConf()->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
+ <option value="PT1H" <?= 'PT1H' === FreshRSS_Context::userConf()->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
</select>
</label>
</div>
@@ -81,8 +81,8 @@
<div class="group-controls">
<label class="checkbox" for="keep_favourites">
<input type="checkbox" name="keep_favourites" id="keep_favourites" value="1"<?=
- FreshRSS_Context::$user_conf->archiving['keep_favourites'] !== false ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_favourites'] !== false ? 1 : 0 ?>"/>
+ FreshRSS_Context::userConf()->archiving['keep_favourites'] !== false ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->archiving['keep_favourites'] !== false ? 1 : 0 ?>"/>
<?= _t('conf.archiving.keep_favourites') ?>
</label>
</div>
@@ -92,8 +92,8 @@
<div class="group-controls">
<label class="checkbox" for="keep_labels">
<input type="checkbox" name="keep_labels" id="keep_labels" value="1"<?=
- FreshRSS_Context::$user_conf->archiving['keep_labels'] !== false ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_labels'] !== false ? 1 : 0 ?>"/>
+ FreshRSS_Context::userConf()->archiving['keep_labels'] !== false ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->archiving['keep_labels'] !== false ? 1 : 0 ?>"/>
<?= _t('conf.archiving.keep_labels') ?>
</label>
</div>
@@ -103,8 +103,8 @@
<div class="group-controls">
<label class="checkbox" for="keep_unreads">
<input type="checkbox" name="keep_unreads" id="keep_unreads" value="1"<?=
- FreshRSS_Context::$user_conf->archiving['keep_unreads'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_unreads'] ? 1 : 0 ?>"/>
+ FreshRSS_Context::userConf()->archiving['keep_unreads'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->archiving['keep_unreads'] ? 1 : 0 ?>"/>
<?= _t('conf.archiving.keep_unreads') ?>
</label>
</div>
@@ -114,8 +114,8 @@
<div class="group-controls">
<label for="keep_min_default"><?= _t('conf.archiving.keep_min_by_feed') ?>
<input type="number" id="keep_min_default" name="keep_min_default" min="0" value="<?=
- FreshRSS_Context::$user_conf->archiving['keep_min'] ?>"
- data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_min'] ?>">
+ FreshRSS_Context::userConf()->archiving['keep_min'] ?>"
+ data-leave-validation="<?= FreshRSS_Context::userConf()->archiving['keep_min'] ?>">
</label>
</div>
</div>
diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml
index b48dcbf71..d373c0bb5 100644
--- a/app/views/configure/display.phtml
+++ b/app/views/configure/display.phtml
@@ -16,10 +16,10 @@
<div class="form-group">
<label class="group-name" for="language"><?= _t('conf.display.language') ?></label>
<div class="group-controls">
- <select name="language" id="language" data-leave-validation="<?= FreshRSS_Context::$user_conf->language ?>">
+ <select name="language" id="language" data-leave-validation="<?= FreshRSS_Context::userConf()->language ?>">
<?php $languages = Minz_Translate::availableLanguages(); ?>
<?php foreach ($languages as $lang) { ?>
- <option value="<?= $lang ?>"<?= FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : '' ?>><?= _t('gen.lang.' . $lang) ?></option>
+ <option value="<?= $lang ?>"<?= FreshRSS_Context::userConf()->language === $lang ? ' selected="selected"' : '' ?>><?= _t('gen.lang.' . $lang) ?></option>
<?php } ?>
</select>
</div>
@@ -28,15 +28,15 @@
<div class="form-group">
<label class="group-name" for="timezone"><?= _t('conf.display.timezone') ?></label>
<div class="group-controls">
- <select name="timezone" id="timezone" data-leave-validation="<?= FreshRSS_Context::$user_conf->timezone ?>">
+ <select name="timezone" id="timezone" data-leave-validation="<?= FreshRSS_Context::userConf()->timezone ?>">
<?php
$timezones = array_merge([''], DateTimeZone::listIdentifiers());
- if (!in_array(FreshRSS_Context::$user_conf->timezone, $timezones, true)) {
- FreshRSS_Context::$user_conf->timezone = '';
+ if (!in_array(FreshRSS_Context::userConf()->timezone, $timezones, true)) {
+ FreshRSS_Context::userConf()->timezone = '';
}
?>
<?php foreach ($timezones as $timezone): ?>
- <option value="<?= $timezone ?>"<?= FreshRSS_Context::$user_conf->timezone === $timezone ? ' selected="selected"' : '' ?>>
+ <option value="<?= $timezone ?>"<?= FreshRSS_Context::userConf()->timezone === $timezone ? ' selected="selected"' : '' ?>>
<?= $timezone == '' ? _t('gen.short.by_default') . ' (' . FreshRSS_Context::defaultTimeZone() . ')' : $timezone ?>
</option>
<?php endforeach; ?>
@@ -49,16 +49,16 @@
<div class="group-controls">
<ul class="theme-preview-list">
<?php $slides = count($this->themes); $i = 1; $themeAvailable = false; ?>
- <?php /** @var array{'id':string, 'deprecated':bool, 'author':string, 'name':string, 'description':string} $theme */
- foreach($this->themes as $theme) { ?>
- <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {
+ <?php
+ foreach ($this->themes as $theme) { ?>
+ <?php if (FreshRSS_Context::userConf()->theme === $theme['id']) {
$checked = 'checked="checked"';
$themeAvailable = true;
} else {
$checked = '';
} ?>
<input type="radio" name="theme" id="img-<?= $i ?>" <?= $checked ?> value="<?= $theme['id'] ?>"
- data-leave-validation="<?= (FreshRSS_Context::$user_conf->theme === $theme['id']) ? 1 : 0 ?>" />
+ data-leave-validation="<?= (FreshRSS_Context::userConf()->theme === $theme['id']) ? 1 : 0 ?>" />
<li class="preview-container">
<div class="preview">
<img src="<?= Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png') ?>" loading="lazy" />
@@ -98,7 +98,7 @@
<label for="img-<?= $i - 1 ?>" class="prev">‹</label>
</div>
<div class="properties alert-error">
- <div><?= _t('conf.display.theme_not_available', FreshRSS_Context::$user_conf->theme)?></div>
+ <div><?= _t('conf.display.theme_not_available', FreshRSS_Context::userConf()->theme)?></div>
</div>
</li>
<?php }?>
@@ -109,14 +109,14 @@
<div class="form-group">
<label class="group-name" for="darkMode"><?= _t('conf.display.darkMode') ?></label>
<div class="group-controls">
- <select name="darkMode" id="darkMode" data-leave-validation="<?= FreshRSS_Context::$user_conf->darkMode ?>">
- <option value="no"<?= FreshRSS_Context::$user_conf->darkMode === 'no' ? ' selected' : '' ?>><?= _t('conf.display.darkMode.no') ?></option>
- <option value="auto"<?= FreshRSS_Context::$user_conf->darkMode === 'auto' ? ' selected' : '' ?>><?= _t('conf.display.darkMode.auto') ?></option>
+ <select name="darkMode" id="darkMode" data-leave-validation="<?= FreshRSS_Context::userConf()->darkMode ?>">
+ <option value="no"<?= FreshRSS_Context::userConf()->darkMode === 'no' ? ' selected' : '' ?>><?= _t('conf.display.darkMode.no') ?></option>
+ <option value="auto"<?= FreshRSS_Context::userConf()->darkMode === 'auto' ? ' selected' : '' ?>><?= _t('conf.display.darkMode.auto') ?></option>
</select>
</div>
</div>
- <?php $width = FreshRSS_Context::$user_conf->content_width; ?>
+ <?php $width = FreshRSS_Context::userConf()->content_width; ?>
<div class="form-group">
<label class="group-name" for="content_width"><?= _t('conf.display.width.content') ?></label>
<div class="group-controls">
@@ -137,7 +137,7 @@
</div>
</div>
- <?php $topline_website = FreshRSS_Context::$user_conf->topline_website; ?>
+ <?php $topline_website = FreshRSS_Context::userConf()->topline_website; ?>
<div class="form-group">
<label class="group-name" for="topline_website"><?= _t('conf.display.website.label') ?></label>
<div class="group-controls">
@@ -158,7 +158,7 @@
</div>
</div>
- <?php $topline_thumbnail = FreshRSS_Context::$user_conf->topline_thumbnail; ?>
+ <?php $topline_thumbnail = FreshRSS_Context::userConf()->topline_thumbnail; ?>
<div class="form-group">
<label class="group-name" for="topline_thumbnail"><?= _t('conf.display.thumbnail.label') ?></label>
<div class="group-controls">
@@ -201,50 +201,50 @@
<tr>
<th><?= _t('conf.display.icon.top_line') ?></th>
<td><input type="checkbox" name="topline_read" value="1"<?=
- FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_read ?>" /></td>
+ FreshRSS_Context::userConf()->topline_read ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_read ?>" /></td>
<td><input type="checkbox" name="topline_favorite" value="1"<?=
- FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_favorite ?>" /></td>
+ FreshRSS_Context::userConf()->topline_favorite ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_favorite ?>" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" name="topline_summary" value="1"<?=
- FreshRSS_Context::$user_conf->topline_summary ? 'checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_summary ?>" /></td>
+ FreshRSS_Context::userConf()->topline_summary ? 'checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_summary ?>" /></td>
<td><input type="checkbox" name="topline_display_authors" value="1"<?=
- FreshRSS_Context::$user_conf->topline_display_authors ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_display_authors ?>" /></td>
+ FreshRSS_Context::userConf()->topline_display_authors ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_display_authors ?>" /></td>
<td><input type="checkbox" name="topline_date" value="1"<?=
- FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_date ?>" /></td>
- <td><input type="checkbox" name="topline_link" value="1"<?= FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_link ?>" /></td>
+ FreshRSS_Context::userConf()->topline_date ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_date ?>" /></td>
+ <td><input type="checkbox" name="topline_link" value="1"<?= FreshRSS_Context::userConf()->topline_link ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->topline_link ?>" /></td>
</tr><tr>
<th><?= _t('conf.display.icon.bottom_line') ?></th>
<td><input type="checkbox" name="bottomline_read" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_read ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_read ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_read ?>" /></td>
<td><input type="checkbox" name="bottomline_favorite" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_favorite ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_favorite ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_favorite ?>" /></td>
<td><input type="checkbox" name="bottomline_myLabels" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_myLabels ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_myLabels ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_myLabels ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_myLabels ?>" /></td>
<td><input type="checkbox" name="bottomline_tags" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_tags ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_tags ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_tags ?>" /></td>
<td><input type="checkbox" name="bottomline_sharing" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_sharing ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_sharing ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_sharing ?>" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" name="bottomline_date" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_date ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_date ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_date ?>" /></td>
<td><input type="checkbox" name="bottomline_link" value="1"<?=
- FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_link ?>" /></td>
+ FreshRSS_Context::userConf()->bottomline_link ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->bottomline_link ?>" /></td>
</tr>
</tbody>
</table>
@@ -255,8 +255,8 @@
<label class="group-name" for="html5_notif_timeout"><?= _t('conf.display.notif_html5.timeout') ?></label>
<div class="group-controls">
<input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?=
- FreshRSS_Context::$user_conf->html5_notif_timeout ?>"
- data-leave-validation="<?= FreshRSS_Context::$user_conf->html5_notif_timeout ?>" /> <?= _t('conf.display.notif_html5.seconds') ?>
+ FreshRSS_Context::userConf()->html5_notif_timeout ?>"
+ data-leave-validation="<?= FreshRSS_Context::userConf()->html5_notif_timeout ?>" /> <?= _t('conf.display.notif_html5.seconds') ?>
</div>
</div>
@@ -264,8 +264,8 @@
<div class="group-controls">
<label class="checkbox" for="show_nav_buttons">
<input type="checkbox" name="show_nav_buttons" id="show_nav_buttons" value="1"<?=
- FreshRSS_Context::$user_conf->show_nav_buttons ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->show_nav_buttons ?>" />
+ FreshRSS_Context::userConf()->show_nav_buttons ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->show_nav_buttons ?>" />
<?= _t('conf.display.show_nav_buttons') ?>
</label>
</div>
diff --git a/app/views/configure/integration.phtml b/app/views/configure/integration.phtml
index fc3cc2a32..973ee128f 100644
--- a/app/views/configure/integration.phtml
+++ b/app/views/configure/integration.phtml
@@ -57,8 +57,11 @@
</template>
<?php
- foreach (FreshRSS_Context::$user_conf->sharing as $key => $share_options) {
+ foreach (FreshRSS_Context::userConf()->sharing as $key => $share_options) {
$share = FreshRSS_Share::get($share_options['type']);
+ if ($share === null) {
+ continue;
+ }
$share->update($share_options);
?>
<formgroup class="group-share dragbox" id="group-share-<?= $key ?>">
diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml
index 94cf51977..17fdbe7c3 100644
--- a/app/views/configure/reading.phtml
+++ b/app/views/configure/reading.phtml
@@ -17,10 +17,10 @@
<div class="form-group">
<label class="group-name" for="view_mode"><?= _t('conf.reading.view.default') ?></label>
<div class="group-controls">
- <select name="view_mode" id="view_mode" data-leave-validation="<?= FreshRSS_Context::$user_conf->view_mode ?>">
- <option value="normal"<?= FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.normal') ?></option>
- <option value="reader"<?= FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.reader') ?></option>
- <option value="global"<?= FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.global') ?></option>
+ <select name="view_mode" id="view_mode" data-leave-validation="<?= FreshRSS_Context::userConf()->view_mode ?>">
+ <option value="normal"<?= FreshRSS_Context::userConf()->view_mode === 'normal' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.normal') ?></option>
+ <option value="reader"<?= FreshRSS_Context::userConf()->view_mode === 'reader' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.reader') ?></option>
+ <option value="global"<?= FreshRSS_Context::userConf()->view_mode === 'global' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.global') ?></option>
</select>
</div>
</div>
@@ -28,10 +28,10 @@
<div class="form-group">
<label class="group-name" for="default_view"><?= _t('conf.reading.show') ?></label>
<div class="group-controls">
- <select name="default_view" id="default_view" data-leave-validation="<?= FreshRSS_Context::$user_conf->default_view ?>">
- <option value="adaptive"<?= FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.adaptive') ?></option>
- <option value="all"<?= FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.all_articles') ?></option>
- <option value="unread"<?= FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.unread') ?></option>
+ <select name="default_view" id="default_view" data-leave-validation="<?= FreshRSS_Context::userConf()->default_view ?>">
+ <option value="adaptive"<?= FreshRSS_Context::userConf()->default_view === 'adaptive' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.adaptive') ?></option>
+ <option value="all"<?= FreshRSS_Context::userConf()->default_view === 'all' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.all_articles') ?></option>
+ <option value="unread"<?= FreshRSS_Context::userConf()->default_view === 'unread' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.unread') ?></option>
</select>
</div>
</div>
@@ -40,8 +40,8 @@
<label class="group-name" for="posts_per_page"><?= _t('conf.reading.articles_per_page') ?></label>
<div class="group-controls">
<input type="number" id="posts_per_page" name="posts_per_page" value="<?=
- FreshRSS_Context::$user_conf->posts_per_page ?>" min="5" max="500"
- data-leave-validation="<?= FreshRSS_Context::$user_conf->posts_per_page ?>"/>
+ FreshRSS_Context::userConf()->posts_per_page ?>" min="5" max="500"
+ data-leave-validation="<?= FreshRSS_Context::userConf()->posts_per_page ?>"/>
<p class="help"><?= _i('help') ?> <?= _t('conf.reading.number_divided_when_reader') ?></p>
</div>
</div>
@@ -50,8 +50,8 @@
<div class="group-controls">
<label class="checkbox" for="auto_load_more">
<input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?=
- FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->auto_load_more ?>"/>
+ FreshRSS_Context::userConf()->auto_load_more ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->auto_load_more ?>"/>
<?= _t('conf.reading.auto_load_more') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -61,9 +61,9 @@
<div class="form-group">
<label class="group-name" for="sort_order"><?= _t('conf.reading.sort') ?></label>
<div class="group-controls">
- <select name="sort_order" id="sort_order" data-leave-validation="<?= FreshRSS_Context::$user_conf->sort_order ?>">
- <option value="DESC"<?= FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.newer_first') ?></option>
- <option value="ASC"<?= FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.older_first') ?></option>
+ <select name="sort_order" id="sort_order" data-leave-validation="<?= FreshRSS_Context::userConf()->sort_order ?>">
+ <option value="DESC"<?= FreshRSS_Context::userConf()->sort_order === 'DESC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.newer_first') ?></option>
+ <option value="ASC"<?= FreshRSS_Context::userConf()->sort_order === 'ASC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.older_first') ?></option>
</select>
</div>
</div>
@@ -75,14 +75,14 @@
<div class="form-group">
<label class="group-name" for="display_categories"><?= _t('conf.reading.display_categories_unfolded') ?></label>
<div class="group-controls">
- <select name="display_categories" id="display_categories" data-leave-validation="<?= FreshRSS_Context::$user_conf->display_categories ?>">
- <option value="active"<?= FreshRSS_Context::$user_conf->display_categories === 'active' ? ' selected="selected"' : '' ?>><?=
+ <select name="display_categories" id="display_categories" data-leave-validation="<?= FreshRSS_Context::userConf()->display_categories ?>">
+ <option value="active"<?= FreshRSS_Context::userConf()->display_categories === 'active' ? ' selected="selected"' : '' ?>><?=
_t('conf.reading.show.active_category') ?></option>
- <option value="remember"<?= FreshRSS_Context::$user_conf->display_categories === 'remember' ? ' selected="selected"' : '' ?>><?=
+ <option value="remember"<?= FreshRSS_Context::userConf()->display_categories === 'remember' ? ' selected="selected"' : '' ?>><?=
_t('conf.reading.show.remember_categories') ?></option>
- <option value="all"<?= FreshRSS_Context::$user_conf->display_categories === 'all' ? ' selected="selected"' : '' ?>><?=
+ <option value="all"<?= FreshRSS_Context::userConf()->display_categories === 'all' ? ' selected="selected"' : '' ?>><?=
_t('conf.reading.show.all_categories') ?></option>
- <option value="none"<?= FreshRSS_Context::$user_conf->display_categories === 'none' ? ' selected="selected"' : '' ?>><?=
+ <option value="none"<?= FreshRSS_Context::userConf()->display_categories === 'none' ? ' selected="selected"' : '' ?>><?=
_t('conf.reading.show.no_category') ?></option>
</select>
</div>
@@ -92,8 +92,8 @@
<div class="group-controls">
<label class="checkbox" for="show_fav_unread">
<input type="checkbox" name="show_fav_unread" id="show_fav_unread" value="1"<?=
- FreshRSS_Context::$user_conf->show_fav_unread ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->show_fav_unread ?>"/>
+ FreshRSS_Context::userConf()->show_fav_unread ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->show_fav_unread ?>"/>
<?= _t('conf.reading.always_show_favorites') ?>
<p class="help"><?= _i('help') ?> <?= _t('conf.reading.show_fav_unread_help') ?></p>
</label>
@@ -104,8 +104,8 @@
<div class="group-controls">
<label class="checkbox" for="hide_read_feeds">
<input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?=
- FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->hide_read_feeds ?>"/>
+ FreshRSS_Context::userConf()->hide_read_feeds ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->hide_read_feeds ?>"/>
<?= _t('conf.reading.hide_read_feeds') ?>
</label>
</div>
@@ -117,32 +117,32 @@
<div class="form-group">
<label class="group-name" for="show_feed_name"><?= _t('conf.reading.article.feed_title') ?></label>
<div class="group-controls">
- <select name="show_feed_name" id="show_feed_name" data-leave-validation="<?= FreshRSS_Context::$user_conf->show_feed_name ?>">
- <option value="0"<?= FreshRSS_Context::$user_conf->show_feed_name === '0' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.none') ?></option>
- <option value="t"<?= FreshRSS_Context::$user_conf->show_feed_name === 't' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.above_title') ?></option>
- <option value="a"<?= FreshRSS_Context::$user_conf->show_feed_name === 'a' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.with_authors') ?></option>
+ <select name="show_feed_name" id="show_feed_name" data-leave-validation="<?= FreshRSS_Context::userConf()->show_feed_name ?>">
+ <option value="0"<?= FreshRSS_Context::userConf()->show_feed_name === '0' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.none') ?></option>
+ <option value="t"<?= FreshRSS_Context::userConf()->show_feed_name === 't' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.above_title') ?></option>
+ <option value="a"<?= FreshRSS_Context::userConf()->show_feed_name === 'a' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.feed_name.with_authors') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="show_author_date"><?= _t('conf.reading.article.authors_date') ?></label>
<div class="group-controls">
- <select name="show_author_date" id="show_author_date" data-leave-validation="<?= FreshRSS_Context::$user_conf->show_author_date ?>">
- <option value="0" <?= FreshRSS_Context::$user_conf->show_author_date === '0' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.none') ?></option>
- <option value="h" <?= FreshRSS_Context::$user_conf->show_author_date === 'h' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.header') ?></option>
- <option value="f" <?= FreshRSS_Context::$user_conf->show_author_date === 'f' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.footer') ?></option>
- <option value="b" <?= FreshRSS_Context::$user_conf->show_author_date === 'b' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.both') ?></option>
+ <select name="show_author_date" id="show_author_date" data-leave-validation="<?= FreshRSS_Context::userConf()->show_author_date ?>">
+ <option value="0" <?= FreshRSS_Context::userConf()->show_author_date === '0' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.none') ?></option>
+ <option value="h" <?= FreshRSS_Context::userConf()->show_author_date === 'h' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.header') ?></option>
+ <option value="f" <?= FreshRSS_Context::userConf()->show_author_date === 'f' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.footer') ?></option>
+ <option value="b" <?= FreshRSS_Context::userConf()->show_author_date === 'b' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.article.authors_date.both') ?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="group-name" for="show_tags"><?= _t('conf.reading.article.tags') ?></label>
<div class="group-controls">
- <select class="select-input-changer" name="show_tags" id="show_tags" data-name="show_tags_max" data-leave-validation="<?= FreshRSS_Context::$user_conf->show_tags ?>">
- <option value="0" <?= FreshRSS_Context::$user_conf->show_tags === '0' ? ' selected="selected"' : '' ?> data-input-visible="false"><?= _t('conf.reading.article.tags.none') ?></option>
- <option value="h" <?= FreshRSS_Context::$user_conf->show_tags === 'h' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.header') ?></option>
- <option value="f" <?= FreshRSS_Context::$user_conf->show_tags === 'f' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.footer') ?></option>
- <option value="b" <?= FreshRSS_Context::$user_conf->show_tags === 'b' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.both') ?></option>
+ <select class="select-input-changer" name="show_tags" id="show_tags" data-name="show_tags_max" data-leave-validation="<?= FreshRSS_Context::userConf()->show_tags ?>">
+ <option value="0" <?= FreshRSS_Context::userConf()->show_tags === '0' ? ' selected="selected"' : '' ?> data-input-visible="false"><?= _t('conf.reading.article.tags.none') ?></option>
+ <option value="h" <?= FreshRSS_Context::userConf()->show_tags === 'h' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.header') ?></option>
+ <option value="f" <?= FreshRSS_Context::userConf()->show_tags === 'f' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.footer') ?></option>
+ <option value="b" <?= FreshRSS_Context::userConf()->show_tags === 'b' ? ' selected="selected"' : '' ?> data-input-visible="true"><?= _t('conf.reading.article.tags.both') ?></option>
</select>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</div>
@@ -150,7 +150,7 @@
<div class="form-group" id="show_tags_max-block">
<label class="group-name" for="show_tags_max"><?= _t('conf.reading.article.tags_max') ?></label>
<div class="group-controls">
- <input type="number" id="show_tags_max" name="show_tags_max" value="<?= FreshRSS_Context::$user_conf->show_tags_max ?>" min="0" data-leave-validation="<?= FreshRSS_Context::$user_conf->show_tags_max ?>" data-number="2" />
+ <input type="number" id="show_tags_max" name="show_tags_max" value="<?= FreshRSS_Context::userConf()->show_tags_max ?>" min="0" data-leave-validation="<?= FreshRSS_Context::userConf()->show_tags_max ?>" data-number="2" />
<p class="help"><?= _i('help') ?> <?= _t('conf.reading.article.tags_max.help') ?></p>
</div>
</div>
@@ -162,8 +162,8 @@
<div class="group-controls">
<label class="checkbox" for="display_posts">
<input type="checkbox" name="display_posts" id="display_posts" value="1"<?=
- FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->display_posts ?>"/>
+ FreshRSS_Context::userConf()->display_posts ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->display_posts ?>"/>
<?= _t('conf.reading.display_articles_unfolded') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -174,8 +174,8 @@
<div class="group-controls">
<label class="checkbox" for="sticky_post">
<input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?=
- FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->sticky_post ?>"/>
+ FreshRSS_Context::userConf()->sticky_post ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->sticky_post ?>"/>
<?= _t('conf.reading.sticky_post') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -186,8 +186,8 @@
<div class="group-controls">
<label class="checkbox" for="sides_close_article">
<input type="checkbox" name="sides_close_article" id="sides_close_article" value="1"<?=
- FreshRSS_Context::$user_conf->sides_close_article ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->sides_close_article ?>"/>
+ FreshRSS_Context::userConf()->sides_close_article ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->sides_close_article ?>"/>
<?= _t('conf.reading.sides_close_article') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -201,8 +201,8 @@
<div class="group-controls">
<label class="checkbox" for="auto_remove_article">
<input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?=
- FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->auto_remove_article ?>"/>
+ FreshRSS_Context::userConf()->auto_remove_article ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->auto_remove_article ?>"/>
<?= _t('conf.reading.auto_remove_article') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -213,8 +213,8 @@
<div class="group-controls">
<label class="checkbox" for="reading_confirm">
<input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?=
- FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->reading_confirm ?>"/>
+ FreshRSS_Context::userConf()->reading_confirm ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->reading_confirm ?>"/>
<?= _t('conf.reading.confirm_enabled') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
@@ -226,8 +226,8 @@
<div class="group-controls">
<label class="checkbox" for="onread_jump_next">
<input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?=
- FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->onread_jump_next ?>"/>
+ FreshRSS_Context::userConf()->onread_jump_next ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->onread_jump_next ?>"/>
<?= _t('conf.reading.jump_next') ?>
</label>
</div>
@@ -237,8 +237,8 @@
<div class="group-controls">
<label class="checkbox" for="mark_updated_article_unread">
<input type="checkbox" name="mark_updated_article_unread" id="mark_updated_article_unread" value="1"<?=
- FreshRSS_Context::$user_conf->mark_updated_article_unread ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_updated_article_unread ?>"/>
+ FreshRSS_Context::userConf()->mark_updated_article_unread ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_updated_article_unread ?>"/>
<?= _t('conf.reading.mark_updated_article_unread') ?>
</label>
</div>
@@ -249,8 +249,8 @@
<div class="group-controls">
<label class="checkbox" for="check_open_article">
<input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['article'] ?>"/>
+ FreshRSS_Context::userConf()->mark_when['article'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['article'] ?>"/>
<?= _t('conf.reading.read.article_viewed') ?>
</label>
</div>
@@ -261,8 +261,8 @@
<div class="group-controls">
<label class="checkbox" for="check_open_site">
<input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['site'] ?>"/>
+ FreshRSS_Context::userConf()->mark_when['site'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['site'] ?>"/>
<?= _t('conf.reading.read.article_open_on_website') ?>
</label>
</div>
@@ -273,8 +273,8 @@
<div class="group-controls">
<label class="checkbox" for="check_scroll">
<input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['scroll'] ?>"/>
+ FreshRSS_Context::userConf()->mark_when['scroll'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['scroll'] ?>"/>
<?= _t('conf.reading.read.scroll') ?>
</label>
</div>
@@ -285,8 +285,8 @@
<div class="group-controls">
<label class="checkbox" for="check_focus">
<input type="checkbox" name="mark_focus" id="check_focus" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['focus'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['focus'] ?>" />
+ FreshRSS_Context::userConf()->mark_when['focus'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['focus'] ?>" />
<?= _t('conf.reading.read.focus') ?>
</label>
</div>
@@ -297,10 +297,10 @@
<div class="group-controls">
<label class="checkbox" for="enable_read_when_same_title_in_feed">
<input type="checkbox" name="enable_read_when_same_title_in_feed" id="enable_read_when_same_title_in_feed" value="1"<?=
- empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? '' : ' checked="checked"' ?>
- data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? 0 : 1 ?>"/>
+ empty(FreshRSS_Context::userConf()->mark_when['same_title_in_feed']) ? '' : ' checked="checked"' ?>
+ data-leave-validation="<?= empty(FreshRSS_Context::userConf()->mark_when['same_title_in_feed']) ? 0 : 1 ?>"/>
<?= _t('conf.reading.read.when_same_title') ?>
- <?php $read_when_same_title_in_feed = empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? 25 : FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']; ?>
+ <?php $read_when_same_title_in_feed = empty(FreshRSS_Context::userConf()->mark_when['same_title_in_feed']) ? 25 : FreshRSS_Context::userConf()->mark_when['same_title_in_feed']; ?>
<input type="number" id="read_when_same_title_in_feed" name="read_when_same_title_in_feed" min="0"
value="<?= $read_when_same_title_in_feed ?>" data-leave-validation="<?= $read_when_same_title_in_feed ?>" />
</label>
@@ -312,8 +312,8 @@
<div class="group-controls">
<label class="checkbox" for="mark_upon_reception">
<input type="checkbox" name="mark_upon_reception" id="mark_upon_reception" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['reception'] ?>"/>
+ FreshRSS_Context::userConf()->mark_when['reception'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['reception'] ?>"/>
<?= _t('conf.reading.read.upon_reception') ?>
</label>
</div>
@@ -324,8 +324,8 @@
<div class="group-controls">
<label class="checkbox" for="read_upon_gone">
<input type="checkbox" name="read_upon_gone" id="read_upon_gone" value="1"<?=
- FreshRSS_Context::$user_conf->mark_when['gone'] ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['gone'] ?>"/>
+ FreshRSS_Context::userConf()->mark_when['gone'] ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->mark_when['gone'] ?>"/>
<?= _t('conf.reading.read.upon_gone') ?>
</label>
</div>
@@ -335,10 +335,10 @@
<div class="group-controls">
<label class="checkbox" for="keep_max_n_unread">
<input type="checkbox" name="enable_keep_max_n_unread" id="enable_keep_max_n_unread" value="1"<?=
- empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? '' : ' checked="checked"' ?>
- data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? 0 : 1 ?>"/>
+ empty(FreshRSS_Context::userConf()->mark_when['max_n_unread']) ? '' : ' checked="checked"' ?>
+ data-leave-validation="<?= empty(FreshRSS_Context::userConf()->mark_when['max_n_unread']) ? 0 : 1 ?>"/>
<?= _t('conf.reading.read.keep_max_n_unread') ?>
- <?php $keep_max_n_unread = empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? 1000 : FreshRSS_Context::$user_conf->mark_when['max_n_unread']; ?>
+ <?php $keep_max_n_unread = empty(FreshRSS_Context::userConf()->mark_when['max_n_unread']) ? 1000 : FreshRSS_Context::userConf()->mark_when['max_n_unread']; ?>
<input type="number" id="keep_max_n_unread" name="keep_max_n_unread" min="0" value="<?= $keep_max_n_unread ?>" data-leave-validation="<?= $keep_max_n_unread ?>" />
</label>
</div>
@@ -351,7 +351,7 @@
<label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<textarea name="filteractions_read" id="filteractions_read" class="w100"><?php
- foreach (FreshRSS_Context::$user_conf->filtersAction('read') as $filterRead) {
+ foreach (FreshRSS_Context::userConf()->filtersAction('read') as $filterRead) {
echo $filterRead->getRawInput(), PHP_EOL;
}
?></textarea>
@@ -366,8 +366,8 @@
<div class="group-controls">
<label class="checkbox" for="lazyload">
<input type="checkbox" name="lazyload" id="lazyload" value="1"<?=
- FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$user_conf->lazyload ?>"/>
+ FreshRSS_Context::userConf()->lazyload ? ' checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::userConf()->lazyload ?>"/>
<?= _t('conf.reading.img_with_lazyload') ?>
<noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml
index e578938cd..0d7ee4cb7 100644
--- a/app/views/configure/shortcut.phtml
+++ b/app/views/configure/shortcut.phtml
@@ -16,7 +16,7 @@
<?php } ?>
</datalist>
- <?php $s = FreshRSS_Context::$user_conf->shortcuts; ?>
+ <?php $s = FreshRSS_Context::userConf()->shortcuts; ?>
<?php if ([] !== $nonStandard = getNonStandardShortcuts($s)): ?>
<p class="alert alert-error">
diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml
index d19698932..09d1fe188 100644
--- a/app/views/configure/system.phtml
+++ b/app/views/configure/system.phtml
@@ -16,16 +16,16 @@
<div class="form-group">
<label class="group-name" for="instance-name"><?= _t('admin.system.instance-name') ?></label>
<div class="group-controls">
- <input type="text" id="instance-name" name="instance-name" value="<?= FreshRSS_Context::$system_conf->title ?>"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->title ?>"/>
+ <input type="text" id="instance-name" name="instance-name" value="<?= FreshRSS_Context::systemConf()->title ?>"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->title ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="base-url"><?= _t('admin.system.base-url') ?></label>
<div class="group-controls">
- <input type="text" id="base-url" name="base-url" value="<?= FreshRSS_Context::$system_conf->base_url ?>"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->base_url ?>" disabled="disabled" />
+ <input type="text" id="base-url" name="base-url" value="<?= FreshRSS_Context::systemConf()->base_url ?>"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->base_url ?>" disabled="disabled" />
<p class="help"><?= _i('help') ?> <?= _t('admin.system.base-url.recommendation', dirname(Minz_Request::guessBaseUrl())) ?></p>
<p class="help"><?= _i('help') ?> <?= _t('admin.system.sensitive-parameter') ?></p>
</div>
@@ -35,7 +35,7 @@
<label class="group-name" for="websub"><?= _t('sub.feed.websub') ?></label>
<div class="group-controls">
<input type="checkbox" id="websub" name="websub" disabled="disabled" <?=
- FreshRSS_Context::$system_conf->pubsubhubbub_enabled && Minz_Request::serverIsPublic(FreshRSS_Context::$system_conf->base_url) ? 'checked="checked"' : '' ?> />
+ FreshRSS_Context::systemConf()->pubsubhubbub_enabled && Minz_Request::serverIsPublic(FreshRSS_Context::systemConf()->base_url) ? 'checked="checked"' : '' ?> />
<p class="help"><?= _i('help') ?> <?= _t('admin.system.websub.help') ?></p>
<p class="help"><?= _i('help') ?> <?= _t('admin.system.sensitive-parameter') ?></p>
</div>
@@ -44,32 +44,32 @@
<div class="form-group">
<label class="group-name" for="auto-update-url"><?= _t('admin.system.auto-update-url') ?></label>
<div class="group-controls">
- <input type="text" id="auto-update-url" name="auto-update-url" value="<?= FreshRSS_Context::$system_conf->auto_update_url ?>"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->auto_update_url ?>"/>
+ <input type="text" id="auto-update-url" name="auto-update-url" value="<?= FreshRSS_Context::systemConf()->auto_update_url ?>"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->auto_update_url ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="max-feeds"><?= _t('admin.system.max-feeds') ?></label>
<div class="group-controls">
- <input type="number" id="max-feeds" name="max-feeds" value="<?= FreshRSS_Context::$system_conf->limits['max_feeds'] ?>" min="1"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_feeds'] ?>"/>
+ <input type="number" id="max-feeds" name="max-feeds" value="<?= FreshRSS_Context::systemConf()->limits['max_feeds'] ?>" min="1"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->limits['max_feeds'] ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="max-categories"><?= _t('admin.system.max-categories') ?></label>
<div class="group-controls">
- <input type="number" id="max-categories" name="max-categories" value="<?= FreshRSS_Context::$system_conf->limits['max_categories'] ?>" min="1"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_categories'] ?>"/>
+ <input type="number" id="max-categories" name="max-categories" value="<?= FreshRSS_Context::systemConf()->limits['max_categories'] ?>" min="1"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->limits['max_categories'] ?>"/>
</div>
</div>
<div class="form-group">
<label class="group-name" for="cookie-duration"><?= _t('admin.system.cookie-duration.number') ?></label>
<div class="group-controls">
- <input type="number" id="cookie-duration" name="cookie-duration" value="<?= FreshRSS_Context::$system_conf->limits['cookie_duration'] ?>" min="0"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['cookie_duration'] ?>"/>
+ <input type="number" id="cookie-duration" name="cookie-duration" value="<?= FreshRSS_Context::systemConf()->limits['cookie_duration'] ?>" min="0"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->limits['cookie_duration'] ?>"/>
<p class="help"><?= _i('help') ?> <?= _t('admin.system.cookie-duration.help') ?></p>
</div>
</div>
@@ -80,9 +80,9 @@
<label class="group-name" for="max-registrations-select"><?= _t('admin.system.registration.select.label') ?></label>
<div class="group-controls">
<select class="select-input-changer" name="" data-name="max-registrations">
- <option value="1" <?= FreshRSS_Context::$system_conf->limits['max_registrations'] == 1 ? 'selected = "selected"' : ''; ?> data-input-visible="false"><?= _t('admin.system.registration.select.option.noform') ?></option>
- <option value="0" <?= FreshRSS_Context::$system_conf->limits['max_registrations'] == 0 ? 'selected = "selected"' : ''; ?> data-input-visible="false"><?= _t('admin.system.registration.select.option.nolimit') ?></option>
- <option value="2" <?= FreshRSS_Context::$system_conf->limits['max_registrations'] > 1 ? 'selected = "selected"' : ''; ?> data-input-visible="true"><?= _t('admin.system.registration.select.option.setaccountsnumber') ?></option>
+ <option value="1" <?= FreshRSS_Context::systemConf()->limits['max_registrations'] == 1 ? 'selected = "selected"' : ''; ?> data-input-visible="false"><?= _t('admin.system.registration.select.option.noform') ?></option>
+ <option value="0" <?= FreshRSS_Context::systemConf()->limits['max_registrations'] == 0 ? 'selected = "selected"' : ''; ?> data-input-visible="false"><?= _t('admin.system.registration.select.option.nolimit') ?></option>
+ <option value="2" <?= FreshRSS_Context::systemConf()->limits['max_registrations'] > 1 ? 'selected = "selected"' : ''; ?> data-input-visible="true"><?= _t('admin.system.registration.select.option.setaccountsnumber') ?></option>
</select>
</div>
</div>
@@ -91,8 +91,8 @@
<label class="group-name" for="max-registrations-input"><?= _t('admin.system.registration.number') ?></label>
<div class="group-controls">
<?php $number = count(listUsers()); ?>
- <input type="number" id="max-registrations-input" name="" value="<?= FreshRSS_Context::$system_conf->limits['max_registrations'] > 1 ? FreshRSS_Context::$system_conf->limits['max_registrations'] : $number + 1; ?>" min="2"
- data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_registrations'] > 1 ? FreshRSS_Context::$system_conf->limits['max_registrations'] : $number + 1; ?>" data-number="<?= $number ?>"/>
+ <input type="number" id="max-registrations-input" name="" value="<?= FreshRSS_Context::systemConf()->limits['max_registrations'] > 1 ? FreshRSS_Context::systemConf()->limits['max_registrations'] : $number + 1; ?>" min="2"
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->limits['max_registrations'] > 1 ? FreshRSS_Context::systemConf()->limits['max_registrations'] : $number + 1; ?>" data-number="<?= $number ?>"/>
<span id="max-registrations-status-disabled">(= <?= _t('admin.system.registration.status.disabled') ?>)</span><span id="max-registrations-status-enabled">(= <?= _t('admin.system.registration.status.enabled') ?>)</span>
</div>
</div>
@@ -124,8 +124,8 @@
name="force-email-validation"
id="force-email-validation"
value="1"
- <?= FreshRSS_Context::$system_conf->force_email_validation ? 'checked="checked"' : '' ?>
- data-leave-validation="<?= FreshRSS_Context::$system_conf->force_email_validation ?>"
+ <?= FreshRSS_Context::systemConf()->force_email_validation ? 'checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::systemConf()->force_email_validation ?>"
/>
<?= _t('admin.system.force_email_validation') ?>
</label>
diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml
index c51289f56..da3bcf844 100644
--- a/app/views/feed/add.phtml
+++ b/app/views/feed/add.phtml
@@ -1,7 +1,7 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
- if ($this->feed) {
+ if ($this->feed !== null) {
?>
<main class="post">
<h1><?= _t('sub.feed.add') ?></h1>
diff --git a/app/views/feed/contentSelectorPreview.phtml b/app/views/feed/contentSelectorPreview.phtml
index a5afb10f4..a93e88783 100644
--- a/app/views/feed/contentSelectorPreview.phtml
+++ b/app/views/feed/contentSelectorPreview.phtml
@@ -4,7 +4,7 @@
FreshRSS::preLayout();
?>
<!DOCTYPE html>
-<html class="preview_background" lang="<?= FreshRSS_Context::$user_conf->language ?>" xml:lang="<?= FreshRSS_Context::$user_conf->language ?>">
+<html class="preview_background" lang="<?= FreshRSS_Context::userConf()->language ?>" xml:lang="<?= FreshRSS_Context::userConf()->language ?>">
<head>
<?= FreshRSS_View::headStyle() ?>
<script src="<?= Minz_Url::display('/scripts/preview.js?' . @filemtime(PUBLIC_PATH . '/scripts/preview.js')) ?>"></script>
diff --git a/app/views/helpers/category/update.phtml b/app/views/helpers/category/update.phtml
index 68132ad27..36c0abfe8 100644
--- a/app/views/helpers/category/update.phtml
+++ b/app/views/helpers/category/update.phtml
@@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
+ if ($this->category === null) {
+ throw new FreshRSS_Context_Exception('Category not initialised!');
+ }
?>
<div class="post">
<h2>
@@ -28,7 +31,7 @@
<div class="form-group">
<label class="group-name" for="position"><?= _t('sub.category.position') ?></label>
<div class="group-controls">
- <input type="number" name="position" id="position" min="1" value="<?= $this->category->attributes('position') ?>" />
+ <input type="number" name="position" id="position" min="1" value="<?= $this->category->attributeInt('position') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.category.position_help') ?></p>
</div>
</div>
@@ -46,7 +49,7 @@
<label class="group-name" for="opml_url"><?= _t('sub.category.opml_url') ?></label>
<div class="group-controls">
<div class="stick">
- <input id="opml_url" name="opml_url" type="url" autocomplete="off" class="long" data-disable-update="refreshOpml" value="<?= $this->category->attributes('opml_url') ?>" />
+ <input id="opml_url" name="opml_url" type="url" autocomplete="off" class="long" data-disable-update="refreshOpml" value="<?= $this->category->attributeString('opml_url') ?>" />
<button type="submit" class="btn" id="refreshOpml" formmethod="post" formaction="<?= _url('category', 'refreshOpml', 'id', $this->category->id()) ?>">
<?= _i('refresh') ?> <?= _t('gen.action.refresh_opml') ?>
</button>
@@ -90,7 +93,8 @@
<legend><?= _t('sub.category.archiving') ?></legend>
<?php
- $archiving = $this->category->attributes('archiving');
+ $archiving = $this->category->attributeArray('archiving');
+ /** @var array<'default'?:bool,'keep_period'?:string,'keep_max'?:int,'keep_min'?:int,'keep_favourites'?:bool,'keep_labels'?:bool,'keep_unreads'?:bool>|null $archiving */
if (empty($archiving)) {
$archiving = [ 'default' => true ];
} else {
@@ -101,7 +105,7 @@
'keep_period_count' => '3',
'keep_period_unit' => 'P1M',
];
- if (!empty($archiving['keep_period'])) {
+ if (!empty($archiving['keep_period']) && is_string($archiving['keep_period'])) {
if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $archiving['keep_period'], $matches)) {
$volatile['enable_keep_period'] = true;
$volatile['keep_period_count'] = $matches['count'];
@@ -109,21 +113,21 @@
}
}
//Defaults
- if (!isset($archiving['keep_max'])) {
- $archiving['keep_max'] = false;
+ if (!isset($archiving['keep_max']) || !is_int($archiving['keep_max'])) {
+ $archiving['keep_max'] = 0;
}
- if (!isset($archiving['keep_favourites'])) {
+ if (!isset($archiving['keep_min']) || !is_int($archiving['keep_min'])) {
+ $archiving['keep_min'] = 50;
+ }
+ if (!isset($archiving['keep_favourites']) || !is_bool($archiving['keep_favourites'])) {
$archiving['keep_favourites'] = true;
}
- if (!isset($archiving['keep_labels'])) {
+ if (!isset($archiving['keep_labels']) || !is_bool($archiving['keep_labels'])) {
$archiving['keep_labels'] = true;
}
- if (!isset($archiving['keep_unreads'])) {
+ if (!isset($archiving['keep_unreads']) || !is_bool($archiving['keep_unreads'])) {
$archiving['keep_unreads'] = false;
}
- if (!isset($archiving['keep_min'])) {
- $archiving['keep_min'] = 50;
- }
?>
<p class="alert alert-warn">
diff --git a/app/views/helpers/configure/query.phtml b/app/views/helpers/configure/query.phtml
index 0f76bc202..145425271 100644
--- a/app/views/helpers/configure/query.phtml
+++ b/app/views/helpers/configure/query.phtml
@@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
+ if ($this->query === null) {
+ throw new FreshRSS_Context_Exception('Query not initialised!');
+ }
?>
<div class="post">
<h2><?= $this->query->getName() ?></h2>
diff --git a/app/views/helpers/export/opml.phtml b/app/views/helpers/export/opml.phtml
index 2c3e004fc..ce53bfc02 100644
--- a/app/views/helpers/export/opml.phtml
+++ b/app/views/helpers/export/opml.phtml
@@ -30,7 +30,7 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
break;
}
/** @var array<string,string> */
- $xPathSettings = $feed->attributes('xpath');
+ $xPathSettings = $feed->attributeArray('xpath') ?? [];
$outline['frss:xPathItem'] = $xPathSettings['item'] ?? null;
$outline['frss:xPathItemTitle'] = $xPathSettings['itemTitle'] ?? null;
$outline['frss:xPathItemContent'] = $xPathSettings['itemContent'] ?? null;
@@ -56,8 +56,8 @@ function feedsToOutlines(array $feeds, bool $excludeMutedFeeds = false): array {
$outline['frss:cssFullContent'] = htmlspecialchars_decode($feed->pathEntries(), ENT_QUOTES);
}
- if ($feed->attributes('path_entries_filter') != '') {
- $outline['frss:cssFullContentFilter'] = $feed->attributes('path_entries_filter');
+ if ($feed->attributeString('path_entries_filter') != '') {
+ $outline['frss:cssFullContentFilter'] = $feed->attributeString('path_entries_filter');
}
// Remove null attributes
@@ -76,7 +76,7 @@ $opml_array = [
'frss' => FreshRSS_Export_Service::FRSS_NAMESPACE,
],
'head' => [
- 'title' => FreshRSS_Context::$system_conf->title,
+ 'title' => FreshRSS_Context::systemConf()->title,
'dateCreated' => new DateTime(),
],
'body' => [],
@@ -90,7 +90,7 @@ if (!empty($this->categories)) {
];
if ($cat->kind() === FreshRSS_Category::KIND_DYNAMIC_OPML) {
- $outline['frss:opmlUrl'] = $cat->attributes('opml_url');
+ $outline['frss:opmlUrl'] = $cat->attributeString('opml_url');
}
$opml_array['body'][] = $outline;
diff --git a/app/views/helpers/extension/configure.phtml b/app/views/helpers/extension/configure.phtml
index 5cf7f9c0a..b714eb553 100644
--- a/app/views/helpers/extension/configure.phtml
+++ b/app/views/helpers/extension/configure.phtml
@@ -4,6 +4,9 @@
if (!Minz_Request::paramBoolean('ajax')) {
$this->partial('aside_configure');
}
+ if ($this->extension === null) {
+ throw new FreshRSS_Context_Exception('Extension not initialised!');
+ }
?>
<div class="post">
<h2>
diff --git a/app/views/helpers/extension/details.phtml b/app/views/helpers/extension/details.phtml
index b8d0d784f..d1f773020 100644
--- a/app/views/helpers/extension/details.phtml
+++ b/app/views/helpers/extension/details.phtml
@@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
+ if ($this->ext_details === null) {
+ throw new FreshRSS_Context_Exception('Extension not initialised!');
+ }
$name_encoded = urlencode($this->ext_details->getName());
$ext_enabled = $this->ext_details->isEnabled();
diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml
index af2503256..5d4f1cc4b 100644
--- a/app/views/helpers/feed/update.phtml
+++ b/app/views/helpers/feed/update.phtml
@@ -1,6 +1,9 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
+ if ($this->feed === null) {
+ throw new FreshRSS_Context_Exception('Feed not initialised!');
+ }
?>
<div class="post" id="feed_update">
<h1><?= $this->feed->name() ?></h1>
@@ -184,9 +187,9 @@
<label class="group-name" for="mark_updated_article_unread"><?= _t('conf.reading.mark_updated_article_unread') ?></label>
<div class="group-controls">
<select name="mark_updated_article_unread" id="mark_updated_article_unread" class="w50">
- <option value=""<?= $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
- <option value="0"<?= $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
- <option value="1"<?= $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
+ <option value=""<?= $this->feed->attributeBoolean('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributeBoolean('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributeBoolean('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</div>
</div>
@@ -195,12 +198,12 @@
<label class="group-name" for="read_when_same_title_in_feed"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_when_same_title_in_feed" id="read_when_same_title_in_feed" class="w50">
- <option value=""<?= $this->feed->attributes('read_when_same_title_in_feed') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
- <option value="0"<?= $this->feed->attributes('read_when_same_title_in_feed') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
- <option value="10"<?= $this->feed->attributes('read_when_same_title_in_feed') == 10 ? ' selected="selected"' : '' ?>>10</option>
- <option value="25"<?= $this->feed->attributes('read_when_same_title_in_feed') == 25 ? ' selected="selected"' : '' ?>>25</option>
- <option value="100"<?= $this->feed->attributes('read_when_same_title_in_feed') == 100 ? ' selected="selected"' : '' ?>>100</option>
- <option value="1000"<?= $this->feed->attributes('read_when_same_title_in_feed') == 1000 ? ' selected="selected"' : '' ?>>1 000</option>
+ <option value=""<?= $this->feed->attributeBoolean('read_when_same_title_in_feed') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributeBoolean('read_when_same_title_in_feed') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="10"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 10 ? ' selected="selected"' : '' ?>>10</option>
+ <option value="25"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 25 ? ' selected="selected"' : '' ?>>25</option>
+ <option value="100"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 100 ? ' selected="selected"' : '' ?>>100</option>
+ <option value="1000"<?= $this->feed->attributeInt('read_when_same_title_in_feed') == 1000 ? ' selected="selected"' : '' ?>>1 000</option>
</select>
<?= _t('conf.reading.read.when_same_title') ?>
</div>
@@ -210,9 +213,9 @@
<label class="group-name" for="read_upon_reception"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_upon_reception" id="read_upon_reception" class="w50">
- <option value=""<?= $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
- <option value="0"<?= $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
- <option value="1"<?= $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
+ <option value=""<?= $this->feed->attributeBoolean('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributeBoolean('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributeBoolean('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
<?= _t('conf.reading.read.upon_reception') ?>
</div>
@@ -222,9 +225,9 @@
<label class="group-name" for="read_upon_gone"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<select name="read_upon_gone" id="read_upon_gone" class="w50">
- <option value=""<?= $this->feed->attributes('read_upon_gone') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
- <option value="0"<?= $this->feed->attributes('read_upon_gone') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
- <option value="1"<?= $this->feed->attributes('read_upon_gone') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
+ <option value=""<?= $this->feed->attributeBoolean('read_upon_gone') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributeBoolean('read_upon_gone') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributeBoolean('read_upon_gone') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
<?= _t('conf.reading.read.upon_gone') ?>
</div>
@@ -245,7 +248,10 @@
<div class="form-group">
<label class="group-name" for="keep_max_n_unread"><?= _t('conf.reading.read.keep_max_n_unread') ?></label>
<div class="group-controls">
- <input type="number" name="keep_max_n_unread" id="keep_max_n_unread" class="w50" min="1" max="10000000" value="<?= $this->feed->attributes('keep_max_n_unread') ?>" placeholder="<?= _t('gen.short.by_default') ?>" />
+ <input type="number" name="keep_max_n_unread" id="keep_max_n_unread" class="w50" min="1" max="10000000"
+ data-leave-validation="<?= $this->feed->attributeInt('keep_max_n_unread') ?>"
+ value="<?= $this->feed->attributeInt('keep_max_n_unread') ?>"
+ placeholder="<?= _t('gen.short.by_default') ?>" />
</div>
</div>
@@ -267,7 +273,8 @@
</div>
</div>
<?php
- $archiving = $this->feed->attributes('archiving');
+ $archiving = $this->feed->attributeArray('archiving');
+ /** @var array<'default'?:bool,'keep_period'?:string,'keep_max'?:int,'keep_min'?:int,'keep_favourites'?:bool,'keep_labels'?:bool,'keep_unreads'?:bool>|null $archiving */
if (empty($archiving)) {
$archiving = [ 'default' => true ];
} else {
@@ -278,7 +285,7 @@
'keep_period_count' => '3',
'keep_period_unit' => 'P1M',
];
- if (!empty($archiving['keep_period'])) {
+ if (!empty($archiving['keep_period']) && is_string($archiving['keep_period'])) {
if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $archiving['keep_period'], $matches)) {
$volatile['enable_keep_period'] = true;
$volatile['keep_period_count'] = $matches['count'];
@@ -286,19 +293,19 @@
}
}
//Defaults
- if (!isset($archiving['keep_max'])) {
- $archiving['keep_max'] = false;
+ if (!isset($archiving['keep_max']) || !is_int($archiving['keep_max'])) {
+ $archiving['keep_max'] = 0;
}
- if (!isset($archiving['keep_min'])) {
+ if (!isset($archiving['keep_min']) || !is_int($archiving['keep_min'])) {
$archiving['keep_min'] = 50;
}
- if (!isset($archiving['keep_favourites'])) {
+ if (!isset($archiving['keep_favourites']) || !is_bool($archiving['keep_favourites'])) {
$archiving['keep_favourites'] = true;
}
- if (!isset($archiving['keep_labels'])) {
+ if (!isset($archiving['keep_labels']) || !is_bool($archiving['keep_labels'])) {
$archiving['keep_labels'] = true;
}
- if (!isset($archiving['keep_unreads'])) {
+ if (!isset($archiving['keep_unreads']) || !is_bool($archiving['keep_unreads'])) {
$archiving['keep_unreads'] = false;
}
?>
@@ -406,7 +413,7 @@
<fieldset id="html_xpath">
<?php
- $xpath = Minz_Helper::htmlspecialchars_utf8((array)($this->feed->attributes('xpath')));
+ $xpath = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeArray('xpath') ?? []);
?>
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.kind.html_xpath.help') ?></p>
<div class="form-group">
@@ -521,7 +528,7 @@
<div class="form-group">
<?php
- $path_entries_filter = Minz_Helper::htmlspecialchars_utf8((string)($this->feed->attributes('path_entries_filter')));
+ $path_entries_filter = Minz_Helper::htmlspecialchars_utf8($this->feed->attributeString('path_entries_filter') ?? '');
?>
<label class="group-name" for="path_entries_filter"><?= _t('sub.feed.css_path_filter') ?></label>
<div class="group-controls">
@@ -537,13 +544,13 @@
<label class="group-name" for="curl_params_cookie"><?= _t('sub.feed.css_cookie') ?></label>
<div class="group-controls">
<input type="text" name="curl_params_cookie" id="curl_params_cookie" class="w100" value="<?=
- is_array($this->feed->attributes('curl_params')) && !empty($this->feed->attributes('curl_params')[CURLOPT_COOKIE]) ?
- $this->feed->attributes('curl_params')[CURLOPT_COOKIE] : ''
+ $this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_COOKIE]) ?
+ $this->feed->attributeArray('curl_params')[CURLOPT_COOKIE] : ''
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.css_cookie_help') ?></p>
<label for="curl_params_cookiefile">
<input type="checkbox" name="curl_params_cookiefile" id="curl_params_cookiefile" value="1"<?=
- is_array($this->feed->attributes('curl_params')) && isset($this->feed->attributes('curl_params')[CURLOPT_COOKIEFILE]) ?
+ $this->feed->attributeArray('curl_params') !== null && isset($this->feed->attributeArray('curl_params')[CURLOPT_COOKIEFILE]) ?
' checked="checked"' : ''
?> />
<?= _t('sub.feed.accept_cookies') ?>
@@ -556,8 +563,8 @@
<label class="group-name" for="curl_params_redirects"><?= _t('sub.feed.max_http_redir') ?></label>
<div class="group-controls">
<input type="number" name="curl_params_redirects" id="curl_params_redirects" class="w50" min="-1" value="<?=
- is_array($this->feed->attributes('curl_params')) && !empty($this->feed->attributes('curl_params')[CURLOPT_MAXREDIRS]) ?
- $this->feed->attributes('curl_params')[CURLOPT_MAXREDIRS] : ''
+ $this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_MAXREDIRS]) ?
+ $this->feed->attributeArray('curl_params')[CURLOPT_MAXREDIRS] : ''
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.max_http_redir_help') ?></p>
</div>
@@ -567,9 +574,9 @@
<label class="group-name" for="content_action"><?= _t('sub.feed.content_action') ?></label>
<div class="group-controls">
<select name="content_action" id="content_action" class="w50">
- <option value="replace"<?= 'replace' === $this->feed->attributes('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.replace') ?></option>
- <option value="prepend"<?= 'prepend' === $this->feed->attributes('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.prepend') ?></option>
- <option value="append"<?= 'append' === $this->feed->attributes('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.append') ?></option>
+ <option value="replace"<?= 'replace' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.replace') ?></option>
+ <option value="prepend"<?= 'prepend' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.prepend') ?></option>
+ <option value="append"<?= 'append' === $this->feed->attributeString('content_action') ? ' selected="selected"' : '' ?>><?= _t('sub.feed.content_action.append') ?></option>
</select>
</div>
</div>
@@ -578,8 +585,8 @@
<label class="group-name" for="curl_params_useragent"><?= _t('sub.feed.useragent') ?></label>
<div class="group-controls">
<input type="text" name="curl_params_useragent" id="curl_params_useragent" class="w100" value="<?=
- is_array($this->feed->attributes('curl_params')) && !empty($this->feed->attributes('curl_params')[CURLOPT_USERAGENT]) ?
- $this->feed->attributes('curl_params')[CURLOPT_USERAGENT] : ''
+ $this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_USERAGENT]) ?
+ $this->feed->attributeArray('curl_params')[CURLOPT_USERAGENT] : ''
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.useragent_help') ?></p>
</div>
@@ -590,8 +597,8 @@
<div class="group-controls">
<select name="proxy_type" id="proxy_type"><?php
$type = '';
- if (is_array($this->feed->attributes('curl_params')) && isset($this->feed->attributes('curl_params')[CURLOPT_PROXYTYPE])) {
- $type = $this->feed->attributes('curl_params')[CURLOPT_PROXYTYPE];
+ if ($this->feed->attributeArray('curl_params') !== null && isset($this->feed->attributeArray('curl_params')[CURLOPT_PROXYTYPE])) {
+ $type = $this->feed->attributeArray('curl_params')[CURLOPT_PROXYTYPE];
}
foreach(['' => '', 3 => 'NONE', 0 => 'HTTP', 2 => 'HTTPS', 4 => 'SOCKS4', 6 => 'SOCKS4A', 5 => 'SOCKS5', 7 => 'SOCKS5H'] as $k => $v) {
echo '<option value="' . $k . ($type === $k ? '" selected="selected' : '' ) . '">' . $v . '</option>';
@@ -599,8 +606,8 @@
?>
</select>
<input type="text" name="curl_params" id="curl_params" value="<?=
- is_array($this->feed->attributes('curl_params')) && !empty($this->feed->attributes('curl_params')[CURLOPT_PROXY]) ?
- $this->feed->attributes('curl_params')[CURLOPT_PROXY] : ''
+ $this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_PROXY]) ?
+ $this->feed->attributeArray('curl_params')[CURLOPT_PROXY] : ''
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.proxy_help') ?></p>
</div>
@@ -609,7 +616,7 @@
<div class="form-group">
<label class="group-name" for="timeout"><?= _t('sub.feed.timeout') ?></label>
<div class="group-controls">
- <input type="number" name="timeout" id="timeout" class="w50" min="3" max="900" value="<?= $this->feed->attributes('timeout') ?>" placeholder="<?= _t('gen.short.by_default') ?>" />
+ <input type="number" name="timeout" id="timeout" class="w50" min="3" max="900" value="<?= $this->feed->attributeInt('timeout') ?>" placeholder="<?= _t('gen.short.by_default') ?>" />
</div>
</div>
@@ -617,9 +624,9 @@
<label class="group-name" for="ssl_verify"><?= _t('sub.feed.ssl_verify') ?></label>
<div class="group-controls">
<select name="ssl_verify" id="ssl_verify" class="w50">
- <option value=""<?= $this->feed->attributes('ssl_verify') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
- <option value="0"<?= $this->feed->attributes('ssl_verify') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
- <option value="1"<?= $this->feed->attributes('ssl_verify') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
+ <option value=""<?= $this->feed->attributeBoolean('ssl_verify') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributeBoolean('ssl_verify') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributeBoolean('ssl_verify') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</div>
</div>
@@ -627,7 +634,7 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="clear_cache">
- <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributes('clear_cache') ? ' checked="checked"' : '' ?> />
+ <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributeBoolean('clear_cache') ? ' checked="checked"' : '' ?> />
<?= _t('sub.feed.clear_cache') ?>
</label>
</div>
diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml
index dba0e44a3..e5bfd7fd0 100644
--- a/app/views/helpers/index/normal/entry_bottom.phtml
+++ b/app/views/helpers/index/normal/entry_bottom.phtml
@@ -1,13 +1,13 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
- $bottomline_read = FreshRSS_Context::$user_conf->bottomline_read;
- $bottomline_favorite = FreshRSS_Context::$user_conf->bottomline_favorite;
- $bottomline_sharing = FreshRSS_Context::$user_conf->bottomline_sharing && (count(FreshRSS_Context::$user_conf->sharing) > 0);
- $bottomline_myLabels = FreshRSS_Context::$user_conf->bottomline_myLabels;
- $bottomline_tags = FreshRSS_Context::$user_conf->bottomline_tags;
- $bottomline_date = FreshRSS_Context::$user_conf->bottomline_date;
- $bottomline_link = FreshRSS_Context::$user_conf->bottomline_link;
+ $bottomline_read = FreshRSS_Context::userConf()->bottomline_read;
+ $bottomline_favorite = FreshRSS_Context::userConf()->bottomline_favorite;
+ $bottomline_sharing = FreshRSS_Context::userConf()->bottomline_sharing && (count(FreshRSS_Context::userConf()->sharing) > 0);
+ $bottomline_myLabels = FreshRSS_Context::userConf()->bottomline_myLabels;
+ $bottomline_tags = FreshRSS_Context::userConf()->bottomline_tags;
+ $bottomline_date = FreshRSS_Context::userConf()->bottomline_date;
+ $bottomline_link = FreshRSS_Context::userConf()->bottomline_link;
?><ul class="horizontal-list bottom"><?php
if (FreshRSS_Auth::hasAccess()) {
if ($bottomline_read) {
@@ -81,8 +81,8 @@
<li class="dropdown-header"><?= _t('index.share') ?> <a href="<?= _url('configure', 'integration') ?>"><?= _i('configure') ?></a></li><?php
$id = $this->entry->id();
$link = $this->entry->link();
- $title = $this->entry->title() . ' · ' . $this->feed->name();
- foreach (FreshRSS_Context::$user_conf->sharing as $share_options) {
+ $title = $this->entry->title() . ' · ' . ($this->feed === null ? '' : $this->feed->name());
+ foreach (FreshRSS_Context::userConf()->sharing as $share_options) {
$share = FreshRSS_Share::get($share_options['type']);
if ($share === null) {
continue;
diff --git a/app/views/helpers/index/normal/entry_header.phtml b/app/views/helpers/index/normal/entry_header.phtml
index 6a693b0a9..b324a5949 100644
--- a/app/views/helpers/index/normal/entry_header.phtml
+++ b/app/views/helpers/index/normal/entry_header.phtml
@@ -1,15 +1,18 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
- $topline_read = FreshRSS_Context::$user_conf->topline_read;
- $topline_favorite = FreshRSS_Context::$user_conf->topline_favorite;
- $topline_website = FreshRSS_Context::$user_conf->topline_website;
- $topline_thumbnail = FreshRSS_Context::$user_conf->topline_thumbnail;
- $topline_summary = FreshRSS_Context::$user_conf->topline_summary;
- $topline_display_authors = FreshRSS_Context::$user_conf->topline_display_authors;
- $topline_date = FreshRSS_Context::$user_conf->topline_date;
- $topline_link = FreshRSS_Context::$user_conf->topline_link;
- $lazyload = FreshRSS_Context::$user_conf->lazyload;
+ if ($this->feed === null) {
+ throw new FreshRSS_Context_Exception('Feed not initialised!');
+ }
+ $topline_read = FreshRSS_Context::userConf()->topline_read;
+ $topline_favorite = FreshRSS_Context::userConf()->topline_favorite;
+ $topline_website = FreshRSS_Context::userConf()->topline_website;
+ $topline_thumbnail = FreshRSS_Context::userConf()->topline_thumbnail;
+ $topline_summary = FreshRSS_Context::userConf()->topline_summary;
+ $topline_display_authors = FreshRSS_Context::userConf()->topline_display_authors;
+ $topline_date = FreshRSS_Context::userConf()->topline_date;
+ $topline_link = FreshRSS_Context::userConf()->topline_link;
+ $lazyload = FreshRSS_Context::userConf()->lazyload;
?><ul class="horizontal-list flux_header website<?= $topline_website ?>"><?php
if (FreshRSS_Auth::hasAccess()) {
if ($topline_read) {
@@ -37,7 +40,7 @@
if ($topline_website !== 'none'):
?><li class="item website <?= $topline_website ?>">
<a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>" class="item-element" title="<?= _t('gen.action.filter') ?>: <?= $this->feed->name() ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons && 'name' !== $topline_website): ?><img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?><?php if ('icon' !== $topline_website): ?><span class="websiteName"><?= $this->feed->name() ?></span><?php endif; ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons && 'name' !== $topline_website): ?><img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?><?php if ('icon' !== $topline_website): ?><span class="websiteName"><?= $this->feed->name() ?></span><?php endif; ?>
</a>
</li><?php
endif; ?>
diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml
index 38a7751ee..29f78e5ee 100644
--- a/app/views/helpers/javascript_vars.phtml
+++ b/app/views/helpers/javascript_vars.phtml
@@ -1,27 +1,27 @@
<?php
declare(strict_types=1);
/** @var FreshRSS_View $this */
-$mark = FreshRSS_Context::$user_conf->mark_when;
-$s = FreshRSS_Context::$user_conf->shortcuts;
+$mark = FreshRSS_Context::userConf()->mark_when;
+$s = FreshRSS_Context::userConf()->shortcuts;
$extData = Minz_ExtensionManager::callHook('js_vars', []);
echo htmlspecialchars(json_encode(array(
'context' => array(
'anonymous' => !FreshRSS_Auth::hasAccess(),
'auto_remove_article' => !!FreshRSS_Context::isAutoRemoveAvailable(),
- 'hide_posts' => !(FreshRSS_Context::$user_conf->display_posts || Minz_Request::actionName() === 'reader'),
- 'display_order' => Minz_Request::paramString('order') ?: FreshRSS_Context::$user_conf->sort_order,
- 'display_categories' => FreshRSS_Context::$user_conf->display_categories,
+ 'hide_posts' => !(FreshRSS_Context::userConf()->display_posts || Minz_Request::actionName() === 'reader'),
+ 'display_order' => Minz_Request::paramString('order') ?: FreshRSS_Context::userConf()->sort_order,
+ 'display_categories' => FreshRSS_Context::userConf()->display_categories,
'auto_mark_article' => !!$mark['article'],
'auto_mark_site' => !!$mark['site'],
'auto_mark_scroll' => !!$mark['scroll'],
'auto_mark_focus' => !!$mark['focus'],
- 'auto_load_more' => !!FreshRSS_Context::$user_conf->auto_load_more,
+ 'auto_load_more' => !!FreshRSS_Context::userConf()->auto_load_more,
'auto_actualize_feeds' => Minz_Session::paramBoolean('actualize_feeds'),
- 'does_lazyload' => !!FreshRSS_Context::$user_conf->lazyload ,
- 'sides_close_article' => !!FreshRSS_Context::$user_conf->sides_close_article,
+ 'does_lazyload' => !!FreshRSS_Context::userConf()->lazyload ,
+ 'sides_close_article' => !!FreshRSS_Context::userConf()->sides_close_article,
'sticky_post' => !!FreshRSS_Context::isStickyPostEnabled(),
- 'html5_notif_timeout' => FreshRSS_Context::$user_conf->html5_notif_timeout,
- 'auth_type' => FreshRSS_Context::$system_conf->auth_type,
+ 'html5_notif_timeout' => FreshRSS_Context::userConf()->html5_notif_timeout,
+ 'auth_type' => FreshRSS_Context::systemConf()->auth_type,
'current_view' => Minz_Request::actionName(),
'csrf' => FreshRSS_Auth::csrfToken(),
'mtime' => [
@@ -69,7 +69,7 @@ echo htmlspecialchars(json_encode(array(
'notif_request_failed' => _t('gen.js.feedback.request_failed'),
'category_empty' => _t('gen.js.category_empty'),
'labels_empty' => _t('gen.js.labels_empty'),
- 'language' => FreshRSS_Context::$user_conf->language,
+ 'language' => FreshRSS_Context::userConf()->language,
),
'icons' => array(
'read' => rawurlencode(_i('read')),
diff --git a/app/views/helpers/stream-footer.phtml b/app/views/helpers/stream-footer.phtml
index 41f4315b5..0cbab601a 100644
--- a/app/views/helpers/stream-footer.phtml
+++ b/app/views/helpers/stream-footer.phtml
@@ -32,13 +32,13 @@
<?php } elseif ($hasAccess) { ?>
<?= _t('gen.stream.nothing_to_load') ?><br />
<button id="bigMarkAsRead"
- class="as-link <?= FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : '' ?>"
+ class="as-link <?= FreshRSS_Context::userConf()->reading_confirm ? 'confirm" disabled="disabled' : '' ?>"
form="stream-footer"
formaction="<?= Minz_Url::display($url_mark_read) ?>"
type="submit">
<span class="bigTick">✓</span><br />
<span class="markAllRead"><?= _t('gen.stream.mark_all_read') ?></span><br />
- <?php if (FreshRSS_Context::$user_conf->onread_jump_next) { ?>
+ <?php if (FreshRSS_Context::userConf()->onread_jump_next) { ?>
<span class="jumpNext"><?= _t('conf.reading.jump_next') ?></span>
<?php } ?>
</button>
diff --git a/app/views/index/about.phtml b/app/views/index/about.phtml
index 5ee1729cd..1c41cf4d6 100644
--- a/app/views/index/about.phtml
+++ b/app/views/index/about.phtml
@@ -33,8 +33,8 @@
<?= FRESHRSS_VERSION ?>
<?php
- $env = FreshRSS_Context::$system_conf->environment;
- if ($env !== 'production' && FreshRSS_Context::$user_conf->is_admin) { ?>
+ $env = FreshRSS_Context::systemConf()->environment;
+ if ($env !== 'production' && FreshRSS_Context::userConf()->is_admin) { ?>
<h2>data/config.php</h2>
<code>'environment' => '<?= $env; ?>'</code><br />
<?php
diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml
index 0ddc22e11..6a46ec2ca 100644
--- a/app/views/index/global.phtml
+++ b/app/views/index/global.phtml
@@ -6,7 +6,7 @@
$class = '';
$state_unread = false;
- if (FreshRSS_Context::$user_conf->hide_read_feeds &&
+ if (FreshRSS_Context::userConf()->hide_read_feeds &&
FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) &&
!FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) {
$class = ' state_unread';
@@ -62,7 +62,7 @@
?>
<li id="f_<?= $feed->id() ?>" class="item feed<?= $error_class, $empty_class, $mute_class ?>" title="<?= $error_title, $empty_title ?>"
data-unread="<?= $feed->nbNotRead() ?>" data-priority="<?= $feed->priority() ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?><img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?><img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?>
<a class="item-title" data-unread="<?= format_number($feed->nbNotRead()) ?>" href="<?= Minz_Url::display($url_base) ?>"><?= $feed->name() ?></a>
</li>
<?php } ?>
@@ -82,6 +82,6 @@
<div id="overlay">
<a class="close" href="#"><?= _i('close') ?></a>
- <div id="panel"<?= FreshRSS_Context::$user_conf->display_posts ? '' : ' class="hide_posts"' ?>>
+ <div id="panel"<?= FreshRSS_Context::userConf()->display_posts ? '' : ' class="hide_posts"' ?>>
</div>
</div>
diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml
index 0d484f518..42c2e0072 100644
--- a/app/views/index/normal.phtml
+++ b/app/views/index/normal.phtml
@@ -11,10 +11,10 @@ call_user_func($this->callbackBeforeEntries, $this);
$display_today = true;
$display_yesterday = true;
$display_others = true;
-$hidePosts = !FreshRSS_Context::$user_conf->display_posts;
-$lazyload = FreshRSS_Context::$user_conf->lazyload;
-$content_width = FreshRSS_Context::$user_conf->content_width;
-$MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
+$hidePosts = !FreshRSS_Context::userConf()->display_posts;
+$lazyload = FreshRSS_Context::userConf()->lazyload;
+$content_width = FreshRSS_Context::userConf()->content_width;
+$MAX_TAGS_DISPLAYED = FreshRSS_Context::userConf()->show_tags_max;
$useKeepUnreadImportant = !FreshRSS_Context::isImportant() && !FreshRSS_Context::isFeed();
$today = @strtotime('today');
@@ -74,12 +74,15 @@ $today = @strtotime('today');
?>" data-priority="<?= $this->feed->priority()
?>"><?php
$this->renderHelper('index/normal/entry_header');
+ if ($this->feed === null) {
+ throw new FreshRSS_Context_Exception('Feed not initialised!');
+ }
$tags = null;
$firstTags = array();
$remainingTags = array();
- if (FreshRSS_Context::$user_conf->show_tags === 'h' || FreshRSS_Context::$user_conf->show_tags === 'f' || FreshRSS_Context::$user_conf->show_tags === 'b') {
+ if (FreshRSS_Context::userConf()->show_tags === 'h' || FreshRSS_Context::userConf()->show_tags === 'f' || FreshRSS_Context::userConf()->show_tags === 'b') {
$tags = $this->entry->tags();
if (!empty($tags)) {
if ($MAX_TAGS_DISPLAYED > 0) {
@@ -93,14 +96,14 @@ $today = @strtotime('today');
?><article class="flux_content" dir="auto">
<div class="content <?= $content_width ?>">
<header>
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 't') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 't') { ?>
<div class="website"><a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $this->feed->name() ?></span></a>
</div>
<?php } ?>
- <?php if (FreshRSS_Context::$user_conf->show_tags === 'h' || FreshRSS_Context::$user_conf->show_tags === 'b') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_tags === 'h' || FreshRSS_Context::userConf()->show_tags === 'b') { ?>
<div class="tags">
<?php
if (!empty($tags)) {
@@ -132,11 +135,11 @@ $today = @strtotime('today');
<?php
} ?>
<h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?= $this->entry->link() ?>" title="<?= _t('conf.shortcut.see_on_website')?>"><?= $this->entry->title() ?></a></h1>
- <?php if (FreshRSS_Context::$user_conf->show_author_date === 'h' || FreshRSS_Context::$user_conf->show_author_date === 'b') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_author_date === 'h' || FreshRSS_Context::userConf()->show_author_date === 'b') { ?>
<div class="subtitle">
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 'a') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
<div class="website"><a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $this->feed->name() ?></span></a>
</div>
@@ -164,8 +167,8 @@ $today = @strtotime('today');
echo $lazyload && $hidePosts ? lazyimg($this->entry->content(true)) : $this->entry->content(true);
?></div>
<?php
- $display_authors_date = FreshRSS_Context::$user_conf->show_author_date === 'f' || FreshRSS_Context::$user_conf->show_author_date === 'b';
- $display_tags = FreshRSS_Context::$user_conf->show_tags === 'f' || FreshRSS_Context::$user_conf->show_tags === 'b';
+ $display_authors_date = FreshRSS_Context::userConf()->show_author_date === 'f' || FreshRSS_Context::userConf()->show_author_date === 'b';
+ $display_tags = FreshRSS_Context::userConf()->show_tags === 'f' || FreshRSS_Context::userConf()->show_tags === 'b';
if ($display_authors_date || $display_tags) {
?>
@@ -173,9 +176,9 @@ $today = @strtotime('today');
<?php
if ($display_authors_date) { ?>
<div class="subtitle">
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 'a') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
<div class="website"><a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $this->feed->name() ?></span></a>
</div>
@@ -266,4 +269,4 @@ $today = @strtotime('today');
<?= _i('close') ?>
</a>
-<?php if ($nbEntries > 0 && FreshRSS_Context::$user_conf->show_nav_buttons) $this->partial('nav_entries'); ?>
+<?php if ($nbEntries > 0 && FreshRSS_Context::userConf()->show_nav_buttons) $this->partial('nav_entries'); ?>
diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml
index dc90a144a..f2d7ab46b 100644
--- a/app/views/index/reader.phtml
+++ b/app/views/index/reader.phtml
@@ -8,9 +8,9 @@ if (!Minz_Request::paramBoolean('ajax')) {
call_user_func($this->callbackBeforeEntries, $this);
-$lazyload = FreshRSS_Context::$user_conf->lazyload;
-$content_width = FreshRSS_Context::$user_conf->content_width;
-$MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
+$lazyload = FreshRSS_Context::userConf()->lazyload;
+$content_width = FreshRSS_Context::userConf()->content_width;
+$MAX_TAGS_DISPLAYED = FreshRSS_Context::userConf()->show_tags_max;
?>
<main id="stream" class="reader">
<h1 class="title_hidden"><?= _t('conf.reading.view.reader') ?></h1>
@@ -35,7 +35,7 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
$firstTags = array();
$remainingTags = array();
- if (FreshRSS_Context::$user_conf->show_tags == 'h' || FreshRSS_Context::$user_conf->show_tags == 'f' || FreshRSS_Context::$user_conf->show_tags == 'b') {
+ if (FreshRSS_Context::userConf()->show_tags == 'h' || FreshRSS_Context::userConf()->show_tags == 'f' || FreshRSS_Context::userConf()->show_tags == 'b') {
$tags = $this->entry->tags();
if (!empty($tags)) {
if ($MAX_TAGS_DISPLAYED > 0) {
@@ -69,15 +69,15 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
<a class="read" href="<?= Minz_Url::display($readUrl) ?>" title="<?= _t('conf.shortcut.mark_read') ?>"><?= _i($item->isRead() ? 'read' : 'unread') ?></a>
<a class="bookmark" href="<?= Minz_Url::display($favoriteUrl) ?>" title="<?= _t('conf.shortcut.mark_favorite') ?>"><?= _i($item->isFavorite() ? 'starred' : 'non-starred') ?></a>
<?php } ?>
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 't') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 't') { ?>
<a class="website" href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $feed->name() ?></span></a>
<?php } ?>
</div>
- <?php if (FreshRSS_Context::$user_conf->show_tags === 'h' || FreshRSS_Context::$user_conf->show_tags === 'b') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_tags === 'h' || FreshRSS_Context::userConf()->show_tags === 'b') { ?>
<div class="tags">
<?php
if (!empty($tags)) {
@@ -109,11 +109,11 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
<?php } ?>
<h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?= $item->link() ?>"><?= $item->title() ?></a></h1>
- <?php if (FreshRSS_Context::$user_conf->show_author_date === 'h' || FreshRSS_Context::$user_conf->show_author_date === 'b') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_author_date === 'h' || FreshRSS_Context::userConf()->show_author_date === 'b') { ?>
<div class="subtitle">
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 'a') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
<div class="website"><a href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $feed->name() ?></span></a></div>
<?php } ?>
@@ -141,17 +141,17 @@ $MAX_TAGS_DISPLAYED = FreshRSS_Context::$user_conf->show_tags_max;
<?= $item->content(true) ?>
</div>
<?php
- $display_authors_date = FreshRSS_Context::$user_conf->show_author_date === 'f' || FreshRSS_Context::$user_conf->show_author_date === 'b';
- $display_tags = FreshRSS_Context::$user_conf->show_tags === 'f' || FreshRSS_Context::$user_conf->show_tags === 'b';
+ $display_authors_date = FreshRSS_Context::userConf()->show_author_date === 'f' || FreshRSS_Context::userConf()->show_author_date === 'b';
+ $display_tags = FreshRSS_Context::userConf()->show_tags === 'f' || FreshRSS_Context::userConf()->show_tags === 'b';
if ($display_authors_date || $display_tags) {
?>
<footer>
<?php if ($display_authors_date) { ?>
<div class="subtitle">
- <?php if (FreshRSS_Context::$user_conf->show_feed_name === 'a') { ?>
+ <?php if (FreshRSS_Context::userConf()->show_feed_name === 'a') { ?>
<div class="website"><a href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>" title="<?= _t('gen.action.filter') ?>">
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?>
<img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php
endif; ?><span><?= $feed->name() ?></span></a></div>
<?php } ?>
diff --git a/app/views/index/rss.phtml b/app/views/index/rss.phtml
index a10aa806b..0205b0703 100644
--- a/app/views/index/rss.phtml
+++ b/app/views/index/rss.phtml
@@ -47,7 +47,7 @@ foreach ($this->entries as $item) {
echo "\t\t\t", '<media:thumbnail url="' . $thumbnail['url']
. (empty($thumbnail['width']) ? '' : '" width="' . $thumbnail['width'])
. (empty($thumbnail['height']) ? '' : '" height="' . $thumbnail['height'])
- . (empty($thumbnail['time']) ? '' : '" time="' . $thumbnail['time'])
+ . (empty($thumbnail['type']) ? '' : '" type="' . $thumbnail['type'])
. '" />', "\n";
}
$enclosures = $item->enclosures(false);
diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml
index a671bb83e..5390a00a3 100644
--- a/app/views/stats/idle.phtml
+++ b/app/views/stats/idle.phtml
@@ -36,15 +36,15 @@
$empty_class = '';
$empty_title = '';
- if ($feed != null && $feed->nbEntries() == 0) {
+ if ($feed !== null && $feed->nbEntries() == 0) {
$empty_class = ' empty';
$empty_title = _t('sub.feed.empty');
}
- $mute_class = $feed->mute() ? ' mute' : '';
+ $mute_class = ($feed !== null && $feed->mute()) ? ' mute' : '';
?>
<li class="item feed<?= $error_class, $empty_class, $mute_class ?>" title="<?= $error_title, $empty_title ?>">
<a class="configure open-slider" href="<?= _url('stats', 'feed', 'id', $feedInPeriod['id'], 'sub', 'idle') ?>" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a>
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?><img class="favicon" src="<?= $feedInPeriod['favicon'] ?>" alt="✇" loading="lazy" /><?php endif; ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?><img class="favicon" src="<?= $feedInPeriod['favicon'] ?>" alt="✇" loading="lazy" /><?php endif; ?>
<span title="<?= timestamptodate((int)($feedInPeriod['last_date']), false) ?>"><?= $feedInPeriod['name'] ?>
(<?= _t('admin.stats.number_entries', $feedInPeriod['nb_articles']) ?>)</span>
</li>
diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml
index a1a874b31..4bb966e8b 100644
--- a/app/views/subscription/index.phtml
+++ b/app/views/subscription/index.phtml
@@ -34,8 +34,8 @@
?>
<div class="box">
<div class="box-title">
- <a class="configure open-slider" href="<?= _url('category', 'update', 'id', $cat->id()) ?>" data-cat-position="<?= $cat->attributes('position') ?>"><?= _i('configure') ?></a>
- <h2><?= $cat->name() ?><?php if ($cat->kind() == FreshRSS_Category::KIND_DYNAMIC_OPML) { echo " " . _i('opml-dyn'); } ?></h2>
+ <a class="configure open-slider" href="<?= _url('category', 'update', 'id', $cat->id()) ?>" data-cat-position="<?= $cat->attributeString('position') ?>"><?= _i('configure') ?></a>
+ <h2><?= $cat->name() ?><?php if ($cat->kind() === FreshRSS_Category::KIND_DYNAMIC_OPML) { echo " " . _i('opml-dyn'); } ?></h2>
</div>
<ul class="box-content drop-zone scrollbar-thin" dropzone="move" data-cat-id="<?= $cat->id() ?>">
<?php
@@ -63,7 +63,7 @@
<li class="item feed<?= $error_class, $empty_class, $mute_class ?>" title="<?= $error_title, $empty_title ?>"
draggable="true" data-feed-id="<?= $feed->id() ?>" data-priority="<?= $feed->priority() ?>">
<a class="configure open-slider" href="<?= _url('subscription', 'feed', 'id', $feed->id()) ?>" title="<?= _t('gen.action.manage') ?>"><?= _i('configure') ?></a>
- <?php if (FreshRSS_Context::$user_conf->show_favicons): ?><img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?>
+ <?php if (FreshRSS_Context::userConf()->show_favicons): ?><img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" loading="lazy" /><?php endif; ?>
<span class="item-title"><?= $feed->name() ?></span>
</li>
<?php
diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml
index dcff153d6..12ae3d07d 100644
--- a/app/views/user/manage.phtml
+++ b/app/views/user/manage.phtml
@@ -21,7 +21,7 @@
<select name="new_user_language" id="new_user_language">
<?php $languages = Minz_Translate::availableLanguages(); ?>
<?php foreach ($languages as $lang) { ?>
- <option value="<?= $lang ?>"<?= FreshRSS_Context::$user_conf->language === $lang ?
+ <option value="<?= $lang ?>"<?= FreshRSS_Context::userConf()->language === $lang ?
' selected="selected"' : '' ?>><?= _t('gen.lang.' . $lang) ?></option>
<?php } ?>
</select>
diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml
index 0a41d4dc4..576e821b2 100644
--- a/app/views/user/profile.phtml
+++ b/app/views/user/profile.phtml
@@ -36,7 +36,7 @@
<div class="form-group">
<label class="group-name" for="email"><?= _t('conf.profile.email') ?></label>
<div class="group-controls">
- <input id="email" name="email" type="email" value="<?= FreshRSS_Context::$user_conf->mail_login ?>" />
+ <input id="email" name="email" type="email" value="<?= FreshRSS_Context::userConf()->mail_login ?>" />
</div>
</div>
@@ -56,12 +56,12 @@
<?php if (FreshRSS_Auth::accessNeedsAction()) { ?>
<div class="form-group">
<label class="group-name" for="token"><?= _t('admin.auth.token') ?></label>
- <?php $token = FreshRSS_Context::$user_conf->token; ?>
+ <?php $token = FreshRSS_Context::userConf()->token; ?>
<div class="group-controls">
<input type="text" id="token" name="token" value="<?= $token ?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" data-leave-validation="<?= $token ?>"/>
<p class="help"><?= _i('help') ?> <?= _t('admin.auth.token_help') ?></p>
<kbd><?= Minz_Url::display(array('a' => 'rss', 'params' => array('user' => Minz_User::name(),
- 'token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true) ?></kbd>
+ 'token' => $token, 'hours' => FreshRSS_Context::userConf()->since_hours_posts_per_rss)), 'html', true) ?></kbd>
</div>
</div>
<?php } ?>
@@ -74,7 +74,7 @@
</div>
</form>
- <?php if (FreshRSS_Context::$system_conf->api_enabled) { ?>
+ <?php if (FreshRSS_Context::systemConf()->api_enabled) { ?>
<form method="post" action="<?= _url('api', 'updatePassword') ?>">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<legend><?= _t('conf.profile.api') ?></legend>
diff --git a/app/views/user/validateEmail.phtml b/app/views/user/validateEmail.phtml
index 8f822fe6a..a2f486d86 100644
--- a/app/views/user/validateEmail.phtml
+++ b/app/views/user/validateEmail.phtml
@@ -4,11 +4,11 @@
?>
<main class="post">
<p>
- <?= _t('user.email.validation.need_to', FreshRSS_Context::$system_conf->title) ?>
+ <?= _t('user.email.validation.need_to', FreshRSS_Context::systemConf()->title) ?>
</p>
<p>
- <?= _t('user.email.validation.email_sent_to', FreshRSS_Context::$user_conf->mail_login) ?>
+ <?= _t('user.email.validation.email_sent_to', FreshRSS_Context::userConf()->mail_login) ?>
</p>
<form action="<?= _url('user', 'sendValidationEmail') ?>" method="post">
diff --git a/cli/_cli.php b/cli/_cli.php
index eb2152082..91fa8de36 100644
--- a/cli/_cli.php
+++ b/cli/_cli.php
@@ -35,11 +35,12 @@ function cliInitUser(string $username): string {
fail('FreshRSS error: user not found: ' . $username . "\n");
}
- if (!FreshRSS_Context::initUser($username)) {
+ FreshRSS_Context::initUser($username);
+ if (!FreshRSS_Context::hasUserConf()) {
fail('FreshRSS error: invalid configuration for user: ' . $username . "\n");
}
- $ext_list = FreshRSS_Context::$user_conf->extensions_enabled;
+ $ext_list = FreshRSS_Context::userConf()->extensions_enabled;
Minz_ExtensionManager::enableByList($ext_list, 'user');
return $username;
@@ -80,10 +81,10 @@ function performRequirementCheck(string $databaseType): void {
*/
function getLongOptions(array $options, string $regex): array {
$longOptions = array_filter($options, static function (string $a) use ($regex) {
- return preg_match($regex, $a);
+ return preg_match($regex, $a) === 1;
});
return array_map(static function (string $a) use ($regex) {
- return preg_replace($regex, '', $a);
+ return preg_replace($regex, '', $a) ?? '';
}, $longOptions);
}
diff --git a/cli/_update-or-create-user.php b/cli/_update-or-create-user.php
index 69e6ce589..385bbd549 100644
--- a/cli/_update-or-create-user.php
+++ b/cli/_update-or-create-user.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
diff --git a/cli/actualize-user.php b/cli/actualize-user.php
index 870eda9b2..99b48116d 100755
--- a/cli/actualize-user.php
+++ b/cli/actualize-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
@@ -17,7 +17,7 @@ if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($o
$username = cliInitUser($options['user']);
-Minz_ExtensionManager::callHook('freshrss_user_maintenance');
+Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance');
fwrite(STDERR, 'FreshRSS actualizing user “' . $username . "”…\n");
diff --git a/cli/create-user.php b/cli/create-user.php
index 286befe85..c360a88a5 100755
--- a/cli/create-user.php
+++ b/cli/create-user.php
@@ -38,7 +38,7 @@ if (!empty($options['api_password'])) {
}
}
-invalidateHttpCache(FreshRSS_Context::$system_conf->default_user);
+invalidateHttpCache(FreshRSS_Context::systemConf()->default_user);
echo 'ℹ️ Remember to refresh the feeds of the user: ', $username ,
"\t", './cli/actualize-user.php --user ', $username, "\n";
diff --git a/cli/db-optimize.php b/cli/db-optimize.php
index 2561e7cb2..82f545420 100755
--- a/cli/db-optimize.php
+++ b/cli/db-optimize.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
diff --git a/cli/delete-user.php b/cli/delete-user.php
index 2ad84b7dc..d8d3033cc 100755
--- a/cli/delete-user.php
+++ b/cli/delete-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
@@ -24,7 +24,7 @@ if (!preg_grep("/^$username$/i", $usernames)) {
fail('FreshRSS error: username not found “' . $username . '”');
}
-if (strcasecmp($username, FreshRSS_Context::$system_conf->default_user) === 0) {
+if (strcasecmp($username, FreshRSS_Context::systemConf()->default_user) === 0) {
fail('FreshRSS error: default user must not be deleted: “' . $username . '”');
}
@@ -32,6 +32,6 @@ echo 'FreshRSS deleting user “', $username, "”…\n";
$ok = FreshRSS_user_Controller::deleteUser($username);
-invalidateHttpCache(FreshRSS_Context::$system_conf->default_user);
+invalidateHttpCache(FreshRSS_Context::systemConf()->default_user);
done($ok);
diff --git a/cli/do-install.php b/cli/do-install.php
index 1b391a458..c69d5f081 100755
--- a/cli/do-install.php
+++ b/cli/do-install.php
@@ -44,7 +44,7 @@ fwrite(STDERR, 'FreshRSS install…' . "\n");
$config = array(
'salt' => generateSalt(),
- 'db' => FreshRSS_Context::$system_conf->db,
+ 'db' => FreshRSS_Context::systemConf()->db,
);
$customConfigPath = DATA_PATH . '/config.custom.php';
@@ -62,7 +62,7 @@ foreach ($params as $param) {
}
}
-if ((!empty($config['base_url'])) && Minz_Request::serverIsPublic($config['base_url'])) {
+if ((!empty($config['base_url'])) && is_string($config['base_url']) && Minz_Request::serverIsPublic($config['base_url'])) {
$config['pubsubhubbub_enabled'] = true;
}
diff --git a/cli/export-opml-for-user.php b/cli/export-opml-for-user.php
index a28bddced..51beb12f3 100755
--- a/cli/export-opml-for-user.php
+++ b/cli/export-opml-for-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
diff --git a/cli/export-sqlite-for-user.php b/cli/export-sqlite-for-user.php
index e1dc83987..ee8e183f6 100755
--- a/cli/export-sqlite-for-user.php
+++ b/cli/export-sqlite-for-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = [
'user:',
diff --git a/cli/export-zip-for-user.php b/cli/export-zip-for-user.php
index dedcb6c11..5458784bf 100755
--- a/cli/export-zip-for-user.php
+++ b/cli/export-zip-for-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
diff --git a/cli/i18n/I18nData.php b/cli/i18n/I18nData.php
index 6e87e1d7e..f6bc7fb5d 100644
--- a/cli/i18n/I18nData.php
+++ b/cli/i18n/I18nData.php
@@ -330,7 +330,7 @@ class I18nData {
}
private function getFilenamePrefix(string $key): string {
- return preg_replace('/\..*/', '.php', $key);
+ return preg_replace('/\..*/', '.php', $key) ?? '';
}
}
diff --git a/cli/i18n/I18nValue.php b/cli/i18n/I18nValue.php
index 22317e1ae..88d0ea494 100644
--- a/cli/i18n/I18nValue.php
+++ b/cli/i18n/I18nValue.php
@@ -21,7 +21,7 @@ class I18nValue {
}
$data = explode(' -> ', $data);
- $this->value = array_shift($data);
+ $this->value = (string)(array_shift($data) ?? '');
if (count($data) === 0) {
return;
}
diff --git a/cli/import-for-user.php b/cli/import-for-user.php
index 212be7653..b4731b13b 100755
--- a/cli/import-for-user.php
+++ b/cli/import-for-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = array(
'user:',
diff --git a/cli/import-sqlite-for-user.php b/cli/import-sqlite-for-user.php
index 62a9d86c4..b61a73523 100755
--- a/cli/import-sqlite-for-user.php
+++ b/cli/import-sqlite-for-user.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
require(__DIR__ . '/_cli.php');
-performRequirementCheck(FreshRSS_Context::$system_conf->db['type'] ?? '');
+performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? '');
$params = [
'user:',
diff --git a/cli/list-users.php b/cli/list-users.php
index 276239b25..f9e63f4f6 100755
--- a/cli/list-users.php
+++ b/cli/list-users.php
@@ -5,9 +5,9 @@ require(__DIR__ . '/_cli.php');
$users = listUsers();
sort($users);
-if (FreshRSS_Context::$system_conf->default_user !== ''
- && in_array(FreshRSS_Context::$system_conf->default_user, $users, true)) {
- array_unshift($users, FreshRSS_Context::$system_conf->default_user);
+if (FreshRSS_Context::systemConf()->default_user !== ''
+ && in_array(FreshRSS_Context::systemConf()->default_user, $users, true)) {
+ array_unshift($users, FreshRSS_Context::systemConf()->default_user);
$users = array_unique($users);
}
diff --git a/cli/reconfigure.php b/cli/reconfigure.php
index 7d502a17a..84cb42d60 100755
--- a/cli/reconfigure.php
+++ b/cli/reconfigure.php
@@ -41,10 +41,56 @@ fwrite(STDERR, 'Reconfiguring FreshRSS…' . "\n");
foreach ($params as $param) {
$param = rtrim($param, ':');
if (isset($options[$param])) {
- FreshRSS_Context::$system_conf->$param = $options[$param] === false ? true : $options[$param];
+ switch ($param) {
+ case 'allow_anonymous_refresh':
+ FreshRSS_Context::systemConf()->allow_anonymous_refresh = true;
+ break;
+ case 'allow_anonymous':
+ FreshRSS_Context::systemConf()->allow_anonymous = true;
+ break;
+ case 'allow_robots':
+ FreshRSS_Context::systemConf()->allow_robots = true;
+ break;
+ case 'api_enabled':
+ FreshRSS_Context::systemConf()->api_enabled = true;
+ break;
+ case 'auth_type':
+ if (in_array($options[$param], ['form', 'http_auth', 'none'], true)) {
+ FreshRSS_Context::systemConf()->auth_type = $options[$param];
+ } else {
+ fail('FreshRSS invalid authentication method! auth_type must be one of { form, http_auth, none }');
+ }
+ break;
+ case 'base_url':
+ FreshRSS_Context::systemConf()->base_url = $options[$param];
+ break;
+ case 'default_user':
+ if (FreshRSS_user_Controller::checkUsername($options[$param])) {
+ FreshRSS_Context::systemConf()->default_user = $options[$param];
+ } else {
+ fail('FreshRSS invalid default username! default_user must be ASCII alphanumeric');
+ }
+ break;
+ case 'disable_update':
+ FreshRSS_Context::systemConf()->disable_update = true;
+ break;
+ case 'environment':
+ if (in_array($options[$param], ['development', 'production', 'silent'], true)) {
+ FreshRSS_Context::systemConf()->environment = $options[$param];
+ } else {
+ fail('FreshRSS invalid environment! environment must be one of { development, production, silent }');
+ }
+ break;
+ case 'language':
+ FreshRSS_Context::systemConf()->language = $options[$param];
+ break;
+ case 'title':
+ FreshRSS_Context::systemConf()->title = $options[$param];
+ break;
+ }
}
}
-$db = FreshRSS_Context::$system_conf->db;
+$db = FreshRSS_Context::systemConf()->db;
foreach ($dBparams as $dBparam) {
$dBparam = rtrim($dBparam, ':');
if (isset($options[$dBparam])) {
@@ -52,19 +98,10 @@ foreach ($dBparams as $dBparam) {
$db[$param] = $options[$dBparam];
}
}
-FreshRSS_Context::$system_conf->db = $db;
+/** @var array{'type':string,'host':string,'user':string,'password':string,'base':string,'prefix':string,
+ * 'connection_uri_params':string,'pdo_options':array<int,int|string|bool>} $db */
+FreshRSS_Context::systemConf()->db = $db;
-if (!FreshRSS_user_Controller::checkUsername(FreshRSS_Context::$system_conf->default_user)) {
- fail('FreshRSS invalid default username (must be ASCII alphanumeric): ' .
- FreshRSS_Context::$system_conf->default_user);
-}
-
-if (isset(FreshRSS_Context::$system_conf->auth_type) &&
- !in_array(FreshRSS_Context::$system_conf->auth_type, ['form', 'http_auth', 'none'], true)) {
- fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none }: '
- . FreshRSS_Context::$system_conf->auth_type);
-}
-
-FreshRSS_Context::$system_conf->save();
+FreshRSS_Context::systemConf()->save();
done();
diff --git a/cli/user-info.php b/cli/user-info.php
index f24f81078..fbf60482a 100755
--- a/cli/user-info.php
+++ b/cli/user-info.php
@@ -19,8 +19,10 @@ if (!validateOptions($argv, $params)) {
if (empty($options['user'])) {
$users = listUsers();
} elseif (is_array($options['user'])) {
+ /** @var array<string> $users */
$users = $options['user'];
} else {
+ /** @var array<string> $users */
$users = array($options['user']);
}
@@ -67,10 +69,10 @@ foreach ($users as $username) {
$feedList = $feedDAO->listFeedsIds();
$data = array(
- 'default' => $username === FreshRSS_Context::$system_conf->default_user ? '*' : '',
+ 'default' => $username === FreshRSS_Context::systemConf()->default_user ? '*' : '',
'user' => $username,
- 'admin' => FreshRSS_Context::$user_conf->is_admin ? '*' : '',
- 'enabled' => FreshRSS_Context::$user_conf->enabled ? '*' : '',
+ 'admin' => FreshRSS_Context::userConf()->is_admin ? '*' : '',
+ 'enabled' => FreshRSS_Context::userConf()->enabled ? '*' : '',
'last_user_activity' => FreshRSS_UserDAO::mtime($username),
'database_size' => $databaseDAO->size(),
'categories' => $catDAO->count(),
@@ -79,8 +81,8 @@ foreach ($users as $username) {
'unreads' => (int)$nbEntries['unread'],
'favourites' => (int)$nbFavorites['all'],
'tags' => $tagDAO->count(),
- 'lang' => FreshRSS_Context::$user_conf->language,
- 'mail_login' => FreshRSS_Context::$user_conf->mail_login,
+ 'lang' => FreshRSS_Context::userConf()->language,
+ 'mail_login' => FreshRSS_Context::userConf()->mail_login,
);
if (isset($options['h'])) { //Human format
$data['last_user_activity'] = date('c', $data['last_user_activity']);
diff --git a/composer.json b/composer.json
index 5ca412826..e1c96e3c6 100644
--- a/composer.json
+++ b/composer.json
@@ -61,7 +61,7 @@
"phpcs": "phpcs . -s",
"phpcbf": "phpcbf . -p -s",
"phpstan": "phpstan analyse --memory-limit 512M .",
- "phpstan-next": "phpstan analyse --level 8 --memory-limit 512M $(find . -type d -name 'vendor' -prune -o -name '*.php' -o -name '*.phtml' | grep -Fxvf ./tests/phpstan-next.txt | sort | paste -s -)",
+ "phpstan-next": "phpstan analyse --level 9 --memory-limit 512M $(find . -type d -name 'vendor' -prune -o -name '*.php' -o -name '*.phtml' | grep -Fxvf ./tests/phpstan-next.txt | sort | paste -s -)",
"phpunit": "phpunit --bootstrap ./tests/bootstrap.php --verbose ./tests",
"translations": "cli/manipulate.translation.php -a format",
"test": [
diff --git a/composer.lock b/composer.lock
index 731faa89c..ef46040ff 100644
--- a/composer.lock
+++ b/composer.lock
@@ -138,16 +138,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v4.17.1",
+ "version": "v4.18.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
+ "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
- "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
+ "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
"shasum": ""
},
"require": {
@@ -188,9 +188,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
},
- "time": "2023-08-13T19:53:39+00:00"
+ "time": "2023-12-10T21:03:43+00:00"
},
{
"name": "phar-io/manifest",
@@ -305,16 +305,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.39",
+ "version": "1.10.50",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4"
+ "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4",
- "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
+ "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
"shasum": ""
},
"require": {
@@ -363,7 +363,7 @@
"type": "tidelift"
}
],
- "time": "2023-10-17T15:46:26+00:00"
+ "time": "2023-12-13T10:59:42+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
@@ -419,21 +419,21 @@
},
{
"name": "phpstan/phpstan-strict-rules",
- "version": "1.5.1",
+ "version": "1.5.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
- "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6"
+ "reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b21c03d4f6f3a446e4311155f4be9d65048218e6",
- "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6",
+ "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/7a50e9662ee9f3942e4aaaf3d603653f60282542",
+ "reference": "7a50e9662ee9f3942e4aaaf3d603653f60282542",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
- "phpstan/phpstan": "^1.10"
+ "phpstan/phpstan": "^1.10.34"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
@@ -462,9 +462,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
- "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.1"
+ "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.2"
},
- "time": "2023-03-29T14:47:40+00:00"
+ "time": "2023-10-30T14:35:06+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -787,16 +787,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.13",
+ "version": "9.6.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
+ "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
- "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1",
+ "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1",
"shasum": ""
},
"require": {
@@ -870,7 +870,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15"
},
"funding": [
{
@@ -886,7 +886,7 @@
"type": "tidelift"
}
],
- "time": "2023-09-19T05:39:22+00:00"
+ "time": "2023-12-01T16:55:19+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -1854,16 +1854,16 @@
},
{
"name": "squizlabs/php_codesniffer",
- "version": "3.7.2",
+ "version": "3.8.0",
"source": {
"type": "git",
- "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
+ "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
+ "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
- "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7",
+ "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7",
"shasum": ""
},
"require": {
@@ -1873,7 +1873,7 @@
"php": ">=5.4.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/phpcs",
@@ -1892,35 +1892,58 @@
"authors": [
{
"name": "Greg Sherwood",
- "role": "lead"
+ "role": "Former lead"
+ },
+ {
+ "name": "Juliette Reinders Folmer",
+ "role": "Current lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
- "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards",
"static analysis"
],
"support": {
- "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
- "source": "https://github.com/squizlabs/PHP_CodeSniffer",
- "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
+ "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
+ "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
+ "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
},
- "time": "2023-02-22T23:07:41+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/PHPCSStandards",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/jrfnl",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/php_codesniffer",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-12-08T12:32:31+00:00"
},
{
"name": "theseer/tokenizer",
- "version": "1.2.1",
+ "version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
+ "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
- "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
+ "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"shasum": ""
},
"require": {
@@ -1949,7 +1972,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
},
"funding": [
{
@@ -1957,7 +1980,7 @@
"type": "github"
}
],
- "time": "2021-07-28T10:34:58+00:00"
+ "time": "2023-11-20T00:12:19+00:00"
}
],
"aliases": [],
diff --git a/config-user.default.php b/config-user.default.php
index 733701a3a..7bf5485f1 100644
--- a/config-user.default.php
+++ b/config-user.default.php
@@ -121,5 +121,8 @@ return array (
),
'html5_notif_timeout' => 0,
'show_nav_buttons' => true,
- 'extensions_enabled' => array(),
+ # List of enabled FreshRSS extensions.
+ 'extensions_enabled' => [],
+ # Extensions configurations
+ 'extensions' => [],
);
diff --git a/config.default.php b/config.default.php
index f7c4e1315..872975546 100644
--- a/config.default.php
+++ b/config.default.php
@@ -190,6 +190,8 @@ return array(
# List of enabled FreshRSS extensions.
'extensions_enabled' => [
],
+ # Extensions configurations
+ 'extensions' => [],
# Disable self-update,
'disable_update' => false,
diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php
index 1aa4cae86..18fa6e7df 100644
--- a/lib/Minz/Configuration.php
+++ b/lib/Minz/Configuration.php
@@ -6,8 +6,8 @@ declare(strict_types=1);
* @property string $base_url
* @property array{'type':string,'host':string,'user':string,'password':string,'base':string,'prefix':string,
* 'connection_uri_params':string,'pdo_options':array<int,int|string|bool>} $db
- * @property-read string $disable_update
- * @property-read string $environment
+ * @property bool $disable_update
+ * @property string $environment
* @property array<string,bool> $extensions_enabled
* @property-read string $mailer
* @property-read array{'hostname':string,'host':string,'auth':bool,'username':string,'password':string,'secure':string,'port':int,'from':string} $smtp
diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php
index a8f883eb6..5386a64e7 100644
--- a/lib/Minz/Extension.php
+++ b/lib/Minz/Extension.php
@@ -19,8 +19,6 @@ abstract class Minz_Extension {
private $version;
/** @var 'system'|'user' */
private $type;
- /** @var string */
- private $config_key = 'extensions';
/** @var array<string,mixed>|null */
private $user_configuration;
/** @var array<string,mixed>|null */
@@ -175,8 +173,11 @@ abstract class Minz_Extension {
$mtime = @filemtime("{$this->path}/static/{$filename}");
} else {
$username = Minz_User::name();
- $path = USERS_PATH . "/{$username}/{$this->config_key}/{$this->getName()}/{$filename}";
- $file_name_url = urlencode("{$username}/{$this->config_key}/{$this->getName()}/{$filename}");
+ if ($username == null) {
+ return '';
+ }
+ $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}/{$filename}";
+ $file_name_url = urlencode("{$username}/extensions/{$this->getName()}/{$filename}");
$mtime = @filemtime($path);
}
@@ -224,8 +225,8 @@ abstract class Minz_Extension {
}
switch ($type) {
- case 'system': return FreshRSS_Context::$system_conf !== null;
- case 'user': return FreshRSS_Context::$user_conf !== null;
+ case 'system': return FreshRSS_Context::hasSystemConf();
+ case 'user': return FreshRSS_Context::hasUserConf();
}
}
@@ -233,50 +234,40 @@ abstract class Minz_Extension {
private function isExtensionConfigured(string $type): bool {
switch ($type) {
case 'user':
- $conf = FreshRSS_Context::$user_conf;
+ $conf = FreshRSS_Context::userConf();
break;
case 'system':
- $conf = FreshRSS_Context::$system_conf;
+ $conf = FreshRSS_Context::systemConf();
break;
+ default:
+ return false;
}
- if ($conf === null || !$conf->hasParam($this->config_key)) {
+ if (!$conf->hasParam('extensions')) {
return false;
}
- $extensions = $conf->{$this->config_key};
- return array_key_exists($this->getName(), $extensions);
- }
-
- /**
- * @phpstan-param 'system'|'user' $type
- * @return array<string,mixed>
- */
- private function getConfiguration(string $type): array {
- if (!$this->isConfigurationEnabled($type)) {
- return [];
- }
-
- if (!$this->isExtensionConfigured($type)) {
- return [];
- }
-
- $conf = "{$type}_conf";
- return FreshRSS_Context::$$conf->{$this->config_key}[$this->getName()];
+ return array_key_exists($this->getName(), $conf->extensions);
}
/**
* @return array<string,mixed>
*/
public final function getSystemConfiguration(): array {
- return $this->getConfiguration('system');
+ if ($this->isConfigurationEnabled('system') && $this->isExtensionConfigured('system')) {
+ return FreshRSS_Context::systemConf()->extensions[$this->getName()];
+ }
+ return [];
}
/**
* @return array<string,mixed>
*/
public final function getUserConfiguration(): array {
- return $this->getConfiguration('user');
+ if ($this->isConfigurationEnabled('user') && $this->isExtensionConfigured('user')) {
+ return FreshRSS_Context::userConf()->extensions[$this->getName()];
+ }
+ return [];
}
/**
@@ -314,17 +305,26 @@ abstract class Minz_Extension {
* @param array<string,mixed> $configuration
*/
private function setConfiguration(string $type, array $configuration): void {
- $conf = "{$type}_conf";
+ switch ($type) {
+ case 'system':
+ $conf = FreshRSS_Context::systemConf();
+ break;
+ case 'user':
+ $conf = FreshRSS_Context::userConf();
+ break;
+ default:
+ return;
+ }
- if (FreshRSS_Context::$$conf->hasParam($this->config_key)) {
- $extensions = FreshRSS_Context::$$conf->{$this->config_key};
+ if ($conf->hasParam('extensions')) {
+ $extensions = $conf->extensions;
} else {
$extensions = [];
}
$extensions[$this->getName()] = $configuration;
- FreshRSS_Context::$$conf->{$this->config_key} = $extensions;
- FreshRSS_Context::$$conf->save();
+ $conf->extensions = $extensions;
+ $conf->save();
}
/** @param array<string,mixed> $configuration */
@@ -341,23 +341,28 @@ abstract class Minz_Extension {
/** @phpstan-param 'system'|'user' $type */
private function removeConfiguration(string $type): void {
- if (!$this->isConfigurationEnabled($type)) {
+ if (!$this->isConfigurationEnabled($type) || !$this->isExtensionConfigured($type)) {
return;
}
- if (!$this->isExtensionConfigured($type)) {
- return;
+ switch ($type) {
+ case 'system':
+ $conf = FreshRSS_Context::systemConf();
+ break;
+ case 'user':
+ $conf = FreshRSS_Context::userConf();
+ break;
+ default:
+ return;
}
- $conf = "{$type}_conf";
- $extensions = FreshRSS_Context::$$conf->{$this->config_key};
+ $extensions = $conf->extensions;
unset($extensions[$this->getName()]);
if (empty($extensions)) {
- $extensions = null;
+ $extensions = [];
}
-
- FreshRSS_Context::$$conf->{$this->config_key} = $extensions;
- FreshRSS_Context::$$conf->save();
+ $conf->extensions = $extensions;
+ $conf->save();
}
public final function removeSystemConfiguration(): void {
@@ -372,7 +377,7 @@ abstract class Minz_Extension {
public final function saveFile(string $filename, string $content): void {
$username = Minz_User::name();
- $path = USERS_PATH . "/{$username}/{$this->config_key}/{$this->getName()}";
+ $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}";
if (!file_exists($path)) {
mkdir($path, 0777, true);
@@ -383,7 +388,10 @@ abstract class Minz_Extension {
public final function removeFile(string $filename): void {
$username = Minz_User::name();
- $path = USERS_PATH . "/{$username}/{$this->config_key}/{$this->getName()}/{$filename}";
+ if ($username == null) {
+ return;
+ }
+ $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}/{$filename}";
if (file_exists($path)) {
unlink($path);
diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php
index e1443b9c3..9d8b94cbd 100644
--- a/lib/Minz/ExtensionManager.php
+++ b/lib/Minz/ExtensionManager.php
@@ -147,7 +147,7 @@ final class Minz_ExtensionManager {
$meta_raw_content = file_get_contents($metadata_filename) ?: '';
/** @var array{'name':string,'entrypoint':string,'path':string,'author'?:string,'description'?:string,'version'?:string,'type'?:'system'|'user'}|null $meta_json */
$meta_json = json_decode($meta_raw_content, true);
- if (!$meta_json || !self::isValidMetadata($meta_json)) {
+ if (!is_array($meta_json) || !self::isValidMetadata($meta_json)) {
// metadata.json is not a json file? Invalid!
// or metadata.json is invalid (no required information), invalid!
Minz_Log::warning('`' . $metadata_filename . '` is not a valid metadata file');
@@ -347,9 +347,9 @@ final class Minz_ExtensionManager {
call_user_func($function, ...$args);
}
} elseif ($signature === 'NoneToString') {
- return self::callNoneToString($hook_name);
+ return self::callHookString($hook_name);
} elseif ($signature === 'NoneToNone') {
- self::callNoneToNone($hook_name);
+ self::callHookVoid($hook_name);
}
return;
}
@@ -391,9 +391,9 @@ final class Minz_ExtensionManager {
* @param string $hook_name is the hook to call.
* @return string concatenated result of the call to all the hooks.
*/
- private static function callNoneToString(string $hook_name): string {
+ public static function callHookString(string $hook_name): string {
$result = '';
- foreach (self::$hook_list[$hook_name]['list'] as $function) {
+ foreach (self::$hook_list[$hook_name]['list'] ?? [] as $function) {
$result = $result . call_user_func($function);
}
return $result;
@@ -407,8 +407,8 @@ final class Minz_ExtensionManager {
*
* @param string $hook_name is the hook to call.
*/
- private static function callNoneToNone(string $hook_name): void {
- foreach (self::$hook_list[$hook_name]['list'] as $function) {
+ public static function callHookVoid(string $hook_name): void {
+ foreach (self::$hook_list[$hook_name]['list'] ?? [] as $function) {
call_user_func($function);
}
}
diff --git a/lib/Minz/Helper.php b/lib/Minz/Helper.php
index 642b9304c..04539ec40 100644
--- a/lib/Minz/Helper.php
+++ b/lib/Minz/Helper.php
@@ -19,12 +19,12 @@ class Minz_Helper {
* @phpstan-param T $var
* @phpstan-return T
*
- * @param string|array<string> $var
- * @return string|array<string>
+ * @param string|array<mixed> $var
+ * @return string|array<mixed>
*/
public static function htmlspecialchars_utf8($var) {
if (is_array($var)) {
- return array_map(array('Minz_Helper', 'htmlspecialchars_utf8'), $var);
+ return array_map(['Minz_Helper', 'htmlspecialchars_utf8'], $var);
} elseif (is_string($var)) {
return htmlspecialchars($var, ENT_COMPAT, 'UTF-8');
} else {
diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php
index 69b2357d2..b107d3df9 100644
--- a/lib/Minz/ModelPdo.php
+++ b/lib/Minz/ModelPdo.php
@@ -129,7 +129,7 @@ class Minz_ModelPdo {
$db = Minz_Configuration::get('system')->db;
throw new Minz_PDOConnectionException(
- $ex->getMessage(),
+ $ex === null ? '' : $ex->getMessage(),
$db['user'], Minz_Exception::ERROR
);
}
diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php
index 0ac1a9fe3..f39982be1 100644
--- a/lib/Minz/Request.php
+++ b/lib/Minz/Request.php
@@ -58,7 +58,7 @@ class Minz_Request {
}
}
- /** @return array<string|int,string|array<string,string>> */
+ /** @return array<string|int,string|array<string,string|int>> */
public static function paramArray(string $key, bool $specialchars = false): array {
if (empty(self::$params[$key]) || !is_array(self::$params[$key])) {
return [];
@@ -89,8 +89,8 @@ class Minz_Request {
}
public static function paramInt(string $key): int {
- if (!empty(self::$params[$key])) {
- return intval(self::$params[$key]);
+ if (!empty(self::$params[$key]) && is_numeric(self::$params[$key])) {
+ return (int)self::$params[$key];
}
return 0;
}
@@ -119,7 +119,7 @@ class Minz_Request {
* @return array<string>
*/
public static function paramTextToArray(string $key, array $default = []): array {
- if (isset(self::$params[$key])) {
+ if (isset(self::$params[$key]) && is_string(self::$params[$key])) {
return preg_split('/\R/', self::$params[$key]) ?: [];
}
return $default;
@@ -431,7 +431,7 @@ class Minz_Request {
if ($ORIGINAL_INPUT == false) {
return;
}
- if (null === $json = json_decode($ORIGINAL_INPUT, true)) {
+ if (!is_array($json = json_decode($ORIGINAL_INPUT, true))) {
return;
}
diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php
index 4553d3083..99b7fef45 100644
--- a/lib/Minz/Session.php
+++ b/lib/Minz/Session.php
@@ -159,7 +159,7 @@ class Minz_Session {
* @param bool $force if false, does not clear the language parameter
*/
public static function unset_session(bool $force = false): void {
- $language = self::param('language');
+ $language = self::paramString('language');
if (!self::$volatile) {
session_destroy();
diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php
index 8f2e2527a..183fa48ca 100644
--- a/lib/Minz/Translate.php
+++ b/lib/Minz/Translate.php
@@ -186,7 +186,7 @@ class Minz_Translate {
/**
* Translate a key into its corresponding value based on selected language.
* @param string $key the key to translate.
- * @param mixed ...$args additional parameters for variable keys.
+ * @param bool|float|int|string ...$args additional parameters for variable keys.
* @return string value corresponding to the key.
* If no value is found, return the key itself.
*/
@@ -211,6 +211,9 @@ class Minz_Translate {
// Go through the i18n keys to get the correct translation value.
$translates = self::$translates[$top_level];
+ if (!is_array($translates)) {
+ $translates = [];
+ }
$size_group = count($group);
$level_processed = 0;
$translation_value = $key;
@@ -253,7 +256,7 @@ class Minz_Translate {
/**
* Alias for Minz_Translate::t()
* @param string $key
- * @param mixed ...$args
+ * @param bool|float|int|string ...$args
*/
function _t(string $key, ...$args): string {
return Minz_Translate::t($key, ...$args);
diff --git a/lib/Minz/Url.php b/lib/Minz/Url.php
index 0c17e3ec7..2104759cd 100644
--- a/lib/Minz/Url.php
+++ b/lib/Minz/Url.php
@@ -72,7 +72,7 @@ class Minz_Url {
$and = '&';
}
- if (!empty($url['params']['#'])) {
+ if (!empty($url['params']) && is_array($url['params']) && !empty($url['params']['#'])) {
$anchor = '#' . ($encodage === 'html' ? htmlspecialchars($url['params']['#'], ENT_QUOTES, 'UTF-8') : $url['params']['#']);
unset($url['params']['#']);
}
@@ -89,7 +89,7 @@ class Minz_Url {
$separator = $and;
}
- if (isset($url['params'])) {
+ if (isset($url['params']) && is_array($url['params'])) {
unset($url['params']['c']);
unset($url['params']['a']);
foreach ($url['params'] as $key => $param) {
@@ -101,7 +101,7 @@ class Minz_Url {
}
}
- if (!empty($url['#'])) {
+ if (!empty($url['#']) && is_string($url['#'])) {
$uri .= '#' . ($encodage === 'html' ? htmlspecialchars($url['#'], ENT_QUOTES, 'UTF-8') : $url['#']);
}
@@ -141,7 +141,9 @@ class Minz_Url {
*/
public static function unserialize(string $url = ''): array {
try {
- return json_decode(base64_decode($url, true) ?: '', true, JSON_THROW_ON_ERROR) ?? [];
+ $result = json_decode(base64_decode($url, true) ?: '', true, JSON_THROW_ON_ERROR) ?? [];
+ /** @var array{'c'?:string,'a'?:string,'params'?:array<string,mixed>} $result */
+ return $result;
} catch (\Throwable $exception) {
return [];
}
diff --git a/lib/Minz/View.php b/lib/Minz/View.php
index f67cf6277..c215ecdab 100644
--- a/lib/Minz/View.php
+++ b/lib/Minz/View.php
@@ -345,6 +345,8 @@ class Minz_View {
public function attributeParams(): void {
foreach (Minz_View::$params as $key => $value) {
+ // TODO: Do not use variable variable (noVariableVariables)
+ /** @phpstan-ignore-next-line */
$this->$key = $value;
}
}
diff --git a/lib/favicons.php b/lib/favicons.php
index 5cf4295f5..df893b309 100644
--- a/lib/favicons.php
+++ b/lib/favicons.php
@@ -45,9 +45,8 @@ function downloadHttp(string &$url, array $curlOptions = []): string {
]);
FreshRSS_Context::initSystem();
- $system_conf = FreshRSS_Context::$system_conf;
- if (isset($system_conf)) {
- curl_setopt_array($ch, $system_conf->curl_options);
+ if (FreshRSS_Context::hasSystemConf()) {
+ curl_setopt_array($ch, FreshRSS_Context::systemConf()->curl_options);
}
curl_setopt_array($ch, $curlOptions);
diff --git a/lib/lib_install.php b/lib/lib_install.php
index 720c4bf77..f36d2eaa6 100644
--- a/lib/lib_install.php
+++ b/lib/lib_install.php
@@ -77,13 +77,12 @@ function generateSalt(): string {
}
function initDb(): string {
- $conf = FreshRSS_Context::$system_conf;
- $db = $conf->db;
+ $db = FreshRSS_Context::systemConf()->db;
if (empty($db['pdo_options'])) {
$db['pdo_options'] = [];
}
$db['pdo_options'][PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
- $conf->db = $db; //TODO: Remove this Minz limitation "Indirect modification of overloaded property"
+ FreshRSS_Context::systemConf()->db = $db; //TODO: Remove this Minz limitation "Indirect modification of overloaded property"
if (empty($db['type'])) {
$db['type'] = 'sqlite';
@@ -95,7 +94,7 @@ function initDb(): string {
$dbBase = $db['base'] ?? '';
//For first connection, use default database for PostgreSQL, empty database for MySQL / MariaDB:
$db['base'] = $db['type'] === 'pgsql' ? 'postgres' : '';
- $conf->db = $db;
+ FreshRSS_Context::systemConf()->db = $db;
try {
//First connection without database name to create the database
$databaseDAO = FreshRSS_Factory::createDatabaseDAO();
@@ -104,7 +103,7 @@ function initDb(): string {
}
//Restore final database parameters for auto-creation and for future connections
$db['base'] = $dbBase;
- $conf->db = $db;
+ FreshRSS_Context::systemConf()->db = $db;
if ($databaseDAO != null) {
//Perform database auto-creation
$databaseDAO->create();
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index 0ab49e25e..e01e8fa81 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -249,22 +249,19 @@ function sensitive_log($log) {
* @throws FreshRSS_Context_Exception
*/
function customSimplePie(array $attributes = array()): SimplePie {
- if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
- }
- $limits = FreshRSS_Context::$system_conf->limits;
+ $limits = FreshRSS_Context::systemConf()->limits;
$simplePie = new SimplePie();
$simplePie->set_useragent(FRESHRSS_USERAGENT);
- $simplePie->set_syslog(FreshRSS_Context::$system_conf->simplepie_syslog_enabled);
+ $simplePie->set_syslog(FreshRSS_Context::systemConf()->simplepie_syslog_enabled);
$simplePie->set_cache_name_function('sha1');
$simplePie->set_cache_location(CACHE_PATH);
$simplePie->set_cache_duration($limits['cache_duration']);
$simplePie->enable_order_by_date(false);
- $feed_timeout = empty($attributes['timeout']) ? 0 : (int)$attributes['timeout'];
+ $feed_timeout = empty($attributes['timeout']) || !is_numeric($attributes['timeout']) ? 0 : (int)$attributes['timeout'];
$simplePie->set_timeout($feed_timeout > 0 ? $feed_timeout : $limits['timeout']);
- $curl_options = FreshRSS_Context::$system_conf->curl_options;
+ $curl_options = FreshRSS_Context::systemConf()->curl_options;
if (isset($attributes['ssl_verify'])) {
$curl_options[CURLOPT_SSL_VERIFYHOST] = $attributes['ssl_verify'] ? 2 : 0;
$curl_options[CURLOPT_SSL_VERIFYPEER] = (bool)$attributes['ssl_verify'];
@@ -408,11 +405,8 @@ function enforceHttpEncoding(string $html, string $contentType = ''): string {
* @param array<string,mixed> $attributes
*/
function httpGet(string $url, string $cachePath, string $type = 'html', array $attributes = []): string {
- if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
- }
- $limits = FreshRSS_Context::$system_conf->limits;
- $feed_timeout = empty($attributes['timeout']) ? 0 : intval($attributes['timeout']);
+ $limits = FreshRSS_Context::systemConf()->limits;
+ $feed_timeout = empty($attributes['timeout']) || !is_numeric($attributes['timeout']) ? 0 : intval($attributes['timeout']);
$cacheMtime = @filemtime($cachePath);
if ($cacheMtime !== false && $cacheMtime > time() - intval($limits['cache_duration'])) {
@@ -427,7 +421,7 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a
cleanCache(CLEANCACHE_HOURS);
}
- if (FreshRSS_Context::$system_conf->simplepie_syslog_enabled) {
+ if (FreshRSS_Context::systemConf()->simplepie_syslog_enabled) {
syslog(LOG_INFO, 'FreshRSS GET ' . $type . ' ' . SimplePie_Misc::url_remove_credentials($url));
}
@@ -462,7 +456,7 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a
CURLOPT_ENCODING => '', //Enable all encodings
]);
- curl_setopt_array($ch, FreshRSS_Context::$system_conf->curl_options);
+ curl_setopt_array($ch, FreshRSS_Context::systemConf()->curl_options);
if (isset($attributes['curl_params']) && is_array($attributes['curl_params'])) {
curl_setopt_array($ch, $attributes['curl_params']);
@@ -571,10 +565,7 @@ function listUsers(): array {
* @return bool true if number of users >= max registrations, false else.
*/
function max_registrations_reached(): bool {
- if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
- }
- $limit_registrations = FreshRSS_Context::$system_conf->limits['max_registrations'];
+ $limit_registrations = FreshRSS_Context::systemConf()->limits['max_registrations'];
$number_accounts = count(listUsers());
return $limit_registrations > 0 && $number_accounts >= $limit_registrations;
@@ -671,10 +662,10 @@ function connectionRemoteAddress(): string {
* Check if the client (e.g. last proxy) is allowed to send unsafe headers.
* This uses the `TRUSTED_PROXY` environment variable or the `trusted_sources` configuration option to get an array of the authorized ranges,
* The connection IP is obtained from the `CONN_REMOTE_ADDR` (if available, to be robust even when using Apache mod_remoteip) or `REMOTE_ADDR` environment variables.
- * @return bool, true if the sender’s IP is in one of the ranges defined in the configuration, else false
+ * @return bool true if the sender’s IP is in one of the ranges defined in the configuration, else false
*/
function checkTrustedIP(): bool {
- if (FreshRSS_Context::$system_conf === null) {
+ if (!FreshRSS_Context::hasSystemConf()) {
return false;
}
$remoteIp = connectionRemoteAddress();
@@ -686,7 +677,7 @@ function checkTrustedIP(): bool {
$trusted = preg_split('/\s+/', $trusted, -1, PREG_SPLIT_NO_EMPTY);
}
if (!is_array($trusted) || empty($trusted)) {
- $trusted = FreshRSS_Context::$system_conf->trusted_sources;
+ $trusted = FreshRSS_Context::systemConf()->trusted_sources;
}
foreach ($trusted as $cidr) {
if (checkCIDR($remoteIp, $cidr)) {
diff --git a/p/api/fever.php b/p/api/fever.php
index cc5778e9f..8cf3dfc21 100644
--- a/p/api/fever.php
+++ b/p/api/fever.php
@@ -19,7 +19,7 @@ require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader
FreshRSS_Context::initSystem();
// check if API is enabled globally
-if (FreshRSS_Context::$system_conf == null || !FreshRSS_Context::$system_conf->api_enabled) {
+if (!FreshRSS_Context::hasSystemConf() || !FreshRSS_Context::systemConf()->api_enabled) {
Minz_Log::warning('Fever API: service unavailable!');
Minz_Log::debug('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG);
header('HTTP/1.1 503 Service Unavailable');
@@ -149,20 +149,17 @@ final class FeverAPI
* your FreshRSS "username:your-api-password" combination
*/
private function authenticate(): bool {
- if (FreshRSS_Context::$system_conf === null) {
- throw new FreshRSS_Context_Exception('System configuration not initialised!');
- }
- FreshRSS_Context::$user_conf = null;
+ FreshRSS_Context::clearUserConf();
Minz_User::change();
$feverKey = empty($_POST['api_key']) ? '' : substr(trim($_POST['api_key']), 0, 128);
if (ctype_xdigit($feverKey)) {
$feverKey = strtolower($feverKey);
- $username = @file_get_contents(DATA_PATH . '/fever/.key-' . sha1(FreshRSS_Context::$system_conf->salt) . '-' . $feverKey . '.txt', false);
+ $username = @file_get_contents(DATA_PATH . '/fever/.key-' . sha1(FreshRSS_Context::systemConf()->salt) . '-' . $feverKey . '.txt', false);
if ($username != false) {
$username = trim($username);
- FreshRSS_Context::$user_conf = FreshRSS_Context::initUser($username); // Assignment to help PHPStan
- if (FreshRSS_Context::$user_conf != null && $feverKey === FreshRSS_Context::$user_conf->feverKey && FreshRSS_Context::$user_conf->enabled) {
- Minz_Translate::init(FreshRSS_Context::$user_conf->language);
+ FreshRSS_Context::initUser($username);
+ if ($feverKey === FreshRSS_Context::userConf()->feverKey && FreshRSS_Context::userConf()->enabled) {
+ Minz_Translate::init(FreshRSS_Context::userConf()->language);
$this->entryDAO = FreshRSS_Factory::createEntryDao();
$this->feedDAO = FreshRSS_Factory::createFeedDao();
return true;
@@ -180,7 +177,7 @@ final class FeverAPI
public function isAuthenticatedApiUser(): bool {
$this->authenticate();
- return FreshRSS_Context::$user_conf !== null;
+ return FreshRSS_Context::hasUserConf();
}
/**
@@ -350,11 +347,11 @@ final class FeverAPI
/** @return array<array<string,int|string>> */
private function getFavicons(): array {
- if (FreshRSS_Context::$system_conf == null) {
+ if (!FreshRSS_Context::hasSystemConf()) {
return [];
}
$favicons = array();
- $salt = FreshRSS_Context::$system_conf->salt;
+ $salt = FreshRSS_Context::systemConf()->salt;
$myFeeds = $this->feedDAO->listFeeds();
foreach ($myFeeds as $feed) {
diff --git a/p/api/greader.php b/p/api/greader.php
index 91a7b5d13..5f351195c 100644
--- a/p/api/greader.php
+++ b/p/api/greader.php
@@ -179,15 +179,15 @@ final class GReaderAPI {
$user = $headerAuthX[0];
if (FreshRSS_user_Controller::checkUsername($user)) {
FreshRSS_Context::initUser($user);
- if (FreshRSS_Context::$user_conf == null || FreshRSS_Context::$system_conf == null) {
+ if (!FreshRSS_Context::hasUserConf() || !FreshRSS_Context::hasSystemConf()) {
Minz_Log::warning('Invalid API user ' . $user . ': configuration cannot be found.');
self::unauthorized();
}
- if (!FreshRSS_Context::$user_conf->enabled) {
+ if (!FreshRSS_Context::userConf()->enabled) {
Minz_Log::warning('Invalid API user ' . $user . ': configuration cannot be found.');
self::unauthorized();
}
- if ($headerAuthX[1] === sha1(FreshRSS_Context::$system_conf->salt . $user . FreshRSS_Context::$user_conf->apiPasswordHash)) {
+ if ($headerAuthX[1] === sha1(FreshRSS_Context::systemConf()->salt . $user . FreshRSS_Context::userConf()->apiPasswordHash)) {
return $user;
} else {
Minz_Log::warning('Invalid API authorisation for user ' . $user);
@@ -206,14 +206,14 @@ final class GReaderAPI {
//https://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html
if (FreshRSS_user_Controller::checkUsername($email)) {
FreshRSS_Context::initUser($email);
- if (FreshRSS_Context::$user_conf == null || FreshRSS_Context::$system_conf == null) {
+ if (!FreshRSS_Context::hasUserConf() || !FreshRSS_Context::hasSystemConf()) {
Minz_Log::warning('Invalid API user ' . $email . ': configuration cannot be found.');
self::unauthorized();
}
- if (FreshRSS_Context::$user_conf->apiPasswordHash != '' && password_verify($pass, FreshRSS_Context::$user_conf->apiPasswordHash)) {
+ if (FreshRSS_Context::userConf()->apiPasswordHash != '' && password_verify($pass, FreshRSS_Context::userConf()->apiPasswordHash)) {
header('Content-Type: text/plain; charset=UTF-8');
- $auth = $email . '/' . sha1(FreshRSS_Context::$system_conf->salt . $email . FreshRSS_Context::$user_conf->apiPasswordHash);
+ $auth = $email . '/' . sha1(FreshRSS_Context::systemConf()->salt . $email . FreshRSS_Context::userConf()->apiPasswordHash);
echo 'SID=', $auth, "\n",
'LSID=null', "\n", //Vienna RSS
'Auth=', $auth, "\n";
@@ -234,11 +234,11 @@ final class GReaderAPI {
//http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/
//https://github.com/ericmann/gReader-Library/blob/master/greader.class.php
$user = Minz_User::name();
- if ($user === null || $conf === null || FreshRSS_Context::$system_conf === null) {
+ if ($user === null || $conf === null || !FreshRSS_Context::hasSystemConf()) {
self::unauthorized();
}
//Minz_Log::debug('token('. $user . ')', API_LOG); //TODO: Implement real token that expires
- $token = str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters
+ $token = str_pad(sha1(FreshRSS_Context::systemConf()->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters
echo $token, "\n";
exit();
}
@@ -246,7 +246,7 @@ final class GReaderAPI {
private static function checkToken(?FreshRSS_UserConfiguration $conf, string $token): bool {
//http://code.google.com/p/google-reader-api/wiki/ActionToken
$user = Minz_User::name();
- if ($user === null || $conf === null || FreshRSS_Context::$system_conf === null) {
+ if ($user === null || $conf === null || !FreshRSS_Context::hasSystemConf()) {
self::unauthorized();
}
if ($user !== Minz_User::INTERNAL_USER && ( //TODO: Check security consequences
@@ -254,7 +254,7 @@ final class GReaderAPI {
$token === 'x')) { //Reeder
return true;
}
- if ($token === str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) {
+ if ($token === str_pad(sha1(FreshRSS_Context::systemConf()->salt . $user . $conf->apiPasswordHash), 57, 'Z')) {
return true;
}
Minz_Log::warning('Invalid POST token: ' . $token, API_LOG);
@@ -264,7 +264,7 @@ final class GReaderAPI {
/** @return never */
private static function userInfo() {
//https://github.com/theoldreader/api#user-info
- if (FreshRSS_Context::$user_conf == null) {
+ if (!FreshRSS_Context::hasUserConf()) {
self::unauthorized();
}
$user = Minz_User::name();
@@ -272,7 +272,7 @@ final class GReaderAPI {
'userId' => $user,
'userName' => $user,
'userProfileId' => $user,
- 'userEmail' => FreshRSS_Context::$user_conf->mail_login,
+ 'userEmail' => FreshRSS_Context::userConf()->mail_login,
), JSON_OPTIONS));
}
@@ -340,11 +340,11 @@ final class GReaderAPI {
/** @return never */
private static function subscriptionList() {
- if (FreshRSS_Context::$system_conf == null) {
+ if (!FreshRSS_Context::hasSystemConf()) {
self::internalServerError();
}
header('Content-Type: application/json; charset=UTF-8');
- $salt = FreshRSS_Context::$system_conf->salt;
+ $salt = FreshRSS_Context::systemConf()->salt;
$faviconsUrl = Minz_Url::display('/f.php?', '', true);
$faviconsUrl = str_replace('/api/greader.php/reader/api/0/subscription', '', $faviconsUrl); //Security if base_url is not set properly
$subscriptions = array();
@@ -1003,7 +1003,7 @@ final class GReaderAPI {
//Minz_Log::debug('----------------------------------------------------------------', API_LOG);
//Minz_Log::debug(debugInfo(), API_LOG);
- if (FreshRSS_Context::$system_conf == null || !FreshRSS_Context::$system_conf->api_enabled) {
+ if (!FreshRSS_Context::hasSystemConf() || !FreshRSS_Context::systemConf()->api_enabled) {
self::serviceUnavailable();
} elseif ($pathInfos[1] === 'check' && $pathInfos[2] === 'compatibility') {
self::checkCompatibility();
@@ -1014,10 +1014,10 @@ final class GReaderAPI {
if ($pathInfos[1] !== 'accounts') {
self::authorizationToUser();
}
- if (FreshRSS_Context::$user_conf != null) {
- Minz_Translate::init(FreshRSS_Context::$user_conf->language);
+ if (FreshRSS_Context::hasUserConf()) {
+ Minz_Translate::init(FreshRSS_Context::userConf()->language);
Minz_ExtensionManager::init();
- Minz_ExtensionManager::enableByList(FreshRSS_Context::$user_conf->extensions_enabled, 'user');
+ Minz_ExtensionManager::enableByList(FreshRSS_Context::userConf()->extensions_enabled, 'user');
} else {
Minz_Translate::init();
}
@@ -1163,7 +1163,7 @@ final class GReaderAPI {
// Always exits
case 'edit-tag': //http://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3/
$token = isset($_POST['T']) ? trim($_POST['T']) : '';
- self::checkToken(FreshRSS_Context::$user_conf, $token);
+ self::checkToken(FreshRSS_Context::userConf(), $token);
$a = $_POST['a'] ?? ''; //Add: user/-/state/com.google/read user/-/state/com.google/starred
$r = $_POST['r'] ?? ''; //Remove: user/-/state/com.google/read user/-/state/com.google/starred
$e_ids = multiplePosts('i'); //item IDs
@@ -1171,14 +1171,14 @@ final class GReaderAPI {
// Always exits
case 'rename-tag': //https://github.com/theoldreader/api
$token = isset($_POST['T']) ? trim($_POST['T']) : '';
- self::checkToken(FreshRSS_Context::$user_conf, $token);
+ self::checkToken(FreshRSS_Context::userConf(), $token);
$s = $_POST['s'] ?? ''; //user/-/label/Folder
$dest = $_POST['dest'] ?? ''; //user/-/label/NewFolder
self::renameTag($s, $dest);
// Always exits
case 'disable-tag': //https://github.com/theoldreader/api
$token = isset($_POST['T']) ? trim($_POST['T']) : '';
- self::checkToken(FreshRSS_Context::$user_conf, $token);
+ self::checkToken(FreshRSS_Context::userConf(), $token);
$s_s = multiplePosts('s');
foreach ($s_s as $s) {
self::disableTag($s); //user/-/label/Folder
@@ -1186,7 +1186,7 @@ final class GReaderAPI {
// Always exits
case 'mark-all-as-read':
$token = isset($_POST['T']) ? trim($_POST['T']) : '';
- self::checkToken(FreshRSS_Context::$user_conf, $token);
+ self::checkToken(FreshRSS_Context::userConf(), $token);
$streamId = trim($_POST['s'] ?? '');
$ts = trim($_POST['ts'] ?? '0'); //Older than timestamp in nanoseconds
if (!ctype_digit($ts)) {
@@ -1195,7 +1195,7 @@ final class GReaderAPI {
self::markAllAsRead($streamId, $ts);
// Always exits
case 'token':
- self::token(FreshRSS_Context::$user_conf);
+ self::token(FreshRSS_Context::userConf());
// Always exits
case 'user-info':
self::userInfo();
diff --git a/p/api/pshb.php b/p/api/pshb.php
index d48ece0aa..b4d553430 100644
--- a/p/api/pshb.php
+++ b/p/api/pshb.php
@@ -11,11 +11,11 @@ header('X-Content-Type-Options: nosniff');
$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, MAX_PAYLOAD) ?: '';
FreshRSS_Context::initSystem();
-if (FreshRSS_Context::$system_conf == null) {
+if (!FreshRSS_Context::hasSystemConf()) {
header('HTTP/1.1 500 Internal Server Error');
die('Invalid system init!');
}
-FreshRSS_Context::$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!)
+FreshRSS_Context::systemConf()->auth_type = 'none'; // avoid necessity to be logged in (not saved!)
//Minz_Log::debug(print_r(array('_SERVER' => $_SERVER, '_GET' => $_GET, '_POST' => $_POST, 'INPUT' => $ORIGINAL_INPUT), true), PSHB_LOG);
@@ -126,12 +126,12 @@ foreach ($users as $userFilename) {
try {
FreshRSS_Context::initUser($username);
- if (FreshRSS_Context::$user_conf == null || !FreshRSS_Context::$user_conf->enabled) {
+ if (!FreshRSS_Context::hasUserConf() || !FreshRSS_Context::userConf()->enabled) {
Minz_Log::warning('FreshRSS skip disabled user ' . $username);
continue;
}
- Minz_ExtensionManager::enableByList(FreshRSS_Context::$user_conf->extensions_enabled, 'user');
- Minz_Translate::reset(FreshRSS_Context::$user_conf->language);
+ Minz_ExtensionManager::enableByList(FreshRSS_Context::userConf()->extensions_enabled, 'user');
+ Minz_Translate::reset(FreshRSS_Context::userConf()->language);
[$updated_feeds, , $nb_new_articles] = FreshRSS_feed_Controller::actualizeFeeds(null, $self, null, $simplePie);
if ($nb_new_articles > 0) {
diff --git a/p/ext.php b/p/ext.php
index 788488b27..379dfc35b 100644
--- a/p/ext.php
+++ b/p/ext.php
@@ -95,8 +95,8 @@ function sendNotFoundResponse() {
die();
}
-if (!isset($_GET['f']) ||
- !isset($_GET['t'])) {
+if (!isset($_GET['f']) || !is_string($_GET['f']) ||
+ !isset($_GET['t']) || !is_string($_GET['t'])) {
sendBadRequestResponse('Query string is incomplete.');
}
diff --git a/phpstan.neon b/phpstan.neon
index e262ad984..2335f6ac9 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,7 +1,6 @@
parameters:
# TODO: Increase rule-level https://phpstan.org/user-guide/rule-levels
- level: 7
- treatPhpDocTypesAsCertain: false
+ level: 8
fileExtensions:
- php
- phtml
@@ -36,6 +35,7 @@ parameters:
- TMP_PATH
- USERS_PATH
reportMaybesInPropertyPhpDocTypes: false
+ treatPhpDocTypesAsCertain: false
strictRules:
allRules: false
booleansInConditions: false # TODO pass
@@ -43,14 +43,17 @@ parameters:
disallowedConstructs: false
disallowedLooseComparison: false
matchingInheritedMethodNames: true
- noVariableVariables: false # TODO pass
+ noVariableVariables: true
numericOperandsInArithmeticOperators: true
overwriteVariablesWithLoop: true
requireParentConstructorCall: true
strictCalls: true
switchConditionsMatchingType: true
uselessCast: true
+ ignoreErrors:
+ # - '#Only booleans are allowed in (a negated boolean|a ternary operator condition|an elseif condition|an if condition|&&|\|\|), (bool|false|int(<[0-9, max]+>)?|true|null|\|)+ given.*#'
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
+ # - vendor/phpstan/phpstan/conf/bleedingEdge.neon
diff --git a/tests/phpstan-next.txt b/tests/phpstan-next.txt
index f1d6be340..8e28e66a8 100644
--- a/tests/phpstan-next.txt
+++ b/tests/phpstan-next.txt
@@ -1,73 +1,15 @@
-# List of files, which are not yet passing PHPStan level 8 https://phpstan.org/user-guide/rule-levels
+# List of files, which are not yet passing PHPStan level 9 https://phpstan.org/user-guide/rule-levels
# Used for automated tests to avoid regressions in files already passing that level.
# Can be regenerated with something like:
-# find . -type d -name 'vendor' -prune -o -name '*.php' -exec sh -c 'vendor/bin/phpstan analyse --level 8 --memory-limit 512M {} >/dev/null 2>/dev/null || echo {}' \;
+# find . -type d -name 'vendor' -prune -o -name '*.php' -exec sh -c 'vendor/bin/phpstan analyse --level 9 --memory-limit 512M {} >/dev/null 2>/dev/null || echo {}' \;
-./app/Controllers/apiController.php
-./app/Controllers/authController.php
-./app/Controllers/categoryController.php
./app/Controllers/configureController.php
-./app/Controllers/feedController.php
./app/Controllers/importExportController.php
-./app/Controllers/indexController.php
-./app/Controllers/javascriptController.php
-./app/Controllers/tagController.php
-./app/Controllers/updateController.php
-./app/Controllers/userController.php
-./app/install.php
-./app/layout/aside_configure.phtml
-./app/layout/aside_feed.phtml
-./app/layout/header.phtml
-./app/layout/layout.phtml
-./app/layout/nav_menu.phtml
-./app/layout/simple.phtml
-./app/Mailers/UserMailer.php
-./app/Models/Auth.php
-./app/Models/BooleanSearch.php
-./app/Models/Context.php
./app/Models/DatabaseDAO.php
-./app/Models/DatabaseDAOPGSQL.php
./app/Models/Entry.php
./app/Models/Feed.php
-./app/Models/FeedDAO.php
-./app/Models/FormAuth.php
-./app/Models/StatsDAO.php
./app/Services/ImportService.php
-./app/views/auth/index.phtml
./app/views/configure/archiving.phtml
-./app/views/configure/display.phtml
-./app/views/configure/integration.phtml
-./app/views/configure/reading.phtml
-./app/views/configure/shortcut.phtml
-./app/views/configure/system.phtml
-./app/views/feed/contentSelectorPreview.phtml
-./app/views/helpers/category/update.phtml
-./app/views/helpers/configure/query.phtml
-./app/views/helpers/export/opml.phtml
-./app/views/helpers/extension/configure.phtml
-./app/views/helpers/extension/details.phtml
./app/views/helpers/feed/update.phtml
-./app/views/helpers/index/normal/entry_bottom.phtml
-./app/views/helpers/index/normal/entry_header.phtml
-./app/views/helpers/javascript_vars.phtml
-./app/views/helpers/stream-footer.phtml
-./app/views/index/about.phtml
-./app/views/index/global.phtml
-./app/views/index/normal.phtml
-./app/views/index/reader.phtml
-./app/views/stats/idle.phtml
-./app/views/subscription/index.phtml
-./app/views/user/manage.phtml
-./app/views/user/profile.phtml
-./app/views/user/validateEmail.phtml
-./cli/_cli.php
-./cli/create-user.php
-./cli/delete-user.php
-./cli/do-install.php
-./cli/i18n/I18nData.php
-./cli/i18n/I18nValue.php
-./cli/list-users.php
-./cli/reconfigure.php
-./cli/user-info.php
-./lib/lib_install.php
-./lib/Minz/ModelPdo.php
+./lib/Minz/Helper.php
+./lib/Minz/Request.php