Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improve error message for missing PHP DB extensions #9160

Merged
merged 2 commits into from
Sep 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions system/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace CodeIgniter\Database;

use CodeIgniter\Exceptions\ConfigException;
use CodeIgniter\Exceptions\CriticalError;
use InvalidArgumentException;

/**
Expand Down Expand Up @@ -54,6 +56,8 @@ public function load(array $params = [], string $alias = '')
throw new InvalidArgumentException('You have not selected a database type to connect to.');
}

assert($this->checkDbExtension($params['DBDriver']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the assert here if the method throws by itself?

Copy link
Member Author

@kenjis kenjis Aug 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention is not to slow down CI4 at all by executing the check every time in production environment.
When zend.assertions is -1, PHP does not generate code for assert().

First, this check (error message) is only for PHP beginners. Once the extension is enabled, the check will be not needed.
And this error often happens on development environments.
On shared hosting servers, they probably know what DBMS is supported, and PHP extensions for supported DBs are installed.


$this->connections[$alias] = $this->initDriver($params['DBDriver'], 'Connection', $params);

return $this->connections[$alias];
Expand Down Expand Up @@ -124,9 +128,9 @@ protected function parseDSN(array $params): array
/**
* Creates a database object.
*
* @param string $driver Driver name. FQCN can be used.
* @param string $class 'Connection'|'Forge'|'Utils'
* @param array|object $argument The constructor parameter.
* @param string $driver Driver name. FQCN can be used.
* @param string $class 'Connection'|'Forge'|'Utils'
* @param array|ConnectionInterface $argument The constructor parameter or DB connection
*
* @return BaseConnection|BaseUtils|Forge
*/
Expand All @@ -138,4 +142,43 @@ protected function initDriver(string $driver, string $class, $argument): object

return new $classname($argument);
}

/**
* Check the PHP database extension is loaded.
*
* @param string $driver DB driver or FQCN for custom driver
*/
private function checkDbExtension(string $driver): bool
{
if (str_contains($driver, '\\')) {
// Cannot check a fully qualified classname for a custom driver.
return true;
}

$extensionMap = [
// DBDriver => PHP extension
'MySQLi' => 'mysqli',
'SQLite3' => 'sqlite3',
'Postgre' => 'pgsql',
'SQLSRV' => 'sqlsrv',
'OCI8' => 'oci8',
];

$extension = $extensionMap[$driver] ?? '';

if ($extension === '') {
$message = 'Invalid DBDriver name: "' . $driver . '"';

throw new ConfigException($message);
}

if (extension_loaded($extension)) {
return true;
}

$message = 'The required PHP extension "' . $extension . '" is not loaded.'
. ' Install and enable it to use "' . $driver . '" driver.';

throw new CriticalError($message);
}
}
Loading