summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
authorilotterytea <iltsu@alright.party>2025-06-03 03:16:41 +0400
committerilotterytea <iltsu@alright.party>2025-06-03 03:16:41 +0400
commit4bf4a5379d879ce1da91cc20e6899c093fe6bd28 (patch)
tree27326d361258df6268b5ffc91cef6f2c075e4de9 /public
parent487b0592e3a10688f4d54e0feeef4f8ffb689bbe (diff)
feat: file deletion
Diffstat (limited to 'public')
-rw-r--r--public/delete.php64
-rw-r--r--public/index.php35
-rw-r--r--public/upload.php16
-rw-r--r--public/uploaders.php8
4 files changed, 118 insertions, 5 deletions
diff --git a/public/delete.php b/public/delete.php
new file mode 100644
index 0000000..161c6ed
--- /dev/null
+++ b/public/delete.php
@@ -0,0 +1,64 @@
+<?php
+include_once $_SERVER['DOCUMENT_ROOT'] . '/../config.php';
+include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/utils.php';
+
+if (!FILE_DELETION) {
+ json_response(null, 'File deletion is not allowed!', 403);
+ exit();
+}
+
+$file_id = $_GET['f'] ?: null;
+$password = $_GET['key'] ?: null;
+
+if (!isset($file_id, $password)) {
+ json_response(null, "Fields 'f' and 'key' must be set!", 400);
+ exit();
+}
+
+$file_id = explode('.', $file_id);
+$file_ext = $file_id[1];
+$file_id = $file_id[0];
+
+if (!preg_match('/^[a-zA-Z0-9_-]+$/', $file_id) || !preg_match('/^[a-zA-Z0-9]+$/', $file_ext)) {
+ json_response(null, "Invalid file ID or extension", 400);
+ exit();
+}
+
+if (!is_file(FILE_UPLOAD_DIRECTORY . "/{$file_id}.{$file_ext}")) {
+ json_response(null, "File {$file_id} not found", 404);
+ exit();
+}
+
+if (!is_file(FILE_METADATA_DIRECTORY . "/{$file_id}.metadata.json")) {
+ json_response(null, "File metadata {$file_id} not found", 404);
+ exit();
+}
+
+$metadata = json_decode(file_get_contents(FILE_METADATA_DIRECTORY . "/{$file_id}.metadata.json"), true);
+
+if (!array_key_exists('password', $metadata)) {
+ json_response(null, "File {$file_id} does not have a password. File cannot be deleted!", 400);
+ exit();
+}
+
+if (!password_verify($password, $metadata['password'])) {
+ json_response(null, "Bad password", 401);
+ exit();
+}
+
+if (
+ !unlink(FILE_UPLOAD_DIRECTORY . "/{$file_id}.{$file_ext}") ||
+ !unlink(FILE_THUMBNAIL_DIRECTORY . "/{$file_id}.webp") ||
+ !unlink(FILE_METADATA_DIRECTORY . "/{$file_id}.metadata.json")
+) {
+ json_response(null, "Failed to delete a file ID {$file_id}", 500);
+ exit();
+}
+
+json_response(
+ [
+ 'id' => $file_id,
+ 'extension' => $file_ext
+ ],
+ 'Successfully deleted the file'
+); \ No newline at end of file
diff --git a/public/index.php b/public/index.php
index 9da069d..d6c759c 100644
--- a/public/index.php
+++ b/public/index.php
@@ -273,6 +273,10 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php';
if (file.urls && file.urls.download_url) {
file_url = file.urls.download_url;
}
+ let file_deletion = '';
+ if (file.urls && file.urls.deletion_url) {
+ file_deletion = `<button onclick="deleteUploadedFile('${file.urls.deletion_url}', '${file.id}')">Delete</button>`;
+ }
return `
<div class="box item column gap-4 pad-4">
@@ -292,11 +296,36 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php';
<a href="${file_url}">
<button>Open</button>
</a>
+ ${file_deletion}
</div>
</div>
`;
}
+ function deleteUploadedFile(url, id) {
+ fetch(url, {
+ 'headers': {
+ 'Accept': 'application/json'
+ },
+ 'method': 'DELETE'
+ }).then((r) => r.json())
+ .then((json) => {
+ if (json.status_code != 200) {
+ alert(`${json.message} (${json.status_code})`);
+ return;
+ }
+
+ let files = getUploadedFiles();
+ files = files.filter((x) => x.id !== id);
+ localStorage.setItem('uploaded_files', JSON.stringify(files));
+ loadUploadedFiles();
+ })
+ .catch((err) => {
+ alert('Failed to delete the file. Look into the console!');
+ console.error(err);
+ });
+ }
+
// loading already existing uploaded files
function loadUploadedFiles() {
let files = getUploadedFiles();
@@ -307,13 +336,9 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php';
html += addUploadedFile(file);
}
- if (html.length > 0) {
- uploadedFiles.parentElement.style.display = 'flex';
- }
+ uploadedFiles.parentElement.style.display = html.length > 0 ? 'flex' : 'none';
uploadedFiles.innerHTML = html;
-
- localStorage.setItem('uploaded_files', JSON.stringify(files));
}
loadUploadedFiles();
diff --git a/public/upload.php b/public/upload.php
index 96d1f4b..1f5b838 100644
--- a/public/upload.php
+++ b/public/upload.php
@@ -162,11 +162,27 @@ try {
'download_url' => INSTANCE_URL . "/{$file_data['id']}.{$file_data['extension']}"
];
+ if (FILE_METADATA && FILE_DELETION) {
+ $file_data['password'] = $_POST['password'] ?? generate_random_char_sequence(FILE_ID_CHARACTERS, FILE_DELETION_KEY_LENGTH);
+ $file_data['urls']['deletion_url'] = INSTANCE_URL . "/delete.php?f={$file_data['id']}.{$file_data['extension']}&key={$file_data['password']}";
+ }
+
if ($_SERVER['HTTP_ACCEPT'] == 'application/json') {
json_response($file_data, null, 201);
} else {
header("Location: /{$file_data['id']}.{$file_data['extension']}");
}
+
+ if (FILE_METADATA) {
+ unset($file_data['urls']);
+ $file_data['password'] = password_hash($file_data['password'], PASSWORD_DEFAULT);
+ if (!is_dir(FILE_METADATA_DIRECTORY) && !mkdir(FILE_METADATA_DIRECTORY, 0777, true)) {
+ throw new RuntimeException('Failed to create a folder for file metadata');
+ }
+ if (!file_put_contents(FILE_METADATA_DIRECTORY . "/{$file_data['id']}.metadata.json", json_encode($file_data, JSON_UNESCAPED_SLASHES))) {
+ throw new RuntimeException('Failed to create a file metadata');
+ }
+ }
} catch (RuntimeException $e) {
if ($_SERVER['HTTP_ACCEPT'] == 'application/json') {
json_response(null, $e->getMessage(), 400);
diff --git a/public/uploaders.php b/public/uploaders.php
index 57cf8b4..ed0478a 100644
--- a/public/uploaders.php
+++ b/public/uploaders.php
@@ -75,6 +75,10 @@ foreach (FILE_ACCEPTED_MIME_TYPES as $k => $v) {
<th>URL:</th>
<td><code class="copy">{json:data.urls.download_url}</code></td>
</tr>
+ <tr>
+ <th>Deletion URL:</th>
+ <td><code class="copy">{json:data.urls.deletion_url}</code></td>
+ </tr>
</table>
<p>Then, select it via <b>Destinations &rarr; Image uploader &rarr; Custom image
uploader</b></p>
@@ -103,6 +107,10 @@ foreach (FILE_ACCEPTED_MIME_TYPES as $k => $v) {
<th>Image link:</th>
<td><code class="copy">{data.urls.download_url}</code></td>
</tr>
+ <tr>
+ <th>Deletion link:</th>
+ <td><code class="copy">{data.urls.deletion_url}</code></td>
+ </tr>
</table>
</section>
</div>