diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Minz/ModelPdo.php | 2 | ||||
| -rw-r--r-- | lib/Minz/Translate.php | 4 | ||||
| -rw-r--r-- | lib/lib_rss.php | 158 |
3 files changed, 74 insertions, 90 deletions
diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 0f5b9efca..85796b53a 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -26,7 +26,7 @@ class Minz_ModelPdo { private static $sharedCurrentUser; /** - * @var Minz_Pdo|null + * @var Minz_Pdo */ protected $pdo; diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index 584f08aa0..07d48ec08 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -87,10 +87,10 @@ class Minz_Translate { * preferred languages then returns the default language * @param string|null $user the connected user language (nullable) * @param array<string> $preferred an array of the preferred languages - * @param string $default the preferred language to use + * @param string|null $default the preferred language to use * @return string containing the language to use */ - public static function getLanguage($user, $preferred, $default) { + public static function getLanguage(?string $user, array $preferred, ?string $default): string { if (null !== $user) { return $user; } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index d1821b639..893bed8eb 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -4,8 +4,8 @@ if (version_compare(PHP_VERSION, FRESHRSS_MIN_PHP_VERSION, '<')) { } if (!function_exists('mb_strcut')) { - function mb_strcut($str, $start, $length = null, $encoding = 'UTF-8') { - return substr($str, $start, $length); + function mb_strcut(string $str, int $start, ?int $length = null, string $encoding = 'UTF-8'): string { + return substr($str, $start, $length) ?: ''; } } @@ -34,7 +34,7 @@ function join_path(...$path_parts): string { } //<Auto-loading> -function classAutoloader($class) { +function classAutoloader(string $class): void { if (strpos($class, 'FreshRSS') === 0) { $components = explode('_', $class); switch (count($components)) { @@ -73,14 +73,10 @@ function classAutoloader($class) { spl_autoload_register('classAutoloader'); //</Auto-loading> -/** - * @param string $url - * @return string - */ -function idn_to_puny($url) { +function idn_to_puny(string $url): string { if (function_exists('idn_to_ascii')) { $idn = parse_url($url, PHP_URL_HOST); - if ($idn != '') { + if (is_string($idn) && $idn != '') { // https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003 if (defined('INTL_IDNA_VARIANT_UTS46')) { $puny = idn_to_ascii($idn, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); @@ -90,7 +86,7 @@ function idn_to_puny($url) { $puny = idn_to_ascii($idn); } $pos = strpos($url, $idn); - if ($puny != '' && $pos !== false) { + if ($puny != false && $pos !== false) { $url = substr_replace($url, $puny, $pos, strlen($idn)); } } @@ -99,11 +95,9 @@ function idn_to_puny($url) { } /** - * @param string $url - * @param bool $fixScheme * @return string|false */ -function checkUrl($url, $fixScheme = true) { +function checkUrl(string $url, bool $fixScheme = true) { $url = trim($url); if ($url == '') { return ''; @@ -127,31 +121,19 @@ function checkUrl($url, $fixScheme = true) { * @return string */ function safe_ascii($text) { - return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?: ''; } if (function_exists('mb_convert_encoding')) { - /** - * @param string $text - * @return string - */ - function safe_utf8($text) { - return mb_convert_encoding($text, 'UTF-8', 'UTF-8'); + function safe_utf8(string $text): string { + return mb_convert_encoding($text, 'UTF-8', 'UTF-8') ?: ''; } } elseif (function_exists('iconv')) { - /** - * @param string $text - * @return string - */ - function safe_utf8($text) { - return iconv('UTF-8', 'UTF-8//IGNORE', $text); + function safe_utf8(string $text): string { + return iconv('UTF-8', 'UTF-8//IGNORE', $text) ?: ''; } } else { - /** - * @param string $text - * @return string - */ - function safe_utf8($text) { + function safe_utf8(string $text): string { return $text; } } @@ -178,14 +160,14 @@ function escapeToUnicodeAlternative($text, $extended = true) { return trim(str_replace($problem, $replace, $text)); } -function format_number($n, $precision = 0) { +function format_number(float $n, int $precision = 0): string { // number_format does not seem to be Unicode-compatible return str_replace(' ', ' ', // Thin non-breaking space number_format($n, $precision, '.', ' ') ); } -function format_bytes($bytes, $precision = 2, $system = 'IEC') { +function format_bytes(int $bytes, int $precision = 2, string $system = 'IEC'): string { if ($system === 'IEC') { $base = 1024; $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB'); @@ -202,7 +184,7 @@ function format_bytes($bytes, $precision = 2, $system = 'IEC') { return format_number($bytes, $precision) . ' ' . $units[$pow]; } -function timestamptodate ($t, $hour = true) { +function timestamptodate(int $t, bool $hour = true): string { $month = _t('gen.date.' . date('M', $t)); if ($hour) { $date = _t('gen.date.format_date_hour', $month); @@ -210,14 +192,13 @@ function timestamptodate ($t, $hour = true) { $date = _t('gen.date.format_date', $month); } - return @date ($date, $t); + return @date($date, $t) ?: ''; } /** * Decode HTML entities but preserve XML entities. - * @param string|null $text */ -function html_only_entity_decode($text): string { +function html_only_entity_decode(?string $text): string { static $htmlEntitiesOnly = null; if ($htmlEntitiesOnly === null) { $htmlEntitiesOnly = array_flip(array_diff( @@ -225,7 +206,7 @@ function html_only_entity_decode($text): string { get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES, 'UTF-8') //Preserve XML entities )); } - return $text == '' ? '' : strtr($text, $htmlEntitiesOnly); + return $text == null ? '' : strtr($text, $htmlEntitiesOnly); } /** @@ -239,8 +220,10 @@ function sensitive_log($log) { foreach ($log as $k => $v) { if (in_array($k, ['api_key', 'Passwd', 'T'])) { $log[$k] = '██'; - } else { + } elseif (is_array($v) || is_string($v)) { $log[$k] = sensitive_log($v); + } else { + return ''; } } } elseif (is_string($log)) { @@ -248,7 +231,7 @@ function sensitive_log($log) { '/\b(auth=.*?\/)[^&]+/i', '/\b(Passwd=)[^&]+/i', '/\b(Authorization)[^&]+/i', - ], '$1█', $log); + ], '$1█', $log) ?? ''; } return $log; } @@ -257,6 +240,9 @@ function sensitive_log($log) { * @param array<string,mixed> $attributes */ function customSimplePie($attributes = array()): SimplePie { + if (FreshRSS_Context::$system_conf === null) { + throw new FreshRSS_Context_Exception('System configuration not initialised!'); + } $limits = FreshRSS_Context::$system_conf->limits; $simplePie = new SimplePie(); $simplePie->set_useragent(FRESHRSS_USERAGENT); @@ -338,13 +324,13 @@ function customSimplePie($attributes = array()): SimplePie { } /** - * @param int|false $maxLength + * @param string $data */ -function sanitizeHTML($data, string $base = '', $maxLength = false) { - if (!is_string($data) || ($maxLength !== false && $maxLength <= 0)) { +function sanitizeHTML($data, string $base = '', ?int $maxLength = null): string { + if (!is_string($data) || ($maxLength !== null && $maxLength <= 0)) { return ''; } - if ($maxLength !== false) { + if ($maxLength !== null) { $data = mb_strcut($data, 0, $maxLength, 'UTF-8'); } static $simplePie = null; @@ -353,7 +339,7 @@ function sanitizeHTML($data, string $base = '', $maxLength = false) { $simplePie->init(); } $result = html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_HTML, $base)); - if ($maxLength !== false && strlen($result) > $maxLength) { + if ($maxLength !== null && strlen($result) > $maxLength) { //Sanitizing has made the result too long so try again shorter $data = mb_strcut($result, 0, (2 * $maxLength) - strlen($result) - 2, 'UTF-8'); return sanitizeHTML($data, $base, $maxLength); @@ -361,9 +347,9 @@ function sanitizeHTML($data, string $base = '', $maxLength = false) { return $result; } -function cleanCache(int $hours = 720) { +function cleanCache(int $hours = 720): void { // N.B.: GLOB_BRACE is not available on all platforms - $files = array_merge(glob(CACHE_PATH . '/*.html', GLOB_NOSORT), glob(CACHE_PATH . '/*.spc', GLOB_NOSORT)); + $files = array_merge(glob(CACHE_PATH . '/*.html', GLOB_NOSORT) ?: [], glob(CACHE_PATH . '/*.spc', GLOB_NOSORT) ?: []); foreach ($files as $file) { if (substr($file, -10) === 'index.html') { continue; @@ -412,13 +398,16 @@ 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']); $cacheMtime = @filemtime($cachePath); if ($cacheMtime !== false && $cacheMtime > time() - intval($limits['cache_duration'])) { $body = @file_get_contents($cachePath); - if ($body != '') { + if ($body != false) { syslog(LOG_DEBUG, 'FreshRSS uses cache for ' . SimplePie_Misc::url_remove_credentials($url)); return $body; } @@ -472,7 +461,7 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a } $body = curl_exec($ch); $c_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $c_content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); //TODO: Check if that may be null + $c_content_type = '' . curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $c_error = curl_error($ch); curl_close($ch); @@ -481,7 +470,7 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a $body = ''; // TODO: Implement HTTP 410 Gone } - if ($body == false) { + if (!is_string($body)) { $body = ''; } else { $body = enforceHttpEncoding($body, $c_content_type); @@ -498,10 +487,9 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a * Validate an email address, supports internationalized addresses. * * @param string $email The address to validate - * * @return bool true if email is valid, else false */ -function validateEmailAddress($email) { +function validateEmailAddress(string $email): bool { $mailer = new PHPMailer\PHPMailer\PHPMailer(); $mailer->CharSet = 'utf-8'; $punyemail = $mailer->punyencodeAddress($email); @@ -512,9 +500,8 @@ function validateEmailAddress($email) { * Add support of image lazy loading * Move content from src attribute to data-original * @param string $content is the text we want to parse - * @return string */ -function lazyimg($content) { +function lazyimg(string $content): string { return preg_replace([ '/<((?:img|iframe)[^>]+?)src="([^"]+)"([^>]*)>/i', "/<((?:img|iframe)[^>]+?)src='([^']+)'([^>]*)>/i", @@ -523,18 +510,15 @@ function lazyimg($content) { "<$1src='" . Minz_Url::display('/themes/icons/grey.gif') . "' data-original='$2'$3>", ], $content - ); + ) ?? ''; } -/** - * @return string - */ -function uTimeString() { +function uTimeString(): string { $t = @gettimeofday(); return $t['sec'] . str_pad('' . $t['usec'], 6, '0', STR_PAD_LEFT); } -function invalidateHttpCache($username = '') { +function invalidateHttpCache(string $username = ''): bool { if (!FreshRSS_user_Controller::checkUsername($username)) { Minz_Session::_param('touch', uTimeString()); $username = Minz_Session::param('currentUser', '_'); @@ -549,12 +533,12 @@ function invalidateHttpCache($username = '') { /** * @return array<string> */ -function listUsers() { +function listUsers(): array { $final_list = array(); $base_path = join_path(DATA_PATH, 'users'); $dir_list = array_values(array_diff( - scandir($base_path), - array('..', '.', '_') + scandir($base_path) ?: [], + ['..', '.', '_'] )); foreach ($dir_list as $file) { if ($file[0] !== '.' && is_dir(join_path($base_path, $file)) && file_exists(join_path($base_path, $file, 'config.php'))) { @@ -567,12 +551,14 @@ function listUsers() { /** * Return if the maximum number of registrations has been reached. - * - * Note a max_regstrations of 0 means there is no limit. + * Note a max_registrations of 0 means there is no limit. * * @return boolean true if number of users >= max registrations, false else. */ -function max_registrations_reached() { +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']; $number_accounts = count(listUsers()); @@ -589,7 +575,7 @@ function max_registrations_reached() { * @param string $username the name of the user of which we want the configuration. * @return FreshRSS_UserConfiguration|null object, or null if the configuration cannot be loaded. */ -function get_user_configuration($username) { +function get_user_configuration(string $username) { if (!FreshRSS_user_Controller::checkUsername($username)) { return null; } @@ -621,7 +607,7 @@ function get_user_configuration($username) { */ function ipToBits(string $ip): string { $binaryip = ''; - foreach (str_split(inet_pton($ip)) as $char) { + foreach (str_split(inet_pton($ip) ?: '') as $char) { $binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT); } return $binaryip; @@ -654,6 +640,9 @@ function checkCIDR(string $ip, string $range): bool { * @return boolean, 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) { + throw new FreshRSS_Context_Exception('System configuration not initialised!'); + } if (!empty($_SERVER['REMOTE_ADDR'])) { foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) { if (checkCIDR($_SERVER['REMOTE_ADDR'], $cidr)) { @@ -664,10 +653,7 @@ function checkTrustedIP(): bool { return false; } -/** - * @return string - */ -function httpAuthUser() { +function httpAuthUser(): string { if (!empty($_SERVER['REMOTE_USER'])) { return $_SERVER['REMOTE_USER']; } elseif (!empty($_SERVER['HTTP_REMOTE_USER']) && checkTrustedIP()) { @@ -680,10 +666,7 @@ function httpAuthUser() { return ''; } -/** - * @return bool - */ -function cryptAvailable() { +function cryptAvailable(): bool { try { $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG'; return $hash === @crypt('password', $hash); @@ -699,7 +682,7 @@ function cryptAvailable() { * * @return array<string,bool> of tested values. */ -function check_install_php() { +function check_install_php(): array { $pdo_mysql = extension_loaded('pdo_mysql'); $pdo_pgsql = extension_loaded('pdo_pgsql'); $pdo_sqlite = extension_loaded('pdo_sqlite'); @@ -723,7 +706,7 @@ function check_install_php() { * * @return array<string,bool> of tested values. */ -function check_install_files() { +function check_install_files(): array { return array( // @phpstan-ignore-next-line 'data' => DATA_PATH && touch(DATA_PATH . '/index.html'), // is_writable() is not reliable for a folder on NFS @@ -742,7 +725,7 @@ function check_install_files() { * * @return array<string,bool> of tested values. */ -function check_install_database() { +function check_install_database(): array { $status = array( 'connection' => true, 'tables' => false, @@ -773,17 +756,14 @@ function check_install_database() { /** * Remove a directory recursively. - * * From http://php.net/rmdir#110489 - * - * @param string $dir the directory to remove */ -function recursive_unlink($dir) { +function recursive_unlink(string $dir): bool { if (!is_dir($dir)) { return true; } - $files = array_diff(scandir($dir), array('.', '..')); + $files = array_diff(scandir($dir) ?: [], ['.', '..']); foreach ($files as $filename) { $filename = $dir . '/' . $filename; if (is_dir($filename)) { @@ -803,7 +783,7 @@ function recursive_unlink($dir) { * @param array<int,array<string,string>> $queries an array of queries. * @return array<int,array<string,string>> without queries where $get is appearing. */ -function remove_query_by_get($get, $queries) { +function remove_query_by_get(string $get, array $queries): array { $final_queries = array(); foreach ($queries as $key => $query) { if (empty($query['get']) || $query['get'] !== $get) { @@ -827,7 +807,11 @@ const SHORTCUT_KEYS = [ 'End', 'Enter', 'Escape', 'Home', 'Insert', 'PageDown', 'PageUp', 'Space', 'Tab', ]; -function getNonStandardShortcuts($shortcuts) { +/** + * @param array<string> $shortcuts + * @return array<string> + */ +function getNonStandardShortcuts(array $shortcuts): array { $standard = strtolower(implode(' ', SHORTCUT_KEYS)); $nonStandard = array_filter($shortcuts, function ($shortcut) use ($standard) { @@ -838,7 +822,7 @@ function getNonStandardShortcuts($shortcuts) { return $nonStandard; } -function errorMessageInfo($errorTitle, $error = '') { +function errorMessageInfo(string $errorTitle, string $error = ''): string { $errorTitle = htmlspecialchars($errorTitle, ENT_NOQUOTES, 'UTF-8'); $message = ''; |
