473 lines
14 KiB
PHP
473 lines
14 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
final class Settings
|
|
{
|
|
/** @var array<string,string> */
|
|
private array $values;
|
|
|
|
private function __construct(array $values)
|
|
{
|
|
$this->values = $values;
|
|
}
|
|
|
|
public static function load(string $path): self
|
|
{
|
|
$values = [];
|
|
if (is_readable($path)) {
|
|
$lines = file($path, FILE_IGNORE_NEW_LINES);
|
|
if ($lines !== false) {
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
if ($line === '' || $line[0] === '#') {
|
|
continue;
|
|
}
|
|
|
|
if (!preg_match('/^([A-Za-z0-9_]+)=(.*)$/', $line, $m)) {
|
|
continue;
|
|
}
|
|
|
|
$values[$m[1]] = self::parseShValue((string)$m[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return new self($values);
|
|
}
|
|
|
|
/**
|
|
* @return array{host:string,port:int,database:string,user:string,password:string,socket:string}
|
|
*/
|
|
public static function loadMysqlCredentials(string $path): array
|
|
{
|
|
if (!is_readable($path)) {
|
|
throw new RuntimeException('Brak pliku z danymi MySQL: ' . $path);
|
|
}
|
|
|
|
$lines = file($path, FILE_IGNORE_NEW_LINES);
|
|
if ($lines === false) {
|
|
throw new RuntimeException('Nie można odczytać pliku: ' . $path);
|
|
}
|
|
|
|
$kv = [];
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
if ($line === '' || $line[0] === '#') {
|
|
continue;
|
|
}
|
|
|
|
if (strpos($line, '=') !== false) {
|
|
[$k, $v] = array_map('trim', explode('=', $line, 2));
|
|
if ($k !== '') {
|
|
$kv[strtoupper($k)] = self::parseShValue($v);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$parts = explode(':', $line);
|
|
if (count($parts) >= 5) {
|
|
return [
|
|
'host' => trim($parts[0]) !== '' ? trim($parts[0]) : 'localhost',
|
|
'port' => (int)(trim($parts[1]) !== '' ? trim($parts[1]) : '3306'),
|
|
'database' => trim($parts[2]) !== '' ? trim($parts[2]) : 'mysql',
|
|
'user' => trim($parts[3]) !== '' ? trim($parts[3]) : 'root',
|
|
'password' => trim(implode(':', array_slice($parts, 4))),
|
|
'socket' => '',
|
|
];
|
|
}
|
|
}
|
|
|
|
$host = trim((string)($kv['HOST'] ?? $kv['MYSQL_HOST'] ?? ''));
|
|
if ($host === '') {
|
|
$host = 'localhost';
|
|
}
|
|
|
|
$portRaw = trim((string)($kv['PORT'] ?? $kv['MYSQL_PORT'] ?? '3306'));
|
|
$port = preg_match('/^[0-9]+$/', $portRaw) ? (int)$portRaw : 3306;
|
|
if ($port < 1 || $port > 65535) {
|
|
$port = 3306;
|
|
}
|
|
|
|
$database = trim((string)($kv['DATABASE'] ?? $kv['MYSQL_DATABASE'] ?? $kv['DB'] ?? 'mysql'));
|
|
if ($database === '' || $database === '*') {
|
|
$database = 'mysql';
|
|
}
|
|
|
|
$user = trim((string)($kv['USER'] ?? $kv['MYSQL_USER'] ?? 'root'));
|
|
$password = trim((string)($kv['PASSWORD'] ?? $kv['PASSWD'] ?? $kv['MYSQL_PASSWORD'] ?? ''));
|
|
$socket = trim((string)($kv['SOCKET'] ?? $kv['MYSQL_SOCKET'] ?? ''));
|
|
|
|
if ($user === '') {
|
|
throw new RuntimeException('Brak użytkownika MySQL w pliku: ' . $path);
|
|
}
|
|
|
|
return [
|
|
'host' => $host,
|
|
'port' => $port,
|
|
'database' => $database,
|
|
'user' => $user,
|
|
'password' => $password,
|
|
'socket' => $socket,
|
|
];
|
|
}
|
|
|
|
public function mysqlCredentialsFile(): string
|
|
{
|
|
$path = trim($this->getString('MYSQL_PLUGIN_CREDENTIALS_FILE', '/usr/local/directadmin/conf/alt-mysql.conf'));
|
|
return $path !== '' ? $path : '/usr/local/directadmin/conf/alt-mysql.conf';
|
|
}
|
|
|
|
public function mysqlClientBinDir(): string
|
|
{
|
|
return rtrim(trim($this->getString('MYSQL_PLUGIN_CLIENT_BIN_DIR', '')), '/');
|
|
}
|
|
|
|
public function getString(string $key, string $default = ''): string
|
|
{
|
|
return isset($this->values[$key]) ? trim($this->values[$key]) : $default;
|
|
}
|
|
|
|
public function getInt(string $key, int $default = 0): int
|
|
{
|
|
if (!isset($this->values[$key])) {
|
|
return $default;
|
|
}
|
|
|
|
$value = trim($this->values[$key]);
|
|
if ($value === '' || !preg_match('/^-?[0-9]+$/', $value)) {
|
|
return $default;
|
|
}
|
|
|
|
return (int)$value;
|
|
}
|
|
|
|
public function getBool(string $key, bool $default = false): bool
|
|
{
|
|
if (!isset($this->values[$key])) {
|
|
return $default;
|
|
}
|
|
|
|
return self::toBool($this->values[$key], $default);
|
|
}
|
|
|
|
public function defaultDatabasesLimit(): int
|
|
{
|
|
$limit = $this->getInt('MYSQL_PLUGIN_DEFAULT_DB_LIMIT', 5);
|
|
return $limit < 0 ? 0 : $limit;
|
|
}
|
|
|
|
public function alwaysEnabled(): bool
|
|
{
|
|
return $this->getBool('always_enabled', true);
|
|
}
|
|
|
|
public function maxHostsPerUser(): int
|
|
{
|
|
$limit = $this->getInt('MYSQL_PLUGIN_MAX_HOSTS_PER_USER', 30);
|
|
return $limit < 1 ? 1 : $limit;
|
|
}
|
|
|
|
public function allowRemoteHosts(): bool
|
|
{
|
|
if (array_key_exists('allow_remote_hosts', $this->values)) {
|
|
return self::toBool($this->values['allow_remote_hosts'], false);
|
|
}
|
|
|
|
if (array_key_exists('MYSQL_PLUGIN_ALLOW_REMOTE_HOSTS', $this->values)) {
|
|
return self::toBool($this->values['MYSQL_PLUGIN_ALLOW_REMOTE_HOSTS'], false);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function modifyServerConfiguration(): bool
|
|
{
|
|
if ($this->allowRemoteHosts()) {
|
|
return true;
|
|
}
|
|
|
|
if (array_key_exists('modify_server_configuration', $this->values)) {
|
|
return self::toBool($this->values['modify_server_configuration'], false);
|
|
}
|
|
|
|
if (array_key_exists('MYSQL_PLUGIN_MODIFY_SERVER_CONFIGURATION', $this->values)) {
|
|
return self::toBool($this->values['MYSQL_PLUGIN_MODIFY_SERVER_CONFIGURATION'], false);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function hostSyncScript(): string
|
|
{
|
|
$default = '/usr/local/directadmin/plugins/alt-mysql/scripts/setup/mysql_host_sync.sh';
|
|
$path = $this->getString('MYSQL_PLUGIN_SUDO_SYNC_HOSTS', $default);
|
|
return $path !== '' ? $path : $default;
|
|
}
|
|
|
|
public function enableBackup(): bool
|
|
{
|
|
return $this->getBool('ENABLE_BACKUP', true);
|
|
}
|
|
|
|
public function enableUploadBackup(): bool
|
|
{
|
|
return $this->getBool('ENABLE_UPLOAD_BACKUP', true);
|
|
}
|
|
|
|
public function enableAdminer(): bool
|
|
{
|
|
if (!$this->getBool('ENABLE_PHPMYADMIN', $this->getBool('ENABLE_ADMINER', true))) {
|
|
return false;
|
|
}
|
|
|
|
return $this->isPhpMyAdminInstalled();
|
|
}
|
|
|
|
public function phpMyAdminInstallDir(): string
|
|
{
|
|
$path = trim($this->getString('PHPMYADMIN_INSTALL_DIR', '/var/www/html/alt-mysql-phpmyadmin'));
|
|
return $path !== '' ? rtrim($path, '/') : '/var/www/html/alt-mysql-phpmyadmin';
|
|
}
|
|
|
|
public function adminerUrlPath(): string
|
|
{
|
|
$path = trim($this->getString('PHPMYADMIN_URL_PATH', $this->getString('ADMINER_URL_PATH', '/alt-mysql-phpmyadmin')));
|
|
if ($path === '') {
|
|
return '/alt-mysql-phpmyadmin';
|
|
}
|
|
|
|
if ($path[0] !== '/') {
|
|
$path = '/' . $path;
|
|
}
|
|
|
|
$path = rtrim($path, '/');
|
|
return $path !== '' ? $path : '/alt-mysql-phpmyadmin';
|
|
}
|
|
|
|
public function adminerPublicBaseUrl(): string
|
|
{
|
|
$url = trim($this->getString('PHPMYADMIN_PUBLIC_BASE_URL', $this->getString('ADMINER_PUBLIC_BASE_URL', '')));
|
|
if ($url === '') {
|
|
return '';
|
|
}
|
|
|
|
$url = rtrim($url, '/');
|
|
if (!preg_match('#^https?://#i', $url)) {
|
|
return '';
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
public function adminerPublic(): bool
|
|
{
|
|
return $this->getBool('PHPMYADMIN_PUBLIC', $this->getBool('ADMINER_PUBLIC', false));
|
|
}
|
|
|
|
public function adminerSsoDir(): string
|
|
{
|
|
$path = trim($this->getString('PHPMYADMIN_SSO_DIR', $this->getString('ADMINER_SSO_DIR', $this->phpMyAdminInstallDir() . '/runtime')));
|
|
if ($path === '') {
|
|
$path = $this->phpMyAdminInstallDir() . '/runtime';
|
|
}
|
|
return rtrim($path, '/');
|
|
}
|
|
|
|
public function adminerTicketTtl(): int
|
|
{
|
|
$ttl = $this->getInt('PHPMYADMIN_TICKET_TTL', $this->getInt('ADMINER_TICKET_TTL', 120));
|
|
if ($ttl < 10) {
|
|
return 10;
|
|
}
|
|
if ($ttl > 300) {
|
|
return 300;
|
|
}
|
|
return $ttl;
|
|
}
|
|
|
|
public function adminerSessionTtl(): int
|
|
{
|
|
$ttl = $this->getInt('PHPMYADMIN_SESSION_TTL', $this->getInt('ADMINER_SESSION_TTL', 900));
|
|
if ($ttl < 60) {
|
|
return 60;
|
|
}
|
|
if ($ttl > 3600) {
|
|
return 3600;
|
|
}
|
|
return $ttl;
|
|
}
|
|
|
|
public function adminerRoleTtl(): int
|
|
{
|
|
$ttl = $this->getInt('PHPMYADMIN_ROLE_TTL', $this->getInt('ADMINER_ROLE_TTL', 1200));
|
|
if ($ttl < 120) {
|
|
return 120;
|
|
}
|
|
if ($ttl > 7200) {
|
|
return 7200;
|
|
}
|
|
return $ttl;
|
|
}
|
|
|
|
public function phpMyAdminIntegrationWarning(): string
|
|
{
|
|
if (!$this->getBool('ENABLE_PHPMYADMIN', $this->getBool('ENABLE_ADMINER', true))) {
|
|
return '';
|
|
}
|
|
|
|
$dir = $this->phpMyAdminInstallDir();
|
|
if (!is_dir($dir)) {
|
|
return 'Prywatna kopia phpMyAdmin dla pluginu nie jest zainstalowana. Uruchom scripts/setup/phpmyadmin_private_install.sh jako root.';
|
|
}
|
|
|
|
$config = $dir . '/config.inc.php';
|
|
$signon = $dir . '/da_signon.php';
|
|
$signonUrl = $dir . '/da_login.php';
|
|
|
|
if (!is_readable($config)) {
|
|
return 'Prywatny phpMyAdmin pluginu jest zainstalowany, ale nie można odczytać config.inc.php.';
|
|
}
|
|
|
|
if (!is_readable($signon)) {
|
|
return 'Prywatny phpMyAdmin pluginu jest zainstalowany, ale brakuje da_signon.php. Uruchom scripts/setup/phpmyadmin_repair.sh jako root.';
|
|
}
|
|
if (!is_readable($signonUrl)) {
|
|
return 'Prywatny phpMyAdmin pluginu jest zainstalowany, ale brakuje da_login.php. Uruchom scripts/setup/phpmyadmin_repair.sh jako root.';
|
|
}
|
|
|
|
$contents = file_get_contents($config);
|
|
if (!is_string($contents) || strpos($contents, 'DA_MYSQL_PMA_DEFAULT_CONF') === false) {
|
|
return 'Prywatny phpMyAdmin pluginu nie ma konfiguracji alt-mysql. Uruchom scripts/setup/phpmyadmin_repair.sh jako root.';
|
|
}
|
|
if (strpos($contents, "SignonURL'] = da_mysql_phpmyadmin_signon_url") === false) {
|
|
return 'Prywatny phpMyAdmin pluginu nie ma wymaganej konfiguracji SignonURL. Uruchom scripts/setup/phpmyadmin_repair.sh jako root.';
|
|
}
|
|
$signonUrlContents = file_get_contents($signonUrl);
|
|
if (!is_string($signonUrlContents) || strpos($signonUrlContents, 'da_mysql_login_consume_ticket') === false) {
|
|
return 'Prywatny phpMyAdmin pluginu nie obsługuje jednorazowych ticketów SSO. Uruchom scripts/setup/phpmyadmin_repair.sh jako root.';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
public function allowRestoreToOtherDatabase(): bool
|
|
{
|
|
return $this->getBool('ALLOW_RESTORE_TO_OTHER_DATABASE', true);
|
|
}
|
|
|
|
public function enableTableCount(): bool
|
|
{
|
|
return $this->getBool('ENABLE_TABLE_COUNT', true);
|
|
}
|
|
|
|
public function countDatabaseSize(): bool
|
|
{
|
|
return $this->getBool('COUNT_DATABASE_SIZE', true);
|
|
}
|
|
|
|
public function compressBackup(): bool
|
|
{
|
|
return $this->getBool('COMPRESS_BACKUP', true);
|
|
}
|
|
|
|
public function hitmeBackupLocation(string $daUser = ''): string
|
|
{
|
|
$path = $this->getString('HITME_BACKUP_LOCATION', '/home/admin/mysql_backup');
|
|
if ($path === '') {
|
|
$path = '/home/admin/mysql_backup';
|
|
}
|
|
|
|
if ($daUser !== '') {
|
|
$path = str_replace(['DA_USER', 'da_user'], $daUser, $path);
|
|
}
|
|
|
|
return rtrim($path, '/');
|
|
}
|
|
|
|
public function userBaseBackupDir(string $daUser = ''): string
|
|
{
|
|
$path = $this->getString('USER_BASE_BACKUP_DIR', '/home/DA_USER/mysql_backup');
|
|
if ($path === '') {
|
|
$path = '/home/DA_USER/mysql_backup';
|
|
}
|
|
|
|
if ($daUser !== '') {
|
|
$path = str_replace(['DA_USER', 'da_user'], $daUser, $path);
|
|
}
|
|
|
|
return rtrim($path, '/');
|
|
}
|
|
|
|
public function userBackupDateFormat(): string
|
|
{
|
|
$format = $this->getString('USER_BACKUP_DATE_FORMAT', 'd.m.Y-H.i');
|
|
return $format !== '' ? $format : 'd.m.Y-H.i';
|
|
}
|
|
|
|
public function loadOrCreateSecret(string $path): string
|
|
{
|
|
if (is_readable($path)) {
|
|
$value = trim((string)file_get_contents($path));
|
|
if ($value !== '') {
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
$secret = bin2hex(random_bytes(32));
|
|
$dir = dirname($path);
|
|
if (!is_dir($dir)) {
|
|
@mkdir($dir, 0700, true);
|
|
}
|
|
|
|
if (@file_put_contents($path, $secret) !== false) {
|
|
@chmod($path, 0600);
|
|
return $secret;
|
|
}
|
|
|
|
return hash('sha256', __FILE__ . '|' . php_uname('n') . '|' . $path . '|alt-mysql');
|
|
}
|
|
|
|
public static function toBool(string $value, bool $default = false): bool
|
|
{
|
|
$v = strtolower(trim($value));
|
|
if ($v === '') {
|
|
return $default;
|
|
}
|
|
|
|
if (in_array($v, ['1', 'true', 'yes', 'y', 'on', 'checked'], true)) {
|
|
return true;
|
|
}
|
|
|
|
if (in_array($v, ['0', 'false', 'no', 'n', 'off', 'unchecked'], true)) {
|
|
return false;
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
private function isPhpMyAdminInstalled(): bool
|
|
{
|
|
$dir = $this->phpMyAdminInstallDir();
|
|
return is_dir($dir) && is_readable($dir . '/index.php') && is_readable($dir . '/config.inc.php');
|
|
}
|
|
|
|
private static function parseShValue(string $value): string
|
|
{
|
|
$value = trim($value);
|
|
if ($value === '') {
|
|
return '';
|
|
}
|
|
|
|
if ($value[0] === '\'' && substr($value, -1) === '\'') {
|
|
return substr($value, 1, -1);
|
|
}
|
|
|
|
if ($value[0] === '"' && substr($value, -1) === '"') {
|
|
return stripcslashes(substr($value, 1, -1));
|
|
}
|
|
|
|
$value = preg_replace('/\s+#.*$/', '', $value);
|
|
return trim((string)$value);
|
|
}
|
|
}
|