Skip to content

Commit 5c37052

Browse files
committed
Merge branch '9.0' into 9.1
2 parents c4d1b64 + 749d56a commit 5c37052

38 files changed

Lines changed: 851 additions & 87 deletions

File tree

Neos.Cache/Classes/Backend/RedisBackend.php

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* - port: The TCP port of the redis server (will be ignored if connecting to a socket)
3535
* - database: The database index that will be used. By default,
3636
* Redis has 16 databases with index number 0 - 15
37+
* - username: The username needed for the redis clients to connect to the server (hostname)
3738
* - password: The password needed for redis clients to connect to the server (hostname)
3839
* - batchSize: Maximum number of parameters per query for batch operations
3940
*
@@ -69,6 +70,8 @@ class RedisBackend extends IndependentAbstractBackend implements TaggableBackend
6970

7071
protected int $database = 0;
7172

73+
protected string $username = '';
74+
7275
protected string $password = '';
7376

7477
protected int $compressionLevel = 0;
@@ -192,8 +195,8 @@ public function has(string $entryIdentifier): bool
192195
* old entries for the identifier still exist, they are removed as well.
193196
*
194197
* @param string $entryIdentifier Specifies the cache entry to remove
195-
* @throws \RuntimeException
196198
* @return boolean true if (at least) an entry could be removed or false if no entry was found
199+
* @throws \RuntimeException
197200
* @api
198201
*/
199202
public function remove(string $entryIdentifier): bool
@@ -262,8 +265,8 @@ public function collectGarbage(): void
262265
* Removes all cache entries of this cache which are tagged by the specified tag.
263266
*
264267
* @param string $tag The tag the entries must have
265-
* @throws \RuntimeException
266268
* @return integer The number of entries which have been affected by this flush
269+
* @throws \RuntimeException
267270
* @api
268271
*/
269272
public function flushByTag(string $tag): int
@@ -295,8 +298,8 @@ public function flushByTag(string $tag): int
295298
* Removes all cache entries of this cache which are tagged by the specified tags.
296299
*
297300
* @param array<string> $tags The tag the entries must have
298-
* @throws \RuntimeException
299301
* @return integer The number of entries which have been affected by this flush
302+
* @throws \RuntimeException
300303
* @api
301304
*/
302305
public function flushByTags(array $tags): int
@@ -473,6 +476,11 @@ public function setDatabase(int|string $database): void
473476
$this->database = (int)$database;
474477
}
475478

479+
public function setUsername(string $username): void
480+
{
481+
$this->username = $username;
482+
}
483+
476484
public function setPassword(string $password): void
477485
{
478486
$this->password = $password;
@@ -505,7 +513,7 @@ private function uncompress(bool|string $value): bool|string
505513
if (empty($value)) {
506514
return $value;
507515
}
508-
return $this->useCompression() ? gzdecode((string) $value) : $value;
516+
return $this->useCompression() ? gzdecode((string)$value) : $value;
509517
}
510518

511519
private function compress(string $value): string
@@ -540,8 +548,16 @@ private function getRedisClient(): \Redis
540548
}
541549
}
542550

