Files
ITL-Huge/application/model/GalleryModel.php
2026-01-26 10:37:06 +01:00

324 lines
11 KiB
PHP

<?php
class GalleryModel
{
private static $cipher = 'AES-256-CBC';
public static function getAllImages($user_id = null, $page = 1, $per_page = 20)
{
$database = DatabaseFactory::getFactory()->getConnection();
$offset = ($page - 1) * $per_page;
if ($user_id) {
$sql = "SELECT g.*, u.user_name
FROM gallery g
JOIN users u ON g.user_id = u.user_id
WHERE g.user_id = :user_id
ORDER BY g.created_at DESC
LIMIT :offset, :per_page";
$query = $database->prepare($sql);
$query->bindParam(':user_id', $user_id, PDO::PARAM_INT);
} else {
$sql = "SELECT g.*, u.user_name
FROM gallery g
JOIN users u ON g.user_id = u.user_id
WHERE g.is_public = 1
ORDER BY g.created_at DESC
LIMIT :offset, :per_page";
$query = $database->prepare($sql);
}
$query->bindParam(':offset', $offset, PDO::PARAM_INT);
$query->bindParam(':per_page', $per_page, PDO::PARAM_INT);
$query->execute();
return $query->fetchAll(PDO::FETCH_OBJ);
}
public static function getImageCount($user_id = null)
{
$database = DatabaseFactory::getFactory()->getConnection();
if ($user_id) {
$sql = "SELECT COUNT(*) as count FROM gallery WHERE user_id = :user_id";
$query = $database->prepare($sql);
$query->execute(array(':user_id' => $user_id));
} else {
$sql = "SELECT COUNT(*) as count FROM gallery WHERE is_public = 1";
$query = $database->prepare($sql);
$query->execute();
}
$result = $query->fetch(PDO::FETCH_ASSOC);
return (int)$result['count'];
}
public static function getImage($image_id)
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SELECT g.*, u.user_name
FROM gallery g
JOIN users u ON g.user_id = u.user_id
WHERE g.id = :image_id LIMIT 1";
$query = $database->prepare($sql);
$query->execute(array(':image_id' => $image_id));
return $query->fetch(PDO::FETCH_OBJ);
}
public static function uploadImage($file, $title, $description, $is_public)
{
$user_id = Session::get('user_id');
if (!$user_id) {
Session::add('feedback_negative', 'You must be logged in to upload');
return false;
}
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($file['type'], $allowed_types)) {
Session::add('feedback_negative', 'Invalid file type. Allowed: JPG, PNG, GIF, WebP');
return false;
}
$max_size = 10 * 1024 * 1024;
if ($file['size'] > $max_size) {
Session::add('feedback_negative', 'File too large. Maximum size: 10MB');
return false;
}
$image_data = file_get_contents($file['tmp_name']);
if ($image_data === false) {
Session::add('feedback_negative', 'Failed to read uploaded file');
return false;
}
$thumb_data = self::createThumbnailData($file['tmp_name'], $file['type'], 300);
if (!$thumb_data) {
Session::add('feedback_negative', 'Failed to create thumbnail');
return false;
}
$encryption_key = bin2hex(random_bytes(32));
$iv = random_bytes(openssl_cipher_iv_length(self::$cipher));
$encrypted_image = openssl_encrypt($image_data, self::$cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
$encrypted_thumb = openssl_encrypt($thumb_data, self::$cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
$encrypted_image = base64_encode($iv . $encrypted_image);
$encrypted_thumb = base64_encode($iv . $encrypted_thumb);
$upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$filename = uniqid('enc_') . '_' . time() . '.bin';
$thumb_filename = 'thumb_' . $filename;
if (file_put_contents($upload_dir . $filename, $encrypted_image) === false) {
Session::add('feedback_negative', 'Failed to save encrypted image');
return false;
}
if (file_put_contents($upload_dir . $thumb_filename, $encrypted_thumb) === false) {
unlink($upload_dir . $filename);
Session::add('feedback_negative', 'Failed to save encrypted thumbnail');
return false;
}
try {
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "INSERT INTO gallery (user_id, filename, thumb_filename, title, description, is_public, file_size, mime_type, encryption_key)
VALUES (:user_id, :filename, :thumb_filename, :title, :description, :is_public, :file_size, :mime_type, :encryption_key)";
$query = $database->prepare($sql);
$result = $query->execute(array(
':user_id' => $user_id,
':filename' => $filename,
':thumb_filename' => $thumb_filename,
':title' => $title ?: pathinfo($file['name'], PATHINFO_FILENAME),
':description' => $description,
':is_public' => $is_public ? 1 : 0,
':file_size' => $file['size'],
':mime_type' => $file['type'],
':encryption_key' => $encryption_key
));
if ($result) {
return $database->lastInsertId();
}
unlink($upload_dir . $filename);
unlink($upload_dir . $thumb_filename);
Session::add('feedback_negative', 'Failed to save to database');
return false;
} catch (PDOException $e) {
unlink($upload_dir . $filename);
unlink($upload_dir . $thumb_filename);
Session::add('feedback_negative', 'Database error: ' . $e->getMessage());
return false;
}
}
public static function getDecryptedImage($image_id, $thumbnail = false)
{
$image = self::getImage($image_id);
if (!$image) {
return null;
}
$upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
$filename = $thumbnail ? $image->thumb_filename : $image->filename;
$filepath = $upload_dir . $filename;
if (!file_exists($filepath)) {
return null;
}
$encrypted_data = file_get_contents($filepath);
if ($encrypted_data === false) {
return null;
}
$encrypted_data = base64_decode($encrypted_data);
$iv_length = openssl_cipher_iv_length(self::$cipher);
$iv = substr($encrypted_data, 0, $iv_length);
$encrypted_data = substr($encrypted_data, $iv_length);
$decrypted = openssl_decrypt($encrypted_data, self::$cipher, $image->encryption_key, OPENSSL_RAW_DATA, $iv);
return array(
'data' => $decrypted,
'mime_type' => $image->mime_type
);
}
public static function updateImage($image_id, $title, $description, $is_public)
{
$user_id = Session::get('user_id');
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "UPDATE gallery SET title = :title, description = :description, is_public = :is_public
WHERE id = :image_id AND user_id = :user_id";
$query = $database->prepare($sql);
return $query->execute(array(
':image_id' => $image_id,
':user_id' => $user_id,
':title' => $title,
':description' => $description,
':is_public' => $is_public ? 1 : 0
));
}
public static function deleteImage($image_id)
{
$user_id = Session::get('user_id');
$image = self::getImage($image_id);
if (!$image || $image->user_id != $user_id) {
return false;
}
$upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
$filepath = $upload_dir . $image->filename;
$thumbpath = $upload_dir . $image->thumb_filename;
if (file_exists($filepath)) {
unlink($filepath);
}
if (file_exists($thumbpath)) {
unlink($thumbpath);
}
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "DELETE FROM gallery WHERE id = :image_id AND user_id = :user_id";
$query = $database->prepare($sql);
return $query->execute(array(':image_id' => $image_id, ':user_id' => $user_id));
}
private static function createThumbnailData($source, $mime_type, $max_size)
{
$image_info = getimagesize($source);
if (!$image_info) {
return false;
}
$width = $image_info[0];
$height = $image_info[1];
$type = $image_info[2];
switch ($type) {
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($source);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($source);
break;
case IMAGETYPE_GIF:
$image = imagecreatefromgif($source);
break;
case IMAGETYPE_WEBP:
$image = imagecreatefromwebp($source);
break;
default:
return false;
}
if (!$image) {
return false;
}
$ratio = min($max_size / $width, $max_size / $height);
if ($ratio >= 1) {
$new_width = $width;
$new_height = $height;
} else {
$new_width = (int)($width * $ratio);
$new_height = (int)($height * $ratio);
}
$thumb = imagecreatetruecolor($new_width, $new_height);
if ($type == IMAGETYPE_PNG || $type == IMAGETYPE_GIF) {
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
$transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
imagefilledrectangle($thumb, 0, 0, $new_width, $new_height, $transparent);
}
imagecopyresampled($thumb, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
ob_start();
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($thumb, null, 85);
break;
case IMAGETYPE_PNG:
imagepng($thumb, null, 8);
break;
case IMAGETYPE_GIF:
imagegif($thumb);
break;
case IMAGETYPE_WEBP:
imagewebp($thumb, null, 85);
break;
}
$thumb_data = ob_get_clean();
return $thumb_data;
}
public static function formatFileSize($bytes)
{
if ($bytes >= 1048576) {
return number_format($bytes / 1048576, 2) . ' MB';
} elseif ($bytes >= 1024) {
return number_format($bytes / 1024, 2) . ' KB';
}
return $bytes . ' bytes';
}
}