From f2106c2fbf2f4e778dbf400ad0ac3732f1aaaee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B0=8F=E7=99=BD=E5=93=A6?= Date: Sun, 30 Nov 2025 13:05:45 +0000 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- about.php | 286 +++++++++++++++++++++++++++++++++++ api-docs.php | 152 +++++++++++++++++++ captcha.php | 43 ++++++ config.php | 402 ++++++++++++++++++++++++++++++++++++++++++++++++++ dashboard.php | 282 +++++++++++++++++++++++++++++++++++ 5 files changed, 1165 insertions(+) create mode 100644 about.php create mode 100644 api-docs.php create mode 100644 captcha.php create mode 100644 config.php create mode 100644 dashboard.php diff --git a/about.php b/about.php new file mode 100644 index 0000000..0071838 --- /dev/null +++ b/about.php @@ -0,0 +1,286 @@ + + + + + + + + 关于我们 - <?php echo SITE_NAME; ?> + + + + + + +
+
+
+

关于

+

安全、快速、免费的图片托管服务

+
+ +
+
+

我们的使命

+

为用户提供简单易用、功能强大的图片托管解决方案,让每个人都能轻松分享和管理自己的图片资源。

+
+ +
+

主要特性

+
+
+ +

批量上传

+

支持多文件同时上传,拖拽操作

+
+
+ +

标签分类

+

智能标签系统,方便图片管理

+
+
+ +

API 支持

+

完整的 RESTful API 接口

+
+
+ +

深色模式

+

支持明暗主题切换

+
+
+ +

安全可靠

+

多重安全验证机制

+
+
+ +

响应式设计

+

完美适配各种设备

+
+
+
+ +
+

技术栈

+
+
+ + PHP +
+
+ + MySQL +
+
+ + JavaScript +
+
+ + HTML5 +
+
+ + CSS3 +
+
+
+ +
+

统计数据

+
+ query("SELECT COUNT(*) as total FROM users"); + $totalUsers = $stmt->fetch(PDO::FETCH_ASSOC)['total']; + + $stmt = $pdo->query("SELECT COUNT(*) as total FROM images"); + $totalImages = $stmt->fetch(PDO::FETCH_ASSOC)['total']; + + $stmt = $pdo->query("SELECT SUM(file_size) as total FROM images"); + $totalSize = $stmt->fetch(PDO::FETCH_ASSOC)['total'] ?: 0; + + $stmt = $pdo->query("SELECT COUNT(*) as total FROM images WHERE DATE(uploaded_at) = CURDATE()"); + $todayImages = $stmt->fetch(PDO::FETCH_ASSOC)['total']; + } catch(PDOException $e) { + $totalUsers = $totalImages = $totalSize = $todayImages = 0; + } + ?> +
+
+
注册用户
+
+
+
+
托管图片
+
+
+
+
存储空间
+
+
+
+
今日上传
+
+
+
+ +
+

常见问题

+
+
+

支持哪些图片格式?

+

支持 JPG、PNG、GIF、WebP 格式,单文件最大 5MB。

+
+
+

图片会永久保存吗?

+

是的,所有上传的图片都会永久保存,除非用户主动删除。

+
+
+

如何获取 API 密钥?

+

登录后在 API 文档页面可以生成和管理您的 API 密钥。

+
+
+

支持外链吗?

+

支持,每张图片都提供直接链接,可以嵌入到其他网站。

+
+
+
+ +
+

联系我们

+
+

如果您有任何问题或建议,欢迎通过以下方式联系我们:

