$env * @return array */ private function loadDatabaseConfig(array $env): array { $keys = [ 'DB_SSL', 'DB_SSL_IS_PAAS', 'DB_SSL_KEY_PATH', 'DB_SSL_CERT_PATH', 'DB_SSL_CA_PATH', 'DB_SSL_CIPHER', 'DB_SSL_VERIFY_SERVER', ]; foreach ($keys as $key) { unset($_ENV[$key], $_SERVER[$key]); putenv($key); } foreach ($env as $key => $value) { if ($value === null) { $_ENV[$key] = 'null'; $_SERVER[$key] = 'null'; putenv("$key=null"); } else { $_ENV[$key] = $value; $_SERVER[$key] = $value; putenv("$key=$value"); } } return require base_path('config/database.php'); } public function test_ssl_disabled_yields_no_pdo_options(): void { $config = $this->loadDatabaseConfig(['DB_SSL' => 'false']); $this->assertSame([], $config['connections']['mysql']['options']); $this->assertSame([], $config['connections']['mariadb']['options']); } public function test_ssl_enabled_paas_mode_includes_ca_and_verify_only(): void { $config = $this->loadDatabaseConfig([ 'DB_SSL' => 'true', 'DB_SSL_IS_PAAS' => 'true', 'DB_SSL_CA_PATH' => '/path/to/ca.pem', 'DB_SSL_VERIFY_SERVER' => 'true', ]); $options = $config['connections']['mysql']['options']; $this->assertSame('/path/to/ca.pem', $options[PDO::MYSQL_ATTR_SSL_CA]); $this->assertTrue($options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT]); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_KEY, $options); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CERT, $options); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CIPHER, $options); } public function test_ssl_enabled_self_hosted_mode_includes_full_client_cert_set(): void { $config = $this->loadDatabaseConfig([ 'DB_SSL' => 'true', 'DB_SSL_KEY_PATH' => '/path/to/key.pem', 'DB_SSL_CERT_PATH' => '/path/to/cert.pem', 'DB_SSL_CA_PATH' => '/path/to/ca.pem', 'DB_SSL_CIPHER' => 'ECDHE-RSA-AES256-GCM-SHA384', ]); $options = $config['connections']['mysql']['options']; $this->assertSame('/path/to/key.pem', $options[PDO::MYSQL_ATTR_SSL_KEY]); $this->assertSame('/path/to/cert.pem', $options[PDO::MYSQL_ATTR_SSL_CERT]); $this->assertSame('/path/to/ca.pem', $options[PDO::MYSQL_ATTR_SSL_CA]); $this->assertSame('ECDHE-RSA-AES256-GCM-SHA384', $options[PDO::MYSQL_ATTR_SSL_CIPHER]); } public function test_null_cipher_is_omitted_not_passed_as_null(): void { // Regression for #19411. .env.example ships DB_SSL_CIPHER=null and // the old code passed that through as PDO::MYSQL_ATTR_SSL_CIPHER => // null, which made libmysql / libmariadb fail with "Cannot connect // to MySQL using SSL". A null cipher MUST be omitted so the driver // negotiates a default. $config = $this->loadDatabaseConfig([ 'DB_SSL' => 'true', 'DB_SSL_KEY_PATH' => '/path/to/key.pem', 'DB_SSL_CERT_PATH' => '/path/to/cert.pem', 'DB_SSL_CA_PATH' => '/path/to/ca.pem', 'DB_SSL_CIPHER' => null, ]); $options = $config['connections']['mysql']['options']; $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CIPHER, $options); } public function test_null_paths_are_omitted_across_every_ssl_key(): void { // Same shape trap as CIPHER: any of the path envs left at the // .env.example default of `null` would land as PDO::MYSQL_ATTR_SSL_* // => null and break the SSL handshake. Every path key gets the // omit-when-null treatment. $config = $this->loadDatabaseConfig([ 'DB_SSL' => 'true', 'DB_SSL_KEY_PATH' => null, 'DB_SSL_CERT_PATH' => null, 'DB_SSL_CA_PATH' => null, 'DB_SSL_CIPHER' => null, ]); $options = $config['connections']['mysql']['options']; $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_KEY, $options); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CERT, $options); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CA, $options); $this->assertArrayNotHasKey(PDO::MYSQL_ATTR_SSL_CIPHER, $options); // VERIFY_SERVER_CERT is always included with a bool cast because // both true and false are valid values. $this->assertArrayHasKey(PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, $options); $this->assertFalse($options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT]); } public function test_mariadb_connection_shares_the_same_ssl_options(): void { $config = $this->loadDatabaseConfig([ 'DB_SSL' => 'true', 'DB_SSL_KEY_PATH' => '/path/to/key.pem', 'DB_SSL_CERT_PATH' => '/path/to/cert.pem', 'DB_SSL_CA_PATH' => '/path/to/ca.pem', ]); $this->assertSame( $config['connections']['mysql']['options'], $config['connections']['mariadb']['options'] ); } }