上传文件至 /
This commit is contained in:
37
delete-image.php
Normal file
37
delete-image.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$image_id = $_GET['id'] ?? 0;
|
||||||
|
|
||||||
|
if ($image_id) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT filename, user_id FROM images WHERE id = ?");
|
||||||
|
$stmt->execute([$image_id]);
|
||||||
|
$image = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($image && ($_SESSION['user_id'] == $image['user_id'] || $_SESSION['username'] === 'admin')) {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM images WHERE id = ?");
|
||||||
|
$stmt->execute([$image_id]);
|
||||||
|
|
||||||
|
$file_path = 'uploads/' . $image['filename'];
|
||||||
|
if (file_exists($file_path)) {
|
||||||
|
unlink($file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['success'] = t('image_deleted_success');
|
||||||
|
} else {
|
||||||
|
$_SESSION['error'] = t('no_permission_delete');
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$_SESSION['error'] = t('delete_failed') . ': ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: dashboard.php');
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
276
feedback.php
Normal file
276
feedback.php
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$type = $_POST['type'];
|
||||||
|
$subject = trim($_POST['subject']);
|
||||||
|
$message = trim($_POST['message']);
|
||||||
|
|
||||||
|
if (empty($subject) || empty($message)) {
|
||||||
|
$error = '请填写主题和内容';
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO feedbacks (user_id, type, subject, message) VALUES (?, ?, ?, ?)");
|
||||||
|
if ($stmt->execute([$_SESSION['user_id'], $type, $subject, $message])) {
|
||||||
|
$success = '反馈提交成功!感谢您的意见。';
|
||||||
|
|
||||||
|
sendNotification(
|
||||||
|
$_SESSION['user_id'],
|
||||||
|
'feedback_result',
|
||||||
|
'反馈已收到',
|
||||||
|
"您的反馈「{$subject}」已提交成功,我们会尽快处理。",
|
||||||
|
'feedback.php'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$error = '提交失败,请稍后重试';
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$error = '系统错误:' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>意见反馈 - <?php echo SITE_NAME; ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="feedback-container">
|
||||||
|
<div class="feedback-header">
|
||||||
|
<h1><i class="fas fa-comment-dots"></i> 意见反馈</h1>
|
||||||
|
<p>您的建议对我们非常重要,我们会认真阅读每一条反馈</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if($error): ?>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> <?php echo $error; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if($success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="fas fa-check-circle"></i> <?php echo $success; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="feedback-form card">
|
||||||
|
<form method="POST" action="">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="type">
|
||||||
|
<i class="fas fa-tag"></i> 反馈类型
|
||||||
|
</label>
|
||||||
|
<select id="type" name="type" required>
|
||||||
|
<option value="bug">错误报告</option>
|
||||||
|
<option value="feature">功能建议</option>
|
||||||
|
<option value="suggestion">改进建议</option>
|
||||||
|
<option value="other">其他</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subject">
|
||||||
|
<i class="fas fa-heading"></i> 主题
|
||||||
|
</label>
|
||||||
|
<input type="text" id="subject" name="subject" required
|
||||||
|
placeholder="请简要描述您的问题或建议"
|
||||||
|
value="<?php echo isset($_POST['subject']) ? htmlspecialchars($_POST['subject']) : ''; ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="message">
|
||||||
|
<i class="fas fa-edit"></i> 详细内容
|
||||||
|
</label>
|
||||||
|
<textarea id="message" name="message" rows="8" required
|
||||||
|
placeholder="请详细描述您的问题、建议或改进想法..."><?php echo isset($_POST['message']) ? htmlspecialchars($_POST['message']) : ''; ?></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="fas fa-paper-plane"></i> 提交反馈
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feedback-info card">
|
||||||
|
<h3><i class="fas fa-info-circle"></i> 反馈说明</h3>
|
||||||
|
<div class="info-grid">
|
||||||
|
<div class="info-item">
|
||||||
|
<i class="fas fa-bug"></i>
|
||||||
|
<div>
|
||||||
|
<h4>错误报告</h4>
|
||||||
|
<p>遇到系统错误、功能异常或显示问题</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<i class="fas fa-lightbulb"></i>
|
||||||
|
<div>
|
||||||
|
<h4>功能建议</h4>
|
||||||
|
<p>希望添加的新功能或改进建议</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<i class="fas fa-cogs"></i>
|
||||||
|
<div>
|
||||||
|
<h4>改进建议</h4>
|
||||||
|
<p>对现有功能的优化和改进意见</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<i class="fas fa-question"></i>
|
||||||
|
<div>
|
||||||
|
<h4>其他反馈</h4>
|
||||||
|
<p>其他任何想要告诉我们的内容</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feedback-history card">
|
||||||
|
<h3><i class="fas fa-history"></i> 我的反馈记录</h3>
|
||||||
|
<?php
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM feedbacks WHERE user_id = ? ORDER BY created_at DESC LIMIT 5");
|
||||||
|
$stmt->execute([$_SESSION['user_id']]);
|
||||||
|
$feedbacks = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($feedbacks)) {
|
||||||
|
echo '<p class="text-muted">暂无反馈记录</p>';
|
||||||
|
} else {
|
||||||
|
echo '<div class="feedback-list">';
|
||||||
|
foreach ($feedbacks as $feedback) {
|
||||||
|
$statusClass = [
|
||||||
|
'pending' => 'status-pending',
|
||||||
|
'reviewed' => 'status-verified',
|
||||||
|
'resolved' => 'status-public'
|
||||||
|
][$feedback['status']] ?? 'status-pending';
|
||||||
|
|
||||||
|
$typeLabels = [
|
||||||
|
'bug' => '错误报告',
|
||||||
|
'feature' => '功能建议',
|
||||||
|
'suggestion' => '改进建议',
|
||||||
|
'other' => '其他'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<div class="feedback-item">
|
||||||
|
<div class="feedback-header">
|
||||||
|
<strong>' . htmlspecialchars($feedback['subject']) . '</strong>
|
||||||
|
<span class="status-badge ' . $statusClass . '">' . $feedback['status'] . '</span>
|
||||||
|
</div>
|
||||||
|
<div class="feedback-meta">
|
||||||
|
<span class="feedback-type">' . ($typeLabels[$feedback['type']] ?? $feedback['type']) . '</span>
|
||||||
|
<span class="feedback-time">' . date('Y-m-d H:i', strtotime($feedback['created_at'])) . '</span>
|
||||||
|
</div>
|
||||||
|
<div class="feedback-content">' . nl2br(htmlspecialchars($feedback['message'])) . '</div>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
echo '<p class="text-muted">加载反馈记录失败</p>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.feedback-container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.feedback-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
.feedback-header h1 {
|
||||||
|
color: var(--primary-color);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.feedback-form {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.feedback-info {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 15px;
|
||||||
|
padding: 15px;
|
||||||
|
background: var(--bg-color);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
.info-item i {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--primary-color);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.info-item h4 {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
.info-item p {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.feedback-list {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.feedback-item {
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
background: var(--bg-color);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
border-left: 4px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
.feedback-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.feedback-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.feedback-type {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
.feedback-content {
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
179
forgot-password.php
Normal file
179
forgot-password.php
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
$success = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$email = trim($_POST['email']);
|
||||||
|
$captcha = trim($_POST['captcha']);
|
||||||
|
|
||||||
|
if (empty($email)) {
|
||||||
|
$error = t('enter_email');
|
||||||
|
} elseif (CAPTCHA_ENABLED && (empty($captcha) || $captcha !== $_SESSION['captcha'])) {
|
||||||
|
$error = t('invalid_captcha');
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("SELECT id, username FROM users WHERE email = ?");
|
||||||
|
$stmt->execute([$email]);
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$token = bin2hex(random_bytes(32));
|
||||||
|
$expires_at = date('Y-m-d H:i:s', time() + PASSWORD_RESET_EXPIRE);
|
||||||
|
|
||||||
|
$pdo->prepare("DELETE FROM password_resets WHERE email = ?")->execute([$email]);
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, ?)");
|
||||||
|
|
||||||
|
if ($stmt->execute([$email, $token, $expires_at])) {
|
||||||
|
if (sendPasswordResetEmail($email, $user['username'], $token)) {
|
||||||
|
$success = t('reset_link_sent');
|
||||||
|
} else {
|
||||||
|
$reset_link = SITE_URL . "/reset-password.php?token=" . $token;
|
||||||
|
$success = t('reset_link_generated') . "<br><a href='$reset_link' style='word-break: break-all;'>$reset_link</a>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = t('system_error');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = t('email_not_registered');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo t('forgot_password'); ?> - <?php echo SITE_NAME; ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="auth-container">
|
||||||
|
<div class="auth-card card">
|
||||||
|
<h2><i class="fas fa-key"></i> <?php echo t('forgot_password'); ?></h2>
|
||||||
|
|
||||||
|
<div class="instructions card">
|
||||||
|
<h3><i class="fas fa-info-circle"></i> <?php echo t('password_reset_instructions'); ?></h3>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fas fa-envelope"></i> <?php echo t('enter_registered_email'); ?></li>
|
||||||
|
<li><i class="fas fa-link"></i> <?php echo t('reset_link_will_be_sent'); ?></li>
|
||||||
|
<li><i class="fas fa-clock"></i> <?php echo t('reset_link_expires'); ?></li>
|
||||||
|
<li><i class="fas fa-trash"></i> <?php echo t('check_spam_folder'); ?></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if($error): ?>
|
||||||
|
<div class="alert alert-error">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> <?php echo $error; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if($success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<i class="fas fa-check-circle"></i> <?php echo $success; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(strpos($success, t('reset_link_generated')) !== false): ?>
|
||||||
|
<div class="instructions card" style="background: #fff3cd; border-left-color: #ffc107;">
|
||||||
|
<h3><i class="fas fa-exclamation-triangle"></i> <?php echo t('email_send_problem'); ?></h3>
|
||||||
|
<p><?php echo t('manual_copy_instructions'); ?></p>
|
||||||
|
<p><?php echo t('contact_admin'); ?>: <a href="mailto:<?php echo SMTP_FROM_EMAIL; ?>"><?php echo SMTP_FROM_EMAIL; ?></a></p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="instructions card" style="background: #d4edda; border-left-color: #28a745;">
|
||||||
|
<h3><i class="fas fa-check-circle"></i> <?php echo t('email_sent_success'); ?></h3>
|
||||||
|
<p><?php echo t('check_email_instructions'); ?></p>
|
||||||
|
<p><?php echo t('no_email_received'); ?> <a href="#" onclick="location.reload(); return false;"><?php echo t('resend_email'); ?></a></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if(empty($success)): ?>
|
||||||
|
<form method="POST" action="">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">
|
||||||
|
<i class="fas fa-envelope"></i> <?php echo t('email'); ?>
|
||||||
|
</label>
|
||||||
|
<input type="email" id="email" name="email" required
|
||||||
|
value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : ''; ?>"
|
||||||
|
placeholder="<?php echo t('enter_registered_email'); ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if(CAPTCHA_ENABLED): ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="captcha">
|
||||||
|
<i class="fas fa-shield-alt"></i> <?php echo t('captcha'); ?>
|
||||||
|
</label>
|
||||||
|
<div class="captcha-container">
|
||||||
|
<input type="text" id="captcha" name="captcha" required maxlength="4"
|
||||||
|
placeholder="<?php echo t('enter_captcha'); ?>">
|
||||||
|
<img src="captcha.php" alt="<?php echo t('captcha'); ?>"
|
||||||
|
onclick="this.src='captcha.php?'+Math.random()"
|
||||||
|
title="<?php echo t('refresh_captcha'); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary btn-full">
|
||||||
|
<i class="fas fa-paper-plane"></i> <?php echo t('send_reset_link'); ?>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="auth-links">
|
||||||
|
<p>
|
||||||
|
<a href="login.php">
|
||||||
|
<i class="fas fa-arrow-left"></i> <?php echo t('back_to_login'); ?>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<?php echo t('no_account'); ?>
|
||||||
|
<a href="register.php">
|
||||||
|
<i class="fas fa-user-plus"></i> <?php echo t('register_now'); ?>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('email')?.focus();
|
||||||
|
|
||||||
|
document.getElementById('captcha')?.addEventListener('input', function(e) {
|
||||||
|
this.value = this.value.toUpperCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelector('form')?.addEventListener('submit', function(e) {
|
||||||
|
const email = document.getElementById('email').value;
|
||||||
|
if (!email) {
|
||||||
|
alert('<?php echo t('enter_email'); ?>');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
|
if (!emailRegex.test(email)) {
|
||||||
|
alert('<?php echo t('invalid_email'); ?>');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
<?php if(CAPTCHA_ENABLED): ?>
|
||||||
|
const captcha = document.getElementById('captcha').value;
|
||||||
|
if (!captcha) {
|
||||||
|
alert('<?php echo t('enter_captcha'); ?>');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
<?php endif; ?>
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
generate-api-key.php
Normal file
20
generate-api-key.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api_key = bin2hex(random_bytes(API_KEY_LENGTH / 2));
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET api_key = ? WHERE id = ?");
|
||||||
|
|
||||||
|
if ($stmt->execute([$api_key, $_SESSION['user_id']])) {
|
||||||
|
$_SESSION['success'] = t('api_key_generated');
|
||||||
|
} else {
|
||||||
|
$_SESSION['error'] = t('api_key_generation_failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: ' . ($_SERVER['HTTP_REFERER'] ?? 'dashboard.php'));
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
180
index.php
Normal file
180
index.php
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
$bingImage = getBingDailyImage();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT i.*, u.username,
|
||||||
|
(SELECT COUNT(*) FROM image_feedbacks WHERE image_id = i.id AND type = 'like') as like_count
|
||||||
|
FROM images i
|
||||||
|
LEFT JOIN users u ON i.user_id = u.id
|
||||||
|
WHERE i.is_public = 1
|
||||||
|
ORDER BY i.uploaded_at DESC
|
||||||
|
LIMIT 12
|
||||||
|
");
|
||||||
|
$stmt->execute();
|
||||||
|
$publicImages = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$publicImages = [];
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="<?php echo $lang; ?>" data-theme="<?php echo $currentUserSettings['dark_mode'] ? 'dark' : 'light'; ?>">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo t('site_title'); ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php include 'components/navbar.php'; ?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<?php if($bingImage): ?>
|
||||||
|
<section class="bing-daily">
|
||||||
|
<div class="card">
|
||||||
|
<div class="bing-image">
|
||||||
|
<img src="<?php echo $bingImage['url']; ?>"
|
||||||
|
alt="<?php echo htmlspecialchars($bingImage['title']); ?>"
|
||||||
|
loading="lazy">
|
||||||
|
</div>
|
||||||
|
<div class="bing-info">
|
||||||
|
<h3><i class="fas fa-camera"></i> <?php echo t('bing_daily'); ?></h3>
|
||||||
|
<p><?php echo htmlspecialchars($bingImage['title']); ?></p>
|
||||||
|
<small><?php echo htmlspecialchars($bingImage['copyright']); ?></small>
|
||||||
|
<div class="bing-actions mt-2">
|
||||||
|
<button onclick="downloadBingImage('<?php echo $bingImage['url']; ?>', '<?php echo htmlspecialchars($bingImage['title']); ?>')"
|
||||||
|
class="btn btn-sm">
|
||||||
|
<i class="fas fa-download"></i> <?php echo t('download'); ?>
|
||||||
|
</button>
|
||||||
|
<?php if($bingImage['copyrightlink']): ?>
|
||||||
|
<a href="<?php echo $bingImage['copyrightlink']; ?>" target="_blank" class="btn btn-sm btn-secondary">
|
||||||
|
<i class="fas fa-info-circle"></i> <?php echo t('view_details'); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
|
||||||
|
<header class="hero">
|
||||||
|
<h1><?php echo t('hero_title'); ?></h1>
|
||||||
|
<p><?php echo t('hero_subtitle'); ?></p>
|
||||||
|
<?php if(!$isLoggedIn): ?>
|
||||||
|
<div class="hero-buttons">
|
||||||
|
<a href="register.php" class="btn btn-primary">
|
||||||
|
<i class="fas fa-user-plus"></i> <?php echo t('register_now'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="login.php" class="btn btn-secondary">
|
||||||
|
<i class="fas fa-sign-in-alt"></i> <?php echo t('user_login'); ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<a href="upload.php" class="btn btn-primary">
|
||||||
|
<i class="fas fa-cloud-upload-alt"></i> <?php echo t('upload'); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="features">
|
||||||
|
<h2 class="text-center"><?php echo t('features'); ?></h2>
|
||||||
|
<div class="feature-grid">
|
||||||
|
<div class="feature-card card">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="fas fa-bolt"></i>
|
||||||
|
</div>
|
||||||
|
<h3><?php echo t('fast_upload'); ?></h3>
|
||||||
|
<p><?php echo t('fast_upload_desc'); ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card card">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="fas fa-shield-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3><?php echo t('secure'); ?></h3>
|
||||||
|
<p><?php echo t('secure_desc'); ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card card">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<i class="fas fa-database"></i>
|
||||||
|
</div>
|
||||||
|
<h3><?php echo t('permanent'); ?></h3>
|
||||||
|
<p><?php echo t('permanent_desc'); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if(!empty($publicImages)): ?>
|
||||||
|
<section class="gallery-section">
|
||||||
|
<h2 class="text-center"><?php echo t('gallery_showcase'); ?></h2>
|
||||||
|
<div class="gallery">
|
||||||
|
<?php foreach($publicImages as $image): ?>
|
||||||
|
<div class="gallery-item card">
|
||||||
|
<a href="view-image.php?id=<?php echo $image['id']; ?>">
|
||||||
|
<img src="uploads/<?php echo $image['filename']; ?>"
|
||||||
|
alt="<?php echo htmlspecialchars($image['title']); ?>"
|
||||||
|
loading="lazy">
|
||||||
|
</a>
|
||||||
|
<div class="image-info">
|
||||||
|
<div class="image-title">
|
||||||
|
<?php echo htmlspecialchars($image['title'] ?: t('untitled')); ?>
|
||||||
|
</div>
|
||||||
|
<div class="image-meta">
|
||||||
|
<span><i class="fas fa-user"></i> <?php echo htmlspecialchars($image['username']); ?></span>
|
||||||
|
<span><i class="fas fa-eye"></i> <?php echo $image['views']; ?></span>
|
||||||
|
<span><i class="fas fa-heart"></i> <?php echo $image['like_count']; ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="footer-content">
|
||||||
|
<p>© <?php echo date('Y'); ?> <?php echo SITE_NAME; ?>. <?php echo t('all_rights_reserved'); ?></p>
|
||||||
|
<p>
|
||||||
|
<a href="feedback.php"><i class="fas fa-comment-dots"></i> <?php echo t('feedback'); ?></a> |
|
||||||
|
<a href="about.php"><i class="fas fa-info-circle"></i> <?php echo t('about'); ?></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function downloadBingImage(url, title) {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `Bing_${title.replace(/[^a-z0-9]/gi, '_')}.jpg`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const images = document.querySelectorAll('img[loading="lazy"]');
|
||||||
|
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const img = entry.target;
|
||||||
|
img.src = img.src;
|
||||||
|
imageObserver.unobserve(img);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
images.forEach(img => imageObserver.observe(img));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user