上传文件至「/」

这个提交包含在:
2026-07-24 11:43:02 +08:00
父节点 7324fd9ef5
当前提交 1ea74a17b2
修改 14 个文件,包含 1873 行新增328 行删除
+2
查看文件
@@ -0,0 +1,2 @@
<?php
header('HTTP/2 404 Not Found');
+9 -17
查看文件
@@ -3,9 +3,9 @@
![](https://img.shields.io/badge/%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC-Beta_0.1-red)
Parlz Domain 是一个开源、简洁的二级域名分发系统,使用的技术是 PHP 和 MySQL (MariaDB)。目前支持 Cloudflare API,后续会加入更多 API 支持。
Parlz Domain 是一个开源、简洁的二级域名分发系统,使用的技术是 PHP 和 MySQL (MariaDB)。目前支持 Cloudflare API 和 Aliyun API,后续会加入更多 API 支持。
域名会自动写入名称和记录值,目前会自动配置灰云及 TTL 5min
域名会自动写入名称和记录值。
### `建立初衷`
和 PicHost 一样,网上大多数程序都是 Vite、Go...搭建的。配置很麻烦,不仅要装一堆依赖而且还要整端口和反代。于是,我就开发这个源码了。可能会持续更新。
@@ -21,25 +21,16 @@ Parlz Domain 是一个开源、简洁的二级域名分发系统,使用的技
找到 Release 并直接下载源码压缩包即可。
### `配置` (重要)
打开 **`config.php`** 文件,根据注释来配置这些行:
1. 打开 **`config.php`** 文件,根据注释来配置这些行:
```php
define('DB_HOST', ''); // 数据库地址
define('DB_NAME', ''); // 数据库名称
define('DB_USER', ''); // 数据库用户
define('DB_PASS', ''); // 数据库密码
$DOMAINS_CONFIG = [
'Domain1' => [ // 你要托管的另一个子域名
'zone_id' => '', // 区域 ID,在 CF 的域名三个点就有
'api_token' => '' // API,在 CF 的账户栏有一个 API 配置,需要给 DNS 读写权限。
],
'Domain2' => [ // 以此类推...
'zone_id' => '',
'api_token' => ''
],
'Domain3' => [
'zone_id' => '',
'api_token' => ''
]
'Domain1' => [], // Domain1: 你要托管的域名
'Domain2' => [], // 以此类推
'Domain3' => []
];
define('SMTP_HOST', ''); // SMTP 地址
define('SMTP_PORT', 587); // SMTP 端口
@@ -51,8 +42,9 @@ define('SMTP_FROM_NAME', ''); // SMTP 发件人名称,可以使用你自己的
define('SITE_URL', ''); // 分发站点 URL
define('SITE_NAME', ''); // 分发站点名称
```
配置好后,在终端中输入以下命令安装 PHPMailer:
2. 访问 `https://你的网站/install.php` 来导入数据库。
3. 访问 `https://你的网站/aliapi/setup_token.php` 来生成 Aliyun Token。
4. 在终端中输入以下命令安装 PHPMailer:
```sh
composer install
```
+35
查看文件
@@ -43,6 +43,27 @@ $currentTheme = getTheme();
<title><?php echo $action === 'login' ? '登录' : '注册'; ?> - <?php echo SITE_NAME; ?></title>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
<meta name="description" content="登录,Parlz Domains 账号,管理你的二级域名。">
<meta name="keywords" content="登录,用户登录,域名管理">
<link rel="icon" href="favicon.ico">
<meta name="robots" content="index, follow">
<link rel="alternate" hreflang="zh-CN" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/auth.php" />
<link rel="me" href="https://git.parlz.com/Xiaoxiaobai5724/parlz-domain">
<meta property="og:title" content="登录 - Parlz Domains">
<meta property="og:description" content="登录 Parlz Domains 账号,管理你的二级域名。">
<meta property="og:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/auth.php">
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="登录 - <?php echo SITE_NAME; ?>">
<meta name="twitter:description" content="登录 <?php echo SITE_NAME; ?> 账号。">
<meta name="twitter:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta name="twitter:site" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/auth.php">
<link rel="canonical" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/auth.php">
</head>
<body>
<div class="container auth-container">
@@ -75,6 +96,8 @@ $currentTheme = getTheme();
</form>
<div class="auth-switch">
还没有账号?<a href="?action=register">立即注册</a>
<a href="forgot_password.php">忘记密码?</a>
注册用户默认已同意 <a href="/doc/?file=md/使用协议.md">使用协议</a> 和 <a href="/doc/?file=md/隐私政策.md">隐私政策</a>。
</div>
<?php else: ?>
@@ -107,9 +130,21 @@ $currentTheme = getTheme();
</form>
<div class="auth-switch">
已有账号?<a href="?action=login">立即登录</a>
<a href="forgot_password.php">忘记密码?</a>
注册用户默认已同意 <a href="/doc/?file=md/使用协议.md">使用协议</a> 和 <a href="/doc/?file=md/隐私政策.md">隐私政策</a>。
</div>
<?php endif; ?>
</div>
</div>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "登录 - <?php echo SITE_NAME; ?>",
"description": "登录 <?php echo SITE_NAME; ?> 账号,管理你的二级域名。",
"url": "https://<?php echo $_SERVER['HTTP_HOST']; ?>/login",
"inLanguage": "zh-CN"
}
</script>
</body>
</html>
+26 -17
查看文件
@@ -1,16 +1,17 @@
<?php
define('DB_HOST', '');
define('DB_NAME', '');
define('DB_USER', '');
define('DB_PASS', '');
define('DB_HOST', ''); // 数据库地址
define('DB_NAME', ''); // 数据库名称
define('DB_USER', ''); // 数据库用户
define('DB_PASS', ''); // 数据库密码
define('DB_CHARSET', 'utf8mb4');
/**
$DOMAINS_CONFIG = [
'Domain1' => [
'zone_id' => '',
'api_token' => ''
'Domain1' => [ // 你要托管的另一个子域名
'zone_id' => '', // 区域 ID,在 CF 的域名三个点就有
'api_token' => '' // API,在 CF 的账户栏有一个 API 配置,需要给 DNS 读写权限。
],
'Domain2' => [
'Domain2' => [ // 以此类推...
'zone_id' => '',
'api_token' => ''
],
@@ -20,15 +21,23 @@ $DOMAINS_CONFIG = [
]
];
define('SMTP_HOST', '');
define('SMTP_PORT', 587);
define('SMTP_SECURE', 'tls');
define('SMTP_USERNAME', '');
define('SMTP_PASSWORD', '');
define('SMTP_FROM_EMAIL', '');
define('SMTP_FROM_NAME', '');
define('SITE_URL', '');
define('SITE_NAME', '');
*/
$DOMAINS_CONFIG = [
'Domain1' => [],
'Domain2' => [],
'Domain3' => []
];
define('SMTP_HOST', ''); // SMTP 地址
define('SMTP_PORT', 587); // SMTP 端口
define('SMTP_SECURE', 'tls'); // SMTP 协议,ssl 加密,tls 不加密
define('SMTP_USERNAME', ''); // SMTP 用户名
define('SMTP_PASSWORD', ''); // SMTP 授权码
define('SMTP_FROM_EMAIL', ''); // SMTP 发件邮箱,和用户名保持一致即可
define('SMTP_FROM_NAME', ''); // SMTP 发件人名称,可以使用你自己的站点名字
define('SITE_URL', ''); // 分发站点 URL
define('SITE_NAME', ''); // 分发站点名称
define('CREDIT_PER_DOMAIN', 5);
define('MAX_DOMAINS_PER_USER', 10);
define('SIGN_IN_CREDIT', 2);
+71 -2
查看文件
@@ -82,6 +82,26 @@ $currentTheme = getTheme();
<title>用户面板 - <?php echo SITE_NAME; ?></title>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
<meta name="description" content="<?php echo SITE_NAME; ?> 管理你的域名,查看积分,签到获取奖励。">
<meta name="keywords" content="parlz,parlzdomains,域名管理,我的域名,积分查询">
<link rel="icon" href="favicon.ico">
<link rel="alternate" hreflang="zh-CN" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/dashboard" />
<meta property="og:title" content="用户面板 - <?php echo SITE_NAME; ?>">
<meta property="og:description" content="自研域名分发网站,免费获取二级域名,支持 A、AAAA、CNAME、MX、NS、TXT 等记录。积分制管理,每日签到得积分,邀请好友额外奖励。基于阿里云DNS,稳定可靠。">
<meta property="og:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="用户面板 - <?php echo SITE_NAME; ?>">
<meta name="twitter:description" content="自研域名分发网站,免费获取二级域名,支持 A、AAAA、CNAME、MX、NS、TXT 等记录。积分制管理,每日签到得积分,邀请好友额外奖励。基于阿里云DNS,稳定可靠。">
<meta name="twitter:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta name="twitter:site" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/">
<link rel="canonical" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/dashboard">
<link rel="me" href="https://git.parlz.com/Xiaoxiaobai5724/parlz-domain">
</head>
<body>
<div class="container">
@@ -156,7 +176,40 @@ $currentTheme = getTheme();
</form>
</div>
</div>
<!-- 欢迎区域 -->
<div class="welcome-header">
<div>
<h1>👋 欢迎回来,<?php echo htmlspecialchars($userInfo['username']); ?></h1>
<p style="color:var(--text-secondary);font-size:14px;">
您在 <?php echo date('Y-m-d', strtotime($userInfo['created_at'])); ?> 注册
<?php if ($userInfo['is_admin']): ?>
<span style="background:var(--accent-blue);color:#fff;padding:2px 12px;border-radius:4px;font-size:12px;margin-left:10px;">
<i class="fas fa-crown"></i> 管理员
</span>
<?php endif; ?>
</p>
</div>
<div class="user-actions">
<form method="POST" style="display:inline;">
<input type="hidden" name="action" value="sign_in">
<button type="submit" class="btn btn-primary" <?php echo $signInToday ? 'disabled' : ''; ?>>
<i class="fas fa-calendar-check"></i>
<?php echo $signInToday ? '已签到' : '签到 (+' . SIGN_IN_CREDIT . '积分)'; ?>
</button>
</form>
</div>
</div>
<div class="alert alert-warning" style="margin-bottom:25px;border-left:4px solid var(--accent-red);background:rgba(248,81,73,0.08);">
<div style="display:flex;align-items:flex-start;gap:14px;">
<div style="font-size:28px;flex-shrink:0;">⚠️</div>
<div>
<div style="font-weight:700;font-size:16px;color:var(--accent-red);">📢 重要提醒:</div>
<div style="font-size:14px;color:var(--text-secondary);margin-top:4px;line-height:1.8;">
严禁使用本平台域名搭建色情、淫秽、低俗、赌博、博彩、诈骗、毒品、违禁品交易、传播病毒、木马、钓鱼、侵犯他人知识产权或隐私权的网站。一旦发现,立即封号并移交公安机关处理!如果您发现了,请发送邮件至 odoorbell@163.com。
</div>
</div>
</div>
</div>
<!-- 统计卡片 -->
<div class="stats-grid">
<div class="stat-card credits">
@@ -372,7 +425,7 @@ $currentTheme = getTheme();
// 切换事件
typeSelect.addEventListener('change', function() {
const type = this.value;
hintSpan.innerHTML = hints[type] || '请输入记录值';
hintSpan.innerHTML = hints[type] || '请输入记录值';
valueInput.placeholder = placeholders[type] || '请输入记录值。';
// 添加小字提示
@@ -409,5 +462,21 @@ $currentTheme = getTheme();
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfilePage",
"name": "<?php echo htmlspecialchars($userInfo['username']); ?> 的域名管理面板",
"description": "管理你的二级域名,当前拥有 <?php echo $domainCount; ?> 个域名,<?php echo $credits; ?> 积分。",
"url": "https://<?php echo $_SERVER['HTTP_HOST']; ?>/dashboard",
"about": {
"@type": "Person",
"name": "<?php echo htmlspecialchars($userInfo['username']); ?>",
"description": "<?php echo SITE_NAME; ?> 用户"
},
"dateCreated": "<?php echo date('Y-m-d', strtotime($userInfo['created_at'])); ?>",
"inLanguage": "zh-CN"
}
</script>
</body>
</html>
+117
查看文件
@@ -0,0 +1,117 @@
<?php
require_once 'functions.php';
$currentTheme = getTheme();
$message = null;
$success = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim($_POST['email'] ?? '');
if (empty($email)) {
$message = '请输入邮箱地址';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$message = '请输入有效的邮箱地址';
} else {
$result = requestPasswordReset($email);
if ($result['success']) {
$success = true;
$message = $result['message'];
} else {
$message = $result['message'];
}
}
}
$pageTitle = '忘记密码 - ' . SITE_NAME;
$pageDescription = '重置您的 ' . SITE_NAME . ' 账号密码,通过邮箱验证找回账号。';
?>
<!DOCTYPE html>
<html lang="zh-CN" data-theme="<?php echo $currentTheme; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<meta name="description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<link rel="canonical" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/forgot_password">
<meta name="robots" content="index, follow">
<link rel="alternate" hreflang="zh-CN" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/forgot_password.php" />
<link rel="icon" href="favicon.ico">
<meta property="og:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
<meta property="og:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<meta property="og:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/forgot_password.php">
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
<meta property="og:locale" content="zh_CN">
<!-- ===== Twitter Card ===== -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
<meta name="twitter:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<meta name="twitter:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta name="twitter:site" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>">
<!-- ===== Schema.org ===== -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "<?php echo htmlspecialchars($pageTitle); ?>",
"description": "<?php echo htmlspecialchars($pageDescription); ?>",
"url": "https://<?php echo $_SERVER['HTTP_HOST']; ?>/forgot-password",
"inLanguage": "zh-CN"
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="auth-container">
<div class="auth-card">
<div class="icon-top">
<i class="fas fa-key"></i>
</div>
<h2>忘记密码</h2>
<p class="subtitle">输入您的邮箱,我们将发送重置链接</p>
<?php if ($message): ?>
<div class="alert alert-<?php echo $success ? 'success' : 'error'; ?>">
<i class="fas <?php echo $success ? 'fa-check-circle' : 'fa-exclamation-circle'; ?>"></i>
<?php echo htmlspecialchars($message); ?>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="success-box">
<i class="fas fa-envelope"></i>
<h3>📧 邮件已发送</h3>
<p>请检查您的邮箱,点击邮件中的链接重置密码。<br>如果没收到邮件,请检查垃圾箱。</p>
<a href="/login" class="btn btn-primary" style="display:inline-flex;width:auto;padding:12px 32px;">
<i class="fas fa-sign-in-alt"></i> 返回登录
</a>
</div>
<?php else: ?>
<form method="POST">
<div class="form-group">
<label><i class="fas fa-envelope"></i> 邮箱地址</label>
<input type="email" name="email" placeholder="请输入注册邮箱" required>
</div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-paper-plane"></i> 发送重置链接
</button>
</form>
<div class="auth-links">
想起密码了?<a href="/login">返回登录</a>
</div>
<?php endif; ?>
</div>
</div>
</div>
</body>
</html>
+428 -273
查看文件
@@ -5,6 +5,100 @@ require_once 'vendor/autoload.php'; // PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
/**
* 输出 Canonical 标签
*/
function renderCanonical($customUrl = null) {
if ($customUrl) {
$url = $customUrl;
} else {
$scheme = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
// 移除查询参数中的无关参数(如 session、utm 等)
$parsed = parse_url($uri);
if (isset($parsed['query'])) {
parse_str($parsed['query'], $query);
// 移除无关参数
unset($query['_ajax'], $query['t'], $query['sid']);
$newQuery = http_build_query($query);
$url = $scheme . '://' . $host . $parsed['path'] . ($newQuery ? '?' . $newQuery : '');
} else {
$url = $scheme . '://' . $host . $uri;
}
}
echo '<link rel="canonical" href="' . htmlspecialchars($url) . '">' . "\n";
}
/**
* 输出 Schema.org 结构化数据(网站和组织)
*/
function renderSchemaOrg($pageType = 'WebPage', $extraData = []) {
$schema = [
'@context' => 'https://schema.org',
'@type' => $pageType,
'name' => SITE_NAME,
'description' => '免费二级域名分发平台,支持A、AAAA、CNAME、MX、NS、TXT、SRV记录',
'url' => 'https://' . $_SERVER['HTTP_HOST'],
'inLanguage' => 'zh-CN',
'about' => [
'@type' => 'Thing',
'name' => '域名分发'
]
];
// 根据页面类型添加额外数据
if ($pageType === 'WebPage') {
$schema['dateModified'] = date('Y-m-d\TH:i:sP');
}
if ($pageType === 'Product') {
$schema['offers'] = [
'@type' => 'Offer',
'price' => '0',
'priceCurrency' => 'CNY',
'availability' => 'https://schema.org/InStock'
];
}
// 合并额外数据
if (!empty($extraData)) {
$schema = array_merge($schema, $extraData);
}
echo '<script type="application/ld+json">' . "\n";
echo json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo "\n" . '</script>' . "\n";
}
/**
* 输出面包屑结构化数据
*/
function renderBreadcrumbSchema($items) {
$schema = [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => []
];
$position = 1;
foreach ($items as $item) {
$schema['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $position,
'name' => $item['name'],
'item' => $item['url']
];
$position++;
}
echo '<script type="application/ld+json">' . "\n";
echo json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo "\n" . '</script>' . "\n";
}
// ===== 用户相关函数 =====
/**
@@ -137,7 +231,7 @@ function sendVerificationEmail($email, $username, $token) {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>邮箱验证</title>
<style>
@import url("https://cdn.jsdmirror.com/gh/willow-god/Sharding-fonts/Yozai-Medium/result.min.css");
@import url("https://cdn.jsdmirror.com/gh/willow-god/Sharding-fonts/Yozai-Medium/result.min.css");
body { font-family: "Yozai Medium"; background: #f6f8fa; padding: 40px 20px; }
.container { max-width: 560px; margin: 0 auto; background: #ffffff; border-radius: 12px; padding: 40px; box-shadow: 0 8px 32px rgba(0,0,0,0.08); }
.header { text-align: center; margin-bottom: 30px; }
@@ -221,6 +315,148 @@ function verifyEmail($token) {
return ['success' => true, 'message' => '邮箱验证成功!'];
}
/**
* 请求密码重置
*/
function requestPasswordReset($email) {
$pdo = getDB();
// 检查用户是否存在
$stmt = $pdo->prepare("SELECT id, username FROM users WHERE email = ? AND is_verified = 1");
$stmt->execute([$email]);
$user = $stmt->fetch();
if (!$user) {
// 为了安全,不暴露用户是否存在
return ['success' => true, 'message' => '如果该邮箱已注册,我们将发送重置链接'];
}
// 生成重置令牌
$token = bin2hex(random_bytes(32));
$expires = date('Y-m-d H:i:s', strtotime('+1 hour'));
// 保存令牌
$stmt = $pdo->prepare("UPDATE users SET reset_token = ?, reset_expires = ? WHERE id = ?");
$stmt->execute([$token, $expires, $user['id']]);
// 发送重置邮件
sendResetEmail($email, $user['username'], $token);
return ['success' => true, 'message' => '如果该邮箱已注册,我们将发送重置链接'];
}
/**
* 重置密码
*/
function resetPassword($token, $newPassword) {
$pdo = getDB();
// 验证令牌
$stmt = $pdo->prepare("SELECT id FROM users WHERE reset_token = ? AND reset_expires > NOW()");
$stmt->execute([$token]);
$user = $stmt->fetch();
if (!$user) {
return ['success' => false, 'message' => '重置链接无效或已过期'];
}
// 更新密码
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("UPDATE users SET password = ?, reset_token = NULL, reset_expires = NULL WHERE id = ?");
$stmt->execute([$hashedPassword, $user['id']]);
return ['success' => true, 'message' => '密码已重置,请使用新密码登录'];
}
/**
* 发送重置密码邮件
*/
function sendResetEmail($email, $username, $token) {
$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;
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
$mail->setFrom(SMTP_FROM_EMAIL, SMTP_FROM_NAME);
$mail->addAddress($email, $username);
$mail->isHTML(true);
$resetLink = SITE_URL . "/reset-password?token=" . $token;
$mail->Subject = '重置密码 - ' . SITE_NAME;
$mail->Body = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重置密码</title>
<style>
@import url("https://cdn.jsdmirror.com/gh/willow-god/Sharding-fonts/Yozai-Medium/result.min.css");
body { font-family: "Yozai Medium"; background: #f6f8fa; padding: 40px 20px; }
.container { max-width: 560px; margin: 0 auto; background: #ffffff; border-radius: 12px; padding: 40px; box-shadow: 0 8px 32px rgba(0,0,0,0.08); }
.header { text-align: center; margin-bottom: 30px; }
.header h1 { color: #24292f; font-size: 24px; margin: 0; }
.content { color: #24292f; line-height: 1.8; }
.btn { display: inline-block; padding: 12px 32px; background: #0969da; color: #ffffff !important; text-decoration: none; border-radius: 6px; font-weight: 600; margin: 20px 0; }
.btn:hover { background: #0550ae; }
.footer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #d0d7de; font-size: 12px; color: #57606a; text-align: center; }
.link-box { background: #f6f8fa; padding: 12px 16px; border-radius: 6px; word-break: break-all; font-size: 13px; color: #57606a; border: 1px solid #d0d7de; }
.highlight { color: #0969da; font-weight: 600; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔑 重置密码</h1>
</div>
<div class="content">
<p>您好,<strong>' . htmlspecialchars($username) . '</strong></p>
<p>我们收到了您重置密码的请求。请点击下方按钮设置新密码:</p>
<p style="text-align: center;">
<a href="' . $resetLink . '" class="btn">🔐 重置密码</a>
</p>
<p style="color: #57606a; font-size: 14px;">如果按钮无法点击,请复制以下链接到浏览器打开:</p>
<div class="link-box">' . $resetLink . '</div>
<p style="margin-top: 20px; font-size: 14px; color: #57606a;">
⏰ 此链接 <span class="highlight">1 小时</span> 内有效。<br>
🔒 如果您没有请求重置密码,请忽略此邮件。
</p>
</div>
<div class="footer">
<p>' . SITE_NAME . ' · 安全可靠</p>
<p style="margin-top: 4px;">© ' . date('Y') . ' ' . SITE_NAME . '</p>
</div>
</div>
</body>
</html>
';
$mail->AltBody = "重置密码 - " . SITE_NAME . "\n\n" .
"您好," . $username . "\n\n" .
"请访问以下链接重置您的密码:\n" .
$resetLink . "\n\n" .
"此链接 1 小时内有效。\n\n" .
"如果您没有请求重置密码,请忽略此邮件。";
$mail->send();
return true;
} catch (Exception $e) {
error_log("重置邮件发送失败: " . $e->getMessage());
return false;
}
}
// ===== 积分相关函数 =====
/**
@@ -517,8 +753,152 @@ function getRecordTypeHint($type) {
return $hints[$type] ?? '';
}
// ===== 阿里云 API 函数(通过你的 aliapi 接口) =====
/**
* 添加域名(扣除积分)
* 调用阿里云API的通用函数
*/
function callAliyunAPI($endpoint, $params) {
$tokenFile = __DIR__ . '/aliapi/.token';
$token = trim(file_get_contents($tokenFile));
$params['token'] = $token;
$url = "https://" . $_SERVER['HTTP_HOST'] . "/aliapi/api/" . $endpoint . ".php";
$fullUrl = $url . '?' . http_build_query($params);
error_log("阿里云API请求: " . $fullUrl);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
error_log("阿里云 API CURL 错误: " . $curlError);
return ['success' => false, 'message' => 'CURL 错误: ' . $curlError];
}
$result = json_decode($response, true);
if (!$result) {
error_log("阿里云 API 响应解析失败: " . $response);
return ['success' => false, 'message' => '响应解析失败。'];
}
error_log("阿里云 API 响应: " . $response);
return $result;
}
/**
* 添加DNS记录(调用阿里云API)
*/
function addAliyunRecord($mainDomain, $subdomain, $type, $value) {
$params = [
'domain_name' => $mainDomain,
'rr' => $subdomain,
'type' => strtoupper($type),
'value' => $value,
'ttl' => 600
];
// MX和SRV记录需要priority参数
$typeUpper = strtoupper($type);
if ($typeUpper === 'MX' || $typeUpper === 'SRV') {
$parts = preg_split('/\s+/', trim($value));
if (count($parts) >= 1 && is_numeric($parts[0])) {
$params['priority'] = intval($parts[0]);
}
}
$result = callAliyunAPI('add_record', $params);
if ($result && isset($result['code']) && $result['code'] === 200) {
return ['success' => true, 'message' => '添加成功', 'data' => $result['data'] ?? []];
} else {
$errorMsg = $result['message'] ?? '未知错误';
return ['success' => false, 'message' => '添加失败: ' . $errorMsg];
}
}
/**
* 删除DNS记录(调用阿里云API)
*/
function deleteAliyunRecord($mainDomain, $subdomain) {
// 1. 先查询记录ID
$listParams = [
'domain_name' => $mainDomain,
'rr_keyword' => $subdomain
];
$listResult = callAliyunAPI('list_records', $listParams);
if (!$listResult || $listResult['code'] !== 200) {
error_log("查询记录失败: " . ($listResult['message'] ?? '未知错误'));
return false;
}
// 查找匹配的记录ID
$recordId = null;
if (isset($listResult['data']['records'])) {
foreach ($listResult['data']['records'] as $record) {
if ($record['rr'] === $subdomain) {
$recordId = $record['record_id'];
break;
}
}
}
if (!$recordId) {
error_log("未找到记录: {$subdomain}.{$mainDomain}");
return false;
}
// 2. 删除记录
$deleteParams = ['record_id' => $recordId];
$deleteResult = callAliyunAPI('delete_record', $deleteParams);
if ($deleteResult && isset($deleteResult['code']) && $deleteResult['code'] === 200) {
return true;
}
error_log("删除记录失败: " . ($deleteResult['message'] ?? '未知错误'));
return false;
}
/**
* 查询DNS记录列表(调用阿里云API)
*/
function listAliyunRecords($mainDomain, $rrKeyword = null, $type = null) {
$params = [
'domain_name' => $mainDomain,
'page' => 1,
'page_size' => 100
];
if ($rrKeyword !== null) {
$params['rr_keyword'] = $rrKeyword;
}
if ($type !== null) {
$params['type'] = strtoupper($type);
}
$result = callAliyunAPI('list_records', $params);
if ($result && isset($result['code']) && $result['code'] === 200) {
return ['success' => true, 'data' => $result['data'] ?? []];
} else {
return ['success' => false, 'message' => $result['message'] ?? '查询失败'];
}
}
/**
* 添加域名(扣除积分)- 使用阿里云API
*/
function addDomain($userId, $mainDomain, $subdomain, $type, $value) {
// 检查权限
@@ -557,10 +937,10 @@ function addDomain($userId, $mainDomain, $subdomain, $type, $value) {
$pdo->beginTransaction();
try {
// 先尝试添加到 Cloudflare
$cfResult = addCloudflareRecord($mainDomain, $subdomain, $type, $value);
if (!$cfResult['success']) {
return ['success' => false, 'message' => '添加失败: ' . $cfResult['message']];
// 先尝试添加到阿里云
$aliResult = addAliyunRecord($mainDomain, $subdomain, $type, $value);
if (!$aliResult['success']) {
return ['success' => false, 'message' => '添加失败: ' . $aliResult['message']];
}
// 扣减积分
@@ -579,8 +959,8 @@ function addDomain($userId, $mainDomain, $subdomain, $type, $value) {
} catch (Exception $e) {
$pdo->rollBack();
// 如果数据库失败,尝试删除 Cloudflare 记录
deleteCloudflareRecord($mainDomain, $subdomain);
// 如果数据库失败,尝试删除阿里云记录
deleteAliyunRecord($mainDomain, $subdomain);
return ['success' => false, 'message' => '添加失败: ' . $e->getMessage()];
}
}
@@ -596,7 +976,7 @@ function getUserDomains($userId) {
}
/**
* 删除域名
* 删除域名 - 使用阿里云API
*/
function deleteDomain($userId, $domainId) {
$pdo = getDB();
@@ -610,8 +990,11 @@ function deleteDomain($userId, $domainId) {
return ['success' => false, 'message' => '该域名不存在。'];
}
// 从 Cloudflare 删除
deleteCloudflareRecord($domain['main_domain'], $domain['subdomain']);
// 从阿里云删除
$deleted = deleteAliyunRecord($domain['main_domain'], $domain['subdomain']);
if (!$deleted) {
error_log("阿里云删除失败: " . $domain['subdomain'] . '.' . $domain['main_domain'] . ',但数据库将继续删除');
}
// 软删除
$stmt = $pdo->prepare("UPDATE domains SET status = 0 WHERE id = ?");
@@ -620,268 +1003,6 @@ function deleteDomain($userId, $domainId) {
return ['success' => true, 'message' => '域名删除成功。'];
}
// ===== Cloudflare API函数 =====
/**
* 获取域名配置
*/
function getDomainConfig($mainDomain) {
global $DOMAINS_CONFIG;
return $DOMAINS_CONFIG[$mainDomain] ?? null;
}
/**
* 添加Cloudflare记录(最终修复SRV - 使用正确的字段名)
*/
function addCloudflareRecord($mainDomain, $subdomain, $type, $value) {
$config = getDomainConfig($mainDomain);
if (!$config) {
error_log("Cloudflare 错误: 未找到域名配置 - {$mainDomain}");
return ['success' => false, 'message' => '未找到域名配置'];
}
$fullDomain = strtolower($subdomain) . '.' . strtolower($mainDomain);
$type = strtoupper($type);
// 检查记录是否已存在
$ch = curl_init('https://api.cloudflare.com/client/v4/zones/' . $config['zone_id'] . '/dns_records?name=' . urlencode($fullDomain) . '&type=' . $type);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $config['api_token']
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
if ($result && $result['success'] && !empty($result['result'])) {
error_log("Cloudflare 记录已存在 - {$fullDomain}");
return ['success' => false, 'message' => '该记录已存在。'];
}
}
// 构建请求数据 - 基础字段
$data = [
'type' => $type,
'name' => $fullDomain,
'ttl' => 300,
'proxied' => false // 必须明确设置为 false
];
// 根据记录类型处理值
switch ($type) {
case 'A':
if (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return ['success' => false, 'message' => '无效的 IPv4 地址。'];
}
$data['content'] = $value;
break;
case 'AAAA':
if (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return ['success' => false, 'message' => '无效的 IPv6 地址。'];
}
$data['content'] = $value;
break;
case 'CNAME':
$value = strtolower(trim($value));
if (!preg_match('/^([a-z0-9\-]+\.)+[a-z]{2,}$/', $value)) {
return ['success' => false, 'message' => '无效的域名格式。'];
}
$data['content'] = $value;
break;
case 'MX':
$parts = preg_split('/\s+/', trim($value));
if (count($parts) != 2) {
return ['success' => false, 'message' => 'MX 记录格式: 优先级 域名 (例如: 10 mail.example.com)。'];
}
if (!is_numeric($parts[0]) || intval($parts[0]) < 0 || intval($parts[0]) > 65535) {
return ['success' => false, 'message' => '优先级必须是 0-65535 之间的数字。'];
}
$domain = strtolower(trim($parts[1]));
if (!preg_match('/^([a-z0-9\-]+\.)+[a-z]{2,}$/', $domain)) {
return ['success' => false, 'message' => '无效的邮件服务器域名。'];
}
$data['priority'] = intval($parts[0]);
$data['content'] = $domain;
break;
case 'NS':
$value = strtolower(trim($value));
if (!preg_match('/^([a-z0-9\-]+\.)+[a-z]{2,}$/', $value)) {
return ['success' => false, 'message' => '无效的域名服务器地址。'];
}
$data['content'] = $value;
break;
case 'TXT':
if (strlen($value) > 255) {
return ['success' => false, 'message' => 'TXT 记录值不能超过 255 字符。'];
}
$data['content'] = $value;
break;
case 'SRV':
// ===== SRV记录特殊处理 =====
$parts = preg_split('/\s+/', trim($value));
if (count($parts) != 4) {
return ['success' => false, 'message' => 'SRV 记录格式: 优先级 权重 端口 目标域名 (例如: 10 5 5060 sip.example.com)'];
}
$priority = intval($parts[0]);
$weight = intval($parts[1]);
$port = intval($parts[2]);
$target = strtolower(trim($parts[3]));
// 验证数值范围
if ($priority < 0 || $priority > 65535) {
return ['success' => false, 'message' => '优先级必须是 0-65535 之间的数字。'];
}
if ($weight < 0 || $weight > 65535) {
return ['success' => false, 'message' => '权重必须是 0-65535 之间的数字。'];
}
if ($port < 0 || $port > 65535) {
return ['success' => false, 'message' => '端口必须是 0-65535 之间的数字。'];
}
// 验证目标域名
if ($target !== '.' && !preg_match('/^([a-z0-9\-]+\.)+[a-z]{2,}$/', $target)) {
return ['success' => false, 'message' => '无效的目标域名,请输入有效的域名或用 . 表示空。'];
}
// ===== 重要:SRV 记录使用不同的字段名 =====
// Cloudflare SRV API 要求使用这些字段名:
// - priority, weight, port, target (不是 content!)
$data['priority'] = (int)$priority;
$data['weight'] = (int)$weight;
$data['port'] = (int)$port;
$data['target'] = (string)$target; // 关键:使用 target 而不是 content
$data['proxied'] = false;
error_log("SRV 数据: priority={$priority}, weight={$weight}, port={$port}, target={$target}");
break;
default:
return ['success' => false, 'message' => '不支持的记录类型'];
}
// 记录请求数据用于调试
error_log("Cloudflare 请求数据: " . json_encode($data));
$ch = curl_init('https://api.cloudflare.com/client/v4/zones/' . $config['zone_id'] . '/dns_records');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $config['api_token']
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// 记录响应
error_log("Cloudflare 响应: HTTP {$httpCode}");
error_log("Cloudflare 响应内容: " . $response);
if ($curlError) {
error_log("Cloudflare CURL 错误: " . $curlError);
return ['success' => false, 'message' => 'CURL 错误: ' . $curlError];
}
if ($httpCode === 200) {
$result = json_decode($response, true);
if ($result && $result['success']) {
error_log("Cloudflare 添加成功: {$fullDomain}");
return ['success' => true, 'message' => '添加成功'];
} else {
$errorMsg = '未知错误';
if (isset($result['errors']) && !empty($result['errors'])) {
$errorMsg = $result['errors'][0]['message'] ?? 'API错误';
if (isset($result['errors'][0]['error_chain'])) {
foreach ($result['errors'][0]['error_chain'] as $chain) {
if (isset($chain['message'])) {
$errorMsg .= ' - ' . $chain['message'];
}
}
}
}
error_log("Cloudflare API 错误: " . $errorMsg);
return ['success' => false, 'message' => 'Cloudflare 错误: ' . $errorMsg];
}
}
// 解析错误响应
$result = json_decode($response, true);
if ($result && isset($result['errors'])) {
$errorMsg = '';
foreach ($result['errors'] as $error) {
$errorMsg .= $error['message'] . ' ';
if (isset($error['error_chain'])) {
foreach ($error['error_chain'] as $chain) {
if (isset($chain['message'])) {
$errorMsg .= '- ' . $chain['message'] . ' ';
}
}
}
}
return ['success' => false, 'message' => '请求错误: ' . trim($errorMsg)];
}
return ['success' => false, 'message' => "HTTP错误: {$httpCode} - " . substr($response, 0, 200)];
}
/**
* 删除Cloudflare记录(支持SRV
*/
function deleteCloudflareRecord($mainDomain, $subdomain) {
$config = getDomainConfig($mainDomain);
if (!$config) return false;
$fullDomain = $subdomain . '.' . $mainDomain;
$zoneId = $config['zone_id'];
$token = $config['api_token'];
// 查询记录ID - 不限定类型,因为SRV记录可能用target字段
$ch = curl_init('https://api.cloudflare.com/client/v4/zones/' . $zoneId . '/dns_records?name=' . urlencode($fullDomain));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
$response = curl_exec($ch);
$result = json_decode($response, true);
curl_close($ch);
if (isset($result['result']) && !empty($result['result'])) {
$recordId = $result['result'][0]['id'];
$ch = curl_init('https://api.cloudflare.com/client/v4/zones/' . $zoneId . '/dns_records/' . $recordId);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
curl_exec($ch);
curl_close($ch);
return true;
}
return false;
}
// ===== 其他辅助函数 =====
/**
@@ -959,4 +1080,38 @@ function getMainDomains() {
global $DOMAINS_CONFIG;
return array_keys($DOMAINS_CONFIG);
}
/**
* 兼容旧代码 - 获取所有域名(管理员使用)
*/
function getDomains($mainDomain = null) {
$pdo = getDB();
$sql = "SELECT d.*, u.username FROM domains d
LEFT JOIN users u ON d.user_id = u.id
WHERE d.status = 1";
$params = [];
if ($mainDomain) {
$sql .= " AND d.main_domain = ?";
$params[] = $mainDomain;
}
$sql .= " ORDER BY d.created_at DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
/**
* 兼容旧代码 - 获取所有域名(包含已删除的)
*/
function getAllDomains() {
$pdo = getDB();
$stmt = $pdo->query("SELECT d.*, u.username FROM domains d
LEFT JOIN users u ON d.user_id = u.id
ORDER BY d.created_at DESC");
return $stmt->fetchAll();
}
?>
+68 -6
查看文件
@@ -19,9 +19,30 @@ $mainDomains = getMainDomains();
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="自研域名分发网站,免费获取二级域名,支持 A、AAAA、CNAME、MX、NS、TXT 等记录。积分制管理,每日签到得积分,邀请好友额外奖励。基于阿里云DNS,稳定可靠。" />
<meta name="keywords" content="域名,二级域名,免费,域名分发,分发,积分,记录" />
<meta name="robots" content="index, follow">
<title><?php echo SITE_NAME; ?> - 用心制作的免费二级域名分发网站</title>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
<link rel="icon" href="favicon.ico">
<link rel="alternate" hreflang="zh-CN" href="https://dns.parlz.com/" />
<meta property="og:title" content="Parlz Domains - 用心制作的免费二级域名分发网站">
<meta property="og:description" content="自研域名分发网站,免费获取二级域名,支持 A、AAAA、CNAME、MX、NS、TXT 等记录。积分制管理,每日签到得积分,邀请好友额外奖励。基于阿里云DNS,稳定可靠。">
<meta property="og:image" content="https://dns.parlz.com/favicon.ico">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:url" content="https://dns.parlz.com/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Parlz Domains">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Parlz Domains - 用心制作的免费二级域名分发网站">
<meta name="twitter:description" content="自研域名分发网站,免费获取二级域名,支持 A、AAAA、CNAME、MX、NS、TXT 等记录。积分制管理,每日签到得积分,邀请好友额外奖励。基于阿里云DNS,稳定可靠。">
<meta name="twitter:image" content="https://dns.parlz.com/favicon.ico">
<meta name="twitter:site" content="https://dns.parlz.com/">
<link rel="canonical" href="https://dns.parlz.com/">
<link rel="me" href="https://git.parlz.com/Xiaoxiaobai5724/parlz-domain">
</head>
<body>
<div class="container">
@@ -35,10 +56,10 @@ $mainDomains = getMainDomains();
<i class="fas <?php echo $currentTheme === 'dark' ? 'fa-sun' : 'fa-moon'; ?>"></i>
</button>
</form>
<a href="auth.php?action=login" class="btn btn-primary btn-sm">
<a href="login" class="btn btn-primary btn-sm">
<i class="fas fa-sign-in-alt"></i>
</a>
<a href="auth.php?action=register" class="btn btn-sm" style="background:var(--bg-primary);border:1px solid var(--border-color);color:var(--text-primary);">
<a href="register" class="btn btn-sm" style="background:var(--bg-primary);border:1px solid var(--border-color);color:var(--text-primary);">
<i class="fas fa-user-plus"></i>
</a>
</div>
@@ -51,10 +72,10 @@ $mainDomains = getMainDomains();
<br>积分制管理,每日签到免费领取积分
</p>
<div class="btn-group">
<a href="auth.php?action=register" class="btn btn-primary btn-large">
<a href="register" class="btn btn-primary btn-large">
<i class="fas fa-user-plus"></i> 立即注册
</a>
<a href="auth.php?action=login" class="btn btn-outline btn-large">
<a href="login" class="btn btn-outline btn-large">
<i class="fas fa-sign-in-alt"></i> 已有账号
</a>
</div>
@@ -90,8 +111,8 @@ $mainDomains = getMainDomains();
</div>
<div class="feature-card">
<i class="fas fa-cloud-upload-alt"></i>
<h3>Cloudflare 驱动</h3>
<p>域名自动托管到 Cloudflare,全球节点加速,稳定可靠</p>
<h3>域名数量</h3>
<p>目前有 3 个域名:euil.cn、feld.top、lrgdmc.cn,全球节点加速,稳定可靠</p>
</div>
<div class="feature-card">
<i class="fas fa-users"></i>
@@ -108,7 +129,48 @@ $mainDomains = getMainDomains();
<p style="margin-top:6px;font-size:12px;">
<i class="fas fa-shield-alt"></i> 所有数据安全加密
</p>
<div class="social-links" style="display: none;">
<a href="https://facebook.com/" target="_blank" rel="noopener">
<i class="fab fa-facebook"></i>
</a>
<a href="https://twitter.com/" target="_blank" rel="noopener">
<i class="fab fa-twitter"></i>
</a>
<a href="https://linkedin.com/" target="_blank" rel="noopener">
<i class="fab fa-linkedin"></i>
</a>
<a href="https://instagram.com/" target="_blank" rel="noopener">
<i class="fab fa-instagram"></i>
</a>
<a href="https://youtube.com/" target="_blank" rel="noopener">
<i class="fab fa-youtube"></i>
</a>
</div>
</footer>
</div>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Parlz Domains",
"description": "免费二级域名分发平台,支持 A、AAAA、CNAME、MX、NS、TXT、SRV 记录,积分制管理。",
"url": "https://dns.parlz.com/",
"applicationCategory": "NetworkApplication",
"operatingSystem": "All",
"browserRequirements": "现代浏览器",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "CNY",
"availability": "https://schema.org/InStock"
},
"provider": {
"@type": "Organization",
"name": "Parlz Domains",
"url": "https://dns.parlz.com/"
},
"inLanguage": "zh-CN"
}
</script>
</body>
</html>
+6 -3
查看文件
@@ -22,10 +22,13 @@ try {
is_admin TINYINT DEFAULT 0,
is_verified TINYINT DEFAULT 0,
verification_token VARCHAR(64),
reset_token VARCHAR(64) NULL,
reset_expires DATETIME NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_sign_in DATE,
INDEX idx_invite_code (invite_code),
INDEX idx_email (email),
INDEX idx_reset_token (reset_token),
FOREIGN KEY (invited_by) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
@@ -83,12 +86,12 @@ try {
('max_domains_per_user', '10'),
('sign_in_credit', '2'),
('invite_credit', '10'),
('site_name', '域名分发系统')
('site_name', 'Parlz Domains')
");
// 创建管理员账户(提示用户输入)
echo "<h2>数据库安装成功!</h2>";
echo "<p><b>您已安装 Parlz Domains Beta 0.1。</b></p>"
echo "<h2>数据库安装成功!</h2>";
echo "<p><b>您已安装 " . SITE_NAME . " Beta 0.2。</b></p>";
echo "<p>请访问 <a href='auth.php?action=register'>注册页面</a> 来创建管理员账户。</p>";
echo "<p><a href='/'>进入首页</a></p>";
+147
查看文件
@@ -0,0 +1,147 @@
<?php
require_once 'functions.php';
$currentTheme = getTheme();
$message = null;
$success = false;
$token = $_GET['token'] ?? '';
// 验证token
if (empty($token)) {
$message = '缺少重置令牌';
$error = true;
} else {
// 验证token是否有效
$pdo = getDB();
$stmt = $pdo->prepare("SELECT id, email FROM users WHERE reset_token = ? AND reset_expires > NOW()");
$stmt->execute([$token]);
$user = $stmt->fetch();
if (!$user) {
$message = '重置链接无效或已过期,请重新申请';
$error = true;
} else {
$error = false;
}
}
// 处理密码重置
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$error) {
$password = $_POST['password'] ?? '';
$confirm = $_POST['confirm_password'] ?? '';
if (strlen($password) < 6) {
$message = '密码长度至少6位';
} elseif ($password !== $confirm) {
$message = '两次密码输入不一致';
} else {
$result = resetPassword($token, $password);
if ($result['success']) {
$success = true;
$message = $result['message'];
} else {
$message = $result['message'];
}
}
}
$pageTitle = '重置密码 - ' . SITE_NAME;
$pageDescription = '重置您的 ' . SITE_NAME . ' 账号密码。';
?>
<!DOCTYPE html>
<html lang="zh-CN" data-theme="<?php echo $currentTheme; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<meta name="description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<link rel="canonical" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/reset-password.php">
<meta name="robots" content="index, follow">
<link rel="alternate" hreflang="zh-CN" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/reset_password.php" />
<meta name="twitter:site" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/reset_password.php">
<meta property="og:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
<meta property="og:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<meta property="og:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/reset_password">
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
<meta name="twitter:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
<meta name="twitter:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "<?php echo htmlspecialchars($pageTitle); ?>",
"description": "<?php echo htmlspecialchars($pageDescription); ?>",
"url": "https://<?php echo $_SERVER['HTTP_HOST']; ?>/reset_password.php",
"inLanguage": "zh-CN"
}
</script>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="auth-container">
<div class="auth-card">
<div class="icon-top">
<i class="fas fa-lock"></i>
</div>
<h2>重置密码</h2>
<p class="subtitle">设置新密码</p>
<?php if ($message && !$success): ?>
<div class="alert alert-error">
<i class="fas fa-exclamation-circle"></i>
<?php echo htmlspecialchars($message); ?>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="success-box">
<i class="fas fa-check-circle"></i>
<h3>✅ 密码重置成功</h3>
<p><?php echo htmlspecialchars($message); ?></p>
<a href="/login" class="btn btn-primary" style="display:inline-flex;width:auto;padding:12px 32px;">
<i class="fas fa-sign-in-alt"></i> 立即登录
</a>
</div>
<?php elseif ($error): ?>
<div class="alert alert-error" style="margin-top:10px;">
<i class="fas fa-exclamation-circle"></i>
<?php echo htmlspecialchars($message); ?>
</div>
<div class="auth-links" style="margin-top:20px;">
<a href="/forgot-password">重新申请重置链接</a>
</div>
<?php else: ?>
<form method="POST">
<div class="form-group">
<label><i class="fas fa-lock"></i> 新密码</label>
<input type="password" name="password" placeholder="至少6位" required minlength="6">
<div class="password-hint">密码至少6个字符</div>
</div>
<div class="form-group">
<label><i class="fas fa-lock"></i> 确认密码</label>
<input type="password" name="confirm_password" placeholder="再次输入新密码" required minlength="6">
</div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-check"></i> 确认重置
</button>
</form>
<div class="auth-links">
<a href="/login">返回登录</a>
</div>
<?php endif; ?>
</div>
</div>
</div>
</body>
</html>
+4
查看文件
@@ -0,0 +1,4 @@
User-agent: *
Disallow: /vendor/
Disallow: /aliapi/
Sitemap: https://dns.parlz.com/sitemap.xml
+356
查看文件
@@ -0,0 +1,356 @@
<?php
require_once 'functions.php';
$currentTheme = getTheme();
if (isset($_GET['ajax']) && $_GET['ajax'] == 1) {
header('Content-Type: application/json; charset=utf-8');
$domain = isset($_GET['domain']) ? trim($_GET['domain']) : '';
if (empty($domain)) {
echo json_encode(['success' => false, 'message' => '请提供域名参数']);
exit;
}
if (!preg_match('/^([a-z0-9\-]+\.)+[a-z]{2,}$/i', $domain)) {
echo json_encode(['success' => false, 'message' => '域名格式无效']);
exit;
}
$pdo = getDB();
$parts = explode('.', $domain);
$subdomain = strtolower($parts[0]);
$mainDomain = strtolower(implode('.', array_slice($parts, 1)));
$mainDomains = getMainDomains();
if (!in_array($mainDomain, $mainDomains)) {
echo json_encode([
'success' => true,
'available' => false,
'message' => '不支持的域名: ' . $mainDomain,
'record_type' => null,
'record_value' => null,
'username' => null,
'created_at' => null
]);
exit;
}
$stmt = $pdo->prepare("SELECT d.*, u.username FROM domains d LEFT JOIN users u ON d.user_id = u.id WHERE d.main_domain = ? AND d.subdomain = ? AND d.status = 1");
$stmt->execute([$mainDomain, $subdomain]);
$record = $stmt->fetch();
if ($record) {
echo json_encode([
'success' => true,
'available' => false,
'message' => '该域名已被 ' . htmlspecialchars($record['username'] ?? '用户') . ' 占用',
'record_type' => $record['record_type'],
'record_value' => $record['record_value'],
'username' => $record['username'] ?? null,
'created_at' => $record['created_at']
]);
} else {
echo json_encode([
'success' => true,
'available' => true,
'message' => '域名可用',
'record_type' => null,
'record_value' => null,
'username' => null,
'created_at' => null
]);
}
exit;
}
?>
<!DOCTYPE html>
<html lang="zh-CN" data-theme="<?php echo $currentTheme; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>域名查询 - <?php echo SITE_NAME; ?></title>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
<meta name="description" content="查询域名是否被占用。支持 euil.cn、feld.top、lrgdmc.cn 等主域名。">
<meta name="keywords" content="域名查询,域名占用,子域名查询">
<meta property="og:title" content="域名查询 - <?php echo SITE_NAME; ?>">
<meta property="og:description" content="查询域名是否被占用。支持多个主域名。">
<meta property="og:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/search">
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?php echo SITE_NAME; ?>">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="域名查询 - <?php echo SITE_NAME; ?>">
<meta name="twitter:description" content="查询域名是否被占用。">
<meta name="twitter:image" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/favicon.ico">
<meta name="robots" content="index, follow">
<link rel="alternate" hreflang="zh-CN" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/search" />
<meta name="twitter:site" content="https://<?php echo $_SERVER['HTTP_HOST']; ?>/search">
<link rel="canonical" href="https://<?php echo $_SERVER['HTTP_HOST']; ?>/search">
</head>
<body>
<div class="container">
<header>
<div class="header-content">
<h1><i class="fas fa-globe"></i> <?php echo SITE_NAME; ?></h1>
<div class="header-actions">
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="toggle_theme">
<button type="submit" class="theme-toggle" title="切换主题">
<i class="fas <?php echo $currentTheme === 'dark' ? 'fa-sun' : 'fa-moon'; ?>"></i>
</button>
</form>
<a href="auth.php?action=login" class="btn btn-primary btn-sm">
<i class="fas fa-sign-in-alt"></i>
</a>
<a href="auth.php?action=register" class="btn btn-sm" style="background:var(--bg-primary);border:1px solid var(--border-color);color:var(--text-primary);">
<i class="fas fa-user-plus"></i>
</a>
</div>
</div>
</header>
<div class="search-container">
<div class="search-header">
<h1><i class="fas fa-search"></i> 域名查询</h1>
<p>输入要查询的域名,检查是否已被注册或占用</p>
</div>
<div class="search-box">
<input type="text" id="domainInput" placeholder="输入域名,例如:abc.euil.cn" />
<button class="btn btn-primary" id="searchBtn">
<i class="fas fa-search"></i> 查询
</button>
</div>
<div class="result-card" id="resultCard">
<div class="result-status" id="resultStatus">
<div class="icon"><div class="loading-spinner"></div></div>
<div class="info">
<div class="main" id="resultMain">查询中...</div>
<div class="sub" id="resultSub">正在检查域名状态</div>
</div>
</div>
<div class="result-details" id="resultDetails">
<table>
<tr><td>完整域名</td><td id="detailFullDomain">-</td></tr>
<tr><td>状态</td><td id="detailStatus">-</td></tr>
<tr><td>所属用户</td><td id="detailUser">-</td></tr>
<tr><td>创建时间</td><td id="detailTime">-</td></tr>
</table>
</div>
<div class="result-actions" id="resultActions">
<a href="#" class="btn btn-primary" id="actionAddDomain" style="display:none;">
<i class="fas fa-plus"></i> 添加此域名
</a>
</div>
</div>
<div class="card history-card">
<div class="card-header">
<h2><i class="fas fa-clock"></i> 最近查询</h2>
<span class="clear-history" id="clearHistory">清空记录</span>
</div>
<div class="card-body" id="historyContainer">
<div class="empty-state">
<i class="fas fa-inbox"></i>
<p>暂无查询记录</p>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var domainInput = document.getElementById('domainInput');
var searchBtn = document.getElementById('searchBtn');
var resultCard = document.getElementById('resultCard');
var resultStatus = document.getElementById('resultStatus');
var resultMain = document.getElementById('resultMain');
var resultSub = document.getElementById('resultSub');
var detailFullDomain = document.getElementById('detailFullDomain');
var detailStatus = document.getElementById('detailStatus');
var detailType = document.getElementById('detailType');
var detailValue = document.getElementById('detailValue');
var detailUser = document.getElementById('detailUser');
var detailTime = document.getElementById('detailTime');
var actionAddDomain = document.getElementById('actionAddDomain');
var historyContainer = document.getElementById('historyContainer');
var clearHistoryBtn = document.getElementById('clearHistory');
loadHistory();
searchBtn.addEventListener('click', doSearch);
domainInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') doSearch();
});
document.querySelectorAll('.tag').forEach(function(tag) {
tag.addEventListener('click', function() {
domainInput.value = this.dataset.domain;
doSearch();
});
});
clearHistoryBtn.addEventListener('click', function() {
if (confirm('确定要清空所有查询记录吗?')) {
localStorage.removeItem('domainSearchHistory');
loadHistory();
}
});
function doSearch() {
var domain = domainInput.value.trim();
if (!domain) {
alert('请输入域名');
return;
}
if (!domain.match(/^([a-z0-9\-]+\.)+[a-z]{2,}$/i)) {
alert('请输入正确的域名格式,例如:api.euil.cn');
return;
}
resultCard.classList.add('show');
resultStatus.className = 'result-status checking';
resultStatus.querySelector('.icon').innerHTML = '<div class="loading-spinner"></div>';
resultMain.textContent = '查询中...';
resultSub.textContent = '正在检查域名 ' + domain;
actionAddDomain.style.display = 'none';
var xhr = new XMLHttpRequest();
xhr.open('GET', '/search/' + encodeURIComponent(domain) + '&ajax=1', true);
xhr.timeout = 30000;
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
var data = JSON.parse(xhr.responseText);
if (data.success) {
displayResult(data, domain);
saveHistory(domain, data);
} else {
showError(data.message || '查询失败');
}
} catch (e) {
showError('解析响应失败');
}
} else {
showError('服务器错误 (HTTP ' + xhr.status + ')');
}
}
};
xhr.onerror = function() {
showError('网络错误,请稍后重试');
};
xhr.ontimeout = function() {
showError('请求超时,请稍后重试');
};
xhr.send();
}
function displayResult(data, domain) {
resultStatus.className = 'result-status ' + (data.available ? 'available' : 'unavailable');
resultStatus.querySelector('.icon').innerHTML = '<i class="fas ' + (data.available ? 'fa-check-circle' : 'fa-times-circle') + '"></i>';
if (data.available) {
resultMain.textContent = '✅ 域名可用!';
resultSub.textContent = '该域名尚未被注册,可以添加使用';
actionAddDomain.style.display = 'inline-block';
actionAddDomain.href = 'dashboard.php?domain=' + encodeURIComponent(domain);
} else {
resultMain.textContent = '❌ 域名已被占用';
resultSub.textContent = data.message || '该域名已被注册或占用';
actionAddDomain.style.display = 'none';
}
detailFullDomain.textContent = domain;
detailStatus.textContent = data.available ? '可用' : '已占用';
detailType.textContent = data.record_type || '-';
detailValue.textContent = data.record_value || '-';
detailUser.textContent = data.username || '-';
detailTime.textContent = data.created_at || '-';
}
function showError(message) {
resultStatus.className = 'result-status';
resultStatus.querySelector('.icon').innerHTML = '<i class="fas fa-exclamation-circle" style="color:var(--accent-red);font-size:28px;"></i>';
resultMain.textContent = '❌ 查询失败';
resultSub.textContent = message;
actionAddDomain.style.display = 'none';
detailFullDomain.textContent = '-';
detailStatus.textContent = '错误';
detailType.textContent = '-';
detailValue.textContent = '-';
detailUser.textContent = '-';
detailTime.textContent = '-';
}
function saveHistory(domain, data) {
var history = JSON.parse(localStorage.getItem('domainSearchHistory') || '[]');
history = history.filter(function(item) { return item.domain !== domain; });
history.unshift({
domain: domain,
available: data.available,
time: new Date().toISOString()
});
if (history.length > 20) history = history.slice(0, 20);
localStorage.setItem('domainSearchHistory', JSON.stringify(history));
loadHistory();
}
function loadHistory() {
var history = JSON.parse(localStorage.getItem('domainSearchHistory') || '[]');
if (history.length === 0) {
historyContainer.innerHTML = '<div class="empty-state"><i class="fas fa-inbox"></i><p>暂无查询记录</p></div>';
return;
}
var html = '<div class="history-list">';
history.forEach(function(item) {
var statusClass = item.available ? 'available' : 'unavailable';
var statusText = item.available ? '✅ 可用' : '❌ 已占用';
var time = new Date(item.time).toLocaleString('zh-CN');
html += '<div class="history-item" data-domain="' + item.domain + '">' +
'<span class="domain-name">' + item.domain + '</span>' +
'<span>' +
'<span class="status-badge ' + statusClass + '">' + statusText + '</span> ' +
'<span class="time-text">' + time + '</span>' +
'</span>' +
'</div>';
});
html += '</div>';
historyContainer.innerHTML = html;
document.querySelectorAll('.history-item').forEach(function(item) {
item.addEventListener('click', function() {
domainInput.value = this.dataset.domain;
doSearch();
});
});
}
var urlParams = new URLSearchParams(window.location.search);
var domainParam = urlParams.get('domain');
if (domainParam) {
domainInput.value = domainParam;
doSearch();
}
});
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SearchResultsPage",
"name": "域名查询 - <?php echo SITE_NAME; ?>",
"description": "查询域名是否被占用,支持 euil.cn、feld.top、lrgdmc.cn 等主域名。",
"url": "https://<?php echo $_SERVER['HTTP_HOST']; ?>/search",
"inLanguage": "zh-CN",
"about": {
"@type": "Thing",
"name": "域名查询"
}
}
</script>
</body>
</html>
+546 -10
查看文件
@@ -21,7 +21,7 @@
--accent-orange: #f0883e;
--radius: 12px;
--radius-sm: 6px;
--transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1)
}
[data-theme="light"] {
@@ -54,7 +54,7 @@
}
* {
font-family: "Yozai Medium"
font-family: "Yozai Medium"
}
html {
@@ -969,7 +969,7 @@ tbody tr:last-child td {
background: var(--bg-primary);
padding: 1px 10px;
border-radius: 4px;
font-size: 11px;
font-size: 12px;
font-weight: 700;
color: var(--accent-yellow);
border: 1px solid var(--border-color)
@@ -1386,7 +1386,7 @@ footer .fa-heart {
}
.recent-user {
font-size: 11px
font-size: 12px
}
.record-type-help {
@@ -1419,7 +1419,7 @@ footer .fa-heart {
}
.btn-sm {
font-size: 11px;
font-size: 12px;
padding: 4px 10px
}
}
@@ -1439,7 +1439,7 @@ footer .fa-heart {
}
.stat-card .label {
font-size: 11px
font-size: 12px
}
.features-grid {
@@ -1460,7 +1460,7 @@ footer .fa-heart {
}
.feature-card p {
font-size: 11px
font-size: 12px
}
.hero h1 {
@@ -1476,7 +1476,7 @@ footer .fa-heart {
}
.domain-badge {
font-size: 11px;
font-size: 12px;
padding: 4px 10px
}
@@ -1485,7 +1485,7 @@ footer .fa-heart {
}
.badge {
font-size: 11px;
font-size: 12px;
padding: 1px 10px
}
@@ -1509,6 +1509,542 @@ footer .fa-heart {
}
.stats-bar .stat-label {
font-size: 11px
font-size: 12px
}
}
.search-container {
max-width: 700px;
margin: 60px auto 40px
}
.search-box-large {
display: flex;
gap: 12px;
background: var(--bg-secondary);
padding: 20px;
border-radius: var(--radius);
border: 1px solid var(--border-color);
box-shadow: var(--shadow)
}
.search-box-large input {
flex: 1;
padding: 14px 18px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-primary);
font-size: 16px;
outline: none;
transition: all var(--transition)
}
.search-box-large input:focus {
border-color: var(--accent-blue);
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.15)
}
.search-box-large button {
padding: 14px 32px;
font-size: 16px;
white-space: nowrap
}
.result-card {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: var(--radius);
padding: 30px;
margin-top: 25px;
box-shadow: var(--shadow);
display: none
}
.result-card.show {
display: block;
animation: slideDown 0.4s ease
}
.result-status {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 20px;
border-radius: var(--radius-sm);
margin-bottom: 16px
}
.result-status.available {
background: rgba(63, 185, 80, 0.12);
border: 1px solid var(--accent-green);
color: var(--accent-green)
}
.result-status.unavailable {
background: rgba(248, 81, 73, 0.12);
border: 1px solid var(--accent-red);
color: var(--accent-red)
}
.result-status.checking {
background: rgba(88, 166, 255, 0.12);
border: 1px solid var(--accent-blue);
color: var(--accent-blue)
}
.result-status .icon {
font-size: 28px
}
.result-status .info {
flex: 1
}
.result-status .info .main {
font-size: 18px;
font-weight: 600
}
.result-status .info .sub {
font-size: 13px;
opacity: 0.8
}
.result-details {
padding: 16px 20px;
background: var(--bg-primary);
border-radius: var(--radius-sm);
border: 1px solid var(--border-color)
}
.result-details table {
width: 100%;
font-size: 14px
}
.result-details table td {
padding: 6px 10px
}
.result-details table td:first-child {
color: var(--text-muted);
width: 120px
}
.result-actions {
margin-top: 16px;
display: flex;
gap: 12px;
flex-wrap: wrap
}
.suggestions {
margin-top: 12px;
display: flex;
gap: 8px;
flex-wrap: wrap
}
.suggestions .tag {
padding: 4px 14px;
border-radius: 20px;
background: var(--bg-primary);
border: 1px solid var(--border-color);
font-size: 13px;
color: var(--text-secondary);
cursor: pointer;
transition: all var(--transition)
}
.suggestions .tag:hover {
border-color: var(--accent-blue);
color: var(--accent-blue)
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid var(--border-color);
border-top-color: var(--accent-blue);
border-radius: 50%;
animation: spin 0.8s linear infinite
}
@keyframes spin {
to {
transform: rotate(360deg)
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-20px)
}
to {
opacity: 1;
transform: translateY(0)
}
}
.history-list {
margin-top: 20px
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 14px;
border-bottom: 1px solid var(--border-color);
font-size: 14px
}
.history-item:last-child {
border-bottom: none
}
.history-item .status-badge {
font-size: 12px;
padding: 2px 12px;
border-radius: 12px
}
.status-badge.available {
background: rgba(63, 185, 80, 0.15);
color: var(--accent-green)
}
.status-badge.unavailable {
background: rgba(248, 81, 73, 0.15);
color: var(--accent-red)
}
.suggestions-title {
font-size: 13px;
color: var(--text-muted);
margin-top: 12px
}
@media (max-width:600px) {
.search-box-large {
flex-direction: column
}
.search-box-large button {
width: 100%;
justify-content: center
}
.result-status {
flex-direction: column;
text-align: center
}
.result-details table td {
display: block;
padding: 4px 0
}
.result-details table td:first-child {
width: auto;
font-weight: 600
}
}
.auth-container {
max-width: 440px;
margin: 60px auto 40px;
padding: 0 16px
}
.auth-card {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: var(--radius);
padding: 40px;
box-shadow: var(--shadow)
}
.auth-card .icon-top {
text-align: center;
font-size: 48px;
color: var(--accent-blue);
margin-bottom: 16px
}
.auth-card h2 {
text-align: center;
margin-bottom: 8px;
font-weight: 700
}
.auth-card .subtitle {
text-align: center;
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 24px
}
.auth-card .form-group {
margin-bottom: 18px
}
.auth-card .form-group label {
display: block;
font-size: 14px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 6px
}
.auth-card .form-group label i {
margin-right: 6px;
color: var(--accent-blue)
}
.auth-card .form-group input {
width: 100%;
padding: 12px 16px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-primary);
font-size: 15px;
transition: all var(--transition);
outline: none
}
.auth-card .form-group input:focus {
border-color: var(--accent-blue);
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.15)
}
.auth-card .btn-primary {
width: 100%;
padding: 14px;
font-size: 16px;
justify-content: center
}
.auth-card .auth-links {
text-align: center;
margin-top: 18px;
font-size: 14px;
color: var(--text-secondary)
}
.auth-card .auth-links a {
color: var(--accent-blue);
text-decoration: none
}
.auth-card .auth-links a:hover {
text-decoration: underline
}
.alert {
padding: 12px 16px;
border-radius: var(--radius-sm);
margin-bottom: 18px;
display: flex;
align-items: center;
gap: 10px;
font-size: 14px
}
.alert-success {
background: rgba(63, 185, 80, 0.12);
border: 1px solid var(--accent-green);
color: var(--accent-green)
}
.alert-error {
background: rgba(248, 81, 73, 0.12);
border: 1px solid var(--accent-red);
color: var(--accent-red)
}
.alert i {
font-size: 18px
}
.success-box {
text-align: center;
padding: 20px 0
}
.success-box i {
font-size: 64px;
color: var(--accent-green);
margin-bottom: 16px
}
.success-box h3 {
margin-bottom: 8px
}
.success-box p {
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 20px
}
@media (max-width:600px) {
.auth-card {
padding: 24px 20px
}
}
.auth-container {
max-width: 440px;
margin: 60px auto 40px;
padding: 0 16px
}
.auth-card {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: var(--radius);
padding: 40px;
box-shadow: var(--shadow)
}
.auth-card .icon-top {
text-align: center;
font-size: 48px;
color: var(--accent-blue);
margin-bottom: 16px
}
.auth-card h2 {
text-align: center;
margin-bottom: 8px;
font-weight: 700
}
.auth-card .subtitle {
text-align: center;
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 24px
}
.auth-card .form-group {
margin-bottom: 18px
}
.auth-card .form-group label {
display: block;
font-size: 14px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 6px
}
.auth-card .form-group label i {
margin-right: 6px;
color: var(--accent-blue)
}
.auth-card .form-group input {
width: 100%;
padding: 12px 16px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-primary);
font-size: 15px;
transition: all var(--transition);
outline: none
}
.auth-card .form-group input:focus {
border-color: var(--accent-blue);
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.15)
}
.auth-card .btn-primary {
width: 100%;
padding: 14px;
font-size: 16px;
justify-content: center
}
.auth-card .auth-links {
text-align: center;
margin-top: 18px;
font-size: 14px;
color: var(--text-secondary)
}
.auth-card .auth-links a {
color: var(--accent-blue);
text-decoration: none
}
.auth-card .auth-links a:hover {
text-decoration: underline
}
.alert {
padding: 12px 16px;
border-radius: var(--radius-sm);
margin-bottom: 18px;
display: flex;
align-items: center;
gap: 10px;
font-size: 14px
}
.alert-success {
background: rgba(63, 185, 80, 0.12);
border: 1px solid var(--accent-green);
color: var(--accent-green)
}
.alert-error {
background: rgba(248, 81, 73, 0.12);
border: 1px solid var(--accent-red);
color: var(--accent-red)
}
.alert i {
font-size: 18px
}
.success-box {
text-align: center;
padding: 20px 0
}
.success-box i {
font-size: 64px;
color: var(--accent-green);
margin-bottom: 16px
}
.success-box h3 {
margin-bottom: 8px
}
.success-box p {
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 20px
}
.password-hint {
font-size: 12px;
color: var(--text-muted);
margin-top: 4px
}
@media (max-width:600px) {
.auth-card {
padding: 24px 20px
}
}
+58
查看文件
@@ -0,0 +1,58 @@
<?php
require_once 'functions.php';
$token = $_GET['token'] ?? '';
// 添加调试日志
error_log("验证请求 - Token: " . $token);
if (empty($token)) {
die('缺少验证令牌');
}
$result = verifyEmail($token);
// 调试日志
error_log("验证结果: " . ($result['success'] ? '成功' : '失败') . " - " . $result['message']);
?>
<!DOCTYPE html>
<html lang="zh-CN" data-theme="<?php echo getTheme(); ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>邮箱验证 - <?php echo SITE_NAME; ?></title>
<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container verify-container">
<div class="verify-card">
<?php if ($result['success']): ?>
<div class="icon success">
<i class="fas fa-check-circle"></i>
</div>
<h2>验证成功!</h2>
<p>您的邮箱已成功验证,现在可以登录来使用所有功能了。</p>
<a href="auth.php?action=login" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> 去登录
</a>
<?php else: ?>
<div class="icon error">
<i class="fas fa-exclamation-circle"></i>
</div>
<h2>验证失败!</h2>
<p><?php echo htmlspecialchars($result['message']); ?></p>
<p style="font-size: 13px; color: var(--text-muted);">
<i class="fas fa-info-circle"></i>
可能的原因:链接已过期、已被使用或无效,请联系管理员手动激活。
</p>
<div style="display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;">
<a href="auth.php?action=login" class="btn btn-outline">
<i class="fas fa-sign-in-alt"></i> 登录
</a>
</div>
<?php endif; ?>
</div>
</div>
</body>
</html>