Force resumable chunk size & fix chunk cleanup
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
- Fix Gallery View: medium screen devices get 3 max columns and small screen devices 2 max columns.
|
- Fix Gallery View: medium screen devices get 3 max columns and small screen devices 2 max columns.
|
||||||
- Ensure gallery view toggle button displays after refresh page.
|
- Ensure gallery view toggle button displays after refresh page.
|
||||||
|
- Force resumable chunk size & fix chunk cleanup
|
||||||
|
|
||||||
### filePreview.js Enhancements
|
### filePreview.js Enhancements
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ function initResumableUpload() {
|
|||||||
query: { folder: window.currentFolder || "root", upload_token: window.csrfToken },
|
query: { folder: window.currentFolder || "root", upload_token: window.csrfToken },
|
||||||
chunkSize: 1.5 * 1024 * 1024, // 1.5 MB chunks
|
chunkSize: 1.5 * 1024 * 1024, // 1.5 MB chunks
|
||||||
simultaneousUploads: 3,
|
simultaneousUploads: 3,
|
||||||
|
forceChunkSize: true,
|
||||||
testChunks: false,
|
testChunks: false,
|
||||||
throttleProgressCallbacks: 1,
|
throttleProgressCallbacks: 1,
|
||||||
headers: { "X-CSRF-Token": window.csrfToken }
|
headers: { "X-CSRF-Token": window.csrfToken }
|
||||||
|
|||||||
@@ -2,63 +2,52 @@
|
|||||||
require_once 'config.php';
|
require_once 'config.php';
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
// Validate CSRF token from POST
|
|
||||||
$receivedToken = isset($_POST['csrf_token']) ? trim($_POST['csrf_token']) : '';
|
$receivedToken = isset($_POST['csrf_token']) ? trim($_POST['csrf_token']) : '';
|
||||||
if ($receivedToken !== $_SESSION['csrf_token']) {
|
if ($receivedToken !== $_SESSION['csrf_token']) {
|
||||||
echo json_encode(["error" => "Invalid CSRF token"]);
|
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
|
echo json_encode(["error" => "Invalid CSRF token"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure a folder parameter is provided
|
|
||||||
if (!isset($_POST['folder'])) {
|
if (!isset($_POST['folder'])) {
|
||||||
echo json_encode(["error" => "No folder specified"]);
|
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "No folder specified"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$folder = urldecode($_POST['folder']);
|
$folder = urldecode($_POST['folder']);
|
||||||
$regex = "/^resumable_" . PATTERN_FOLDER_NAME . "$/u"; // full regex pattern
|
// The folder name should match the "resumable_" pattern exactly.
|
||||||
|
$regex = "/^resumable_" . PATTERN_FOLDER_NAME . "$/u";
|
||||||
if (!preg_match($regex, $folder)) {
|
if (!preg_match($regex, $folder)) {
|
||||||
echo json_encode(["error" => "Invalid folder name"]);
|
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Invalid folder name"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tempDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder;
|
$tempDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder;
|
||||||
|
|
||||||
// If the folder doesn't exist, simply return success.
|
|
||||||
if (!is_dir($tempDir)) {
|
if (!is_dir($tempDir)) {
|
||||||
echo json_encode(["success" => true, "message" => "Temporary folder already removed."]);
|
echo json_encode(["success" => true, "message" => "Temporary folder already removed."]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively delete directory using RecursiveDirectoryIterator
|
|
||||||
function rrmdir($dir) {
|
function rrmdir($dir) {
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
$it = new RecursiveIteratorIterator(
|
$it = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
|
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
|
||||||
RecursiveIteratorIterator::CHILD_FIRST
|
RecursiveIteratorIterator::CHILD_FIRST
|
||||||
);
|
);
|
||||||
foreach ($it as $file) {
|
foreach ($it as $file) {
|
||||||
if ($file->isDir()){
|
$file->isDir() ? rmdir($file->getRealPath()) : unlink($file->getRealPath());
|
||||||
rmdir($file->getRealPath());
|
|
||||||
} else {
|
|
||||||
unlink($file->getRealPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rmdir($dir);
|
rmdir($dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
rrmdir($tempDir);
|
rrmdir($tempDir);
|
||||||
|
|
||||||
// Verify removal
|
|
||||||
if (!is_dir($tempDir)) {
|
if (!is_dir($tempDir)) {
|
||||||
echo json_encode(["success" => true, "message" => "Temporary folder removed."]);
|
echo json_encode(["success" => true, "message" => "Temporary folder removed."]);
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(["error" => "Failed to remove temporary folder."]);
|
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Failed to remove temporary folder."]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
199
upload.php
199
upload.php
@@ -7,48 +7,43 @@ $headers = array_change_key_case(getallheaders(), CASE_LOWER);
|
|||||||
$receivedToken = isset($headers['x-csrf-token']) ? trim($headers['x-csrf-token']) : '';
|
$receivedToken = isset($headers['x-csrf-token']) ? trim($headers['x-csrf-token']) : '';
|
||||||
|
|
||||||
if ($receivedToken !== $_SESSION['csrf_token']) {
|
if ($receivedToken !== $_SESSION['csrf_token']) {
|
||||||
echo json_encode(["error" => "Invalid CSRF token"]);
|
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
|
echo json_encode(["error" => "Invalid CSRF token"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure user is authenticated.
|
// Ensure user is authenticated.
|
||||||
if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) {
|
if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) {
|
||||||
echo json_encode(["error" => "Unauthorized"]);
|
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
|
echo json_encode(["error" => "Unauthorized"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$username = $_SESSION['username'] ?? '';
|
$username = $_SESSION['username'] ?? '';
|
||||||
if ($username) {
|
if ($username) {
|
||||||
$userPermissions = loadUserPermissions($username);
|
$userPermissions = loadUserPermissions($username);
|
||||||
if (isset($userPermissions['disableUpload']) && $userPermissions['disableUpload'] === true) {
|
if (!empty($userPermissions['disableUpload'])) {
|
||||||
http_response_code(403); // Return a 403 Forbidden status.
|
http_response_code(403);
|
||||||
echo json_encode(["error" => "Disabled upload users are not allowed to upload."]);
|
echo json_encode(["error" => "Upload disabled for this user."]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle test chunk requests.
|
* Handle test chunk requests.
|
||||||
* When testChunks is enabled in Resumable.js, the client sends GET requests with a "resumableTest" parameter.
|
|
||||||
*/
|
*/
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['resumableTest'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['resumableTest'])) {
|
||||||
$chunkNumber = intval($_GET['resumableChunkNumber']);
|
$chunkNumber = intval($_GET['resumableChunkNumber']);
|
||||||
$resumableIdentifier = $_GET['resumableIdentifier'];
|
$resumableIdentifier = $_GET['resumableIdentifier'] ?? '';
|
||||||
$folder = isset($_GET['folder']) ? trim($_GET['folder']) : 'root';
|
$folder = isset($_GET['folder']) ? trim($_GET['folder']) : 'root';
|
||||||
// Determine the base upload directory.
|
|
||||||
$baseUploadDir = UPLOAD_DIR;
|
$baseUploadDir = UPLOAD_DIR;
|
||||||
if ($folder !== 'root') {
|
if ($folder !== 'root') {
|
||||||
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
||||||
}
|
}
|
||||||
$tempDir = $baseUploadDir . 'resumable_' . $resumableIdentifier . DIRECTORY_SEPARATOR;
|
$tempDir = $baseUploadDir . 'resumable_' . $resumableIdentifier . DIRECTORY_SEPARATOR;
|
||||||
$chunkFile = $tempDir . $chunkNumber;
|
$chunkFile = $tempDir . $chunkNumber;
|
||||||
if (file_exists($chunkFile)) {
|
echo json_encode(["status" => file_exists($chunkFile) ? "found" : "not found"]);
|
||||||
http_response_code(200);
|
http_response_code(file_exists($chunkFile) ? 200 : 404);
|
||||||
} else {
|
|
||||||
http_response_code(404);
|
|
||||||
}
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,73 +51,91 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['resumableTest'])) {
|
|||||||
// Chunked upload handling (POST requests)
|
// Chunked upload handling (POST requests)
|
||||||
// ---------------------
|
// ---------------------
|
||||||
if (isset($_POST['resumableChunkNumber'])) {
|
if (isset($_POST['resumableChunkNumber'])) {
|
||||||
// ------------- Chunked Upload Handling -------------
|
$chunkNumber = intval($_POST['resumableChunkNumber']);
|
||||||
$chunkNumber = intval($_POST['resumableChunkNumber']); // current chunk (1-indexed)
|
|
||||||
$totalChunks = intval($_POST['resumableTotalChunks']);
|
$totalChunks = intval($_POST['resumableTotalChunks']);
|
||||||
$chunkSize = intval($_POST['resumableChunkSize']);
|
$chunkSize = intval($_POST['resumableChunkSize']);
|
||||||
$totalSize = intval($_POST['resumableTotalSize']);
|
$totalSize = intval($_POST['resumableTotalSize']);
|
||||||
$resumableIdentifier = $_POST['resumableIdentifier']; // unique file identifier
|
$resumableIdentifier = $_POST['resumableIdentifier'] ?? '';
|
||||||
$resumableFilename = $_POST['resumableFilename'];
|
$resumableFilename = urldecode(basename($_POST['resumableFilename']));
|
||||||
|
|
||||||
|
if (!preg_match(REGEX_FILE_NAME, $resumableFilename)) {
|
||||||
// First, strip directory components.
|
http_response_code(400);
|
||||||
$resumableFilename = urldecode(basename($_POST['resumableFilename']));
|
echo json_encode(["error" => "Invalid file name: $resumableFilename"]);
|
||||||
if (!preg_match(REGEX_FILE_NAME, $resumableFilename)) {
|
exit;
|
||||||
http_response_code(400);
|
}
|
||||||
echo json_encode(["error" => "Invalid file name: " . $resumableFilename]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$folder = isset($_POST['folder']) ? trim($_POST['folder']) : 'root';
|
$folder = isset($_POST['folder']) ? trim($_POST['folder']) : 'root';
|
||||||
if ($folder !== 'root' && !preg_match(REGEX_FOLDER_NAME, $folder)) {
|
if ($folder !== 'root' && !preg_match(REGEX_FOLDER_NAME, $folder)) {
|
||||||
|
http_response_code(400);
|
||||||
echo json_encode(["error" => "Invalid folder name"]);
|
echo json_encode(["error" => "Invalid folder name"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the base upload directory.
|
// Determine the base upload directory.
|
||||||
$baseUploadDir = UPLOAD_DIR;
|
$baseUploadDir = UPLOAD_DIR;
|
||||||
if ($folder !== 'root') {
|
if ($folder !== 'root') {
|
||||||
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
||||||
if (!is_dir($baseUploadDir)) {
|
}
|
||||||
mkdir($baseUploadDir, 0775, true);
|
if (!is_dir($baseUploadDir) && !mkdir($baseUploadDir, 0775, true)) {
|
||||||
}
|
http_response_code(500);
|
||||||
} else {
|
echo json_encode(["error" => "Failed to create upload directory"]);
|
||||||
if (!is_dir($baseUploadDir)) {
|
exit;
|
||||||
mkdir($baseUploadDir, 0775, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a temporary directory for the chunks.
|
// Use a temporary directory for the chunks.
|
||||||
$tempDir = $baseUploadDir . 'resumable_' . $resumableIdentifier . DIRECTORY_SEPARATOR;
|
$tempDir = $baseUploadDir . 'resumable_' . $resumableIdentifier . DIRECTORY_SEPARATOR;
|
||||||
if (!is_dir($tempDir)) {
|
if (!is_dir($tempDir) && !mkdir($tempDir, 0775, true)) {
|
||||||
mkdir($tempDir, 0775, true);
|
http_response_code(500);
|
||||||
}
|
echo json_encode(["error" => "Failed to create temporary chunk directory"]);
|
||||||
|
|
||||||
// Save the current chunk.
|
|
||||||
$chunkFile = $tempDir . $chunkNumber; // store chunk using its number as filename
|
|
||||||
if (!move_uploaded_file($_FILES["file"]["tmp_name"], $chunkFile)) {
|
|
||||||
echo json_encode(["error" => "Failed to move uploaded chunk"]);
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if all chunks have been uploaded.
|
// Ensure there is no PHP upload error.
|
||||||
$uploadedChunks = glob($tempDir . "*");
|
if (!isset($_FILES["file"]) || $_FILES["file"]["error"] !== UPLOAD_ERR_OK) {
|
||||||
if (count($uploadedChunks) < $totalChunks) {
|
http_response_code(400);
|
||||||
// More chunks remain – respond and let the client continue.
|
echo json_encode(["error" => "Upload error on chunk $chunkNumber"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the current chunk.
|
||||||
|
$chunkFile = $tempDir . $chunkNumber;
|
||||||
|
if (!move_uploaded_file($_FILES["file"]["tmp_name"], $chunkFile)) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Failed to move uploaded chunk $chunkNumber"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all chunks have been uploaded by verifying each expected chunk.
|
||||||
|
$allChunksPresent = true;
|
||||||
|
for ($i = 1; $i <= $totalChunks; $i++) {
|
||||||
|
if (!file_exists($tempDir . $i)) {
|
||||||
|
$allChunksPresent = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$allChunksPresent) {
|
||||||
echo json_encode(["status" => "chunk uploaded"]);
|
echo json_encode(["status" => "chunk uploaded"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All chunks are present. Merge chunks.
|
// All chunks are present. Merge the chunks.
|
||||||
$targetPath = $baseUploadDir . $resumableFilename;
|
$targetPath = $baseUploadDir . $resumableFilename;
|
||||||
if (!$out = fopen($targetPath, "wb")) {
|
if (!$out = fopen($targetPath, "wb")) {
|
||||||
|
http_response_code(500);
|
||||||
echo json_encode(["error" => "Failed to open target file for writing"]);
|
echo json_encode(["error" => "Failed to open target file for writing"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
// Concatenate each chunk in order.
|
|
||||||
for ($i = 1; $i <= $totalChunks; $i++) {
|
for ($i = 1; $i <= $totalChunks; $i++) {
|
||||||
$chunkPath = $tempDir . $i;
|
$chunkPath = $tempDir . $i;
|
||||||
|
if (!file_exists($chunkPath)) {
|
||||||
|
fclose($out);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Chunk $i missing during merge"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
if (!$in = fopen($chunkPath, "rb")) {
|
if (!$in = fopen($chunkPath, "rb")) {
|
||||||
fclose($out);
|
fclose($out);
|
||||||
|
http_response_code(500);
|
||||||
echo json_encode(["error" => "Failed to open chunk $i"]);
|
echo json_encode(["error" => "Failed to open chunk $i"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -134,27 +147,17 @@ if (!preg_match(REGEX_FILE_NAME, $resumableFilename)) {
|
|||||||
fclose($out);
|
fclose($out);
|
||||||
|
|
||||||
// --- Metadata Update for Chunked Upload ---
|
// --- Metadata Update for Chunked Upload ---
|
||||||
// For chunked uploads, assume no relativePath; so folderPath is simply $folder.
|
|
||||||
$folderPath = $folder;
|
$folderPath = $folder;
|
||||||
$metadataKey = ($folderPath === '' || $folderPath === 'root') ? "root" : $folderPath;
|
$metadataKey = ($folderPath === '' || $folderPath === 'root') ? "root" : $folderPath;
|
||||||
// Generate a metadata file name based on the folder path.
|
|
||||||
$metadataFileName = str_replace(['/', '\\', ' '], '-', $metadataKey) . '_metadata.json';
|
$metadataFileName = str_replace(['/', '\\', ' '], '-', $metadataKey) . '_metadata.json';
|
||||||
$metadataFile = META_DIR . $metadataFileName;
|
$metadataFile = META_DIR . $metadataFileName;
|
||||||
|
|
||||||
$uploadedDate = date(DATE_TIME_FORMAT);
|
$uploadedDate = date(DATE_TIME_FORMAT);
|
||||||
$uploader = $_SESSION['username'] ?? "Unknown";
|
$uploader = $_SESSION['username'] ?? "Unknown";
|
||||||
|
|
||||||
// Load existing metadata, if any.
|
$metadataCollection = file_exists($metadataFile) ? json_decode(file_get_contents($metadataFile), true) : [];
|
||||||
if (file_exists($metadataFile)) {
|
if (!is_array($metadataCollection)) {
|
||||||
$metadataCollection = json_decode(file_get_contents($metadataFile), true);
|
|
||||||
if (!is_array($metadataCollection)) {
|
|
||||||
$metadataCollection = [];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$metadataCollection = [];
|
$metadataCollection = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add metadata for this file if not already present.
|
|
||||||
if (!isset($metadataCollection[$resumableFilename])) {
|
if (!isset($metadataCollection[$resumableFilename])) {
|
||||||
$metadataCollection[$resumableFilename] = [
|
$metadataCollection[$resumableFilename] = [
|
||||||
"uploaded" => $uploadedDate,
|
"uploaded" => $uploadedDate,
|
||||||
@@ -164,97 +167,83 @@ if (!preg_match(REGEX_FILE_NAME, $resumableFilename)) {
|
|||||||
}
|
}
|
||||||
// --- End Metadata Update ---
|
// --- End Metadata Update ---
|
||||||
|
|
||||||
// Cleanup: remove the temporary directory and its chunks.
|
// Cleanup: use a robust recursive function.
|
||||||
array_map('unlink', glob("$tempDir*"));
|
function rrmdir($dir) {
|
||||||
rmdir($tempDir);
|
if (!is_dir($dir)) return;
|
||||||
|
$items = new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
|
||||||
|
RecursiveIteratorIterator::CHILD_FIRST
|
||||||
|
);
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$item->isDir() ? rmdir($item->getRealPath()) : unlink($item->getRealPath());
|
||||||
|
}
|
||||||
|
rmdir($dir);
|
||||||
|
}
|
||||||
|
rrmdir($tempDir);
|
||||||
|
|
||||||
echo json_encode(["success" => "File uploaded successfully"]);
|
echo json_encode(["success" => "File uploaded successfully"]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// ------------- Full Upload (Non-chunked) -------------
|
// ------------- Full Upload (Non-chunked) -------------
|
||||||
// Validate folder name input.
|
|
||||||
$folder = isset($_POST['folder']) ? trim($_POST['folder']) : 'root';
|
$folder = isset($_POST['folder']) ? trim($_POST['folder']) : 'root';
|
||||||
if ($folder !== 'root' && !preg_match(REGEX_FOLDER_NAME, $folder)) {
|
if ($folder !== 'root' && !preg_match(REGEX_FOLDER_NAME, $folder)) {
|
||||||
|
http_response_code(400);
|
||||||
echo json_encode(["error" => "Invalid folder name"]);
|
echo json_encode(["error" => "Invalid folder name"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the base upload directory.
|
|
||||||
$baseUploadDir = UPLOAD_DIR;
|
$baseUploadDir = UPLOAD_DIR;
|
||||||
if ($folder !== 'root') {
|
if ($folder !== 'root') {
|
||||||
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
$baseUploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . $folder . DIRECTORY_SEPARATOR;
|
||||||
if (!is_dir($baseUploadDir)) {
|
}
|
||||||
mkdir($baseUploadDir, 0775, true);
|
if (!is_dir($baseUploadDir) && !mkdir($baseUploadDir, 0775, true)) {
|
||||||
}
|
http_response_code(500);
|
||||||
} else {
|
echo json_encode(["error" => "Failed to create upload directory"]);
|
||||||
if (!is_dir($baseUploadDir)) {
|
exit;
|
||||||
mkdir($baseUploadDir, 0775, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare a collection to hold metadata for each folder.
|
$metadataCollection = [];
|
||||||
$metadataCollection = []; // key: folder path, value: metadata array
|
$metadataChanged = [];
|
||||||
$metadataChanged = []; // key: folder path, value: boolean
|
|
||||||
|
|
||||||
// Use a Unicode-enabled pattern to allow special characters.
|
|
||||||
$safeFileNamePattern = REGEX_FILE_NAME;
|
$safeFileNamePattern = REGEX_FILE_NAME;
|
||||||
|
|
||||||
foreach ($_FILES["file"]["name"] as $index => $fileName) {
|
foreach ($_FILES["file"]["name"] as $index => $fileName) {
|
||||||
// First, ensure we only work with the base filename to avoid traversal issues.
|
|
||||||
$safeFileName = trim(urldecode(basename($fileName)));
|
$safeFileName = trim(urldecode(basename($fileName)));
|
||||||
if (!preg_match($safeFileNamePattern, $safeFileName)) {
|
if (!preg_match($safeFileNamePattern, $safeFileName)) {
|
||||||
|
http_response_code(400);
|
||||||
echo json_encode(["error" => "Invalid file name: " . $fileName]);
|
echo json_encode(["error" => "Invalid file name: " . $fileName]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Minimal Folder/Subfolder Logic ---
|
|
||||||
$relativePath = '';
|
$relativePath = '';
|
||||||
if (isset($_POST['relativePath'])) {
|
if (isset($_POST['relativePath'])) {
|
||||||
if (is_array($_POST['relativePath'])) {
|
$relativePath = is_array($_POST['relativePath']) ? $_POST['relativePath'][$index] ?? '' : $_POST['relativePath'];
|
||||||
$relativePath = $_POST['relativePath'][$index] ?? '';
|
|
||||||
} else {
|
|
||||||
$relativePath = $_POST['relativePath'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$folderPath = $folder;
|
||||||
// Determine the complete folder path for upload and for metadata.
|
$uploadDir = $baseUploadDir;
|
||||||
$folderPath = $folder; // Base folder as provided ("root" or a subfolder)
|
|
||||||
$uploadDir = $baseUploadDir; // Start with the base upload directory
|
|
||||||
if (!empty($relativePath)) {
|
if (!empty($relativePath)) {
|
||||||
$subDir = dirname($relativePath);
|
$subDir = dirname($relativePath);
|
||||||
if ($subDir !== '.' && $subDir !== '') {
|
if ($subDir !== '.' && $subDir !== '') {
|
||||||
$folderPath = ($folder === 'root') ? $subDir : $folder . "/" . $subDir;
|
$folderPath = ($folder === 'root') ? $subDir : $folder . "/" . $subDir;
|
||||||
$uploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR
|
$uploadDir = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $folderPath) . DIRECTORY_SEPARATOR;
|
||||||
. str_replace('/', DIRECTORY_SEPARATOR, $folderPath) . DIRECTORY_SEPARATOR;
|
|
||||||
}
|
}
|
||||||
// Reapply basename to the relativePath to get the final safe file name.
|
|
||||||
$safeFileName = basename($relativePath);
|
$safeFileName = basename($relativePath);
|
||||||
}
|
}
|
||||||
// --- End Minimal Folder/Subfolder Logic ---
|
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0775, true)) {
|
||||||
|
http_response_code(500);
|
||||||
// Make sure the final upload directory exists.
|
echo json_encode(["error" => "Failed to create subfolder"]);
|
||||||
if (!is_dir($uploadDir)) {
|
exit;
|
||||||
mkdir($uploadDir, 0775, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$targetPath = $uploadDir . $safeFileName;
|
$targetPath = $uploadDir . $safeFileName;
|
||||||
|
|
||||||
if (move_uploaded_file($_FILES["file"]["tmp_name"][$index], $targetPath)) {
|
if (move_uploaded_file($_FILES["file"]["tmp_name"][$index], $targetPath)) {
|
||||||
// Generate a unique metadata file name based on the folder path.
|
|
||||||
$metadataKey = ($folderPath === '' || $folderPath === 'root') ? "root" : $folderPath;
|
$metadataKey = ($folderPath === '' || $folderPath === 'root') ? "root" : $folderPath;
|
||||||
$metadataFileName = str_replace(['/', '\\', ' '], '-', $metadataKey) . '_metadata.json';
|
$metadataFileName = str_replace(['/', '\\', ' '], '-', $metadataKey) . '_metadata.json';
|
||||||
$metadataFile = META_DIR . $metadataFileName;
|
$metadataFile = META_DIR . $metadataFileName;
|
||||||
|
|
||||||
if (!isset($metadataCollection[$metadataKey])) {
|
if (!isset($metadataCollection[$metadataKey])) {
|
||||||
if (file_exists($metadataFile)) {
|
$metadataCollection[$metadataKey] = file_exists($metadataFile) ? json_decode(file_get_contents($metadataFile), true) : [];
|
||||||
$metadataCollection[$metadataKey] = json_decode(file_get_contents($metadataFile), true);
|
if (!is_array($metadataCollection[$metadataKey])) {
|
||||||
} else {
|
|
||||||
$metadataCollection[$metadataKey] = [];
|
$metadataCollection[$metadataKey] = [];
|
||||||
}
|
}
|
||||||
$metadataChanged[$metadataKey] = false;
|
$metadataChanged[$metadataKey] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($metadataCollection[$metadataKey][$safeFileName])) {
|
if (!isset($metadataCollection[$metadataKey][$safeFileName])) {
|
||||||
$uploadedDate = date(DATE_TIME_FORMAT);
|
$uploadedDate = date(DATE_TIME_FORMAT);
|
||||||
$uploader = $_SESSION['username'] ?? "Unknown";
|
$uploader = $_SESSION['username'] ?? "Unknown";
|
||||||
@@ -265,12 +254,12 @@ if (!preg_match(REGEX_FILE_NAME, $resumableFilename)) {
|
|||||||
$metadataChanged[$metadataKey] = true;
|
$metadataChanged[$metadataKey] = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
http_response_code(500);
|
||||||
echo json_encode(["error" => "Error uploading file"]);
|
echo json_encode(["error" => "Error uploading file"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After processing all files, write out metadata files for folders that changed.
|
|
||||||
foreach ($metadataCollection as $folderKey => $data) {
|
foreach ($metadataCollection as $folderKey => $data) {
|
||||||
if ($metadataChanged[$folderKey]) {
|
if ($metadataChanged[$folderKey]) {
|
||||||
$metadataFileName = str_replace(['/', '\\', ' '], '-', $folderKey) . '_metadata.json';
|
$metadataFileName = str_replace(['/', '\\', ' '], '-', $folderKey) . '_metadata.json';
|
||||||
|
|||||||
Reference in New Issue
Block a user