Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d536bd3e20 | ||
|
|
ec95543395 | ||
|
|
6c8707f08b | ||
|
|
91e73b1f1d | ||
|
|
5274da2c70 |
No files matched your search
+1
-1
@@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
libmagickwand-dev \
|
libmagickwand-dev \
|
||||||
unzip \
|
unzip \
|
||||||
&& docker-php-ext-configure gd --with-jpeg --with-webp \
|
&& docker-php-ext-configure gd --with-jpeg --with-webp \
|
||||||
&& docker-php-ext-install pdo_sqlite zip gd \
|
&& docker-php-ext-install pdo_sqlite zip gd opcache \
|
||||||
&& pecl install imagick \
|
&& pecl install imagick \
|
||||||
&& docker-php-ext-enable imagick
|
&& docker-php-ext-enable imagick
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -467,7 +467,7 @@ require_once 'include/header.php';
|
|||||||
<li class="list-group-item d-flex justify-content-between align-items-center" data-id="<?php echo $bookmark['id']; ?>">
|
<li class="list-group-item d-flex justify-content-between align-items-center" data-id="<?php echo $bookmark['id']; ?>">
|
||||||
<span>
|
<span>
|
||||||
<i class="bi bi-grip-vertical sort-handle" style="cursor: move;"></i>
|
<i class="bi bi-grip-vertical sort-handle" style="cursor: move;"></i>
|
||||||
<img src="<?php echo $icon_src; ?>" class="ms-2 me-2" style="width: 16px; height: 16px;" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
<img src="<?php echo $icon_src; ?>" class="ms-2 me-2" style="width: 16px; height: 16px;" loading="lazy" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
||||||
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php if($settings['open_new_tab'] ?? '1' === '1') echo 'target="_blank"'; ?>><?php echo htmlspecialchars($bookmark['title']); ?></a>
|
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php if($settings['open_new_tab'] ?? '1' === '1') echo 'target="_blank"'; ?>><?php echo htmlspecialchars($bookmark['title']); ?></a>
|
||||||
<?php if ($bookmark['is_favorite']): ?>
|
<?php if ($bookmark['is_favorite']): ?>
|
||||||
<i class="bi bi-star-fill text-warning" title="Favorite"></i>
|
<i class="bi bi-star-fill text-warning" title="Favorite"></i>
|
||||||
|
|||||||
@@ -3,3 +3,20 @@ post_max_size = 100M
|
|||||||
memory_limit = 512M
|
memory_limit = 512M
|
||||||
max_execution_time = 300
|
max_execution_time = 300
|
||||||
extension=imagick.so
|
extension=imagick.so
|
||||||
|
|
||||||
|
[opcache]
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.memory_consumption=128
|
||||||
|
opcache.interned_strings_buffer=8
|
||||||
|
opcache.max_accelerated_files=4000
|
||||||
|
opcache.revalidate_freq=60
|
||||||
|
opcache.fast_shutdown=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
|
||||||
|
; Session configuration
|
||||||
|
session.cookie_lifetime = 86400
|
||||||
|
session.gc_maxlifetime = 86400
|
||||||
|
session.cookie_httponly = 1
|
||||||
|
session.use_strict_mode = 1
|
||||||
|
session.cookie_secure = 0
|
||||||
|
session.cookie_samesite = "Lax"
|
||||||
@@ -57,10 +57,17 @@ if ($theme === 'dark' || in_array('dark-background-active', $body_classes)) {
|
|||||||
<meta name="robots" content="noindex, nofollow">
|
<meta name="robots" content="noindex, nofollow">
|
||||||
<title><?php echo htmlspecialchars($settings['site_title'] ?? 'Bookmarkly'); ?></title>
|
<title><?php echo htmlspecialchars($settings['site_title'] ?? 'Bookmarkly'); ?></title>
|
||||||
<link rel="icon" href="<?php echo htmlspecialchars($settings['site_favicon'] ?? $settings['site_logo'] ?? 'include/images/favicon.ico'); ?>">
|
<link rel="icon" href="<?php echo htmlspecialchars($settings['site_favicon'] ?? $settings['site_logo'] ?? 'include/images/favicon.ico'); ?>">
|
||||||
|
|
||||||
|
<!-- Apple Touch Icons -->
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="<?php echo htmlspecialchars($settings['site_favicon'] ?? $settings['site_logo'] ?? 'include/images/favicon.ico'); ?>">
|
||||||
|
<link rel="apple-touch-icon" sizes="152x152" href="<?php echo htmlspecialchars($settings['site_favicon'] ?? $settings['site_logo'] ?? 'include/images/favicon.ico'); ?>">
|
||||||
|
<link rel="apple-touch-icon" sizes="120x120" href="<?php echo htmlspecialchars($settings['site_favicon'] ?? $settings['site_logo'] ?? 'include/images/favicon.ico'); ?>">
|
||||||
|
<link rel="preconnect" href="https://cdn.jsdelivr.net">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="include/css/style.css" rel="stylesheet">
|
<link href="include/css/style.css" rel="stylesheet">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
||||||
|
<script defer src="https://analytics.hibbit.cloud/script.js" data-website-id="0f6a81c8-d2f5-4849-a2d1-3eff2cb8819e"></script>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--bg-brightness: <?php echo intval($bg_brightness); ?>%;
|
--bg-brightness: <?php echo intval($bg_brightness); ?>%;
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ ini_set('session.cookie_httponly', 1);
|
|||||||
ini_set('session.use_strict_mode', 1);
|
ini_set('session.use_strict_mode', 1);
|
||||||
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
|
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0);
|
||||||
|
|
||||||
|
// Set default session cookie lifetime to 24 hours (86400 seconds)
|
||||||
|
ini_set('session.cookie_lifetime', 86400);
|
||||||
|
ini_set('session.gc_maxlifetime', 86400);
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
// The $pdo object is available from init.php which included this file.
|
// The $pdo object is available from init.php which included this file.
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ require_once 'include/header.php';
|
|||||||
?>
|
?>
|
||||||
<div class="col-lg-2 col-md-3 col-sm-4 col-6 mb-3">
|
<div class="col-lg-2 col-md-3 col-sm-4 col-6 mb-3">
|
||||||
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php echo $target_attr; ?> class="btn d-flex align-items-center text-start p-2 bookmark-link">
|
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php echo $target_attr; ?> class="btn d-flex align-items-center text-start p-2 bookmark-link">
|
||||||
<img src="<?php echo $icon_src; ?>" alt="" class="bookmark-favorite-icon me-3" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
<img src="<?php echo $icon_src; ?>" alt="" class="bookmark-favorite-icon me-3" loading="lazy" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
||||||
<div>
|
<div>
|
||||||
<span><?php echo htmlspecialchars($bookmark['title']); ?></span>
|
<span><?php echo htmlspecialchars($bookmark['title']); ?></span>
|
||||||
<small class="d-block text-muted"><?php echo htmlspecialchars($display_url); ?></small>
|
<small class="d-block text-muted"><?php echo htmlspecialchars($display_url); ?></small>
|
||||||
@@ -209,7 +209,7 @@ require_once 'include/header.php';
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php echo $target_attr; ?> class="list-group-item list-group-item-action d-flex align-items-center">
|
<a href="<?php echo htmlspecialchars($bookmark['url']); ?>" <?php echo $target_attr; ?> class="list-group-item list-group-item-action d-flex align-items-center">
|
||||||
<img src="<?php echo $icon_src; ?>" alt="" class="bookmark-icon me-2" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
<img src="<?php echo $icon_src; ?>" alt="" class="bookmark-icon me-2" loading="lazy" onerror="this.onerror=null;this.src='include/images/default-icon.png';">
|
||||||
<span><?php echo htmlspecialchars($bookmark['title']); ?></span>
|
<span><?php echo htmlspecialchars($bookmark['title']); ?></span>
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ return [
|
|||||||
'modal_category' => 'Category',
|
'modal_category' => 'Category',
|
||||||
'modal_select_category' => 'Select a category...',
|
'modal_select_category' => 'Select a category...',
|
||||||
'modal_icon_url' => 'Icon URL (optional)',
|
'modal_icon_url' => 'Icon URL (optional)',
|
||||||
'modal_icon_url_help' => 'Find icons at <a href="https://selfh.st/icons/" target="_blank">selfh.st/icons</a> and <a href="https://dashboardicons.com/icons" target="_blank">dashboardicons.com/icons</a>.',
|
'modal_icon_url_help' => 'Find icons at <a href="https://selfh.st/icons/" target="_blank">selfh.st</a> and <a href="https://dashboardicons.com/icons" target="_blank">dashboardicons.com/icons</a>.',
|
||||||
'modal_icon_upload' => 'Upload Icon (optional)',
|
'modal_icon_upload' => 'Upload Icon (optional)',
|
||||||
'modal_current_icon' => 'Current Icon',
|
'modal_current_icon' => 'Current Icon',
|
||||||
'modal_remove_icon_button' => 'Remove Custom Icon',
|
'modal_remove_icon_button' => 'Remove Custom Icon',
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$seconds = 14 * 24 * 60 * 60; // Default to 2 weeks
|
$seconds = 14 * 24 * 60 * 60; // Default to 2 weeks
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set session cookie lifetime
|
// Update session cookie with extended lifetime
|
||||||
ini_set('session.cookie_lifetime', $seconds);
|
|
||||||
ini_set('session.gc_maxlifetime', $seconds);
|
|
||||||
|
|
||||||
// Update session cookie with new lifetime
|
|
||||||
$params = session_get_cookie_params();
|
$params = session_get_cookie_params();
|
||||||
setcookie(session_name(), session_id(), time() + $seconds, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
setcookie(session_name(), session_id(), time() + $seconds, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||||
|
} else {
|
||||||
|
// For normal login, set cookie to expire at end of browser session
|
||||||
|
$params = session_get_cookie_params();
|
||||||
|
setcookie(session_name(), session_id(), 0, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Location: index.php');
|
header('Location: index.php');
|
||||||
|
|||||||
+123
-1
@@ -6,6 +6,86 @@ $GLOBALS['body_class'] = 'settings-page';
|
|||||||
|
|
||||||
require_once 'include/auth.php';
|
require_once 'include/auth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize an image while maintaining aspect ratio and transparency
|
||||||
|
* @param string $source_path Path to source image
|
||||||
|
* @param string $destination_path Path to save resized image
|
||||||
|
* @param int $max_width Maximum width
|
||||||
|
* @param int $max_height Maximum height
|
||||||
|
* @param string $extension File extension
|
||||||
|
* @return bool Success status
|
||||||
|
*/
|
||||||
|
function resizeImage($source_path, $destination_path, $max_width, $max_height, $extension) {
|
||||||
|
// Get original image dimensions
|
||||||
|
$image_info = getimagesize($source_path);
|
||||||
|
if ($image_info === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$original_width = $image_info[0];
|
||||||
|
$original_height = $image_info[1];
|
||||||
|
|
||||||
|
// Calculate new dimensions maintaining aspect ratio
|
||||||
|
$ratio = min($max_width / $original_width, $max_height / $original_height);
|
||||||
|
$new_width = round($original_width * $ratio);
|
||||||
|
$new_height = round($original_height * $ratio);
|
||||||
|
|
||||||
|
// Create image resource based on file type
|
||||||
|
switch (strtolower($extension)) {
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
$source_image = imagecreatefromjpeg($source_path);
|
||||||
|
break;
|
||||||
|
case 'png':
|
||||||
|
$source_image = imagecreatefrompng($source_path);
|
||||||
|
break;
|
||||||
|
case 'gif':
|
||||||
|
$source_image = imagecreatefromgif($source_path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($source_image === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new image with transparency support
|
||||||
|
$new_image = imagecreatetruecolor($new_width, $new_height);
|
||||||
|
|
||||||
|
// Preserve transparency for PNG and GIF
|
||||||
|
if ($extension === 'png' || $extension === 'gif') {
|
||||||
|
imagealphablending($new_image, false);
|
||||||
|
imagesavealpha($new_image, true);
|
||||||
|
$transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127);
|
||||||
|
imagefilledrectangle($new_image, 0, 0, $new_width, $new_height, $transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the image
|
||||||
|
imagecopyresampled($new_image, $source_image, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height);
|
||||||
|
|
||||||
|
// Save the resized image
|
||||||
|
$result = false;
|
||||||
|
switch (strtolower($extension)) {
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
$result = imagejpeg($new_image, $destination_path, 90);
|
||||||
|
break;
|
||||||
|
case 'png':
|
||||||
|
$result = imagepng($new_image, $destination_path, 9);
|
||||||
|
break;
|
||||||
|
case 'gif':
|
||||||
|
$result = imagegif($new_image, $destination_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up memory
|
||||||
|
imagedestroy($source_image);
|
||||||
|
imagedestroy($new_image);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
// Flash messages for feedback
|
// Flash messages for feedback
|
||||||
$message = '';
|
$message = '';
|
||||||
$message_type = '';
|
$message_type = '';
|
||||||
@@ -68,11 +148,45 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if (in_array($favicon_ext, $allowed_favicon_ext)) {
|
if (in_array($favicon_ext, $allowed_favicon_ext)) {
|
||||||
$favicon_filename = 'favicon.' . $favicon_ext;
|
$favicon_filename = 'favicon.' . $favicon_ext;
|
||||||
$favicon_path = $uploadDir . $favicon_filename;
|
$favicon_path = $uploadDir . $favicon_filename;
|
||||||
|
|
||||||
|
// Check if it's an image file (not SVG or ICO)
|
||||||
|
if (in_array($favicon_ext, ['png', 'jpg', 'jpeg', 'gif'])) {
|
||||||
|
// Get image dimensions
|
||||||
|
$image_info = getimagesize($_FILES['site_favicon']['tmp_name']);
|
||||||
|
if ($image_info === false) {
|
||||||
|
$_SESSION['flash_message'] = ['text' => 'Invalid image file for favicon.', 'type' => 'danger'];
|
||||||
|
} else {
|
||||||
|
$width = $image_info[0];
|
||||||
|
$height = $image_info[1];
|
||||||
|
|
||||||
|
// Validate dimensions (minimum 180x180, maximum 256x256)
|
||||||
|
if ($width < 180 || $height < 180) {
|
||||||
|
$_SESSION['flash_message'] = ['text' => 'Favicon must be at least 180x180 pixels for Apple Touch Icon compatibility.', 'type' => 'danger'];
|
||||||
|
} elseif ($width > 256 || $height > 256) {
|
||||||
|
// Resize if too large
|
||||||
|
if (resizeImage($_FILES['site_favicon']['tmp_name'], $favicon_path, 256, 256, $favicon_ext)) {
|
||||||
|
$upsert_stmt->execute(['site_favicon', $favicon_path . '?v=' . time()]);
|
||||||
|
$_SESSION['flash_message'] = ['text' => 'Favicon uploaded and resized to 256x256 pixels for optimal Apple Touch Icon compatibility.', 'type' => 'success'];
|
||||||
|
} else {
|
||||||
|
$_SESSION['flash_message'] = ['text' => 'Failed to resize favicon.', 'type' => 'danger'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Size is acceptable, just move the file
|
||||||
if (move_uploaded_file($_FILES['site_favicon']['tmp_name'], $favicon_path)) {
|
if (move_uploaded_file($_FILES['site_favicon']['tmp_name'], $favicon_path)) {
|
||||||
$upsert_stmt->execute(['site_favicon', $favicon_path . '?v=' . time()]);
|
$upsert_stmt->execute(['site_favicon', $favicon_path . '?v=' . time()]);
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['flash_message'] = ['text' => 'Failed to move uploaded favicon.', 'type' => 'danger'];
|
$_SESSION['flash_message'] = ['text' => 'Failed to move uploaded favicon.', 'type' => 'danger'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For SVG and ICO files, just move them without resizing
|
||||||
|
if (move_uploaded_file($_FILES['site_favicon']['tmp_name'], $favicon_path)) {
|
||||||
|
$upsert_stmt->execute(['site_favicon', $favicon_path . '?v=' . time()]);
|
||||||
|
} else {
|
||||||
|
$_SESSION['flash_message'] = ['text' => 'Failed to move uploaded favicon.', 'type' => 'danger'];
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['flash_message'] = ['text' => 'Invalid file type for favicon.', 'type' => 'danger'];
|
$_SESSION['flash_message'] = ['text' => 'Invalid file type for favicon.', 'type' => 'danger'];
|
||||||
}
|
}
|
||||||
@@ -277,7 +391,15 @@ require_once 'include/header.php';
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="site_favicon" class="form-label">Site Favicon</label>
|
<label for="site_favicon" class="form-label">Site Favicon</label>
|
||||||
<input type="file" class="form-control" id="site_favicon" name="site_favicon">
|
<input type="file" class="form-control" id="site_favicon" name="site_favicon" accept="image/png,image/jpeg,image/gif,image/svg+xml,image/x-icon">
|
||||||
|
<div class="form-text">
|
||||||
|
<strong>Apple Touch Icon Requirements:</strong><br>
|
||||||
|
• Minimum size: 180x180 pixels<br>
|
||||||
|
• Maximum size: 256x256 pixels<br>
|
||||||
|
• Supported formats: PNG, JPG, GIF, SVG, ICO<br>
|
||||||
|
• Images larger than 256x256 will be automatically resized<br>
|
||||||
|
• Images smaller than 180x180 will be rejected
|
||||||
|
</div>
|
||||||
<?php if (!empty($settings['site_favicon'])): ?>
|
<?php if (!empty($settings['site_favicon'])): ?>
|
||||||
<small class="form-text text-muted d-block mt-2">Current favicon: <img src="<?php echo htmlspecialchars($settings['site_favicon']); ?>" alt="Current Favicon" style="max-height: 16px; vertical-align: middle;"></small>
|
<small class="form-text text-muted d-block mt-2">Current favicon: <img src="<?php echo htmlspecialchars($settings['site_favicon']); ?>" alt="Current Favicon" style="max-height: 16px; vertical-align: middle;"></small>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
Reference in new issue
Block a user