From b1d24fbdb7d1cc948c946295035dad6df550fb7e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 27 Dec 2024 12:12:49 +0100 Subject: PHPStan 2.0 (#7131) * PHPStan 2.0 fix https://github.com/FreshRSS/FreshRSS/issues/6989 https://github.com/phpstan/phpstan/releases/tag/2.0.0 https://github.com/phpstan/phpstan/blob/2.0.x/UPGRADING.md * More * More * Done * fix i18n CLI * Restore a PHPStan Next test For work towards PHPStan Level 10 * 4 more on Level 10 * fix getTagsForEntry * API at Level 10 * More Level 10 * Finish Minz at Level 10 * Finish CLI at Level 10 * Finish Controllers at Level 10 * More Level 10 * More * Pass bleedingEdge * Clean PHPStan options and add TODOs * Level 10 for main config * More * Consitency array vs. list * Sanitize themes get_infos * Simplify TagDAO->getTagsForEntries() * Finish reportAnyTypeWideningInVarTag * Prepare checkBenevolentUnionTypes and checkImplicitMixed * Fixes * Refix * Another fix * Casing of __METHOD__ constant --- p/api/fever.php | 68 +++++++++---------- p/api/greader.php | 197 +++++++++++++++++++++++++++--------------------------- p/api/pshb.php | 4 +- p/api/query.php | 4 +- p/f.php | 2 +- 5 files changed, 136 insertions(+), 139 deletions(-) (limited to 'p') diff --git a/p/api/fever.php b/p/api/fever.php index 7bab2ce5d..92523db06 100644 --- a/p/api/fever.php +++ b/p/api/fever.php @@ -31,7 +31,7 @@ Minz_Session::init('FreshRSS', true); // ================================================================================================ // -$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1_048_576) ?: '';; +$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1_048_576) ?: ''; function debugInfo(): string { if (function_exists('getallheaders')) { @@ -39,7 +39,7 @@ function debugInfo(): string { } else { //nginx http://php.net/getallheaders#84262 $ALL_HEADERS = []; foreach ($_SERVER as $name => $value) { - if (str_starts_with($name, 'HTTP_')) { + if (is_string($name) && str_starts_with($name, 'HTTP_')) { $ALL_HEADERS[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } } @@ -120,6 +120,8 @@ final class FeverDAO extends Minz_ModelPdo $entries = []; foreach ($result as $dao) { + /** @var array{id?:string,id_feed?:int,guid?:string,title?:string,author?:string,content?:string,link?:string,date?:int|string,lastSeen?:int, + * hash?:string,is_read?:bool|int,is_favorite?:bool|int,tags?:string|array,attributes?:?string,thumbnail?:string,timestamp?:string} $dao */ $entries[] = FreshRSS_Entry::fromArray($dao); } @@ -151,7 +153,7 @@ final class FeverAPI private function authenticate(): bool { FreshRSS_Context::clearUserConf(); Minz_User::change(); - $feverKey = empty($_POST['api_key']) ? '' : substr(trim($_POST['api_key']), 0, 128); + $feverKey = empty($_POST['api_key']) || !is_string($_POST['api_key']) ? '' : substr(trim($_POST['api_key']), 0, 128); if (ctype_xdigit($feverKey)) { $feverKey = strtolower($feverKey); $username = @file_get_contents(DATA_PATH . '/fever/.key-' . sha1(FreshRSS_Context::systemConf()->salt) . '-' . $feverKey . '.txt', false); @@ -223,9 +225,9 @@ final class FeverAPI $response_arr['saved_item_ids'] = $this->getSavedItemIds(); } - if (isset($_REQUEST['mark'], $_REQUEST['as'], $_REQUEST['id']) && ctype_digit($_REQUEST['id'])) { - $id = (string)$_REQUEST['id']; - $before = (int)($_REQUEST['before'] ?? '0'); + if (is_string($_REQUEST['mark'] ?? null) && is_string($_REQUEST['as'] ?? null) && is_string($_REQUEST['id'] ?? null) && ctype_digit($_REQUEST['id'])) { + $id = $_REQUEST['id']; + $before = is_numeric($_REQUEST['before'] ?? null) ? (int)$_REQUEST['before'] : 0; switch (strtolower($_REQUEST['mark'])) { case 'item': switch ($_REQUEST['as']) { @@ -306,7 +308,7 @@ final class FeverAPI return $lastUpdate; } - /** @return array> */ + /** @return list */ private function getFeeds(): array { $feeds = []; $myFeeds = $this->feedDAO->listFeeds(); @@ -328,7 +330,7 @@ final class FeverAPI return $feeds; } - /** @return array> */ + /** @return list */ private function getGroups(): array { $groups = []; @@ -345,7 +347,7 @@ final class FeverAPI return $groups; } - /** @return array> */ + /** @return list */ private function getFavicons(): array { if (!FreshRSS_Context::hasSystemConf()) { return []; @@ -378,7 +380,7 @@ final class FeverAPI } /** - * @return array> + * @return list> */ private function getFeedsGroup(): array { $groups = []; @@ -401,7 +403,7 @@ final class FeverAPI /** * AFAIK there is no 'hot links' alternative in FreshRSS - * @return array + * @return list */ private function getLinks(): array { return []; @@ -452,46 +454,42 @@ final class FeverAPI return $this->entryDAO->markFavorite($id, false); } - /** @return array> */ + /** @return list> */ private function getItems(): array { $feed_ids = []; $entry_ids = []; $max_id = ''; $since_id = ''; - if (isset($_REQUEST['feed_ids']) || isset($_REQUEST['group_ids'])) { - if (isset($_REQUEST['feed_ids'])) { - $feed_ids = explode(',', $_REQUEST['feed_ids']); - } - - if (isset($_REQUEST['group_ids'])) { - $categoryDAO = FreshRSS_Factory::createCategoryDao(); - $group_ids = explode(',', $_REQUEST['group_ids']); - $feeds = []; - foreach ($group_ids as $id) { - $category = $categoryDAO->searchById((int)$id); //TODO: Transform to SQL query without loop! Consider FreshRSS_CategoryDAO::listCategories(true) - if ($category == null) { - continue; - } - foreach ($category->feeds() as $feed) { - $feeds[] = $feed->id(); - } + if (is_string($_REQUEST['feed_ids'] ?? null)) { + $feed_ids = explode(',', $_REQUEST['feed_ids']); + } elseif (is_string($_REQUEST['group_ids'] ?? null)) { + $categoryDAO = FreshRSS_Factory::createCategoryDao(); + $group_ids = explode(',', $_REQUEST['group_ids']); + $feeds = []; + foreach ($group_ids as $id) { + $category = $categoryDAO->searchById((int)$id); //TODO: Transform to SQL query without loop! Consider FreshRSS_CategoryDAO::listCategories(true) + if ($category == null) { + continue; + } + foreach ($category->feeds() as $feed) { + $feeds[] = $feed->id(); } - $feed_ids = array_unique($feeds); } + $feed_ids = array_unique($feeds); } - if (isset($_REQUEST['max_id'])) { + if (is_string($_REQUEST['max_id'] ?? null)) { // use the max_id argument to request the previous $item_limit items - $max_id = '' . $_REQUEST['max_id']; + $max_id = $_REQUEST['max_id']; if (!ctype_digit($max_id)) { $max_id = ''; } - } elseif (isset($_REQUEST['with_ids'])) { + } elseif (is_string($_REQUEST['with_ids'] ?? null)) { $entry_ids = explode(',', $_REQUEST['with_ids']); - } elseif (isset($_REQUEST['since_id'])) { + } elseif (is_string($_REQUEST['since_id'] ?? null)) { // use the since_id argument to request the next $item_limit items - $since_id = '' . $_REQUEST['since_id']; + $since_id = $_REQUEST['since_id']; if (!ctype_digit($since_id)) { $since_id = ''; } diff --git a/p/api/greader.php b/p/api/greader.php index dd3b78235..9769f66cb 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -28,8 +28,6 @@ Server-side API compatible with Google Reader API layer 2 require(__DIR__ . '/../../constants.php'); require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader -$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576) ?: ''; - if (PHP_INT_SIZE < 8) { //32-bit /** @return numeric-string */ function hex2dec(string $hex): string { @@ -53,13 +51,13 @@ const JSON_OPTIONS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; function headerVariable(string $headerName, string $varName): string { $header = ''; $upName = 'HTTP_' . strtoupper($headerName); - if (isset($_SERVER[$upName])) { + if (is_string($_SERVER[$upName] ?? null)) { $header = '' . $_SERVER[$upName]; - } elseif (isset($_SERVER['REDIRECT_' . $upName])) { + } elseif (is_string($_SERVER['REDIRECT_' . $upName] ?? null)) { $header = '' . $_SERVER['REDIRECT_' . $upName]; } elseif (function_exists('getallheaders')) { $ALL_HEADERS = getallheaders(); - if (isset($ALL_HEADERS[$headerName])) { + if (is_string($ALL_HEADERS[$headerName] ?? null)) { $header = '' . $ALL_HEADERS[$headerName]; } } @@ -70,47 +68,47 @@ function headerVariable(string $headerName, string $varName): string { return is_string($pairs[$varName]) ? $pairs[$varName] : ''; } -/** @return array */ -function multiplePosts(string $name): array { - //https://bugs.php.net/bug.php?id=51633 - global $ORIGINAL_INPUT; - $inputs = explode('&', $ORIGINAL_INPUT); - $result = []; - $prefix = $name . '='; - $prefixLength = strlen($prefix); - foreach ($inputs as $input) { - if (str_starts_with($input, $prefix)) { - $result[] = urldecode(substr($input, $prefixLength)); +final class GReaderAPI { + + private static string $ORIGINAL_INPUT = ''; + + /** @return list */ + private static function multiplePosts(string $name): array { + //https://bugs.php.net/bug.php?id=51633 + $inputs = explode('&', self::$ORIGINAL_INPUT); + $result = []; + $prefix = $name . '='; + $prefixLength = strlen($prefix); + foreach ($inputs as $input) { + if (str_starts_with($input, $prefix)) { + $result[] = urldecode(substr($input, $prefixLength)); + } } + return $result; } - return $result; -} -function debugInfo(): string { - if (function_exists('getallheaders')) { - $ALL_HEADERS = getallheaders(); - } else { //nginx http://php.net/getallheaders#84262 - $ALL_HEADERS = []; - foreach ($_SERVER as $name => $value) { - if (str_starts_with($name, 'HTTP_')) { - $ALL_HEADERS[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; + private static function debugInfo(): string { + if (function_exists('getallheaders')) { + $ALL_HEADERS = getallheaders(); + } else { //nginx http://php.net/getallheaders#84262 + $ALL_HEADERS = []; + foreach ($_SERVER as $name => $value) { + if (is_string($name) && str_starts_with($name, 'HTTP_')) { + $ALL_HEADERS[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; + } } } + $log = sensitive_log([ + 'date' => date('c'), + 'headers' => $ALL_HEADERS, + '_SERVER' => $_SERVER, + '_GET' => $_GET, + '_POST' => $_POST, + '_COOKIE' => $_COOKIE, + 'INPUT' => self::$ORIGINAL_INPUT, + ]); + return print_r($log, true); } - global $ORIGINAL_INPUT; - $log = sensitive_log([ - 'date' => date('c'), - 'headers' => $ALL_HEADERS, - '_SERVER' => $_SERVER, - '_GET' => $_GET, - '_POST' => $_POST, - '_COOKIE' => $_COOKIE, - 'INPUT' => $ORIGINAL_INPUT, - ]); - return print_r($log, true); -} - -final class GReaderAPI { private static function noContent(): never { header('HTTP/1.1 204 No Content'); @@ -119,7 +117,7 @@ final class GReaderAPI { private static function badRequest(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('HTTP/1.1 400 Bad Request'); header('Content-Type: text/plain; charset=UTF-8'); die('Bad Request!'); @@ -127,7 +125,7 @@ final class GReaderAPI { private static function unauthorized(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('HTTP/1.1 401 Unauthorized'); header('Content-Type: text/plain; charset=UTF-8'); header('Google-Bad-Token: true'); @@ -136,7 +134,7 @@ final class GReaderAPI { private static function internalServerError(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('HTTP/1.1 500 Internal Server Error'); header('Content-Type: text/plain; charset=UTF-8'); die('Internal Server Error!'); @@ -144,7 +142,7 @@ final class GReaderAPI { private static function notImplemented(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('HTTP/1.1 501 Not Implemented'); header('Content-Type: text/plain; charset=UTF-8'); die('Not Implemented!'); @@ -152,7 +150,7 @@ final class GReaderAPI { private static function serviceUnavailable(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('HTTP/1.1 503 Service Unavailable'); header('Content-Type: text/plain; charset=UTF-8'); die('Service Unavailable!'); @@ -160,7 +158,7 @@ final class GReaderAPI { private static function checkCompatibility(): never { Minz_Log::warning(__METHOD__, API_LOG); - Minz_Log::debug(__METHOD__ . ' ' . debugInfo(), API_LOG); + Minz_Log::debug(__METHOD__ . ' ' . self::debugInfo(), API_LOG); header('Content-Type: text/plain; charset=UTF-8'); if (PHP_INT_SIZE < 8 && !function_exists('gmp_init')) { die('FAIL 64-bit or GMP extension! Wrong PHP configuration.'); @@ -365,9 +363,9 @@ final class GReaderAPI { } /** - * @param array $streamNames StreamId(s) to operate on. The parameter may be repeated to edit multiple subscriptions at once - * @param array $titles Title(s) to use for the subscription(s). Each title is associated with the corresponding streamName - * @param 'subscribe'|'unsubscribe'|'edit' $action + * @param list $streamNames StreamId(s) to operate on. The parameter may be repeated to edit multiple subscriptions at once + * @param list $titles Title(s) to use for the subscription(s). Each title is associated with the corresponding streamName + * @param string $action 'subscribe'|'unsubscribe'|'edit' * @param string $add StreamId to add the subscription(s) to (generally a category) * @param string $remove StreamId to remove the subscription(s) from (generally a category) */ @@ -544,8 +542,8 @@ final class GReaderAPI { } /** - * @param array $entries - * @return array> + * @param list $entries + * @return list> */ private static function entriesToArray(array $entries): array { if (empty($entries)) { @@ -668,7 +666,7 @@ final class GReaderAPI { $entryDAO = FreshRSS_Factory::createEntryDao(); $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, 0, $continuation, $searches); - $entries = iterator_to_array($entries); //TODO: Improve + $entries = array_values(iterator_to_array($entries)); //TODO: Improve $items = self::entriesToArray($entries); @@ -754,7 +752,7 @@ final class GReaderAPI { } /** - * @param array $e_ids + * @param list $e_ids */ private static function streamContentsItems(array $e_ids, string $order): never { header('Content-Type: application/json; charset=UTF-8'); @@ -765,11 +763,11 @@ final class GReaderAPI { $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' } } - /** @var array $e_ids */ + /** @var list $e_ids */ $entryDAO = FreshRSS_Factory::createEntryDao(); $entries = $entryDAO->listByIds($e_ids, $order === 'o' ? 'ASC' : 'DESC'); - $entries = iterator_to_array($entries); //TODO: Improve + $entries = array_values(iterator_to_array($entries)); //TODO: Improve $items = self::entriesToArray($entries); @@ -785,9 +783,9 @@ final class GReaderAPI { } /** - * @param array $e_ids IDs of the items to edit - * @param array $as tags to add to all the listed items - * @param array $rs tags to remove from all the listed items + * @param list $e_ids IDs of the items to edit + * @param list $as tags to add to all the listed items + * @param list $rs tags to remove from all the listed items */ private static function editTag(array $e_ids, array $as, array $rs): never { foreach ($e_ids as $i => $e_id) { @@ -795,7 +793,7 @@ final class GReaderAPI { $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' } } - /** @var array $e_ids */ + /** @var list $e_ids */ $entryDAO = FreshRSS_Factory::createEntryDao(); $tagDAO = FreshRSS_Factory::createTagDao(); @@ -960,8 +958,6 @@ final class GReaderAPI { } public static function parse(): never { - global $ORIGINAL_INPUT; - header('Access-Control-Allow-Headers: Authorization'); header('Access-Control-Allow-Methods: GET, POST'); header('Access-Control-Allow-Origin: *'); @@ -971,8 +967,8 @@ final class GReaderAPI { } $pathInfo = ''; - if (empty($_SERVER['PATH_INFO'])) { - if (!empty($_SERVER['ORIG_PATH_INFO'])) { + if (empty($_SERVER['PATH_INFO']) || !is_string($_SERVER['PATH_INFO'])) { + if (!empty($_SERVER['ORIG_PATH_INFO']) && is_string($_SERVER['ORIG_PATH_INFO'])) { // Compatibility https://php.net/reserved.variables.server $pathInfo = $_SERVER['ORIG_PATH_INFO']; } @@ -992,7 +988,7 @@ final class GReaderAPI { FreshRSS_Context::initSystem(); //Minz_Log::debug('----------------------------------------------------------------', API_LOG); - //Minz_Log::debug(debugInfo(), API_LOG); + //Minz_Log::debug(self::debugInfo(), API_LOG); if (!FreshRSS_Context::hasSystemConf() || !FreshRSS_Context::systemConf()->api_enabled) { self::serviceUnavailable(); @@ -1013,15 +1009,18 @@ final class GReaderAPI { Minz_Translate::init(); } + self::$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576) ?: ''; + if ($pathInfos[1] === 'accounts') { - if (($pathInfos[2] === 'ClientLogin') && isset($_REQUEST['Email']) && isset($_REQUEST['Passwd'])) { + if (($pathInfos[2] === 'ClientLogin') && is_string($_REQUEST['Email'] ?? null) && is_string($_REQUEST['Passwd'] ?? null)) { self::clientLogin($_REQUEST['Email'], $_REQUEST['Passwd']); } } elseif (isset($pathInfos[3], $pathInfos[4]) && $pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && $pathInfos[3] === '0') { if (Minz_User::name() === null) { self::unauthorized(); } - $timestamp = isset($_GET['ck']) ? (int)$_GET['ck'] : 0; //ck=[unix timestamp] : Use the current Unix time here, helps Google with caching. + // ck=[unix timestamp]: Use the current Unix time here, helps Google with caching + $timestamp = is_numeric($_GET['ck'] ?? null) ? (int)$_GET['ck'] : 0; switch ($pathInfos[4]) { case 'stream': /** @@ -1031,41 +1030,41 @@ final class GReaderAPI { * exclude items from a particular feed (obviously not useful in this request, * but xt appears in other listing requests). */ - $exclude_target = $_GET['xt'] ?? ''; - $filter_target = $_GET['it'] ?? ''; + $exclude_target = is_string($_GET['xt'] ?? null) ? $_GET['xt'] : ''; + $filter_target = is_string($_GET['it'] ?? null) ? $_GET['it'] : ''; //n=[integer] : The maximum number of results to return. - $count = isset($_GET['n']) ? (int)$_GET['n'] : 20; + $count = is_numeric($_GET['n'] ?? null) ? (int)$_GET['n'] : 20; //r=[d|n|o] : Sort order of item results. d or n gives items in descending date order, o in ascending order. - $order = $_GET['r'] ?? 'd'; + $order = is_string($_GET['r'] ?? null) ? $_GET['r'] : 'd'; /** * ot=[unix timestamp] : The time from which you want to retrieve items. * Only items that have been crawled by Google Reader after this time will be returned. */ - $start_time = isset($_GET['ot']) ? (int)$_GET['ot'] : 0; - $stop_time = isset($_GET['nt']) ? (int)$_GET['nt'] : 0; + $start_time = is_numeric($_GET['ot'] ?? null) ? (int)$_GET['ot'] : 0; + $stop_time = is_numeric($_GET['nt'] ?? null) ? (int)$_GET['nt'] : 0; /** * Continuation token. If a StreamContents response does not represent * all items in a timestamp range, it will have a continuation attribute. * The same request can be re-issued with the value of that attribute put * in this parameter to get more items */ - $continuation = isset($_GET['c']) ? trim((string)$_GET['c']) : ''; + $continuation = is_string($_GET['c'] ?? null) ? trim($_GET['c']) : ''; if (!ctype_digit($continuation)) { $continuation = ''; } if (isset($pathInfos[5]) && $pathInfos[5] === 'contents') { - if (!isset($pathInfos[6]) && isset($_GET['s'])) { + if (!isset($pathInfos[6]) && is_string($_GET['s'] ?? null)) { // Compatibility BazQux API https://github.com/bazqux/bazqux-api#fetching-streams $streamIdInfos = explode('/', $_GET['s']); foreach ($streamIdInfos as $streamIdInfo) { $pathInfos[] = $streamIdInfo; } } - if (isset($pathInfos[6]) && isset($pathInfos[7])) { + if (isset($pathInfos[6], $pathInfos[7])) { if ($pathInfos[6] === 'feed') { $include_target = $pathInfos[7]; - if ($include_target != '' && !is_numeric($include_target)) { - $include_target = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI']; + if ($include_target !== '' && !is_numeric($include_target)) { + $include_target = empty($_SERVER['REQUEST_URI']) || !is_string($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI']; if (preg_match('#/reader/api/0/stream/contents/feed/([A-Za-z0-9\'!*()%$_.~+-]+)#', $include_target, $matches) === 1) { $include_target = urldecode($matches[1]); } else { @@ -1095,13 +1094,13 @@ final class GReaderAPI { $count, $order, $filter_target, $exclude_target, $continuation); } } elseif ($pathInfos[5] === 'items') { - if ($pathInfos[6] === 'ids' && isset($_GET['s'])) { + if ($pathInfos[6] === 'ids' && is_string($_GET['s'] ?? null)) { // StreamId for which to fetch the item IDs. // TODO: support multiple streams $streamId = $_GET['s']; self::streamContentsItemsIds($streamId, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } elseif ($pathInfos[6] === 'contents' && isset($_POST['i'])) { //FeedMe - $e_ids = multiplePosts('i'); //item IDs + $e_ids = self::multiplePosts('i'); //item IDs self::streamContentsItems($e_ids, $order); } } @@ -1120,8 +1119,8 @@ final class GReaderAPI { self::subscriptionExport(); // Always exits case 'import': - if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' && $ORIGINAL_INPUT != '') { - self::subscriptionImport($ORIGINAL_INPUT); + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST' && self::$ORIGINAL_INPUT != '') { + self::subscriptionImport(self::$ORIGINAL_INPUT); } break; case 'list': @@ -1132,23 +1131,23 @@ final class GReaderAPI { case 'edit': if (isset($_REQUEST['s'], $_REQUEST['ac'])) { // StreamId to operate on. The parameter may be repeated to edit multiple subscriptions at once - $streamNames = empty($_POST['s']) && isset($_GET['s']) ? [$_GET['s']] : multiplePosts('s'); + $streamNames = empty($_POST['s']) && is_string($_GET['s'] ?? null) ? [$_GET['s']] : self::multiplePosts('s'); /* Title to use for the subscription. For the `subscribe` action, * if not specified then the feed’s current title will be used. Can * be used with the `edit` action to rename a subscription */ - $titles = empty($_POST['t']) && isset($_GET['t']) ? [$_GET['t']] : multiplePosts('t'); + $titles = empty($_POST['t']) && is_string($_GET['t'] ?? null) ? [$_GET['t']] : self::multiplePosts('t'); // Action to perform on the given StreamId. Possible values are `subscribe`, `unsubscribe` and `edit` - $action = $_REQUEST['ac']; + $action = is_string($_REQUEST['ac'] ?? null) ? $_REQUEST['ac'] : ''; // StreamId to add the subscription to (generally a user label) // (in FreshRSS, we do not support repeated values since a feed can only be in one category) - $add = $_REQUEST['a'] ?? ''; + $add = is_string($_REQUEST['a'] ?? null) ? $_REQUEST['a'] : ''; // StreamId to remove the subscription from (generally a user label) (in FreshRSS, we do not support repeated values) - $remove = $_REQUEST['r'] ?? ''; + $remove = is_string($_REQUEST['r'] ?? null) ? $_REQUEST['r'] : ''; self::subscriptionEdit($streamNames, $titles, $action, $add, $remove); } break; case 'quickadd': //https://github.com/theoldreader/api - if (isset($_REQUEST['quickadd'])) { + if (is_string($_REQUEST['quickadd'] ?? null)) { self::quickadd($_REQUEST['quickadd']); } break; @@ -1161,35 +1160,35 @@ final class GReaderAPI { self::unreadCount(); // Always exits case 'edit-tag': // https://web.archive.org/web/20200616071132/https://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3 - $token = isset($_POST['T']) ? trim($_POST['T']) : ''; + $token = is_string($_POST['T'] ?? null) ? trim($_POST['T']) : ''; self::checkToken(FreshRSS_Context::userConf(), $token); // Add (Can be repeated to add multiple tags at once): user/-/state/com.google/read user/-/state/com.google/starred - $as = multiplePosts('a'); + $as = self::multiplePosts('a'); // Remove (Can be repeated to remove multiple tags at once): user/-/state/com.google/read user/-/state/com.google/starred - $rs = multiplePosts('r'); - $e_ids = multiplePosts('i'); //item IDs + $rs = self::multiplePosts('r'); + $e_ids = self::multiplePosts('i'); //item IDs self::editTag($e_ids, $as, $rs); // Always exits case 'rename-tag': //https://github.com/theoldreader/api - $token = isset($_POST['T']) ? trim($_POST['T']) : ''; + $token = is_string($_POST['T'] ?? null) ? trim($_POST['T']) : ''; self::checkToken(FreshRSS_Context::userConf(), $token); - $s = $_POST['s'] ?? ''; //user/-/label/Folder - $dest = $_POST['dest'] ?? ''; //user/-/label/NewFolder + $s = is_string($_POST['s'] ?? null) ? trim($_POST['s']) : ''; //user/-/label/Folder + $dest = is_string($_POST['dest'] ?? null) ? trim($_POST['dest']) : ''; //user/-/label/NewFolder self::renameTag($s, $dest); // Always exits case 'disable-tag': //https://github.com/theoldreader/api - $token = isset($_POST['T']) ? trim($_POST['T']) : ''; + $token = is_string($_POST['T'] ?? null) ? trim($_POST['T']) : ''; self::checkToken(FreshRSS_Context::userConf(), $token); - $s_s = multiplePosts('s'); + $s_s = self::multiplePosts('s'); foreach ($s_s as $s) { self::disableTag($s); //user/-/label/Folder } // Always exits case 'mark-all-as-read': - $token = isset($_POST['T']) ? trim($_POST['T']) : ''; + $token = is_string($_POST['T'] ?? null) ? trim($_POST['T']) : ''; self::checkToken(FreshRSS_Context::userConf(), $token); - $streamId = trim($_POST['s'] ?? ''); - $ts = trim($_POST['ts'] ?? '0'); //Older than timestamp in nanoseconds + $streamId = is_string($_POST['s'] ?? null) ? trim($_POST['s']) : ''; + $ts = is_string($_POST['ts'] ?? null) ? trim($_POST['ts']) : '0'; //Older than timestamp in nanoseconds if (!ctype_digit($ts)) { self::badRequest(); } diff --git a/p/api/pshb.php b/p/api/pshb.php index f8903d385..6b5bda4b5 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -19,7 +19,7 @@ FreshRSS_Context::systemConf()->auth_type = 'none'; // avoid necessity to be log // Minz_Log::debug(print_r(['_SERVER' => $_SERVER, '_GET' => $_GET, '_POST' => $_POST, 'INPUT' => $ORIGINAL_INPUT], true), PSHB_LOG); -$key = isset($_GET['k']) ? substr($_GET['k'], 0, 128) : ''; +$key = isset($_GET['k']) && is_string($_GET['k']) ? substr($_GET['k'], 0, 128) : ''; if (!ctype_xdigit($key)) { header('HTTP/1.1 422 Unprocessable Entity'); die('Invalid feed key format!'); @@ -67,7 +67,7 @@ if (empty($users)) { } if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'subscribe') { - $leaseSeconds = empty($_REQUEST['hub_lease_seconds']) ? 0 : (int)$_REQUEST['hub_lease_seconds']; + $leaseSeconds = empty($_REQUEST['hub_lease_seconds']) || !is_numeric($_REQUEST['hub_lease_seconds']) ? 0 : (int)$_REQUEST['hub_lease_seconds']; if ($leaseSeconds > 60) { $hubJson['lease_end'] = time() + $leaseSeconds; } else { diff --git a/p/api/query.php b/p/api/query.php index 00a04d083..1c2bda32d 100644 --- a/p/api/query.php +++ b/p/api/query.php @@ -134,7 +134,7 @@ switch ($type) { Minz_Error::error(404, "Category {$id} not found!"); die(); } - $view->categories = [ $cat->id() => $cat ]; + $view->categories = [ $cat ]; break; case 'f': // Feed $feed = FreshRSS_Category::findFeed(FreshRSS_Context::categories(), $id); @@ -142,7 +142,7 @@ switch ($type) { Minz_Error::error(404, "Feed {$id} not found!"); die(); } - $view->feeds = [ $feed->id() => $feed ]; + $view->feeds = [ $feed ]; $view->categories = []; break; default: diff --git a/p/f.php b/p/f.php index 1efcb97e5..1bf358a3d 100644 --- a/p/f.php +++ b/p/f.php @@ -15,7 +15,7 @@ function show_default_favicon(int $cacheSeconds = 3600): void { } $id = $_SERVER['QUERY_STRING'] ?? '0'; -if (!ctype_xdigit($id)) { +if (!is_string($id) || !ctype_xdigit($id)) { $id = '0'; } -- cgit v1.2.3