diff --git a/.phpstan.neon b/.phpstan.neon index fb731728b8..15d3ec15fb 100644 --- a/.phpstan.neon +++ b/.phpstan.neon @@ -2,6 +2,9 @@ # # SPDX-License-Identifier: CC0-1.0 +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + parameters: level: 3 @@ -23,6 +26,10 @@ parameters: dynamicConstantNames: - DB_UPDATE_VERSION + # See all rules at https://github.com/phpstan/phpstan-strict-rules/blob/2.0.x/rules.neon + strictRules: + allRules: false + ignoreErrors: - # Ignore missing GdImage class in PHP <= 7.4 diff --git a/composer.json b/composer.json index 9973336590..fc26674ca7 100644 --- a/composer.json +++ b/composer.json @@ -157,6 +157,7 @@ "php-mock/php-mock-phpunit": "^2.10", "phpmd/phpmd": "^2.15", "phpstan/phpstan": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9" }, "scripts": { diff --git a/composer.lock b/composer.lock index fb9fadddbd..ab66a33d05 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "897b878d6db24b9a6437bd9f971478be", + "content-hash": "e93a8ac7e31cf3e5e0ca76134e5ffa0b", "packages": [ { "name": "asika/simple-console", @@ -5849,6 +5849,54 @@ ], "time": "2024-11-11T15:43:04+00:00" }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.0" + }, + "time": "2024-10-26T16:04:33+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.31", diff --git a/src/Console/Worker.php b/src/Console/Worker.php index 97b7160d03..09ff5f6599 100644 --- a/src/Console/Worker.php +++ b/src/Console/Worker.php @@ -92,5 +92,7 @@ HELP; CoreWorker::unclaimProcess($process); $this->processRepo->delete($process); + + return; } } diff --git a/src/Content/Pager.php b/src/Content/Pager.php index 0cdf5c0e4a..222247c6f5 100644 --- a/src/Content/Pager.php +++ b/src/Content/Pager.php @@ -208,15 +208,15 @@ class Pager 'class' => $this->getPage() == 1 ? 'disabled' : '' ]; - $numpages = $totalItemCount / $this->getItemsPerPage(); + $numpages = (int) ceil($totalItemCount / $this->getItemsPerPage()); $numstart = 1; $numstop = $numpages; // Limit the number of displayed page number buttons. if ($numpages > 8) { - $numstart = (($this->getPage() > 4) ? ($this->getPage() - 4) : 1); - $numstop = (($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8)); + $numstart = ($this->getPage() > 4) ? ($this->getPage() - 4) : 1; + $numstop = ($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8); } $pages = []; @@ -237,22 +237,6 @@ class Pager } } - if (($totalItemCount % $this->getItemsPerPage()) != 0) { - if ($i == $this->getPage()) { - $pages[$i] = [ - 'url' => '#', - 'text' => $i, - 'class' => 'current active' - ]; - } else { - $pages[$i] = [ - 'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i), - 'text' => $i, - 'class' => 'n' - ]; - } - } - $data['pages'] = $pages; $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages); diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index 72c61f38cc..701125dd27 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -55,7 +55,7 @@ class HTML $xpath = new DOMXPath($doc); - /** @var \DOMNode[] $list */ + /** @var \DOMNodeList<\DOMNode>|false $list */ $list = $xpath->query("//" . $tag); foreach ($list as $node) { $attr = []; @@ -1018,7 +1018,7 @@ class HTML */ public static function checkRelMeLink(DOMDocument $doc, UriInterface $meUrl): bool { - $xpath = new \DOMXpath($doc); + $xpath = new \DOMXPath($doc); // This expression checks that "me" is among the space-delimited values of the "rel" attribute. // And that the href attribute contains exactly the provided URL diff --git a/src/Core/Lock/Type/AbstractLock.php b/src/Core/Lock/Type/AbstractLock.php index 9d8b5849b2..6854be267c 100644 --- a/src/Core/Lock/Type/AbstractLock.php +++ b/src/Core/Lock/Type/AbstractLock.php @@ -28,7 +28,7 @@ abstract class AbstractLock implements ICanLock */ protected function hasAcquiredLock(string $key): bool { - return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true; + return isset($this->acquiredLocks[$key]) && $this->acquiredLocks[$key] === true; } /** diff --git a/src/Core/Session/Handler/Cache.php b/src/Core/Session/Handler/Cache.php index 7629d9a164..65b87872a7 100644 --- a/src/Core/Session/Handler/Cache.php +++ b/src/Core/Session/Handler/Cache.php @@ -99,8 +99,11 @@ class Cache extends AbstractSessionHandler } #[\ReturnTypeWillChange] - public function gc($max_lifetime): bool + /** + * @return int|false + */ + public function gc($max_lifetime) { - return true; + return 0; // Cache does not support garbage collection, so we return 0 to indicate no action taken } } diff --git a/src/Core/Session/Handler/Database.php b/src/Core/Session/Handler/Database.php index 3ef64294b9..d8146139a1 100644 --- a/src/Core/Session/Handler/Database.php +++ b/src/Core/Session/Handler/Database.php @@ -124,13 +124,23 @@ class Database extends AbstractSessionHandler } #[\ReturnTypeWillChange] - public function gc($max_lifetime): bool + /** + * @return int|false + */ + public function gc($max_lifetime) { try { - return $this->dba->delete('session', ["`expire` < ?", time()]); + $result = $this->dba->delete('session', ["`expire` < ?", time()]); } catch (\Exception $exception) { $this->logger->warning('Cannot use garbage collector.', ['exception' => $exception]); return false; } + + if ($result !== false) { + // TODO: DBA::delete() returns true, but we need to return the number of deleted rows as interger + $result = 0; + } + + return $result; } } diff --git a/src/Core/Worker.php b/src/Core/Worker.php index fd33278502..fd2ab5c242 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -521,7 +521,7 @@ class Worker } if ($sleeping) { - DI::logger()->info('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]); + DI::logger()->info('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load ?? [], 'called-by' => System::callstack(1)]); } } diff --git a/src/Database/PostUpdate.php b/src/Database/PostUpdate.php index 6aebda8096..031c2fec1d 100644 --- a/src/Database/PostUpdate.php +++ b/src/Database/PostUpdate.php @@ -193,7 +193,7 @@ class PostUpdate Contact::removeDuplicates($contact['nurl'], $contact['uid']); } - DBA::close($contact); + DBA::close($contacts); DI::keyValue()->set('post_update_version', 1322); DI::logger()->info('Done'); diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 471f6e313a..92ee97b816 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -8,7 +8,7 @@ namespace Friendica\Network; use DOMDocument; -use DomXPath; +use DOMXPath; use Exception; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -1273,7 +1273,7 @@ class Probe return []; } - $xpath = new DomXPath($doc); + $xpath = new DOMXPath($doc); $vcards = $xpath->query("//div[contains(concat(' ', @class, ' '), ' vcard ')]"); if (!is_object($vcards)) { diff --git a/src/Object/Image.php b/src/Object/Image.php index 0aad761341..283a8d4895 100644 --- a/src/Object/Image.php +++ b/src/Object/Image.php @@ -363,12 +363,11 @@ class Image * Rotates image * * @param integer $degrees degrees to rotate image - * @return mixed */ - public function rotate(int $degrees) + public function rotate(int $degrees): void { if (!$this->isValid()) { - return false; + return; } if ($this->isImagick()) { @@ -393,12 +392,11 @@ class Image * * @param boolean $horiz optional, default true * @param boolean $vert optional, default false - * @return mixed */ - public function flip(bool $horiz = true, bool $vert = false) + public function flip(bool $horiz = true, bool $vert = false): void { if (!$this->isValid()) { - return false; + return; } if ($this->isImagick()) { diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index a779a59a86..c5a182f98e 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -592,7 +592,7 @@ class HTTPSignature return []; } - $sig_block = self::parseSigHeader($http_headers['HTTP_SIGNATURE']); + $sig_block = self::parseSigheader($http_headers['HTTP_SIGNATURE']); if (empty($sig_block['keyId'])) { DI::logger()->debug('No keyId', ['sig_block' => $sig_block]); @@ -652,7 +652,7 @@ class HTTPSignature } } - $sig_block = self::parseSigHeader($http_headers['HTTP_SIGNATURE']); + $sig_block = self::parseSigheader($http_headers['HTTP_SIGNATURE']); // Add fields from the signature block to the header. See issue 8845 if (!empty($sig_block['created']) && empty($headers['(created)'])) {