Use raw file uploads
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
PLUGIN="u-navigator"
|
PLUGIN="u-navigator"
|
||||||
VERSION="2026.06.23.r045"
|
VERSION="2026.06.23.r046"
|
||||||
PKG_DIR="packages"
|
PKG_DIR="packages"
|
||||||
WORK_DIR=".plugin-build"
|
WORK_DIR=".plugin-build"
|
||||||
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -7,6 +7,31 @@ if (!is_dir($target['path'])) {
|
|||||||
unav_error(400, 'Upload target must be a directory');
|
unav_error(400, 'Upload target must be a directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['relativePath']) || isset($_SERVER['HTTP_X_UNAV_RELATIVE_PATH'])) {
|
||||||
|
$relativeName = (string)($_GET['relativePath'] ?? $_SERVER['HTTP_X_UNAV_RELATIVE_PATH']);
|
||||||
|
$destination = unav_prepare_upload_destination($target['path'], $relativeName);
|
||||||
|
$input = fopen('php://input', 'rb');
|
||||||
|
$output = fopen($destination['path'], 'xb');
|
||||||
|
if (!$input || !$output) {
|
||||||
|
if ($input) {
|
||||||
|
fclose($input);
|
||||||
|
}
|
||||||
|
if ($output) {
|
||||||
|
fclose($output);
|
||||||
|
}
|
||||||
|
unav_error(500, 'Could not open upload stream');
|
||||||
|
}
|
||||||
|
stream_copy_to_stream($input, $output);
|
||||||
|
fclose($input);
|
||||||
|
fclose($output);
|
||||||
|
unav_json([
|
||||||
|
'uploaded' => [[
|
||||||
|
'name' => $destination['relative'],
|
||||||
|
'size' => filesize($destination['path']) ?: 0,
|
||||||
|
]],
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
$uploaded = [];
|
$uploaded = [];
|
||||||
$names = unav_upload_array($_FILES['files']['name'] ?? []);
|
$names = unav_upload_array($_FILES['files']['name'] ?? []);
|
||||||
$errors = unav_upload_array($_FILES['files']['error'] ?? []);
|
$errors = unav_upload_array($_FILES['files']['error'] ?? []);
|
||||||
@@ -17,33 +42,38 @@ foreach ($names as $index => $name) {
|
|||||||
unav_error(400, 'Upload failed');
|
unav_error(400, 'Upload failed');
|
||||||
}
|
}
|
||||||
$relativeName = $relativePaths[$index] ?? $name;
|
$relativeName = $relativePaths[$index] ?? $name;
|
||||||
$safeName = unav_upload_safe_relative_path((string)$relativeName);
|
$destination = unav_prepare_upload_destination($target['path'], (string)$relativeName);
|
||||||
|
if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) {
|
||||||
|
unav_error(500, 'Could not store uploaded file');
|
||||||
|
}
|
||||||
|
$uploaded[] = [
|
||||||
|
'name' => $destination['relative'],
|
||||||
|
'size' => filesize($destination['path']) ?: 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
unav_json(['uploaded' => $uploaded], 201);
|
||||||
|
|
||||||
|
function unav_prepare_upload_destination(string $targetPath, string $relativeName): array {
|
||||||
|
$safeName = unav_upload_safe_relative_path($relativeName);
|
||||||
$relativeParent = dirname($safeName);
|
$relativeParent = dirname($safeName);
|
||||||
if ($relativeParent !== '.') {
|
if ($relativeParent !== '.') {
|
||||||
$parentCandidate = $target['path'] . '/' . $relativeParent;
|
$parentCandidate = $targetPath . '/' . $relativeParent;
|
||||||
unav_root_for_real($target['path']);
|
unav_root_for_real($targetPath);
|
||||||
if (!is_dir($parentCandidate) && !mkdir($parentCandidate, 0777, true) && !is_dir($parentCandidate)) {
|
if (!is_dir($parentCandidate) && !mkdir($parentCandidate, 0777, true) && !is_dir($parentCandidate)) {
|
||||||
unav_error(500, 'Could not create upload directory');
|
unav_error(500, 'Could not create upload directory');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$destination = unav_destination_path($target['path'] . '/' . $safeName);
|
$destination = unav_destination_path($targetPath . '/' . $safeName);
|
||||||
if (file_exists($destination['path'])) {
|
if (file_exists($destination['path'])) {
|
||||||
unav_error(409, 'Destination already exists');
|
unav_error(409, 'Destination already exists');
|
||||||
}
|
}
|
||||||
if (!is_dir(dirname($destination['path']))) {
|
if (!is_dir(dirname($destination['path']))) {
|
||||||
unav_error(500, 'Could not create upload directory');
|
unav_error(500, 'Could not create upload directory');
|
||||||
}
|
}
|
||||||
if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) {
|
return ['path' => $destination['path'], 'relative' => $safeName];
|
||||||
unav_error(500, 'Could not store uploaded file');
|
|
||||||
}
|
|
||||||
$uploaded[] = [
|
|
||||||
'name' => $safeName,
|
|
||||||
'size' => filesize($destination['path']) ?: 0,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unav_json(['uploaded' => $uploaded], 201);
|
|
||||||
|
|
||||||
function unav_upload_array($value): array {
|
function unav_upload_array($value): array {
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
return array_values($value);
|
return array_values($value);
|
||||||
|
|||||||
+14
-6
@@ -904,13 +904,21 @@ async function uploadFileList(win, files, targetPath) {
|
|||||||
const uploadItems = normalizeUploadItems(files);
|
const uploadItems = normalizeUploadItems(files);
|
||||||
for (const [index, item] of uploadItems.entries()) {
|
for (const [index, item] of uploadItems.entries()) {
|
||||||
recordDebug('upload.file.request', { path: item.path, size: item.file.size, index: index + 1, total: uploadItems.length });
|
recordDebug('upload.file.request', { path: item.path, size: item.file.size, index: index + 1, total: uploadItems.length });
|
||||||
const form = new FormData();
|
const params = new URLSearchParams({
|
||||||
form.append('files', item.file, item.file.name);
|
path: targetPath,
|
||||||
form.append('relativePath', item.path);
|
relativePath: item.path
|
||||||
appendCsrf(form);
|
});
|
||||||
await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), {
|
const token = getCsrfToken();
|
||||||
|
if (token) {
|
||||||
|
params.set('csrf_token', token);
|
||||||
|
recordDebug('csrf.attached', { length: token.length });
|
||||||
|
} else {
|
||||||
|
recordDebug('csrf.missing', {});
|
||||||
|
}
|
||||||
|
await fetchChecked(apiUrl(`upload.php?${params.toString()}`), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: form
|
headers: { 'Content-Type': 'application/octet-stream' },
|
||||||
|
body: item.file
|
||||||
});
|
});
|
||||||
recordDebug('upload.file.done', { path: item.path, index: index + 1, total: uploadItems.length });
|
recordDebug('upload.file.done', { path: item.path, index: index + 1, total: uploadItems.length });
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "u-navigator">
|
<!ENTITY name "u-navigator">
|
||||||
<!ENTITY author "Michael Roll">
|
<!ENTITY author "Michael Roll">
|
||||||
<!ENTITY version "2026.06.23.r045">
|
<!ENTITY version "2026.06.23.r046">
|
||||||
<!ENTITY package "&name;-&version;.tgz">
|
<!ENTITY package "&name;-&version;.tgz">
|
||||||
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
||||||
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
|
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<FILE Name="/boot/config/plugins/&name;/&package;">
|
<FILE Name="/boot/config/plugins/&name;/&package;">
|
||||||
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
|
||||||
<MD5>cd3b5a92d7174924985b5d929cb180fe</MD5>
|
<MD5>acb81bdc26294c48b2115013cac89015</MD5>
|
||||||
</FILE>
|
</FILE>
|
||||||
|
|
||||||
<FILE Run="/bin/bash">
|
<FILE Run="/bin/bash">
|
||||||
|
|||||||
Reference in New Issue
Block a user