mirror of
https://github.com/axeloz/filesharing.git
synced 2025-05-06 10:03:55 +02:00
Prevent duplicate files + fixing first upload
- server now warns if file is duplicate (below 1G) - fixing upload status on the first file of the bundle
This commit is contained in:
parent
50165e7d9b
commit
ae339d1d42
8 changed files with 59 additions and 17 deletions
|
@ -9,6 +9,8 @@ APP_LOCALE=en
|
||||||
UPLOAD_MAX_FILESIZE=1G
|
UPLOAD_MAX_FILESIZE=1G
|
||||||
UPLOAD_MAX_FILES=1000
|
UPLOAD_MAX_FILES=1000
|
||||||
UPLOAD_LIMIT_IPS=127.0.0.1
|
UPLOAD_LIMIT_IPS=127.0.0.1
|
||||||
|
UPLOAD_PREVENT_DUPLICATES=true
|
||||||
|
HASH_MAX_FILESIZE=1G
|
||||||
|
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
SESSION_DRIVER=file
|
SESSION_DRIVER=file
|
||||||
|
|
|
@ -45,7 +45,7 @@ class Upload {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
array_push($metadata['files'], $file);
|
array_unshift($metadata['files'], $file);
|
||||||
self::setMetadata($bundleId, $metadata);
|
self::setMetadata($bundleId, $metadata);
|
||||||
|
|
||||||
return $metadata;
|
return $metadata;
|
||||||
|
@ -93,12 +93,7 @@ class Upload {
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($values as $k => $v) {
|
foreach ($values as $k => $v) {
|
||||||
$unit = preg_replace('/[^bkmgtpezy]/i', '', $v);
|
$values[$k] = self::humanReadableToBytes($v);
|
||||||
$size = preg_replace('/[^0-9\.]/', '', $v);
|
|
||||||
if ($unit) {
|
|
||||||
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
|
|
||||||
$values[$k] = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])), 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$min = min($values);
|
$min = min($values);
|
||||||
|
@ -108,6 +103,25 @@ class Upload {
|
||||||
return $min;
|
return $min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function humanReadableToBytes($value) {
|
||||||
|
$unit = preg_replace('/[^bkmgtpezy]/i', '', $value);
|
||||||
|
$size = preg_replace('/[^0-9\.]/', '', $value);
|
||||||
|
if (! empty($unit)) {
|
||||||
|
$value = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])), 1);
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isDuplicateFile($bundleId, $hash) {
|
||||||
|
$metadata = self::getMetadata($bundleId);
|
||||||
|
foreach ($metadata['files'] as $f) {
|
||||||
|
if ($f['hash'] !== null && $f['hash'] == $hash) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static function canUpload($current_ip) {
|
public static function canUpload($current_ip) {
|
||||||
|
|
||||||
// Getting the IP limit configuration
|
// Getting the IP limit configuration
|
||||||
|
|
|
@ -63,15 +63,25 @@ class UploadController extends Controller
|
||||||
$bundleId, $filename, 'uploads'
|
$bundleId, $filename, 'uploads'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$size = Storage::disk('uploads')->size($fullpath);
|
||||||
|
if (config('sharing.upload_prevent_duplicates', true) === true && $size < Upload::humanReadableToBytes(config('sharing.hash_maxfilesize', '1G'))) {
|
||||||
|
$hash = sha1_file(Storage::disk('uploads')->path($fullpath));
|
||||||
|
if (Upload::isDuplicateFile($bundleId, $hash)) {
|
||||||
|
Storage::disk('uploads')->delete($fullpath);
|
||||||
|
throw new Exception(__('app.duplicate-file'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generating file metadata
|
// Generating file metadata
|
||||||
$file = [
|
$file = [
|
||||||
'uuid' => $request->uuid,
|
'uuid' => $request->uuid,
|
||||||
'original' => $original,
|
'original' => $original,
|
||||||
'filesize' => Storage::disk('uploads')->size($fullpath),
|
'filesize' => $size,
|
||||||
'fullpath' => $fullpath,
|
'fullpath' => $fullpath,
|
||||||
'filename' => $filename,
|
'filename' => $filename,
|
||||||
'created_at' => time(),
|
'created_at' => time(),
|
||||||
'status' => true
|
'status' => true,
|
||||||
|
'hash' => $hash ?? null
|
||||||
];
|
];
|
||||||
|
|
||||||
$metadata = Upload::addFileMetaData($bundleId, $file);
|
$metadata = Upload::addFileMetaData($bundleId, $file);
|
||||||
|
|
|
@ -29,4 +29,11 @@ return [
|
||||||
*/
|
*/
|
||||||
'upload_ip_limit' => env('UPLOAD_LIMIT_IPS', null),
|
'upload_ip_limit' => env('UPLOAD_LIMIT_IPS', null),
|
||||||
|
|
||||||
|
'upload_prevent_duplicates' => env('UPLOAD_PREVENT_DUPLICATES', true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Max filesize hash processing
|
||||||
|
** TODO: find the best value to avoid too long time processing
|
||||||
|
*/
|
||||||
|
'hash_maxfilesize' => env('HASH_MAX_FILESIZE', '1G')
|
||||||
];
|
];
|
||||||
|
|
|
@ -81,4 +81,5 @@ return [
|
||||||
'password' => 'Password',
|
'password' => 'Password',
|
||||||
'do-login' => 'Login now',
|
'do-login' => 'Login now',
|
||||||
'pending' => 'Drafts',
|
'pending' => 'Drafts',
|
||||||
|
'duplicate-file' => 'This file already exists in the bundle'
|
||||||
];
|
];
|
||||||
|
|
|
@ -81,4 +81,5 @@ return [
|
||||||
'password' => 'Mot de passe',
|
'password' => 'Mot de passe',
|
||||||
'do-login' => 'S\'authentifier',
|
'do-login' => 'S\'authentifier',
|
||||||
'pending' => 'Brouillons',
|
'pending' => 'Brouillons',
|
||||||
|
'duplicate-file' => 'Ce fichier existe déjà dans l\'archive'
|
||||||
];
|
];
|
||||||
|
|
|
@ -89,6 +89,8 @@ In order to configure your application, copy the .env.example file into .env. Th
|
||||||
| `APP_DEBUG` | change this to `false` when in production (`true` otherwise) |
|
| `APP_DEBUG` | change this to `false` when in production (`true` otherwise) |
|
||||||
| `APP_TIMEZONE` | change this to your current timezone |
|
| `APP_TIMEZONE` | change this to your current timezone |
|
||||||
| `APP_LOCALE` | change this to "fr" or "en" |
|
| `APP_LOCALE` | change this to "fr" or "en" |
|
||||||
|
| `UPLOAD_PREVENT_DUPLICATES` | Should the app block duplicate files (true | false) |
|
||||||
|
| `HASH_MAX_FILESIZE`| max filesize for hashing file to check for duplicate files. If files are higher, they will not be hashed. Find the best value to better time / memory consumption |
|
||||||
| `UPLOAD_MAX_FILES` | (*optional*) maximal number of files per bundle |
|
| `UPLOAD_MAX_FILES` | (*optional*) maximal number of files per bundle |
|
||||||
| `UPLOAD_MAX_FILESIZE` | (*optional*) change this to the value you want (K, M, G, T, ...). Attention : you must configure your PHP settings too (`post_max_size`, `upload_max_filesize` and `memory_limit`). When missing, using PHP lowest configuration |
|
| `UPLOAD_MAX_FILESIZE` | (*optional*) change this to the value you want (K, M, G, T, ...). Attention : you must configure your PHP settings too (`post_max_size`, `upload_max_filesize` and `memory_limit`). When missing, using PHP lowest configuration |
|
||||||
| `UPLOAD_LIMIT_IPS` | (*optional*) a comma separated list of IPs from which you may upload files. Different formats are supported : Full IP address (192.168.10.2), Wildcard format (192.168.10.*), CIDR Format (192.168.10/24 or 1.2.3.4/255.255.255.0) or Start-end IP (192.168.10.0-192.168.10.10). When missing, filtering is disabled. |
|
| `UPLOAD_LIMIT_IPS` | (*optional*) a comma separated list of IPs from which you may upload files. Different formats are supported : Full IP address (192.168.10.2), Wildcard format (192.168.10.*), CIDR Format (192.168.10/24 or 1.2.3.4/255.255.255.0) or Start-end IP (192.168.10.0-192.168.10.10). When missing, filtering is disabled. |
|
||||||
|
|
|
@ -202,11 +202,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dropzone.on('addedfile', (file) => {
|
this.dropzone.on('addedfile', (file) => {
|
||||||
console.log('added file')
|
|
||||||
|
|
||||||
file.uuid = this.uuid()
|
file.uuid = this.uuid()
|
||||||
|
|
||||||
this.metadata.files.push({
|
this.metadata.files.unshift({
|
||||||
uuid: file.uuid,
|
uuid: file.uuid,
|
||||||
original: file.name,
|
original: file.name,
|
||||||
filesize: file.size,
|
filesize: file.size,
|
||||||
|
@ -215,6 +213,7 @@
|
||||||
created_at: moment().unix(),
|
created_at: moment().unix(),
|
||||||
status: 'uploading'
|
status: 'uploading'
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dropzone.on('sending', (file, xhr, data) => {
|
this.dropzone.on('sending', (file, xhr, data) => {
|
||||||
|
@ -224,15 +223,21 @@
|
||||||
this.dropzone.on('uploadprogress', (file, progress, bytes) => {
|
this.dropzone.on('uploadprogress', (file, progress, bytes) => {
|
||||||
let fileIndex = null
|
let fileIndex = null
|
||||||
|
|
||||||
if (fileIndex = this.findFileIndex(file.upload.uuid)) {
|
if (fileIndex = this.findFileIndex(file.uuid)) {
|
||||||
this.metadata.files[fileIndex].progress = Math.round(progress)
|
this.metadata.files[fileIndex].progress = Math.round(progress)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dropzone.on('error', (file, message) => {
|
this.dropzone.on('error', (file, message) => {
|
||||||
let fileIndex = this.findFileIndex(file.upload.uuid)
|
let fileIndex = this.findFileIndex(file.uuid)
|
||||||
this.metadata.files[fileIndex].status = false
|
this.metadata.files[fileIndex].status = false
|
||||||
|
|
||||||
|
if (message.hasOwnProperty('error')) {
|
||||||
|
this.metadata.files[fileIndex].message = message.error
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.metadata.files[fileIndex].message = message
|
this.metadata.files[fileIndex].message = message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dropzone.on('complete', (file) => {
|
this.dropzone.on('complete', (file) => {
|
||||||
|
@ -606,10 +611,10 @@
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<span class="text-xs text-slate-400" x-show="countFilesOnServer() == 0">@lang('app.no-file')</span>
|
<span class="text-xs text-slate-400" x-show="Object.keys(metadata.files).length == 0">@lang('app.no-file')</span>
|
||||||
|
|
||||||
{{-- Files list --}}
|
{{-- Files list --}}
|
||||||
<ul id="output" class="text-xs max-h-32 overflow-y-scroll pb-3" x-show="countFilesOnServer() > 0">
|
<ul id="output" class="text-xs max-h-32 overflow-y-scroll pb-3" x-show="Object.keys(metadata.files).length > 0">
|
||||||
<template x-for="(f, k) in metadata.files" :key="k">
|
<template x-for="(f, k) in metadata.files" :key="k">
|
||||||
<li
|
<li
|
||||||
title="{{ __('app.click-to-remove') }}"
|
title="{{ __('app.click-to-remove') }}"
|
||||||
|
|
Loading…
Add table
Reference in a new issue