2024-03-01 22:14:20 +01:00
< ? php
2024-04-27 11:48:58 +02:00
declare ( strict_types = 1 );
2024-03-01 22:14:20 +01:00
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 );
}
2024-04-26 14:37:54 +02:00
function autoRotateImage ( Imagick $imagick ) : void {
// Get the current orientation of the image
try {
$orientation = $imagick -> getImageOrientation ();
switch ( $orientation ) {
case Imagick :: ORIENTATION_BOTTOMRIGHT : // upside down
$imagick -> rotateimage ( " #000 " , 180 ); // rotate 180 degrees
break ;
case Imagick :: ORIENTATION_RIGHTTOP : // 90 degrees CW
$imagick -> rotateimage ( " #000 " , 90 ); // rotate 90 degrees CW
break ;
case Imagick :: ORIENTATION_LEFTBOTTOM : // 90 degrees CCW
$imagick -> rotateimage ( " #000 " , - 90 ); // rotate 90 degrees CCW
break ;
}
// Reset orientation to normal after the correction
$imagick -> setImageOrientation ( Imagick :: ORIENTATION_TOPLEFT );
} catch ( ImagickException ) {
}
}
2024-03-01 22:14:20 +01:00
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-27 11:48:58 +02:00
function saveUploadedFileInDatabase ( string $filePath , string $fileType , int $width , int $height ) : bool
2024-03-01 22:14:20 +01:00
{
global $mysqli ;
2024-04-27 11:48:58 +02:00
$stmt = $mysqli -> prepare ( " INSERT INTO Files (Path, Type, UploadedBy, UploadedAt, Width, Height) VALUES (?, ?, ?, NOW(), ?, ?) " );
$stmt -> bind_param ( " ssiii " , $filePath , $fileType , $_SESSION [ " ID " ], $width , $height );
2024-03-01 22:14:20 +01:00
$stmt -> execute ();
$stat = $stmt -> affected_rows > 0 ;
$stmt -> close ();
return $stat ;
}
function doImageUpload ( $inFile , $outFile ) : bool
{
// Create Imagick object
2024-04-27 11:48:58 +02:00
$width = 0 ;
$height = 0 ;
2024-03-10 22:55:29 +01:00
try {
$imagick = new Imagick ( $inFile );
$imagick -> setImageFormat ( 'webp' );
2024-04-26 14:37:54 +02:00
autoRotateImage ( $imagick );
2024-03-10 22:55:29 +01:00
$imagick -> stripImage ();
$imagick -> writeImage ( $outFile );
2024-04-27 11:48:58 +02:00
$width = $imagick -> getImageWidth ();
$height = $imagick -> getImageHeight ();
2024-04-25 10:19:24 +02:00
$imagick -> destroy ();
2024-04-26 14:37:54 +02:00
} catch ( ImagickException ) {
2024-03-10 22:55:29 +01:00
}
2024-03-01 22:14:20 +01:00
// Check if the reencoding was successful
if ( file_exists ( $outFile )) {
2024-04-27 11:48:58 +02:00
return saveUploadedFileInDatabase ( $outFile , 'image/webp' , $width , $height );
2024-03-01 22:14:20 +01:00
} 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-26 09:46:10 +02:00
if ( isLoggedIn ()) {
2024-03-01 22:14:20 +01:00
global $mysqli ;
2024-04-26 09:46:10 +02:00
if ( ! $onlyMine && ! isModerator ()) {
$onlyMine = true ;
}
2024-04-26 15:09:45 +02:00
$query = " SELECT Files.ID, Files.Path, Files.Type, Files.UploadedAt, Files.UploadedBy, Users.Nickname FROM Files INNER JOIN Users ON Files.UploadedBy = Users.ID ORDER BY UploadedAt DESC " ;
2024-03-01 22:14:20 +01:00
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 = " " ;
2024-04-26 15:09:45 +02:00
$uploadedByID = 0 ;
$uploadedBy = " " ;
2024-03-01 22:14:20 +01:00
2024-04-26 15:09:45 +02:00
$stmt -> bind_result ( $id , $path , $type , $uploadedAt , $uploadedByID , $uploadedBy );
2024-03-01 22:14:20 +01:00
$stmt -> execute ();
// Fetch the results into the bound variables
while ( $stmt -> fetch ()) {
$files [] = [
'ID' => $id ,
'Path' => $path ,
'Type' => $type ,
'UploadedAt' => $uploadedAt ,
2024-04-26 15:09:45 +02:00
'UploadedByID' => $uploadedByID ,
2024-03-01 22:14:20 +01:00
'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-04-25 10:49:45 +02:00
if ( $type [ 0 ] == " image " ) {
2024-03-10 22:55:29 +01:00
$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 " ]);
2024-04-26 01:33:20 +02:00
$date = makePathSafe ( date ( " YmdHis " ));
2024-03-01 22:14:20 +01:00
$filename = makePathSafe ( $filename );
$extension = match ( $type ) {
'image' => 'webp' ,
default => 'dummy' ,
};
2024-04-11 10:36:40 +02:00
if ( $extension != " dummy " ) {
2024-04-25 10:30:22 +02:00
$basepath = " uploads/ $type / $id / $date " ;
mkdir ( $basepath , 755 , true );
return $basepath . " / $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
}
2024-04-25 15:01:17 +02:00
function fileExists ( int $fileId , bool $onlyMine = true ) : bool | string
2024-04-11 10:36:40 +02:00
{
2024-04-26 09:46:10 +02:00
if ( ! $fileId ) {
2024-04-11 10:36:40 +02:00
return false ;
}
global $mysqli ;
2024-04-26 09:51:40 +02:00
if ( ! $onlyMine && ! isModerator ()) {
2024-04-11 10:36:40 +02:00
$onlyMine = true ;
}
2024-04-26 10:47:42 +02:00
$query = 'SELECT ID, Path FROM Files WHERE ID = ?' . ( $onlyMine ? ' AND UploadedBy = ?' : '' );
$stmtfileexists = $mysqli -> prepare ( $query );
2024-04-11 10:36:40 +02:00
if ( $onlyMine ) {
2024-04-26 10:47:42 +02:00
$stmtfileexists -> bind_param ( 'ii' , $fileId , $_SESSION [ 'ID' ]);
2024-04-11 10:36:40 +02:00
} else {
$stmtfileexists -> bind_param ( 'i' , $fileId );
}
2024-04-25 15:01:17 +02:00
$filePath = " " ;
2024-04-26 10:39:00 +02:00
$id = null ;
2024-04-26 10:46:34 +02:00
$stmtfileexists -> bind_result ( $id , $filePath );
2024-04-26 10:47:42 +02:00
$stmtfileexists -> execute ();
2024-04-25 23:37:52 +02:00
$stmtfileexists -> fetch ();
2024-04-26 10:47:42 +02:00
if ( $id != null ) {
2024-04-25 15:01:17 +02:00
return $filePath ;
2024-04-26 09:46:10 +02:00
} else {
2024-04-25 15:01:17 +02:00
return false ;
}
2024-04-11 10:36:40 +02:00
}
2024-04-25 10:19:24 +02:00
function addToGroup ( int $groupId , int $fileId ) : array
2024-04-11 10:36:40 +02:00
{
$output = [ " Status " => " Fail " ];
if ( ! $groupId || ! $fileId ) {
return $output ;
}
global $mysqli ;
$stmtcheck = $mysqli -> prepare ( 'SELECT ID FROM FileGroups WHERE CreatorID != ? AND ID = ?' );
2024-04-26 10:52:11 +02:00
$stmtcheck -> bind_param ( 'ii' , $_SESSION [ 'ID' ], $groupId );
2024-04-11 10:36:40 +02:00
$stmtcheck -> execute ();
if ( $stmtcheck -> affected_rows == 0 ) {
if ( fileExists ( $fileId , false )) {
$stmtadd = $mysqli -> prepare ( 'INSERT INTO FileGroups (FileID, CreatorID, ID) VALUES (?, ?, ?)' );
2024-04-26 10:52:11 +02:00
$stmtadd -> bind_param ( 'iii' , $fileId , $_SESSION [ 'ID' ], $groupId );
2024-04-11 10:36:40 +02:00
$stmtadd -> execute ();
if ( $stmtadd -> affected_rows > 0 ) {
$output [ " Status " ] = " Success " ;
}
}
}
return $output ;
2024-04-25 09:04:10 +02:00
}
2024-04-26 14:37:54 +02:00
function deleteFile ( int $fileID ) : array
2024-04-25 15:01:17 +02:00
{
2024-04-26 01:17:49 +02:00
global $mysqli ;
2024-04-25 15:01:17 +02:00
$out = [ " Status " => " Fail " ];
2024-04-26 09:46:10 +02:00
if ( isLoggedIn ()) {
2024-04-26 01:17:49 +02:00
$file_location = fileExists ( $fileID , ! isAdmin ());
$query = ! isAdmin () ? 'DELETE FROM Files WHERE ID = ? AND UploadedBy = ?' : 'DELETE FROM Files WHERE ID = ?' ;
$stmtDelete = $mysqli -> prepare ( $query );
if ( ! isAdmin ()) {
2024-04-26 10:52:11 +02:00
$stmtDelete -> bind_param ( 'ii' , $fileID , $_SESSION [ 'ID' ]);
2024-04-26 01:17:49 +02:00
} else {
$stmtDelete -> bind_param ( 'i' , $fileID );
}
$stmtDelete -> execute ();
if ( $file_location ) {
if ( unlink ( $file_location ) && $stmtDelete -> affected_rows > 0 ) {
$out [ 'Status' ] = 'Success' ;
}
2024-04-25 15:01:17 +02:00
}
}
return $out ;
2024-03-01 22:14:20 +01:00
}