324 lines
11 KiB
PHP
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';
|
|
}
|
|
}
|