Import alt-mysql plugin

This commit is contained in:
Marek Miklewicz
2026-07-04 15:48:19 +02:00
commit d71fcf9ace
101 changed files with 18635 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
return static function (AppContext $ctx): void {
$pluginErrorLog = PLUGIN_ROOT . '/error.log';
$rawMode = defined('DA_MYSQL_RAW_MODE') && DA_MYSQL_RAW_MODE === true;
$log = static function (string $message) use ($pluginErrorLog, $ctx): void {
$entry = sprintf(
"[%s] DOWNLOAD_DIRECT action=%s user=%s remote=%s method=%s uri=%s %s\n",
date('c'),
$ctx->action(),
$ctx->daUser->username(),
Http::server('REMOTE_ADDR'),
Http::method(),
Http::server('REQUEST_URI'),
$message
);
@error_log($entry, 3, $pluginErrorLog);
};
try {
if (!$ctx->daUser->hasPluginAccess()) {
throw new RuntimeException('Brak dostępu do pluginu.');
}
$queue = new BackupQueueService($ctx->settings, $ctx->daUser);
$jobId = trim($ctx->queryString('job'));
$backupPath = trim($ctx->queryString('path'));
$downloadPath = '';
$logLabel = '';
if ($jobId !== '') {
$logLabel = 'job_id=' . $jobId;
$downloadPath = $queue->resolveBackupTargetFileForCurrentUser($jobId);
} elseif ($backupPath !== '') {
$logLabel = 'path=' . $backupPath;
$downloadPath = $queue->resolveUserBackupFileForCurrentUser($backupPath);
} else {
throw new RuntimeException('Brak parametru job lub path.');
}
// Reuse streaming logic from index handler (simplified)
$log('start ' . $logLabel);
if (!is_file($downloadPath) || !is_readable($downloadPath)) {
throw new RuntimeException('Plik backupu nie istnieje lub brak odczytu.');
}
$downloadName = basename($downloadPath);
$downloadName = preg_replace('/[^A-Za-z0-9._-]+/', '_', $downloadName) ?? 'backup.sql';
$contentType = 'application/octet-stream';
if (preg_match('/\\.sql$/i', $downloadName)) {
$contentType = 'application/sql';
} elseif (preg_match('/\\.gz$/i', $downloadName)) {
$contentType = 'application/gzip';
}
clearstatcache(true, $downloadPath);
$size = @filesize($downloadPath);
while (ob_get_level() > 0) {
@ob_end_clean();
}
if (function_exists('apache_setenv')) {
@apache_setenv('no-gzip', '1');
}
@ini_set('zlib.output_compression', '0');
@ini_set('output_buffering', '0');
if ($rawMode) {
$statusLine = 'HTTP/1.1 200 OK';
echo $statusLine . "\r\n";
echo 'Content-Type: ' . $contentType . "\r\n";
echo 'Content-Disposition: attachment; filename="' . str_replace('"', '', $downloadName) . "\"\r\n";
echo "X-Content-Type-Options: nosniff\r\n";
echo "Cache-Control: no-store, no-cache, must-revalidate\r\n";
echo "Pragma: no-cache\r\n";
if (is_int($size) && $size > 0) {
echo 'Content-Length: ' . (string)$size . "\r\n";
}
echo "\r\n";
} else {
if (headers_sent($hsFile, $hsLine)) {
$log('headers_sent ' . $logLabel . ' file=' . $hsFile . ' line=' . (string)$hsLine);
throw new RuntimeException('Nagłówki zostały już wysłane.');
}
header_remove('Content-Encoding');
header('Content-Type: ' . $contentType);
header('Content-Disposition: attachment; filename="' . str_replace('"', '', $downloadName) . '"');
header('X-Content-Type-Options: nosniff');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
if (is_int($size) && $size > 0) {
header('Content-Length: ' . (string)$size);
}
}
$bytes = @readfile($downloadPath);
$log('done ' . $logLabel . ' bytes=' . (string)$bytes);
exit;
} catch (Throwable $e) {
$log('error message=' . $e->getMessage());
if ($rawMode) {
echo "HTTP/1.1 404 Not Found\r\n";
echo "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
echo 'Nie można pobrać backupu: ' . $e->getMessage();
} else {
http_response_code(404);
header('Content-Type: text/plain; charset=UTF-8');
echo 'Nie można pobrać backupu: ' . $e->getMessage();
}
exit;
}
};