2024-03-01 22:14:20 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
function makePathSafe($userInput): string
|
|
|
|
{
|
|
|
|
// Keep only alphanumeric characters, underscores, and hyphens
|
|
|
|
$safeString = preg_replace('/[^\w\-]/', '', $userInput);
|
|
|
|
|
|
|
|
// Ensure no path traversal
|
|
|
|
$safeString = str_replace('..', '_', $safeString);
|
|
|
|
|
|
|
|
// Trim leading/trailing underscores
|
|
|
|
$safeString = trim($safeString, '_');
|
|
|
|
|
|
|
|
// Replace directory separator characters with underscores
|
|
|
|
$safeString = str_replace(['/', '\\'], '_', $safeString);
|
|
|
|
|
|
|
|
// Limit length for safety
|
|
|
|
return substr($safeString, 0, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getIncomingFiles(): array
|
|
|
|
{
|
|
|
|
$files = $_FILES;
|
|
|
|
$files2 = [];
|
|
|
|
foreach ($files as $infoArr) {
|
|
|
|
$filesByInput = [];
|
|
|
|
foreach ($infoArr as $key => $valueArr) {
|
|
|
|
if (is_array($valueArr)) { // file input "multiple"
|
|
|
|
foreach ($valueArr as $i => $value) {
|
|
|
|
$filesByInput[$i][$key] = $value;
|
|
|
|
}
|
|
|
|
} else { // -> string, normal file input
|
|
|
|
$filesByInput[] = $infoArr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$files2 = array_merge($files2, $filesByInput);
|
|
|
|
}
|
|
|
|
$files3 = [];
|
|
|
|
foreach ($files2 as $file) { // let's filter empty & errors
|
|
|
|
if (!$file['error']) $files3[] = $file;
|
|
|
|
}
|
|
|
|
return $files3;
|
|
|
|
}
|
|
|
|
|
2024-04-11 10:36:40 +02:00
|
|
|
function saveUploadedFileInDatabase($filePath, $fileType): bool
|
2024-03-01 22:14:20 +01:00
|
|
|
{
|
|
|
|
global $mysqli;
|
|
|
|
$stmt = $mysqli->prepare("INSERT INTO Files (Path, Type, UploadedBy, UploadedAt) VALUES (?, ?, ?, NOW())");
|
|
|
|
$stmt->bind_param("ssi", $filePath, $fileType, $_SESSION["ID"]);
|
|
|
|
$stmt->execute();
|
|
|
|
$stat = $stmt->affected_rows > 0;
|
|
|
|
$stmt->close();
|
|
|
|
return $stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
function doImageUpload($inFile, $outFile): bool
|
|
|
|
{
|
|
|
|
// Create Imagick object
|
2024-03-10 22:55:29 +01:00
|
|
|
try {
|
|
|
|
$imagick = new Imagick($inFile);
|
|
|
|
} catch (ImagickException $e) {
|
|
|
|
}
|
2024-03-01 22:14:20 +01:00
|
|
|
|
|
|
|
// Set the desired format for reencoding (WebP)
|
2024-03-10 22:55:29 +01:00
|
|
|
try {
|
|
|
|
$imagick->setImageFormat('webp');
|
|
|
|
} catch (ImagickException $e) {
|
|
|
|
}
|
2024-03-01 22:14:20 +01:00
|
|
|
|
|
|
|
// Remove non-essential metadata
|
2024-03-10 22:55:29 +01:00
|
|
|
try {
|
|
|
|
$imagick->stripImage();
|
|
|
|
} catch (ImagickException $e) {
|
|
|
|
}
|
2024-03-01 22:14:20 +01:00
|
|
|
|
|
|
|
// Write the reencoded image to the output file
|
2024-03-10 22:55:29 +01:00
|
|
|
try {
|
|
|
|
$imagick->writeImage($outFile);
|
|
|
|
} catch (ImagickException $e) {
|
|
|
|
}
|
2024-03-01 22:14:20 +01:00
|
|
|
|
|
|
|
// Destroy the Imagick object to free up resources
|
|
|
|
$imagick->destroy();
|
|
|
|
|
|
|
|
// Check if the reencoding was successful
|
|
|
|
if (file_exists($outFile)) {
|
|
|
|
return saveUploadedFileInDatabase($outFile, 'image/webp');
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-11 10:36:40 +02:00
|
|
|
function listFiles($onlyMine = true): array
|
2024-03-01 22:14:20 +01:00
|
|
|
{
|
|
|
|
$output = ["Status" => "Fail"];
|
|
|
|
require_once "lib/account.php";
|
2024-04-11 10:36:40 +02:00
|
|
|
if (($onlyMine && isLoggedIn()) || (!$onlyMine && isModerator())) {
|
2024-03-01 22:14:20 +01:00
|
|
|
global $mysqli;
|
|
|
|
$query = "SELECT ID, Path, Type, UploadedAt, UploadedBy FROM Files";
|
|
|
|
|
2024-04-11 10:36:40 +02:00
|
|
|
if ($onlyMine) {
|
2024-03-01 22:14:20 +01:00
|
|
|
$query .= " WHERE UploadedBy = ?";
|
|
|
|
}
|
|
|
|
|
|
|
|
$stmt = $mysqli->prepare($query);
|
2024-04-11 10:36:40 +02:00
|
|
|
if ($onlyMine) {
|
2024-03-01 22:14:20 +01:00
|
|
|
$stmt->bind_param("i", $_SESSION["ID"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$id = 0;
|
|
|
|
$path = "";
|
|
|
|
$type = "";
|
|
|
|
$uploadedAt = "";
|
|
|
|
$uploadedBy = 0;
|
|
|
|
|
|
|
|
$stmt->bind_result($id, $path, $type, $uploadedAt, $uploadedBy);
|
|
|
|
|
|
|
|
$stmt->execute();
|
|
|
|
|
|
|
|
// Fetch the results into the bound variables
|
|
|
|
while ($stmt->fetch()) {
|
|
|
|
$files[] = [
|
|
|
|
'ID' => $id,
|
|
|
|
'Path' => $path,
|
|
|
|
'Type' => $type,
|
|
|
|
'UploadedAt' => $uploadedAt,
|
|
|
|
'UploadedBy' => $uploadedBy,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if any results were fetched
|
|
|
|
if (!empty($files)) {
|
|
|
|
$output["Status"] = "Success";
|
|
|
|
$output["Files"] = $files;
|
|
|
|
}
|
|
|
|
|
|
|
|
$stmt->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $output;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseIncomingFiles(): array
|
|
|
|
{
|
|
|
|
$incomingFiles = getIncomingFiles();
|
|
|
|
$success = true;
|
|
|
|
|
|
|
|
foreach ($incomingFiles as $incomingFile) {
|
|
|
|
if ($incomingFile["error"] == 0 && is_file($incomingFile["tmp_name"])) {
|
|
|
|
$type = explode("/", $incomingFile["type"]);
|
2024-03-10 22:55:29 +01:00
|
|
|
if ($type == "image") {
|
|
|
|
$imgFname = pathinfo($incomingFile["name"], PATHINFO_FILENAME);
|
|
|
|
$uploadPath = getUploadPath("image", $imgFname);
|
|
|
|
if (!empty($uploadPath)) {
|
|
|
|
if (!doImageUpload($incomingFile["tmp_name"], $uploadPath)) {
|
2024-03-01 22:14:20 +01:00
|
|
|
$success = false;
|
|
|
|
}
|
2024-03-10 22:55:29 +01:00
|
|
|
} else {
|
|
|
|
$success = false;
|
|
|
|
}
|
2024-03-01 22:14:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$output = ["Status" => "Fail"];
|
2024-04-11 10:36:40 +02:00
|
|
|
if ($success) {
|
2024-03-01 22:14:20 +01:00
|
|
|
$output["Status"] = "Success";
|
|
|
|
}
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getUploadPath($type = "unknown", $filename = "hehe"): string
|
|
|
|
{
|
|
|
|
$type = makePathSafe($type);
|
|
|
|
$id = makePathSafe($_SESSION["ID"]);
|
|
|
|
$date = makePathSafe(date("Y/m/d"));
|
|
|
|
$filename = makePathSafe($filename);
|
|
|
|
$extension = match ($type) {
|
|
|
|
'image' => 'webp',
|
|
|
|
default => 'dummy',
|
|
|
|
};
|
2024-04-11 10:36:40 +02:00
|
|
|
if ($extension != "dummy") {
|
2024-03-01 22:14:20 +01:00
|
|
|
return "uploads/$type/$id/$date/$filename.$extension";
|
2024-04-11 10:36:40 +02:00
|
|
|
} else {
|
2024-03-01 22:14:20 +01:00
|
|
|
return "";
|
|
|
|
}
|
2024-04-11 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function fileExists(int $fileId, bool $onlyMine = true): bool
|
|
|
|
{
|
|
|
|
if(!$fileId) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
global $mysqli;
|
|
|
|
if (!$onlyMine && !isAdmin()) {
|
|
|
|
$onlyMine = true;
|
|
|
|
}
|
|
|
|
$query = 'SELECT ID FROM Files WHERE ID = ?' . $onlyMine ? ' AND UploadedBy = ?' : '';
|
|
|
|
$stmtfileexists = $mysqli->prepare($query);
|
|
|
|
if ($onlyMine) {
|
|
|
|
$stmtfileexists->bind_param('ii', $fileId, $_SESSION['id']);
|
|
|
|
} else {
|
|
|
|
$stmtfileexists->bind_param('i', $fileId);
|
|
|
|
}
|
|
|
|
$stmtfileexists->execute();
|
|
|
|
return $stmtfileexists->affected_rows > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addToGroup(int $groupId, int $fileId): bool
|
|
|
|
{
|
|
|
|
$output = ["Status" => "Fail"];
|
|
|
|
if (!$groupId || !$fileId) {
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
global $mysqli;
|
|
|
|
$stmtcheck = $mysqli->prepare('SELECT ID FROM FileGroups WHERE CreatorID != ? AND ID = ?');
|
|
|
|
$stmtcheck->bind_param('ii', $_SESSION['id'], $groupId);
|
|
|
|
$stmtcheck->execute();
|
|
|
|
if ($stmtcheck->affected_rows == 0) {
|
|
|
|
if (fileExists($fileId, false)) {
|
|
|
|
$stmtadd = $mysqli->prepare('INSERT INTO FileGroups (FileID, CreatorID, ID) VALUES (?, ?, ?)');
|
|
|
|
$stmtadd->bind_param('iii', $fileId, $_SESSION['id'], $groupId);
|
|
|
|
$stmtadd->execute();
|
|
|
|
if ($stmtadd->affected_rows > 0) {
|
|
|
|
$output["Status"] = "Success";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $output;
|
2024-03-01 22:14:20 +01:00
|
|
|
}
|