543-
if ($this->password !== '' && !$redis->auth($this->password)) {
544-
throw new CacheException('Redis authentication failed.', 1502366200);
551+
if ($this->username !== '' && $this->password !== '') {
552+
$result = $redis->auth([$this->username, $this->password]);
553+
if ($result === false) {
554+
throw new CacheException(sprintf('Redis authentication failed, using username "%s" and a %s bytes long password.', $this->username, strlen($this->password)), 1725607160);
555+
}
556+
} elseif ($this->password !== '') {
557+
$result = $redis->auth($this->password);
558+
if ($result === false) {
559+
throw new CacheException(sprintf('Redis authentication failed, using a %s bytes long password.', strlen($this->password)), 1502366200);
560+
}
545561
}
546562
$redis->select($this->database);
547563
return $redis;

Neos.Cache/Classes/Backend/SimpleFileBackend.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private function tryRemoveWithLock(string $fileName): bool
221221
// In the worst case, the unlink will just fail due to concurrent access and the caller needs to deal with that.
222222
return unlink($fileName);
223223
}
224-
$file = fopen($fileName, 'rb');
224+
$file = @fopen($fileName, 'rb');
225225
if ($file === false) {
226226
return false;
227227
}
@@ -542,7 +542,7 @@ protected function writeCacheFile(string $cacheEntryPathAndFilename, string $dat
542542
// It's important that we use the 'c' flag below, as `fopen` will otherwise truncate the file
543543
// if it already exists. If we used 'w' and then didn't get the lock, the file would end up empty.
544544
// https://www.php.net/manual/en/function.fopen.php#refsect1-function.fopen-parameters
545-
$file = fopen($cacheEntryPathAndFilename, 'cb');
545+
$file = @fopen($cacheEntryPathAndFilename, 'cb');
546546
if ($file === false) {
547547
continue;
548548
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php
2+
3+
namespace Neos\Cache\Tests\Functional\Backend;
4+
5+
include_once(__DIR__ . '/../../BaseTestCase.php');
6+
7+
/*
8+
* This file is part of the Neos.Cache package.
9+
*
10+
* (c) Contributors of the Neos Project - www.neos.io
11+
*
12+
* This package is Open Source Software. For the full copyright and license
13+
* information, please view the LICENSE file which was distributed with this
14+
* source code.
15+
*/
16+
17+
use Exception;
18+
use Neos\Cache\Backend\RedisBackend;
19+
use Neos\Cache\EnvironmentConfiguration;
20+
use Neos\Cache\Tests\BaseTestCase;
21+
use RedisException;
22+
use Redis;
23+
24+
/**
25+
* Testcase for the redis cache backend
26+
*
27+
* These tests use an actual Redis instance and will place and remove keys in db 0!
28+
* Since all keys have the 'TestCache:' prefix, running the tests should have
29+
* no side effects on non-related cache entries.
30+
*
31+
* Tests require Redis listening on 127.0.0.1:6379. Furthermore, the following users are required
32+
* default:<no_password>
33+
* test_no_password:<no_password>
34+
* test_password:<secret_password>
35+
*
36+
* The users can be added by:
37+
* acl setuser test_no_password on > ~* &* +@all
38+
* acl setuser test_password on >secret_password ~* &* +@all
39+
*
40+
* @requires extension redis
41+
*/
42+
class RedisBackendAuthenticationTest extends BaseTestCase
43+
{
44+
/**
45+
* @var Redis|null
46+
*/
47+
protected static ?Redis $redis = null;
48+
49+
/**
50+
* Create required Redis users for the test suite
51+
*/
52+
public static function setUpBeforeClass(): void
53+
{
54+
try {
55+
self::$redis = new Redis();
56+
self::$redis->connect('127.0.0.1', 6379);
57+
58+
// clean state before
59+
@self::$redis->rawCommand('ACL', 'DELUSER', 'test_no_password');
60+
@self::$redis->rawCommand('ACL', 'DELUSER', 'test_password');
61+
62+
// add users
63+
self::$redis->rawCommand('ACL', 'SETUSER', 'test_no_password', 'on', '>', '~*', '&*', '+@all');
64+
self::$redis->rawCommand('ACL', 'SETUSER', 'test_password', 'on', '>secret_password', '~*', '&*', '+@all');
65+
} catch (Exception $e) {
66+
self::markTestSkipped('Could not prepare Redis users: ' . $e->getMessage());
67+
}
68+
}
69+
70+
/**
71+
* Tear down Redis users after the suite has run
72+
*/
73+
public static function tearDownAfterClass(): void
74+
{
75+
if (self::$redis instanceof Redis) {
76+
try {
77+
self::$redis->rawCommand('ACL', 'DELUSER', 'test_no_password');
78+
self::$redis->rawCommand('ACL', 'DELUSER', 'test_password');
79+
} catch (Exception $e) {
80+
// ignore
81+
}
82+
self::$redis->close();
83+
self::$redis = null;
84+
}
85+
}
86+
87+
/**
88+
* Set up test case
89+
*
90+
* @return void
91+
*/
92+
protected function setUp(): void
93+
{
94+
$phpredisVersion = phpversion('redis');
95+
if (version_compare($phpredisVersion, '5.0.0', '<')) {
96+
$this->markTestSkipped(sprintf('phpredis extension version %s is not supported. Please update to version 5.0.0+.', $phpredisVersion));
97+
}
98+
try {
99+
if (!@fsockopen('127.0.0.1', 6379)) {
100+
$this->markTestSkipped('redis server not reachable');
101+
}
102+
} catch (Exception $e) {
103+
$this->markTestSkipped('redis server not reachable');
104+
}
105+
}
106+
107+
/**
108+
* @test
109+
*/
110+
public function defaultUserNoPassword()
111+
{
112+
$backend = new RedisBackend(
113+
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
114+
['hostname' => '127.0.0.1', 'database' => 0]
115+
);
116+
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
117+
}
118+
119+
/**
120+
* @test
121+
*/
122+
public function usernameNoPassword()
123+
{
124+
$backend = new RedisBackend(
125+
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
126+
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_no_password']
127+
);
128+
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
129+
}
130+
131+
/**
132+
* @test
133+
*/
134+
public function usernamePassword()
135+
{
136+
$backend = new RedisBackend(
137+
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
138+
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_password', 'password' => 'secret_password']
139+
);
140+
$this->assertInstanceOf('Neos\Cache\Backend\RedisBackend', $backend);
141+
}
142+
143+
/**
144+
* @test
145+
*/
146+
public function incorrectUsernamePassword()
147+
{
148+
$this->expectException(RedisException::class);
149+
$backend = new RedisBackend(
150+
new EnvironmentConfiguration('Redis a wonderful color Testing', '/some/path', PHP_MAXPATHLEN),
151+
['hostname' => '127.0.0.1', 'database' => 0, 'username' => 'test_password', 'password' => 'incorrect_password']
152+
);
153+
}
154+
}

Neos.Cache/Tests/Unit/Backend/AbstractBackendTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ protected function setUp(): void
3636
class_exists(AbstractBackend::class);
3737
$className = 'ConcreteBackend_' . md5(uniqid(mt_rand(), true));
3838
eval('
39+
#[\AllowDynamicProperties]
3940
class ' . $className . ' extends \Neos\Cache\Backend\AbstractBackend {
4041
public function set(string $entryIdentifier, string $data, array $tags = [], int $lifetime = NULL): void {}
4142
public function get(string $entryIdentifier): string {}

Neos.Eel/Resources/Private/PHP/php-peg/tests/ParserTestBase.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
class ParserTestWrapper {
1010

11-
function __construct($testcase, $class) {
11+
private mixed $testcase;
12+
private mixed $class;
13+
14+
function __construct($testcase, $class) {
1215
$this->testcase = $testcase;
1316
$this->class = $class;
1417
}

Neos.Flow.Log/Tests/Unit/Backend/AbstractBackendTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ protected function setUp(): void
3232
$this->backendClassName = 'ConcreteBackend_' . md5(uniqid(mt_rand(), true));
3333
eval('
3434
class ' . $this->backendClassName . ' extends \Neos\Flow\Log\Backend\AbstractBackend {
35+
protected $someOption;
3536
public function open(): void {}
3637
public function append(string $message, int $severity = 1, $additionalData = NULL, string $packageKey = NULL, string $className = NULL, string $methodName = NULL): void {}
3738
public function close(): void {}

Neos.Flow/Classes/Aop/Builder/ProxyClassBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ public function buildProxyClass(string $targetClassName, array $aspectContainers
409409
$proxyClass->addProperty($propertyName, var_export($propertyIntroduction->getInitialValue(), true), $propertyIntroduction->getPropertyVisibility(), $propertyIntroduction->getPropertyDocComment());
410410
}
411411

412-
$proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode(" if (method_exists(get_parent_class(\$this), 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable([parent::class, 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray'])) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n");
412+
$proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode(" if (method_exists(parent::class, 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable([parent::class, 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray'])) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n");
413413
$proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode($this->buildMethodsAndAdvicesArrayCode($interceptedMethods));
414414
$proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->setVisibility(ProxyMethodGenerator::VISIBILITY_PROTECTED);
415415

Neos.Flow/Classes/Configuration/ConfigurationManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ public function registerConfigurationType(string $configurationType, $configurat
225225
if ($configurationLoader === null) {
226226
$configurationLoader = new MergeLoader(new YamlSource(), $configurationType);
227227

228-
// B/C layer
228+
// B/C layer
229229
} elseif (is_string($configurationLoader)) {
230230
$configurationLoader = $this->convertLegacyProcessingType($configurationType, $configurationLoader);
231231
}

Neos.Flow/Classes/Core/Booting/Scripts.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ protected static function ensureCLISubrequestsUseCurrentlyRunningPhpBinary($phpB
868868

869869
// Try to resolve which binary file PHP is pointing to
870870
$output = [];
871-
exec(join(' ', $command), $output, $result);
871+
exec(implode(' ', $command), $output, $result);
872872

873873
if ($result === 0 && count($output) === 1) {
874874
// Resolve any wrapper
@@ -938,12 +938,13 @@ protected static function ensureWebSubrequestsUseCurrentlyRunningPhpVersion($php
938938
EOF;
939939
$command[] = '2>&1'; // Output errors in response
940940

941-
exec(join(' ', $command), $output, $result);
941+
$commandString = implode(' ', $command);
942+
exec($commandString, $output, $result);
942943

943944
$phpInformation = json_decode($output[0] ?? '{}', true) ?: [];
944945

945946
if ($result !== 0 || ($phpInformation['sapi'] ?? null) !== 'cli') {
946-
throw new Exception\SubProcessException(sprintf('PHP binary might not exist or is not suitable for cli usage. Command `%s` didnt succeed.', $phpCommand), 1689676967447);
947+
throw new Exception\SubProcessException(sprintf('PHP binary might not exist or is not suitable for CLI usage. Command `%s` did not succeed.', $commandString), 1689676967447);
947948
}
948949

949950
/**

Neos.Flow/Classes/Core/Bootstrap.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ protected function defineConstants()
480480
}
481481

482482
if (!defined('FLOW_PATH_ROOT')) {
483-
$rootPath = isset($_SERVER['FLOW_ROOTPATH']) ? $_SERVER['FLOW_ROOTPATH'] : false;
483+
$rootPath = $_SERVER['FLOW_ROOTPATH'] ?? false;
484484
if ($rootPath === false && isset($_SERVER['REDIRECT_FLOW_ROOTPATH'])) {
485485
$rootPath = $_SERVER['REDIRECT_FLOW_ROOTPATH'];
486486
}
@@ -530,7 +530,7 @@ protected function defineConstants()
530530
define('FLOW_PATH_PACKAGES', FLOW_PATH_ROOT . 'Packages/');
531531

532532
if (!defined('FLOW_PATH_TEMPORARY_BASE')) {
533-
define('FLOW_PATH_TEMPORARY_BASE', self::getEnvironmentConfigurationSetting('FLOW_PATH_TEMPORARY_BASE') ?: FLOW_PATH_DATA . '/Temporary');
533+
define('FLOW_PATH_TEMPORARY_BASE', self::getEnvironmentConfigurationSetting('FLOW_PATH_TEMPORARY_BASE') ?: FLOW_PATH_DATA . 'Temporary');
534534
$temporaryDirectoryPath = Environment::composeTemporaryDirectoryName(FLOW_PATH_TEMPORARY_BASE, $this->context);
535535
define('FLOW_PATH_TEMPORARY', $temporaryDirectoryPath);
536536
}
@@ -613,7 +613,9 @@ public static function getEnvironmentConfigurationSetting(string $variableName)
613613
return $variableValue;
614614
}
615615

616-
$variableValue = getenv('REDIRECT_' . $variableName);
616+
$redirectVariableName = 'REDIRECT_' . $variableName;
617+
618+
$variableValue = getenv($redirectVariableName);
617619
if ($variableValue !== false) {
618620
return $variableValue;
619621
}
@@ -622,8 +624,8 @@ public static function getEnvironmentConfigurationSetting(string $variableName)
622624
return $_SERVER[$variableName];
623625
}
624626

625-
if (isset($_SERVER['REDIRECT_' . $variableName])) {
626-
return $_SERVER['REDIRECT_' . $variableName];
627+
if (isset($_SERVER[$redirectVariableName])) {
628+
return $_SERVER[$redirectVariableName];
627629
}
628630

629631
return null;

0 commit comments

Comments
 (0)