mirror of
https://github.com/michalcz10/USB-RAID-Array.git
synced 2026-11-11 07:59:04 +00:00
308 lines
9.8 KiB
PHP
308 lines
9.8 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../config/config.php';
|
|
require_once __DIR__ . '/../../includes/workspace.php';
|
|
|
|
if (!isset($_GET['token'])) {
|
|
die("Invalid request. No token provided.");
|
|
}
|
|
|
|
$token = $_GET['token'];
|
|
$database = getDatabaseConnection();
|
|
|
|
// Get share information
|
|
$statement = $database->prepare("SELECT * FROM share WHERE token = ? AND expiration > NOW()");
|
|
$statement->bind_param("s", $token);
|
|
$statement->execute();
|
|
$result = $statement->get_result();
|
|
|
|
if ($result->num_rows === 0) {
|
|
die("Invalid or expired share link.");
|
|
}
|
|
|
|
$share = $result->fetch_assoc();
|
|
$filePath = $share['file_path'];
|
|
$downloadAllowed = $share['download_allowed'] == 1;
|
|
$result->free();
|
|
$statement->close();
|
|
$database->close();
|
|
|
|
// Initialize SFTP
|
|
$sftp = initializeSFTP();
|
|
|
|
if (!$sftp->stat($filePath)) {
|
|
die("File not found: $filePath");
|
|
}
|
|
|
|
$fileName = basename($filePath);
|
|
$fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
|
$fileSize = $sftp->stat($filePath)['size'];
|
|
|
|
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
|
|
$videoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv'];
|
|
$audioExtensions = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac'];
|
|
|
|
$isImage = in_array($fileExtension, $imageExtensions);
|
|
$isVideo = in_array($fileExtension, $videoExtensions);
|
|
$isAudio = in_array($fileExtension, $audioExtensions);
|
|
|
|
if (!$isImage && !$isVideo && !$isAudio) {
|
|
die("Unsupported file type");
|
|
}
|
|
|
|
$mimeMap = [
|
|
'mp4' => 'video/mp4',
|
|
'webm' => 'video/mp4',
|
|
'ogg' => 'video/mp4',
|
|
'mov' => 'video/mp4',
|
|
'avi' => 'video/mp4',
|
|
'mkv' => 'video/mp4',
|
|
|
|
'jpg' => 'image/jpeg',
|
|
'jpeg' => 'image/jpeg',
|
|
'png' => 'image/png',
|
|
'gif' => 'image/gif',
|
|
'bmp' => 'image/bmp',
|
|
'webp' => 'image/webp',
|
|
'svg' => 'image/svg+xml',
|
|
|
|
'mp3' => 'audio/mpeg',
|
|
'wav' => 'audio/wav',
|
|
'm4a' => 'audio/mp4',
|
|
'flac' => 'audio/flac',
|
|
'aac' => 'audio/aac',
|
|
];
|
|
|
|
$mimeType = isset($mimeMap[$fileExtension]) ? $mimeMap[$fileExtension] : 'application/octet-stream';
|
|
|
|
// If streaming requested, stream file
|
|
if (isset($_GET['stream'])) {
|
|
// Similar streaming code as in view.php
|
|
session_write_close();
|
|
while (ob_get_level()) {
|
|
ob_end_clean();
|
|
}
|
|
if (ini_get('zlib.output_compression')) {
|
|
ini_set('zlib.output_compression', 'Off');
|
|
}
|
|
|
|
$start = 0;
|
|
$end = $fileSize - 1;
|
|
$length = $fileSize;
|
|
|
|
if (isset($_SERVER['HTTP_RANGE'])) {
|
|
$rangeHeader = $_SERVER['HTTP_RANGE'];
|
|
$matches = [];
|
|
if (preg_match('/bytes=(\d+)-(\d*)/', $rangeHeader, $matches)) {
|
|
$start = intval($matches[1]);
|
|
|
|
if (!empty($matches[2])) {
|
|
$end = intval($matches[2]);
|
|
}
|
|
|
|
$length = $end - $start + 1;
|
|
|
|
header('HTTP/1.1 206 Partial Content');
|
|
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $fileSize);
|
|
}
|
|
}
|
|
|
|
header("Content-Type: $mimeType");
|
|
header("Accept-Ranges: bytes");
|
|
header("Content-Length: $length");
|
|
header("Cache-Control: no-cache, no-store, must-revalidate");
|
|
header("Pragma: no-cache");
|
|
header("Expires: 0");
|
|
|
|
set_time_limit(0);
|
|
|
|
$minChunkSize = 64 * 1024;
|
|
$maxChunkSize = 2 * 1024 * 1024;
|
|
$chunkSize = 256 * 1024;
|
|
|
|
$currentPosition = $start;
|
|
$bytesRemaining = $length;
|
|
$lastChunkTime = microtime(true);
|
|
|
|
try {
|
|
while ($bytesRemaining > 0) {
|
|
if (connection_aborted() || connection_status() !== CONNECTION_NORMAL) {
|
|
break;
|
|
}
|
|
|
|
$readSize = min($chunkSize, $bytesRemaining);
|
|
$chunkData = $sftp->get($filePath, false, $currentPosition, $readSize);
|
|
|
|
if ($chunkData !== false) {
|
|
$bytesSent = strlen($chunkData);
|
|
echo $chunkData;
|
|
$bytesRemaining -= $bytesSent;
|
|
$currentPosition += $bytesSent;
|
|
|
|
if (ob_get_level()) {
|
|
ob_flush();
|
|
}
|
|
flush();
|
|
|
|
$currentTime = microtime(true);
|
|
$timeDiff = $currentTime - $lastChunkTime;
|
|
$lastChunkTime = $currentTime;
|
|
|
|
if ($timeDiff > 0) {
|
|
$speed = $bytesSent / $timeDiff;
|
|
$chunkSize = min(
|
|
max($minChunkSize, $chunkSize * (($speed > 512 * 1024) ? 1.5 : 0.8)),
|
|
$maxChunkSize
|
|
);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
usleep(100000);
|
|
}
|
|
} catch (Exception $exception) {
|
|
error_log("Shared streaming error: " . $exception->getMessage());
|
|
}
|
|
exit;
|
|
}
|
|
|
|
// Create download handler
|
|
if (isset($_GET['download'])) {
|
|
if (!$downloadAllowed) {
|
|
die("Download not permitted for this share.");
|
|
}
|
|
|
|
// Download file code similar to download.php
|
|
header("Content-Type: application/octet-stream");
|
|
header("Content-Disposition: attachment; filename=\"$fileName\"");
|
|
header("Content-Length: $fileSize");
|
|
|
|
$minChunkSize = 64 * 1024;
|
|
$maxChunkSize = 2 * 1024 * 1024;
|
|
$chunkSize = 256 * 1024;
|
|
|
|
$currentPosition = 0;
|
|
$bytesRemaining = $fileSize;
|
|
|
|
set_time_limit(0);
|
|
|
|
while ($bytesRemaining > 0) {
|
|
$readSize = min($chunkSize, $bytesRemaining);
|
|
$chunkData = $sftp->get($filePath, false, $currentPosition, $readSize);
|
|
|
|
if ($chunkData !== false) {
|
|
$bytesRead = strlen($chunkData);
|
|
echo $chunkData;
|
|
$bytesRemaining -= $bytesRead;
|
|
$currentPosition += $bytesRead;
|
|
flush();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
exit;
|
|
}
|
|
|
|
function formatBytes($bytes, $precision = 2) {
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
$bytes = max($bytes, 0);
|
|
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
|
$pow = min($pow, count($units) - 1);
|
|
$bytes /= (1 << (10 * $pow));
|
|
return round($bytes, $precision) . ' ' . $units[$pow];
|
|
}
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Shared Media - <?= htmlspecialchars($fileName) ?></title>
|
|
<link rel="icon" href="../../img/favicon.ico" type="image/x-icon">
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
<link rel="stylesheet" href="<?= workspaceAsset('../../', 'css/modern.css') ?>">
|
|
<link rel="stylesheet" href="<?= workspaceAsset('../../', 'css/workspace.css') ?>">
|
|
<link rel="stylesheet" href="<?= workspaceAsset('../../', 'content/ftp/css/view.css') ?>">
|
|
<script src="<?= workspaceAsset('../../', 'js/theme.js') ?>"></script>
|
|
<script src="<?= workspaceAsset('../../', 'js/ui.js') ?>" defer></script>
|
|
</head>
|
|
<?php renderWorkspaceStart([
|
|
'root' => '../../',
|
|
'active' => 'shared',
|
|
'section' => 'Shared file',
|
|
'eyebrow' => 'Shared with you',
|
|
'title' => $fileName,
|
|
'description' => 'Preview and access the file shared with you.',
|
|
'guest' => true,
|
|
'class' => 'media-page',
|
|
]); ?>
|
|
|
|
<div class="content-toolbar"><span class="badge">Shared link</span><p>Available until <?= htmlspecialchars(date('F j, Y, g:i a', strtotime($share['expiration']))) ?></p></div>
|
|
<section class="content-panel media-panel">
|
|
<article class="col-12">
|
|
<div class="media-container position-relative">
|
|
<?php if ($isImage): ?>
|
|
<img src="shared.php?token=<?= urlencode($token) ?>&stream=1" alt="<?= htmlspecialchars($fileName) ?>" class="img-fluid">
|
|
<?php elseif ($isVideo): ?>
|
|
<video id="videoPlayer" controls autoplay playsinline>
|
|
<source src="shared.php?token=<?= urlencode($token) ?>&stream=1" type="<?= $mimeType ?>">
|
|
Your browser does not support this video format.
|
|
</video>
|
|
<?php if($fileExtension !== 'mp4'): ?>
|
|
<div class="alert alert-warning mt-2">
|
|
Note: For best results, use MP4 format (H.264 codec). Other formats may not play correctly in all browsers.
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php elseif ($isAudio): ?>
|
|
<audio controls autoplay style="width: 80%;">
|
|
<source src="shared.php?token=<?= urlencode($token) ?>&stream=1" type="<?= $mimeType ?>">
|
|
Your browser does not support the audio element.
|
|
</audio>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($downloadAllowed) : ?>
|
|
<a href="shared.php?token=<?= urlencode($token) ?>&download=1" class="btn btn-success m-3">Download</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="file-info mt-4">
|
|
<h4>File Information</h4>
|
|
<table class="table table-bordered w-auto mx-auto text-wrap">
|
|
<tr>
|
|
<th>File Name</th>
|
|
<td class="text-break"><?= htmlspecialchars($fileName) ?></td>
|
|
</tr>
|
|
<tr>
|
|
<th>File Type</th>
|
|
<td><?= htmlspecialchars(strtoupper($fileExtension)) ?></td>
|
|
</tr>
|
|
<tr>
|
|
<th>File Size</th>
|
|
<td><?= formatBytes($fileSize) ?></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
|
|
<?php renderWorkspaceEnd(); ?>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const mediaElement = document.querySelector('video, audio');
|
|
|
|
if (mediaElement) {
|
|
const savedVolume = localStorage.getItem('mediaVolume');
|
|
if (savedVolume !== null) {
|
|
mediaElement.volume = parseFloat(savedVolume);
|
|
}
|
|
|
|
mediaElement.addEventListener('volumechange', () => {
|
|
localStorage.setItem('mediaVolume', mediaElement.volume);
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|