diff --git a/.github/workflows/lint-php.yml b/.github/workflows/lint-php.yml
index 8310c3cebf1e6..22db44fca033f 100644
--- a/.github/workflows/lint-php.yml
+++ b/.github/workflows/lint-php.yml
@@ -47,7 +47,7 @@ jobs:
strategy:
matrix:
- php-versions: [ '8.2', '8.3', '8.4' ]
+ php-versions: [ '8.2', '8.3', '8.4', '8.5' ]
name: php-lint
diff --git a/.github/workflows/phpunit-mariadb.yml b/.github/workflows/phpunit-mariadb.yml
index 1758fc83eac4d..e329261d55a13 100644
--- a/.github/workflows/phpunit-mariadb.yml
+++ b/.github/workflows/phpunit-mariadb.yml
@@ -60,13 +60,15 @@ jobs:
fail-fast: false
matrix:
php-versions: ['8.2']
- mariadb-versions: ['10.3', '10.6', '10.11', '11.4', '11.8']
+ mariadb-versions: ['10.6', '10.11', '11.4', '11.8']
include:
- php-versions: '8.3'
mariadb-versions: '10.11'
coverage: ${{ github.event_name != 'pull_request' }}
- php-versions: '8.4'
mariadb-versions: '11.8'
+ - php-versions: '8.5'
+ mariadb-versions: '11.8'
name: MariaDB ${{ matrix.mariadb-versions }} (PHP ${{ matrix.php-versions }}) - database tests
diff --git a/.github/workflows/phpunit-memcached.yml b/.github/workflows/phpunit-memcached.yml
index 16c7d91827bf5..4c1a32b64b9bd 100644
--- a/.github/workflows/phpunit-memcached.yml
+++ b/.github/workflows/phpunit-memcached.yml
@@ -56,7 +56,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php-versions: ['8.3', '8.4']
+ php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
diff --git a/.github/workflows/phpunit-mysql.yml b/.github/workflows/phpunit-mysql.yml
index f0635d5a3ef70..f7de37051f609 100644
--- a/.github/workflows/phpunit-mysql.yml
+++ b/.github/workflows/phpunit-mysql.yml
@@ -67,6 +67,8 @@ jobs:
coverage: ${{ github.event_name != 'pull_request' }}
- mysql-versions: '8.4'
php-versions: '8.4'
+ - mysql-versions: '8.4'
+ php-versions: '8.5'
name: MySQL ${{ matrix.mysql-versions }} (PHP ${{ matrix.php-versions }}) - database tests
diff --git a/.github/workflows/phpunit-nodb.yml b/.github/workflows/phpunit-nodb.yml
index c23e620da204f..a6487011639b4 100644
--- a/.github/workflows/phpunit-nodb.yml
+++ b/.github/workflows/phpunit-nodb.yml
@@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php-versions: ['8.3', '8.4']
+ php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
diff --git a/.github/workflows/phpunit-oci.yml b/.github/workflows/phpunit-oci.yml
index c489810c6db23..c414dfb76e2e9 100644
--- a/.github/workflows/phpunit-oci.yml
+++ b/.github/workflows/phpunit-oci.yml
@@ -69,6 +69,8 @@ jobs:
php-versions: '8.3'
- oracle-versions: '23'
php-versions: '8.4'
+ - oracle-versions: '23'
+ php-versions: '8.5'
name: Oracle ${{ matrix.oracle-versions }} (PHP ${{ matrix.php-versions }}) - database tests
diff --git a/.github/workflows/phpunit-pgsql.yml b/.github/workflows/phpunit-pgsql.yml
index e67767f61de6b..f139ca90d4d33 100644
--- a/.github/workflows/phpunit-pgsql.yml
+++ b/.github/workflows/phpunit-pgsql.yml
@@ -68,6 +68,8 @@ jobs:
coverage: ${{ github.event_name != 'pull_request' }}
- php-versions: '8.4'
postgres-versions: '18'
+ - php-versions: '8.5'
+ postgres-versions: '18'
name: PostgreSQL ${{ matrix.postgres-versions }} (PHP ${{ matrix.php-versions }}) - database tests
diff --git a/.github/workflows/phpunit-sqlite.yml b/.github/workflows/phpunit-sqlite.yml
index 76a66f185077b..9f92d6ba5e238 100644
--- a/.github/workflows/phpunit-sqlite.yml
+++ b/.github/workflows/phpunit-sqlite.yml
@@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php-versions: ['8.3', '8.4']
+ php-versions: ['8.3', '8.4', '8.5']
include:
- php-versions: '8.2'
coverage: ${{ github.event_name != 'pull_request' }}
diff --git a/apps/files_sharing/tests/SharedMountTest.php b/apps/files_sharing/tests/SharedMountTest.php
index bfc0016d31800..f70dae065d234 100644
--- a/apps/files_sharing/tests/SharedMountTest.php
+++ b/apps/files_sharing/tests/SharedMountTest.php
@@ -375,7 +375,6 @@ public function testShareMountOverShare(): void {
$mountProvider = Server::get(MountProvider::class);
$reflectionClass = new \ReflectionClass($mountProvider);
$reflectionCacheFactory = $reflectionClass->getProperty('cacheFactory');
- $reflectionCacheFactory->setAccessible(true);
$reflectionCacheFactory->setValue($mountProvider, $cacheFactory);
// share to user
diff --git a/lib/private/DB/ConnectionFactory.php b/lib/private/DB/ConnectionFactory.php
index 2429eeb142fa3..421125603118d 100644
--- a/lib/private/DB/ConnectionFactory.php
+++ b/lib/private/DB/ConnectionFactory.php
@@ -88,12 +88,23 @@ public function getDefaultConnectionParams($type) {
throw new \InvalidArgumentException("Unsupported type: $type");
}
$result = $this->defaultConnectionParams[$normalizedType];
- // \PDO::MYSQL_ATTR_FOUND_ROWS may not be defined, e.g. when the MySQL
- // driver is missing. In this case, we won't be able to connect anyway.
- if ($normalizedType === 'mysql' && defined('\PDO::MYSQL_ATTR_FOUND_ROWS')) {
- $result['driverOptions'] = [
- \PDO::MYSQL_ATTR_FOUND_ROWS => true,
- ];
+ /**
+ * {@see \PDO::MYSQL_ATTR_FOUND_ROWS} may not be defined, e.g. when the MySQL
+ * driver is missing. In this case, we won't be able to connect anyway.
+ * In PHP 8.5 it's deprecated and {@see \Pdo\Mysql::ATTR_FOUND_ROWS} should be used,
+ * but that is only available since PHP 8.4
+ */
+ if ($normalizedType === 'mysql') {
+ if (PHP_VERSION_ID >= 80500 && class_exists(\Pdo\Mysql::class)) {
+ /** @psalm-suppress UndefinedClass */
+ $result['driverOptions'] = [
+ \Pdo\Mysql::ATTR_FOUND_ROWS => true,
+ ];
+ } elseif (PHP_VERSION_ID < 80500 && defined('\PDO::MYSQL_ATTR_FOUND_ROWS')) {
+ $result['driverOptions'] = [
+ \PDO::MYSQL_ATTR_FOUND_ROWS => true,
+ ];
+ }
}
return $result;
}
diff --git a/lib/private/DB/SQLiteSessionInit.php b/lib/private/DB/SQLiteSessionInit.php
index 5fe0cb3abf64c..3e05b6e59a15c 100644
--- a/lib/private/DB/SQLiteSessionInit.php
+++ b/lib/private/DB/SQLiteSessionInit.php
@@ -44,7 +44,11 @@ public function postConnect(ConnectionEventArgs $args) {
/** @var \Doctrine\DBAL\Driver\PDO\Connection $connection */
$connection = $args->getConnection()->getWrappedConnection();
$pdo = $connection->getWrappedConnection();
- $pdo->sqliteCreateFunction('md5', 'md5', 1);
+ if (PHP_VERSION_ID >= 80500 && method_exists($pdo, 'createFunction')) {
+ $pdo->createFunction('md5', 'md5', 1);
+ } else {
+ $pdo->sqliteCreateFunction('md5', 'md5', 1);
+ }
}
public function getSubscribedEvents() {
diff --git a/lib/private/Image.php b/lib/private/Image.php
index 4eabce5e4f869..eb5812c878519 100644
--- a/lib/private/Image.php
+++ b/lib/private/Image.php
@@ -839,7 +839,6 @@ public function resize(int $maxSize): bool {
return false;
}
$result = $this->resizeNew($maxSize);
- imagedestroy($this->resource);
$this->resource = $result;
return $this->valid();
}
@@ -875,7 +874,6 @@ public function preciseResize(int $width, int $height): bool {
return false;
}
$result = $this->preciseResizeNew($width, $height);
- imagedestroy($this->resource);
$this->resource = $result;
return $this->valid();
}
diff --git a/lib/private/Log.php b/lib/private/Log.php
index cbdd0f767ad80..88df3c032afb2 100644
--- a/lib/private/Log.php
+++ b/lib/private/Log.php
@@ -342,14 +342,14 @@ public function logException(Throwable $exception, array $context = []): void {
$this->error('Failed to load ExceptionSerializer serializer while trying to log ' . $exception->getMessage());
return;
}
+
+ $context = array_map($this->normalizer->format(...), $context);
$data = $context;
- unset($data['app']);
- unset($data['level']);
+ unset($data['app'], $data['level']);
+
$data = array_merge($serializer->serializeException($exception), $data);
$data = $this->interpolateMessage($data, isset($context['message']) && $context['message'] !== '' ? $context['message'] : ('Exception thrown: ' . get_class($exception)), 'CustomMessage');
- array_walk($context, [$this->normalizer, 'format']);
-
$this->eventDispatcher?->dispatchTyped(new BeforeMessageLoggedEvent($app, $level, $data));
try {
@@ -374,8 +374,7 @@ public function logData(string $message, array $data, array $context = []): void
$level = $context['level'] ?? ILogger::ERROR;
$minLevel = $this->getLogLevel($context, $message);
-
- array_walk($context, [$this->normalizer, 'format']);
+ $data = array_map($this->normalizer->format(...), $data);
try {
if ($level >= $minLevel) {
@@ -385,8 +384,6 @@ public function logData(string $message, array $data, array $context = []): void
}
$this->writeLog($app, $data, $level);
}
-
- $context['level'] = $level;
} catch (Throwable $e) {
// make sure we dont hard crash if logging fails
error_log('Error when trying to log exception: ' . $e->getMessage() . ' ' . $e->getTraceAsString());
diff --git a/lib/versioncheck.php b/lib/versioncheck.php
index d1073d84c4e83..dd7790ff9616e 100644
--- a/lib/versioncheck.php
+++ b/lib/versioncheck.php
@@ -5,7 +5,7 @@
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-// Show warning if a PHP version below 8.1 is used,
+// Show warning if a PHP version below 8.2 is used,
if (PHP_VERSION_ID < 80200) {
http_response_code(500);
echo 'This version of Nextcloud requires at least PHP 8.2
';
@@ -13,10 +13,10 @@
exit(1);
}
-// Show warning if >= PHP 8.5 is used as Nextcloud is not compatible with >= PHP 8.5 for now
-if (PHP_VERSION_ID >= 80500) {
+// Show warning if >= PHP 8.6 is used as Nextcloud is not compatible with >= PHP 8.6 for now
+if (PHP_VERSION_ID >= 80600) {
http_response_code(500);
- echo 'This version of Nextcloud is not compatible with PHP>=8.5.
';
+ echo 'This version of Nextcloud is not compatible with PHP>=8.6.
';
echo 'You are currently running ' . PHP_VERSION . '.';
exit(1);
}
diff --git a/tests/lib/Files/ViewTest.php b/tests/lib/Files/ViewTest.php
index e7ce3ee9526cf..274f8cb6d0975 100644
--- a/tests/lib/Files/ViewTest.php
+++ b/tests/lib/Files/ViewTest.php
@@ -1811,13 +1811,13 @@ public static function basicOperationProviderForLocks(): array {
['touch', ['test.txt'], 'test.txt', 'touch', null, null, null],
// ---- no hooks, no locks ---
- ['is_dir', ['dir'], 'dir', null],
- ['is_file', ['dir'], 'dir', null],
+ ['is_dir', ['dir'], 'dir', ''],
+ ['is_file', ['dir'], 'dir', ''],
[
'stat',
['dir'],
'dir',
- null,
+ '',
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
@@ -1828,7 +1828,7 @@ public static function basicOperationProviderForLocks(): array {
'filetype',
['dir'],
'dir',
- null,
+ '',
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
@@ -1839,7 +1839,7 @@ public static function basicOperationProviderForLocks(): array {
'filesize',
['dir'],
'dir',
- null,
+ '',
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
@@ -1847,17 +1847,17 @@ public static function basicOperationProviderForLocks(): array {
/* Return an int */
100
],
- ['isCreatable', ['dir'], 'dir', null],
- ['isReadable', ['dir'], 'dir', null],
- ['isUpdatable', ['dir'], 'dir', null],
- ['isDeletable', ['dir'], 'dir', null],
- ['isSharable', ['dir'], 'dir', null],
- ['file_exists', ['dir'], 'dir', null],
+ ['isCreatable', ['dir'], 'dir', ''],
+ ['isReadable', ['dir'], 'dir', ''],
+ ['isUpdatable', ['dir'], 'dir', ''],
+ ['isDeletable', ['dir'], 'dir', ''],
+ ['isSharable', ['dir'], 'dir', ''],
+ ['file_exists', ['dir'], 'dir', ''],
[
'filemtime',
['dir'],
'dir',
- null,
+ '',
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
@@ -1875,23 +1875,23 @@ public static function basicOperationProviderForLocks(): array {
* @param array $operationArgs arguments for the operation
* @param string $lockedPath path of the locked item to check
* @param string $hookType hook type
- * @param int $expectedLockBefore expected lock during pre hooks
- * @param int $expectedLockDuring expected lock during operation
- * @param int $expectedLockAfter expected lock during post hooks
- * @param int $expectedStrayLock expected lock after returning, should
- * be null (unlock) for most operations
+ * @param ?int $expectedLockBefore expected lock during pre hooks
+ * @param ?int $expectedLockDuring expected lock during operation
+ * @param ?int $expectedLockAfter expected lock during post hooks
+ * @param ?int $expectedStrayLock expected lock after returning, should
+ * be null (unlock) for most operations
*/
#[\PHPUnit\Framework\Attributes\DataProvider('basicOperationProviderForLocks')]
public function testLockBasicOperation(
- $operation,
- $operationArgs,
- $lockedPath,
- $hookType,
- $expectedLockBefore = ILockingProvider::LOCK_SHARED,
- $expectedLockDuring = ILockingProvider::LOCK_SHARED,
- $expectedLockAfter = ILockingProvider::LOCK_SHARED,
- $expectedStrayLock = null,
- $returnValue = true,
+ string $operation,
+ array $operationArgs,
+ string $lockedPath,
+ string $hookType,
+ ?int $expectedLockBefore = ILockingProvider::LOCK_SHARED,
+ ?int $expectedLockDuring = ILockingProvider::LOCK_SHARED,
+ ?int $expectedLockAfter = ILockingProvider::LOCK_SHARED,
+ ?int $expectedStrayLock = null,
+ mixed $returnValue = true,
): void {
$view = new View('/' . $this->user . '/files/');
@@ -1931,7 +1931,7 @@ function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
// do operation
call_user_func_array([$view, $operation], $operationArgs);
- if ($hookType !== null) {
+ if ($hookType !== '') {
$this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook');
$this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook');
$this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation');
@@ -2530,7 +2530,7 @@ function () use ($view, $path, $onMountPoint, &$lockTypePost): void {
}
);
- if ($hookType !== null) {
+ if ($hookType !== '') {
Util::connectHook(
Filesystem::CLASSNAME,
$hookType,
diff --git a/tests/lib/HelperStorageTest.php b/tests/lib/HelperStorageTest.php
index 81cff4a283e81..914936c9657ad 100644
--- a/tests/lib/HelperStorageTest.php
+++ b/tests/lib/HelperStorageTest.php
@@ -102,14 +102,12 @@ public function testGetStorageInfo(): void {
private function getIncludeExternalStorage(): bool {
$class = new \ReflectionClass(\OC_Helper::class);
$prop = $class->getProperty('quotaIncludeExternalStorage');
- $prop->setAccessible(true);
return $prop->getValue(null) ?? false;
}
private function setIncludeExternalStorage(bool $include) {
$class = new \ReflectionClass(\OC_Helper::class);
$prop = $class->getProperty('quotaIncludeExternalStorage');
- $prop->setAccessible(true);
$prop->setValue(null, $include);
}
diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php
index 54368c93b8bcb..1b387df0eb580 100644
--- a/tests/lib/TestCase.php
+++ b/tests/lib/TestCase.php
@@ -248,15 +248,10 @@ protected static function invokePrivate($object, $methodName, array $parameters
if ($reflection->hasMethod($methodName)) {
$method = $reflection->getMethod($methodName);
-
- $method->setAccessible(true);
-
return $method->invokeArgs($object, $parameters);
} elseif ($reflection->hasProperty($methodName)) {
$property = $reflection->getProperty($methodName);
- $property->setAccessible(true);
-
if (!empty($parameters)) {
if ($property->isStatic()) {
$property->setValue(null, array_pop($parameters));