Require PHP 7.4+ (#5720)

* Require PHP 7.4+
https://github.com/FreshRSS/FreshRSS/discussions/5474

* Update Docker oldest
Alpine 3.13 with PHP 7.4.26

* Add missing packets to Docker oldest

* Update to typed properties
https://php.net/migration74.new-features#migration74.new-features.core.typed-properties

* More types
This commit is contained in:
Alexandre Alapetite 2023-10-30 20:47:27 +01:00 committed by GitHub
parent 4a02352ccc
commit 06d0099504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 364 additions and 624 deletions

View File

@ -1,4 +1,4 @@
FROM alpine:3.8
FROM alpine:3.13
ENV TZ UTC
SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
@ -7,7 +7,7 @@ RUN apk add --no-cache \
tzdata \
apache2 php7-apache2 \
php7 php7-curl php7-gmp php7-intl php7-mbstring php7-xml php7-zip \
php7-ctype php7-dom php7-iconv php7-json php7-opcache php7-openssl php7-phar php7-session php7-xmlreader php7-xml php7-zlib \
php7-ctype php7-dom php7-iconv php7-json php7-opcache php7-openssl php7-phar php7-session php7-simplexml php7-xmlreader php7-xmlwriter php7-xml php7-tokenizer php7-zlib \
php7-pdo_sqlite php7-pdo_mysql php7-pdo_pgsql
RUN mkdir -p /var/www/FreshRSS /run/apache2/

View File

@ -58,7 +58,7 @@ FreshRSS nest fourni avec aucune garantie.
* Serveur modeste, par exemple sous Linux ou Windows
* Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles)
* Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres)
* PHP 7.2+
* PHP 7.4+
* Requis : [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/session), [ctype](https://www.php.net/ctype), et [PDO_MySQL](https://www.php.net/pdo-mysql) ou [PDO_SQLite](https://www.php.net/pdo-sqlite) ou [PDO_PGSQL](https://www.php.net/pdo-pgsql)
* Recommandés : [GMP](https://www.php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](https://www.php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](https://www.php.net/mbstring) (pour le texte Unicode), [iconv](https://www.php.net/iconv) (pour conversion dencodages), [ZIP](https://www.php.net/zip) (pour import/export), [zlib](https://www.php.net/zlib) (pour les flux compressés)
* MySQL 5.5.3+ ou équivalent MariaDB, ou SQLite 3.7.4+, ou PostgreSQL 9.5+

View File

@ -58,7 +58,7 @@ FreshRSS comes with absolutely no warranty.
* Light server running Linux or Windows
* It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles)
* A web server: Apache2 (recommended), nginx, lighttpd (not tested on others)
* PHP 7.2+
* PHP 7.4+
* Required extensions: [cURL](https://www.php.net/curl), [DOM](https://www.php.net/dom), [JSON](https://www.php.net/json), [XML](https://www.php.net/xml), [session](https://www.php.net/session), [ctype](https://www.php.net/ctype), and [PDO_MySQL](https://www.php.net/pdo-mysql) or [PDO_SQLite](https://www.php.net/pdo-sqlite) or [PDO_PGSQL](https://www.php.net/pdo-pgsql)
* Recommended extensions: [GMP](https://www.php.net/gmp) (for API access on 32-bit platforms), [IDN](https://www.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://www.php.net/mbstring) (for Unicode strings), [iconv](https://www.php.net/iconv) (for charset conversion), [ZIP](https://www.php.net/zip) (for import/export), [zlib](https://www.php.net/zlib) (for compressed feeds)
* MySQL 5.5.3+ or MariaDB equivalent, or SQLite 3.7.4+, or PostgreSQL 9.5+

View File

@ -7,9 +7,8 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController {
/**
* JavaScript request or not.
* @var bool
*/
private $ajax = false;
private bool $ajax = false;
/**
* This action is called before every other action in that class. It is

View File

@ -5,11 +5,9 @@
*/
class FreshRSS_importExport_Controller extends FreshRSS_ActionController {
/** @var FreshRSS_EntryDAO */
private $entryDAO;
private FreshRSS_EntryDAO $entryDAO;
/** @var FreshRSS_FeedDAO */
private $feedDAO;
private FreshRSS_FeedDAO $feedDAO;
/**
* This action is called before every other action in that class. It is

View File

@ -7,9 +7,8 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
/**
* JavaScript request or not.
* @var bool|mixed
*/
private $ajax = false;
private bool $ajax = false;
/**
* This action is called before every other action in that class. It is

View File

@ -2,8 +2,7 @@
class FreshRSS_AlreadySubscribed_Exception extends Exception {
/** @var string */
private $feedName = '';
private string $feedName = '';
public function __construct(string $url, string $feedName) {
parent::__construct('Already subscribed! ' . $url, 2135);

View File

@ -2,8 +2,7 @@
class FreshRSS_FeedNotAdded_Exception extends Exception {
/** @var string */
private $url = '';
private string $url = '';
public function __construct(string $url) {
parent::__construct('Feed not added! ' . $url, 2147);

View File

@ -2,8 +2,7 @@
class FreshRSS_Zip_Exception extends Exception {
/** @var int */
private $zipErrorCode = 0;
private int $zipErrorCode = 0;
public function __construct(int $zipErrorCode) {
parent::__construct('ZIP error!', 2141);

View File

@ -9,8 +9,7 @@ class FreshRSS_Auth {
*/
public const DEFAULT_COOKIE_DURATION = 7776000;
/** @var bool */
private static $login_ok = false;
private static bool $login_ok = false;
/**
* This method initializes authentication system.

View File

@ -5,16 +5,14 @@
*/
class FreshRSS_BooleanSearch {
/** @var string */
private $raw_input = '';
private string $raw_input = '';
/** @var array<FreshRSS_BooleanSearch|FreshRSS_Search> */
private $searches = [];
private array $searches = [];
/**
* @phpstan-var 'AND'|'OR'|'AND NOT'
* @var string
*/
private $operator;
private string $operator;
/** @param 'AND'|'OR'|'AND NOT' $operator */
public function __construct(string $input, int $level = 0, string $operator = 'AND') {

View File

@ -12,26 +12,19 @@ class FreshRSS_Category extends Minz_Model {
*/
public const KIND_DYNAMIC_OPML = 2;
/** @var int */
private $id = 0;
/** @var int */
private $kind = 0;
/** @var string */
private $name;
/** @var int */
private $nbFeeds = -1;
/** @var int */
private $nbNotRead = -1;
private int $id = 0;
private int $kind = 0;
private string $name;
private int $nbFeeds = -1;
private int $nbNotRead = -1;
/** @var array<FreshRSS_Feed>|null */
private $feeds;
private ?array $feeds = null;
/** @var bool|int */
private $hasFeedsWithError = false;
/** @var array<string,mixed> */
private $attributes = [];
/** @var int */
private $lastUpdate = 0;
/** @var bool */
private $error = false;
private array $attributes = [];
private int $lastUpdate = 0;
private bool $error = false;
/**
* @param array<FreshRSS_Feed>|null $feeds

View File

@ -6,50 +6,31 @@
*/
final class FreshRSS_Context {
/**
* @var FreshRSS_UserConfiguration|null
*/
public static $user_conf;
/**
* @var FreshRSS_SystemConfiguration|null
*/
public static $system_conf;
public static ?FreshRSS_UserConfiguration $user_conf = null;
public static ?FreshRSS_SystemConfiguration $system_conf = null;
/**
* @var array<int,FreshRSS_Category>
*/
public static $categories = [];
public static array $categories = [];
/**
* @var array<int,FreshRSS_Tag>
*/
public static $tags = [];
/**
* @var string
*/
public static $name = '';
/**
* @var string
*/
public static $description = '';
/**
* @var int
*/
public static $total_unread = 0;
public static array $tags = [];
public static string $name = '';
public static string $description = '';
public static int $total_unread = 0;
/** @var array{'all':int,'read':int,'unread':int} */
public static $total_starred = [
public static array $total_starred = [
'all' => 0,
'read' => 0,
'unread' => 0,
];
/**
* @var int
*/
public static $get_unread = 0;
public static int $get_unread = 0;
/** @var array{'all':bool,'starred':bool,'feed':int|false,'category':int|false,'tag':int|false,'tags':bool} */
public static $current_get = [
public static array $current_get = [
'all' => false,
'starred' => false,
'feed' => false,
@ -58,45 +39,19 @@ final class FreshRSS_Context {
'tags' => false,
];
/**
* @var string
*/
public static $next_get = 'a';
/**
* @var int
*/
public static $state = 0;
public static string $next_get = 'a';
public static int $state = 0;
/**
* @phpstan-var 'ASC'|'DESC'
* @var string
*/
public static $order = 'DESC';
/**
* @var int
*/
public static $number = 0;
/** @var FreshRSS_BooleanSearch */
public static $search;
/**
* @var string
*/
public static $first_id = '';
/**
* @var string
*/
public static $next_id = '';
/**
* @var string
*/
public static $id_max = '';
/**
* @var int
*/
public static $sinceHours = 0;
/**
* @var bool
*/
public static $isCli = false;
public static string $order = 'DESC';
public static int $number = 0;
public static FreshRSS_BooleanSearch $search;
public static string $first_id = '';
public static string $next_id = '';
public static string $id_max = '';
public static int $sinceHours = 0;
public static bool $isCli = false;
/**
* Initialize the context for the global system.

View File

@ -7,38 +7,26 @@ class FreshRSS_Entry extends Minz_Model {
public const STATE_FAVORITE = 4;
public const STATE_NOT_FAVORITE = 8;
/** @var string */
private $id = '0';
/** @var string */
private $guid;
/** @var string */
private $title;
private string $id = '0';
private string $guid;
private string $title;
/** @var array<string> */
private $authors;
/** @var string */
private $content;
/** @var string */
private $link;
/** @var int */
private $date;
/** @var int */
private $lastSeen = 0;
/** @var string In microseconds */
private $date_added = '0';
/** @var string */
private $hash = '';
/** @var bool|null */
private $is_read;
/** @var bool|null */
private $is_favorite;
/** @var int */
private $feedId;
/** @var FreshRSS_Feed|null */
private $feed;
private array $authors;
private string $content;
private string $link;
private int $date;
private int $lastSeen = 0;
/** In microseconds */
private string $date_added = '0';
private string $hash = '';
private ?bool $is_read;
private ?bool $is_favorite;
private int $feedId;
private ?FreshRSS_Feed $feed;
/** @var array<string> */
private $tags = [];
private array $tags = [];
/** @var array<string,mixed> */
private $attributes = [];
private array $attributes = [];
/**
* @param int|string $pubdate

View File

@ -190,8 +190,7 @@ SQL;
return $result;
}
/** @var PDOStatement|null */
private $updateEntryPrepared = null;
private ?PDOStatement $updateEntryPrepared = null;
/** @param array{'id':string,'guid':string,'title':string,'author':string,'content':string,'link':string,'date':int,'lastSeen':int,'hash':string,
* 'is_read':bool|int|null,'is_favorite':bool|int|null,'id_feed':int,'tags':string,'attributes':array<string,mixed>} $valuesTmp */

View File

@ -37,54 +37,32 @@ class FreshRSS_Feed extends Minz_Model {
public const ARCHIVING_RETENTION_COUNT_LIMIT = 10000;
public const ARCHIVING_RETENTION_PERIOD = 'P3M';
/** @var int */
private $id = 0;
/** @var string */
private $url = '';
/** @var int */
private $kind = 0;
/** @var int */
private $categoryId = 1;
/** @var FreshRSS_Category|null */
private $category;
/** @var int */
private $nbEntries = -1;
/** @var int */
private $nbNotRead = -1;
/** @var int */
private $nbPendingNotRead = 0;
/** @var string */
private $name = '';
/** @var string */
private $website = '';
/** @var string */
private $description = '';
/** @var int */
private $lastUpdate = 0;
/** @var int */
private $priority = self::PRIORITY_MAIN_STREAM;
/** @var string */
private $pathEntries = '';
/** @var string */
private $httpAuth = '';
/** @var bool */
private $error = false;
/** @var int */
private $ttl = self::TTL_DEFAULT;
private int $id = 0;
private string $url = '';
private int $kind = 0;
private int $categoryId = 1;
private ?FreshRSS_Category $category;
private int $nbEntries = -1;
private int $nbNotRead = -1;
private int $nbPendingNotRead = 0;
private string $name = '';
private string $website = '';
private string $description = '';
private int $lastUpdate = 0;
private int $priority = self::PRIORITY_MAIN_STREAM;
private string $pathEntries = '';
private string $httpAuth = '';
private bool $error = false;
private int $ttl = self::TTL_DEFAULT;
/** @var array<string,mixed> */
private $attributes = [];
/** @var bool */
private $mute = false;
/** @var string */
private $hash = '';
/** @var string */
private $lockPath = '';
/** @var string */
private $hubUrl = '';
/** @var string */
private $selfUrl = '';
private array $attributes = [];
private bool $mute = false;
private string $hash = '';
private string $lockPath = '';
private string $hubUrl = '';
private string $selfUrl = '';
/** @var array<FreshRSS_FilterAction> $filterActions */
private $filterActions = null;
private array $filterActions = [];
public function __construct(string $url, bool $validate = true) {
if ($validate) {

View File

@ -2,10 +2,9 @@
class FreshRSS_FilterAction {
/** @var FreshRSS_BooleanSearch */
private $booleanSearch = null;
private FreshRSS_BooleanSearch $booleanSearch;
/** @var array<string>|null */
private $actions = null;
private ?array $actions = null;
/** @param array<string> $actions */
private function __construct(FreshRSS_BooleanSearch $booleanSearch, array $actions) {

View File

@ -3,12 +3,10 @@
declare(strict_types=1);
class FreshRSS_Log extends Minz_Model {
/** @var string */
private $date;
/** @var string */
private $level;
/** @var string */
private $information;
private string $date;
private string $level;
private string $information;
public function date(): string {
return $this->date;

View File

@ -5,24 +5,12 @@
*/
class FreshRSS_ReadingMode {
/**
* @var string
*/
protected $id;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $title;
protected string $id;
protected string $name;
protected string $title;
/** @var array{'c':string,'a':string,'params':array<string,mixed>} */
protected $urlParams;
/**
* @var bool
*/
protected $isActive = false;
protected array $urlParams;
protected bool $isActive = false;
/**
* ReadingMode constructor.

View File

@ -12,64 +12,63 @@ class FreshRSS_Search {
/**
* This contains the user input string
* @var string
*/
private $raw_input = '';
private string $raw_input = '';
// The following properties are extracted from the raw input
/** @var array<string>|null */
private $entry_ids;
private ?array $entry_ids = null;
/** @var array<int>|null */
private $feed_ids;
private ?array $feed_ids = null;
/** @var array<int>|'*'|null */
private $label_ids;
private $label_ids = null;
/** @var array<string>|null */
private $label_names;
private ?array $label_names = null;
/** @var array<string>|null */
private $intitle;
private ?array $intitle = null;
/** @var int|false|null */
private $min_date;
private $min_date = null;
/** @var int|false|null */
private $max_date;
private $max_date = null;
/** @var int|false|null */
private $min_pubdate;
private $min_pubdate = null;
/** @var int|false|null */
private $max_pubdate;
private $max_pubdate = null;
/** @var array<string>|null */
private $inurl;
private ?array $inurl = null;
/** @var array<string>|null */
private $author;
private ?array $author = null;
/** @var array<string>|null */
private $tags;
private ?array $tags = null;
/** @var array<string>|null */
private $search;
private ?array $search = null;
/** @var array<string>|null */
private $not_entry_ids;
private ?array $not_entry_ids = null;
/** @var array<int>|null */
private $not_feed_ids;
private ?array $not_feed_ids = null;
/** @var array<int>|'*'|null */
private $not_label_ids;
private $not_label_ids = null;
/** @var array<string>|null */
private $not_label_names;
private ?array $not_label_names = null;
/** @var array<string>|null */
private $not_intitle;
private ?array $not_intitle = null;
/** @var int|false|null */
private $not_min_date;
private $not_min_date = null;
/** @var int|false|null */
private $not_max_date;
private $not_max_date = null;
/** @var int|false|null */
private $not_min_pubdate;
private $not_min_pubdate = null;
/** @var int|false|null */
private $not_max_pubdate;
private $not_max_pubdate = null;
/** @var array<string>|null */
private $not_inurl;
private ?array $not_inurl = null;
/** @var array<string>|null */
private $not_author;
private ?array $not_author = null;
/** @var array<string>|null */
private $not_tags;
private ?array $not_tags = null;
/** @var array<string>|null */
private $not_search;
private ?array $not_search = null;
public function __construct(string $input) {
$input = self::cleanSearch($input);

View File

@ -8,7 +8,7 @@ class FreshRSS_Share {
* The list of available sharing options.
* @var array<string,FreshRSS_Share>
*/
private static $list_sharing = [];
private static array $list_sharing = [];
/**
* Register a new sharing option.
@ -71,45 +71,31 @@ class FreshRSS_Share {
}
/** @var string */
private $type;
/** @var string */
private $name;
/** @var string */
private $url_transform;
private string $type;
private string $name;
private string $url_transform;
/** @var array<callable>|array<string,array<callable>> */
private $transforms;
private array $transforms;
/**
* @phpstan-var 'simple'|'advanced'
* @var string
*/
private $form_type;
/** @var string */
private $help_url;
/** @var string|null */
private $custom_name = null;
/** @var string|null */
private $base_url = null;
/** @var string|null */
private $id = null;
/** @var string|null */
private $title = null;
/** @var string|null */
private $link = null;
/** @var bool */
private $isDeprecated;
private string $form_type;
private string $help_url;
private ?string $custom_name = null;
private ?string $base_url = null;
private ?string $id = null;
private ?string $title = null;
private ?string $link = null;
private bool $isDeprecated;
/**
* @phpstan-var 'GET'|'POST'
* @var string
*/
private $method;
/** @var string|null */
private $field;
private string $method;
private ?string $field;
/**
* @phpstan-var 'button'|null
* @var string
*/
private $HTMLtag;
private ?string $HTMLtag;
/**
* Create a FreshRSS_Share object.

View File

@ -1,26 +1,15 @@
<?php
class FreshRSS_Tag extends Minz_Model {
/**
* @var int
*/
private $id = 0;
/**
* @var string
*/
private $name;
private int $id = 0;
private string $name;
/**
* @var array<string,mixed>
*/
private $attributes = [];
/**
* @var int
*/
private $nbEntries = -1;
/**
* @var int
*/
private $nbUnread = -1;
private array $attributes = [];
private int $nbEntries = -1;
private int $nbUnread = -1;
public function __construct(string $name = '') {
$this->_name($name);

View File

@ -1,12 +1,10 @@
<?php
class FreshRSS_Themes extends Minz_Model {
/** @var string */
private static $themesUrl = '/themes/';
/** @var string */
private static $defaultIconsUrl = '/themes/icons/';
/** @var string */
public static $defaultTheme = 'Origine';
private static string $themesUrl = '/themes/';
private static string $defaultIconsUrl = '/themes/icons/';
public static string $defaultTheme = 'Origine';
/** @return array<string> */
public static function getList(): array {
@ -51,10 +49,9 @@ class FreshRSS_Themes extends Minz_Model {
return false;
}
/** @var string */
private static $themeIconsUrl;
private static string $themeIconsUrl;
/** @var array<string,int> */
private static $themeIcons;
private static array $themeIcons;
/**
* @return false|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}}

View File

@ -8,30 +8,18 @@
*/
class FreshRSS_UserQuery {
/** @var bool */
private $deprecated = false;
/** @var string */
private $get = '';
/** @var string */
private $get_name = '';
/** @var string */
private $get_type = '';
/** @var string */
private $name = '';
/** @var string */
private $order = '';
/** @var FreshRSS_BooleanSearch */
private $search;
/** @var int */
private $state = 0;
/** @var string */
private $url = '';
/** @var FreshRSS_FeedDAO|null */
private $feed_dao;
/** @var FreshRSS_CategoryDAO|null */
private $category_dao;
/** @var FreshRSS_TagDAO|null */
private $tag_dao;
private bool $deprecated = false;
private string $get = '';
private string $get_name = '';
private string $get_type = '';
private string $name = '';
private string $order = '';
private FreshRSS_BooleanSearch $search;
private int $state = 0;
private string $url = '';
private ?FreshRSS_FeedDAO $feed_dao;
private ?FreshRSS_CategoryDAO $category_dao;
private ?FreshRSS_TagDAO $tag_dao;
/**
* @param array{'get'?:string,'name'?:string,'order'?:string,'search'?:string,'state'?:int,'url'?:string} $query

View File

@ -10,166 +10,121 @@ class FreshRSS_View extends Minz_View {
/** @var callable */
public $callbackBeforePagination;
/** @var array<FreshRSS_Category> */
public $categories;
/** @var FreshRSS_Category|null */
public $category;
/** @var string */
public $current_user;
public array $categories;
public ?FreshRSS_Category $category;
public string $current_user;
/** @var iterable<FreshRSS_Entry> */
public $entries;
/** @var FreshRSS_Entry */
public $entry;
/** @var FreshRSS_Feed|null */
public $feed;
public FreshRSS_Entry $entry;
public ?FreshRSS_Feed $feed;
/** @var array<FreshRSS_Feed> */
public $feeds;
/** @var int */
public $nbUnreadTags;
public array $feeds;
public int $nbUnreadTags;
/** @var array<FreshRSS_Tag> */
public $tags;
public array $tags;
/** @var array<int,array{'id':int,'name':string,'id_entry':string,'checked':bool}> */
public $tagsForEntry;
public array $tagsForEntry;
/** @var array<string,array<string>> */
public $tagsForEntries;
public array $tagsForEntries;
/** @var array<string,string> */
public $notification;
/** @var bool */
public $excludeMutedFeeds;
public array $notification;
public bool $excludeMutedFeeds;
// Substriptions
/** @var FreshRSS_Category|null */
public $default_category;
/** @var bool */
public $displaySlider;
/** @var bool */
public $load_ok;
/** @var bool */
public $onlyFeedsWithError;
/** @var bool */
public $signalError;
public ?FreshRSS_Category $default_category;
public bool $displaySlider = false;
public bool $load_ok;
public bool $onlyFeedsWithError;
public bool $signalError;
// Manage users
/** @var array{'feed_count':int,'article_count':int,'database_size':int,'language':string,'mail_login':string,'enabled':bool,'is_admin':bool,'last_user_activity':string,'is_default':bool} */
public $details;
/** @var bool */
public $disable_aside;
/** @var bool */
public $show_email_field;
/** @var string */
public $username;
public array $details;
public bool $disable_aside;
public bool $show_email_field;
public string $username;
/** @var array<array{'language':string,'enabled':bool,'is_admin':bool,'enabled':bool,'article_count':int,'database_size':int,'last_user_activity':string,'mail_login':string,'feed_count':int,'is_default':bool}> */
public $users;
public array $users;
// Updates
/** @var string */
public $last_update_time;
public string $last_update_time;
/** @var array<string,bool> */
public $status_files;
public array $status_files;
/** @var array<string,bool> */
public $status_php;
/** @var bool */
public $update_to_apply;
public array $status_php;
public bool $update_to_apply;
/** @var array<string,bool> */
public $status_database;
/** @var bool */
public $is_release_channel_stable;
public array $status_database;
public bool $is_release_channel_stable;
// Archiving
/** @var int */
public $nb_total;
/** @var int */
public $size_total;
/** @var int */
public $size_user;
public int $nb_total;
public int $size_total;
public int $size_user;
// Display
/** @var array<string,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}}> */
public $themes;
public array $themes;
// Shortcuts
/** @var array<int, string> */
public $list_keys;
public array $list_keys;
// User queries
/** @var array<int,FreshRSS_UserQuery> */
public $queries;
public array $queries;
/** @var FreshRSS_UserQuery|null */
public $query;
public ?FreshRSS_UserQuery $query = null;
// Export / Import
/** @var string */
public $content;
public string $content;
/** @var array<string,array<string>> */
public $entryIdsTagNames;
/** @var string */
public $list_title;
/** @var int */
public $queryId;
/** @var string */
public $type;
public array $entryIdsTagNames;
public string $list_title;
public int $queryId;
public string $type;
// Form login
/** @var int */
public $cookie_days;
public int $cookie_days;
// Registration
/** @var bool */
public $can_register;
/** @var string */
public $preferred_language;
/** @var bool */
public $show_tos_checkbox;
/** @var string */
public $terms_of_service;
/** @var string */
public $site_title;
/** @var string */
public $validation_url;
public bool $can_register;
public string $preferred_language;
public bool $show_tos_checkbox;
public string $terms_of_service;
public string $site_title;
public string $validation_url;
// Logs
/** @var int */
public $currentPage;
/** @var Minz_Paginator */
public $logsPaginator;
/** @var int */
public $nbPage;
public int $currentPage;
public Minz_Paginator $logsPaginator;
public int $nbPage;
// RSS view
/** @var string */
public $rss_title = '';
/** @var string */
public $rss_url = '';
/** @var string */
public $rss_base = '';
/** @var bool */
public $internal_rendering = false;
public string $rss_title = '';
public string $rss_url = '';
public string $rss_base = '';
public bool $internal_rendering = false;
// Content preview
/** @var string */
public $fatalError;
/** @var string */
public $htmlContent;
/** @var bool */
public $selectorSuccess;
public string $fatalError;
public string $htmlContent;
public bool $selectorSuccess;
// Extensions
/** @var array<string,array{'name':string,'author':string,'description':string,'version':string,'entrypoint':string,'type':'system'|'user','url':string,'method':string,'directory':string}> */
public $available_extensions;
/** @var ?Minz_Extension */
public $ext_details;
public array $available_extensions;
public ?Minz_Extension $ext_details;
/** @var array{'system':array<Minz_Extension>,'user':array<Minz_Extension>} */
public $extension_list;
/** @var ?Minz_Extension */
public $extension;
public array $extension_list;
public ?Minz_Extension $extension;
/** @var array<string,string> */
public $extensions_installed;
public array $extensions_installed;
// Errors
/** @var string */
public $code;
/** @var string */
public $errorMessage;
public string $code;
public string $errorMessage;
/** @var array<string,string> */
public $message;
public array $message;
}

View File

@ -5,14 +5,12 @@ declare(strict_types=1);
final class FreshRSS_ViewJavascript extends FreshRSS_View {
/** @var array<FreshRSS_Category> */
public $categories;
public array $categories;
/** @var array<FreshRSS_Feed> */
public $feeds;
public array $feeds;
/** @var array<FreshRSS_Tag> */
public $tags;
public array $tags;
/** @var string */
public $nonce;
/** @var string */
public $salt1;
public string $nonce;
public string $salt1;
}

View File

@ -4,54 +4,47 @@ declare(strict_types=1);
final class FreshRSS_ViewStats extends FreshRSS_View {
/** @var FreshRSS_Category|null */
public $default_category;
public ?FreshRSS_Category $default_category;
/** @var array<FreshRSS_Category> */
public $categories;
/** @var FreshRSS_Feed|null */
public $feed;
public array $categories;
public ?FreshRSS_Feed $feed;
/** @var array<FreshRSS_Feed> */
public $feeds;
/** @var bool */
public $displaySlider;
public array $feeds;
public bool $displaySlider = false;
/** @var float */
public $average;
/** @var float */
public $averageDayOfWeek;
/** @var float */
public $averageHour;
/** @var float */
public $averageMonth;
public float $average;
public float $averageDayOfWeek;
public float $averageHour;
public float $averageMonth;
/** @var array<string> */
public $days;
public array $days;
/** @var array<string,array<int,int|string>> */
public $entryByCategory;
public array $entryByCategory;
/** @var array<int,int> */
public $entryCount;
public array $entryCount;
/** @var array<string,array<int,int|string>> */
public $feedByCategory;
public array $feedByCategory;
/** @var array<int, string> */
public $hours24Labels;
public array $hours24Labels;
/** @var array<string,array<int,array<string,int|string>>> */
public $idleFeeds;
public array $idleFeeds;
/** @var array<int,string> */
public $last30DaysLabel;
public array $last30DaysLabel;
/** @var array<int,string> */
public $last30DaysLabels;
public array $last30DaysLabels;
/** @var array<string,string> */
public $months;
public array $months;
/** @var array{'total':int,'count_unreads':int,'count_reads':int,'count_favorites':int}|false */
public $repartition;
/** @var array{'main_stream':array{'total':int,'count_unreads':int,'count_reads':int,'count_favorites':int}|false,'all_feeds':array{'total':int,'count_unreads':int,'count_reads':int,'count_favorites':int}|false} */
public $repartitions;
public array $repartitions;
/** @var array<int,int> */
public $repartitionDayOfWeek;
public array $repartitionDayOfWeek;
/** @var array<string,int>|array<int,int> */
public $repartitionHour;
public array $repartitionHour;
/** @var array<int,int> */
public $repartitionMonth;
public array $repartitionMonth;
/** @var array<array{'id':int,'name':string,'category':string,'count':int}> */
public $topFeed;
public array $topFeed;
}

View File

@ -4,20 +4,16 @@
* Provide useful methods to generate files to export.
*/
class FreshRSS_Export_Service {
/** @var string */
private $username;
/** @var FreshRSS_CategoryDAO */
private $category_dao;
private string $username;
/** @var FreshRSS_FeedDAO */
private $feed_dao;
private FreshRSS_CategoryDAO $category_dao;
/** @var FreshRSS_EntryDAO */
private $entry_dao;
private FreshRSS_FeedDAO $feed_dao;
/** @var FreshRSS_TagDAO */
private $tag_dao;
private FreshRSS_EntryDAO $entry_dao;
private FreshRSS_TagDAO $tag_dao;
public const FRSS_NAMESPACE = 'https://freshrss.org/opml';
public const TYPE_HTML_XPATH = 'HTML+XPath';

View File

@ -4,14 +4,13 @@
* Provide methods to import files.
*/
class FreshRSS_Import_Service {
/** @var FreshRSS_CategoryDAO */
private $catDAO;
/** @var FreshRSS_FeedDAO */
private $feedDAO;
private FreshRSS_CategoryDAO $catDAO;
/** @var bool true if success, false otherwise */
private $lastStatus;
private FreshRSS_FeedDAO $feedDAO;
/** true if success, false otherwise */
private bool $lastStatus;
/**
* Initialize the service for the given user.

View File

@ -5,15 +5,12 @@ require_once __DIR__ . '/I18nValidatorInterface.php';
class I18nCompletionValidator implements I18nValidatorInterface {
/** @var array<string,array<string,I18nValue>> */
private $reference;
private array $reference;
/** @var array<string,array<string,I18nValue>> */
private $language;
/** @var int */
private $totalEntries = 0;
/** @var int */
private $passEntries = 0;
/** @var string */
private $result = '';
private array $language;
private int $totalEntries = 0;
private int $passEntries = 0;
private string $result = '';
/**
* @param array<string,array<string,I18nValue>> $reference

View File

@ -5,7 +5,7 @@ class I18nData {
public const REFERENCE_LANGUAGE = 'en';
/** @var array<string,array<string,array<string,I18nValue>>> */
private $data;
private array $data;
/** @param array<string,array<string,array<string,I18nValue>>> $data */
public function __construct(array $data) {

View File

@ -5,15 +5,12 @@ require_once __DIR__ . '/I18nValidatorInterface.php';
class I18nUsageValidator implements I18nValidatorInterface {
/** @var array<string> */
private $code;
private array $code;
/** @var array<string,array<string,string>> */
private $reference;
/** @var int */
private $totalEntries = 0;
/** @var int */
private $failedEntries = 0;
/** @var string */
private $result = '';
private array $reference;
private int $totalEntries = 0;
private int $failedEntries = 0;
private string $result = '';
/**
* @param array<string,array<string,string>> $reference

View File

@ -10,10 +10,8 @@ class I18nValue {
self::STATE_TODO,
];
/** @var string */
private $value;
/** @var string|null */
private $state;
private string $value;
private ?string $state = null;
public function __construct(string $data) {
$data = explode(' -> ', $data);

View File

@ -17,7 +17,7 @@
"WebSub"
],
"require": {
"php": ">=7.2",
"php": ">=7.4",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",

4
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "280bec285929f5841748be3d4e256011",
"content-hash": "1f09a030b755d6dd8104c9f7a5035f47",
"packages": [],
"packages-dev": [
{
@ -1966,7 +1966,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.2",
"php": ">=7.4",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",

View File

@ -2,7 +2,7 @@
//NB: Do not edit; use ./constants.local.php instead.
//<Not customisable>
const FRESHRSS_MIN_PHP_VERSION = '7.2.0';
const FRESHRSS_MIN_PHP_VERSION = '7.4.0';
const FRESHRSS_VERSION = '1.22.2-dev';
const FRESHRSS_WEBSITE = 'https://freshrss.org';
const FRESHRSS_WIKI = 'https://freshrss.github.io/FreshRSS/';

View File

@ -7,7 +7,7 @@ You need to verify that your server can run FreshRSS before installing it. If yo
| Software | Recommended | Also Works With |
| ------------- | ----------------------- | ----------------------- |
| Web server | **Apache 2** | Nginx, lighttpd |
| PHP | **PHP 7.2+** | |
| PHP | **PHP 7.4+** | |
| PHP modules | Required: libxml, cURL, JSON, PDO_MySQL, PCRE and ctype.<br />Required (32-bit only): GMP <br />Recommended: Zlib, mbstring, iconv, ZipArchive<br />*For the whole modules list see [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L7-L9)* | |
| Database | **MySQL 5.5.3+** | SQLite 3.7.4+, PostgreSQL 9.5+ |
| Browser | **Firefox** | Chrome, Opera, Safari, or Edge |

View File

@ -95,7 +95,7 @@ server {
# php files handling
# this regex is mandatory because of the API
location ~ ^.+?\.php(/.*)?$ {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
# By default, the variable PATH_INFO is not set under PHP-FPM
# But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var!

View File

@ -7,7 +7,7 @@ Il est toutefois de votre responsabilité de vérifier que votre hébergement pe
| Logiciel | Recommandé | Fonctionne aussi avec |
| -------- | ----------- | --------------------- |
| Serveur web | **Apache 2** | Nginx |
| PHP | **PHP 7.2+** | |
| PHP | **PHP 7.4+** | |
| Modules PHP | Requis : libxml, cURL, JSON, PDO_MySQL, PCRE et ctype<br />Requis (32 bits seulement) : GMP<br />Recommandé : Zlib, mbstring et iconv, ZipArchive<br />*Pour une liste complète des modules nécessaires voir le [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/edge/Docker/Dockerfile-Alpine#L7-L9)* | |
| Base de données | **MySQL 5.5.3+** | SQLite 3.7.4+, PostgreSQL 9.5+ |
| Navigateur | **Firefox** | Chrome, Opera, Safari, or Edge |
@ -115,7 +115,7 @@ server {
# gestion des fichiers php
# il est nécessaire dutiliser cette expression régulière pour le bon fonctionnement de lAPI
location ~ ^.+?\.php(/.*)?$ {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
# Par défaut la variable PATH_INFO nest pas définie sous PHP-FPM
# or lAPI FreshRSS greader.php en a besoin. Si vous avez un “Bad Request”, vérifiez bien cette dernière !

View File

@ -10,12 +10,12 @@
class Minz_ActionController {
/** @var array<string,string> */
private static $csp_default = [
private static array $csp_default = [
'default-src' => "'self'",
];
/** @var array<string,string> */
private $csp_policies;
private array $csp_policies;
/** @var Minz_View */
protected $view;
@ -25,7 +25,7 @@ class Minz_ActionController {
* @var class-string
* @deprecated Use constructor with view type instead
*/
public static $defaultViewType = Minz_View::class;
public static string $defaultViewType = Minz_View::class;
/**
* @phpstan-param class-string|'' $viewType

View File

@ -17,7 +17,7 @@ class Minz_Configuration {
* The list of configurations.
* @var array<string,static>
*/
private static $config_list = array();
private static array $config_list = array();
/**
* Add a new configuration to the list of configuration.
@ -72,31 +72,28 @@ class Minz_Configuration {
* Unused.
* @phpstan-ignore-next-line
*/
private $namespace = '';
private string $namespace = '';
/**
* The filename for the current configuration.
* @var string
*/
private $config_filename = '';
private string $config_filename = '';
/**
* The filename for the current default values, null by default.
* @var string|null
*/
private $default_filename = null;
private ?string $default_filename = null;
/**
* The configuration values, an empty array by default.
* @var array<string,mixed>
*/
private $data = array();
private array $data = [];
/**
* An object which help to set good values in configuration.
* @var Minz_ConfigurationSetterInterface|null
*/
private $configuration_setter;
private ?Minz_ConfigurationSetterInterface $configuration_setter = null;
/**
* Create a new Minz_Configuration object.

View File

@ -12,15 +12,12 @@ class Minz_Dispatcher {
/**
* Singleton
* @var Minz_Dispatcher|null
*/
private static $instance;
/** @var bool */
private static $needsReset;
private static ?Minz_Dispatcher $instance = null;
private static bool $needsReset;
/** @var array<string,string> */
private static $registrations = [];
/** @var Minz_ActionController */
private $controller;
private static array $registrations = [];
private Minz_ActionController $controller;
/**
* Retrieves the Dispatcher instance

View File

@ -26,10 +26,10 @@ abstract class Minz_Extension {
private $system_configuration;
/** @var array{0:'system',1:'user'} */
public static $authorized_types = array(
public static array $authorized_types = [
'system',
'user',
);
];
/** @var bool */
private $is_enabled;

View File

@ -6,22 +6,21 @@
* @todo see coding style for methods!!
*/
final class Minz_ExtensionManager {
/** @var string */
private static $ext_metaname = 'metadata.json';
/** @var string */
private static $ext_entry_point = 'extension.php';
private static string $ext_metaname = 'metadata.json';
private static string $ext_entry_point = 'extension.php';
/** @var array<string,Minz_Extension> */
private static $ext_list = array();
private static array $ext_list = [];
/** @var array<string,Minz_Extension> */
private static $ext_list_enabled = array();
private static array $ext_list_enabled = [];
/** @var array<string,bool> */
private static $ext_auto_enabled = array();
private static array $ext_auto_enabled = [];
/**
* List of available hooks. Please keep this list sorted.
* @var array<string,array{'list':array<callable>,'signature':'NoneToNone'|'NoneToString'|'OneToOne'|'PassArguments'}>
*/
private static $hook_list = array(
private static array $hook_list = [
'check_url_before_add' => array( // function($url) -> Url | null
'list' => array(),
'signature' => 'OneToOne',
@ -90,7 +89,7 @@ final class Minz_ExtensionManager {
'list' => array(),
'signature' => 'PassArguments',
),
);
];
/** Remove extensions and hooks from a previous initialisation */
private static function reset(): void {

View File

@ -25,8 +25,7 @@
*/
class Minz_FrontController {
/** @var Minz_Dispatcher */
protected $dispatcher;
protected Minz_Dispatcher $dispatcher;
/**
* Constructeur

View File

@ -32,12 +32,10 @@ class Minz_Mailer {
*/
protected $view;
/** @var string */
private $mailer;
private string $mailer;
/** @var array{'hostname':string,'host':string,'auth':bool,'username':string,'password':string,'secure':string,'port':int,'from':string} */
private $smtp_config;
/** @var int */
private $debug_level;
private array $smtp_config;
private int $debug_level;
/**
* Constructor.

View File

@ -9,11 +9,11 @@
*/
class Minz_Migrator
{
/** @var string[] */
private $applied_versions;
/** @var array<string> */
private array $applied_versions;
/** @var array<callable> */
private $migrations = [];
private array $migrations = [];
/**
* Execute a list of migrations, skipping versions indicated in a file

View File

@ -10,9 +10,8 @@
class Minz_ModelArray {
/**
* $filename est le nom du fichier
* @var string
*/
protected $filename;
protected string $filename;
/**
* Ouvre le fichier indiqué, charge le tableau dans $array et le $filename

View File

@ -12,29 +12,16 @@ class Minz_ModelPdo {
/**
* Shares the connection to the database between all instances.
* @var bool
*/
public static $usesSharedPdo = true;
public static bool $usesSharedPdo = true;
/**
* @var Minz_Pdo|null
*/
private static $sharedPdo;
private static ?Minz_Pdo $sharedPdo = null;
/**
* @var string|null
*/
private static $sharedCurrentUser;
private static ?string $sharedCurrentUser;
/**
* @var Minz_Pdo
*/
protected $pdo;
protected Minz_Pdo $pdo;
/**
* @var string|null
*/
protected $current_user;
protected ?string $current_user;
/**
* @throws Minz_ConfigurationNamespaceException

View File

@ -11,27 +11,27 @@ class Minz_Paginator {
/**
* @var array<Minz_Model> tableau des éléments à afficher/gérer
*/
private $items = array ();
private array $items = [];
/**
* @var int le nombre d'éléments par page
* le nombre d'éléments par page
*/
private $nbItemsPerPage = 10;
private int $nbItemsPerPage = 10;
/**
* @var int page actuelle à gérer
* page actuelle à gérer
*/
private $currentPage = 1;
private int $currentPage = 1;
/**
* @var int le nombre de pages de pagination
* le nombre de pages de pagination
*/
private $nbPage = 1;
private int $nbPage = 1;
/**
* @var int le nombre d'éléments
* le nombre d'éléments
*/
private $nbItems = 0;
private int $nbItems = 0;
/**
* Constructeur

View File

@ -14,8 +14,7 @@ abstract class Minz_Pdo extends PDO {
abstract public function dbType(): string;
/** @var string */
private $prefix = '';
private string $prefix = '';
public function prefix(): string {
return $this->prefix;
}

View File

@ -8,20 +8,17 @@
* Request représente la requête http
*/
class Minz_Request {
/** @var string */
private static $controller_name = '';
/** @var string */
private static $action_name = '';
/** @var array<string,mixed> */
private static $params = array();
/** @var string */
private static $default_controller_name = 'index';
/** @var string */
private static $default_action_name = 'index';
private static string $controller_name = '';
private static string $action_name = '';
/** @var array<string,mixed> */
private static array $params = [];
private static string $default_controller_name = 'index';
private static string $default_action_name = 'index';
/** @var array{'c'?:string,'a'?:string,'params'?:array<string,mixed>} */
private static $originalRequest = [];
private static array $originalRequest = [];
/**
* Getteurs

View File

@ -4,16 +4,13 @@
* The Minz_Session class handles users session
*/
class Minz_Session {
/**
* @var bool
*/
private static $volatile = false;
private static bool $volatile = false;
/**
* For mutual exclusion.
* @var bool
*/
private static $locked = false;
private static bool $locked = false;
public static function lock(): bool {
if (!self::$volatile && !self::$locked) {

View File

@ -13,25 +13,24 @@ class Minz_Translate {
* $path_list is the list of registered base path to search translations.
* @var array<string>
*/
private static $path_list = array();
private static array $path_list = [];
/**
* $lang_name is the name of the current language to use.
* @var string
*/
private static $lang_name;
private static string $lang_name;
/**
* $lang_files is a list of registered i18n files.
* @var array<string,array<string>>
*/
private static $lang_files = array();
private static array $lang_files = [];
/**
* $translates is a cache for i18n translation.
* @var array<string,mixed>
*/
private static $translates = array();
private static array $translates = [];
/**
* Init the translation object.

View File

@ -12,22 +12,19 @@ class Minz_View {
private const LAYOUT_PATH_NAME = '/layout/';
private const LAYOUT_DEFAULT = 'layout';
/** @var string */
private $view_filename = '';
/** @var string */
private $layout_filename = '';
private string $view_filename = '';
private string $layout_filename = '';
/** @var array<string> */
private static $base_pathnames = array(APP_PATH);
/** @var string */
private static $title = '';
private static array $base_pathnames = [APP_PATH];
private static string $title = '';
/** @var array<array{'media':string,'url':string}> */
private static $styles = [];
private static array $styles = [];
/** @var array<array{'url':string,'id':string,'defer':bool,'async':bool}> */
private static $scripts = [];
private static array $scripts = [];
/** @var string|array{'dark'?:string,'light'?:string,'default'?:string} */
private static $themeColors;
/** @var array<string,mixed> */
private static $params = [];
private static array $params = [];
/**
* Determines if a layout is used or not

View File

@ -136,11 +136,9 @@ final class FeverAPI
const STATUS_OK = 1;
const STATUS_ERR = 0;
/** @var FreshRSS_EntryDAO */
private $entryDAO;
private FreshRSS_EntryDAO $entryDAO;
/** @var FreshRSS_FeedDAO */
private $feedDAO;
private FreshRSS_FeedDAO $feedDAO;
/**
* Authenticate the user

View File

@ -6,11 +6,9 @@ use PHPUnit\Framework\TestCase;
class LogDAOTest extends TestCase {
private const LOG_FILE_TEST = 'logFileTest.txt';
/** @var FreshRSS_LogDAO */
private $logDAO;
private FreshRSS_LogDAO $logDAO;
/** @var string */
private $logPath;
private string $logPath;
protected function setUp(): void {
$this->logDAO = new FreshRSS_LogDAO();
@ -27,7 +25,6 @@ class LogDAOTest extends TestCase {
$line = $this->logDAO::lines(self::LOG_FILE_TEST);
self::assertIsArray($line);
self::assertCount(1, $line);
self::assertInstanceOf(FreshRSS_Log::class, $line[0]);
self::assertEquals('Wed, 08 Feb 2023 15:35:05 +0000', $line[0]->date());

View File

@ -5,7 +5,7 @@ require_once __DIR__ . '/../../../cli/i18n/I18nValue.php';
class I18nDataTest extends PHPUnit\Framework\TestCase {
/** @var array<string,array<string,array<string,I18nValue>>> */
private $referenceData;
private array $referenceData;
/** @var I18nValue&PHPUnit\Framework\MockObject\MockObject */
private $value;

View File

@ -4,8 +4,8 @@ require_once __DIR__ . '/../../../cli/i18n/I18nValue.php';
require_once __DIR__ . '/../../../cli/i18n/I18nUsageValidator.php';
class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
/** @var I18nValue */
private $value;
private I18nValue $value;
public function setUp(): void {
$this->value = $this->getMockBuilder(I18nValue::class)