From 99b1c96f4bd961f4010ee428df39889e36d0d975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Sedl=C3=A1k?= Date: Sun, 18 Oct 2026 15:55:34 +0200 Subject: [PATCH] revise backend --- README.md | 5 + Web/config/config.php | 12 +- Web/content/adminpanel.php | 197 ++++++++++++--------------------- Web/content/changepassword.php | 125 +++++++-------------- Web/content/ftp/createdir.php | 24 ++-- Web/content/ftp/createfile.php | 43 ++----- Web/content/ftp/delete.php | 29 +++-- Web/content/ftp/download.php | 117 ++++++++++---------- Web/content/ftp/extract.php | 61 ++++------ Web/content/ftp/index.php | 75 ++++++------- Web/content/ftp/open.php | 28 ++--- Web/content/ftp/pdf.php | 18 +-- Web/content/ftp/rename.php | 32 ++---- Web/content/ftp/serverstat.php | 15 +-- Web/content/ftp/shared.php | 42 +++---- Web/content/ftp/upload.php | 177 +++++++++++------------------ Web/content/ftp/view.php | 59 ++++------ Web/content/login.php | 124 ++++++++------------- Web/includes/auth.php | 28 +++++ Web/includes/remotepaths.php | 22 ++++ tests/backend_test.php | 147 ++++++++++++++++++++++++ tests/remotepaths_test.php | 16 ++- tests/workspace_test.php | 5 +- 23 files changed, 681 insertions(+), 720 deletions(-) create mode 100644 Web/includes/auth.php create mode 100644 tests/backend_test.php diff --git a/README.md b/README.md index a804175..06ec4b0 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Z kořene repozitáře: php tests/workspace_test.php php tests/serverstats_test.php php tests/remotepaths_test.php +php tests/backend_test.php node --check Web/js/theme.js node --check Web/js/ui.js node --check Web/content/ftp/js/index.js @@ -136,6 +137,10 @@ node --check Web/content/ftp/js/index.js PHP testy používají testovací data a nepotřebují připojení k databázi ani SSH. Kontrolují vykreslení stránek, navigaci podle role, zpracování statistik a stavy RAID polí. Node.js slouží u uvedených příkazů ke kontrole syntaxe; pro běh aplikace není potřeba. +Test backendu navíc ověřuje přihlášení, oprávnění operací, hranice vzdálených cest, vytváření prázdných souborů a upload. Spouští handlery v oddělených PHP procesech s testovacími náhradami databáze a SFTP; vyžaduje dostupné `proc_open`. + +V backendu používej popisné názvy lokálních proměnných ve stylu `camelCase`, například `$username`, `$passwordHash`, `$database`, `$statement`, `$directoryPath` a `$canUpload`. Konfigurační proměnné `$DB_*`, `$SFTP_*`, `$SSH_*` a existující klíče databáze, formulářů a session (`uname`, `pswd`, `defPath`, `upPer` apod.) zůstávají kvůli kompatibilitě zachované. Společné kontroly přihlášení, oprávnění a hesel jsou v `Web/includes/auth.php`; práci s POSIX cestami soustřeď do `Web/includes/remotepaths.php`. + ## Časté problémy | Problém | Co zkontrolovat | diff --git a/Web/config/config.php b/Web/config/config.php index b71264f..7d70062 100644 --- a/Web/config/config.php +++ b/Web/config/config.php @@ -19,7 +19,7 @@ $SFTP_HOST = '172.16.1.11'; $SFTP_USER = 'usbraid'; $SFTP_PASS = 'usbraid'; // Default remote path – uses session value if set -$defaultPath = $_SESSION['defPath'] ?? '/'; +$defaultPath = normalizePath($_SESSION['defPath'] ?? '/'); // SSH credentials (placeholders) $SSH_HOST = '172.16.1.11'; @@ -29,12 +29,12 @@ $SSH_PASS = 'usbraid'; /** Helper: Get a MySQLi connection */ function getDatabaseConnection(): mysqli { global $DB_HOST, $DB_USER, $DB_PASS, $DB_NAME; - $conn = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME); - if ($conn->connect_error) { - die('Connection failed: ' . $conn->connect_error); + $database = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME); + if ($database->connect_error) { + die('Connection failed: ' . $database->connect_error); } - $conn->set_charset('utf8'); - return $conn; + $database->set_charset('utf8'); + return $database; } /** Helper: Initialise SFTP connection */ diff --git a/Web/content/adminpanel.php b/Web/content/adminpanel.php index 8a43c45..b321611 100644 --- a/Web/content/adminpanel.php +++ b/Web/content/adminpanel.php @@ -1,139 +1,80 @@ connect_error) { - die("Database connection failed: " . $conn->connect_error); -} +$database = getDatabaseConnection(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_POST['uname']) && isset($_POST['pswd'])) { - $uname = trim($_POST['uname']); - $pswd = trim($_POST['pswd']); - $is_admin = isset($_POST['admin']) ? 1 : 0; - $defPath = isset($_POST['defPath']) ? trim($_POST['defPath']) : ''; - $delPer = isset($_POST['delPer']) ? (int)$_POST['delPer'] : 0; - $dowPer = isset($_POST['downPer']) ? (int)$_POST['downPer'] : 0; - $upPer = isset($_POST['upPer']) ? (int)$_POST['upPer'] : 0; + $username = is_string($_POST['uname'] ?? null) ? trim($_POST['uname']) : ''; + $password = is_string($_POST['pswd'] ?? null) ? $_POST['pswd'] : ''; + $defaultPath = is_string($_POST['defPath'] ?? null) ? normalizePath(trim($_POST['defPath'])) : '/'; + $isAdmin = isset($_POST['admin']) ? 1 : 0; + $canDelete = isset($_POST['delPer']) ? 1 : 0; + $canDownload = isset($_POST['downPer']) ? 1 : 0; + $canUpload = isset($_POST['upPer']) ? 1 : 0; + $_SESSION['message_type'] = 'error'; - if (empty($uname) || empty($pswd)) { - $_SESSION['message'] = 'Error: Username and password are required!'; - $_SESSION['message_type'] = 'error'; - } else if (!CheckPassword($pswd)) { - $_SESSION['message'] = 'Error: Password must be at least 8 characters long, contain at least one number and one uppercase letter!'; - $_SESSION['message_type'] = 'error'; - } else { - $sql_check = "SELECT * FROM users WHERE uname = ?"; - $stmt_check = $conn->prepare($sql_check); - if (!$stmt_check) { - $_SESSION['message'] = 'Error: Database preparation failed.'; - $_SESSION['message_type'] = 'error'; + if ($username === '' || $password === '') { + $_SESSION['message'] = 'Error: Username and password are required!'; + } elseif (!isPasswordValid($password)) { + $_SESSION['message'] = 'Error: Password must be at least 8 characters long, contain at least one number and one uppercase letter!'; + } else { + try { + $statement = $database->prepare('SELECT uname FROM users WHERE uname = ?'); + $statement->bind_param('s', $username); + $statement->execute(); + $result = $statement->get_result(); + $userExists = $result->num_rows > 0; + $result->free(); + $statement->close(); + + if ($userExists) { + $_SESSION['message'] = 'Error: Username already exists!'; } else { - $stmt_check->bind_param("s", $uname); - $stmt_check->execute(); - $result_check = $stmt_check->get_result(); - - if ($result_check->num_rows > 0) { - $_SESSION['message'] = 'Error: Username already exists!'; - $_SESSION['message_type'] = 'error'; - } else { - $sql_insert = "INSERT INTO users (uname, pswd, admin, defPath, delPer, downPer, upPer) VALUES (?, ?, ?, ?, ?, ?, ?)"; - $stmt_insert = $conn->prepare($sql_insert); - if (!$stmt_insert) { - $_SESSION['message'] = 'Error: Database preparation failed.'; - $_SESSION['message_type'] = 'error'; - } else { - $hash = password_hash($pswd, PASSWORD_BCRYPT); - if (!$hash) { - $_SESSION['message'] = 'Error: Password hashing failed.'; - $_SESSION['message_type'] = 'error'; - } else { - $stmt_insert->bind_param("ssisiii", $uname, $hash, $is_admin, $defPath, $delPer, $dowPer, $upPer); - if ($stmt_insert->execute()) { - $_SESSION['message'] = 'User added successfully!'; - $_SESSION['message_type'] = 'success'; - } else { - $_SESSION['message'] = 'Error: Failed to add user. Please try again later.'; - $_SESSION['message_type'] = 'error'; - } - } - } - } - $stmt_check->close(); - if (isset($stmt_insert)) { - $stmt_insert->close(); - } + $passwordHash = password_hash($password, PASSWORD_BCRYPT); + $statement = $database->prepare('INSERT INTO users (uname, pswd, admin, defPath, delPer, downPer, upPer) VALUES (?, ?, ?, ?, ?, ?, ?)'); + $statement->bind_param('ssisiii', $username, $passwordHash, $isAdmin, $defaultPath, $canDelete, $canDownload, $canUpload); + $statement->execute(); + $statement->close(); + $_SESSION['message'] = 'User added successfully!'; + $_SESSION['message_type'] = 'success'; } + } catch (mysqli_sql_exception $exception) { + error_log($exception->getMessage()); + $_SESSION['message'] = 'Error: Failed to add user. Please try again later.'; } - - header("Location: adminpanel.php"); - exit(); - } else { - $_SESSION['message'] = 'Error: Missing form data!'; - $_SESSION['message_type'] = 'error'; - header("Location: adminpanel.php"); - exit(); } + $database->close(); + header('Location: adminpanel.php'); + exit; } -if (isset($_GET['delete'])) { - $delete_uname = htmlspecialchars($_GET['delete']); - $sql = "DELETE FROM users WHERE uname=?"; - $stmt = $conn->prepare($sql); - if ($stmt) { - $stmt->bind_param("s", $delete_uname); - if ($stmt->execute()) { - $_SESSION['message'] = 'User deleted successfully!'; - $_SESSION['message_type'] = 'success'; - } else { - $_SESSION['message'] = 'Error: Failed to delete user.'; - $_SESSION['message_type'] = 'error'; - } - $stmt->close(); - } else { - $_SESSION['message'] = 'Error: Database preparation failed.'; +if (isset($_GET['delete']) && is_string($_GET['delete'])) { + $usernameToDelete = $_GET['delete']; + try { + $statement = $database->prepare('DELETE FROM users WHERE uname = ?'); + $statement->bind_param('s', $usernameToDelete); + $statement->execute(); + $statement->close(); + $_SESSION['message'] = 'User deleted successfully!'; + $_SESSION['message_type'] = 'success'; + } catch (mysqli_sql_exception $exception) { + error_log($exception->getMessage()); + $_SESSION['message'] = 'Error: Failed to delete user.'; $_SESSION['message_type'] = 'error'; } - - header("Location: adminpanel.php"); - exit(); + $database->close(); + header('Location: adminpanel.php'); + exit; } -$result = $conn->query("SELECT uname, admin, defPath, delPer, downPer, upPer FROM users"); - +$result = $database->query('SELECT uname, admin, defPath, delPer, downPer, upPer FROM users'); $message = $_SESSION['message'] ?? ''; -$message_type = $_SESSION['message_type'] ?? ''; -unset($_SESSION['message']); -unset($_SESSION['message_type']); - -function CheckPassword($password) { - if (strlen($password) < 8) { - return false; - } - if (!preg_match('/[0-9]/', $password)) { - return false; - } - if (!preg_match('/[A-Z]/', $password)) { - return false; - } - return true; -} +$messageType = $_SESSION['message_type'] ?? ''; +unset($_SESSION['message'], $_SESSION['message_type']); ?> @@ -169,7 +110,7 @@ function CheckPassword($password) {
-
+
@@ -223,16 +164,16 @@ function CheckPassword($password) { - fetch_assoc()) { ?> + fetch_assoc()) { ?> - - - - - - + + + + + + - + @@ -244,5 +185,5 @@ function CheckPassword($password) { close(); +$database->close(); ?> diff --git a/Web/content/changepassword.php b/Web/content/changepassword.php index 82d7f2b..748d403 100644 --- a/Web/content/changepassword.php +++ b/Web/content/changepassword.php @@ -1,95 +1,56 @@ connect_error) { - $message = "Database connection failed!"; - $messageType = "danger"; - } else { - $sql = "SELECT pswd FROM users WHERE uname=?"; - $stmt = $conn->prepare($sql); - $stmt->bind_param("s", $uname); - $stmt->execute(); - $result = $stmt->get_result(); - - if ($result && $result->num_rows > 0) { - $row = $result->fetch_assoc(); - $stored_hash = $row["pswd"]; - - if (password_verify($current_password, $stored_hash)) { - $new_hash = password_hash($new_password, PASSWORD_BCRYPT); - $update_sql = "UPDATE users SET pswd=? WHERE uname=?"; - $update_stmt = $conn->prepare($update_sql); - $update_stmt->bind_param("ss", $new_hash, $uname); - - if ($update_stmt->execute()) { - $message = "Password changed successfully!"; - $messageType = "success"; - } else { - $message = "Error updating password: " . $conn->error; - $messageType = "danger"; - } - $update_stmt->close(); - } else { - $message = "Current password is incorrect!"; - $messageType = "danger"; - } - } else { - $message = "User not found!"; - $messageType = "danger"; - } - - $stmt->close(); - $conn->close(); - } - } + if (!is_string($currentPassword) || !is_string($newPassword) || !is_string($confirmPassword)) { + $message = 'All fields are required!'; + } elseif (!isPasswordValid($newPassword)) { + $message = 'New password must be at least 8 characters long, contain at least one number and one uppercase letter!'; + } elseif ($newPassword !== $confirmPassword) { + $message = 'New passwords do not match!'; } else { - $message = "All fields are required!"; - $messageType = "danger"; - } -} + $database = getDatabaseConnection(); + try { + $username = $_SESSION['uname']; + $statement = $database->prepare('SELECT pswd FROM users WHERE uname = ?'); + $statement->bind_param('s', $username); + $statement->execute(); + $result = $statement->get_result(); + $user = $result->fetch_assoc(); + $result->free(); + $statement->close(); -function CheckPassword($password) { - if (strlen($password) < 8) { - return false; + if (!$user) { + $message = 'User not found!'; + } elseif (!password_verify($currentPassword, $user['pswd'])) { + $message = 'Current password is incorrect!'; + } else { + $passwordHash = password_hash($newPassword, PASSWORD_BCRYPT); + $statement = $database->prepare('UPDATE users SET pswd = ? WHERE uname = ?'); + $statement->bind_param('ss', $passwordHash, $username); + $statement->execute(); + $statement->close(); + $message = 'Password changed successfully!'; + $messageType = 'success'; + } + } catch (mysqli_sql_exception $exception) { + error_log($exception->getMessage()); + $message = 'Unable to change password. Please try again.'; + } finally { + $database->close(); + } } - if (!preg_match('/[0-9]/', $password)) { - return false; - } - if (!preg_match('/[A-Z]/', $password)) { - return false; - } - return true; } ?> diff --git a/Web/content/ftp/createdir.php b/Web/content/ftp/createdir.php index 7b06a96..5ab1688 100644 --- a/Web/content/ftp/createdir.php +++ b/Web/content/ftp/createdir.php @@ -1,15 +1,14 @@ mkdir($newDirPath)) { + if ($sftp->mkdir($newDirectoryPath)) { echo "Directory created successfully!"; } else { http_response_code(500); @@ -38,4 +38,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' http_response_code(400); echo "Invalid request"; -exit; \ No newline at end of file +exit; diff --git a/Web/content/ftp/createfile.php b/Web/content/ftp/createfile.php index 4cf6475..fc5ddf6 100644 --- a/Web/content/ftp/createfile.php +++ b/Web/content/ftp/createfile.php @@ -1,29 +1,14 @@ put($newFilePath, $tempFile)) { - @unlink($tempFile); - + $newFilePath = rtrim($currentPath, '/') . '/' . $fileName; + header('Content-Type: application/json; charset=UTF-8'); + if ($sftp->put($newFilePath, '')) { echo json_encode(['success' => true, 'filePath' => $newFilePath]); } else { - @unlink($tempFile); - http_response_code(500); echo json_encode(['success' => false, 'message' => 'Failed to create file.']); } @@ -65,4 +44,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' http_response_code(400); echo "Invalid request"; -exit; \ No newline at end of file +exit; diff --git a/Web/content/ftp/delete.php b/Web/content/ftp/delete.php index c5ce30f..9d3c889 100644 --- a/Web/content/ftp/delete.php +++ b/Web/content/ftp/delete.php @@ -1,26 +1,35 @@ is_dir($itemToDelete)) { function deleteFolder($sftp, $folderPath) { $items = $sftp->nlist($folderPath); + if ($items === false) return false; foreach ($items as $item) { if ($item === '.' || $item === '..') continue; $itemPath = $folderPath . '/' . $item; if ($sftp->is_dir($itemPath)) { - deleteFolder($sftp, $itemPath); + if (!deleteFolder($sftp, $itemPath)) return false; } else { - $sftp->delete($itemPath); + if (!$sftp->delete($itemPath)) return false; } } return $sftp->rmdir($folderPath); @@ -31,9 +40,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete'])) { $success = $sftp->delete($itemToDelete); } - header("Location: index.php?path=" . urlencode($parentDir)); + if (!$success) { + http_response_code(500); + exit('Failed to delete the item.'); + } + header("Location: index.php?path=" . urlencode($parentPath)); exit; } header("Location: index.php"); -exit; \ No newline at end of file +exit; diff --git a/Web/content/ftp/download.php b/Web/content/ftp/download.php index 539ec52..a5c557c 100644 --- a/Web/content/ftp/download.php +++ b/Web/content/ftp/download.php @@ -1,10 +1,10 @@ getMessage() . "\n", FILE_APPEND); - throw new Exception("Failed to connect to SFTP server: " . $e->getMessage()); + } catch (Exception $exception) { + file_put_contents($logFile, "SFTP connection failed: " . $exception->getMessage() . "\n", FILE_APPEND); + throw new Exception("Failed to connect to SFTP server: " . $exception->getMessage()); } - function zipFolderRecursive($sftp, $remoteBasePath, $currentPath, $zip, $logFile, &$tempFiles) { + function zipFolderRecursive($sftp, $remoteBasePath, $currentPath, $zip, $logFile, &$temporaryFiles) { file_put_contents($logFile, "Processing directory: $currentPath\n", FILE_APPEND); $files = $sftp->nlist($currentPath); @@ -35,36 +35,35 @@ try { file_put_contents($logFile, "Found " . count($files) . " items in $currentPath\n", FILE_APPEND); - foreach ($files as $file) { - if ($file == '.' || $file == '..') continue; + foreach ($files as $fileName) { + if ($fileName == '.' || $fileName == '..') continue; - $fullRemotePath = rtrim($currentPath, '/') . '/' . $file; + $remotePath = rtrim($currentPath, '/') . '/' . $fileName; - $baseDirName = basename($remoteBasePath); - $relPathFromBase = substr($fullRemotePath, strlen(rtrim(remoteDirname($remoteBasePath), '/')) + 1); - file_put_contents($logFile, "Processing: $fullRemotePath (relative: $relPathFromBase)\n", FILE_APPEND); + $relativePath = substr($remotePath, strlen(rtrim(remoteDirname($remoteBasePath), '/')) + 1); + file_put_contents($logFile, "Processing: $remotePath (relative: $relativePath)\n", FILE_APPEND); - $isDir = $sftp->is_dir($fullRemotePath); + $isDirectory = $sftp->is_dir($remotePath); - if ($isDir) { - file_put_contents($logFile, "Found subdirectory: $fullRemotePath\n", FILE_APPEND); - $zip->addEmptyDir($relPathFromBase); + if ($isDirectory) { + file_put_contents($logFile, "Found subdirectory: $remotePath\n", FILE_APPEND); + $zip->addEmptyDir($relativePath); - zipFolderRecursive($sftp, $remoteBasePath, $fullRemotePath, $zip, $logFile, $tempFiles); + zipFolderRecursive($sftp, $remoteBasePath, $remotePath, $zip, $logFile, $temporaryFiles); } else { - $localTempFile = tempnam(sys_get_temp_dir(), 'sftp'); - $tempFiles[] = $localTempFile; - file_put_contents($logFile, "Downloading to temp file: $localTempFile\n", FILE_APPEND); + $temporaryFile = tempnam(sys_get_temp_dir(), 'sftp'); + $temporaryFiles[] = $temporaryFile; + file_put_contents($logFile, "Downloading to temp file: $temporaryFile\n", FILE_APPEND); $downloadStart = time(); - $downloadSuccess = $sftp->get($fullRemotePath, $localTempFile); + $downloadSuccess = $sftp->get($remotePath, $temporaryFile); $downloadTime = time() - $downloadStart; if ($downloadSuccess) { - $fileSize = filesize($localTempFile); + $fileSize = filesize($temporaryFile); file_put_contents($logFile, "Download successful ($downloadTime seconds), size: $fileSize bytes\n", FILE_APPEND); - $zip->addFile($localTempFile, $relPathFromBase); + $zip->addFile($temporaryFile, $relativePath); } else { file_put_contents($logFile, "Failed to download file after $downloadTime seconds\n", FILE_APPEND); } @@ -83,17 +82,17 @@ try { } - $tempFiles = []; + $temporaryFiles = []; try { - zipFolderRecursive($sftp, $folderPath, $folderPath, $zip, $logFile, $tempFiles); + zipFolderRecursive($sftp, $folderPath, $folderPath, $zip, $logFile, $temporaryFiles); file_put_contents($logFile, "Closing zip file\n", FILE_APPEND); $zipSuccess = $zip->close(); - foreach ($tempFiles as $tempFile) { - if (file_exists($tempFile)) { - @unlink($tempFile); + foreach ($temporaryFiles as $temporaryFile) { + if (file_exists($temporaryFile)) { + @unlink($temporaryFile); } } @@ -104,39 +103,39 @@ try { file_put_contents($logFile, "Failed to create zip\n", FILE_APPEND); return false; } - } catch (Exception $e) { - foreach ($tempFiles as $tempFile) { - if (file_exists($tempFile)) { - @unlink($tempFile); + } catch (Exception $exception) { + foreach ($temporaryFiles as $temporaryFile) { + if (file_exists($temporaryFile)) { + @unlink($temporaryFile); } } - file_put_contents($logFile, "Error during zip creation: " . $e->getMessage() . "\n", FILE_APPEND); - throw $e; + file_put_contents($logFile, "Error during zip creation: " . $exception->getMessage() . "\n", FILE_APPEND); + throw $exception; } } if (($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['file'])) || ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['file']))) { - $file = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST['file'] : $_GET['file']; - file_put_contents($logFile, "Requested file: $file\n", FILE_APPEND); + $filePath = requireRemotePath($_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST['file'] : $_GET['file'], $defaultPath); + file_put_contents($logFile, "Requested file: $filePath\n", FILE_APPEND); - $fileExists = $sftp->file_exists($file); - $isDir = $sftp->is_dir($file); + $fileExists = $sftp->file_exists($filePath); + $isDirectory = $sftp->is_dir($filePath); file_put_contents($logFile, "File exists: " . ($fileExists ? "Yes" : "No") . "\n", FILE_APPEND); - file_put_contents($logFile, "Is directory: " . ($isDir ? "Yes" : "No") . "\n", FILE_APPEND); + file_put_contents($logFile, "Is directory: " . ($isDirectory ? "Yes" : "No") . "\n", FILE_APPEND); - if (!$fileExists && !$isDir) { - throw new Exception("File not found: $file"); + if (!$fileExists && !$isDirectory) { + throw new Exception("File not found: $filePath"); } - if ($isDir) { + if ($isDirectory) { $zipFilePath = tempnam(sys_get_temp_dir(), 'folder_') . '.zip'; file_put_contents($logFile, "Creating zip at: $zipFilePath\n", FILE_APPEND); - if (zipFolder($sftp, $file, $zipFilePath, $logFile)) { + if (zipFolder($sftp, $filePath, $zipFilePath, $logFile)) { if (file_exists($zipFilePath) && filesize($zipFilePath) > 0) { file_put_contents($logFile, "Sending zip file to browser, size: " . filesize($zipFilePath) . " bytes\n", FILE_APPEND); @@ -145,7 +144,7 @@ try { } header('Content-Type: application/zip'); - header('Content-Disposition: attachment; filename="' . basename($file) . '.zip"'); + header('Content-Disposition: attachment; filename="' . basename($filePath) . '.zip"'); header('Content-Length: ' . filesize($zipFilePath)); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); @@ -161,19 +160,19 @@ try { throw new Exception("Failed to create zip archive"); } } else { - $localFile = basename($file); - file_put_contents($logFile, "Downloading single file: $localFile\n", FILE_APPEND); + $fileName = basename($filePath); + file_put_contents($logFile, "Downloading single file: $fileName\n", FILE_APPEND); - $tempFile = tempnam(sys_get_temp_dir(), 'file_'); + $temporaryFile = tempnam(sys_get_temp_dir(), 'file_'); $downloadStart = time(); - $downloadSuccess = $sftp->get($file, $tempFile); + $downloadSuccess = $sftp->get($filePath, $temporaryFile); $downloadTime = time() - $downloadStart; file_put_contents($logFile, "Download " . ($downloadSuccess ? "successful" : "failed") . " ($downloadTime seconds)\n", FILE_APPEND); if ($downloadSuccess) { - $fileSize = filesize($tempFile); + $fileSize = filesize($temporaryFile); file_put_contents($logFile, "Downloaded file size: $fileSize bytes\n", FILE_APPEND); if ($fileSize > 0) { @@ -182,29 +181,29 @@ try { } header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="' . $localFile . '"'); + header('Content-Disposition: attachment; filename="' . $fileName . '"'); header('Content-Length: ' . $fileSize); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); - readfile($tempFile); + readfile($temporaryFile); file_put_contents($logFile, "Download completed\n", FILE_APPEND); - @unlink($tempFile); + @unlink($temporaryFile); exit; } else { - @unlink($tempFile); + @unlink($temporaryFile); throw new Exception("Downloaded file is empty"); } } else { - @unlink($tempFile); + @unlink($temporaryFile); throw new Exception("Failed to download file from SFTP server"); } } } else { throw new Exception("Invalid request method or missing file parameter"); } -} catch (Exception $e) { - $errorMessage = "Error: " . $e->getMessage(); +} catch (Exception $exception) { + $errorMessage = "Error: " . $exception->getMessage(); file_put_contents($logFile, $errorMessage . "\n", FILE_APPEND); while (ob_get_level()) { diff --git a/Web/content/ftp/extract.php b/Web/content/ftp/extract.php index f577316..91176e8 100644 --- a/Web/content/ftp/extract.php +++ b/Web/content/ftp/extract.php @@ -1,20 +1,7 @@ get($archivePath, $localArchivePath)) { - rmdir($tempDir); + rmdir($temporaryDirectory); die("Failed to download the archive"); } @@ -48,11 +35,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['archive'])) { // Determine the extraction method based on file extension switch (strtolower($extension)) { case 'zip': - $extractionSuccess = extractZip($localArchivePath, $tempDir); + $extractionSuccess = extractZip($localArchivePath, $temporaryDirectory); break; case 'rar': - $extractionSuccess = extractRar($localArchivePath, $tempDir); + $extractionSuccess = extractRar($localArchivePath, $temporaryDirectory); break; case 'tar': @@ -60,7 +47,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['archive'])) { case 'bz2': case 'xz': case '7z': - $extractionSuccess = extractArchive($localArchivePath, $tempDir); + $extractionSuccess = extractArchive($localArchivePath, $temporaryDirectory); break; default: @@ -69,20 +56,20 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['archive'])) { if ($extractionSuccess) { // Upload extracted files back to the server - uploadExtractedFiles($sftp, $tempDir, $dirPath); + uploadExtractedFiles($sftp, $temporaryDirectory, $directoryPath); // Clean up temporary directory - deleteDirectory($tempDir); + deleteDirectory($temporaryDirectory); // Redirect back to the file listing - header("Location: index.php?path=" . urlencode($dirPath)); + header("Location: index.php?path=" . urlencode($directoryPath)); exit; } else { die("Failed to extract the archive"); } - } catch (Exception $e) { - deleteDirectory($tempDir); - die("Error during extraction: " . $e->getMessage()); + } catch (Exception $exception) { + deleteDirectory($temporaryDirectory); + die("Error during extraction: " . $exception->getMessage()); } } else { header("Location: index.php"); @@ -140,7 +127,7 @@ function extractArchive($archivePath, $destination) { $command = ''; // Change to the destination directory - $currentDir = getcwd(); + $originalDirectory = getcwd(); chdir($destination); if (PHP_OS_FAMILY === 'Windows') { @@ -189,20 +176,20 @@ function extractArchive($archivePath, $destination) { exec($command, $output, $returnCode); // Change back to the original directory - chdir($currentDir); + chdir($originalDirectory); return $returnCode === 0; } // Upload extracted files back to the SFTP server -function uploadExtractedFiles($sftp, $localDir, $remoteDir) { - $items = scandir($localDir); +function uploadExtractedFiles($sftp, $localDirectory, $remoteDirectory) { + $items = scandir($localDirectory); foreach ($items as $item) { if ($item === '.' || $item === '..') continue; - $localPath = $localDir . '/' . $item; - $remotePath = $remoteDir . '/' . $item; + $localPath = $localDirectory . '/' . $item; + $remotePath = $remoteDirectory . '/' . $item; if (is_dir($localPath)) { // Create the directory on the remote server diff --git a/Web/content/ftp/index.php b/Web/content/ftp/index.php index 6f548e5..75f424d 100644 --- a/Web/content/ftp/index.php +++ b/Web/content/ftp/index.php @@ -1,38 +1,31 @@ chdir($currentPath)) { + die("Failed to navigate to the selected folder: $currentPath"); +} - $defaultPath = normalizePath($defaultPath); - $currentPath = isset($_GET['path']) ? normalizePath($_GET['path']) : $defaultPath; - if ($currentPath !== $defaultPath && strpos($currentPath, rtrim($defaultPath, '/') . '/') !== 0) { - $currentPath = $defaultPath; - } +$items = $sftp->nlist(); +if ($items === false) { + http_response_code(500); + exit('Failed to list directory contents.'); +} - if (!$sftp->chdir($currentPath)) { - die("Failed to navigate to the selected folder: $currentPath"); - } - - $items = $sftp->nlist(); - - $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']; - $videoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv']; - $audioExtensions = ['mp3', 'wav', 'm4a', 'flac', 'aac']; - $editableExtensions = ['txt', 'html', 'css', 'js', 'php', 'xml', 'json', 'md', 'csv', 'log', 'ini', 'conf', 'sh', 'bat', 'py', 'rb', 'java', 'c', 'cpp', 'h', 'hpp']; - $archiveExtensions = ['zip', 'rar', 'tar', 'gz', '7z', 'bz2', 'xz', 'tar.gz', 'tar.bz2', 'tar.xz']; +$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']; +$videoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv']; +$audioExtensions = ['mp3', 'wav', 'm4a', 'flac', 'aac']; +$editableExtensions = ['txt', 'html', 'css', 'js', 'php', 'xml', 'json', 'md', 'csv', 'log', 'ini', 'conf', 'sh', 'bat', 'py', 'rb', 'java', 'c', 'cpp', 'h', 'hpp']; +$archiveExtensions = ['zip', 'rar', 'tar', 'gz', '7z', 'bz2', 'xz', 'tar.gz', 'tar.bz2', 'tar.xz']; ?> @@ -67,7 +60,7 @@
- + @@ -154,7 +147,7 @@ - +
Drop files or folders hereOr use the upload buttons to browse your device
@@ -198,20 +191,20 @@ — - +
- +
- + @@ -221,8 +214,8 @@ foreach ($files as $file) : ?> - + @@ -265,23 +258,23 @@ stat(rtrim($currentPath, '/') . '/' . $file)['size']) ?> - +
- +
- + - +
diff --git a/Web/content/ftp/open.php b/Web/content/ftp/open.php index 4a2fe58..99cdb60 100644 --- a/Web/content/ftp/open.php +++ b/Web/content/ftp/open.php @@ -1,22 +1,12 @@ file_exists($filePath) && !$sftp->is_dir($filePa if (in_array(strtolower($extension), $editableExtensions)) { $editable = true; - if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && isset($_SESSION["upPer"]) && $_SESSION["upPer"] == true) { + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && hasPermission('upPer')) { $newContent = $_POST['content']; if ($sftp->put($filePath, $newContent)) { @@ -52,7 +42,7 @@ if (!empty($filePath) && $sftp->file_exists($filePath) && !$sftp->is_dir($filePa $showLineNumbers = in_array(strtolower($extension), ['php', 'js', 'html', 'css', 'py', 'java', 'c', 'cpp', 'h', 'hpp', 'rb', 'sh', 'xml', 'json']); -$parentDir = remoteDirname($filePath); +$parentPath = remoteDirname($filePath); ?> @@ -75,7 +65,7 @@ $parentDir = remoteDirname($filePath); 'title' => $fileName, 'description' => 'View and edit text files in your remote workspace.', 'connected' => true, - 'back' => 'index.php?path=' . urlencode($parentDir), + 'back' => 'index.php?path=' . urlencode($parentPath), 'class' => 'editor-page', ]); ?>
@@ -94,7 +84,7 @@ $parentDir = remoteDirname($filePath);
- + Read-only mode (you don't have upload permissions)
@@ -102,11 +92,11 @@ $parentDir = remoteDirname($filePath);
- +
- +
diff --git a/Web/content/ftp/pdf.php b/Web/content/ftp/pdf.php index 2e256e2..6791247 100644 --- a/Web/content/ftp/pdf.php +++ b/Web/content/ftp/pdf.php @@ -1,11 +1,6 @@ stat($filePath)['size']; @@ -105,8 +100,8 @@ if (isset($_GET['stream'])) { break; } } - } catch (Exception $e) { - error_log("Streaming error: " . $e->getMessage()); + } catch (Exception $exception) { + error_log("Streaming error: " . $exception->getMessage()); } exit; } @@ -138,7 +133,6 @@ if (isset($_GET['stream'])) { 'class' => 'pdf-page', ]); ?> -
@@ -166,7 +160,7 @@ if (isset($_GET['stream'])) {
- + Download
diff --git a/Web/content/ftp/rename.php b/Web/content/ftp/rename.php index b44d93f..e6d66a5 100644 --- a/Web/content/ftp/rename.php +++ b/Web/content/ftp/rename.php @@ -1,18 +1,7 @@ file_exists($newPath) || $sftp->is_dir($newPath)) { die("Error: A file or directory with this name already exists."); } if ($sftp->rename($oldPath, $newPath)) { - header("Location: index.php?path=" . urlencode($dirPath)); + header("Location: index.php?path=" . urlencode($directoryPath)); exit; } else { die("Failed to rename the item. Please try again."); @@ -45,4 +37,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { header("Location: index.php"); exit; } -?> \ No newline at end of file +?> diff --git a/Web/content/ftp/serverstat.php b/Web/content/ftp/serverstat.php index ca5ee0f..67d6813 100644 --- a/Web/content/ftp/serverstat.php +++ b/Web/content/ftp/serverstat.php @@ -1,16 +1,8 @@ 'server-page', ]); ?> -

