112 lines
4.4 KiB
PHP
112 lines
4.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
return static function (AppContext $ctx): void {
|
|
$pluginErrorLog = PLUGIN_ROOT . '/error.log';
|
|
$rawMode = defined('DA_POSTGRESQL_RAW_MODE') && DA_POSTGRESQL_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;
|
|
}
|
|
};
|