From cc47163eca8d86930ae92e255f3f7b577373a181 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 3 Sep 2026 15:49:34 +0200 Subject: [PATCH 1/5] feat: Add rector and psalm rules to enforce strict comparaison Signed-off-by: Carl Schwan --- build/psalm/InArrayStrictChecker.php | 56 ++++++++++++++++ build/psalm/UnstrictComparisonChecker.php | 78 +++++++++++++++++++++++ build/rector.php | 10 ++- psalm.xml | 2 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 build/psalm/InArrayStrictChecker.php create mode 100644 build/psalm/UnstrictComparisonChecker.php diff --git a/build/psalm/InArrayStrictChecker.php b/build/psalm/InArrayStrictChecker.php new file mode 100644 index 0000000000000..46ce36aaf4594 --- /dev/null +++ b/build/psalm/InArrayStrictChecker.php @@ -0,0 +1,56 @@ +getExpr(); + if (!$stmt instanceof FuncCall + || !$stmt->name instanceof Name + || strtolower($stmt->name->toString()) !== 'in_array') { + return null; + } + + $hasStrictArg = false; + foreach ($stmt->getArgs() as $index => $arg) { + if ($arg->name !== null) { + if ($arg->name->toString() === 'strict') { + $hasStrictArg = true; + break; + } + continue; + } + if ($index === 2) { + $hasStrictArg = true; + break; + } + } + + if (!$hasStrictArg) { + IssueBuffer::maybeAdd( + new \Psalm\Issue\UnrecognizedExpression( + 'in_array() must be called with an explicit $strict parameter', + new CodeLocation($event->getStatementsSource()->getSource(), $stmt), + ), + $event->getStatementsSource()->getSuppressedIssues(), + ); + } + + return null; + } +} diff --git a/build/psalm/UnstrictComparisonChecker.php b/build/psalm/UnstrictComparisonChecker.php new file mode 100644 index 0000000000000..cb6d3a0fab5ee --- /dev/null +++ b/build/psalm/UnstrictComparisonChecker.php @@ -0,0 +1,78 @@ +getExpr(); + if ($stmt instanceof VirtualNode) { + // Synthesized by Psalm itself (e.g. the implicit == of a switch/case), not written in the source + return null; + } + if (!$stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal + && !$stmt instanceof PhpParser\Node\Expr\BinaryOp\NotEqual) { + return null; + } + + if (self::isValueComparisonType($event, $stmt->left) && self::isValueComparisonType($event, $stmt->right)) { + return null; + } + + IssueBuffer::maybeAdd( + new \Psalm\Issue\UnrecognizedExpression( + 'Non-strict comparison operators == and != are not allowed in the Nextcloud codebase, use === and !== instead', + new CodeLocation($event->getStatementsSource()->getSource(), $stmt), + ), + $event->getStatementsSource()->getSuppressedIssues(), + ); + return null; + } + + private static function isValueComparisonType(AfterExpressionAnalysisEvent $event, PhpParser\Node\Expr $expr): bool { + $type = $event->getStatementsSource()->getNodeTypeProvider()->getType($expr); + $atomicTypes = $type?->getAtomicTypes() ?? []; + if ($atomicTypes === []) { + return false; + } + + foreach ($atomicTypes as $atomic) { + if (!$atomic instanceof TNamedObject) { + return false; + } + + $isAllowed = false; + foreach (self::VALUE_COMPARISON_CLASSES as $allowedClass) { + if (is_a($atomic->value, $allowedClass, true)) { + $isAllowed = true; + break; + } + } + if (!$isAllowed) { + return false; + } + } + + return true; + } +} diff --git a/build/rector.php b/build/rector.php index f3697174f2199..3664943504a56 100644 --- a/build/rector.php +++ b/build/rector.php @@ -7,6 +7,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +use Nextcloud\Rector\Rector\ReplaceInjectedMethodCallRector; +use Rector\CodeQuality\Rector\Equal\UseIdenticalOverEqualWithSameTypeRector; +use Rector\CodingStyle\Rector\FuncCall\StrictInArrayRector; use Rector\TypeDeclaration\Rector\StmtsAwareInterface\SafeDeclareStrictTypesRector; $nextcloudDir = dirname(__DIR__); @@ -33,5 +36,10 @@ ]) ->withTypeCoverageLevel(0) ->withRules([ - SafeDeclareStrictTypesRector::class + SafeDeclareStrictTypesRector::class, + StrictInArrayRector::class, + UseIdenticalOverEqualWithSameTypeRector::class, + ]) + ->withSkip([ + ReplaceInjectedMethodCallRector::class, ]); diff --git a/psalm.xml b/psalm.xml index 6e04adfaade86..3787cb9f0acad 100644 --- a/psalm.xml +++ b/psalm.xml @@ -22,6 +22,8 @@ + + From 01a1cdec9f6dbe5e93224c81a96ffe03e0f76914 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 3 Sep 2026 15:50:11 +0200 Subject: [PATCH 2/5] feat: run rector with new rules Signed-off-by: Carl Schwan --- apps/dav/appinfo/v1/publicwebdav.php | 3 ++- apps/dav/lib/CalDAV/CalDavBackend.php | 2 +- apps/dav/lib/CalDAV/EventReader.php | 2 +- .../Reminder/NotificationProvider/EmailProvider.php | 2 +- apps/dav/lib/Connector/Sabre/CachingTree.php | 2 +- apps/dav/lib/DAV/CustomPropertiesBackend.php | 6 +++--- apps/dav/lib/DAV/Sharing/Backend.php | 2 +- apps/dav/lib/SystemTag/SystemTagsInUseCollection.php | 2 +- apps/encryption/lib/Command/CleanOrphanedKeys.php | 4 ++-- apps/encryption/lib/Command/FixKeyLocation.php | 2 +- apps/files_external/tests/Storage/SmbTest.php | 2 +- apps/files_sharing/lib/SharedStorage.php | 3 ++- apps/files_trashbin/lib/Command/RestoreAllFiles.php | 2 +- apps/files_versions/lib/Versions/VersionManager.php | 2 +- .../lib/Controller/AppConfigController.php | 2 +- apps/theming/lib/Controller/ThemingController.php | 2 +- apps/user_ldap/lib/Access.php | 2 +- apps/workflowengine/lib/Check/AbstractStringCheck.php | 2 +- apps/workflowengine/lib/Check/RequestRemoteAddress.php | 2 +- build/integration/features/bootstrap/BasicStructure.php | 2 +- build/integration/features/bootstrap/FakeSMTPHelper.php | 2 +- .../integration/features/bootstrap/FederationContext.php | 4 ++-- build/integration/features/bootstrap/Sharing.php | 6 +++--- build/integration/features/bootstrap/WebDav.php | 2 +- core/Command/Base.php | 2 +- lib/private/App/AppStore/Bundles/HubBundle.php | 2 +- lib/private/App/PlatformRepository.php | 2 +- lib/private/AppConfig.php | 7 ++++--- lib/private/Archive/TAR.php | 2 +- lib/private/Config/ConfigManager.php | 4 ++-- lib/private/Config/UserConfig.php | 4 ++-- lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php | 2 +- lib/private/Files/Cache/Cache.php | 4 ++-- lib/private/Files/Storage/Local.php | 2 +- lib/private/Image.php | 2 +- lib/private/Net/HostnameClassifier.php | 2 +- lib/private/legacy/OC_App.php | 2 +- lib/private/legacy/OC_Util.php | 2 +- ocs/v1.php | 8 +++++--- tests/lib/AppFramework/Http/RequestStream.php | 2 +- tests/lib/Files/Storage/Storage.php | 4 ++-- tests/lib/Repair/RepairDavSharesTest.php | 2 +- 42 files changed, 61 insertions(+), 56 deletions(-) diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index 3db3578c7625f..d72929848a389 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -34,6 +34,7 @@ use OCP\L10N\IFactory as IL10nFactory; use OCP\Security\Bruteforce\IThrottler; use OCP\Server; +use OCP\Share\IShare; use Psr\Log\LoggerInterface; // load needed apps @@ -132,7 +133,7 @@ function (\Sabre\DAV\Server $server) use ( Filesystem::logWarningWhenAddingStorageWrapper($previousLog); $rootFolder = Server::get(IRootFolder::class); - $userId = $share->getShareType() === \OCP\Share\IShare::TYPE_REMOTE + $userId = $share->getShareType() === IShare::TYPE_REMOTE ? $share->getShareOwner() : $share->getSharedBy(); $userFolder = $rootFolder->getUserFolder($userId); diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index b3b9ebf4238bd..2f9c52b9367e0 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -2166,7 +2166,7 @@ public function calendarSearch($principalUri, array $filters, $limit = null, $of $result = []; while ($row = $stmt->fetchAssociative()) { $path = $uriMapper[$row['calendarid']] . '/' . $row['uri']; - if (!in_array($path, $result)) { + if (!in_array($path, $result, true)) { $result[] = $path; } } diff --git a/apps/dav/lib/CalDAV/EventReader.php b/apps/dav/lib/CalDAV/EventReader.php index 857148b2ffd94..375eaff12e43a 100644 --- a/apps/dav/lib/CalDAV/EventReader.php +++ b/apps/dav/lib/CalDAV/EventReader.php @@ -182,7 +182,7 @@ public function __construct(VCalendar|VEvent|array|string $input, ?string $uid = // evaluate if start date is floating // set duration to 24 hours and calculate the end date // according to the rfc any event without a end date or duration is a complete day - elseif ($this->baseEventStartDateFloating == true) { + elseif ($this->baseEventStartDateFloating === true) { $this->baseEventDuration = 86400; $this->baseEventEndDate = DateTimeImmutable::createFromInterface($this->baseEventStartDate) ->setTimestamp($this->baseEventStartDate->getTimestamp() + $this->baseEventDuration); diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php index 430617617ad5f..d0ae0bfd87d3f 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php @@ -247,7 +247,7 @@ private function getAllEMailAddressesFromEvent(VEvent $vevent):array { } $cuType = $this->getCUTypeOfAttendee($attendee); - if (\in_array($cuType, ['RESOURCE', 'ROOM', 'UNKNOWN'])) { + if (\in_array($cuType, ['RESOURCE', 'ROOM', 'UNKNOWN'], true)) { // Don't send emails to things continue; } diff --git a/apps/dav/lib/Connector/Sabre/CachingTree.php b/apps/dav/lib/Connector/Sabre/CachingTree.php index 5c3b0d054e419..fbf8369e558cd 100644 --- a/apps/dav/lib/Connector/Sabre/CachingTree.php +++ b/apps/dav/lib/Connector/Sabre/CachingTree.php @@ -31,7 +31,7 @@ public function markDirty($path) { $path = trim($path, '/'); foreach ($this->cache as $nodePath => $node) { $nodePath = (string)$nodePath; - if ($path === '' || $nodePath == $path || str_starts_with($nodePath, $path . '/')) { + if ($path === '' || $nodePath === $path || str_starts_with($nodePath, $path . '/')) { unset($this->cache[$nodePath]); } } diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php index 3a95fe07606ca..60201b97de635 100644 --- a/apps/dav/lib/DAV/CustomPropertiesBackend.php +++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php @@ -276,11 +276,11 @@ public function propFind($path, PropFind $propFind): void { } private function isPropertyAllowed(string $property): bool { - if (in_array($property, self::IGNORED_PROPERTIES)) { + if (in_array($property, self::IGNORED_PROPERTIES, true)) { return false; } if (str_starts_with($property, '{http://owncloud.org/ns}') || str_starts_with($property, '{http://nextcloud.org/ns}')) { - return in_array($property, self::ALLOWED_NC_PROPERTIES); + return in_array($property, self::ALLOWED_NC_PROPERTIES, true); } return true; } @@ -651,7 +651,7 @@ private function encodeValueForDatabase(string $path, string $name, mixed $value "Property \"$name\" has an invalid value of type " . gettype($value), ); } else { - if (!in_array($value::class, self::ALLOWED_SERIALIZED_CLASSES)) { + if (!in_array($value::class, self::ALLOWED_SERIALIZED_CLASSES, true)) { throw new DavException( "Property \"$name\" has an invalid value of class " . $value::class, ); diff --git a/apps/dav/lib/DAV/Sharing/Backend.php b/apps/dav/lib/DAV/Sharing/Backend.php index ba64cea69d825..35cd4744cbe27 100644 --- a/apps/dav/lib/DAV/Sharing/Backend.php +++ b/apps/dav/lib/DAV/Sharing/Backend.php @@ -224,7 +224,7 @@ public function applyShareAcl(array $shares, array $acl): array { 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], 'protected' => true, ]; - } elseif (in_array($this->service->getResourceType(), ['calendar','addressbook'])) { + } elseif (in_array($this->service->getResourceType(), ['calendar','addressbook'], true)) { // Allow changing the properties of read only calendars, // so users can change the visibility. $acl[] = [ diff --git a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php index b1b9648eef325..dccbab366e226 100644 --- a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php @@ -32,7 +32,7 @@ public function __construct( protected string $mediaType = '', ) { $this->name = 'systemtags-assigned'; - if ($this->mediaType != '') { + if ($this->mediaType !== '') { $this->name .= '/' . $this->mediaType; } } diff --git a/apps/encryption/lib/Command/CleanOrphanedKeys.php b/apps/encryption/lib/Command/CleanOrphanedKeys.php index dad49775f6fa1..8b467f0ed7f9a 100644 --- a/apps/encryption/lib/Command/CleanOrphanedKeys.php +++ b/apps/encryption/lib/Command/CleanOrphanedKeys.php @@ -94,7 +94,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($orphanedKeys as $keyPath) { $output->writeln('Orphaned key found: ' . $keyPath); } - if (count($orphanedKeys) == 0) { + if (count($orphanedKeys) === 0) { return self::SUCCESS; } $question = new ConfirmationQuestion('Do you want to delete all orphaned keys? (y/n) ', false); @@ -199,7 +199,7 @@ private function deleteSpecific(InputInterface $input, OutputInterface $output, return $k !== trim($path); }); } - if (count($orphanedKeys) == 0) { + if (count($orphanedKeys) === 0) { return; } $output->writeln('Remaining orphaned keys: '); diff --git a/apps/encryption/lib/Command/FixKeyLocation.php b/apps/encryption/lib/Command/FixKeyLocation.php index a869f967277c9..a573e0d1b8a15 100644 --- a/apps/encryption/lib/Command/FixKeyLocation.php +++ b/apps/encryption/lib/Command/FixKeyLocation.php @@ -323,7 +323,7 @@ private function findKeysByFileName(string $basePath, string $name) { throw new \Exception('Invalid base path ' . $basePath); } while ($child = readdir($dh)) { - if ($child != '..' && $child != '.') { + if ($child !== '..' && $child !== '.') { $childPath = $basePath . '/' . $child; // recurse if the child is not a key folder diff --git a/apps/files_external/tests/Storage/SmbTest.php b/apps/files_external/tests/Storage/SmbTest.php index 7384d13f05bc4..96333334c08d9 100644 --- a/apps/files_external/tests/Storage/SmbTest.php +++ b/apps/files_external/tests/Storage/SmbTest.php @@ -34,7 +34,7 @@ protected function setUp(): void { $id = $this->getUniqueID(); $this->loadConfig(__DIR__ . '/../config.smb.php'); - if (substr($this->config['root'], -1, 1) != '/') { + if (substr($this->config['root'], -1, 1) !== '/') { $this->config['root'] .= '/'; } $this->config['root'] .= $id; //make sure we have an new empty folder to work in diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php index 51f94c54782cb..373ee3fe4dfe2 100644 --- a/apps/files_sharing/lib/SharedStorage.php +++ b/apps/files_sharing/lib/SharedStorage.php @@ -222,7 +222,8 @@ public function instanceOfStorage(string $class): bool { Home::class, HomeObjectStoreStorage::class, IHomeStorage::class - ])) { + ], + true)) { return false; } return parent::instanceOfStorage($class); diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index d2dabe2beae75..4f32db95a3916 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -165,7 +165,7 @@ protected function restoreDeletedFiles(string $uid, int $scope, ?int $since, ?in $output); $trashCount = count($userTrashItems); - if ($trashCount == 0) { + if ($trashCount === 0) { $output->writeln('User has no deleted files in the trashbin matching the given filters'); return; } diff --git a/apps/files_versions/lib/Versions/VersionManager.php b/apps/files_versions/lib/Versions/VersionManager.php index 2e91a063b7021..20929b5df79c9 100644 --- a/apps/files_versions/lib/Versions/VersionManager.php +++ b/apps/files_versions/lib/Versions/VersionManager.php @@ -205,7 +205,7 @@ private static function handleAppLocks(callable $callback): ?bool { } catch (ManuallyLockedException $e) { $owner = (string)$e->getOwner(); $appsThatHandleUpdates = ['text', 'richdocuments']; - if (!in_array($owner, $appsThatHandleUpdates)) { + if (!in_array($owner, $appsThatHandleUpdates, true)) { throw $e; } // The LockWrapper in the files_lock app only compares the lock type and owner diff --git a/apps/provisioning_api/lib/Controller/AppConfigController.php b/apps/provisioning_api/lib/Controller/AppConfigController.php index edee8f28695c7..c8206e7a232ab 100644 --- a/apps/provisioning_api/lib/Controller/AppConfigController.php +++ b/apps/provisioning_api/lib/Controller/AppConfigController.php @@ -200,7 +200,7 @@ protected function verifyAppId(string $app): void { * @throws \InvalidArgumentException */ protected function verifyConfigKey(string $app, string $key, string $value) { - if (in_array($key, ['installed_version', 'enabled', 'types'])) { + if (in_array($key, ['installed_version', 'enabled', 'types'], true)) { throw new \InvalidArgumentException('The given key can not be set'); } diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index 227163d38f0d3..b71a0106ed0e9 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -130,7 +130,7 @@ public function updateStylesheet(string $setting, string $value): DataResponse { break; case 'disableUserTheming': case 'disable-user-theming': - if (!in_array($value, ['yes', 'true', 'no', 'false'])) { + if (!in_array($value, ['yes', 'true', 'no', 'false'], true)) { $error = $this->l10n->t('%1$s should be true or false', ['disable-user-theming']); } else { $this->appConfig->setAppValueBool('disable-user-theming', $value === 'yes' || $value === 'true'); diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index eb8b72109ee13..2b0018e15ae95 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -1052,7 +1052,7 @@ public function countObjects(?int $limit = null, ?int $offset = null) { * @throws ServerNotAvailableException */ private function invokeLDAPMethod(string $command, ...$arguments) { - if ($command == 'controlPagedResultResponse') { + if ($command === 'controlPagedResultResponse') { // php no longer supports call-time pass-by-reference // thus cannot support controlPagedResultResponse as the third argument // is a reference diff --git a/apps/workflowengine/lib/Check/AbstractStringCheck.php b/apps/workflowengine/lib/Check/AbstractStringCheck.php index a8a964d0df3ef..98352b804e752 100644 --- a/apps/workflowengine/lib/Check/AbstractStringCheck.php +++ b/apps/workflowengine/lib/Check/AbstractStringCheck.php @@ -72,7 +72,7 @@ public function validateCheck($operator, $value): void { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } - if (in_array($operator, ['matches', '!matches']) + if (in_array($operator, ['matches', '!matches'], true) && @preg_match($value, '') === false) { throw new \UnexpectedValueException($this->l->t('The given regular expression is invalid'), 2); } diff --git a/apps/workflowengine/lib/Check/RequestRemoteAddress.php b/apps/workflowengine/lib/Check/RequestRemoteAddress.php index 7309263ebfa7c..e59f923f00e96 100644 --- a/apps/workflowengine/lib/Check/RequestRemoteAddress.php +++ b/apps/workflowengine/lib/Check/RequestRemoteAddress.php @@ -69,7 +69,7 @@ public function validateCheck($operator, $value) { throw new \UnexpectedValueException($this->l->t('The given IP range is invalid'), 2); } - if (in_array($operator, ['matchesIPv4', '!matchesIPv4'])) { + if (in_array($operator, ['matchesIPv4', '!matchesIPv4'], true)) { if (!filter_var($decodedValue[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { throw new \UnexpectedValueException($this->l->t('The given IP range is not valid for IPv4'), 3); } diff --git a/build/integration/features/bootstrap/BasicStructure.php b/build/integration/features/bootstrap/BasicStructure.php index 171de3dc4760a..4a30fa720e7f3 100644 --- a/build/integration/features/bootstrap/BasicStructure.php +++ b/build/integration/features/bootstrap/BasicStructure.php @@ -250,7 +250,7 @@ public function sendingToWithDirectUrl($verb, $url, $body) { public function isExpectedUrl($possibleUrl, $finalPart) { $baseUrlChopped = substr($this->baseUrl, 0, -4); $endCharacter = strlen($baseUrlChopped) + strlen($finalPart); - return (substr($possibleUrl, 0, $endCharacter) == "$baseUrlChopped" . "$finalPart"); + return (substr($possibleUrl, 0, $endCharacter) === "$baseUrlChopped" . "$finalPart"); } /** diff --git a/build/integration/features/bootstrap/FakeSMTPHelper.php b/build/integration/features/bootstrap/FakeSMTPHelper.php index 32387869eddcb..0634871ea8c7a 100644 --- a/build/integration/features/bootstrap/FakeSMTPHelper.php +++ b/build/integration/features/bootstrap/FakeSMTPHelper.php @@ -91,7 +91,7 @@ public function receive() { $receivingData = false; $this->reply('250 2.0.0 Ok: queued as ' . $this->generateRandom(10)); $splitmail = explode("\n\n", $this->mail['rawEmail'], 2); - if (count($splitmail) == 2) { + if (count($splitmail) === 2) { $this->mail['emailHeaders'] = $splitmail[0]; $this->mail['emailBody'] = $splitmail[1]; $headers = preg_replace("/ \s+/", ' ', preg_replace("/\n\s/", ' ', $this->mail['emailHeaders'])); diff --git a/build/integration/features/bootstrap/FederationContext.php b/build/integration/features/bootstrap/FederationContext.php index 4f3ce8c44f029..eb1d2bda10cd8 100644 --- a/build/integration/features/bootstrap/FederationContext.php +++ b/build/integration/features/bootstrap/FederationContext.php @@ -63,7 +63,7 @@ public function cleanupRemoteStorages(): void { * @param 'LOCAL'|'REMOTE' $shareeServer */ public function federateSharing(string $sharerUser, string $sharerServer, string $sharerPath, string $shareeUser, string $shareeServer): void { - if ($shareeServer == 'REMOTE') { + if ($shareeServer === 'REMOTE') { $shareWith = "$shareeUser@" . substr($this->remoteBaseUrl, 0, -4); } else { $shareWith = "$shareeUser@" . substr($this->localBaseUrl, 0, -4); @@ -80,7 +80,7 @@ public function federateSharing(string $sharerUser, string $sharerServer, string * @param 'LOCAL'|'REMOTE' $shareeServer */ public function federateGroupSharing(string $sharerUser, string $sharerServer, string $sharerPath, string $shareeGroup, string $shareeServer): void { - if ($shareeServer == 'REMOTE') { + if ($shareeServer === 'REMOTE') { $shareWith = "$shareeGroup@" . substr($this->remoteBaseUrl, 0, -4); } else { $shareWith = "$shareeGroup@" . substr($this->localBaseUrl, 0, -4); diff --git a/build/integration/features/bootstrap/Sharing.php b/build/integration/features/bootstrap/Sharing.php index 6420b2218fce3..def854a09ed13 100644 --- a/build/integration/features/bootstrap/Sharing.php +++ b/build/integration/features/bootstrap/Sharing.php @@ -325,7 +325,7 @@ public function getFieldValueInResponse($field) { public function isFieldInResponse($field, $contentExpected) { $data = simplexml_load_string($this->response->getBody())->data[0]; - if ((string)$field == 'expiration') { + if ((string)$field === 'expiration') { if (!empty($contentExpected)) { $contentExpected = date('Y-m-d', strtotime($contentExpected)) . ' 23:59:59'; } @@ -334,7 +334,7 @@ public function isFieldInResponse($field, $contentExpected) { foreach ($data as $element) { if ($contentExpected == 'A_TOKEN') { $tokenLength = strlen((string)$element->$field); - return $tokenLength == 15 || $tokenLength == 32; + return $tokenLength === 15 || $tokenLength === 32; } elseif ($contentExpected == 'A_NUMBER') { return is_numeric((string)$element->$field); } elseif ($contentExpected == 'AN_URL') { @@ -350,7 +350,7 @@ public function isFieldInResponse($field, $contentExpected) { } else { if ($contentExpected == 'A_TOKEN') { $tokenLength = strlen((string)$data->$field); - return $tokenLength == 15 || $tokenLength == 32; + return $tokenLength === 15 || $tokenLength === 32; } elseif ($contentExpected == 'A_NUMBER') { return is_numeric((string)$data->$field); } elseif ($contentExpected == 'AN_URL') { diff --git a/build/integration/features/bootstrap/WebDav.php b/build/integration/features/bootstrap/WebDav.php index 2053b62315ff4..2a0e5278f1597 100644 --- a/build/integration/features/bootstrap/WebDav.php +++ b/build/integration/features/bootstrap/WebDav.php @@ -1219,7 +1219,7 @@ public function userDeletesEverythingInFolder($user, $folder) { array_shift($elementListKeys); $davPrefix = '/' . $this->getDavFilesPath($user); foreach ($elementListKeys as $element) { - if (substr($element, 0, strlen($davPrefix)) == $davPrefix) { + if (substr($element, 0, strlen($davPrefix)) === $davPrefix) { $element = substr($element, strlen($davPrefix)); } $this->userDeletesFile($user, 'element', $element); diff --git a/core/Command/Base.php b/core/Command/Base.php index 14ec07113fd41..58e391452777a 100644 --- a/core/Command/Base.php +++ b/core/Command/Base.php @@ -134,7 +134,7 @@ public function chunkIterator(\Iterator $iterator, int $count): \Iterator { for ($i = 0; $iterator->valid(); $i++) { $chunk[] = $iterator->current(); $iterator->next(); - if (count($chunk) == $count) { + if (count($chunk) === $count) { // Got a full chunk, yield and start a new one yield $chunk; $chunk = []; diff --git a/lib/private/App/AppStore/Bundles/HubBundle.php b/lib/private/App/AppStore/Bundles/HubBundle.php index ecfec0b181ed4..bfe902be4ce1a 100644 --- a/lib/private/App/AppStore/Bundles/HubBundle.php +++ b/lib/private/App/AppStore/Bundles/HubBundle.php @@ -25,7 +25,7 @@ public function getAppIdentifiers() { ]; $architecture = function_exists('php_uname') ? php_uname('m') : null; - if (isset($architecture) && PHP_OS_FAMILY === 'Linux' && in_array($architecture, ['x86_64', 'aarch64'])) { + if (isset($architecture) && PHP_OS_FAMILY === 'Linux' && in_array($architecture, ['x86_64', 'aarch64'], true)) { $hubApps[] = 'richdocuments'; $hubApps[] = 'richdocumentscode' . ($architecture === 'aarch64' ? '_arm64' : ''); } diff --git a/lib/private/App/PlatformRepository.php b/lib/private/App/PlatformRepository.php index c1cbb5831e01e..dc4362444c9e0 100644 --- a/lib/private/App/PlatformRepository.php +++ b/lib/private/App/PlatformRepository.php @@ -29,7 +29,7 @@ protected function initialize(): array { // Extensions scanning foreach ($loadedExtensions as $name) { - if (in_array($name, ['standard', 'Core'])) { + if (in_array($name, ['standard', 'Core'], true)) { continue; } diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index 0887a41b2d0a8..9e3ceb4ca09bd 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -461,7 +461,7 @@ public function getValueBool(string $app, string $key, bool $default = false, bo $value = $this->getTypedValue($app, $key, $default ? 'true' : 'false', $lazy, self::VALUE_BOOL) ?? ($default ? 'true' : 'false'); /** @psalm-suppress RedundantCast */ $b = strtolower((string)$value); - return in_array($b, ['1', 'true', 'yes', 'on']); + return in_array($b, ['1', 'true', 'yes', 'on'], true); } /** @@ -1587,7 +1587,7 @@ private function convertTypedValue(string $value, int $type): string|int|float|b case self::VALUE_FLOAT: return (float)$value; case self::VALUE_BOOL: - return in_array(strtolower($value), ['1', 'true', 'yes', 'on']); + return in_array(strtolower($value), ['1', 'true', 'yes', 'on'], true); case self::VALUE_ARRAY: try { return json_decode($value, true, flags: JSON_THROW_ON_ERROR); @@ -1769,7 +1769,8 @@ private function matchAndApplyLexiconDefinition( 'enabled', 'installed_version', 'types', - ])) { + ], + true)) { return true; // we don't break stuff for this list of config keys. } $configDetails = $this->getConfigDetailsFromLexicon($app); diff --git a/lib/private/Archive/TAR.php b/lib/private/Archive/TAR.php index b5cfd43304afa..861268eb116b0 100644 --- a/lib/private/Archive/TAR.php +++ b/lib/private/Archive/TAR.php @@ -175,7 +175,7 @@ public function getFolder(string $path): array { if ($pos = strpos($result, '/')) { $result = substr($result, 0, $pos + 1); } - if (!in_array($result, $folderContent)) { + if (!in_array($result, $folderContent, true)) { $folderContent[] = $result; } } diff --git a/lib/private/Config/ConfigManager.php b/lib/private/Config/ConfigManager.php index 432fc344eb530..66a12997e5aba 100644 --- a/lib/private/Config/ConfigManager.php +++ b/lib/private/Config/ConfigManager.php @@ -258,9 +258,9 @@ public function convertToFloat(string $value): float { } public function convertToBool(string $value, ?Entry $entry = null): bool { - if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) { + if (in_array(strtolower($value), ['true', '1', 'on', 'yes'], true)) { $valueBool = true; - } elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) { + } elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'], true)) { $valueBool = false; } else { throw new TypeConflictException('Value cannot be converted to boolean'); diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php index 2869b590f5e0a..6b768604da538 100644 --- a/lib/private/Config/UserConfig.php +++ b/lib/private/Config/UserConfig.php @@ -724,7 +724,7 @@ public function getValueBool( $value = $this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL) ?? ($default ? 'true' : 'false'); /** @psalm-suppress RedundantCast */ $b = strtolower((string)$value); - return in_array($b, ['1', 'true', 'yes', 'on']); + return in_array($b, ['1', 'true', 'yes', 'on'], true); } /** @@ -1931,7 +1931,7 @@ private function convertTypedValue(string $value, ValueType $type): string|int|f case ValueType::FLOAT: return (float)$value; case ValueType::BOOL: - return in_array(strtolower($value), ['1', 'true', 'yes', 'on']); + return in_array(strtolower($value), ['1', 'true', 'yes', 'on'], true); case ValueType::ARRAY: try { return json_decode($value, true, flags: JSON_THROW_ON_ERROR); diff --git a/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php b/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php index 1fba7f1f3d831..9906d79107ca4 100644 --- a/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php +++ b/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php @@ -59,7 +59,7 @@ private function getLikelyShards(array $primaryKeys): array { $shards[] = ShardDefinition::MIGRATION_SHARD; } $encodedShard = $primaryKey & ShardDefinition::PRIMARY_KEY_SHARD_MASK; - if ($encodedShard < count($this->shardDefinition->shards) && !in_array($encodedShard, $shards)) { + if ($encodedShard < count($this->shardDefinition->shards) && !in_array($encodedShard, $shards, true)) { $shards[] = $encodedShard; } } diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index c219d7cdc45b0..b4b1e01071ad1 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -489,7 +489,7 @@ protected function normalizeData(array $data): array { $params = []; $extensionParams = []; foreach ($data as $name => $value) { - if (in_array($name, $fields)) { + if (in_array($name, $fields, true)) { if ($name === 'path') { $params['path_hash'] = md5($value); } elseif ($name === 'mimetype') { @@ -509,7 +509,7 @@ protected function normalizeData(array $data): array { } $params[$name] = $value; } - if (in_array($name, $extensionFields)) { + if (in_array($name, $extensionFields, true)) { $extensionParams[$name] = $value; } } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index a4f0d1cc9bf91..99c4d96ff1f7a 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -116,7 +116,7 @@ public function rmdir(string $path): bool { */ $file = $it->current(); clearstatcache(true, $file->getRealPath()); - if (in_array($file->getBasename(), ['.', '..'])) { + if (in_array($file->getBasename(), ['.', '..'], true)) { $it->next(); continue; } elseif ($file->isFile() || $file->isLink()) { diff --git a/lib/private/Image.php b/lib/private/Image.php index d1a2f164ed52e..015f42bfe6b22 100644 --- a/lib/private/Image.php +++ b/lib/private/Image.php @@ -944,7 +944,7 @@ public function centerCrop(int $size = 0): bool { } $widthOrig = imagesx($this->resource); $heightOrig = imagesy($this->resource); - if ($widthOrig === $heightOrig && $size == 0) { + if ($widthOrig === $heightOrig && $size === 0) { return true; } $ratioOrig = $widthOrig / $heightOrig; diff --git a/lib/private/Net/HostnameClassifier.php b/lib/private/Net/HostnameClassifier.php index 3384d3d936ebf..becf53aacaab8 100644 --- a/lib/private/Net/HostnameClassifier.php +++ b/lib/private/Net/HostnameClassifier.php @@ -41,7 +41,7 @@ public function isLocalHostname(string $hostname): bool { $hostname = rtrim($hostname, '.'); // Disallow local network top-level domains from RFC 6762 $topLevelDomain = substr((strrchr($hostname, '.') ?: ''), 1); - if (in_array($topLevelDomain, self::LOCAL_TOPLEVEL_DOMAINS)) { + if (in_array($topLevelDomain, self::LOCAL_TOPLEVEL_DOMAINS, true)) { return true; } diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index 7fe9fce5d2b8a..27f2ff12038bb 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -236,7 +236,7 @@ public static function getCurrentApp(): string { $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1); } } - if ($topFolder == 'apps') { + if ($topFolder === 'apps') { $length = strlen($topFolder); return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: ''; } else { diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 034e06584cc41..74ba577dae7d3 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -447,7 +447,7 @@ public static function checkServer(SystemConfig $config) { } // Cache the result of this function - Server::get(ISession::class)->set('checkServer_succeeded', count($errors) == 0); + Server::get(ISession::class)->set('checkServer_succeeded', count($errors) === 0); return $errors; } diff --git a/ocs/v1.php b/ocs/v1.php index 264d27d8f94a3..64252b2d2e76b 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -7,14 +7,16 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ - +use OC\NavigationManager; use OC\OCS\ApiHelper; use OC\Route\Router; use OC\SystemConfig; use OC\User\LoginException; +use OCP\App\Events\AppsLoadedEvent; use OCP\App\IAppManager; use OCP\AppFramework\Http; use OCP\AppFramework\OCSController; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IRequest; use OCP\IUserSession; @@ -80,8 +82,8 @@ } // All apps are now loaded to handle the request - Server::get(\OC\NavigationManager::class)->setup(); - Server::get(\OCP\EventDispatcher\IEventDispatcher::class)->dispatchTyped(new \OCP\App\Events\AppsLoadedEvent()); + Server::get(NavigationManager::class)->setup(); + Server::get(IEventDispatcher::class)->dispatchTyped(new AppsLoadedEvent()); Server::get(Router::class)->match('/ocsapp' . $request->getRawPathInfo()); } catch (MaxDelayReached $ex) { diff --git a/tests/lib/AppFramework/Http/RequestStream.php b/tests/lib/AppFramework/Http/RequestStream.php index 4a2670f9df126..583f47d8e50f3 100644 --- a/tests/lib/AppFramework/Http/RequestStream.php +++ b/tests/lib/AppFramework/Http/RequestStream.php @@ -104,7 +104,7 @@ public function stream_stat(): array { } public function stream_metadata(string $path, int $option, $var): bool { - if ($option == STREAM_META_TOUCH) { + if ($option === STREAM_META_TOUCH) { $url = parse_url($path); $varname = $url['host'] ?? ''; if (!isset($GLOBALS[$varname])) { diff --git a/tests/lib/Files/Storage/Storage.php b/tests/lib/Files/Storage/Storage.php index d0a793ca88e4f..672b0cbeec3bc 100644 --- a/tests/lib/Files/Storage/Storage.php +++ b/tests/lib/Files/Storage/Storage.php @@ -101,7 +101,7 @@ public function testDirectories($directory): void { $dh = $this->instance->opendir('/'); $content = []; while (($file = readdir($dh)) !== false) { - if ($file != '.' && $file != '..') { + if ($file !== '.' && $file !== '..') { $content[] = $file; } } @@ -439,7 +439,7 @@ public function testHashInFileName(): void { $dh = $this->instance->opendir('#foo'); $content = []; while ($file = readdir($dh)) { - if ($file != '.' && $file != '..') { + if ($file !== '.' && $file !== '..') { $content[] = $file; } } diff --git a/tests/lib/Repair/RepairDavSharesTest.php b/tests/lib/Repair/RepairDavSharesTest.php index 13653039db08f..c671a6968783d 100644 --- a/tests/lib/Repair/RepairDavSharesTest.php +++ b/tests/lib/Repair/RepairDavSharesTest.php @@ -165,7 +165,7 @@ public function testRun(): void { $this->groupManager->expects($this->any()) ->method('groupExists') ->willReturnCallback(function (string $gid) use ($existingGroups) { - return in_array($gid, $existingGroups); + return in_array($gid, $existingGroups, true); }); $this->repair->run($this->output); From 70316a007a4d948bf99ff8c32fc15d829487eeae Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 3 Sep 2026 16:48:50 +0200 Subject: [PATCH 3/5] chore: Fix manually all strict comparaison Helped a bit by the AI Signed-off-by: Carl Schwan --- .../appstore/lib/Controller/ApiController.php | 10 +++--- .../Controller/RequestHandlerController.php | 2 ++ .../lib/Listener/CommentsEventListener.php | 2 +- .../lib/Controller/DashboardApiController.php | 2 +- apps/dav/appinfo/v1/publicwebdav.php | 2 +- apps/dav/appinfo/v2/publicremote.php | 2 +- apps/dav/lib/CalDAV/Activity/Backend.php | 2 +- .../lib/CalDAV/CachedSubscriptionProvider.php | 2 +- apps/dav/lib/CalDAV/CalDavBackend.php | 6 ++-- apps/dav/lib/CalDAV/CalendarProvider.php | 4 +-- apps/dav/lib/CalDAV/EventReader.php | 3 ++ apps/dav/lib/CalDAV/Schedule/IMipPlugin.php | 4 +-- apps/dav/lib/CalDAV/Schedule/IMipService.php | 2 +- apps/dav/lib/CalDAV/Status/StatusService.php | 2 +- apps/dav/lib/CardDAV/AddressBookImpl.php | 4 +-- apps/dav/lib/CardDAV/CardDavBackend.php | 2 +- apps/dav/lib/Comments/CommentsPlugin.php | 2 +- apps/dav/lib/Connector/LegacyPublicAuth.php | 2 +- .../lib/Connector/Sabre/AppleQuirksPlugin.php | 2 +- apps/dav/lib/Connector/Sabre/Auth.php | 4 +-- .../lib/Connector/Sabre/FilesReportPlugin.php | 2 +- apps/dav/lib/Connector/Sabre/PublicAuth.php | 4 +-- .../InvitationResponseController.php | 2 ++ apps/dav/lib/DAV/CustomPropertiesBackend.php | 2 +- apps/dav/lib/Files/FileSearchBackend.php | 2 +- apps/dav/lib/SetupChecks/WebdavEndpoint.php | 2 +- apps/dav/lib/SystemTag/SystemTagNode.php | 2 +- .../lib/Command/CleanOrphanedKeys.php | 2 +- .../lib/Command/FixEncryptedVersion.php | 2 +- apps/encryption/lib/Crypto/Crypt.php | 11 ++----- apps/encryption/lib/Crypto/Encryption.php | 2 +- .../Controller/MountPublicLinkController.php | 2 +- .../lib/OCM/CloudFederationProviderFiles.php | 2 ++ .../lib/Listener/SyncLivePhotosListener.php | 4 +-- apps/files/lib/Service/UserConfig.php | 4 ++- apps/files/lib/Service/ViewConfig.php | 4 ++- apps/files_external/lib/Command/Create.php | 2 +- .../lib/Command/ListCommand.php | 2 +- .../lib/Lib/ApplicableHelper.php | 8 ++--- .../lib/Lib/Storage/SFTPReadStream.php | 2 +- .../lib/Service/StoragesService.php | 4 +-- .../lib/Dav/PropFindPlugin.php | 2 +- .../lib/Controller/ShareAPIController.php | 4 +-- .../lib/Listener/BeforeNodeReadListener.php | 4 +-- .../Listener/RestrictInteractionListener.php | 2 +- apps/files_sharing/lib/MountProvider.php | 2 +- .../lib/ShareRecipientUpdater.php | 2 +- apps/files_sharing/lib/SharedStorage.php | 2 +- apps/files_sharing/lib/SharesReminderJob.php | 2 +- apps/files_trashbin/lib/Command/Size.php | 4 +-- .../lib/Versions/LegacyVersionsBackend.php | 2 +- .../Controller/LoginRedirectorController.php | 2 +- .../lib/Controller/UsersController.php | 6 ++-- .../lib/Controller/MailSettingsController.php | 2 +- .../lib/SetupChecks/MemcacheConfigured.php | 2 +- .../lib/SetupChecks/OverwriteCliUrl.php | 2 +- .../lib/SetupChecks/SecurityHeaders.php | 2 +- .../lib/SetupChecks/WellKnownUrls.php | 2 +- apps/sharebymail/lib/Activity.php | 2 ++ .../lib/Controller/ThemingController.php | 2 +- .../lib/Listener/BeforePreferenceListener.php | 2 +- apps/theming/lib/Service/ThemesService.php | 6 ++-- apps/theming/lib/ThemingDefaults.php | 2 +- apps/user_ldap/lib/Access.php | 2 +- apps/user_ldap/lib/Command/CheckUser.php | 2 +- apps/user_ldap/lib/Command/ResetGroup.php | 2 +- apps/user_ldap/lib/Command/SetConfig.php | 2 +- apps/user_ldap/lib/Command/ShowConfig.php | 2 +- apps/user_ldap/lib/Command/TestConfig.php | 2 +- apps/user_ldap/lib/Connection.php | 4 +-- apps/user_ldap/lib/GroupPluginManager.php | 2 +- apps/user_ldap/lib/Group_LDAP.php | 6 ++-- apps/user_ldap/lib/Jobs/Sync.php | 2 +- apps/user_ldap/lib/User/Manager.php | 2 +- apps/user_ldap/lib/UserPluginManager.php | 2 +- apps/user_ldap/lib/Wizard.php | 4 ++- .../lib/Service/PHPMongoQuery.php | 8 +++++ .../lib/Check/AbstractStringCheck.php | 2 +- apps/workflowengine/lib/Check/FileSize.php | 2 +- .../lib/Check/FileSystemTags.php | 4 +-- .../lib/Check/RequestRemoteAddress.php | 2 +- apps/workflowengine/lib/Check/RequestTime.php | 2 +- apps/workflowengine/lib/Check/RequestURL.php | 2 +- .../lib/Check/UserGroupMembership.php | 4 +-- apps/workflowengine/lib/Manager.php | 8 ++--- .../lib/Service/RuleMatcher.php | 4 +++ core/Command/Config/System/DeleteConfig.php | 4 +-- core/Command/Config/System/GetConfig.php | 4 +-- core/Command/Db/SchemaEncoder.php | 2 +- core/Command/Info/File.php | 2 +- core/Command/Info/FileUtils.php | 2 +- core/Command/Maintenance/Install.php | 2 +- core/Command/Preview/Generate.php | 2 +- core/Command/TaskProcessing/ListCommand.php | 2 +- core/Command/Upgrade.php | 2 +- core/Command/User/Keys/Verify.php | 2 +- core/Command/User/Setting.php | 32 ++++++++++--------- core/Controller/SetupController.php | 2 +- .../TaskProcessingApiController.php | 2 +- core/Controller/UpdateController.php | 2 +- core/Service/CronService.php | 2 +- core/templates/layout.user.php | 4 +-- lib/OC.php | 10 +++--- lib/private/Accounts/AccountManager.php | 2 +- lib/private/Accounts/AccountProperty.php | 4 +-- lib/private/App/AppManager.php | 4 +-- .../App/AppStore/Fetcher/AppFetcher.php | 2 +- lib/private/App/DependencyAnalyzer.php | 4 ++- lib/private/AppConfig.php | 4 +-- lib/private/Archive/TAR.php | 2 +- .../Login/SetUserTimezoneCommand.php | 2 +- .../Collaborators/GroupPlugin.php | 4 +-- .../Collaborators/RemoteGroupPlugin.php | 2 +- lib/private/Config/ConfigManager.php | 3 +- .../Contacts/ContactsMenu/ContactsStore.php | 2 +- lib/private/DB/Connection.php | 2 +- lib/private/DB/MigrationService.php | 2 +- .../Partitioned/PartitionSplit.php | 2 +- .../QueryBuilder/Sharded/ShardDefinition.php | 4 +-- .../QueryBuilder/Sharded/ShardQueryRunner.php | 2 +- lib/private/DateTimeFormatter.php | 12 +++---- lib/private/DateTimeZone.php | 2 ++ lib/private/DirectEditing/Manager.php | 2 +- lib/private/Encryption/File.php | 2 +- lib/private/Encryption/Util.php | 6 ++-- lib/private/Files/Cache/Cache.php | 7 ++-- lib/private/Files/Cache/QuerySearchHelper.php | 14 ++++---- lib/private/Files/Cache/SearchBuilder.php | 2 +- .../Files/Config/MountProviderCollection.php | 2 +- lib/private/Files/Config/UserMountCache.php | 2 +- .../Files/Conversion/ConversionManager.php | 2 +- lib/private/Files/FilenameValidator.php | 8 ++--- lib/private/Files/Mount/Manager.php | 2 +- lib/private/Files/Node/Root.php | 2 +- .../ObjectStore/PrimaryObjectStoreConfig.php | 2 +- lib/private/Files/SetupManager.php | 10 +++--- lib/private/Files/Storage/Wrapper/Quota.php | 12 ++++--- .../Files/Stream/SeekableHttpStream.php | 2 +- lib/private/Files/View.php | 20 ++++++------ .../FilesMetadata/Model/FilesMetadata.php | 4 +-- lib/private/GlobalScale/Config.php | 4 +-- lib/private/Group/Backend.php | 4 +-- lib/private/Group/Manager.php | 2 +- lib/private/Hooks/EmitterTrait.php | 4 +-- lib/private/Installer.php | 2 +- lib/private/L10N/Factory.php | 8 ++--- lib/private/Log/File.php | 5 +-- lib/private/Migration/MetadataManager.php | 2 ++ lib/private/NavigationManager.php | 3 +- lib/private/OCM/Model/OCMProvider.php | 2 +- lib/private/Preview/HEIC.php | 2 +- lib/private/PreviewManager.php | 10 +++--- .../NC29/SanitizeAccountPropertiesJob.php | 2 +- lib/private/Server.php | 2 +- lib/private/Settings/DeclarativeManager.php | 14 ++++---- lib/private/Settings/Manager.php | 6 ++-- lib/private/Sharing/SharingManager.php | 2 +- lib/private/TaskProcessing/Manager.php | 4 +-- lib/private/Template/Template.php | 2 +- lib/private/Template/functions.php | 2 ++ lib/private/TextProcessing/Manager.php | 2 +- lib/private/User/Manager.php | 4 +-- lib/private/User/Session.php | 2 +- lib/private/legacy/OC_App.php | 4 +-- lib/private/legacy/OC_User.php | 2 +- lib/private/legacy/OC_Util.php | 2 +- .../AuthPublicShareController.php | 2 +- .../FilesMetadata/Model/IFilesMetadata.php | 2 +- .../OCM/Events/OCMEndpointRequestEvent.php | 3 +- lib/public/Util.php | 2 +- tests/lib/TestCase.php | 4 ++- 171 files changed, 327 insertions(+), 282 deletions(-) diff --git a/apps/appstore/lib/Controller/ApiController.php b/apps/appstore/lib/Controller/ApiController.php index c3b0d70df932d..b670c4a7d1a92 100644 --- a/apps/appstore/lib/Controller/ApiController.php +++ b/apps/appstore/lib/Controller/ApiController.php @@ -129,11 +129,11 @@ public function listApps(bool $details = false): DataResponse { $appData['groups'] = $groups; // analyze dependencies - $ignoreMax = in_array($appData['id'], $ignoreMaxApps); + $ignoreMax = in_array($appData['id'], $ignoreMaxApps, true); $missing = $this->dependencyAnalyzer->analyze($appData, $ignoreMax); $appData['missingDependencies'] = $missing; $appData['isCompatible'] = $this->dependencyAnalyzer->isMarkedCompatible($appData); - $appData['internal'] = in_array($appData['id'], $this->appManager->getAlwaysEnabledApps()); + $appData['internal'] = in_array($appData['id'], $this->appManager->getAlwaysEnabledApps(), true); return $appData; }, $apps); @@ -332,7 +332,7 @@ private function fetchApps(): void { $supportedApps = $this->subscriptionRegistry->delegateGetSupportedApps(); $shippedApps = $this->appManager->getAlwaysEnabledApps(); foreach ($apps as $app) { - if (in_array($app['id'], $shippedApps)) { + if (in_array($app['id'], $shippedApps, true)) { // shipped apps are no longer published on the appstore // so skip them to avoid confusion with outdated data continue; @@ -345,7 +345,7 @@ private function fetchApps(): void { $this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]); } - if (in_array($app['id'], $supportedApps)) { + if (in_array($app['id'], $supportedApps, true)) { $this->allApps[$app['id']]['level'] = \OC_App::supportedApp; } } @@ -463,7 +463,7 @@ private function getAppsForCategory(string $requestedCategory = ''): array { 'license' => $app['releases'][0]['licenses'], 'author' => $authors, 'shipped' => $this->appManager->isShipped($app['id']), - 'internal' => in_array($app['id'], $this->appManager->getAlwaysEnabledApps()), + 'internal' => in_array($app['id'], $this->appManager->getAlwaysEnabledApps(), true), 'version' => $currentVersion, 'types' => [], 'documentation' => [ diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index 010a9a23f4391..59e88faee51fa 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -148,6 +148,8 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $ } $supportedShareTypes = $this->config->getSupportedShareTypes($resourceType); + // $shareType is an untyped parameter taken directly from the OCS request body + /** @psalm-suppress UnrecognizedExpression */ if (!in_array($shareType, $supportedShareTypes)) { return new JSONResponse( ['message' => 'Share type "' . $shareType . '" not implemented'], diff --git a/apps/comments/lib/Listener/CommentsEventListener.php b/apps/comments/lib/Listener/CommentsEventListener.php index d420933c862fc..9fbe503c820b2 100644 --- a/apps/comments/lib/Listener/CommentsEventListener.php +++ b/apps/comments/lib/Listener/CommentsEventListener.php @@ -60,7 +60,7 @@ public function handle(Event $event): void { CommentsEvent::EVENT_UPDATE, CommentsEvent::EVENT_DELETE, ]; - if (in_array($eventType, $applicableEvents)) { + if (in_array($eventType, $applicableEvents, true)) { $this->notificationHandler($event); return; } diff --git a/apps/dashboard/lib/Controller/DashboardApiController.php b/apps/dashboard/lib/Controller/DashboardApiController.php index c0768935dfeb7..8a4599a7ec0fa 100644 --- a/apps/dashboard/lib/Controller/DashboardApiController.php +++ b/apps/dashboard/lib/Controller/DashboardApiController.php @@ -64,7 +64,7 @@ private function getShownWidgets(array $widgetIds): array { return array_filter( $this->dashboardManager->getWidgets(), static function (IWidget $widget) use ($widgetIds) { - return in_array($widget->getId(), $widgetIds); + return in_array($widget->getId(), $widgetIds, true); }, ); } diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index d72929848a389..1a94b4a55b17c 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -97,7 +97,7 @@ function (\Sabre\DAV\Server $server) use ( $linkCheckPlugin, $filesDropPlugin ) { - $isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '')); + $isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''), true); /** @var FederatedShareProvider $shareProvider */ $federatedShareProvider = Server::get(FederatedShareProvider::class); if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) { diff --git a/apps/dav/appinfo/v2/publicremote.php b/apps/dav/appinfo/v2/publicremote.php index fedb202bd9f32..dbd4dbcba809e 100644 --- a/apps/dav/appinfo/v2/publicremote.php +++ b/apps/dav/appinfo/v2/publicremote.php @@ -101,7 +101,7 @@ // GET must be allowed for e.g. showing images and allowing Zip downloads if ($server->httpRequest->getMethod() !== 'GET') { // If this is *not* a GET request we only allow access to public DAV from AJAX or when Server2Server is allowed - $isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '')); + $isAjax = in_array('XMLHttpRequest', explode(',', $_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''), true); $federatedShareProvider = Server::get(FederatedShareProvider::class); if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && $isAjax === false) { // this is what is thrown when trying to access a non-existing share diff --git a/apps/dav/lib/CalDAV/Activity/Backend.php b/apps/dav/lib/CalDAV/Activity/Backend.php index e2721f8b03ebb..0f0e861d43589 100644 --- a/apps/dav/lib/CalDAV/Activity/Backend.php +++ b/apps/dav/lib/CalDAV/Activity/Backend.php @@ -578,7 +578,7 @@ protected function getObjectNameAndType(array $objectData) { $vObject = Reader::read($objectData['calendardata']); $component = $componentType = null; foreach ($vObject->getComponents() as $component) { - if (in_array($component->name, ['VEVENT', 'VTODO'])) { + if (in_array($component->name, ['VEVENT', 'VTODO'], true)) { $componentType = $component->name; break; } diff --git a/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php b/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php index 145203d4f39a9..29519881d3d6f 100644 --- a/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php +++ b/apps/dav/lib/CalDAV/CachedSubscriptionProvider.php @@ -23,7 +23,7 @@ public function getCalendars(string $principalUri, array $calendarUris = []): ar $calendarInfos = $this->calDavBackend->getSubscriptionsForUser($principalUri); if (count($calendarUris) > 0) { - $calendarInfos = array_filter($calendarInfos, fn (array $subscription) => in_array($subscription['uri'], $calendarUris)); + $calendarInfos = array_filter($calendarInfos, fn (array $subscription) => in_array($subscription['uri'], $calendarUris, true)); } $calendarInfos = array_values(array_filter($calendarInfos)); diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 2f9c52b9367e0..a4f7b03dc1aca 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -3043,7 +3043,7 @@ public function createSubscription($principalUri, $uri, array $properties) { foreach ($this->subscriptionPropertyMap as $xmlName => [$dbName, $type]) { if (array_key_exists($xmlName, $properties)) { $values[$dbName] = $properties[$xmlName]; - if (in_array($dbName, $propertiesBoolean)) { + if (in_array($dbName, $propertiesBoolean, true)) { $values[$dbName] = true; } } @@ -3684,7 +3684,7 @@ public function updateProperties($calendarId, $objectUri, $calendarData, $calend $indexComponents = ['VEVENT', 'VJOURNAL', 'VTODO']; foreach ($vCalendar->getComponents() as $component) { - if (!in_array($component->name, $indexComponents)) { + if (!in_array($component->name, $indexComponents, true)) { continue; } @@ -3708,7 +3708,7 @@ public function updateProperties($calendarId, $objectUri, $calendarData, $calend $indexedParametersForProperty = self::INDEXED_PARAMETERS[$property->name]; foreach ($parameters as $key => $value) { - if (in_array($key, $indexedParametersForProperty)) { + if (in_array($key, $indexedParametersForProperty, true)) { // is this a shitty db? if ($this->db->supports4ByteText()) { $value = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $value); diff --git a/apps/dav/lib/CalDAV/CalendarProvider.php b/apps/dav/lib/CalDAV/CalendarProvider.php index 615c80f4a581f..255819de68071 100644 --- a/apps/dav/lib/CalDAV/CalendarProvider.php +++ b/apps/dav/lib/CalDAV/CalendarProvider.php @@ -37,11 +37,11 @@ public function getCalendars(string $principalUri, array $calendarUris = []): ar if (!empty($calendarUris)) { $calendarInfos = array_filter($calendarInfos, function ($calendar) use ($calendarUris) { - return in_array($calendar['uri'], $calendarUris); + return in_array($calendar['uri'], $calendarUris, true); }); $federatedCalendarInfos = array_filter($federatedCalendarInfos, function ($federatedCalendar) use ($calendarUris) { - return in_array($federatedCalendar['uri'], $calendarUris); + return in_array($federatedCalendar['uri'], $calendarUris, true); }); } diff --git a/apps/dav/lib/CalDAV/EventReader.php b/apps/dav/lib/CalDAV/EventReader.php index 375eaff12e43a..e27f8032460aa 100644 --- a/apps/dav/lib/CalDAV/EventReader.php +++ b/apps/dav/lib/CalDAV/EventReader.php @@ -739,6 +739,9 @@ public function recurrenceAdvance(): void { $nextExceptionDate = $edateDate; } // if the next date is part of exrule or exdate find another date + // loose comparison needed: DateTime value equality, not instance identity + // (type comes from an untyped Iterator::current(), so psalm can't verify it statically) + /** @psalm-suppress UnrecognizedExpression */ if ($nextOccurrenceDate !== null && $nextExceptionDate !== null && $nextOccurrenceDate == $nextExceptionDate) { $this->recurrenceCurrentDate = $nextOccurrenceDate; $this->recurrenceAdvance(); diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php index 1df4bc01992a1..006f820e4f7b7 100644 --- a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php +++ b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php @@ -253,8 +253,8 @@ public function schedule(Message $iTipMessage) { $invitationLinkRecipients = explode(',', preg_replace('/\s+/', '', strtolower($this->config->getValueString('dav', 'invitation_link_recipients', 'yes')))); if (strcmp('yes', $invitationLinkRecipients[0]) === 0 - || in_array(strtolower($recipient), $invitationLinkRecipients) - || in_array(strtolower($recipientDomain), $invitationLinkRecipients)) { + || in_array(strtolower($recipient), $invitationLinkRecipients, true) + || in_array(strtolower($recipientDomain), $invitationLinkRecipients, true)) { $token = $this->imipService->createInvitationToken($iTipMessage, $vEvent, $lastOccurrence); $this->imipService->addResponseButtons($template, $token); $this->imipService->addMoreOptionsButton($template, $token); diff --git a/apps/dav/lib/CalDAV/Schedule/IMipService.php b/apps/dav/lib/CalDAV/Schedule/IMipService.php index bd1240fb5ed76..1e3a7d1892fbd 100644 --- a/apps/dav/lib/CalDAV/Schedule/IMipService.php +++ b/apps/dav/lib/CalDAV/Schedule/IMipService.php @@ -1273,7 +1273,7 @@ public function isCircle(Property $attendee): bool { public function minimizeInterval(\DateInterval $dateInterval): array { // evaluate if time interval is in the past - if ($dateInterval->invert == 1) { + if ($dateInterval->invert === 1) { return ['interval' => 1, 'scale' => 'past']; } // evaluate interval parts and return smallest time period diff --git a/apps/dav/lib/CalDAV/Status/StatusService.php b/apps/dav/lib/CalDAV/Status/StatusService.php index fbe8d27732723..74481394b5b5a 100644 --- a/apps/dav/lib/CalDAV/Status/StatusService.php +++ b/apps/dav/lib/CalDAV/Status/StatusService.php @@ -163,7 +163,7 @@ private function getCalendarEvents(User $user): array { } $sct = $calendarObject->getSchedulingTransparency(); - if ($sct !== null && strtolower($sct->getValue()) == ScheduleCalendarTransp::TRANSPARENT) { + if ($sct !== null && strtolower($sct->getValue()) === ScheduleCalendarTransp::TRANSPARENT) { // If a calendar is marked as 'transparent', it means we must // ignore it for free-busy purposes. continue; diff --git a/apps/dav/lib/CardDAV/AddressBookImpl.php b/apps/dav/lib/CardDAV/AddressBookImpl.php index 6055f21a142d4..2076adae78063 100644 --- a/apps/dav/lib/CardDAV/AddressBookImpl.php +++ b/apps/dav/lib/CardDAV/AddressBookImpl.php @@ -259,7 +259,7 @@ protected function vCard2Array($uri, VCard $vCard, $withTypes = false) { ]; foreach ($vCard->children() as $property) { - if ($property->name === 'PHOTO' && in_array($property->getValueType(), ['BINARY', 'URI'])) { + if ($property->name === 'PHOTO' && in_array($property->getValueType(), ['BINARY', 'URI'], true)) { $url = $this->urlGenerator->getAbsoluteURL( $this->urlGenerator->linkTo('', 'remote.php') . '/dav/'); $url .= implode('/', [ @@ -270,7 +270,7 @@ protected function vCard2Array($uri, VCard $vCard, $withTypes = false) { ]) . '?photo'; $result['PHOTO'] = 'VALUE=uri:' . $url; - } elseif (in_array($property->name, ['URL', 'GEO', 'CLOUD', 'ADR', 'EMAIL', 'IMPP', 'TEL', 'X-SOCIALPROFILE', 'RELATED', 'LANG', 'X-ADDRESSBOOKSERVER-MEMBER'])) { + } elseif (in_array($property->name, ['URL', 'GEO', 'CLOUD', 'ADR', 'EMAIL', 'IMPP', 'TEL', 'X-SOCIALPROFILE', 'RELATED', 'LANG', 'X-ADDRESSBOOKSERVER-MEMBER'], true)) { if (!isset($result[$property->name])) { $result[$property->name] = []; } diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 8c4da892e041f..51357b704cf51 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -1434,7 +1434,7 @@ protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) ); foreach ($vCard->children() as $property) { - if (!in_array($property->name, self::INDEXED_PROPERTIES)) { + if (!in_array($property->name, self::INDEXED_PROPERTIES, true)) { continue; } $preferred = 0; diff --git a/apps/dav/lib/Comments/CommentsPlugin.php b/apps/dav/lib/Comments/CommentsPlugin.php index 4c3963b194142..bada28b10ce11 100644 --- a/apps/dav/lib/Comments/CommentsPlugin.php +++ b/apps/dav/lib/Comments/CommentsPlugin.php @@ -151,7 +151,7 @@ public function onReport($reportName, $report, $uri) { ]; $ns = '{' . $this::NS_OWNCLOUD . '}'; foreach ($report as $parameter) { - if (!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) { + if (!in_array($parameter['name'], $acceptableParameters, true) || empty($parameter['value'])) { continue; } $args[str_replace($ns, '', $parameter['name'])] = $parameter['value']; diff --git a/apps/dav/lib/Connector/LegacyPublicAuth.php b/apps/dav/lib/Connector/LegacyPublicAuth.php index aad2313bdf795..187b2e8e56dee 100644 --- a/apps/dav/lib/Connector/LegacyPublicAuth.php +++ b/apps/dav/lib/Connector/LegacyPublicAuth.php @@ -77,7 +77,7 @@ protected function validateUserPass($username, $password) { && $this->session->get(PublicAuth::DAV_AUTHENTICATED) === $share->getId()) { return true; } else { - if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { + if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')), true)) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup http_response_code(401); header('WWW-Authenticate: DummyBasic realm="' . $this->realm . '"'); diff --git a/apps/dav/lib/Connector/Sabre/AppleQuirksPlugin.php b/apps/dav/lib/Connector/Sabre/AppleQuirksPlugin.php index 39bce6aaf310a..bf3f2ae579e2a 100644 --- a/apps/dav/lib/Connector/Sabre/AppleQuirksPlugin.php +++ b/apps/dav/lib/Connector/Sabre/AppleQuirksPlugin.php @@ -67,7 +67,7 @@ public function beforeReport(RequestInterface $request, ResponseInterface $respo * @return bool */ public function report($reportName, $report, $path) { - if ($reportName == '{DAV:}principal-property-search' && $this->isMacOSDavAgent) { + if ($reportName === '{DAV:}principal-property-search' && $this->isMacOSDavAgent) { /** @var \Sabre\DAVACL\Xml\Request\PrincipalPropertySearchReport $report */ $report->applyToPrincipalCollectionSet = true; } diff --git a/apps/dav/lib/Connector/Sabre/Auth.php b/apps/dav/lib/Connector/Sabre/Auth.php index 9999433d4481c..71691990c0eaa 100644 --- a/apps/dav/lib/Connector/Sabre/Auth.php +++ b/apps/dav/lib/Connector/Sabre/Auth.php @@ -129,7 +129,7 @@ public function check(RequestInterface $request, ResponseInterface $response) { private function requiresCSRFCheck(): bool { $methodsWithoutCsrf = ['GET', 'HEAD', 'OPTIONS']; - if (in_array($this->request->getMethod(), $methodsWithoutCsrf)) { + if (in_array($this->request->getMethod(), $methodsWithoutCsrf, true)) { return false; } @@ -204,7 +204,7 @@ private function auth(RequestInterface $request, ResponseInterface $response): a $startPos = strrpos($data[1], '/') + 1; $user = $this->userSession->getUser()->getUID(); $data[1] = substr_replace($data[1], $user, $startPos); - } elseif (in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With') ?? ''))) { + } elseif (in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With') ?? ''), true)) { // For ajax requests use dummy auth name to prevent browser popup in case of invalid creditials $response->addHeader('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"'); $response->setStatus(Http::STATUS_UNAUTHORIZED); diff --git a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php index 025b8470fc68a..dfff081330300 100644 --- a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php @@ -331,7 +331,7 @@ public function prepareResponses($filesUri, $requestedProps, $nodes) { $result['href'] = $propFind->getPath(); $resourceType = $this->server->getResourceTypeForNode($node); - if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) { + if (in_array('{DAV:}collection', $resourceType, true) || in_array('{DAV:}principal', $resourceType, true)) { $result['href'] .= '/'; } diff --git a/apps/dav/lib/Connector/Sabre/PublicAuth.php b/apps/dav/lib/Connector/Sabre/PublicAuth.php index 59a7bc178176b..b9ce2fb522b1a 100644 --- a/apps/dav/lib/Connector/Sabre/PublicAuth.php +++ b/apps/dav/lib/Connector/Sabre/PublicAuth.php @@ -194,7 +194,7 @@ protected function validateUserPass($username, $password) { return true; } - if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { + if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')), true)) { // do not re-authenticate over ajax, use dummy auth name to prevent browser popup http_response_code(401); header('WWW-Authenticate: DummyBasic realm="' . $this->realm . '"'); @@ -245,6 +245,6 @@ private function isShareInSession(IShare $share): bool { return false; } - return in_array($share->getId(), $allowedShareIds); + return in_array($share->getId(), $allowedShareIds, true); } } diff --git a/apps/dav/lib/Controller/InvitationResponseController.php b/apps/dav/lib/Controller/InvitationResponseController.php index 5a5105a439165..cd5d47e2ff4f0 100644 --- a/apps/dav/lib/Controller/InvitationResponseController.php +++ b/apps/dav/lib/Controller/InvitationResponseController.php @@ -116,6 +116,8 @@ public function processMoreOptionsResult(string $token):TemplateResponse { $partstat = $this->request->getParam('partStat'); $row = $this->getTokenInformation($token); + // $partstat comes from IRequest::getParam(), which is untyped + /** @psalm-suppress UnrecognizedExpression */ if (!$row || !\in_array($partstat, ['ACCEPTED', 'DECLINED', 'TENTATIVE'])) { return new TemplateResponse($this->appName, 'schedule-response-error', [], 'guest'); } diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php index 60201b97de635..50d28b2b71abd 100644 --- a/apps/dav/lib/DAV/CustomPropertiesBackend.php +++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php @@ -198,7 +198,7 @@ public function propFind($path, PropFind $propFind): void { ]; foreach ($customPropertiesForShares as $customPropertyForShares) { - if (in_array($customPropertyForShares, $allRequestedProps)) { + if (in_array($customPropertyForShares, $allRequestedProps, true)) { $requestedProps[] = $customPropertyForShares; } } diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php index b3b3b5508cf42..6b6e0e50a20ed 100644 --- a/apps/dav/lib/Files/FileSearchBackend.php +++ b/apps/dav/lib/Files/FileSearchBackend.php @@ -118,7 +118,7 @@ private function getPropertyDefinitionsForMetadata(): array { $metadata = $this->filesMetadataManager->getKnownMetadata(); $indexes = $metadata->getIndexes(); foreach ($metadata->getKeys() as $key) { - $isIndex = in_array($key, $indexes); + $isIndex = in_array($key, $indexes, true); $type = match ($metadata->getType($key)) { IMetadataValueWrapper::TYPE_INT => SearchPropertyDefinition::DATATYPE_INTEGER, IMetadataValueWrapper::TYPE_FLOAT => SearchPropertyDefinition::DATATYPE_DECIMAL, diff --git a/apps/dav/lib/SetupChecks/WebdavEndpoint.php b/apps/dav/lib/SetupChecks/WebdavEndpoint.php index e493c6c5a4caf..d86ad1f843d46 100644 --- a/apps/dav/lib/SetupChecks/WebdavEndpoint.php +++ b/apps/dav/lib/SetupChecks/WebdavEndpoint.php @@ -51,7 +51,7 @@ public function run(): SetupResult { $works = null; foreach ($this->runRequest($verb, $url, ['httpErrors' => false]) as $response) { // Check that the response status matches - $works = in_array($response->getStatusCode(), $validStatuses); + $works = in_array($response->getStatusCode(), $validStatuses, true); // Skip the other requests if one works if ($works === true) { break; diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php index 439e82a2defee..c7e97537de8d9 100644 --- a/apps/dav/lib/SystemTag/SystemTagNode.php +++ b/apps/dav/lib/SystemTag/SystemTagNode.php @@ -188,7 +188,7 @@ public function getChild($name) { #[\Override] public function childExists($name) { $objectTypes = $this->tagMapper->getAvailableObjectTypes(); - return in_array($name, $objectTypes); + return in_array($name, $objectTypes, true); } #[\Override] diff --git a/apps/encryption/lib/Command/CleanOrphanedKeys.php b/apps/encryption/lib/Command/CleanOrphanedKeys.php index 8b467f0ed7f9a..6e9629e3db9bd 100644 --- a/apps/encryption/lib/Command/CleanOrphanedKeys.php +++ b/apps/encryption/lib/Command/CleanOrphanedKeys.php @@ -185,7 +185,7 @@ private function deleteAll(array $keys, OutputInterface $output) { private function deleteSpecific(InputInterface $input, OutputInterface $output, array $orphanedKeys) { $question = new Question('Please enter path for key to delete: '); $path = $this->questionHelper->ask($input, $output, $question); - if (!in_array(trim($path), $orphanedKeys)) { + if (!in_array(trim($path), $orphanedKeys, true)) { $output->writeln('Wrong key path'); } else { try { diff --git a/apps/encryption/lib/Command/FixEncryptedVersion.php b/apps/encryption/lib/Command/FixEncryptedVersion.php index 65dc89a7b6bc3..8cf785d81bca8 100644 --- a/apps/encryption/lib/Command/FixEncryptedVersion.php +++ b/apps/encryption/lib/Command/FixEncryptedVersion.php @@ -182,7 +182,7 @@ private function verifyFileContent(string $path, OutputInterface $output, bool $ } $encryptedVersion = $fileInfo->getEncryptedVersion(); $stat = $this->view->stat($path); - if (($encryptedVersion == 0) && isset($stat['hasHeader']) && ($stat['hasHeader'] == true)) { + if (($encryptedVersion === 0) && isset($stat['hasHeader']) && ($stat['hasHeader'] === true)) { // The file has encrypted to false but has an encryption header if ($ignoreCorrectEncVersionCall === true) { // Lets rectify the file by correcting encrypted version diff --git a/apps/encryption/lib/Crypto/Crypt.php b/apps/encryption/lib/Crypto/Crypt.php index 238db34b37967..9972be1edace8 100644 --- a/apps/encryption/lib/Crypto/Crypt.php +++ b/apps/encryption/lib/Crypto/Crypt.php @@ -409,17 +409,10 @@ protected function isValidPrivateKey($plainKey) { } /** - * @param string $keyFileContents - * @param string $passPhrase - * @param string $cipher - * @param int $version - * @param int|string $position - * @param boolean $binaryEncoding - * @return string * @throws DecryptionFailedException */ - public function symmetricDecryptFileContent($keyFileContents, $passPhrase, $cipher = self::DEFAULT_CIPHER, $version = 0, $position = 0, bool $binaryEncoding = false) { - if ($keyFileContents == '') { + public function symmetricDecryptFileContent(string $keyFileContents, string $passPhrase, string $cipher = self::DEFAULT_CIPHER, int $version = 0, int|string $position = 0, bool $binaryEncoding = false): string { + if ($keyFileContents === '') { return ''; } diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php index 5769b48a38137..1d6950a5ab776 100644 --- a/apps/encryption/lib/Crypto/Encryption.php +++ b/apps/encryption/lib/Crypto/Encryption.php @@ -131,7 +131,7 @@ public function begin($path, $user, $mode, array $header, array $accessList) { } /* If useLegacyFileKey is not specified in header, auto-detect, to be safe */ - $useLegacyFileKey = (($header['useLegacyFileKey'] ?? '') == 'false' ? false : null); + $useLegacyFileKey = ((string)($header['useLegacyFileKey'] ?? '') === 'false' ? false : null); $this->fileKey = $this->keyManager->getFileKey($this->path, $useLegacyFileKey, $this->session->decryptAllModeActivated()); diff --git a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php index ac5b5f4ec055f..1575dd1ad7919 100644 --- a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php +++ b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php @@ -95,7 +95,7 @@ public function createFederatedShare($shareWith, $token, $password = '') { $allowedShareIds = []; } - $authenticated = in_array($share->getId(), $allowedShareIds) + $authenticated = in_array($share->getId(), $allowedShareIds, true) || $this->shareManager->checkPassword($share, $password); if ($share->isPasswordProtected() && !$authenticated) { diff --git a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php index 0d1a82a205d6b..e63bea255359d 100644 --- a/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php @@ -127,6 +127,8 @@ public function shareReceived(ICloudFederationShare $share): string { // Check for must-exchange-token requirement $requirements = $protocol['webdav']['requirements'] ?? $protocol['options']['requirements'] ?? []; + // $requirements comes from remote-supplied protocol data of unknown element types + /** @psalm-suppress UnrecognizedExpression */ $mustExchangeToken = in_array('must-exchange-token', $requirements); $accessToken = ''; diff --git a/apps/files/lib/Listener/SyncLivePhotosListener.php b/apps/files/lib/Listener/SyncLivePhotosListener.php index aa1d109b67bf6..62a8725bc16e2 100644 --- a/apps/files/lib/Listener/SyncLivePhotosListener.php +++ b/apps/files/lib/Listener/SyncLivePhotosListener.php @@ -149,7 +149,7 @@ private function handleMove(Node $sourceFile, Node $targetFile, Node $peerFile): $peerTargetName = substr($targetName, 0, -strlen($sourceExtension)) . $peerFileExtension; // in case the rename was initiated from this listener, we stop right now - if (in_array($peerFile->getId(), $this->pendingRenames)) { + if (in_array($peerFile->getId(), $this->pendingRenames, true)) { return; } @@ -245,7 +245,7 @@ private function handleCopyRecursive(Event $event, Node $sourceNode, Node $targe } } elseif ($sourceNode instanceof File && $targetNode instanceof File) { // in case the copy was initiated from this listener, we stop right now - if (in_array($sourceNode->getId(), $this->pendingCopies)) { + if (in_array($sourceNode->getId(), $this->pendingCopies, true)) { return; } diff --git a/apps/files/lib/Service/UserConfig.php b/apps/files/lib/Service/UserConfig.php index d660449cb9bac..a74f26894ceb1 100644 --- a/apps/files/lib/Service/UserConfig.php +++ b/apps/files/lib/Service/UserConfig.php @@ -143,10 +143,12 @@ public function setConfig(string $key, $value): void { throw new \Exception('No user logged in'); } - if (!in_array($key, $this->getAllowedConfigKeys())) { + if (!in_array($key, $this->getAllowedConfigKeys(), true)) { throw new \InvalidArgumentException('Unknown config key'); } + // $value is a string, but allowed values may be booleans (e.g. for toggle configs), so comparison must stay loose + /** @psalm-suppress UnrecognizedExpression */ if (!in_array($value, $this->getAllowedConfigValues($key))) { throw new \InvalidArgumentException('Invalid config value'); } diff --git a/apps/files/lib/Service/ViewConfig.php b/apps/files/lib/Service/ViewConfig.php index 185328d39a833..c8006fc9c7981 100644 --- a/apps/files/lib/Service/ViewConfig.php +++ b/apps/files/lib/Service/ViewConfig.php @@ -102,10 +102,12 @@ public function setConfig(string $view, string $key, $value): void { throw new \Exception('Unknown view'); } - if (!in_array($key, $this->getAllowedConfigKeys())) { + if (!in_array($key, $this->getAllowedConfigKeys(), true)) { throw new \InvalidArgumentException('Unknown config key'); } + // $value is a string, but allowed values may be booleans (e.g. for toggle configs), so comparison must stay loose + /** @psalm-suppress UnrecognizedExpression */ if (!in_array($value, $this->getAllowedConfigValues($key)) && !empty($this->getAllowedConfigValues($key))) { throw new \InvalidArgumentException('Invalid config value'); diff --git a/apps/files_external/lib/Command/Create.php b/apps/files_external/lib/Command/Create.php index 4d4d97a9e52c3..76e0239c6912d 100644 --- a/apps/files_external/lib/Command/Create.php +++ b/apps/files_external/lib/Command/Create.php @@ -120,7 +120,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Http::STATUS_NOT_FOUND; } $supportedSchemes = array_keys($storageBackend->getAuthSchemes()); - if (!in_array($authBackend->getScheme(), $supportedSchemes)) { + if (!in_array($authBackend->getScheme(), $supportedSchemes, true)) { $output->writeln('Authentication backend "' . $authIdentifier . '" not valid for storage backend "' . $storageIdentifier . '" (see `occ files_external:backends storage ' . $storageIdentifier . '` for possible values)'); return self::FAILURE; } diff --git a/apps/files_external/lib/Command/ListCommand.php b/apps/files_external/lib/Command/ListCommand.php index 3ff298b4704b3..e0829d0d2951b 100644 --- a/apps/files_external/lib/Command/ListCommand.php +++ b/apps/files_external/lib/Command/ListCommand.php @@ -114,7 +114,7 @@ public function listMounts($userId, array $mounts, InputInterface $input, Output foreach ($mounts as $mount) { $config = $mount->getBackendOptions(); foreach ($config as $key => $value) { - if (in_array($key, $hideKeys)) { + if (in_array($key, $hideKeys, true)) { $mount->setBackendOption($key, '***REMOVED SENSITIVE VALUE***'); } } diff --git a/apps/files_external/lib/Lib/ApplicableHelper.php b/apps/files_external/lib/Lib/ApplicableHelper.php index 1c603ec2c647b..8e0783b39e82e 100644 --- a/apps/files_external/lib/Lib/ApplicableHelper.php +++ b/apps/files_external/lib/Lib/ApplicableHelper.php @@ -51,12 +51,12 @@ public function isApplicableForUser(StorageConfig $storage, IUser $user): bool { if (count($storage->getApplicableUsers()) + count($storage->getApplicableGroups()) === 0) { return true; } - if (in_array($user->getUID(), $storage->getApplicableUsers())) { + if (in_array($user->getUID(), $storage->getApplicableUsers(), true)) { return true; } $groupIds = $this->groupManager->getUserGroupIds($user); foreach ($groupIds as $groupId) { - if (in_array($groupId, $storage->getApplicableGroups())) { + if (in_array($groupId, $storage->getApplicableGroups(), true)) { return true; } } @@ -84,7 +84,7 @@ public function diffApplicable(StorageConfig $a, StorageConfig $b): \Iterator { } else { $yielded = []; foreach ($a->getApplicableGroups() as $groupId) { - if (!in_array($groupId, $b->getApplicableGroups())) { + if (!in_array($groupId, $b->getApplicableGroups(), true)) { $group = $this->groupManager->get($groupId); if ($group) { foreach ($group->getUsers() as $user) { @@ -99,7 +99,7 @@ public function diffApplicable(StorageConfig $a, StorageConfig $b): \Iterator { } } foreach ($a->getApplicableUsers() as $userId) { - if (!in_array($userId, $b->getApplicableUsers())) { + if (!in_array($userId, $b->getApplicableUsers(), true)) { $user = $this->userManager->get($userId); if ($user && !$this->isApplicableForUser($b, $user)) { if (!isset($yielded[$user->getUID()])) { diff --git a/apps/files_external/lib/Lib/Storage/SFTPReadStream.php b/apps/files_external/lib/Lib/Storage/SFTPReadStream.php index 0547bf25c59a2..7aaeac0040aa7 100644 --- a/apps/files_external/lib/Lib/Storage/SFTPReadStream.php +++ b/apps/files_external/lib/Lib/Storage/SFTPReadStream.php @@ -177,7 +177,7 @@ private function read_chunk() { return $temp; case NET_SFTP_STATUS: [1 => $status] = unpack('N', substr($response, 0, 4)); - if ($status == NET_SFTP_STATUS_EOF) { + if ($status === NET_SFTP_STATUS_EOF) { $this->eof = true; } return ''; diff --git a/apps/files_external/lib/Service/StoragesService.php b/apps/files_external/lib/Service/StoragesService.php index a0088f4950346..545c1be0da68e 100644 --- a/apps/files_external/lib/Service/StoragesService.php +++ b/apps/files_external/lib/Service/StoragesService.php @@ -437,12 +437,12 @@ public function updateOverwriteHomeFolders(): void { $appIdsList = $this->appConfig->getValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS); if ($this->dbConfig->hasHomeFolderOverwriteMount()) { - if (!in_array(Application::APP_ID, $appIdsList)) { + if (!in_array(Application::APP_ID, $appIdsList, true)) { $appIdsList[] = Application::APP_ID; $this->appConfig->setValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS, $appIdsList); } } else { - if (in_array(Application::APP_ID, $appIdsList)) { + if (in_array(Application::APP_ID, $appIdsList, true)) { $appIdsList = array_values(array_filter($appIdsList, fn ($v) => $v !== Application::APP_ID)); $this->appConfig->setValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS, $appIdsList); } diff --git a/apps/files_reminders/lib/Dav/PropFindPlugin.php b/apps/files_reminders/lib/Dav/PropFindPlugin.php index 7be6205ac628e..235b1fc6d5dcc 100644 --- a/apps/files_reminders/lib/Dav/PropFindPlugin.php +++ b/apps/files_reminders/lib/Dav/PropFindPlugin.php @@ -51,7 +51,7 @@ private function preloadCollection( } public function propFind(PropFind $propFind, INode $node) { - if (!in_array(static::REMINDER_DUE_DATE_PROPERTY, $propFind->getRequestedProperties())) { + if (!in_array(static::REMINDER_DUE_DATE_PROPERTY, $propFind->getRequestedProperties(), true)) { return; } diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index ff98c0d08af88..677680697167d 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -891,7 +891,7 @@ private function getSharesInDir(Node $folder): array { $resharingRight = false; $known = []; foreach ($shares as $share) { - if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->userId) { + if (in_array($share->getId(), $known, true) || $share->getSharedWith() === $this->userId) { continue; } @@ -1070,7 +1070,7 @@ private function getFormattedShares( continue; } - if (in_array($share->getId(), $known) + if (in_array($share->getId(), $known, true) || ($share->getSharedWith() === $this->userId && $share->getShareType() === IShare::TYPE_USER)) { continue; } diff --git a/apps/files_sharing/lib/Listener/BeforeNodeReadListener.php b/apps/files_sharing/lib/Listener/BeforeNodeReadListener.php index 65ddb857e4224..5ea097f5bd416 100644 --- a/apps/files_sharing/lib/Listener/BeforeNodeReadListener.php +++ b/apps/files_sharing/lib/Listener/BeforeNodeReadListener.php @@ -75,7 +75,7 @@ public function handleBeforeZipCreatedEvent(BeforeZipCreatedEvent $event): void /** @var ISharedStorage $storage */ $share = $storage->getShare(); - if (!in_array($share->getShareType(), [IShare::TYPE_EMAIL, IShare::TYPE_LINK])) { + if (!in_array($share->getShareType(), [IShare::TYPE_EMAIL, IShare::TYPE_LINK], true)) { return; } @@ -104,7 +104,7 @@ public function handleBeforeNodeReadEvent(BeforeNodeReadEvent $event): void { /** @var ISharedStorage $storage */ $share = $storage->getShare(); - if (!in_array($share->getShareType(), [IShare::TYPE_EMAIL, IShare::TYPE_LINK])) { + if (!in_array($share->getShareType(), [IShare::TYPE_EMAIL, IShare::TYPE_LINK], true)) { return; } diff --git a/apps/files_sharing/lib/Listener/RestrictInteractionListener.php b/apps/files_sharing/lib/Listener/RestrictInteractionListener.php index 32b452d04f5c1..2e942c9a3fc49 100644 --- a/apps/files_sharing/lib/Listener/RestrictInteractionListener.php +++ b/apps/files_sharing/lib/Listener/RestrictInteractionListener.php @@ -78,7 +78,7 @@ public function handle(Event $event): void { if (!$receiver instanceof LinkReceiver && !$receiver instanceof EmailReceiver && (($event->action->filesSharingPermissions !== null && ($event->action->filesSharingPermissions & Constants::PERMISSION_READ) !== Constants::PERMISSION_READ) - || ($event->action->unifiedSharingPermissions !== null && !in_array(NodeReadSharePermissionType::class, $event->action->unifiedSharingPermissions)))) { + || ($event->action->unifiedSharingPermissions !== null && !in_array(NodeReadSharePermissionType::class, $event->action->unifiedSharingPermissions, true)))) { throw new InteractionRestrictedException('No read permission on the share.', $this->l10n->t('File share needs at least read permission.')); } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 50abe44b74d94..dac104f570ce3 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -342,7 +342,7 @@ private function filterShares(iterable $shares, string $userId, array $excludeSh $share->getPermissions() > 0 && $share->getShareOwner() !== $userId && $share->getSharedBy() !== $userId - && !in_array($share->getFullId(), $excludeShareIds) + && !in_array($share->getFullId(), $excludeShareIds, true) ) { yield $share; } diff --git a/apps/files_sharing/lib/ShareRecipientUpdater.php b/apps/files_sharing/lib/ShareRecipientUpdater.php index 144bdc7bc947b..594af4f342361 100644 --- a/apps/files_sharing/lib/ShareRecipientUpdater.php +++ b/apps/files_sharing/lib/ShareRecipientUpdater.php @@ -101,7 +101,7 @@ public function updateForDeletedShare(IUser $user, IShare $share): void { */ public function updateForMovedShare(IUser $user, IShare $share): void { $originalTarget = $share->getOriginalTarget(); - if ($originalTarget != null) { + if ($originalTarget !== null) { $newMountPoint = $this->getMountPointFromTarget($user, $share->getTarget()); $oldMountPoint = $this->getMountPointFromTarget($user, $originalTarget); $this->userMountCache->removeMount($oldMountPoint, $user); diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php index 373ee3fe4dfe2..7a2909c3ad839 100644 --- a/apps/files_sharing/lib/SharedStorage.php +++ b/apps/files_sharing/lib/SharedStorage.php @@ -212,7 +212,7 @@ private function init() { #[\Override] public function instanceOfStorage(string $class): bool { - if ($class === '\OC\Files\Storage\Common' || $class == Common::class) { + if ($class === '\OC\Files\Storage\Common' || $class === Common::class) { return true; } if (in_array($class, [ diff --git a/apps/files_sharing/lib/SharesReminderJob.php b/apps/files_sharing/lib/SharesReminderJob.php index 255d2204a1483..0338b869de9a4 100644 --- a/apps/files_sharing/lib/SharesReminderJob.php +++ b/apps/files_sharing/lib/SharesReminderJob.php @@ -219,7 +219,7 @@ private function filterSharesWithEmptyFolders(array $shares, int $maxResults): a private function prepareReminder(IShare $share): ?array { $sharedWith = $share->getSharedWith(); $reminderInfo = []; - if ($share->getShareType() == IShare::TYPE_USER) { + if ((int)$share->getShareType() === IShare::TYPE_USER) { $user = $this->userManager->get($sharedWith); if ($user === null) { return null; diff --git a/apps/files_trashbin/lib/Command/Size.php b/apps/files_trashbin/lib/Command/Size.php index 90c9402c7b227..2458096ea1e1e 100644 --- a/apps/files_trashbin/lib/Command/Size.php +++ b/apps/files_trashbin/lib/Command/Size.php @@ -89,7 +89,7 @@ private function printTrashbinSize(InputInterface $input, OutputInterface $outpu $userHumanSize = Util::humanFileSize($userSize); } - if ($input->getOption('output') == self::OUTPUT_FORMAT_PLAIN) { + if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) { $output->writeln($userHumanSize); } else { $userValue = ($userSize < 0) ? 'default' : $userSize; @@ -107,7 +107,7 @@ private function printTrashbinSize(InputInterface $input, OutputInterface $outpu }); $userValues = $this->config->getUserValueForUsers('files_trashbin', 'trashbin_size', $users); - if ($input->getOption('output') == self::OUTPUT_FORMAT_PLAIN) { + if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) { $output->writeln("Default size: $globalHumanSize"); $output->writeln(''); if (count($userValues)) { diff --git a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php index 59a52a7f47ae4..f80e5bd14a46d 100644 --- a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php +++ b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php @@ -255,7 +255,7 @@ public function createVersionEntity(File $file): ?VersionEntity { if (!in_array($e->getReason(), [ \OCP\DB\Exception::REASON_CONSTRAINT_VIOLATION, \OCP\DB\Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION, - ]) + ], true) ) { throw $e; } diff --git a/apps/oauth2/lib/Controller/LoginRedirectorController.php b/apps/oauth2/lib/Controller/LoginRedirectorController.php index 8fa2d12c83f7d..35449154cab24 100644 --- a/apps/oauth2/lib/Controller/LoginRedirectorController.php +++ b/apps/oauth2/lib/Controller/LoginRedirectorController.php @@ -86,7 +86,7 @@ public function authorize( $this->session->set('oauth.state', $state); - if (in_array($client->name, $this->appConfig->getValueArray('oauth2', 'skipAuthPickerApplications', []))) { + if (in_array($client->name, $this->appConfig->getValueArray('oauth2', 'skipAuthPickerApplications', []), true)) { /** @see ClientFlowLoginController::showAuthPickerPage **/ $stateToken = $this->random->generate( 64, diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php index 496c89aee23c8..f3ef5fc817fc9 100644 --- a/apps/provisioning_api/lib/Controller/UsersController.php +++ b/apps/provisioning_api/lib/Controller/UsersController.php @@ -845,7 +845,7 @@ public function editUserMultiValue( } // Check if permitted to edit this field - if (!in_array($collectionName, $permittedFields)) { + if (!in_array($collectionName, $permittedFields, true)) { throw new OCSException('', 103); } @@ -1311,7 +1311,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon } } // Check if permitted to edit this field - if (!in_array($key, $permittedFields)) { + if (!in_array($key, $permittedFields, true)) { throw new OCSException('', 113); } // Process the edit @@ -1359,7 +1359,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon break; case self::USER_FIELD_TIMEZONE: // Older browsers still report deprecated aliases like Europe/Kiev. - if (!in_array($value, \DateTimeZone::listIdentifiers(\DateTimeZone::ALL_WITH_BC))) { + if (!in_array($value, \DateTimeZone::listIdentifiers(\DateTimeZone::ALL_WITH_BC), true)) { throw new OCSException($this->l10n->t('Invalid timezone'), 101); } $this->config->setUserValue($targetUser->getUID(), 'core', 'timezone', $value); diff --git a/apps/settings/lib/Controller/MailSettingsController.php b/apps/settings/lib/Controller/MailSettingsController.php index d9333e6122cc8..c0a77b4a20d70 100644 --- a/apps/settings/lib/Controller/MailSettingsController.php +++ b/apps/settings/lib/Controller/MailSettingsController.php @@ -62,7 +62,7 @@ public function setMailSettings( string $mail_sendmailmode, ?bool $mail_noverify = null, ): DataResponse { - $mail_smtpauth = $mail_smtpauth == '1'; + $mail_smtpauth = $mail_smtpauth === true; $configs = [ 'mail_domain' => $mail_domain, diff --git a/apps/settings/lib/SetupChecks/MemcacheConfigured.php b/apps/settings/lib/SetupChecks/MemcacheConfigured.php index ce8814a8ae782..8ab4f642b5468 100644 --- a/apps/settings/lib/SetupChecks/MemcacheConfigured.php +++ b/apps/settings/lib/SetupChecks/MemcacheConfigured.php @@ -42,7 +42,7 @@ public function run(): SetupResult { $memcacheLockingClass = $this->config->getSystemValue('memcache.locking', null); $memcacheLocalClass = $this->config->getSystemValue('memcache.local', null); $caches = array_filter([$memcacheDistributedClass,$memcacheLockingClass,$memcacheLocalClass]); - if (in_array(Memcached::class, array_map(fn (string $class) => ltrim($class, '\\'), $caches))) { + if (in_array(Memcached::class, array_map(fn (string $class) => ltrim($class, '\\'), $caches), true)) { // wrong PHP module is installed if (extension_loaded('memcache') && !extension_loaded('memcached')) { return SetupResult::warning( diff --git a/apps/settings/lib/SetupChecks/OverwriteCliUrl.php b/apps/settings/lib/SetupChecks/OverwriteCliUrl.php index 7202cd7c1a212..da1a5824c86b3 100644 --- a/apps/settings/lib/SetupChecks/OverwriteCliUrl.php +++ b/apps/settings/lib/SetupChecks/OverwriteCliUrl.php @@ -40,7 +40,7 @@ public function run(): SetupResult { // Check correctness by checking if it is a valid URL if (filter_var($currentOverwriteCliUrl, FILTER_VALIDATE_URL)) { - if ($currentOverwriteCliUrl == $suggestedOverwriteCliUrl) { + if ($currentOverwriteCliUrl === $suggestedOverwriteCliUrl) { return SetupResult::success( $this->l10n->t( 'The "overwrite.cli.url" option in your config.php is correctly set to "%s".', diff --git a/apps/settings/lib/SetupChecks/SecurityHeaders.php b/apps/settings/lib/SetupChecks/SecurityHeaders.php index 2fee92d160d59..ec4b7a5cc09b0 100644 --- a/apps/settings/lib/SetupChecks/SecurityHeaders.php +++ b/apps/settings/lib/SetupChecks/SecurityHeaders.php @@ -57,7 +57,7 @@ public function run(): SetupResult { $works = null; foreach ($this->runRequest($verb, $url, ['httpErrors' => false]) as $response) { // Check that the response status matches - if (!in_array($response->getStatusCode(), $validStatuses)) { + if (!in_array($response->getStatusCode(), $validStatuses, true)) { $works = false; continue; } diff --git a/apps/settings/lib/SetupChecks/WellKnownUrls.php b/apps/settings/lib/SetupChecks/WellKnownUrls.php index e1599376efaa8..68ff75afc313b 100644 --- a/apps/settings/lib/SetupChecks/WellKnownUrls.php +++ b/apps/settings/lib/SetupChecks/WellKnownUrls.php @@ -59,7 +59,7 @@ public function run(): SetupResult { $works = null; foreach ($this->runRequest($verb, $url, $requestOptions, isRootRequest: true) as $response) { // Check that the response status matches - $works = in_array($response->getStatusCode(), $validStatuses); + $works = in_array($response->getStatusCode(), $validStatuses, true); // and (if needed) the custom Nextcloud header is set if ($checkCustomHeader) { $works = $works && !empty($response->getHeader('X-NEXTCLOUD-WELL-KNOWN')); diff --git a/apps/sharebymail/lib/Activity.php b/apps/sharebymail/lib/Activity.php index 65a2b3088b808..0d18d527e3521 100644 --- a/apps/sharebymail/lib/Activity.php +++ b/apps/sharebymail/lib/Activity.php @@ -212,6 +212,8 @@ protected function getContactName(string $email): string { continue; } + // $contact['EMAIL'] structure varies by address book backend and vCard cardinality + /** @psalm-suppress UnrecognizedExpression */ if (in_array($email, $contact['EMAIL'])) { return $contact['FN']; } diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index b71a0106ed0e9..76c1129366701 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -402,7 +402,7 @@ public function getImage(string $key, bool $useSvg = true) { #[NoSameSiteCookieRequired] public function getThemeStylesheet(string $themeId, bool $plain = false, bool $withCustomCss = false) { $themes = $this->themesService->getThemes(); - if (!in_array($themeId, array_keys($themes))) { + if (!in_array($themeId, array_keys($themes), true)) { return new NotFoundResponse(); } diff --git a/apps/theming/lib/Listener/BeforePreferenceListener.php b/apps/theming/lib/Listener/BeforePreferenceListener.php index 0e3a9ab931ed3..44ccb62fff6a7 100644 --- a/apps/theming/lib/Listener/BeforePreferenceListener.php +++ b/apps/theming/lib/Listener/BeforePreferenceListener.php @@ -48,7 +48,7 @@ public function handle(Event $event): void { } private function handleThemingValues(BeforePreferenceSetEvent|BeforePreferenceDeletedEvent $event): void { - if (!in_array($event->getConfigKey(), self::ALLOWED_KEYS)) { + if (!in_array($event->getConfigKey(), self::ALLOWED_KEYS, true)) { // Not allowed config key return; } diff --git a/apps/theming/lib/Service/ThemesService.php b/apps/theming/lib/Service/ThemesService.php index 8f5d1eefd550a..9ca49eb6b8eb2 100644 --- a/apps/theming/lib/Service/ThemesService.php +++ b/apps/theming/lib/Service/ThemesService.php @@ -91,7 +91,7 @@ public function enableTheme(ITheme $theme): array { $enabledThemeIds = $this->getEnabledThemes(); // If already enabled, ignore - if (in_array($theme->getId(), $enabledThemeIds)) { + if (in_array($theme->getId(), $enabledThemeIds, true)) { return $enabledThemeIds; } @@ -116,7 +116,7 @@ public function disableTheme(ITheme $theme): array { $themesIds = $this->getEnabledThemes(); // If enabled, removing it - if (in_array($theme->getId(), $themesIds)) { + if (in_array($theme->getId(), $themesIds, true)) { $enabledThemes = array_values(array_diff($themesIds, [$theme->getId()])); $this->setEnabledThemes($enabledThemes); return $enabledThemes; @@ -136,7 +136,7 @@ public function isEnabled(ITheme $theme): bool { if ($user instanceof IUser) { // Using keys as it's faster $themes = $this->getEnabledThemes(); - return in_array($theme->getId(), $themes); + return in_array($theme->getId(), $themes, true); } return false; } diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php index 7aeb3e7107a6f..87b5a58677c5b 100644 --- a/apps/theming/lib/ThemingDefaults.php +++ b/apps/theming/lib/ThemingDefaults.php @@ -464,7 +464,7 @@ public function set($setting, $value): void { $this->appConfig->setAppValueInt(ConfigLexicon::CACHE_BUSTER, (int)$value); break; case ConfigLexicon::USER_THEMING_DISABLED: - $value = in_array($value, ['1', 'true', 'yes', 'on']); + $value = in_array($value, ['1', 'true', 'yes', 'on'], true); $this->appConfig->setAppValueBool(ConfigLexicon::USER_THEMING_DISABLED, $value); break; default: diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index 2b0018e15ae95..aba397f4f09ee 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -364,7 +364,7 @@ private function resemblesDN($attr) { // memberOf is an "operational" attribute, without a definition in any RFC 'memberof' ]; - return in_array($attr, $resemblingAttributes); + return in_array($attr, $resemblingAttributes, true); } /** diff --git a/apps/user_ldap/lib/Command/CheckUser.php b/apps/user_ldap/lib/Command/CheckUser.php index 363518673e76c..b86c58e30b9fd 100644 --- a/apps/user_ldap/lib/Command/CheckUser.php +++ b/apps/user_ldap/lib/Command/CheckUser.php @@ -171,7 +171,7 @@ private function updateUser(string $uid, OutputInterface $output): void { foreach ($result[0] as $attribute => $valueSet) { $output->writeln(' ' . $attribute . ': '); foreach ($valueSet as $value) { - if (in_array($attribute, $avatarAttributes)) { + if (in_array($attribute, $avatarAttributes, true)) { $value = '{ImageData}'; } $output->writeln(' ' . $value); diff --git a/apps/user_ldap/lib/Command/ResetGroup.php b/apps/user_ldap/lib/Command/ResetGroup.php index e26caad7c84d3..f83983bc92ccb 100644 --- a/apps/user_ldap/lib/Command/ResetGroup.php +++ b/apps/user_ldap/lib/Command/ResetGroup.php @@ -55,7 +55,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw new \Exception('Group not found'); } $backends = $group->getBackendNames(); - if (!in_array('LDAP', $backends)) { + if (!in_array('LDAP', $backends, true)) { throw new \Exception('The given group is not a recognized LDAP group.'); } if ($input->getOption('yes') === false) { diff --git a/apps/user_ldap/lib/Command/SetConfig.php b/apps/user_ldap/lib/Command/SetConfig.php index 3b223775bb8e4..8544a0a3d7312 100644 --- a/apps/user_ldap/lib/Command/SetConfig.php +++ b/apps/user_ldap/lib/Command/SetConfig.php @@ -51,7 +51,7 @@ protected function configure(): void { protected function execute(InputInterface $input, OutputInterface $output): int { $availableConfigs = $this->helper->getServerConfigurationPrefixes(); $configID = $input->getArgument('configID'); - if (!in_array($configID, $availableConfigs)) { + if (!in_array($configID, $availableConfigs, true)) { $output->writeln('Invalid configID'); return self::FAILURE; } diff --git a/apps/user_ldap/lib/Command/ShowConfig.php b/apps/user_ldap/lib/Command/ShowConfig.php index 36a8349287cc0..d55706c428336 100644 --- a/apps/user_ldap/lib/Command/ShowConfig.php +++ b/apps/user_ldap/lib/Command/ShowConfig.php @@ -56,7 +56,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $configID = $input->getArgument('configID'); if (!is_null($configID)) { $configIDs[] = $configID; - if (!in_array($configIDs[0], $availableConfigs)) { + if (!in_array($configIDs[0], $availableConfigs, true)) { $output->writeln('Invalid configID'); return self::FAILURE; } diff --git a/apps/user_ldap/lib/Command/TestConfig.php b/apps/user_ldap/lib/Command/TestConfig.php index a67371423b33f..39d6e9d67d749 100644 --- a/apps/user_ldap/lib/Command/TestConfig.php +++ b/apps/user_ldap/lib/Command/TestConfig.php @@ -48,7 +48,7 @@ protected function configure(): void { protected function execute(InputInterface $input, OutputInterface $output): int { $availableConfigs = $this->helper->getServerConfigurationPrefixes(); $configID = $input->getArgument('configID'); - if (!in_array($configID, $availableConfigs)) { + if (!in_array($configID, $availableConfigs, true)) { $output->writeln('Invalid configID'); return self::FAILURE; } diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 3cc86922dada4..ea4d766fe0e84 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -160,7 +160,7 @@ public function __construct( } $helper = Server::get(Helper::class); $this->doNotValidate = !in_array($this->configPrefix, - $helper->getServerConfigurationPrefixes()); + $helper->getServerConfigurationPrefixes(), true); $this->logger = Server::get(LoggerInterface::class); $this->l10n = Util::getL10N('user_ldap'); } @@ -416,7 +416,7 @@ private function doSoftValidation(): void { } else { $uuidAttributes = Access::UUID_ATTRIBUTES; array_unshift($uuidAttributes, 'auto'); - if (!in_array($this->configuration->$effectiveSetting, $uuidAttributes) + if (!in_array($this->configuration->$effectiveSetting, $uuidAttributes, true) && !is_null($this->configID)) { $this->configuration->$effectiveSetting = 'auto'; $this->configuration->saveConfiguration(); diff --git a/apps/user_ldap/lib/GroupPluginManager.php b/apps/user_ldap/lib/GroupPluginManager.php index 8ec7c1bf7af11..bb8daa2ce7f63 100644 --- a/apps/user_ldap/lib/GroupPluginManager.php +++ b/apps/user_ldap/lib/GroupPluginManager.php @@ -55,7 +55,7 @@ public function register(ILDAPGroupPlugin $plugin) { * @return bool */ public function implementsActions($actions) { - return ($actions & $this->respondToActions) == $actions; + return ($actions & $this->respondToActions) === $actions; } /** diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index abeac906a42c8..93320b3166920 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -79,7 +79,7 @@ public function inGroup($uid, $gid): bool { $userDN = $this->access->username2dn($uid); if (isset($this->cachedGroupMembers[$gid])) { - return in_array($userDN, $this->cachedGroupMembers[$gid]); + return in_array($userDN, $this->cachedGroupMembers[$gid], true); } $cacheKeyMembers = 'inGroup-members:' . $gid; @@ -157,7 +157,7 @@ public function inGroup($uid, $gid): bool { return false; } - $isInGroup = in_array($userDN, $members); + $isInGroup = in_array($userDN, $members, true); $this->access->connection->writeToCache($cacheKey, $isInGroup); $this->access->connection->writeToCache($cacheKeyMembers, $members); $this->cachedGroupMembers[$gid] = $members; @@ -1245,7 +1245,7 @@ public function createGroup($gid) { $this->access->cacheGroupExists($gid); } } - return $dn != null; + return $dn !== null && $dn !== false; } throw new Exception('Could not create group in LDAP backend.'); } diff --git a/apps/user_ldap/lib/Jobs/Sync.php b/apps/user_ldap/lib/Jobs/Sync.php index df2f422527ef3..85cece359ede8 100644 --- a/apps/user_ldap/lib/Jobs/Sync.php +++ b/apps/user_ldap/lib/Jobs/Sync.php @@ -160,7 +160,7 @@ public function getCycle(): ?array { if ( $cycleData['prefix'] !== 'none' - && in_array($cycleData['prefix'], $prefixes) + && in_array($cycleData['prefix'], $prefixes, true) ) { return $cycleData; } diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index f9b3f669c3e02..c6892312b0ae7 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -150,7 +150,7 @@ public function getAttributes($minimal = false) { $attributes = array_reduce($attributes, function ($list, $attribute) { $attribute = strtolower(trim((string)$attribute)); - if (!empty($attribute) && !in_array($attribute, $list)) { + if (!empty($attribute) && !in_array($attribute, $list, true)) { $list[] = $attribute; } diff --git a/apps/user_ldap/lib/UserPluginManager.php b/apps/user_ldap/lib/UserPluginManager.php index 5f7a2881d3443..43da25c1a73be 100644 --- a/apps/user_ldap/lib/UserPluginManager.php +++ b/apps/user_ldap/lib/UserPluginManager.php @@ -61,7 +61,7 @@ public function register(ILDAPUserPlugin $plugin) { * @return bool */ public function implementsActions($actions) { - return ($actions & $this->respondToActions) == $actions; + return ($actions & $this->respondToActions) === $actions; } /** diff --git a/apps/user_ldap/lib/Wizard.php b/apps/user_ldap/lib/Wizard.php index 876f001fb2728..f874d15444bcc 100644 --- a/apps/user_ldap/lib/Wizard.php +++ b/apps/user_ldap/lib/Wizard.php @@ -1161,7 +1161,7 @@ public function cumulativeSearchOnAttribute(array $filters, string $attr, int $d $rr = $entry; //will be expected by nextEntry next round $attributes = $this->ldap->getAttributes($cr, $entry); $dn = $this->ldap->getDN($cr, $entry); - if ($attributes === false || $dn === false || in_array($dn, $dnRead)) { + if ($attributes === false || $dn === false || in_array($dn, $dnRead, true)) { continue; } $newItems = []; @@ -1256,6 +1256,8 @@ private function getAttributeValuesFromEntry(array $result, string $attribute, a if ($key === 'count') { continue; } + // $val comes from the raw ldap_get_attributes() result with unknown element types + /** @psalm-suppress UnrecognizedExpression */ if (!in_array($val, $known)) { $known[] = $val; } diff --git a/apps/webhook_listeners/lib/Service/PHPMongoQuery.php b/apps/webhook_listeners/lib/Service/PHPMongoQuery.php index 0c49e89058355..374ab2a137cbd 100644 --- a/apps/webhook_listeners/lib/Service/PHPMongoQuery.php +++ b/apps/webhook_listeners/lib/Service/PHPMongoQuery.php @@ -174,9 +174,13 @@ private static function _executeQueryOnElement(array $query, string $element, ar */ private static function _isEqual($v, $operatorValue): bool { if (is_array($v) && is_array($operatorValue)) { + // deliberately Mongo-style loose array equality, see method docblock + /** @psalm-suppress UnrecognizedExpression */ return $v == $operatorValue; } if (is_array($v)) { + // deliberately Mongo-style loose membership check, see method docblock + /** @psalm-suppress UnrecognizedExpression */ return in_array($operatorValue, $v); } if (is_string($operatorValue) && preg_match('/^\/(.*?)\/([a-z]*)$/i', $operatorValue, $matches)) { @@ -267,6 +271,8 @@ private static function _executeOperatorOnElement(string $operator, $operatorVal if (is_array($v)) { return count(array_intersect($v, $operatorValue)) > 0; } + // $v and $operatorValue are Mongo-style query values of unknown type, loose match is intentional + /** @psalm-suppress UnrecognizedExpression */ return in_array($v, $operatorValue); case '$lt': return $exists && $v < $operatorValue; case '$lte': return $exists && $v <= $operatorValue; @@ -286,6 +292,8 @@ private static function _executeOperatorOnElement(string $operator, $operatorVal if (is_array($v)) { return count(array_intersect($v, $operatorValue)) === 0; } + // $v and $operatorValue are Mongo-style query values of unknown type, loose match is intentional + /** @psalm-suppress UnrecognizedExpression */ return !in_array($v, $operatorValue); case '$exists': return ($operatorValue && $exists) || (!$operatorValue && !$exists); case '$mod': diff --git a/apps/workflowengine/lib/Check/AbstractStringCheck.php b/apps/workflowengine/lib/Check/AbstractStringCheck.php index 98352b804e752..db1fb02d8806f 100644 --- a/apps/workflowengine/lib/Check/AbstractStringCheck.php +++ b/apps/workflowengine/lib/Check/AbstractStringCheck.php @@ -68,7 +68,7 @@ protected function executeStringCheck($operator, $checkValue, $actualValue) { */ #[\Override] public function validateCheck($operator, $value): void { - if (!in_array($operator, ['is', '!is', 'matches', '!matches'])) { + if (!in_array($operator, ['is', '!is', 'matches', '!matches'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Check/FileSize.php b/apps/workflowengine/lib/Check/FileSize.php index 6e312ca9ad3ae..c8eaf422ea7e1 100644 --- a/apps/workflowengine/lib/Check/FileSize.php +++ b/apps/workflowengine/lib/Check/FileSize.php @@ -51,7 +51,7 @@ public function executeCheck($operator, $value): bool { */ #[\Override] public function validateCheck($operator, $value): void { - if (!in_array($operator, ['less', '!less', 'greater', '!greater'])) { + if (!in_array($operator, ['less', '!less', 'greater', '!greater'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Check/FileSystemTags.php b/apps/workflowengine/lib/Check/FileSystemTags.php index dfd4f282c1c49..613ed833d0880 100644 --- a/apps/workflowengine/lib/Check/FileSystemTags.php +++ b/apps/workflowengine/lib/Check/FileSystemTags.php @@ -48,7 +48,7 @@ public function __construct( #[\Override] public function executeCheck($operator, $value) { $systemTags = $this->getSystemTags(); - return ($operator === 'is') === in_array($value, $systemTags); + return ($operator === 'is') === in_array($value, $systemTags, true); } /** @@ -58,7 +58,7 @@ public function executeCheck($operator, $value) { */ #[\Override] public function validateCheck($operator, $value) { - if (!in_array($operator, ['is', '!is'])) { + if (!in_array($operator, ['is', '!is'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Check/RequestRemoteAddress.php b/apps/workflowengine/lib/Check/RequestRemoteAddress.php index e59f923f00e96..34ad8e2caa43a 100644 --- a/apps/workflowengine/lib/Check/RequestRemoteAddress.php +++ b/apps/workflowengine/lib/Check/RequestRemoteAddress.php @@ -60,7 +60,7 @@ public function executeCheck($operator, $value) { */ #[\Override] public function validateCheck($operator, $value) { - if (!in_array($operator, ['matchesIPv4', '!matchesIPv4', 'matchesIPv6', '!matchesIPv6'])) { + if (!in_array($operator, ['matchesIPv4', '!matchesIPv4', 'matchesIPv6', '!matchesIPv6'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Check/RequestTime.php b/apps/workflowengine/lib/Check/RequestTime.php index 5dc77ace92cd9..981c6d18bce26 100644 --- a/apps/workflowengine/lib/Check/RequestTime.php +++ b/apps/workflowengine/lib/Check/RequestTime.php @@ -81,7 +81,7 @@ protected function getTimestamp($currentTimestamp, $value) { */ #[\Override] public function validateCheck($operator, $value) { - if (!in_array($operator, ['in', '!in'])) { + if (!in_array($operator, ['in', '!in'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Check/RequestURL.php b/apps/workflowengine/lib/Check/RequestURL.php index f3e5d5ef108b1..ff15a4c84e2b7 100644 --- a/apps/workflowengine/lib/Check/RequestURL.php +++ b/apps/workflowengine/lib/Check/RequestURL.php @@ -39,7 +39,7 @@ public function executeCheck($operator, $value) { } else { $actualValue = $this->getActualValue(); } - if (in_array($operator, ['is', '!is'])) { + if (in_array($operator, ['is', '!is'], true)) { switch ($value) { case 'webdav': if ($operator === 'is') { diff --git a/apps/workflowengine/lib/Check/UserGroupMembership.php b/apps/workflowengine/lib/Check/UserGroupMembership.php index 2a029dde402a4..5fb90af2514d1 100644 --- a/apps/workflowengine/lib/Check/UserGroupMembership.php +++ b/apps/workflowengine/lib/Check/UserGroupMembership.php @@ -45,7 +45,7 @@ public function executeCheck($operator, $value) { if ($user instanceof IUser) { $groupIds = $this->getUserGroups($user); - return ($operator === 'is') === in_array($value, $groupIds); + return ($operator === 'is') === in_array($value, $groupIds, true); } else { return $operator !== 'is'; } @@ -58,7 +58,7 @@ public function executeCheck($operator, $value) { */ #[\Override] public function validateCheck($operator, $value) { - if (!in_array($operator, ['is', '!is'])) { + if (!in_array($operator, ['is', '!is'], true)) { throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1); } diff --git a/apps/workflowengine/lib/Manager.php b/apps/workflowengine/lib/Manager.php index 527c43ab42478..fdbc8c705b5cb 100644 --- a/apps/workflowengine/lib/Manager.php +++ b/apps/workflowengine/lib/Manager.php @@ -613,7 +613,7 @@ public function deleteOperation(int $id, ScopeContext $scopeContext): bool { protected function validateEvents(string $entity, array $events, IOperation $operation): void { /** @psalm-suppress TaintedCallable newInstance is not called */ $reflection = new \ReflectionClass($entity); - if ($entity !== IEntity::class && !in_array(IEntity::class, $reflection->getInterfaceNames())) { + if ($entity !== IEntity::class && !in_array(IEntity::class, $reflection->getInterfaceNames(), true)) { throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity])); } @@ -655,7 +655,7 @@ public function validateOperation(string $class, string $name, array $checks, st /** @psalm-suppress TaintedCallable newInstance is not called */ $reflection = new \ReflectionClass($class); - if ($class !== IOperation::class && !in_array(IOperation::class, $reflection->getInterfaceNames())) { + if ($class !== IOperation::class && !in_array(IOperation::class, $reflection->getInterfaceNames(), true)) { throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]) . join(', ', $reflection->getInterfaceNames())); } @@ -688,7 +688,7 @@ public function validateOperation(string $class, string $name, array $checks, st } $reflection = new \ReflectionClass($check['class']); - if ($check['class'] !== ICheck::class && !in_array(ICheck::class, $reflection->getInterfaceNames())) { + if ($check['class'] !== ICheck::class && !in_array(ICheck::class, $reflection->getInterfaceNames(), true)) { throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class])); } @@ -700,7 +700,7 @@ public function validateOperation(string $class, string $name, array $checks, st } if (!empty($instance->supportedEntities()) - && !in_array($entity, $instance->supportedEntities()) + && !in_array($entity, $instance->supportedEntities(), true) ) { throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class])); } diff --git a/apps/workflowengine/lib/Service/RuleMatcher.php b/apps/workflowengine/lib/Service/RuleMatcher.php index e4e2c0961ec65..85fd93a41d837 100644 --- a/apps/workflowengine/lib/Service/RuleMatcher.php +++ b/apps/workflowengine/lib/Service/RuleMatcher.php @@ -121,6 +121,8 @@ public function getFlows(bool $returnFirstMatchingOperationOnly = true): array { $additionalScopes = $this->manager->getAllConfiguredScopesForOperation($class) + $this->manager->getAllConfiguredScopesForRuntimeOperation($class); foreach ($additionalScopes as $hash => $scopeCandidate) { + // $scopes and $scopeCandidate are freshly built ScopeContext instances, strict comparison would compare identity instead of value + /** @psalm-suppress UnrecognizedExpression */ if ($scopeCandidate->getScope() !== IManager::SCOPE_USER || in_array($scopeCandidate, $scopes)) { continue; } @@ -151,6 +153,8 @@ public function getFlows(bool $returnFirstMatchingOperationOnly = true): array { $checks = $this->manager->getChecks($checkIds); } + // $configuredEvents may come from json_decode() of stored data with unverified element types + /** @psalm-suppress UnrecognizedExpression */ if ($this->eventName !== null && !in_array($this->eventName, $configuredEvents)) { continue; } diff --git a/core/Command/Config/System/DeleteConfig.php b/core/Command/Config/System/DeleteConfig.php index 2f214875bba1c..c683472b890f4 100644 --- a/core/Command/Config/System/DeleteConfig.php +++ b/core/Command/Config/System/DeleteConfig.php @@ -48,7 +48,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $configName = $configNames[0]; if (count($configNames) > 1) { - if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) { + if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys(), true)) { $output->writeln('System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist'); return 1; } @@ -66,7 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('System config value ' . implode(' => ', $configNames) . ' deleted'); return 0; } else { - if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) { + if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys(), true)) { $output->writeln('System config ' . $configName . ' could not be deleted because it did not exist'); return 1; } diff --git a/core/Command/Config/System/GetConfig.php b/core/Command/Config/System/GetConfig.php index bf89567bd57e7..a45528cca0e06 100644 --- a/core/Command/Config/System/GetConfig.php +++ b/core/Command/Config/System/GetConfig.php @@ -55,11 +55,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $configName = array_shift($configNames); $defaultValue = $input->getOption('default-value'); - if (!in_array($configName, $this->systemConfig->getKeys()) && !$input->hasParameterOption('--default-value')) { + if (!in_array($configName, $this->systemConfig->getKeys(), true) && !$input->hasParameterOption('--default-value')) { return 1; } - if (!in_array($configName, $this->systemConfig->getKeys())) { + if (!in_array($configName, $this->systemConfig->getKeys(), true)) { $configValue = $defaultValue; } else { $configValue = $this->systemConfig->getValue($configName); diff --git a/core/Command/Db/SchemaEncoder.php b/core/Command/Db/SchemaEncoder.php index beae3a8126492..b9772dcad197d 100644 --- a/core/Command/Db/SchemaEncoder.php +++ b/core/Command/Db/SchemaEncoder.php @@ -69,7 +69,7 @@ private function encodeTable(Table $table, AbstractPlatform $platform): array { } elseif ($platform instanceof AbstractMySqlPlatform) { if ($column->getType() instanceof PhpIntegerMappingType) { $data['length'] = null; - } elseif (in_array($data['type'], ['text', 'blob', 'datetime', 'float', 'json'])) { + } elseif (in_array($data['type'], ['text', 'blob', 'datetime', 'float', 'json'], true)) { $data['length'] = 0; } unset($data['collation']); diff --git a/core/Command/Info/File.php b/core/Command/Info/File.php index 8c08b73d102c0..bf9d328d95460 100644 --- a/core/Command/Info/File.php +++ b/core/Command/Info/File.php @@ -101,7 +101,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { $childSize = array_sum(array_map(function (Node $node) { return $node->getSize(); }, $children)); - if ($childSize != $node->getSize()) { + if ((float)$childSize !== (float)$node->getSize()) { $output->writeln(' warning: folder has a size of ' . Util::humanFileSize($node->getSize()) . " but it's children sum up to " . Util::humanFileSize($childSize) . '.'); if (!$node->getStorage()->instanceOfStorage(ObjectStoreStorage::class)) { $output->writeln(' Run occ files:scan --path ' . $node->getPath() . ' to attempt to resolve this.'); diff --git a/core/Command/Info/FileUtils.php b/core/Command/Info/FileUtils.php index 905851d14a558..1c38a7609e444 100644 --- a/core/Command/Info/FileUtils.php +++ b/core/Command/Info/FileUtils.php @@ -90,7 +90,7 @@ public function getNode(string $fileInput): ?Node { } public function formatPermissions(string $type, int $permissions): string { - if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) { + if ($permissions === Constants::PERMISSION_ALL || ($type === 'file' && $permissions === (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) { return 'full permissions'; } diff --git a/core/Command/Maintenance/Install.php b/core/Command/Maintenance/Install.php index 41f7c2ae6aa59..63f036f42667a 100644 --- a/core/Command/Maintenance/Install.php +++ b/core/Command/Maintenance/Install.php @@ -119,7 +119,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int protected function validateInput(InputInterface $input, OutputInterface $output, $supportedDatabases) { $db = strtolower($input->getOption('database')); - if (!in_array($db, $supportedDatabases)) { + if (!in_array($db, $supportedDatabases, true)) { throw new InvalidArgumentException("Database <$db> is not supported. " . implode(', ', $supportedDatabases) . ' are supported.'); } diff --git a/core/Command/Preview/Generate.php b/core/Command/Preview/Generate.php index f827586c6b192..b4dc62c465477 100644 --- a/core/Command/Preview/Generate.php +++ b/core/Command/Preview/Generate.php @@ -57,7 +57,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return array_map('intval', $sizeParts); }, $sizes); - if (in_array(null, $sizes)) { + if (in_array(null, $sizes, true)) { return 1; } diff --git a/core/Command/TaskProcessing/ListCommand.php b/core/Command/TaskProcessing/ListCommand.php index e6b3a5c75de58..0b46d8c2781a7 100644 --- a/core/Command/TaskProcessing/ListCommand.php +++ b/core/Command/TaskProcessing/ListCommand.php @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $appId = $input->getOption('appId'); $customId = $input->getOption('customId'); $status = $input->getOption('status') !== null ? (int)$input->getOption('status') : null; - $scheduledAfter = $input->getOption('scheduledAfter') != null ? (int)$input->getOption('scheduledAfter') : null; + $scheduledAfter = $input->getOption('scheduledAfter') !== null ? (int)$input->getOption('scheduledAfter') : null; $endedBefore = $input->getOption('endedBefore') !== null ? (int)$input->getOption('endedBefore') : null; $tasks = $this->taskProcessingManager->getTasks($userIdFilter, $type, $appId, $customId, $status, $scheduledAfter, $endedBefore); diff --git a/core/Command/Upgrade.php b/core/Command/Upgrade.php index 4a27d74cb96e7..279b7c2c6a987 100644 --- a/core/Command/Upgrade.php +++ b/core/Command/Upgrade.php @@ -163,7 +163,7 @@ function ($success) use ($output, $self): void { $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($output): void { // Read per event, the overwrites are cleared during a major upgrade $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); - if (!in_array($app, $incompatibleOverwrites)) { + if (!in_array($app, $incompatibleOverwrites, true)) { $output->writeln('Disabled incompatible app: ' . $app . ''); } }); diff --git a/core/Command/User/Keys/Verify.php b/core/Command/User/Keys/Verify.php index 6113eaedad555..066ba811b345a 100644 --- a/core/Command/User/Keys/Verify.php +++ b/core/Command/User/Keys/Verify.php @@ -80,7 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Derived public key:'); $output->writeln($publicKeyDerived); - if ($publicKey != $publicKeyDerived) { + if ($publicKey !== $publicKeyDerived) { if (!$input->getOption('update')) { $output->writeln('Stored public key does not match stored private key'); return static::FAILURE; diff --git a/core/Command/User/Setting.php b/core/Command/User/Setting.php index 35df2db5add80..d2e5116fa1da4 100644 --- a/core/Command/User/Setting.php +++ b/core/Command/User/Setting.php @@ -154,26 +154,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 1; } - if ($app === 'settings' && in_array($key, ['email', 'display_name'])) { + if ($app === 'settings' && in_array($key, ['email', 'display_name'], true)) { $user = $this->userManager->get($uid); if ($user instanceof IUser) { if ($key === 'email') { $email = $input->getArgument('value'); $user->setSystemEMailAddress(mb_strtolower(trim($email))); - } elseif ($key === 'display_name') { - if (!$user->setDisplayName($input->getArgument('value'))) { - if ($user->getDisplayName() === $input->getArgument('value')) { - $output->writeln('New and old display name are the same'); - } elseif ($input->getArgument('value') === '') { - $output->writeln('New display name can\'t be empty'); - } else { - $output->writeln('Could not set display name'); - } - return 1; - } + return 0; + } + + // key === 'display_name' + if ($user->setDisplayName($input->getArgument('value'))) { + return 0; + } + + if ($user->getDisplayName() === $input->getArgument('value')) { + $output->writeln('New and old display name are the same'); + } elseif ($input->getArgument('value') === '') { + $output->writeln('New display name can\'t be empty'); + } else { + $output->writeln('Could not set display name'); } - // setEmailAddress and setDisplayName both internally set the value - return 0; + return 1; } } @@ -185,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 1; } - if ($app === 'settings' && in_array($key, ['email', 'display_name'])) { + if ($app === 'settings' && in_array($key, ['email', 'display_name'], true)) { $user = $this->userManager->get($uid); if ($user instanceof IUser) { if ($key === 'email') { diff --git a/core/Controller/SetupController.php b/core/Controller/SetupController.php index a1e0ef55b3baf..7cccb3f0d99d3 100644 --- a/core/Controller/SetupController.php +++ b/core/Controller/SetupController.php @@ -50,7 +50,7 @@ public function run(array $post): void { return; } - if (isset($post['install']) && $post['install'] == 'true') { + if (isset($post['install']) && $post['install'] === 'true') { // We have to launch the installation process : $e = $this->setupHelper->install($post); $errors = ['errors' => $e]; diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php index 91babaaa5cac1..57cd408ecf725 100644 --- a/core/Controller/TaskProcessingApiController.php +++ b/core/Controller/TaskProcessingApiController.php @@ -554,7 +554,7 @@ public function setFileContentsExApp(int $taskId): DataResponse { */ private function getFileContentsInternal(Task $task, int $fileId): StreamResponse|DataResponse { $ids = $this->taskProcessingManager->extractFileIdsFromTask($task); - if (!in_array($fileId, $ids)) { + if (!in_array($fileId, $ids, true)) { return new DataResponse(['message' => $this->l->t('Not found')], Http::STATUS_NOT_FOUND); } if ($task->getUserId() !== null) { diff --git a/core/Controller/UpdateController.php b/core/Controller/UpdateController.php index a027b30d05377..b073221f1c6a0 100644 --- a/core/Controller/UpdateController.php +++ b/core/Controller/UpdateController.php @@ -129,7 +129,7 @@ function (MigratorExecuteSqlEvent $event) use ($eventSource): void { $this->updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps): void { // Read per event, the overwrites are cleared during a major upgrade $incompatibleOverwrites = $this->config->getSystemValue('app_install_overwrite', []); - if (!in_array($app, $incompatibleOverwrites)) { + if (!in_array($app, $incompatibleOverwrites, true)) { $incompatibleApps[] = $app; } }); diff --git a/core/Service/CronService.php b/core/Service/CronService.php index f3394257dc019..379b60b10298f 100644 --- a/core/Service/CronService.php +++ b/core/Service/CronService.php @@ -282,7 +282,7 @@ private function runWeb(string $appMode): void { } else { // Work and success :-) $job = $this->jobList->getNext(); - if ($job != null) { + if ($job !== null) { $this->logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']); $job->start($this->jobList); $this->jobList->setLastJob($job); diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index f5afb020f6691..3bd0e3653add4 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -39,7 +39,7 @@ - + @@ -84,7 +84,7 @@

- getName()) ); ?> diff --git a/lib/OC.php b/lib/OC.php index b3d83a4ec25c9..251aa8b9a2bc1 100644 --- a/lib/OC.php +++ b/lib/OC.php @@ -133,7 +133,7 @@ public static function initPaths(): void { new \OC\AllConfig(new \OC\SystemConfig(self::$config)) ); $scriptName = $fakeRequest->getScriptName(); - if (substr($scriptName, -1) == '/') { + if (substr($scriptName, -1) === '/') { $scriptName .= 'index.php'; //make sure suburi follows the same rules as scriptName if (substr(OC::$SUBURI, -9) !== 'index.php') { @@ -363,7 +363,7 @@ private static function printUpgradePage(\OC\SystemConfig $systemConfig): void { if ($appManager->isShipped($appInfo['id'])) { $incompatibleShippedApps[] = $appInfo['name'] . ' (' . $appInfo['id'] . ')'; } - if (!in_array($appInfo['id'], $incompatibleOverwrites)) { + if (!in_array($appInfo['id'], $incompatibleOverwrites, true)) { $incompatibleDisabledApps[] = $appInfo; } } @@ -682,7 +682,7 @@ public static function boot(): void { // register autoloader self::$loaderStart = microtime(true); - self::$CLI = (php_sapi_name() == 'cli'); + self::$CLI = (php_sapi_name() === 'cli'); // Add default composer PSR-4 autoloader, ensure apcu to be disabled self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php'; @@ -790,7 +790,7 @@ public static function initForRequest(): void { logger('core')->error('Failed to start profiler: ' . $e->getMessage(), ['app' => 'base']); } - if (self::$CLI && in_array('--' . \OCP\Console\ReservedOptions::DEBUG_LOG, $_SERVER['argv'])) { + if (self::$CLI && in_array('--' . \OCP\Console\ReservedOptions::DEBUG_LOG, $_SERVER['argv'], true)) { \OC\Core\Listener\BeforeMessageLoggedEventListener::setup(); } @@ -1260,7 +1260,7 @@ public static function handleRequest(): void { // This prevents browsers from redirecting to the default page and then // attempting to parse HTML as CSS and similar. $destinationHeader = $request->getHeader('Sec-Fetch-Dest'); - if (in_array($destinationHeader, ['font', 'script', 'style'])) { + if (in_array($destinationHeader, ['font', 'script', 'style'], true)) { http_response_code(404); return; } diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php index fed246a9e71c4..7ca9fe6267a10 100644 --- a/lib/private/Accounts/AccountManager.php +++ b/lib/private/Accounts/AccountManager.php @@ -121,7 +121,7 @@ protected function testPropertyScope(IAccountProperty $property, array $allowedS if ( $property->getScope() === self::SCOPE_PRIVATE - && in_array($property->getName(), [self::PROPERTY_DISPLAYNAME, self::PROPERTY_EMAIL]) + && in_array($property->getName(), [self::PROPERTY_DISPLAYNAME, self::PROPERTY_EMAIL], true) ) { if ($throwOnData) { // v2-private is not available for these fields diff --git a/lib/private/Accounts/AccountProperty.php b/lib/private/Accounts/AccountProperty.php index 3be9fcb85aaa1..fbad61d80a7c9 100644 --- a/lib/private/Accounts/AccountProperty.php +++ b/lib/private/Accounts/AccountProperty.php @@ -65,7 +65,7 @@ public function setScope(string $scope): IAccountProperty { IAccountManager::SCOPE_FEDERATED, IAccountManager::SCOPE_PRIVATE, IAccountManager::SCOPE_PUBLISHED - ])) { + ], true)) { throw new InvalidArgumentException('Invalid scope'); } $this->scope = $newScope; @@ -153,7 +153,7 @@ public function setLocallyVerified(string $verified): IAccountProperty { IAccountManager::NOT_VERIFIED, IAccountManager::VERIFICATION_IN_PROGRESS, IAccountManager::VERIFIED, - ])) { + ], true)) { throw new InvalidArgumentException('Provided verification value is invalid'); } $this->locallyVerified = $verified; diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 31624c0127e0a..97776f37365c2 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -417,7 +417,7 @@ private function checkAppForGroups(string $enabled, IGroup $group): bool { return false; } - return in_array($group->getGID(), $groupIds); + return in_array($group->getGID(), $groupIds, true); } } @@ -1007,7 +1007,7 @@ public function getAlwaysEnabledApps() { */ #[\Override] public function isDefaultEnabled(string $appId): bool { - return (in_array($appId, $this->getDefaultEnabledApps())); + return (in_array($appId, $this->getDefaultEnabledApps(), true)); } /** diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php index a39bcfd2e3184..9451211a01e3e 100644 --- a/lib/private/App/AppStore/Fetcher/AppFetcher.php +++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php @@ -165,7 +165,7 @@ public function get($allowUnstable = false): array { // If the admin specified a allow list, filter apps from the appstore if (is_array($allowList) && $this->registry->delegateHasValidSubscription()) { return array_values(array_filter($apps, function (array $app) use ($allowList) { - return in_array($app['id'], $allowList); + return in_array($app['id'], $allowList, true); })); } diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php index 7831ba044f4d0..7990ff32f7d79 100644 --- a/lib/private/App/DependencyAnalyzer.php +++ b/lib/private/App/DependencyAnalyzer.php @@ -179,7 +179,7 @@ private function analyzeDatabases(array $dependencies): array { return $this->getValue($db); }, $supportedDatabases); $currentDatabase = $this->platform->getDatabase(); - if (!in_array($currentDatabase, $supportedDatabases)) { + if (!in_array($currentDatabase, $supportedDatabases, true)) { $missing[] = $this->getL()->t('The following databases are supported: %s', [implode(', ', $supportedDatabases)]); } return $missing; @@ -279,6 +279,8 @@ private function analyzeOS(array $dependencies): array { $oss = [$oss]; } $currentOS = $this->platform->getOS(); + // $oss may contain raw, unnormalized entries (e.g. with @attributes) when a single was given without going through getValue() + /** @psalm-suppress UnrecognizedExpression */ if (!in_array($currentOS, $oss)) { $missing[] = $this->getL()->t('The following platforms are supported: %s', [implode(', ', $oss)]); } diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index 9e3ceb4ca09bd..ed103e58194a5 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -988,7 +988,7 @@ public function updateType(string $app, string $key, int $type = self::VALUE_MIX $this->isLazy($app, $key); // confirm key exists // type can only be one type - if (!in_array($type, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) { + if (!in_array($type, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY], true)) { throw new AppConfigIncorrectTypeException('Unknown value type'); } @@ -1365,7 +1365,7 @@ private function assertParams(string $app = '', string $configKey = '', bool $al } if ($valueType > -1) { $valueType &= ~self::VALUE_SENSITIVE; - if (!in_array($valueType, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY])) { + if (!in_array($valueType, [self::VALUE_MIXED, self::VALUE_STRING, self::VALUE_INT, self::VALUE_FLOAT, self::VALUE_BOOL, self::VALUE_ARRAY], true)) { throw new InvalidArgumentException('Unknown value type'); } } diff --git a/lib/private/Archive/TAR.php b/lib/private/Archive/TAR.php index 861268eb116b0..c7cb7850137dd 100644 --- a/lib/private/Archive/TAR.php +++ b/lib/private/Archive/TAR.php @@ -258,7 +258,7 @@ public function extract(string $dest): bool { #[\Override] public function fileExists(string $path): bool { $files = $this->getFiles(); - if ((in_array($path, $files)) || (in_array($path . '/', $files))) { + if ((in_array($path, $files, true)) || (in_array($path . '/', $files, true))) { return true; } else { $folderPath = rtrim($path, '/') . '/'; diff --git a/lib/private/Authentication/Login/SetUserTimezoneCommand.php b/lib/private/Authentication/Login/SetUserTimezoneCommand.php index 7119e4728006f..0ea6177b609f3 100644 --- a/lib/private/Authentication/Login/SetUserTimezoneCommand.php +++ b/lib/private/Authentication/Login/SetUserTimezoneCommand.php @@ -39,6 +39,6 @@ public function process(LoginData $loginData): LoginResult { private function isValidTimezone(?string $value): bool { // Older browsers still report deprecated aliases like Europe/Kiev. - return $value && in_array($value, \DateTimeZone::listIdentifiers(\DateTimeZone::ALL_WITH_BC)); + return $value && in_array($value, \DateTimeZone::listIdentifiers(\DateTimeZone::ALL_WITH_BC), true); } } diff --git a/lib/private/Collaboration/Collaborators/GroupPlugin.php b/lib/private/Collaboration/Collaborators/GroupPlugin.php index 17ec13de69375..d1f9e331bc0c2 100644 --- a/lib/private/Collaboration/Collaborators/GroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/GroupPlugin.php @@ -80,7 +80,7 @@ public function search(string $search, int $limit, int $offset, ISearchResult $s // FIXME: use a more efficient approach $gid = $group->getGID(); - if (!in_array($gid, $groupIds)) { + if (!in_array($gid, $groupIds, true)) { continue; } if (strtolower($gid) === $lowerSearch || strtolower($group->getDisplayName()) === $lowerSearch) { @@ -109,7 +109,7 @@ public function search(string $search, int $limit, int $offset, ISearchResult $s // On page one we try if the search result has a direct hit on the // user id and if so, we add that to the exact match list $group = $this->groupManager->get($search); - if ($group instanceof IGroup && !$group->hideFromCollaboration() && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) { + if ($group instanceof IGroup && !$group->hideFromCollaboration() && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups, true))) { $result['exact'][] = [ 'label' => $group->getDisplayName(), 'value' => [ diff --git a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php index fd4ca9e3cfe1c..ef42407712e8b 100644 --- a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php +++ b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php @@ -24,7 +24,7 @@ public function __construct( try { $fileSharingProvider = $cloudFederationProviderManager->getCloudFederationProvider('file'); $supportedShareTypes = $fileSharingProvider->getSupportedShareTypes(); - if (in_array('group', $supportedShareTypes)) { + if (in_array('group', $supportedShareTypes, true)) { $this->enabled = true; } } catch (\Exception $e) { diff --git a/lib/private/Config/ConfigManager.php b/lib/private/Config/ConfigManager.php index 66a12997e5aba..6a0bd0dedf8b2 100644 --- a/lib/private/Config/ConfigManager.php +++ b/lib/private/Config/ConfigManager.php @@ -242,7 +242,8 @@ private function migrateUserConfigValue(string $userId, string $appId, Entry $en } public function convertToInt(string $value): int { - if (!is_numeric($value) || (float)$value <> (int)$value) { + // checks the numeric string has no fractional part + if (!is_numeric($value) || (float)$value !== (float)(int)$value) { throw new TypeConflictException('Value is not an integer'); } diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php index 59fa0ed2b8cdf..0063b1f3ac755 100644 --- a/lib/private/Contacts/ContactsMenu/ContactsStore.php +++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php @@ -282,7 +282,7 @@ public function findOne(IUser $user, int $shareType, string $shareWith): ?IEntry foreach ($contacts as $contact) { if ($shareType === 4 && isset($contact['EMAIL'])) { - if (in_array($shareWith, $contact['EMAIL'])) { + if (in_array($shareWith, $contact['EMAIL'], true)) { $match = $contact; break; } diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php index 3b70d011980e8..0ad9886e7c05d 100644 --- a/lib/private/DB/Connection.php +++ b/lib/private/DB/Connection.php @@ -609,7 +609,7 @@ public function setValues(string $table, array $keys, array $values, array $upda if (!in_array($e->getReason(), [ \OCP\DB\Exception::REASON_CONSTRAINT_VIOLATION, \OCP\DB\Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION, - ]) + ], true) ) { throw $e; } diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 761fa5398b69e..31de44ac42eb7 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -274,7 +274,7 @@ private function getMigrationsToExecute($to): array { * @return bool */ private function shallBeExecuted($m, $knownMigrations): bool { - if (in_array($m, $knownMigrations)) { + if (in_array($m, $knownMigrations, true)) { return false; } diff --git a/lib/private/DB/QueryBuilder/Partitioned/PartitionSplit.php b/lib/private/DB/QueryBuilder/Partitioned/PartitionSplit.php index ad4c0fab05533..502ba05f6431d 100644 --- a/lib/private/DB/QueryBuilder/Partitioned/PartitionSplit.php +++ b/lib/private/DB/QueryBuilder/Partitioned/PartitionSplit.php @@ -37,7 +37,7 @@ public function addTable(string $table): void { } public function containsTable(string $table): bool { - return in_array($table, $this->tables); + return in_array($table, $this->tables, true); } public function containsAlias(string $alias): bool { diff --git a/lib/private/DB/QueryBuilder/Sharded/ShardDefinition.php b/lib/private/DB/QueryBuilder/Sharded/ShardDefinition.php index 4f98079d92dab..946ef0b3bd603 100644 --- a/lib/private/DB/QueryBuilder/Sharded/ShardDefinition.php +++ b/lib/private/DB/QueryBuilder/Sharded/ShardDefinition.php @@ -53,7 +53,7 @@ public function hasTable(string $table): bool { if ($this->table === $table) { return true; } - return in_array($table, $this->companionTables); + return in_array($table, $this->companionTables, true); } public function getShardForKey(int $key): int { @@ -75,6 +75,6 @@ public function getAllShards(): array { } public function isKey(string $column): bool { - return $column === $this->primaryKey || in_array($column, $this->companionKeys); + return $column === $this->primaryKey || in_array($column, $this->companionKeys, true); } } diff --git a/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php b/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php index 9906d79107ca4..69403201f9390 100644 --- a/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php +++ b/lib/private/DB/QueryBuilder/Sharded/ShardQueryRunner.php @@ -55,7 +55,7 @@ public function getShards(bool $allShards, array $shardKeys): ?array { private function getLikelyShards(array $primaryKeys): array { $shards = []; foreach ($primaryKeys as $primaryKey) { - if ($primaryKey < $this->shardDefinition->fromFileId && !in_array(ShardDefinition::MIGRATION_SHARD, $shards)) { + if ($primaryKey < $this->shardDefinition->fromFileId && !in_array(ShardDefinition::MIGRATION_SHARD, $shards, true)) { $shards[] = ShardDefinition::MIGRATION_SHARD; } $encodedShard = $primaryKey & ShardDefinition::PRIMARY_KEY_SHARD_MASK; diff --git a/lib/private/DateTimeFormatter.php b/lib/private/DateTimeFormatter.php index 05bfba084d7d7..e5203cddbedf0 100644 --- a/lib/private/DateTimeFormatter.php +++ b/lib/private/DateTimeFormatter.php @@ -141,33 +141,33 @@ public function formatDateSpan($timestamp, $baseTimestamp = null, ?IL10N $l = nu $baseTimestamp->setTime(0, 0, 0); $dateInterval = $timestamp->diff($baseTimestamp); - if ($dateInterval->y == 0 && $dateInterval->m == 0 && $dateInterval->d == 0) { + if ($dateInterval->y === 0 && $dateInterval->m === 0 && $dateInterval->d === 0) { return $l->t('today'); - } elseif ($dateInterval->y == 0 && $dateInterval->m == 0 && $dateInterval->d == 1) { + } elseif ($dateInterval->y === 0 && $dateInterval->m === 0 && $dateInterval->d === 1) { if ($timestamp > $baseTimestamp) { return $l->t('tomorrow'); } else { return $l->t('yesterday'); } - } elseif ($dateInterval->y == 0 && $dateInterval->m == 0) { + } elseif ($dateInterval->y === 0 && $dateInterval->m === 0) { if ($timestamp > $baseTimestamp) { return $l->n('in %n day', 'in %n days', $dateInterval->d); } else { return $l->n('%n day ago', '%n days ago', $dateInterval->d); } - } elseif ($dateInterval->y == 0 && $dateInterval->m == 1) { + } elseif ($dateInterval->y === 0 && $dateInterval->m === 1) { if ($timestamp > $baseTimestamp) { return $l->t('next month'); } else { return $l->t('last month'); } - } elseif ($dateInterval->y == 0) { + } elseif ($dateInterval->y === 0) { if ($timestamp > $baseTimestamp) { return $l->n('in %n month', 'in %n months', $dateInterval->m); } else { return $l->n('%n month ago', '%n months ago', $dateInterval->m); } - } elseif ($dateInterval->y == 1) { + } elseif ($dateInterval->y === 1) { if ($timestamp > $baseTimestamp) { return $l->t('next year'); } else { diff --git a/lib/private/DateTimeZone.php b/lib/private/DateTimeZone.php index d31a50823d02d..c351feb1bb179 100644 --- a/lib/private/DateTimeZone.php +++ b/lib/private/DateTimeZone.php @@ -87,6 +87,8 @@ protected function guessTimeZoneFromOffset($offset, int|false $timestamp): \Date } $dtOffset = $dtz->getOffset($dateTime); + // $dtOffset is int|false and $offset is untyped/mixed; loose comparison intentional + /** @psalm-suppress UnrecognizedExpression */ if ($dtOffset == 3600 * $offset) { return $dtz; } diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php index bfa5edc6d4344..e6b358d80cdd6 100644 --- a/lib/private/DirectEditing/Manager.php +++ b/lib/private/DirectEditing/Manager.php @@ -157,7 +157,7 @@ public function open(string $filePath, ?string $editorId = null, ?int $fileId = private function findEditorForFile(File $file) { foreach ($this->editors as $editor) { - if (in_array($file->getMimeType(), $editor->getMimetypes())) { + if (in_array($file->getMimeType(), $editor->getMimetypes(), true)) { return $editor->getId(); } } diff --git a/lib/private/Encryption/File.php b/lib/private/Encryption/File.php index 0a4423ce38e3c..2c08468dffe1e 100644 --- a/lib/private/Encryption/File.php +++ b/lib/private/Encryption/File.php @@ -95,7 +95,7 @@ public function getAccessList($path) { $storageService = Server::get(GlobalStoragesService::class); $storages = $storageService->getAllStorages(); foreach ($storages as $storage) { - if ($storage->getMountPoint() == substr($ownerPath, 0, strlen($storage->getMountPoint()))) { + if ($storage->getMountPoint() === substr($ownerPath, 0, strlen($storage->getMountPoint()))) { $mountedFor = $this->util->getUserWithAccessToMountPoint($storage->getApplicableUsers(), $storage->getApplicableGroups()); $userIds = array_merge($userIds, $mountedFor); } diff --git a/lib/private/Encryption/Util.php b/lib/private/Encryption/Util.php index 8002131d83e58..81d67c6065175 100644 --- a/lib/private/Encryption/Util.php +++ b/lib/private/Encryption/Util.php @@ -96,6 +96,8 @@ public function getEncryptionModuleId(?array $header = null) { public function createHeader(array $headerData, IEncryptionModule $encryptionModule) { $header = self::HEADER_START . ':' . self::HEADER_ENCRYPTION_MODULE_KEY . ':' . $encryptionModule->getId() . ':'; foreach ($headerData as $key => $value) { + // $headerData comes from the pluggable IEncryptionModule::begin() contract with untyped array keys + /** @psalm-suppress UnrecognizedExpression */ if (in_array($key, $this->ocHeaderKeys)) { throw new EncryptionHeaderKeyExistsException($key); } @@ -277,13 +279,13 @@ public function isExcluded($path) { } //detect system wide folders - if (in_array($root[1], $this->excludedPaths)) { + if (in_array($root[1], $this->excludedPaths, true)) { return true; } // detect user specific folders if ($this->userManager->userExists($root[1]) - && in_array($root[2] ?? '', $this->excludedPaths)) { + && in_array($root[2] ?? '', $this->excludedPaths, true)) { return true; } } diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index b4b1e01071ad1..a6f01a594e079 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -130,7 +130,8 @@ public function get($file) { $query->selectFileCache(); $metadataQuery = $query->selectMetadata(); - if (is_string($file) || $file == '') { + // a file id of 0 is treated the same as an empty path + if (is_string($file) || $file === 0) { // normalize file $file = $this->normalize($file); @@ -603,7 +604,7 @@ public function remove($file) { ->hintShardKey('storage', $this->getNumericStorageId()); $query->executeStatement(); - if ($entry->getMimeType() == FileInfo::MIMETYPE_FOLDER) { + if ($entry->getMimeType() === FileInfo::MIMETYPE_FOLDER) { $this->removeChildren($entry); } @@ -655,7 +656,7 @@ private function removeChildren(ICacheEntry $entry) { /** @var ICacheEntry[] $childFolders */ $childFolders = []; foreach ($children as $child) { - if ($child->getMimeType() == FileInfo::MIMETYPE_FOLDER) { + if ($child->getMimeType() === FileInfo::MIMETYPE_FOLDER) { $childFolders[] = $child; } } diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index 3098d3bd1ad1a..9287dcb005593 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -156,20 +156,20 @@ public function searchInCaches(ISearchQuery $searchQuery, array $caches): array $searchQuery->getSelectFields(), ); - $joinExtendedCache = in_array('metadata_etag', $requestedFields) - || in_array('creation_time', $requestedFields) - || in_array('upload_time', $requestedFields) - || in_array('last_activity', $requestedFields); + $joinExtendedCache = in_array('metadata_etag', $requestedFields, true) + || in_array('creation_time', $requestedFields, true) + || in_array('upload_time', $requestedFields, true) + || in_array('last_activity', $requestedFields, true); $query = $builder->selectFileCache('file', $joinExtendedCache); - if (in_array('systemtag', $requestedFields)) { + if (in_array('systemtag', $requestedFields, true)) { $this->equipQueryForSystemTags($query, $this->requireUser($searchQuery)); } - if (in_array('tagname', $requestedFields) || in_array('favorite', $requestedFields)) { + if (in_array('tagname', $requestedFields, true) || in_array('favorite', $requestedFields, true)) { $this->equipQueryForDavTags($query, $this->requireUser($searchQuery)); } - if (in_array('owner', $requestedFields) || in_array('share_with', $requestedFields) || in_array('share_type', $requestedFields)) { + if (in_array('owner', $requestedFields, true) || in_array('share_with', $requestedFields, true) || in_array('share_type', $requestedFields, true)) { $this->equipQueryForShares($query); } diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index 66cb614043ecc..04763ae804408 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -281,7 +281,7 @@ private function validateComparison(ISearchComparison $operator) { throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); } } - if (!in_array($operator->getType(), $comparisons[$operator->getField()])) { + if (!in_array($operator->getType(), $comparisons[$operator->getField()], true)) { throw new \InvalidArgumentException('Unsupported comparison for field ' . $operator->getField() . ': ' . $operator->getType()); } } diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index 0040dbe1f7168..9a46a7114eb11 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -144,7 +144,7 @@ public function getUserMountsFromProviderByPath( public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array { $providers = array_filter( $this->providers, - fn (string $providerClass) => in_array($providerClass, $mountProviderClasses), + fn (string $providerClass) => in_array($providerClass, $mountProviderClasses, true), ARRAY_FILTER_USE_KEY ); return $this->getUserMountsForProviders($user, array_values($providers)); diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 2e385aa2627b9..1430ab469eff3 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -85,7 +85,7 @@ public function registerMounts(IUser $user, array $mounts, ?array $mountProvider if ($mountInfo->getMountProvider() === '' && isset($newMounts[$mountInfo->getKey()])) { return true; } - return in_array($mountInfo->getMountProvider(), $mountProviderClasses); + return in_array($mountInfo->getMountProvider(), $mountProviderClasses, true); }); } diff --git a/lib/private/Files/Conversion/ConversionManager.php b/lib/private/Files/Conversion/ConversionManager.php index 24a4b8cb6358f..920283ddb8d90 100644 --- a/lib/private/Files/Conversion/ConversionManager.php +++ b/lib/private/Files/Conversion/ConversionManager.php @@ -128,7 +128,7 @@ private function getRegisteredProviders(): array { $appId = $providerRegistration->getAppId(); try { - if (in_array($appId, $this->preferredApps)) { + if (in_array($appId, $this->preferredApps, true)) { $this->preferredProviders[$class] = $this->serverContainer->get($class); continue; } diff --git a/lib/private/Files/FilenameValidator.php b/lib/private/Files/FilenameValidator.php index 095dabdd486b9..2eac9fdad704d 100644 --- a/lib/private/Files/FilenameValidator.php +++ b/lib/private/Files/FilenameValidator.php @@ -224,7 +224,7 @@ public function isForbidden(string $path): bool { // Check for forbidden filenames $forbiddenNames = $this->getForbiddenFilenames(); - if (in_array($filename, $forbiddenNames)) { + if (in_array($filename, $forbiddenNames, true)) { return true; } @@ -254,7 +254,7 @@ public function sanitizeFilename(string $name, ?string $charReplacement = null): $basename = strlen($name) > 1 ? substr($name, 0, strpos($name, '.', 1) ?: null) : $name; - if (in_array(mb_strtolower($basename), $this->getForbiddenBasenames())) { + if (in_array(mb_strtolower($basename), $this->getForbiddenBasenames(), true)) { $name = str_replace($basename, $this->l10n->t('%1$s (renamed)', [$basename]), $name); } @@ -262,7 +262,7 @@ public function sanitizeFilename(string $name, ?string $charReplacement = null): $name = $this->l10n->t('renamed file'); } - if (in_array(mb_strtolower($name), $this->getForbiddenFilenames())) { + if (in_array(mb_strtolower($name), $this->getForbiddenFilenames(), true)) { $name = $this->l10n->t('%1$s (renamed)', [$name]); } @@ -280,7 +280,7 @@ protected function checkForbiddenName(string $filename): void { // (except if the dot is the first character as this is then part of the basename "hidden files") $basename = substr($filename, 0, strpos($filename, '.', 1) ?: null); $forbiddenNames = $this->getForbiddenBasenames(); - if (in_array($basename, $forbiddenNames)) { + if (in_array($basename, $forbiddenNames, true)) { throw new ReservedWordException($this->l10n->t('"%1$s" is a forbidden prefix for file or folder names.', [$filename])); } } diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php index d567355a2766e..8656fb71a00e3 100644 --- a/lib/private/Files/Mount/Manager.php +++ b/lib/private/Files/Mount/Manager.php @@ -249,7 +249,7 @@ public function getSetupManager(): SetupManager { */ public function getMountsByMountProvider(string $path, array $mountProviders): array { $this->getSetupManager()->setupForProvider($path, $mountProviders); - if (\in_array('', $mountProviders)) { + if (\in_array('', $mountProviders, true)) { return $this->mounts; } diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 3428768ad6299..78d88f780be8d 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -435,7 +435,7 @@ public function getByIdInPath(int $id, string $path): array { $mountRoots = array_combine($mountRootIds, $mountRootPaths); $mounts = $this->mountManager->getMountsByMountProvider($path, $mountProviders); - $mountsContainingFile = array_filter($mounts, fn (IMountPoint $mount) => in_array($mount->getMountPoint(), $mountPoints)); + $mountsContainingFile = array_filter($mounts, fn (IMountPoint $mount) => in_array($mount->getMountPoint(), $mountPoints, true)); // if we haven't found a relevant mount that is setup, but we do have relevant mount infos // we try to load them from the mount info. diff --git a/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php b/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php index 02bc28f376e74..fb07c50c083c0 100644 --- a/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php +++ b/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php @@ -150,7 +150,7 @@ public function getObjectStoreConfigs(): ?array { foreach ($configs as $config) { if (is_array($config)) { $bucket = $config['arguments']['bucket'] ?? ''; - if (in_array($bucket, $usedBuckets)) { + if (in_array($bucket, $usedBuckets, true)) { throw new InvalidObjectStoreConfigurationException('Each object store configuration must use distinct bucket names'); } $usedBuckets[] = $bucket; diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 76959f6f01ea3..c25b8883fc770 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -290,7 +290,7 @@ public function setupForUser(IUser $user): void { $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function ( string $providerClass, ) use ($user) { - return !in_array($providerClass, $this->setupUserMountProviders[$user->getUID()]); + return !in_array($providerClass, $this->setupUserMountProviders[$user->getUID()], true); }); }); $this->afterUserFullySetup($user, $previouslySetupProviders); @@ -384,7 +384,7 @@ private function afterUserFullySetup(IUser $user, array $previouslySetupProvider )); $newProviders = array_diff($allProviders, $previouslySetupProviders); $mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) { - return !in_array($mount->getMountProvider(), $previouslySetupProviders); + return !in_array($mount->getMountProvider(), $previouslySetupProviders, true); }); $this->registerMounts($user, $mounts, $newProviders); @@ -525,7 +525,7 @@ public function setupForPath(string $path, bool $includeChildren = false): void $mountProvider = $cachedMount->getMountProvider(); $mountPoint = $cachedMount->getMountPoint(); - $isMountProviderSetup = in_array($mountProvider, $setupProviders); + $isMountProviderSetup = in_array($mountProvider, $setupProviders, true); $isPathSetupAsAuthoritative = $this->isPathSetup($mountPoint); if (!$isMountProviderSetup && !$isPathSetupAsAuthoritative) { if ($mountProvider === '') { @@ -584,7 +584,7 @@ public function setupForPath(string $path, bool $includeChildren = false): void $mountProvider = $cachedMount->getMountProvider(); // skip setup for already set up providers - if (in_array($mountProvider, $setupProviders)) { + if (in_array($mountProvider, $setupProviders, true)) { continue; } @@ -720,7 +720,7 @@ public function setupForProvider(string $path, array $providers): void { return !is_subclass_of($provider, IHomeMountProvider::class); }); - if (in_array('', $providers)) { + if (in_array('', $providers, true)) { $this->setupForUser($user); return; } diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php index b0ff0117b960f..e39fbb60ff2b6 100644 --- a/lib/private/Files/Storage/Wrapper/Quota.php +++ b/lib/private/Files/Storage/Wrapper/Quota.php @@ -128,7 +128,8 @@ public function fopen(string $path, string $mode) { } $free = $this->free_space($path); - if ($this->shouldApplyQuota($path) && $free == 0) { + // treat a failed free_space() the same as no free space + if ($this->shouldApplyQuota($path) && ($free === 0 || $free === 0.0 || $free === false)) { return false; } @@ -194,7 +195,8 @@ public function mkdir(string $path): bool { return $this->getWrapperStorage()->mkdir($path); } $free = $this->free_space($path); - if ($this->shouldApplyQuota($path) && $free == 0) { + // treat a failed free_space() the same as no free space + if ($this->shouldApplyQuota($path) && ($free === 0 || $free === 0.0 || $free === false)) { return false; } @@ -207,7 +209,8 @@ public function touch(string $path, ?int $mtime = null): bool { return $this->getWrapperStorage()->touch($path, $mtime); } $free = $this->free_space($path); - if ($free == 0) { + // treat a failed free_space() the same as no free space + if ($free === 0 || $free === 0.0 || $free === false) { return false; } @@ -225,7 +228,8 @@ public function writeStream(string $path, $stream, ?int $size = null): int { } $free = $this->free_space($path); - if ($this->shouldApplyQuota($path) && $free == 0) { + // treat a failed free_space() the same as no free space + if ($this->shouldApplyQuota($path) && ($free === 0 || $free === 0.0 || $free === false)) { throw new NotEnoughSpaceException(); } diff --git a/lib/private/Files/Stream/SeekableHttpStream.php b/lib/private/Files/Stream/SeekableHttpStream.php index 6b6ab08cbbc1c..55894d6fa9546 100644 --- a/lib/private/Files/Stream/SeekableHttpStream.php +++ b/lib/private/Files/Stream/SeekableHttpStream.php @@ -21,7 +21,7 @@ class SeekableHttpStream implements File { * $return void */ private static function registerIfNeeded() { - if (!in_array(self::PROTOCOL, stream_get_wrappers())) { + if (!in_array(self::PROTOCOL, stream_get_wrappers(), true)) { stream_wrapper_register( self::PROTOCOL, self::class diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index c4162c7df046f..4c4e1c93c58e8 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -1210,7 +1210,7 @@ private function basicOperation(string $operation, string $path, array $hooks = return false; } - if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) { + if (in_array('write', $hooks, true) || in_array('delete', $hooks, true) || in_array('read', $hooks, true)) { // always a shared lock during pre-hooks so the hook can read the file $this->lockFile($path, ILockingProvider::LOCK_SHARED); } @@ -1219,7 +1219,7 @@ private function basicOperation(string $operation, string $path, array $hooks = [$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix); if ($run && $storage) { /** @var Storage $storage */ - if (in_array('write', $hooks) || in_array('delete', $hooks)) { + if (in_array('write', $hooks, true) || in_array('delete', $hooks, true)) { try { $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); } catch (LockedException $e) { @@ -1235,15 +1235,15 @@ private function basicOperation(string $operation, string $path, array $hooks = $result = $storage->$operation($internalPath); } } catch (\Exception $e) { - if (in_array('write', $hooks) || in_array('delete', $hooks)) { + if (in_array('write', $hooks, true) || in_array('delete', $hooks, true)) { $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); - } elseif (in_array('read', $hooks)) { + } elseif (in_array('read', $hooks, true)) { $this->unlockFile($path, ILockingProvider::LOCK_SHARED); } throw $e; } - if ($result !== false && in_array('delete', $hooks)) { + if ($result !== false && in_array('delete', $hooks, true)) { $this->removeUpdate($storage, $internalPath); } if ($result !== false && in_array('write', $hooks, true) && $operation !== 'fopen' && $operation !== 'touch') { @@ -1251,11 +1251,11 @@ private function basicOperation(string $operation, string $path, array $hooks = $sizeDifference = $operation === 'mkdir' ? 0 : $result; $this->writeUpdate($storage, $internalPath, null, $isCreateOperation ? $sizeDifference : null); } - if ($result !== false && in_array('touch', $hooks)) { + if ($result !== false && in_array('touch', $hooks, true)) { $this->writeUpdate($storage, $internalPath, $extraParam, 0); } - if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) { + if ((in_array('write', $hooks, true) || in_array('delete', $hooks, true)) && ($operation !== 'fopen' || $result === false)) { $this->changeLock($path, ILockingProvider::LOCK_SHARED); } @@ -1265,9 +1265,9 @@ private function basicOperation(string $operation, string $path, array $hooks = // make sure our unlocking callback will still be called if connection is aborted ignore_user_abort(true); $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path): void { - if (in_array('write', $hooks)) { + if (in_array('write', $hooks, true)) { $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); - } elseif (in_array('read', $hooks)) { + } elseif (in_array('read', $hooks, true)) { $this->unlockFile($path, ILockingProvider::LOCK_SHARED); } }); @@ -1280,7 +1280,7 @@ private function basicOperation(string $operation, string $path, array $hooks = } if (!$unlockLater - && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) + && (in_array('write', $hooks, true) || in_array('delete', $hooks, true) || in_array('read', $hooks, true)) ) { $this->unlockFile($path, ILockingProvider::LOCK_SHARED); } diff --git a/lib/private/FilesMetadata/Model/FilesMetadata.php b/lib/private/FilesMetadata/Model/FilesMetadata.php index b645166117f6e..205aa936b522b 100644 --- a/lib/private/FilesMetadata/Model/FilesMetadata.php +++ b/lib/private/FilesMetadata/Model/FilesMetadata.php @@ -82,7 +82,7 @@ public function getSyncToken(): string { /** * @inheritDoc - * @return string[] list of keys + * @return list list of keys * @since 28.0.0 */ #[\Override] @@ -99,7 +99,7 @@ public function getKeys(): array { */ #[\Override] public function hasKey(string $needle): bool { - return (in_array($needle, $this->getKeys())); + return (in_array($needle, $this->getKeys(), true)); } /** diff --git a/lib/private/GlobalScale/Config.php b/lib/private/GlobalScale/Config.php index be35487f3c314..6edd0442f4843 100644 --- a/lib/private/GlobalScale/Config.php +++ b/lib/private/GlobalScale/Config.php @@ -52,7 +52,7 @@ public function isSecondary(): bool { #[Override] public function isPrimaryAdmin(string $userId): bool { - return in_array($userId, $this->config->getSystemValue('gss.master.admin', [])) - || in_array($userId, $this->config->getSystemValue('gss.primary.admin', [])); + return in_array($userId, $this->config->getSystemValue('gss.master.admin', []), true) + || in_array($userId, $this->config->getSystemValue('gss.primary.admin', []), true); } } diff --git a/lib/private/Group/Backend.php b/lib/private/Group/Backend.php index 4dd3e273133b4..95c3468369816 100644 --- a/lib/private/Group/Backend.php +++ b/lib/private/Group/Backend.php @@ -70,7 +70,7 @@ public function implementsActions($actions) { */ #[\Override] public function inGroup($uid, $gid) { - return in_array($gid, $this->getUserGroups($uid)); + return in_array($gid, $this->getUserGroups($uid), true); } /** @@ -108,7 +108,7 @@ public function getGroups($search = '', $limit = -1, $offset = 0) { */ #[\Override] public function groupExists($gid) { - return in_array($gid, $this->getGroups($gid, 1)); + return in_array($gid, $this->getGroups($gid, 1), true); } /** diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php index 1f9749746aff9..ccde43705aebe 100644 --- a/lib/private/Group/Manager.php +++ b/lib/private/Group/Manager.php @@ -356,7 +356,7 @@ public function isDelegatedAdmin(string $userId): bool { */ #[\Override] public function isInGroup($userId, $group) { - return in_array($group, $this->getUserIdGroupIds($userId)); + return in_array($group, $this->getUserIdGroupIds($userId), true); } #[\Override] diff --git a/lib/private/Hooks/EmitterTrait.php b/lib/private/Hooks/EmitterTrait.php index 1dddca3f35774..09b0b4717bf90 100644 --- a/lib/private/Hooks/EmitterTrait.php +++ b/lib/private/Hooks/EmitterTrait.php @@ -50,14 +50,14 @@ public function removeListener($scope = null, $method = null, ?callable $callbac } elseif ($scope) { foreach ($allNames as $name) { $parts = explode('::', $name, 2); - if ($parts[0] == $scope) { + if ($parts[0] === $scope) { $names[] = $name; } } } elseif ($method) { foreach ($allNames as $name) { $parts = explode('::', $name, 2); - if ($parts[1] == $method) { + if ($parts[1] === $method) { $names[] = $name; } } diff --git a/lib/private/Installer.php b/lib/private/Installer.php index 1852a103be7a3..6b0060b5b895d 100644 --- a/lib/private/Installer.php +++ b/lib/private/Installer.php @@ -505,7 +505,7 @@ public function installShippedApps(bool $softErrors = false, ?IOutput $output = if (file_exists($app_dir['path'] . "/$filename/appinfo/info.xml")) { if ($this->config->getAppValue($filename, 'installed_version') === '') { $enabled = $this->appManager->isDefaultEnabled($filename); - if (($enabled || in_array($filename, $this->appManager->getAlwaysEnabledApps())) + if (($enabled || in_array($filename, $this->appManager->getAlwaysEnabledApps(), true)) && $this->config->getAppValue($filename, 'enabled') !== 'no') { if ($softErrors) { try { diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php index accdf47efe61c..4a9a87aa060e2 100644 --- a/lib/private/L10N/Factory.php +++ b/lib/private/L10N/Factory.php @@ -404,7 +404,7 @@ public function languageExists($app, $lang) { } $languages = $this->findAvailableLanguages($app); - return in_array($lang, $languages); + return in_array($lang, $languages, true); } #[\Override] @@ -598,8 +598,8 @@ private function getL10nFilesForApp(string $app, string $lang): array { * @param string $app App id or empty string for core * @return string directory */ - protected function findL10nDir($app = null) { - if (in_array($app, ['core', 'lib'])) { + protected function findL10nDir(?string $app = null): string { + if (in_array($app, ['core', 'lib'], true)) { if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) { return $this->serverRoot . '/' . $app . '/l10n/'; } @@ -664,7 +664,7 @@ public function getLanguages(): array { // put appropriate languages into appropriate arrays, to print them sorted // common languages -> divider -> other languages - if (in_array($lang, self::COMMON_LANGUAGE_CODES)) { + if (in_array($lang, self::COMMON_LANGUAGE_CODES, true)) { $commonLanguages[array_search($lang, self::COMMON_LANGUAGE_CODES, true)] = $ln; } else { $otherLanguages[] = $ln; diff --git a/lib/private/Log/File.php b/lib/private/Log/File.php index 57ef1d45cf958..78c7e6d1ac96a 100644 --- a/lib/private/Log/File.php +++ b/lib/private/Log/File.php @@ -86,11 +86,12 @@ public function getEntries(int $limit = 50, int $offset = 0): array { while ($pos >= 0 && ($limit === null || $entriesCount < $limit)) { fseek($handle, $pos); $ch = fgetc($handle); - if ($ch == "\n" || $pos == 0) { + // treat a failed ftell() the same as start-of-file + if ($ch === "\n" || $pos === 0 || $pos === false) { if ($line !== '') { // Add the first character if at the start of the file, // because it doesn't hit the else in the loop - if ($pos == 0) { + if ($pos === 0 || $pos === false) { $line = $ch . $line; } $entry = json_decode($line); diff --git a/lib/private/Migration/MetadataManager.php b/lib/private/Migration/MetadataManager.php index fa81d360a1a08..46604b3c3751b 100644 --- a/lib/private/Migration/MetadataManager.php +++ b/lib/private/Migration/MetadataManager.php @@ -112,6 +112,8 @@ public function getUnsupportedApps(array $metadata): array { private function parseMigrations(array $migrations, array $ignoreMigrations = []): array { $parsed = []; foreach (array_keys($migrations) as $entry) { + // $entry may be an int since json_decode() casts numeric-looking migration version keys to integers + /** @psalm-suppress UnrecognizedExpression */ if (in_array($entry, $ignoreMigrations)) { continue; } diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php index 32aac71e2657a..be798027ccc0b 100644 --- a/lib/private/NavigationManager.php +++ b/lib/private/NavigationManager.php @@ -186,7 +186,8 @@ private function proceedNavigation(array $list, string $type): array { $activeEntry = $this->getActiveEntry(); if ($activeEntry !== null) { foreach ($list as $index => &$navEntry) { - if ($navEntry['id'] == $activeEntry) { + // nav entry ids are app-provided and untyped, so normalize before comparing + if ((string)$navEntry['id'] === $activeEntry) { $navEntry['active'] = true; } else { $navEntry['active'] = false; diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php index 1416c30d22f49..88c1fd0b4655c 100644 --- a/lib/private/OCM/Model/OCMProvider.php +++ b/lib/private/OCM/Model/OCMProvider.php @@ -141,7 +141,7 @@ public function setTokenEndPoint(string $endPoint): static { */ #[\Override] public function getTokenEndPoint(): string { - if (in_array('exchange-token', $this->capabilities)) { + if (in_array('exchange-token', $this->capabilities, true)) { return $this->tokenEndPoint; } return ''; diff --git a/lib/private/Preview/HEIC.php b/lib/private/Preview/HEIC.php index 76b844a6de7d2..b2d6dd2179764 100644 --- a/lib/private/Preview/HEIC.php +++ b/lib/private/Preview/HEIC.php @@ -36,7 +36,7 @@ public function getMimeType(): string { */ #[\Override] public function isAvailable(FileInfo $file): bool { - return in_array('HEIC', \Imagick::queryFormats('HEI*')); + return in_array('HEIC', \Imagick::queryFormats('HEI*'), true); } /** diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php index f1621d7973887..47f0ea1230fee 100644 --- a/lib/private/PreviewManager.php +++ b/lib/private/PreviewManager.php @@ -279,7 +279,7 @@ protected function getEnabledDefaultProvider(): array { OpenDocument::class, ], $imageProviders)); - if (in_array(Image::class, $this->defaultProviders)) { + if (in_array(Image::class, $this->defaultProviders, true)) { $this->defaultProviders = array_merge($this->defaultProviders, $imageProviders); } $this->defaultProviders = array_values(array_unique($this->defaultProviders)); @@ -292,7 +292,7 @@ protected function getEnabledDefaultProvider(): array { * Register the default providers (if enabled) */ protected function registerCoreProvider(string $class, string $mimeType, array $options = []): void { - if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) { + if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider(), true)) { $this->registerProviderClosure($mimeType, function () use ($class, $options): IProviderV2 { /** @var IProviderV2 $class */ return new $class($options); @@ -340,7 +340,7 @@ protected function registerCoreProviders(): void { foreach ($imagickProviders as $queryFormat => $provider) { $class = $provider['class']; - if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) { + if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider(), true)) { continue; } @@ -353,7 +353,7 @@ protected function registerCoreProviders(): void { $this->registerCoreProvidersOffice(); // Video requires ffmpeg - if (in_array(Movie::class, $this->getEnabledDefaultProvider())) { + if (in_array(Movie::class, $this->getEnabledDefaultProvider(), true)) { $movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null); if (!is_string($movieBinary)) { $movieBinary = $this->binaryFinder->findBinaryPath('ffmpeg'); @@ -380,7 +380,7 @@ private function registerCoreProvidersOffice(): void { foreach ($officeProviders as $provider) { $class = $provider['class']; - if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) { + if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider(), true)) { continue; } diff --git a/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php b/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php index 73d589050cacc..efe77798ac483 100644 --- a/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php +++ b/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php @@ -57,7 +57,7 @@ protected function run(mixed $argument): void { $this->accountManager->updateAccount($account); return; } catch (InvalidArgumentException $e) { - if (in_array($e->getMessage(), IAccountManager::ALLOWED_PROPERTIES)) { + if (in_array($e->getMessage(), IAccountManager::ALLOWED_PROPERTIES, true)) { $numRemoved++; $property = $account->getProperty($e->getMessage()); $account->setProperty($property->getName(), '', $property->getScope(), IAccountManager::NOT_VERIFIED); diff --git a/lib/private/Server.php b/lib/private/Server.php index f2d5c731f3f70..c1aae75d9fb48 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -794,7 +794,7 @@ public function __construct( } if (defined('PHPUNIT_RUN') && PHPUNIT_RUN - && in_array('fakeinput', stream_get_wrappers()) + && in_array('fakeinput', stream_get_wrappers(), true) ) { $stream = 'fakeinput://data'; } else { diff --git a/lib/private/Settings/DeclarativeManager.php b/lib/private/Settings/DeclarativeManager.php index b7eeefb282094..401c0e8be2c32 100644 --- a/lib/private/Settings/DeclarativeManager.php +++ b/lib/private/Settings/DeclarativeManager.php @@ -186,7 +186,7 @@ private function getStorageType(string $app, string $fieldId): string { if (array_key_exists($app, $this->appSchemas)) { foreach ($this->appSchemas[$app] as $schema) { foreach ($schema['fields'] as $field) { - if ($field['id'] == $fieldId) { + if ($field['id'] === $fieldId) { if (array_key_exists('storage_type', $field)) { return $field['storage_type']; } @@ -210,7 +210,7 @@ private function getSectionType(string $app, string $fieldId): string { if (array_key_exists($app, $this->appSchemas)) { foreach ($this->appSchemas[$app] as $schema) { foreach ($schema['fields'] as $field) { - if ($field['id'] == $fieldId) { + if ($field['id'] === $fieldId) { return $schema['section_type']; } } @@ -407,7 +407,7 @@ private function validateSchema(string $appId, array $schema): bool { $this->logger->warning('Declarative settings: missing section_type', ['app' => $appId, 'form_id' => $formId]); return false; } - if (!in_array($schema['section_type'], [DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL])) { + if (!in_array($schema['section_type'], [DeclarativeSettingsTypes::SECTION_TYPE_ADMIN, DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL], true)) { $this->logger->warning('Declarative settings: invalid section_type', ['app' => $appId, 'form_id' => $formId, 'section_type' => $schema['section_type']]); return false; } @@ -419,7 +419,7 @@ private function validateSchema(string $appId, array $schema): bool { $this->logger->warning('Declarative settings: missing storage_type', ['app' => $appId, 'form_id' => $formId]); return false; } - if (!in_array($schema['storage_type'], [DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL, DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL])) { + if (!in_array($schema['storage_type'], [DeclarativeSettingsTypes::STORAGE_TYPE_EXTERNAL, DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL], true)) { $this->logger->warning('Declarative settings: invalid storage_type', ['app' => $appId, 'form_id' => $formId, 'storage_type' => $schema['storage_type']]); return false; } @@ -450,13 +450,13 @@ private function validateSchema(string $appId, array $schema): bool { DeclarativeSettingsTypes::SELECT, DeclarativeSettingsTypes::CHECKBOX, DeclarativeSettingsTypes::URL, DeclarativeSettingsTypes::EMAIL, DeclarativeSettingsTypes::NUMBER, DeclarativeSettingsTypes::TEL, DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD, - ])) { + ], true)) { $this->logger->warning('Declarative settings: invalid field type', [ 'app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId, 'type' => $field['type'], ]); return false; } - if (isset($field['sensitive']) && $field['sensitive'] === true && !in_array($field['type'], [DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD])) { + if (isset($field['sensitive']) && $field['sensitive'] === true && !in_array($field['type'], [DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD], true)) { $this->logger->warning('Declarative settings: sensitive field type is supported only for TEXT and PASSWORD types ({app}, {form_id}, {field_id})', [ 'app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId, ]); @@ -475,7 +475,7 @@ private function validateField(string $appId, string $formId, array $field): boo if (in_array($field['type'], [ DeclarativeSettingsTypes::MULTI_SELECT, DeclarativeSettingsTypes::MULTI_CHECKBOX, DeclarativeSettingsTypes::RADIO, DeclarativeSettingsTypes::SELECT - ])) { + ], true)) { if (!isset($field['options'])) { $this->logger->warning('Declarative settings: missing field options', ['app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId]); return false; diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php index 27922ae93688c..49febaa943778 100644 --- a/lib/private/Settings/Manager.php +++ b/lib/private/Settings/Manager.php @@ -330,11 +330,11 @@ public function getAllowedAdminSettings(string $section, IUser $user): array { if ($this->subAdmin->isSubAdmin($user)) { $authorizedGroupFilter = function (ISettings $settings) use ($authorizedSettingsClasses) { return $settings instanceof ISubAdminSettings - || in_array(get_class($settings), $authorizedSettingsClasses) === true; + || in_array(get_class($settings), $authorizedSettingsClasses, true) === true; }; } else { $authorizedGroupFilter = function (ISettings $settings) use ($authorizedSettingsClasses) { - return in_array(get_class($settings), $authorizedSettingsClasses) === true; + return in_array(get_class($settings), $authorizedSettingsClasses, true) === true; }; } $appSettings = $this->getSettings('admin', $section, $authorizedGroupFilter); @@ -362,7 +362,7 @@ public function getAllAllowedAdminSettings(IUser $user): array { $authorizedSettingsClasses = $this->mapper->findAllClassesForUser($user); foreach ($this->settings['admin'] as $section) { foreach ($section as $setting) { - if (in_array(get_class($setting), $authorizedSettingsClasses) === true) { + if (in_array(get_class($setting), $authorizedSettingsClasses, true) === true) { $settings[] = $setting; } } diff --git a/lib/private/Sharing/SharingManager.php b/lib/private/Sharing/SharingManager.php index add248bcb934e..12fcb0c0dcbf0 100644 --- a/lib/private/Sharing/SharingManager.php +++ b/lib/private/Sharing/SharingManager.php @@ -718,7 +718,7 @@ public function selectSharePermissionPreset(ShareAccessContext $accessContext, S $permissionPresetCompatiblePermissionTypeClasses = $this->registry->getPermissionPresetCompatiblePermissionTypeClasses()[$permissionPresetClass]; $presetPermissions = array_combine($allPermissionClasses, array_map(fn (string $class): SharePermission => new SharePermission( $class, - in_array($class, $permissionPresetCompatiblePermissionTypeClasses), + in_array($class, $permissionPresetCompatiblePermissionTypeClasses, true), ), $allPermissionClasses)); $share = new Share( diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index b5aab63e3b2b8..e301bcab1faf6 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -1069,7 +1069,7 @@ private function checkGuestAccess(?string $userId = null): bool { } $guestsAllowed = $this->appConfig->getValueString('core', 'ai.taskprocessing_guests', 'false'); - if ($guestsAllowed == 'true' || !class_exists(UserBackend::class) || !($user->getBackend() instanceof UserBackend)) { + if ($guestsAllowed === 'true' || !class_exists(UserBackend::class) || !($user->getBackend() instanceof UserBackend)) { return true; } return false; @@ -1918,7 +1918,7 @@ private function validateUserAccessToFile(mixed $fileId, ?string $userId): void } $mounts = $this->userMountCache->getMountsForFileId($fileId); $userIds = array_map(fn ($mount) => $mount->getUser()->getUID(), $mounts); - if (!in_array($userId, $userIds)) { + if (!in_array($userId, $userIds, true)) { throw new UnauthorizedException('User ' . $userId . ' does not have access to file ' . $fileId); } } diff --git a/lib/private/Template/Template.php b/lib/private/Template/Template.php index c59eeee3b91de..6b56f5ef925cb 100644 --- a/lib/private/Template/Template.php +++ b/lib/private/Template/Template.php @@ -125,7 +125,7 @@ public function fetchPage(?array $additionalParams = null): string { $headers = ''; foreach (array_merge(\OC_Util::$headers, $this->headers) as $header) { $headers .= '<' . Util::sanitizeHTML($header['tag']); - if (strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes'])))) { + if (strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes'])), true)) { $headers .= ' defer'; } foreach ($header['attributes'] as $name => $value) { diff --git a/lib/private/Template/functions.php b/lib/private/Template/functions.php index 326b5e578e7ee..1c3ba214dc06d 100644 --- a/lib/private/Template/functions.php +++ b/lib/private/Template/functions.php @@ -316,6 +316,8 @@ function html_select_options($options, $selected, $params = []): string { if ($label_name && is_array($label)) { $label = $label[$label_name]; } + // $value may be a numeric array key or an arbitrary label value, while $selected is a string list + /** @psalm-suppress UnrecognizedExpression */ $select = in_array($value, $selected) ? ' selected="selected"' : ''; $html .= '' . "\n"; } diff --git a/lib/private/TextProcessing/Manager.php b/lib/private/TextProcessing/Manager.php index 113ece98b7415..ebdcbdafd9a3a 100644 --- a/lib/private/TextProcessing/Manager.php +++ b/lib/private/TextProcessing/Manager.php @@ -131,7 +131,7 @@ public function getAvailableTaskTypes(): array { } public function canHandleTask(OCPTask $task): bool { - return in_array($task->getType(), $this->getAvailableTaskTypes()); + return in_array($task->getType(), $this->getAvailableTaskTypes(), true); } /** diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index aeabf23995434..ae10049f6fc75 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -145,7 +145,7 @@ public function get($uid, array $excludeBackends = []): ?IUser { } $cachedBackend = $this->cache->get(sha1($uid)); - if (in_array($cachedBackend, $excludeBackends)) { + if (in_array((string)$cachedBackend, $excludeBackends, true)) { $cachedBackend = null; } @@ -163,7 +163,7 @@ public function get($uid, array $excludeBackends = []): ?IUser { continue; } - if (in_array($i, $excludeBackends)) { + if (in_array($i, $excludeBackends, true)) { continue; } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index df25c257a61df..578f8e75b9e25 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -408,7 +408,7 @@ public function logClientIn($user, $dbToken = $this->getTokenFromPassword($password); $isTokenPassword = $dbToken !== null; if (($dbToken instanceof PublicKeyToken) - && !in_array($dbToken->getType(), [IToken::PERMANENT_TOKEN,IToken::ONETIME_TOKEN]) + && !in_array($dbToken->getType(), [IToken::PERMANENT_TOKEN,IToken::ONETIME_TOKEN], true) ) { // Refuse session tokens here, only app tokens and onetime tokens are handled return false; diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index 27f2ff12038bb..242d7765d2caa 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -381,7 +381,7 @@ public function listAllApps(): array { $supportedApps = $this->getSupportedApps(); foreach ($installedApps as $app) { - if (!in_array($app, $blacklist)) { + if (!in_array($app, $blacklist, true)) { $info = $appManager->getAppInfo($app, false, $langCode); if (!is_array($info)) { Server::get(LoggerInterface::class)->error('Could not read app info file for app "' . $app . '"', ['app' => 'core']); @@ -415,7 +415,7 @@ public function listAllApps(): array { $info['removable'] = true; } - if (in_array($app, $supportedApps)) { + if (in_array($app, $supportedApps, true)) { $info['level'] = self::supportedApp; } diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php index 06255371ff6f1..c8a3d43c05240 100644 --- a/lib/private/legacy/OC_User.php +++ b/lib/private/legacy/OC_User.php @@ -121,7 +121,7 @@ public static function setupBackends() { $class = $config['class']; $arguments = $config['arguments']; if (class_exists($class)) { - if (!in_array($i, self::$_setupedBackends)) { + if (!in_array($i, self::$_setupedBackends, true)) { // make a reflection object $reflectionObj = new ReflectionClass($class); diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 74ba577dae7d3..4781a7dddeb91 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -221,7 +221,7 @@ public static function addVendorStyle($application, $file = null, $prepend = fal */ private static function addExternalResource($application, $prepend, $path, $type = 'script'): void { if ($type === 'style') { - if (!in_array($path, self::$styles)) { + if (!in_array($path, self::$styles, true)) { if ($prepend === true) { array_unshift(self::$styles, $path); } else { diff --git a/lib/public/AppFramework/AuthPublicShareController.php b/lib/public/AppFramework/AuthPublicShareController.php index 49b47e4cbd2f5..dbf2aac5a16bf 100644 --- a/lib/public/AppFramework/AuthPublicShareController.php +++ b/lib/public/AppFramework/AuthPublicShareController.php @@ -137,7 +137,7 @@ final public function authenticate(string $password = '', string $passwordReques } // Is user requesting a temporary password? - if ($passwordRequest == '') { + if ($passwordRequest === '') { if ($this->validateIdentity($identityToken)) { $this->generatePassword(); $response = $this->showIdentificationResult(true); diff --git a/lib/public/FilesMetadata/Model/IFilesMetadata.php b/lib/public/FilesMetadata/Model/IFilesMetadata.php index b7e2648496bf3..110cbec5f7a70 100644 --- a/lib/public/FilesMetadata/Model/IFilesMetadata.php +++ b/lib/public/FilesMetadata/Model/IFilesMetadata.php @@ -64,7 +64,7 @@ public function getSyncToken(): string; /** * returns all current metadata keys * - * @return string[] list of keys + * @return list list of keys * @since 28.0.0 */ public function getKeys(): array; diff --git a/lib/public/OCM/Events/OCMEndpointRequestEvent.php b/lib/public/OCM/Events/OCMEndpointRequestEvent.php index ecbb193dad595..70ac95b0e7c2a 100644 --- a/lib/public/OCM/Events/OCMEndpointRequestEvent.php +++ b/lib/public/OCM/Events/OCMEndpointRequestEvent.php @@ -106,7 +106,8 @@ public function getArgs(ParamType ...$params): array { } $typedArgs[] = match($param) { ParamType::STRING => $args[$i], - ParamType::INT => (is_numeric($args[$i]) && ((int)$args[$i] == (float)$args[$i])) ? (int)$args[$i] : null, + // checks the numeric string has no fractional part + ParamType::INT => (is_numeric($args[$i]) && ((float)$args[$i] === (float)(int)$args[$i])) ? (int)$args[$i] : null, ParamType::FLOAT => (is_numeric($args[$i])) ? (float)$args[$i] : null, ParamType::BOOL => in_array(strtolower($args[$i]), ['1', 'true', 'yes', 'on'], true), }; diff --git a/lib/public/Util.php b/lib/public/Util.php index aa030b6327f37..89604dbab1022 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -623,7 +623,7 @@ public static function isFunctionEnabled(string $functionName): bool { $ini = Server::get(IniGetWrapper::class); $disabled = explode(',', $ini->get('disable_functions') ?: ''); $disabled = array_map('trim', $disabled); - if (in_array($functionName, $disabled)) { + if (in_array($functionName, $disabled, true)) { return false; } return true; diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php index 2f5b34fea6228..4d999e65346d4 100644 --- a/tests/lib/TestCase.php +++ b/tests/lib/TestCase.php @@ -1,5 +1,7 @@ getGroupAnnotations(); - return in_array('DB', $annotations) || in_array('SLOWDB', $annotations); + return in_array('DB', $annotations, true) || in_array('SLOWDB', $annotations, true); } } From a886f0b6d269a04141d4bd4cd092a6703c0cc4a1 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 3 Sep 2026 14:23:02 -0400 Subject: [PATCH 4/5] test: handle missing docblock before parsing Signed-off-by: Josh --- tests/lib/TestCase.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php index 4d999e65346d4..f7800d8d0814f 100644 --- a/tests/lib/TestCase.php +++ b/tests/lib/TestCase.php @@ -584,10 +584,15 @@ protected function getGroupAnnotations(): array { $group = $attribute->newInstance(); return $group->name(); }, $r->getAttributes(Group::class)); + if (count($attributes) > 0) { return $attributes; } } + + if ($doc === false) { + return []; + } preg_match_all('#@group\s+(.*?)\n#s', $doc, $annotations); return $annotations[1] ?? []; } From 45cfe1bb71b43f9d9f1df115db9c56c1b2b951f1 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 3 Sep 2026 14:32:18 -0400 Subject: [PATCH 5/5] chore(core): remove redundant display name delete condition Signed-off-by: Josh --- core/Command/User/Setting.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Command/User/Setting.php b/core/Command/User/Setting.php index d2e5116fa1da4..bdbc8950110c2 100644 --- a/core/Command/User/Setting.php +++ b/core/Command/User/Setting.php @@ -194,10 +194,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user->setEMailAddress(''); // setEmailAddress already deletes the value return 0; - } elseif ($key === 'display_name') { - $output->writeln('Display name can\'t be deleted.'); - return 1; } + + $output->writeln('Display name can\'t be deleted.'); + return 1; } }