Live statistics · refreshes every 5 seconds

diff --git a/Web/content/ftp/shared.php b/Web/content/ftp/shared.php index 9f08bba..f424e70 100644 --- a/Web/content/ftp/shared.php +++ b/Web/content/ftp/shared.php @@ -1,26 +1,19 @@ prepare("SELECT * FROM share WHERE token = ? AND expiration > NOW()"); -$stmt->bind_param("s", $token); -$stmt->execute(); -$result = $stmt->get_result(); +$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."); @@ -29,7 +22,9 @@ if ($result->num_rows === 0) { $share = $result->fetch_assoc(); $filePath = $share['file_path']; $downloadAllowed = $share['download_allowed'] == 1; -$stmt->close(); +$result->free(); +$statement->close(); +$database->close(); // Initialize SFTP $sftp = initializeSFTP(); @@ -42,13 +37,13 @@ $fileName = basename($filePath); $fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $fileSize = $sftp->stat($filePath)['size']; -$imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']; -$videoTypes = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv']; -$audioTypes = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac']; +$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, $imageTypes); -$isVideo = in_array($fileExtension, $videoTypes); -$isAudio = in_array($fileExtension, $audioTypes); +$isImage = in_array($fileExtension, $imageExtensions); +$isVideo = in_array($fileExtension, $videoExtensions); +$isAudio = in_array($fileExtension, $audioExtensions); if (!$isImage && !$isVideo && !$isAudio) { die("Unsupported file type"); @@ -165,8 +160,8 @@ if (isset($_GET['stream'])) { usleep(100000); } - } catch (Exception $e) { - error_log("Shared streaming error: " . $e->getMessage()); + } catch (Exception $exception) { + error_log("Shared streaming error: " . $exception->getMessage()); } exit; } @@ -242,7 +237,6 @@ function formatBytes($bytes, $precision = 2) { 'class' => 'media-page', ]); ?> -
Shared link

