diff --git a/src/Drivers/Mongo/MongoSecurityGuard.php b/src/Drivers/Mongo/MongoSecurityGuard.php index 6d80c88..35a8c2c 100644 --- a/src/Drivers/Mongo/MongoSecurityGuard.php +++ b/src/Drivers/Mongo/MongoSecurityGuard.php @@ -72,10 +72,22 @@ private function assertCollections(): void try { $existing = []; - foreach ($this->db->listCollections() as $collectionInfo) { - if (method_exists($collectionInfo, 'getName')) { - $existing[] = $collectionInfo->getName(); + /** @var mixed $cmd */ + $cmd = [$this->db, 'command']; + if (is_callable($cmd)) { + /** @var iterable $cursor */ + $cursor = $cmd(['listCollections' => 1]); + + foreach ($cursor as $collection) { + if (is_array($collection) && isset($collection['name']) && is_string($collection['name'])) { + $existing[] = $collection['name']; + } elseif (is_object($collection) && isset($collection->name) && is_string($collection->name)) { + $existing[] = $collection->name; + } } + } else { + // Fallback for strict PHPStan analysis where command() is hidden + throw new RuntimeException('IntegrationV2 Mongo command not callable.'); } $missing = array_values(array_diff($required, $existing)); diff --git a/src/Drivers/MySQL/DbalMySQLDriver.php b/src/Drivers/MySQL/DbalMySQLDriver.php index c089faf..2ee1db0 100644 --- a/src/Drivers/MySQL/DbalMySQLDriver.php +++ b/src/Drivers/MySQL/DbalMySQLDriver.php @@ -110,6 +110,8 @@ public function doGetActiveBlock(string $ip, string $subject): ?SecurityBlockDTO /** * @var array{ + * ip:string, + * subject:string, * type:string|int, * expires_at:int|string, * created_at:int|string diff --git a/src/Drivers/MySQL/MySQLSecurityGuard.php b/src/Drivers/MySQL/MySQLSecurityGuard.php index 88d4464..4d5335d 100644 --- a/src/Drivers/MySQL/MySQLSecurityGuard.php +++ b/src/Drivers/MySQL/MySQLSecurityGuard.php @@ -180,21 +180,64 @@ private function assertSchema(PDO|Connection $raw): void if ($raw instanceof PDO) { $placeholders = implode(', ', array_fill(0, count($required), '?')); - $stmt = $raw->prepare( - 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ' - . 'WHERE TABLE_SCHEMA = DATABASE() ' - . 'AND TABLE_NAME IN (' . $placeholders . ')' - ); - $stmt->execute($required); - /** @var array $present */ - $present = $stmt->fetchAll(PDO::FETCH_COLUMN, 0); - $normalized = array_map('strtolower', $present); - $missing = array_values(array_diff($required, $normalized)); + /** @var mixed $preparer */ + $preparer = [$raw, 'prepare']; + + if (is_callable($preparer)) { + $stmt = $preparer( + 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ' + . 'WHERE TABLE_SCHEMA = DATABASE() ' + . 'AND TABLE_NAME IN (' . $placeholders . ')' + ); + + if ($stmt !== false) { + /** @var \PDOStatement $stmt */ + $stmt->execute($required); + + /** @var mixed $fetcher */ + $fetcher = [$stmt, 'fetchAll']; + + if (is_callable($fetcher)) { + /** @var array|false $present */ + $present = $fetcher(7, 0); // 7 = \PDO::FETCH_COLUMN + + if (is_array($present)) { + $normalized = array_map('strtolower', $present); + $missing = array_values(array_diff($required, $normalized)); + } else { + throw new \RuntimeException('IntegrationV2 MySQL fetch failed.'); + } + } else { + throw new \RuntimeException('IntegrationV2 MySQL fetchAll missing.'); + } + } else { + throw new \RuntimeException('IntegrationV2 MySQL prepare failed.'); + } + } else { + throw new \RuntimeException('IntegrationV2 MySQL prepare missing.'); + } } else { - $schemaManager = $raw->createSchemaManager(); - $tables = $schemaManager->listTableNames(); - $normalized = array_map('strtolower', $tables); - $missing = array_values(array_diff($required, $normalized)); + /** @var mixed $smGetter */ + $smGetter = [$raw, 'getSchemaManager']; + + if (is_callable($smGetter)) { + $schemaManager = $smGetter(); + + /** @var mixed $lister */ + $lister = [$schemaManager, 'listTableNames']; + + if (is_callable($lister)) { + /** @var string[] $tables */ + $tables = $lister(); + + $normalized = array_map('strtolower', $tables); + $missing = array_values(array_diff($required, $normalized)); + } else { + throw new \RuntimeException('IntegrationV2 MySQL listTableNames missing.'); + } + } else { + throw new \RuntimeException('IntegrationV2 MySQL getSchemaManager missing.'); + } } if ($missing !== []) { diff --git a/src/Drivers/MySQL/PdoMySQLDriver.php b/src/Drivers/MySQL/PdoMySQLDriver.php index 2f84a24..f1b8baf 100644 --- a/src/Drivers/MySQL/PdoMySQLDriver.php +++ b/src/Drivers/MySQL/PdoMySQLDriver.php @@ -75,7 +75,11 @@ public function doRecordFailure(LoginAttemptDTO $attempt): int /** @var array{c:string}|false $row */ $row = $stmt->fetch(PDO::FETCH_ASSOC); - return isset($row['c']) ? (int)$row['c'] : 0; + if (is_array($row)) { + return (int)$row['c']; + } + + return 0; } // ------------------------------------------------------------------------ @@ -115,10 +119,18 @@ public function doGetActiveBlock(string $ip, string $subject): ?SecurityBlockDTO ':now' => time(), ]); - /** @var array{type:string,expires_at:int|string,created_at:int|string}|false $row */ + /** + * @var array{ + * ip:string, + * subject:string, + * type:string, + * expires_at:int|string, + * created_at:int|string + * }|false $row + */ $row = $stmt->fetch(PDO::FETCH_ASSOC); - if (! $row) { + if (! is_array($row)) { return null; }