+
+
+ + 邮箱: support@66ghz.com +
+
+ + 问题反馈: 反馈页面 +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/api-docs.php b/api-docs.php new file mode 100644 index 0000000..1d78d45 --- /dev/null +++ b/api-docs.php @@ -0,0 +1,152 @@ +prepare("SELECT api_key FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $user = $stmt->fetch(PDO::FETCH_ASSOC); +} catch(PDOException $e) { + $user = ['api_key' => null]; +} +?> + + + + + + <?php echo t('api_docs'); ?> - <?php echo SITE_NAME; ?> + + + + + + +
+

+ +
+
+

+ +

+
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ +
+

+ +
+

1.

+
+ POST /api/upload.php

+ //
+ Content-Type: multipart/form-data

+ //
+ api_key = string ()
+ image = file ()
+ title = string ()
+ tags = string ()
+ is_public = integer ()

+ //
+ {
+   "success": true,
+   "data": {
+     "id": 123,
+     "title": "",
+     "url": "/view-image.php?id=123",
+     "direct_url": "/uploads/filename.jpg",
+     "tags": ["", ""]
+   }
+ } +
+
+ +
+

2.

+
+ GET /api/images.php?api_key=&page=1&limit=20

+ //
+ api_key = string ()
+ page = integer ()
+ limit = integer ()

+ //
+ {
+   "success": true,
+   "data": [
+     {
+       "id": 123,
+       "title": "",
+       "url": "/view-image.php?id=123",
+       "direct_url": "/uploads/filename.jpg",
+       "is_public": 1,
+       "views": 45,
+       "file_size_formatted": "2.5 MB"
+     }
+   ],
+   "pagination": {
+     "page": 1,
+     "limit": 20,
+     "total": 150,
+     "pages": 8
+   }
+ } +
+
+ +
+

3.

+
+ #
+ curl -X POST \
+   -F "api_key=" \
+   -F "title=" \
+   -F "is_public=1" \
+   -F "image=@/path/to/your/image.jpg" \
+   "/api/upload.php" +
+ +
+ #
+ curl "/api/images.php?api_key=&page=1&limit=10" +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/captcha.php b/captcha.php new file mode 100644 index 0000000..dd3a322 --- /dev/null +++ b/captcha.php @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/config.php b/config.php new file mode 100644 index 0000000..7296ebc --- /dev/null +++ b/config.php @@ -0,0 +1,402 @@ +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 = " + + + + + + + +
+
+

" . SITE_NAME . "

+
+
+

亲爱的 {$username},

+

感谢您注册" . SITE_NAME . "图床!

+

请点击下面的按钮验证您的邮箱地址:

+

+ 验证邮箱 +

+

如果按钮无法点击,请复制以下链接到浏览器地址栏:

+

{$verification_link}

+

此验证链接 24 小时内有效。

+
+ +
+ + "; + + return sendEmail($email, $subject, $message); +} + +function sendPasswordResetEmail($email, $username, $token) { + $reset_link = SITE_URL . "/reset-password.php?token=" . $token; + + $subject = SITE_NAME . " - 密码重置"; + $message = " + + + + + + + +
+
+

" . SITE_NAME . " - 密码重置

+
+
+

亲爱的 {$username},

+

我们收到了您重置密码的请求。

+

请点击下面的按钮重置您的密码:

+

+ 重置密码 +

+

如果按钮无法点击,请复制以下链接到浏览器地址栏:

+

{$reset_link}

+
+ 注意:此链接在 1 小时内有效。如果您没有请求重置密码,请忽略此邮件。 +
+
+ +
+ + "; + + 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; +} +?> \ No newline at end of file diff --git a/dashboard.php b/dashboard.php new file mode 100644 index 0000000..37b81f3 --- /dev/null +++ b/dashboard.php @@ -0,0 +1,282 @@ +prepare("SELECT * FROM images WHERE user_id = ? ORDER BY uploaded_at DESC"); + $stmt->execute([$_SESSION['user_id']]); + $userImages = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch(PDOException $e) { + $userImages = []; +} + +try { + $stmt = $pdo->prepare("SELECT api_key FROM users WHERE id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $user = $stmt->fetch(PDO::FETCH_ASSOC); +} catch(PDOException $e) { + $user = ['api_key' => null]; +} + +$success = $_SESSION['success'] ?? ''; +$error = $_SESSION['error'] ?? ''; +unset($_SESSION['success'], $_SESSION['error']); + +try { + $stmt = $pdo->prepare("SELECT COUNT(*) as total FROM images WHERE user_id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $totalImages = $stmt->fetch(PDO::FETCH_ASSOC)['total']; + + $stmt = $pdo->prepare("SELECT COUNT(*) as public FROM images WHERE user_id = ? AND is_public = 1"); + $stmt->execute([$_SESSION['user_id']]); + $publicImages = $stmt->fetch(PDO::FETCH_ASSOC)['public']; + + $stmt = $pdo->prepare("SELECT SUM(views) as total_views FROM images WHERE user_id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $totalViews = $stmt->fetch(PDO::FETCH_ASSOC)['total_views'] ?: 0; + + $stmt = $pdo->prepare("SELECT SUM(file_size) as total_size FROM images WHERE user_id = ?"); + $stmt->execute([$_SESSION['user_id']]); + $totalSize = $stmt->fetch(PDO::FETCH_ASSOC)['total_size'] ?: 0; + +} catch(PDOException $e) { + $totalImages = $publicImages = $totalViews = $totalSize = 0; +} +?> + + + + + + <?php echo t('dashboard'); ?> - <?php echo SITE_NAME; ?> + + + + + + +
+
+
+
+
+ : +
+
+
+
+ : +
+
+
+
+ +
+
+
+
+ +
+
+ +
+

+ + + +
+ + +
+ +
+ + + +
+ +
+ + + + + +
+

+

+ + + +
+ + + + +
+

+
+

+ + + + + +
+ +
+ + +
+ +
+ +
+
+
+ + + + \ No newline at end of file