Available until

@@ -293,8 +287,6 @@ function formatBytes($bytes, $precision = 2) { - - - \ No newline at end of file + diff --git a/Web/content/ftp/upload.php b/Web/content/ftp/upload.php index a8d37f4..ec30025 100644 --- a/Web/content/ftp/upload.php +++ b/Web/content/ftp/upload.php @@ -1,130 +1,85 @@ is_dir($directoryPath) && !$sftp->mkdir($directoryPath, 0755, true)) { + http_response_code(500); + exit('Failed to create upload directory.'); + } + } } -function createDirectoryRecursive($sftp, $path) { - if ($sftp->is_dir($path)) { - return true; - } - - $parent = remoteDirname($path); - if ($parent != '/' && !$sftp->is_dir($parent)) { - createDirectoryRecursive($sftp, $parent); - } - - return $sftp->mkdir($path, 0755); +$uploadedFiles = $_FILES['files'] ?? null; +if (!$uploadedFiles || empty($uploadedFiles['name'][0])) { + http_response_code(400); + exit('No files received or file size exceeds PHP limits.'); } -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_POST['create_dirs'])) { - $directories = json_decode($_POST['create_dirs'], true); - - if (is_array($directories)) { - foreach ($directories as $dir) { - $remoteDirPath = $currentPath . '/' . $dir; - createDirectoryRecursive($sftp, $remoteDirPath); - } - } +$uploadErrors = [ + UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize directive in php.ini', + UPLOAD_ERR_FORM_SIZE => 'File exceeds MAX_FILE_SIZE directive in the HTML form', + UPLOAD_ERR_PARTIAL => 'File was only partially uploaded', + UPLOAD_ERR_NO_FILE => 'No file was uploaded', + UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder', + UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', + UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload', +]; +$uploadMessages = []; +$anySuccess = false; +$failureStatus = 500; + +foreach ($uploadedFiles['tmp_name'] as $index => $temporaryPath) { + $fileName = $uploadedFiles['name'][$index]; + $relativePath = $_POST['paths'][$index] ?? ''; + $uploadError = $uploadedFiles['error'][$index]; + if ($uploadError !== UPLOAD_ERR_OK) { + $failureStatus = 400; + $uploadMessages[] = $fileName . ': ' . ($uploadErrors[$uploadError] ?? 'Unknown upload error'); + continue; } - - if (!isset($_FILES['files']) || empty($_FILES['files']['name'][0])) { - echo "No files received or file size exceeds PHP limits."; + + $remotePath = requireRemotePath(rtrim($currentPath, '/') . '/' . ($relativePath !== '' ? $relativePath : $fileName), $currentPath); + if ($remotePath === $currentPath) { http_response_code(400); - exit; + exit('Invalid upload path.'); } - - if ($_FILES['files']['error'][0] !== 0) { - $error = $_FILES['files']['error'][0]; - $errorMessage = "Upload error code: $error"; - - switch ($error) { - case UPLOAD_ERR_INI_SIZE: - $errorMessage = "File exceeds upload_max_filesize directive in php.ini"; - break; - case UPLOAD_ERR_FORM_SIZE: - $errorMessage = "File exceeds MAX_FILE_SIZE directive in the HTML form"; - break; - case UPLOAD_ERR_PARTIAL: - $errorMessage = "File was only partially uploaded"; - break; - case UPLOAD_ERR_NO_FILE: - $errorMessage = "No file was uploaded"; - break; - case UPLOAD_ERR_NO_TMP_DIR: - $errorMessage = "Missing a temporary folder"; - break; - case UPLOAD_ERR_CANT_WRITE: - $errorMessage = "Failed to write file to disk"; - break; - case UPLOAD_ERR_EXTENSION: - $errorMessage = "A PHP extension stopped the file upload"; - break; - } - - echo $errorMessage; - http_response_code(400); - exit; + $directoryPath = remoteDirname($remotePath); + if (!$sftp->is_dir($directoryPath) && !$sftp->mkdir($directoryPath, 0755, true)) { + $uploadMessages[] = 'Failed to create directory for: ' . $fileName; + continue; } - $uploadStatus = array(); - $anySuccess = false; - - foreach ($_FILES['files']['tmp_name'] as $index => $tmpName) { - if (empty($tmpName)) continue; - - $fileName = $_FILES['files']['name'][$index]; - $relativePath = isset($_POST['paths']) && isset($_POST['paths'][$index]) ? $_POST['paths'][$index] : ''; - - if (!empty($relativePath)) { - $fileName = basename($relativePath); - - $dirPart = remoteDirname($relativePath); - if ($dirPart !== '.' && $dirPart !== '') { - $remoteDirPath = $currentPath . '/' . $dirPart; - - if (!$sftp->is_dir($remoteDirPath)) { - createDirectoryRecursive($sftp, $remoteDirPath); - } - - $remotePath = $remoteDirPath . '/' . $fileName; - } else { - $remotePath = $currentPath . '/' . $fileName; - } - } else { - $remotePath = $currentPath . '/' . $fileName; - } - - if ($sftp->put($remotePath, $tmpName, SFTP::SOURCE_LOCAL_FILE)) { - $uploadStatus[] = "Uploaded: " . ($relativePath ? $relativePath : $fileName); - $anySuccess = true; - } else { - $uploadStatus[] = "Failed to upload: " . ($relativePath ? $relativePath : $fileName); - } - } - - if ($anySuccess) { - echo implode("\n", $uploadStatus); - exit; + if ($sftp->put($remotePath, $temporaryPath, SFTP::SOURCE_LOCAL_FILE)) { + $uploadMessages[] = 'Uploaded: ' . ($relativePath !== '' ? $relativePath : $fileName); + $anySuccess = true; } else { - echo "Failed to upload any files. Please check SFTP connection and permissions."; - http_response_code(500); - exit; + $uploadMessages[] = 'Failed to upload: ' . ($relativePath !== '' ? $relativePath : $fileName); } } -echo "No files received or invalid request."; -http_response_code(400); -exit; \ No newline at end of file +if (!$anySuccess) { + http_response_code($failureStatus); +} +header('Content-Type: text/plain; charset=UTF-8'); +echo implode("\n", $uploadMessages); diff --git a/Web/content/ftp/view.php b/Web/content/ftp/view.php index bb4cc3f..7be8a8f 100644 --- a/Web/content/ftp/view.php +++ b/Web/content/ftp/view.php @@ -1,16 +1,7 @@ prepare("INSERT INTO share (token, file_path, expiration, download_allowed) VALUES (?, ?, ?, ?)"); - $stmt->bind_param("sssi", $token, $filePath, $expiration, $downloadAllowed); + $database = getDatabaseConnection(); + $statement = $database->prepare("INSERT INTO share (token, file_path, expiration, download_allowed) VALUES (?, ?, ?, ?)"); + $statement->bind_param("sssi", $token, $filePath, $expiration, $downloadAllowed); - if ($stmt->execute()) { + $shareSaved = $statement->execute(); + $statement->close(); + $database->close(); + + if ($shareSaved) { $shareUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . remoteDirname($_SERVER['PHP_SELF']) . "/shared.php?token=$token"; @@ -47,13 +42,11 @@ if (isset($_POST['createShare'])) { header("Location: view.php?file=" . urlencode($filePath) . "&shared=1"); exit; } else { - $_SESSION['shareError'] = "Failed to create share: " . $conn->error; + $_SESSION['shareError'] = 'Failed to create share. Please try again.'; header("Location: view.php?file=" . urlencode($filePath) . "&shared=0"); exit; } - $stmt->close(); - $conn->close(); } $shareCreated = false; @@ -71,7 +64,7 @@ if (isset($_GET['shared'])) { } } -$filePath = $_GET['file']; +$filePath = requireRemotePath($_GET['file'], $defaultPath); $fileName = basename($filePath); $fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); @@ -79,13 +72,13 @@ if (!$sftp->stat($filePath)) { die("File not found: $filePath"); } -$imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']; -$videoTypes = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv']; -$audioTypes = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac']; +$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, $imageTypes); -$isVideo = in_array($fileExtension, $videoTypes); -$isAudio = in_array($fileExtension, $audioTypes); +$isImage = in_array($fileExtension, $imageExtensions); +$isVideo = in_array($fileExtension, $videoExtensions); +$isAudio = in_array($fileExtension, $audioExtensions); if (!$isImage && !$isVideo && !$isAudio) { die("Unsupported file type"); @@ -238,10 +231,10 @@ if (isset($_GET['stream'])) { // Throttle to prevent CPU overload usleep(100000); // 100ms } - } catch (Exception $e) { - error_log("Streaming error: " . $e->getMessage()); + } catch (Exception $exception) { + error_log("Streaming error: " . $exception->getMessage()); if (isset($_GET['debug'])) { - header("X-Stream-Error: " . $e->getMessage()); + header("X-Stream-Error: " . $exception->getMessage()); } } @@ -252,7 +245,6 @@ if (isset($_GET['stream'])) { } ?> - @@ -278,7 +270,6 @@ if (isset($_GET['stream'])) { 'class' => 'media-page', ]); ?> -
@@ -301,7 +292,7 @@ if (isset($_GET['stream'])) { - + Download @@ -412,8 +403,6 @@ function copyShareUrl() { } - -