65 lines
2.4 KiB
PHP
65 lines
2.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
http_response_code(404);
|
|
exit;
|
|
}
|
|
|
|
$config = require dirname(__DIR__) . '/config.php';
|
|
if (empty($config['installed']) || ($config['db']['driver'] ?? '') !== 'mysql') {
|
|
fwrite(STDERR, "系统尚未安装或未使用 MySQL。\n");
|
|
exit(1);
|
|
}
|
|
|
|
$targetDirectory = $argv[1] ?? '/var/backups/tanwan';
|
|
if (!str_starts_with($targetDirectory, '/') || in_array(rtrim($targetDirectory, '/'), ['', '/', dirname(__DIR__)], true)) {
|
|
fwrite(STDERR, "备份目录必须是 Web 根目录之外的绝对路径。\n");
|
|
exit(1);
|
|
}
|
|
$webRoot = realpath(dirname(__DIR__));
|
|
$resolvedParent = realpath(dirname($targetDirectory));
|
|
if ($webRoot !== false && $resolvedParent !== false && str_starts_with($resolvedParent . '/', $webRoot . '/')) {
|
|
fwrite(STDERR, "禁止将备份写入 Web 根目录。\n");
|
|
exit(1);
|
|
}
|
|
if (!is_dir($targetDirectory) && !mkdir($targetDirectory, 0700, true) && !is_dir($targetDirectory)) {
|
|
fwrite(STDERR, "无法创建备份目录。\n");
|
|
exit(1);
|
|
}
|
|
chmod($targetDirectory, 0700);
|
|
|
|
$db = $config['db'];
|
|
$filename = rtrim($targetDirectory, '/') . '/tanwan-' . date('Ymd-His') . '.sql';
|
|
$command = ['/usr/bin/mariadb-dump', '--single-transaction', '--quick', '--skip-lock-tables', '--default-character-set=utf8mb4'];
|
|
if (in_array((string) $db['host'], ['localhost', 'localhost.localdomain'], true)) {
|
|
$command[] = '--protocol=socket';
|
|
} else {
|
|
$command[] = '--host=' . $db['host'];
|
|
$command[] = '--port=' . $db['port'];
|
|
}
|
|
$command[] = '--user=' . $db['username'];
|
|
$command[] = (string) $db['database'];
|
|
$descriptors = [0 => ['file', '/dev/null', 'rb'], 1 => ['file', $filename, 'wb'], 2 => ['pipe', 'w']];
|
|
$environment = array_merge(getenv(), ['MYSQL_PWD' => (string) $db['password']]);
|
|
$process = proc_open($command, $descriptors, $pipes, null, $environment, ['bypass_shell' => true]);
|
|
if (!is_resource($process)) {
|
|
fwrite(STDERR, "无法启动数据库备份。\n");
|
|
exit(1);
|
|
}
|
|
$errors = stream_get_contents($pipes[2]);
|
|
fclose($pipes[2]);
|
|
$exitCode = proc_close($process);
|
|
if ($exitCode !== 0) {
|
|
@unlink($filename);
|
|
fwrite(STDERR, "备份失败:" . trim($errors) . "\n");
|
|
exit(1);
|
|
}
|
|
chmod($filename, 0600);
|
|
|
|
$cutoff = time() - 14 * 86400;
|
|
foreach (glob(rtrim($targetDirectory, '/') . '/tanwan-*.sql') ?: [] as $oldBackup) {
|
|
if (is_file($oldBackup) && filemtime($oldBackup) < $cutoff) unlink($oldBackup);
|
|
}
|
|
fwrite(STDOUT, $filename . "\n");
|