402 lines
14 KiB
PHP
402 lines
14 KiB
PHP
<?php
|
||
session_start();
|
||
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', 1);
|
||
|
||
use PHPMailer\PHPMailer\PHPMailer;
|
||
use PHPMailer\PHPMailer\SMTP;
|
||
use PHPMailer\PHPMailer\Exception;
|
||
|
||
require_once 'phpmailer/src/Exception.php';
|
||
require_once 'phpmailer/src/PHPMailer.php';
|
||
require_once 'phpmailer/src/SMTP.php';
|
||
|
||
define('DB_HOST', 'HOST');
|
||
define('DB_NAME', 'NAME');
|
||
define('DB_USER', 'USER');
|
||
define('DB_PASS', 'PASS');
|
||
|
||
define('SITE_URL', 'WEB');
|
||
define('SITE_NAME', 'SITE');
|
||
define('MAX_FILE_SIZE', 5 * 1024 * 1024);
|
||
define('ALLOWED_TYPES', ['jpg', 'jpeg', 'png', 'gif', 'webp']);
|
||
define('API_KEY_LENGTH', 32);
|
||
|
||
define('SMTP_HOST', 'EHOST');
|
||
define('SMTP_PORT', NUM);
|
||
define('SMTP_USERNAME', 'EUSER');
|
||
define('SMTP_PASSWORD', 'PASS');
|
||
define('SMTP_FROM_EMAIL', 'FUSER');
|
||
define('SMTP_FROM_NAME', 'FNAME');
|
||
define('SMTP_SECURE', 'SECURE');
|
||
define('SMTP_DEBUG', false);
|
||
|
||
define('BING_API_URL', 'https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN');
|
||
|
||
define('CAPTCHA_ENABLED', true);
|
||
define('PASSWORD_RESET_EXPIRE', 3600);
|
||
|
||
define('DEFAULT_LANGUAGE', 'zh-CN');
|
||
$supported_languages = ['zh-CN', 'en'];
|
||
|
||
try {
|
||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS);
|
||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||
} catch(PDOException $e) {
|
||
die("数据库连接失败: " . $e->getMessage());
|
||
}
|
||
|
||
if (!file_exists('uploads')) {
|
||
mkdir('uploads', 0755, true);
|
||
file_put_contents('uploads/index.html', '');
|
||
file_put_contents('uploads/.htaccess', 'Deny from all');
|
||
}
|
||
if (!file_exists('languages')) mkdir('languages', 0755, true);
|
||
if (!file_exists('admin')) mkdir('admin', 0755, true);
|
||
if (!file_exists('components')) mkdir('components', 0755, true);
|
||
if (!file_exists('api')) mkdir('api', 0755, true);
|
||
|
||
function getLanguage() {
|
||
global $supported_languages;
|
||
|
||
if (isset($_SESSION['language'])) {
|
||
return $_SESSION['language'];
|
||
}
|
||
|
||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||
$browser_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
|
||
if ($browser_lang === 'zh') return 'zh-CN';
|
||
if ($browser_lang === 'en') return 'en';
|
||
}
|
||
|
||
return DEFAULT_LANGUAGE;
|
||
}
|
||
|
||
function loadLanguage($lang) {
|
||
$lang_file = "languages/{$lang}.php";
|
||
if (file_exists($lang_file)) {
|
||
return include $lang_file;
|
||
}
|
||
return include "languages/" . DEFAULT_LANGUAGE . ".php";
|
||
}
|
||
|
||
$lang = getLanguage();
|
||
$translations = loadLanguage($lang);
|
||
$_SESSION['language'] = $lang;
|
||
|
||
function t($key) {
|
||
global $translations;
|
||
return $translations[$key] ?? $key;
|
||
}
|
||
|
||
function getUserSettings($user_id) {
|
||
global $pdo;
|
||
|
||
$stmt = $pdo->prepare("SELECT * FROM user_settings WHERE user_id = ?");
|
||
$stmt->execute([$user_id]);
|
||
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$settings) {
|
||
$stmt = $pdo->prepare("INSERT INTO user_settings (user_id) VALUES (?)");
|
||
$stmt->execute([$user_id]);
|
||
return [
|
||
'dark_mode' => false,
|
||
'language' => 'zh-CN',
|
||
'items_per_page' => 20,
|
||
'email_notifications' => true,
|
||
'browser_notifications' => true
|
||
];
|
||
}
|
||
|
||
return $settings;
|
||
}
|
||
|
||
function updateUserSettings($user_id, $settings) {
|
||
global $pdo;
|
||
|
||
$stmt = $pdo->prepare("INSERT INTO user_settings (user_id, dark_mode, language, items_per_page, email_notifications, browser_notifications)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
ON DUPLICATE KEY UPDATE
|
||
dark_mode = VALUES(dark_mode),
|
||
language = VALUES(language),
|
||
items_per_page = VALUES(items_per_page),
|
||
email_notifications = VALUES(email_notifications),
|
||
browser_notifications = VALUES(browser_notifications)");
|
||
|
||
return $stmt->execute([
|
||
$user_id,
|
||
$settings['dark_mode'] ? 1 : 0,
|
||
$settings['language'],
|
||
$settings['items_per_page'],
|
||
$settings['email_notifications'] ? 1 : 0,
|
||
$settings['browser_notifications'] ? 1 : 0
|
||
]);
|
||
}
|
||
|
||
function getUserNotificationSettings($user_id) {
|
||
global $pdo;
|
||
|
||
$stmt = $pdo->prepare("SELECT nt.name, uns.enabled FROM user_notification_settings uns
|
||
JOIN notification_types nt ON uns.notification_type_id = nt.id
|
||
WHERE uns.user_id = ?");
|
||
$stmt->execute([$user_id]);
|
||
$settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||
|
||
if (empty($settings)) {
|
||
initUserNotificationSettings($user_id);
|
||
return getUserNotificationSettings($user_id);
|
||
}
|
||
|
||
return $settings;
|
||
}
|
||
|
||
function initUserNotificationSettings($user_id) {
|
||
global $pdo;
|
||
$stmt = $pdo->prepare("INSERT INTO user_notification_settings (user_id, notification_type_id, enabled)
|
||
SELECT ?, id, TRUE FROM notification_types");
|
||
return $stmt->execute([$user_id]);
|
||
}
|
||
|
||
function updateUserNotificationSettings($user_id, $settings) {
|
||
global $pdo;
|
||
|
||
foreach ($settings as $type_id => $enabled) {
|
||
$stmt = $pdo->prepare("INSERT INTO user_notification_settings (user_id, notification_type_id, enabled)
|
||
VALUES (?, ?, ?)
|
||
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled)");
|
||
$stmt->execute([$user_id, $type_id, $enabled ? 1 : 0]);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function sendNotification($user_id, $type_name, $title, $message, $related_url = null) {
|
||
global $pdo;
|
||
|
||
$stmt = $pdo->prepare("SELECT uns.enabled FROM user_notification_settings uns
|
||
JOIN notification_types nt ON uns.notification_type_id = nt.id
|
||
WHERE uns.user_id = ? AND nt.name = ?");
|
||
$stmt->execute([$user_id, $type_name]);
|
||
$setting = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$setting || !$setting['enabled']) return false;
|
||
|
||
$stmt = $pdo->prepare("SELECT id FROM notification_types WHERE name = ?");
|
||
$stmt->execute([$type_name]);
|
||
$type = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$type) return false;
|
||
|
||
$stmt = $pdo->prepare("INSERT INTO notifications (user_id, type_id, title, message, related_url)
|
||
VALUES (?, ?, ?, ?, ?)");
|
||
return $stmt->execute([$user_id, $type['id'], $title, $message, $related_url]);
|
||
}
|
||
|
||
function getUnreadNotificationCount($user_id) {
|
||
global $pdo;
|
||
$stmt = $pdo->prepare("SELECT COUNT(*) as count FROM notifications WHERE user_id = ? AND is_read = FALSE");
|
||
$stmt->execute([$user_id]);
|
||
return $stmt->fetch(PDO::FETCH_ASSOC)['count'];
|
||
}
|
||
|
||
function getUserNotifications($user_id, $limit = 10) {
|
||
global $pdo;
|
||
$stmt = $pdo->prepare("SELECT n.*, nt.name as type_name FROM notifications n
|
||
JOIN notification_types nt ON n.type_id = nt.id
|
||
WHERE n.user_id = ?
|
||
ORDER BY n.created_at DESC
|
||
LIMIT ?");
|
||
$stmt->bindValue(1, $user_id, PDO::PARAM_INT);
|
||
$stmt->bindValue(2, $limit, PDO::PARAM_INT);
|
||
$stmt->execute();
|
||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
}
|
||
|
||
function generateRandomString($length = 10) {
|
||
return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||
ceil($length / strlen($x)))), 1, $length);
|
||
}
|
||
|
||
function formatFileSize($bytes) {
|
||
if ($bytes >= 1073741824) return number_format($bytes / 1073741824, 2) . ' GB';
|
||
elseif ($bytes >= 1048576) return number_format($bytes / 1048576, 2) . ' MB';
|
||
elseif ($bytes >= 1024) return number_format($bytes / 1024, 2) . ' KB';
|
||
else return $bytes . ' bytes';
|
||
}
|
||
|
||
function getBingDailyImage() {
|
||
$response = @file_get_contents(BING_API_URL);
|
||
if ($response) {
|
||
$data = json_decode($response, true);
|
||
if ($data && isset($data['images'][0])) {
|
||
$image = $data['images'][0];
|
||
return [
|
||
'url' => 'https://www.bing.com' . $image['url'],
|
||
'title' => $image['title'],
|
||
'copyright' => $image['copyright'],
|
||
'copyrightlink' => $image['copyrightlink']
|
||
];
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function sendEmail($to, $subject, $message) {
|
||
$mail = new PHPMailer(true);
|
||
|
||
try {
|
||
// 服务器设置
|
||
$mail->isSMTP();
|
||
$mail->Host = SMTP_HOST;
|
||
$mail->SMTPAuth = true;
|
||
$mail->Username = SMTP_USERNAME;
|
||
$mail->Password = SMTP_PASSWORD;
|
||
$mail->SMTPSecure = SMTP_SECURE;
|
||
$mail->Port = SMTP_PORT;
|
||
|
||
if (SMTP_DEBUG) {
|
||
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
|
||
}
|
||
|
||
// 收件人
|
||
$mail->setFrom(SMTP_FROM_EMAIL, SMTP_FROM_NAME);
|
||
$mail->addAddress($to);
|
||
|
||
// 内容
|
||
$mail->isHTML(true);
|
||
$mail->Subject = $subject;
|
||
$mail->Body = $message;
|
||
$mail->AltBody = strip_tags($message);
|
||
|
||
return $mail->send();
|
||
|
||
} catch (Exception $e) {
|
||
error_log("邮件发送失败: " . $mail->ErrorInfo);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
function sendVerificationEmail($email, $username, $verification_code) {
|
||
$verification_link = SITE_URL . "/verify.php?code=" . $verification_code;
|
||
|
||
$subject = SITE_NAME . " - 邮箱验证";
|
||
$message = "
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset='utf-8'>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: #3498db; color: white; padding: 20px; text-align: center; }
|
||
.content { padding: 20px; background: #f9f9f9; }
|
||
.button { display: inline-block; padding: 12px 24px; background: #3498db; color: white; text-decoration: none; border-radius: 5px; }
|
||
.footer { text-align: center; padding: 20px; color: #666; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class='container'>
|
||
<div class='header'>
|
||
<h1>" . SITE_NAME . "</h1>
|
||
</div>
|
||
<div class='content'>
|
||
<h2>亲爱的 {$username},</h2>
|
||
<p>感谢您注册" . SITE_NAME . "图床!</p>
|
||
<p>请点击下面的按钮验证您的邮箱地址:</p>
|
||
<p style='text-align: center;'>
|
||
<a href='{$verification_link}' class='button'>验证邮箱</a>
|
||
</p>
|
||
<p>如果按钮无法点击,请复制以下链接到浏览器地址栏:</p>
|
||
<p><small>{$verification_link}</small></p>
|
||
<p>此验证链接 24 小时内有效。</p>
|
||
</div>
|
||
<div class='footer'>
|
||
<p>© " . date('Y') . " " . SITE_NAME . ". 保留所有权利.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>";
|
||
|
||
return sendEmail($email, $subject, $message);
|
||
}
|
||
|
||
function sendPasswordResetEmail($email, $username, $token) {
|
||
$reset_link = SITE_URL . "/reset-password.php?token=" . $token;
|
||
|
||
$subject = SITE_NAME . " - 密码重置";
|
||
$message = "
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset='utf-8'>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
||
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
||
.header { background: #e74c3c; color: white; padding: 20px; text-align: center; }
|
||
.content { padding: 20px; background: #f9f9f9; }
|
||
.button { display: inline-block; padding: 12px 24px; background: #e74c3c; color: white; text-decoration: none; border-radius: 5px; }
|
||
.footer { text-align: center; padding: 20px; color: #666; }
|
||
.warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 10px; border-radius: 5px; margin: 15px 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class='container'>
|
||
<div class='header'>
|
||
<h1>" . SITE_NAME . " - 密码重置</h1>
|
||
</div>
|
||
<div class='content'>
|
||
<h2>亲爱的 {$username},</h2>
|
||
<p>我们收到了您重置密码的请求。</p>
|
||
<p>请点击下面的按钮重置您的密码:</p>
|
||
<p style='text-align: center;'>
|
||
<a href='{$reset_link}' class='button'>重置密码</a>
|
||
</p>
|
||
<p>如果按钮无法点击,请复制以下链接到浏览器地址栏:</p>
|
||
<p><small>{$reset_link}</small></p>
|
||
<div class='warning'>
|
||
<strong>注意:</strong>此链接在 <font color='red'>1</font> 小时内有效。如果您没有请求重置密码,请忽略此邮件。
|
||
</div>
|
||
</div>
|
||
<div class='footer'>
|
||
<p>© " . date('Y') . " " . SITE_NAME . ". 保留所有权利.</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>";
|
||
|
||
return sendEmail($email, $subject, $message);
|
||
}
|
||
|
||
function sendEmailNotification($user_id, $subject, $message) {
|
||
global $pdo;
|
||
|
||
// 获取用户邮箱和设置
|
||
$stmt = $pdo->prepare("
|
||
SELECT u.email, us.email_notifications
|
||
FROM users u
|
||
LEFT JOIN user_settings us ON u.id = us.user_id
|
||
WHERE u.id = ?
|
||
");
|
||
$stmt->execute([$user_id]);
|
||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$user || !$user['email_notifications']) {
|
||
return false;
|
||
}
|
||
|
||
return sendEmail($user['email'], $subject, $message);
|
||
}
|
||
|
||
$currentUserSettings = isset($_SESSION['user_id']) ? getUserSettings($_SESSION['user_id']) : [
|
||
'dark_mode' => false,
|
||
'language' => $lang,
|
||
'items_per_page' => 20,
|
||
'email_notifications' => true,
|
||
'browser_notifications' => true
|
||
];
|
||
|
||
if (!isset($_SESSION['user_id'])) {
|
||
$currentUserSettings['dark_mode'] = isset($_COOKIE['dark_mode']) ? (bool)$_COOKIE['dark_mode'] : false;
|
||
$currentUserSettings['language'] = $lang;
|
||
}
|
||
?>
|