137 lines
5.2 KiB
PHP
137 lines
5.2 KiB
PHP
<?php
|
|
// MariaDBBackend.php
|
|
// Created: 2021-04-30
|
|
// Updated: 2024-04-10
|
|
|
|
namespace Index\Data\MariaDB;
|
|
|
|
use InvalidArgumentException;
|
|
use Index\Version;
|
|
use Index\Data\IDbBackend;
|
|
use Index\Data\IDbConnection;
|
|
use Index\Data\IDbConnectionInfo;
|
|
use Index\Net\EndPoint;
|
|
use Index\Net\UnixEndPoint;
|
|
|
|
/**
|
|
* Information about the MariaDB/MySQL database layer.
|
|
*/
|
|
class MariaDBBackend implements IDbBackend {
|
|
public function isAvailable(): bool {
|
|
return extension_loaded('mysqli');
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
public static function intToVersion(int $version): Version {
|
|
$sub = $version % 100;
|
|
$version = floor($version / 100);
|
|
$minor = $version % 100;
|
|
$version = floor($version / 100);
|
|
$major = $version % 100;
|
|
return new Version($major, $minor, $sub);
|
|
}
|
|
|
|
/**
|
|
* Gets the version of the underlying client library.
|
|
*
|
|
* @return Version Version of the client library.
|
|
*/
|
|
public function getClientVersion(): Version {
|
|
return self::intToVersion(mysqli_get_client_version());
|
|
}
|
|
|
|
/**
|
|
* Creates a connection with a MariaDB or MySQL server.
|
|
*
|
|
* @param MariaDBConnectionInfo $connectionInfo Object that describes the desired connection.
|
|
* @return MariaDBConnection A connection with a MariaDB or MySQL server.
|
|
*/
|
|
public function createConnection(IDbConnectionInfo $connectionInfo): IDbConnection {
|
|
if(!($connectionInfo instanceof MariaDBConnectionInfo))
|
|
throw new InvalidArgumentException('$connectionInfo must by of type MariaDBConnectionInfo');
|
|
|
|
return new MariaDBConnection($connectionInfo);
|
|
}
|
|
|
|
/**
|
|
* Constructs a connection info instance from a dsn.
|
|
*
|
|
* A username and password can be specified in their respective parts of the URL.
|
|
*
|
|
* The host part of the URL can be any DNS name, or special value `:unix:`, documented further down.
|
|
*
|
|
* The path part of the URL is used as the database name. Any prefix or suffix slashes (`/`) are trimmed and others are converted to an underscore (`_`).
|
|
* Meaning `/slash/test/` is converted to `slash_test`.
|
|
*
|
|
* In order to use a Unix socket path, set the host part to `:unix:` and specify `socket=/path/to/socket.sock` in the query.
|
|
*
|
|
* Other supported query parameters are:
|
|
* - `charset=<name>`: Specifies the character set to use for the connection.
|
|
* - `init=<query>`: Any arbitrary SQL command to execute open connecting.
|
|
* - `enc_key=<path>`: Path to a private key file for SSL.
|
|
* - `enc_cert=<path>`: Path to a certificate file for SSL.
|
|
* - `enc_authority=<path>`: Path to a certificate authority file for SSL.
|
|
* - `enc_trusted_certs=<path>`: Path to a directory that contains PEM formatted SSL CA certificates.
|
|
* - `enc_ciphers=<list>`: A list of allowable ciphers to use for SSL encryption.
|
|
* - `enc_no_verify`: Disables verification of the server certificate, allows for MITM attacks.
|
|
* - `compress`: Enables protocol compression.
|
|
*
|
|
* Previously supported query parameters:
|
|
* - `enc_verify=<anything>`: Enabled verification of server certificate. Replaced with `enc_no_verify` as it now defaults to on.
|
|
*
|
|
* @param string|array $dsn DSN with connection information.
|
|
* @return MariaDBConnectionInfo MariaDB connection info.
|
|
*/
|
|
public function parseDsn(string|array $dsn): IDbConnectionInfo {
|
|
if(is_string($dsn)) {
|
|
$dsn = parse_url($dsn);
|
|
if($dsn === false)
|
|
throw new InvalidArgumentException('$dsn is not a valid uri.');
|
|
}
|
|
|
|
if(!isset($dsn['host']))
|
|
throw new InvalidArgumentException('Host is missing from DSN.');
|
|
if(!isset($dsn['path']))
|
|
throw new InvalidArgumentException('Path is missing from DSN.');
|
|
|
|
$host = $dsn['host'];
|
|
$needsUnix = $host === ':unix';
|
|
|
|
if(!$needsUnix && isset($dsn['port']))
|
|
$host .= ':' . $dsn['port'];
|
|
|
|
$user = $dsn['user'] ?? '';
|
|
$pass = $dsn['pass'] ?? '';
|
|
$endPoint = $needsUnix ? null : EndPoint::parse($host);
|
|
$dbName = str_replace('/', '_', trim($dsn['path'], '/')); // cute for table prefixes i think
|
|
|
|
parse_str(str_replace('+', '%2B', $dsn['query'] ?? ''), $query);
|
|
|
|
$unixPath = $query['socket'] ?? null;
|
|
$charSet = $query['charset'] ?? null;
|
|
$initCommand = $query['init'] ?? null;
|
|
$keyPath = $query['enc_key'] ?? null;
|
|
$certPath = $query['enc_cert'] ?? null;
|
|
$certAuthPath = $query['enc_authority'] ?? null;
|
|
$trustedCertsPath = $query['enc_trusted_certs'] ?? null;
|
|
$cipherAlgos = $query['enc_ciphers'] ?? null;
|
|
$verifyCert = !isset($query['enc_no_verify']);
|
|
$useCompression = isset($query['compress']);
|
|
|
|
if($needsUnix) {
|
|
if(empty($unixPath))
|
|
throw new InvalidArgumentException('Unix socket path is missing from DSN.');
|
|
$endPoint = new UnixEndPoint($unixPath);
|
|
}
|
|
|
|
return new MariaDBConnectionInfo(
|
|
$endPoint, $user, $pass, $dbName,
|
|
$charSet, $initCommand, $keyPath, $certPath,
|
|
$certAuthPath, $trustedCertsPath, $cipherAlgos,
|
|
$verifyCert, $useCompression
|
|
);
|
|
}
|
|
}
|