From 13890591e248acc8824becb24ba1939fa061bd34 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 7 Jun 2026 11:10:31 -0400 Subject: [PATCH 1/2] Fix getUniqueId with array data The QueueManager::getUniqueId() should not drop keys when sorting to create canonical data shapes for idempotency keys. Dropping keys allows data with different key semantics to be the 'same'. Instead we should recursively sort data by key. Thanks to Volker Dusch and the PHP Ecosystem security team for reporting this. --- src/QueueManager.php | 20 +++++++++++++++- tests/TestCase/QueueManagerTest.php | 36 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/QueueManager.php b/src/QueueManager.php index 976fd6c..65e5096 100644 --- a/src/QueueManager.php +++ b/src/QueueManager.php @@ -304,7 +304,7 @@ public static function push(string|array $className, array $data = [], array $op */ public static function getUniqueId(string $class, string $method, array $data): string { - sort($data); + $data = static::sortUniqueValues($data); $hashInput = implode('', [ $class, @@ -314,4 +314,22 @@ public static function getUniqueId(string $class, string $method, array $data): return hash('md5', $hashInput); } + + /** + * Recursively sort an array by key + * + * @param array $data The data to sort + * @return array The sorted array + */ + protected static function sortUniqueValues(array $data): array + { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = static::sortUniqueValues($value); + } + } + ksort($data); + + return $data; + } } diff --git a/tests/TestCase/QueueManagerTest.php b/tests/TestCase/QueueManagerTest.php index 85c8474..c584751 100644 --- a/tests/TestCase/QueueManagerTest.php +++ b/tests/TestCase/QueueManagerTest.php @@ -59,6 +59,42 @@ public function tearDown(): void array_map('unlink', glob($this->fsQueuePath . DS . '*')); } + public function testGetUniqueId() + { + $first = QueueManager::getUniqueId('Example', 'hello', [1, 2, 3]); + $second = QueueManager::getUniqueId('Example', 'hello', [3, 2, 1]); + $this->assertNotEquals($first, $second, 'values are sorted by key'); + + $second = QueueManager::getUniqueId('Human', 'hello', [3, 2, 1]); + $this->assertNotEquals($first, $second, 'class changes hash'); + + $second = QueueManager::getUniqueId('Example', 'bye', [3, 2, 1]); + $this->assertNotEquals($first, $second, 'method changes hash'); + + $first = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'guest']); + $second = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'guest']); + $this->assertSame($first, $second, 'same values and keys are the same'); + + $second = QueueManager::getUniqueId('Example', 'hello', ['role' => 'guest', 'user_id' => 'admin']); + $this->assertSame($first, $second, 'reordered keys are the same'); + + $first = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'guest']); + $second = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'admin']); + $this->assertNotEquals($first, $second, 'different values are distinct'); + + $first = QueueManager::getUniqueId('Example', 'hello', ['foo' => 'admin', 'bar' => 'guest']); + $second = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'guest']); + $this->assertNotEquals($first, $second, 'different keys, same values are distinct'); + + $first = QueueManager::getUniqueId('Example', 'hello', ['foo' => 'foo', 'bar' => 'foo']); + $second = QueueManager::getUniqueId('Example', 'hello', ['user_id' => 'admin', 'role' => 'guest']); + $this->assertNotEquals($first, $second, 'different keys and values, are distinct'); + + $first = QueueManager::getUniqueId('Example', 'hello', ['arr' => ['a' => 1, 'b' => 2]]); + $second = QueueManager::getUniqueId('Example', 'hello', ['arr' => ['b' => 2, 'a' => 1]]); + $this->assertEquals($first, $second, 'nested arrays are sorted too'); + } + public function testSetConfig() { QueueManager::setConfig('test', [ From ddb57b4758f8429f6d3eb65c8f39a024e7a69a68 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 8 Jun 2026 00:20:58 -0400 Subject: [PATCH 2/2] Improve types --- src/QueueManager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/QueueManager.php b/src/QueueManager.php index 65e5096..9a8bd89 100644 --- a/src/QueueManager.php +++ b/src/QueueManager.php @@ -318,8 +318,8 @@ public static function getUniqueId(string $class, string $method, array $data): /** * Recursively sort an array by key * - * @param array $data The data to sort - * @return array The sorted array + * @param array $data The data to sort + * @return array The sorted array */ protected static function sortUniqueValues(array $data): array { @@ -328,6 +328,7 @@ protected static function sortUniqueValues(array $data): array $data[$key] = static::sortUniqueValues($value); } } + ksort($data); return $data;