summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/colors.php204
-rwxr-xr-xinclude/controls.php70
-rw-r--r--include/controls_compat.php23
-rw-r--r--include/errorhandler.php13
-rw-r--r--include/functions.php178
-rw-r--r--include/sessions.php36
6 files changed, 358 insertions, 166 deletions
diff --git a/include/colors.php b/include/colors.php
index 41158f96e..5682b55a1 100644
--- a/include/colors.php
+++ b/include/colors.php
@@ -5,7 +5,7 @@ if (file_exists("lib/floIcon.php")) {
require_once "lib/floIcon.php";
}
-function _resolve_htmlcolor($color) {
+function _resolve_htmlcolor(string $color): string {
$htmlcolors = array ("aliceblue" => "#f0f8ff",
"antiquewhite" => "#faebd7",
"aqua" => "#00ffff",
@@ -162,8 +162,14 @@ function _resolve_htmlcolor($color) {
return $color;
}
-### RGB >> HSL
-function _color_rgb2hsl($rgb) {
+/**
+ * RGB >> HSL
+ *
+ * @param array{0: int, 1: int, 2: int} $rgb
+ *
+ * @return array{0: float, 1: float, 2: float}
+ */
+function _color_rgb2hsl(array $rgb): array {
$r = $rgb[0]; $g = $rgb[1]; $b = $rgb[2];
$min = min($r, min($g, $b)); $max = max($r, max($g, $b));
$delta = $max - $min; $l = ($min + $max) / 2; $s = 0;
@@ -179,8 +185,14 @@ function _color_rgb2hsl($rgb) {
} return array($h, $s, $l);
}
-### HSL >> RGB
-function _color_hsl2rgb($hsl) {
+/**
+ * HSL >> RGB
+ *
+ * @param array{0: float, 1: float, 2: float} $hsl
+ *
+ * @return array{0: int, 1: int, 2: int}
+ */
+function _color_hsl2rgb($hsl): array {
$h = $hsl[0]; $s = $hsl[1]; $l = $hsl[2];
$m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
$m1 = $l * 2 - $m2;
@@ -190,40 +202,65 @@ function _color_hsl2rgb($hsl) {
}
### Helper function for _color_hsl2rgb().
-function _color_hue2rgb($m1, $m2, $h) {
- $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
- if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
- if ($h * 2 < 1) return $m2;
- if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
- return $m1;
+function _color_hue2rgb(float $m1, float $m2, float $h): int {
+ $rv = $m1;
+
+ $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
+
+ if ($h * 6 < 1) {
+ $rv = $m1 + ($m2 - $m1) * $h * 6;
+ } else if ($h * 2 < 1) {
+ $rv = $m2;
+ } else if ($h * 3 < 2) {
+ $rv = $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
+ }
+
+ return (int) round($rv);
}
-### Convert a hex color into an RGB triplet.
-function _color_unpack($hex, $normalize = false) {
+/**
+ * Convert a hex color into an RGB triplet.
+ *
+ * @return array{0: int, 1: int, 2: int}
+ */
+function _color_unpack(string $hex, bool $normalize = false): array {
+ $hex = strpos($hex, '#') !== 0 ? _resolve_htmlcolor($hex) : substr($hex, 1);
- if (strpos($hex, '#') !== 0)
- $hex = _resolve_htmlcolor($hex);
- else
- $hex = substr($hex, 1);
+ if (strlen($hex) == 4) {
+ $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
+ }
- if (strlen($hex) == 4) {
- $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
- }
- $c = hexdec($hex);
- for ($i = 16; $i >= 0; $i -= 8) {
- $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
- } return $out;
+ $c = hexdec($hex);
+ $out = [];
+
+ for ($i = 16; $i >= 0; $i -= 8) {
+ $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
+ }
+
+ return $out;
}
-### Convert an RGB triplet to a hex color.
-function _color_pack($rgb, $normalize = false) {
+/**
+ * Convert an RGB triplet to a hex color.
+ *
+ * @param array{0: int, 1: int, 2: int} $rgb
+ */
+function _color_pack(array $rgb, bool $normalize = false): string {
$out = 0;
- foreach ($rgb as $k => $v) {
- $out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
- }return '#'. str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
+
+ foreach ($rgb as $k => $v) {
+ $out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
+ }
+
+ return '#'. str_pad(dechex($out), 6, '0', STR_PAD_LEFT);
}
-function rgb2hsl($arr) {
+/**
+ * @param array{0: int, 1: int, 2: int} $arr
+ *
+ * @return array{0: float, 1: float, 2: float}
+ */
+function rgb2hsl(array $arr): array {
$r = $arr[0];
$g = $arr[1];
$b = $arr[2];
@@ -248,9 +285,14 @@ function rgb2hsl($arr) {
$del_G = ((($var_Max - $var_G ) / 6 ) + ($del_Max / 2 ) ) / $del_Max;
$del_B = ((($var_Max - $var_B ) / 6 ) + ($del_Max / 2 ) ) / $del_Max;
- if ($var_R == $var_Max) $h = $del_B - $del_G;
- else if ($var_G == $var_Max) $h = (1 / 3 ) + $del_R - $del_B;
- else if ($var_B == $var_Max) $h = (2 / 3 ) + $del_G - $del_R;
+ if ($var_R == $var_Max) {
+ $h = $del_B - $del_G;
+ } else if ($var_G == $var_Max) {
+ $h = (1 / 3 ) + $del_R - $del_B;
+ } else {
+ // ($var_B == $var_Max)
+ $h = (2 / 3 ) + $del_G - $del_R;
+ }
if ($h < 0) $h++;
if ($h > 1) $h--;
@@ -259,7 +301,12 @@ function rgb2hsl($arr) {
return array($h, $s, $v);
}
-function hsl2rgb($arr) {
+/**
+ * @param array{0: float, 1: float, 2: float} $arr
+ *
+ * @return array{0: int, 1: int, 2: int}
+ */
+function hsl2rgb(array $arr): array {
$h = $arr[0];
$s = $arr[1];
$v = $arr[2];
@@ -280,63 +327,66 @@ function hsl2rgb($arr) {
else if ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1 ; $var_B = $v ; }
else { $var_R = $v ; $var_G = $var_1 ; $var_B = $var_2 ; }
- $r = $var_R * 255;
- $g = $var_G * 255;
- $B = $var_B * 255;
+ $r = (int) round($var_R * 255);
+ $g = (int) round($var_G * 255);
+ $B = (int) round($var_B * 255);
}
return array($r, $g, $B);
}
- function colorPalette($imageFile, $numColors, $granularity = 5) {
- $granularity = max(1, abs((int)$granularity));
- $colors = array();
-
- $size = @getimagesize($imageFile);
-
- // to enable .ico support place floIcon.php into lib/
- if (strtolower($size['mime']) == 'image/vnd.microsoft.icon') {
-
- if (class_exists("floIcon")) {
+/**
+ * @return array<int, string>|null
+*/
+function colorPalette(string $imageFile, int $numColors, int $granularity = 5): ?array {
+ $granularity = max(1, abs($granularity));
+ $colors = [];
- $ico = new \floIcon();
- @$ico->readICO($imageFile);
+ $size = @getimagesize($imageFile);
+ $img = null;
- if(count($ico->images)==0)
- return false;
- else
- $img = @$ico->images[count($ico->images)-1]->getImageResource();
+ // to enable .ico support place floIcon.php into lib/
+ if (strtolower($size['mime']) == 'image/vnd.microsoft.icon') {
+ if (class_exists("floIcon")) {
+ $ico = new \floIcon();
+ @$ico->readICO($imageFile);
+ if(count($ico->images) == 0) {
+ return null;
} else {
- return false;
+ $img = @$ico->images[count($ico->images)-1]->getImageResource();
}
-
- } else if ($size[0] > 0 && $size[1] > 0) {
- $img = @imagecreatefromstring(file_get_contents($imageFile));
}
+ return null;
+ } else if ($size[0] > 0 && $size[1] > 0) {
+ $img = @imagecreatefromstring(file_get_contents($imageFile));
+ }
- if (!$img) return false;
-
- for($x = 0; $x < $size[0]; $x += $granularity) {
- for($y = 0; $y < $size[1]; $y += $granularity) {
- $thisColor = imagecolorat($img, $x, $y);
- $rgb = imagecolorsforindex($img, $thisColor);
- $red = round(round(($rgb['red'] / 0x33)) * 0x33);
- $green = round(round(($rgb['green'] / 0x33)) * 0x33);
- $blue = round(round(($rgb['blue'] / 0x33)) * 0x33);
- $thisRGB = sprintf('%02X%02X%02X', $red, $green, $blue);
- if(array_key_exists($thisRGB, $colors)) {
- $colors[$thisRGB]++;
- } else{
- $colors[$thisRGB] = 1;
- }
- }
- }
+ if (!$img) {
+ return null;
+ }
- arsort($colors);
- return array_slice(array_keys($colors), 0, $numColors);
+ for($x = 0; $x < $size[0]; $x += $granularity) {
+ for($y = 0; $y < $size[1]; $y += $granularity) {
+ $thisColor = imagecolorat($img, $x, $y);
+ $rgb = imagecolorsforindex($img, $thisColor);
+ $red = round(round(($rgb['red'] / 0x33)) * 0x33);
+ $green = round(round(($rgb['green'] / 0x33)) * 0x33);
+ $blue = round(round(($rgb['blue'] / 0x33)) * 0x33);
+ $thisRGB = sprintf('%02X%02X%02X', $red, $green, $blue);
+
+ if(array_key_exists($thisRGB, $colors)) {
+ $colors[$thisRGB]++;
+ } else {
+ $colors[$thisRGB] = 1;
+ }
+ }
}
- function calculate_avg_color($iconFile) {
+ arsort($colors);
+ return array_slice(array_keys($colors), 0, $numColors);
+}
+
+ function calculate_avg_color(string $iconFile): string {
$palette = colorPalette($iconFile, 4, 4);
if (is_array($palette)) {
diff --git a/include/controls.php b/include/controls.php
index a1a1bc59b..1ea019769 100755
--- a/include/controls.php
+++ b/include/controls.php
@@ -1,7 +1,10 @@
<?php
namespace Controls;
- function attributes_to_string(array $attributes) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function attributes_to_string(array $attributes): string {
$rv = [];
foreach ($attributes as $k => $v) {
@@ -21,21 +24,27 @@
return hidden_tag("op", strtolower(get_class($plugin) . \PluginHost::PUBLIC_METHOD_DELIMITER . $method));
} */
- function public_method_tags(\Plugin $plugin, string $method) {
+ function public_method_tags(\Plugin $plugin, string $method): string {
return hidden_tag("op", strtolower(get_class($plugin) . \PluginHost::PUBLIC_METHOD_DELIMITER . $method));
}
- function pluginhandler_tags(\Plugin $plugin, string $method) {
+ function pluginhandler_tags(\Plugin $plugin, string $method): string {
return hidden_tag("op", "pluginhandler") .
hidden_tag("plugin", strtolower(get_class($plugin))) .
hidden_tag("method", $method);
}
- function button_tag(string $value, string $type, array $attributes = []) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function button_tag(string $value, string $type, array $attributes = []): string {
return "<button dojoType=\"dijit.form.Button\" ".attributes_to_string($attributes)." type=\"$type\">$value</button>";
}
- function input_tag(string $name, string $value, string $type = "text", array $attributes = [], string $id = "") {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function input_tag(string $name, string $value, string $type = "text", array $attributes = [], string $id = ""): string {
$attributes_str = attributes_to_string($attributes);
$dojo_type = strpos($attributes_str, "dojoType") === false ? "dojoType='dijit.form.TextBox'" : "";
@@ -43,23 +52,40 @@
type=\"$type\" value=\"".htmlspecialchars($value)."\">";
}
- function number_spinner_tag(string $name, string $value, array $attributes = [], string $id = "") {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function number_spinner_tag(string $name, string $value, array $attributes = [], string $id = ""): string {
return input_tag($name, $value, "text", array_merge(["dojoType" => "dijit.form.NumberSpinner"], $attributes), $id);
}
- function submit_tag(string $value, array $attributes = []) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function submit_tag(string $value, array $attributes = []): string {
return button_tag($value, "submit", array_merge(["class" => "alt-primary"], $attributes));
}
- function cancel_dialog_tag(string $value, array $attributes = []) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function cancel_dialog_tag(string $value, array $attributes = []): string {
return button_tag($value, "", array_merge(["onclick" => "App.dialogOf(this).hide()"], $attributes));
}
- function icon(string $icon, array $attributes = []) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function icon(string $icon, array $attributes = []): string {
return "<i class=\"material-icons\" ".attributes_to_string($attributes).">$icon</i>";
}
- function select_tag(string $name, $value, array $values, array $attributes = [], string $id = "") {
+ /**
+ * @param mixed $value
+ * @param array<int|string, string> $values
+ * @param array<string, mixed> $attributes
+ */
+ function select_tag(string $name, $value, array $values, array $attributes = [], string $id = ""): string {
$attributes_str = attributes_to_string($attributes);
$dojo_type = strpos($attributes_str, "dojoType") === false ? "dojoType='fox.form.Select'" : "";
@@ -83,7 +109,12 @@
return select_tag($name, $value, $values, $attributes, $id);
}*/
- function select_hash(string $name, $value, array $values, array $attributes = [], string $id = "") {
+ /**
+ * @param mixed $value
+ * @param array<int|string, string> $values
+ * @param array<string, mixed> $attributes
+ */
+ function select_hash(string $name, $value, array $values, array $attributes = [], string $id = ""): string {
$attributes_str = attributes_to_string($attributes);
$dojo_type = strpos($attributes_str, "dojoType") === false ? "dojoType='fox.form.Select'" : "";
@@ -93,7 +124,7 @@
foreach ($values as $k => $v) {
$is_sel = ($k == $value) ? "selected=\"selected\"" : "";
- $rv .= "<option value=\"".htmlspecialchars($k)."\" $is_sel>".htmlspecialchars($v)."</option>";
+ $rv .= "<option value=\"".htmlspecialchars("$k")."\" $is_sel>".htmlspecialchars($v)."</option>";
}
$rv .= "</select>";
@@ -101,13 +132,19 @@
return $rv;
}
- function hidden_tag(string $name, string $value, array $attributes = []) {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function hidden_tag(string $name, string $value, array $attributes = []): string {
return "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\"
".attributes_to_string($attributes)." name=\"".htmlspecialchars($name)."\"
value=\"".htmlspecialchars($value)."\">";
}
- function checkbox_tag(string $name, bool $checked = false, string $value = "", array $attributes = [], string $id = "") {
+ /**
+ * @param array<string, mixed> $attributes
+ */
+ function checkbox_tag(string $name, bool $checked = false, string $value = "", array $attributes = [], string $id = ""): string {
$is_checked = $checked ? "checked" : "";
$value_str = $value ? "value=\"".htmlspecialchars($value)."\"" : "";
@@ -115,8 +152,11 @@
$value_str $is_checked ".attributes_to_string($attributes)." id=\"".htmlspecialchars($id)."\">";
}
+ /**
+ * @param array<string, mixed> $attributes
+ */
function select_feeds_cats(string $name, int $default_id = null, array $attributes = [],
- bool $include_all_cats = true, string $root_id = null, int $nest_level = 0, string $id = "") {
+ bool $include_all_cats = true, string $root_id = null, int $nest_level = 0, string $id = ""): string {
$ret = "";
diff --git a/include/controls_compat.php b/include/controls_compat.php
index d1c2c12b5..5a2a9f2ba 100644
--- a/include/controls_compat.php
+++ b/include/controls_compat.php
@@ -1,7 +1,9 @@
<?php
-
-function stylesheet_tag($filename, $attributes = []) {
+/**
+ * @param array<string, mixed> $attributes
+ */
+function stylesheet_tag(string $filename, array $attributes = []): string {
$attributes_str = \Controls\attributes_to_string(
array_merge(
@@ -16,7 +18,10 @@ function stylesheet_tag($filename, $attributes = []) {
return "<link $attributes_str/>\n";
}
-function javascript_tag($filename, $attributes = []) {
+/**
+ * @param array<string, mixed> $attributes
+ */
+function javascript_tag(string $filename, array $attributes = []): string {
$attributes_str = \Controls\attributes_to_string(
array_merge(
[
@@ -29,26 +34,26 @@ function javascript_tag($filename, $attributes = []) {
return "<script $attributes_str></script>\n";
}
-function format_warning($msg, $id = "") {
+function format_warning(string $msg, string $id = ""): string {
return "<div class=\"alert\" id=\"$id\">$msg</div>";
}
-function format_notice($msg, $id = "") {
+function format_notice(string $msg, string $id = ""): string {
return "<div class=\"alert alert-info\" id=\"$id\">$msg</div>";
}
-function format_error($msg, $id = "") {
+function format_error(string $msg, string $id = ""): string {
return "<div class=\"alert alert-danger\" id=\"$id\">$msg</div>";
}
-function print_notice($msg) {
+function print_notice(string $msg): string {
return print format_notice($msg);
}
-function print_warning($msg) {
+function print_warning(string $msg): string {
return print format_warning($msg);
}
-function print_error($msg) {
+function print_error(string $msg): string {
return print format_error($msg);
}
diff --git a/include/errorhandler.php b/include/errorhandler.php
index 2ad0be062..30b6902b3 100644
--- a/include/errorhandler.php
+++ b/include/errorhandler.php
@@ -1,5 +1,8 @@
<?php
-function format_backtrace($trace) {
+/**
+ * @param array<int, array<string, mixed>> $trace
+ */
+function format_backtrace($trace): string {
$rv = "";
$idx = 1;
@@ -8,7 +11,7 @@ function format_backtrace($trace) {
if (isset($e["file"]) && isset($e["line"])) {
$fmt_args = [];
- if (is_array($e["args"])) {
+ if (is_array($e["args"] ?? false)) {
foreach ($e["args"] as $a) {
if (is_object($a)) {
array_push($fmt_args, "{" . get_class($a) . "}");
@@ -16,7 +19,7 @@ function format_backtrace($trace) {
array_push($fmt_args, "[" . truncate_string(json_encode($a), 256, "...")) . "]";
} else if (is_resource($a)) {
array_push($fmt_args, truncate_string(get_resource_type($a), 256, "..."));
- } else {
+ } else if (is_string($a)) {
array_push($fmt_args, truncate_string($a, 256, "..."));
}
}
@@ -39,7 +42,7 @@ function format_backtrace($trace) {
return $rv;
}
-function ttrss_error_handler($errno, $errstr, $file, $line) {
+function ttrss_error_handler(int $errno, string $errstr, string $file, int $line): bool {
/*if (version_compare(PHP_VERSION, '8.0.0', '<')) {
if (error_reporting() == 0 || !$errno) return false;
} else {
@@ -59,7 +62,7 @@ function ttrss_error_handler($errno, $errstr, $file, $line) {
return false;
}
-function ttrss_fatal_handler() {
+function ttrss_fatal_handler(): bool {
$error = error_get_last();
if ($error !== NULL) {
diff --git a/include/functions.php b/include/functions.php
index 922d3765c..91fb62ec5 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -2,7 +2,7 @@
define('LABEL_BASE_INDEX', -1024);
define('PLUGIN_FEED_BASE_INDEX', -128);
- /** constant is @deprecated, use Config::SCHEMA_VERSION instead */
+ /** @deprecated by Config::SCHEMA_VERSION */
define('SCHEMA_VERSION', Config::SCHEMA_VERSION);
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
@@ -36,15 +36,24 @@
define('SUBSTRING_FOR_DATE', 'SUBSTRING');
}
+ /**
+ * @return bool|int|null|string
+ */
function get_pref(string $pref_name, int $owner_uid = null) {
return Prefs::get($pref_name, $owner_uid ? $owner_uid : $_SESSION["uid"], $_SESSION["profile"] ?? null);
}
- function set_pref(string $pref_name, $value, int $owner_uid = null, bool $strip_tags = true) {
+ /**
+ * @param bool|int|string $value
+ */
+ function set_pref(string $pref_name, $value, int $owner_uid = null, bool $strip_tags = true): bool {
return Prefs::set($pref_name, $value, $owner_uid ? $owner_uid : $_SESSION["uid"], $_SESSION["profile"] ?? null, $strip_tags);
}
- function get_translations() {
+ /**
+ * @return array<string, string>
+ */
+ function get_translations(): array {
$t = array(
"auto" => __("Detect automatically"),
"ar_SA" => "العربيّة (Arabic)",
@@ -81,7 +90,7 @@
require_once "lib/gettext/gettext.inc.php";
- function startup_gettext() {
+ function startup_gettext(): void {
$selected_locale = "";
@@ -157,75 +166,115 @@
require_once 'controls.php';
require_once 'controls_compat.php';
- define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . Config::get_version() . ' (http://tt-rss.org/)');
- ini_set('user_agent', SELF_USER_AGENT);
+ ini_set('user_agent', Config::get_user_agent());
/* compat shims */
- /** function is @deprecated by Config::get_version() */
+ /**
+ * @deprecated by Config::get_version()
+ *
+ * @return array<string, mixed>|string
+ */
function get_version() {
return Config::get_version();
}
- /** function is @deprecated by Config::get_schema_version() */
- function get_schema_version() {
+ /** @deprecated by Config::get_schema_version() */
+ function get_schema_version(): int {
return Config::get_schema_version();
}
- /** function is @deprecated by Debug::log() */
- function _debug($msg) {
- Debug::log($msg);
+ /** @deprecated by Debug::log() */
+ function _debug(string $msg): void {
+ Debug::log($msg);
}
- /** function is @deprecated */
- function getFeedUnread($feed, $is_cat = false) {
+
+ /** @deprecated by Feeds::_get_counters()
+ * @param int|string $feed feed id or tag name
+ * @param bool $is_cat
+ * @return int
+ * @throws PDOException
+ */
+ function getFeedUnread($feed, bool $is_cat = false): int {
return Feeds::_get_counters($feed, $is_cat, true, $_SESSION["uid"]);
}
- /** function is @deprecated by Sanitizer::sanitize() */
- function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false, $highlight_words = false, $article_id = false) {
+ /**
+ * @deprecated by Sanitizer::sanitize()
+ *
+ * @param array<int, string>|null $highlight_words Words to highlight in the HTML output.
+ *
+ * @return false|string The HTML, or false if an error occurred.
+ */
+ function sanitize(string $str, bool $force_remove_images = false, int $owner = null, string $site_url = null, array $highlight_words = null, int $article_id = null) {
return Sanitizer::sanitize($str, $force_remove_images, $owner, $site_url, $highlight_words, $article_id);
}
- /** function is @deprecated by UrlHelper::fetch() */
+ /**
+ * @deprecated by UrlHelper::fetch()
+ *
+ * @param array<string, bool|int|string>|string $params
+ * @return bool|string false if something went wrong, otherwise string contents
+ */
function fetch_file_contents($params) {
return UrlHelper::fetch($params);
}
- /** function is @deprecated by UrlHelper::rewrite_relative() */
+ /**
+ * @deprecated by UrlHelper::rewrite_relative()
+ *
+ * Converts a (possibly) relative URL to a absolute one, using provided base URL.
+ * Provides some exceptions for additional schemes like data: if called with owning element/attribute.
+ *
+ * @param string $base_url Base URL (i.e. from where the document is)
+ * @param string $rel_url Possibly relative URL in the document
+ *
+ * @return string Absolute URL
+ */
function rewrite_relative_url($base_url, $rel_url) {
return UrlHelper::rewrite_relative($base_url, $rel_url);
}
- /** function is @deprecated by UrlHelper::validate() */
- function validate_url($url) {
+ /**
+ * @deprecated by UrlHelper::validate()
+ *
+ * @return bool|string false if something went wrong, otherwise the URL string
+ */
+ function validate_url(string $url) {
return UrlHelper::validate($url);
}
- /** function is @deprecated by UserHelper::authenticate() */
- function authenticate_user($login, $password, $check_only = false, $service = false) {
+ /** @deprecated by UserHelper::authenticate() */
+ function authenticate_user(string $login = null, string $password = null, bool $check_only = false, string $service = null): bool {
return UserHelper::authenticate($login, $password, $check_only, $service);
}
- /** function is @deprecated by TimeHelper::smart_date_time() */
- function smart_date_time($timestamp, $tz_offset = 0, $owner_uid = false, $eta_min = false) {
+ /** @deprecated by TimeHelper::smart_date_time() */
+ function smart_date_time(int $timestamp, int $tz_offset = 0, int $owner_uid = null, bool $eta_min = false): string {
return TimeHelper::smart_date_time($timestamp, $tz_offset, $owner_uid, $eta_min);
}
- /** function is @deprecated by TimeHelper::make_local_datetime() */
- function make_local_datetime($timestamp, $long, $owner_uid = false, $no_smart_dt = false, $eta_min = false) {
+ /** @deprecated by TimeHelper::make_local_datetime() */
+ function make_local_datetime(string $timestamp, bool $long, int $owner_uid = null, bool $no_smart_dt = false, bool $eta_min = false): string {
return TimeHelper::make_local_datetime($timestamp, $long, $owner_uid, $no_smart_dt, $eta_min);
}
// this returns Config::SELF_URL_PATH sans ending slash
- /** function is @deprecated by Config::get_self_url() */
- function get_self_url_prefix() {
+ /** @deprecated by Config::get_self_url() */
+ function get_self_url_prefix(): string {
return Config::get_self_url();
}
/* end compat shims */
- // this is used for user http parameters unless HTML code is actually needed
+ /**
+ * This is used for user http parameters unless HTML code is actually needed.
+ *
+ * @param mixed $param
+ *
+ * @return mixed|null
+ */
function clean($param) {
if (is_array($param)) {
return array_map("trim", array_map("strip_tags", $param));
@@ -244,7 +293,7 @@
}
}
- function make_password($length = 12) {
+ function make_password(int $length = 12): string {
$password = "";
$possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ*%+^";
@@ -269,11 +318,11 @@
return $password;
}
- function validate_csrf($csrf_token) {
+ function validate_csrf(?string $csrf_token): bool {
return isset($csrf_token) && hash_equals($_SESSION['csrf_token'] ?? "", $csrf_token);
}
- function truncate_string($str, $max_len, $suffix = '&hellip;') {
+ function truncate_string(string $str, int $max_len, string $suffix = '&hellip;'): string {
if (mb_strlen($str, "utf-8") > $max_len) {
return mb_substr($str, 0, $max_len, "utf-8") . $suffix;
} else {
@@ -281,7 +330,7 @@
}
}
- function mb_substr_replace($original, $replacement, $position, $length) {
+ function mb_substr_replace(string $original, string $replacement, int $position, int $length): string {
$startString = mb_substr($original, 0, $position, "UTF-8");
$endString = mb_substr($original, $position + $length, mb_strlen($original), "UTF-8");
@@ -290,7 +339,7 @@
return $out;
}
- function truncate_middle($str, $max_len, $suffix = '&hellip;') {
+ function truncate_middle(string $str, int $max_len, string $suffix = '&hellip;'): string {
if (mb_strlen($str) > $max_len) {
return mb_substr_replace($str, $suffix, $max_len / 2, mb_strlen($str) - $max_len);
} else {
@@ -298,15 +347,20 @@
}
}
- function sql_bool_to_bool($s) {
+ /** Convert values accepted by tt-rss as true/false to PHP booleans
+ * @see https://tt-rss.org/wiki/ApiReference#boolean-values
+ * @param null|string $s null values are considered false
+ * @return bool
+ */
+ function sql_bool_to_bool(?string $s): bool {
return $s && ($s !== "f" && $s !== "false"); //no-op for PDO, backwards compat for legacy layer
}
- function bool_to_sql_bool($s) {
+ function bool_to_sql_bool(bool $s): int {
return $s ? 1 : 0;
}
- function file_is_locked($filename) {
+ function file_is_locked(string $filename): bool {
if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/$filename")) {
if (function_exists('flock')) {
$fp = @fopen(Config::get(Config::LOCK_DIRECTORY) . "/$filename", "r");
@@ -328,7 +382,10 @@
}
}
- function make_lockfile($filename) {
+ /**
+ * @return resource|false A file pointer resource on success, or false on error.
+ */
+ function make_lockfile(string $filename) {
$fp = fopen(Config::get(Config::LOCK_DIRECTORY) . "/$filename", "w");
if ($fp && flock($fp, LOCK_EX | LOCK_NB)) {
@@ -352,38 +409,44 @@
}
}
- function checkbox_to_sql_bool($val) {
+ /**
+ * @param mixed $val
+ */
+ function checkbox_to_sql_bool($val): int {
return ($val == "on") ? 1 : 0;
}
- function uniqid_short() {
+ function uniqid_short(): string {
return uniqid(base_convert((string)rand(), 10, 36));
}
- function T_sprintf() {
+ function T_sprintf(): string {
$args = func_get_args();
return vsprintf(__(array_shift($args)), $args);
}
- function T_nsprintf() {
+ function T_nsprintf(): string {
$args = func_get_args();
return vsprintf(_ngettext(array_shift($args), array_shift($args), array_shift($args)), $args);
}
- function init_plugins() {
+ function init_plugins(): bool {
PluginHost::getInstance()->load(Config::get(Config::PLUGINS), PluginHost::KIND_ALL);
return true;
}
if (!function_exists('gzdecode')) {
- function gzdecode($string) { // no support for 2nd argument
+ /**
+ * @return false|string The decoded string or false if an error occurred.
+ */
+ function gzdecode(string $string) { // no support for 2nd argument
return file_get_contents('compress.zlib://data:who/cares;base64,'.
base64_encode($string));
}
}
- function get_random_bytes($length) {
+ function get_random_bytes(int $length): string {
if (function_exists('random_bytes')) {
return random_bytes($length);
} else if (function_exists('openssl_random_pseudo_bytes')) {
@@ -398,7 +461,7 @@
}
}
- function read_stdin() {
+ function read_stdin(): ?string {
$fp = fopen("php://stdin", "r");
if ($fp) {
@@ -410,11 +473,19 @@
return null;
}
- function implements_interface($class, $interface) {
- return in_array($interface, class_implements($class));
+ /**
+ * @param object|string $class
+ */
+ function implements_interface($class, string $interface): bool {
+ $class_implemented_interfaces = class_implements($class);
+
+ if ($class_implemented_interfaces) {
+ return in_array($interface, $class_implemented_interfaces);
+ }
+ return false;
}
- function get_theme_path($theme) {
+ function get_theme_path(string $theme): string {
$check = "themes/$theme";
if (file_exists($check)) return $check;
@@ -424,15 +495,18 @@
return "";
}
- function theme_exists($theme) {
+ function theme_exists(string $theme): bool {
return file_exists("themes/$theme") || file_exists("themes.local/$theme");
}
- function arr_qmarks($arr) {
+ /**
+ * @param array<int, mixed> $arr
+ */
+ function arr_qmarks(array $arr): string {
return str_repeat('?,', count($arr) - 1) . '?';
}
- function get_scripts_timestamp() {
+ function get_scripts_timestamp(): int {
$files = glob("js/*.js");
$ts = 0;
diff --git a/include/sessions.php b/include/sessions.php
index 7f61f6dbe..48afd0a8b 100644
--- a/include/sessions.php
+++ b/include/sessions.php
@@ -1,6 +1,8 @@
<?php
namespace Sessions;
+ use UserHelper;
+
require_once "autoload.php";
require_once "functions.php";
require_once "errorhandler.php";
@@ -19,7 +21,17 @@
ini_set("session.gc_maxlifetime", $session_expire);
ini_set("session.cookie_lifetime", "0");
- function validate_session() {
+ // prolong PHP session cookie
+ if (isset($_COOKIE[$session_name]))
+ setcookie($session_name,
+ $_COOKIE[$session_name],
+ time() + $session_expire,
+ ini_get("session.cookie_path"),
+ ini_get("session.cookie_domain"),
+ ini_get("session.cookie_secure"),
+ ini_get("session.cookie_httponly"));
+
+ function validate_session(): bool {
if (\Config::get(\Config::SINGLE_USER_MODE)) return true;
$pdo = \Db::pdo();
@@ -32,6 +44,11 @@
$_SESSION["login_error_msg"] = __("Session failed to validate (password changed)");
return false;
}
+
+ if ($user->access_level == UserHelper::ACCESS_LEVEL_DISABLED) {
+ $_SESSION["login_error_msg"] = __("Session failed to validate (account is disabled)");
+ return false;
+ }
} else {
$_SESSION["login_error_msg"] = __("Session failed to validate (user not found)");
return false;
@@ -41,11 +58,11 @@
return true;
}
- function ttrss_open ($s, $n) {
+ function ttrss_open(string $savePath, string $sessionName): bool {
return true;
}
- function ttrss_read ($id){
+ function ttrss_read(string $id): string {
global $session_expire;
$sth = \Db::pdo()->prepare("SELECT data FROM ttrss_sessions WHERE id=?");
@@ -67,7 +84,7 @@
}
- function ttrss_write ($id, $data) {
+ function ttrss_write(string $id, string $data): bool {
global $session_expire;
$data = base64_encode($data);
@@ -88,18 +105,18 @@
return true;
}
- function ttrss_close () {
+ function ttrss_close(): bool {
return true;
}
- function ttrss_destroy($id) {
+ function ttrss_destroy(string $id): bool {
$sth = \Db::pdo()->prepare("DELETE FROM ttrss_sessions WHERE id = ?");
$sth->execute([$id]);
return true;
}
- function ttrss_gc ($expire) {
+ function ttrss_gc(int $lifetime): bool {
\Db::pdo()->query("DELETE FROM ttrss_sessions WHERE expire < " . time());
return true;
@@ -109,7 +126,10 @@
session_set_save_handler('\Sessions\ttrss_open',
'\Sessions\ttrss_close', '\Sessions\ttrss_read',
'\Sessions\ttrss_write', '\Sessions\ttrss_destroy',
- '\Sessions\ttrss_gc');
+ '\Sessions\ttrss_gc'); // @phpstan-ignore-line
+ // PHPStan complains about '\Sessions\ttrss_gc' if its $lifetime param isn't marked as string,
+ // but the docs say it's an int. If it is actually a string it'll get coerced to an int.
+
register_shutdown_function('session_write_close');
if (!defined('NO_SESSION_AUTOSTART')) {