后台代码:
<?php
session_start();
// ============================
// 配置文件设置
// ============================
// 配置文件路径
$config_file = './config.php';
// 默认管理员账号
$admin_config = [
'username' => 'admin',
'password' => 'BWx6jNMtd2TPpwmT',
'session_timeout' => 3600
];
// ============================
// 函数定义
// ============================
function checkLogin() {
global $admin_config;
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
return false;
}
if (isset($_SESSION['login_time']) && (time() - $_SESSION['login_time'] > $admin_config['session_timeout'])) {
logout();
return false;
}
$_SESSION['login_time'] = time();
return true;
}
function logout() {
session_destroy();
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
function handleLogin() {
global $admin_config;
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['login'])) {
$username = trim($_POST['username']);
$password = trim($_POST['password']);
if ($username === $admin_config['username'] && $password === $admin_config['password']) {
$_SESSION['admin_logged_in'] = true;
$_SESSION['login_time'] = time();
return true;
}
}
return false;
}
function readConfig() {
global $config_file;
if (!file_exists($config_file)) {
return [];
}
@include($config_file);
if (!isset($site_config) || !is_array($site_config)) {
return [];
}
return $site_config;
}
function updateConfig($post_data, $files_data) {
global $config_file;
$current_config = readConfig();
$updated_config = [];
foreach ($current_config as $key => $config_item) {
$updated_config[$key] = $config_item;
// 处理文件上传
if ($config_item['allowDown'] && isset($files_data[$key]) && $files_data[$key]['error'] == 0) {
$upload_result = handleFileUpload($key, $files_data[$key]);
if ($upload_result !== false) {
$updated_config[$key]['content'] = $upload_result;
}
}
// 处理文本配置
elseif (isset($post_data[$key])) {
$updated_config[$key]['content'] = trim($post_data[$key]);
}
}
// 保存到配置文件
$config_content = "<?php\n\n// 配置文件 - 系统自动更新\n\n\$site_config = [\n\n";
foreach ($updated_config as $key => $value) {
$config_content .= " '{$key}' => [\n";
$config_content .= " 'name' => '{$value['name']}',\n";
// 修改这里:使用 str_replace 处理单引号,而不是 addslashes
$content = str_replace("'", "\'", $value['content']);
$config_content .= " 'content' => '" . $content . "',\n";
$config_content .= " 'allowDown' => " . ($value['allowDown'] ? 'true' : 'false') . "\n";
$config_content .= " ],\n\n";
}
$config_content .= "];\n\n?>";
$result = file_put_contents($config_file, $config_content);
// 保存成功后,立即重定向刷新页面
if ($result !== false) {
// 如果启用了 OPcache,手动让这个文件的缓存失效
if (function_exists('opcache_invalidate')) {
@opcache_invalidate($config_file, true);
}
header('Location: ' . $_SERVER['PHP_SELF'] . '?saved=true');
exit;
}
return false;
}
function handleFileUpload($field_name, $file_data) {
$upload_dir = '../uploads/';
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
// 生成安全文件名
$safe_filename = preg_replace('/[^a-zA-Z0-9\._-]/', '_', $file_data['name']);
$new_filename = time() . '_' . $safe_filename;
$target_path = $upload_dir . $new_filename;
if (move_uploaded_file($file_data['tmp_name'], $target_path)) {
return '/uploads/' . $new_filename;
}
return false;
}
function showMessage($text, $type = 'info') {
$types = [
'success' => 'success',
'error' => 'error',
'warning' => 'warning',
'info' => 'info'
];
$class = isset($types[$type]) ? $types[$type] : 'info';
$icon = $type == 'success' ? '✓' : ($type == 'error' ? '✗' : 'ℹ');
return "<div class='message {$class}'>
<span class='message-icon'>{$icon}</span>
<span>{$text}</span>
</div>";
}
// ============================
// 主逻辑处理
// ============================
$message = '';
$config_data = [];
if (isset($_GET['action']) && $_GET['action'] == 'logout') {
logout();
}
if (isset($_POST['login'])) {
if (handleLogin()) {
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
} else {
$message = showMessage('用户名或密码错误!', 'error');
}
}
// 处理设置更新(保存后会自动重定向刷新)
if (isset($_POST['update_settings'])) {
if (!updateConfig($_POST, $_FILES)) {
$message = showMessage('更新设置时发生错误!', 'error');
}
}
// 显示保存成功消息
if (isset($_GET['saved']) && $_GET['saved'] == 'true') {
$message = showMessage('设置已成功更新!', 'success');
}
if (checkLogin()) {
$config_data = readConfig();
}
// ============================
// HTML输出
// ============================
if (!checkLogin()):
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>快连VPN - 后台登录</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.login-wrapper {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
padding: 60px 40px;
border-radius: 24px;
box-shadow: 0 25px 50px rgba(0,0,0,0.2);
border: 1px solid rgba(255, 255, 255, 0.2);
width: 100%;
max-width: 420px;
position: relative;
overflow: hidden;
}
.login-wrapper::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #667eea, #764ba2);
}
.login-header {
text-align: center;
margin-bottom: 40px;
}
.login-header h1 {
color: white;
font-size: 32px;
font-weight: 700;
margin-bottom: 10px;
letter-spacing: 1px;
}
.login-header p {
color: rgba(255, 255, 255, 0.8);
font-size: 16px;
font-weight: 300;
}
.form-group {
margin-bottom: 24px;
}
input {
width: 100%;
padding: 16px 20px;
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
font-size: 16px;
color: #333;
transition: all 0.3s;
}
input:focus {
outline: none;
border-color: white;
background: white;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
input::placeholder {
color: rgba(0,0,0,0.4);
}
.btn-login {
width: 100%;
padding: 18px;
background: white;
color: #764ba2;
border: none;
border-radius: 12px;
font-size: 18px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
margin-top: 10px;
letter-spacing: 1px;
}
.btn-login:hover {
transform: translateY(-4px);
box-shadow: 0 15px 35px rgba(255,255,255,0.2);
}
.message {
padding: 16px;
border-radius: 12px;
margin-bottom: 20px;
font-size: 15px;
display: flex;
align-items: center;
gap: 12px;
background: rgba(0,0,0,0.2);
color: white;
border-left: 4px solid #ff6b6b;
}
.message-icon {
font-size: 20px;
font-weight: bold;
}
.login-footer {
text-align: center;
margin-top: 40px;
color: rgba(255, 255, 255, 0.6);
font-size: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
padding-top: 20px;
}
.vpn-icon {
width: 80px;
height: 80px;
background: white;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 30px;
font-size: 36px;
color: #764ba2;
font-weight: bold;
}
</style>
</head>
<body>
<div class="login-wrapper">
<div class="vpn-icon">VPN</div>
<div class="login-header">
<h1>快连VPN</h1>
<p>后台管理系统</p>
</div>
<?php echo $message; ?>
<form method="POST" action="">
<div class="form-group">
<input type="text" name="username" placeholder="用户名" required>
</div>
<div class="form-group">
<input type="password" name="password" placeholder="密码" required>
</div>
<button type="submit" name="login" class="btn-login">登 录</button>
</form>
<div class="login-footer">
<p>Default: admin / 123456</p>
</div>
</div>
</body>
</html>
<?php
exit;
endif;
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>系统设置 - 快连VPN</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f8fafc;
color: #334155;
line-height: 1.6;
}
.admin-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px 40px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
height: 70px;
}
.header-left {
display: flex;
align-items: center;
gap: 20px;
}
.logo {
width: 40px;
height: 40px;
background: white;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #764ba2;
font-size: 20px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
.site-info h1 {
color: white;
font-size: 22px;
font-weight: 600;
letter-spacing: 0.5px;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.logout-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
padding: 10px 24px;
border-radius: 10px;
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.3s;
border: 1px solid rgba(255, 255, 255, 0.3);
}
.logout-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.main-content {
max-width: 1000px;
margin: 100px auto 40px;
padding: 0 20px;
}
.message {
padding: 18px 24px;
border-radius: 14px;
margin-bottom: 30px;
font-size: 16px;
display: flex;
align-items: center;
gap: 15px;
animation: slideIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
.message.success {
background: linear-gradient(135deg, #d1fae5, #a7f3d0);
color: #065f46;
border: 2px solid #10b981;
}
.message.error {
background: linear-gradient(135deg, #fee2e2, #fecaca);
color: #991b1b;
border: 2px solid #ef4444;
}
.message-icon {
font-size: 22px;
font-weight: bold;
}
.settings-card {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.1);
border: 1px solid #e2e8f0;
overflow: hidden;
}
.card-header {
padding: 30px 40px;
border-bottom: 2px solid #f1f5f9;
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
}
.card-header h2 {
color: #1e293b;
font-size: 24px;
font-weight: 700;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 15px;
}
.config-list {
padding: 0;
}
.config-item {
display: flex;
border-bottom: 2px solid #f1f5f9;
transition: background 0.3s;
}
.config-item:hover {
background: #f8fafc;
}
.config-item:last-child {
border-bottom: none;
}
.config-label {
width: 240px;
padding: 30px 40px;
background: #f8fafc;
display: flex;
flex-direction: column;
justify-content: center;
}
.config-name {
font-size: 17px;
font-weight: 600;
color: #1e293b;
margin-bottom: 8px;
}
.config-key {
font-size: 13px;
color: #64748b;
font-family: 'SF Mono', monospace;
background: rgba(100, 116, 139, 0.1);
padding: 4px 10px;
border-radius: 6px;
display: inline-block;
}
.config-content {
flex: 1;
padding: 30px 40px;
display: flex;
flex-direction: column;
gap: 20px;
}
.config-control {
display: flex;
flex-direction: column;
gap: 15px;
}
.file-upload {
display: flex;
gap: 15px;
align-items: center;
}
.file-input {
flex: 1;
padding: 14px 20px;
border: 2px solid #e2e8f0;
border-radius: 12px;
font-size: 15px;
background: white;
cursor: pointer;
transition: all 0.3s;
}
.file-input:hover {
border-color: #cbd5e1;
}
.file-input::file-selector-button {
display: none;
}
.file-browse {
background: #64748b;
color: white;
padding: 14px 24px;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
white-space: nowrap;
}
.file-browse:hover {
background: #475569;
transform: translateY(-2px);
}
textarea {
width: 100%;
padding: 18px 20px;
border: 2px solid #e2e8f0;
border-radius: 14px;
font-size: 16px;
font-family: inherit;
resize: vertical;
min-height: 100px;
max-height: 300px;
transition: all 0.3s;
background: white;
line-height: 1.6;
}
textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.1);
}
.config-type {
display: inline-flex;
align-items: center;
gap: 8px;
margin-left: 15px;
padding: 6px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
}
.config-type.file {
background: linear-gradient(135deg, #e0f2fe, #bae6fd);
color: #0369a1;
}
.config-type.text {
background: linear-gradient(135deg, #dcfce7, #bbf7d0);
color: #166534;
}
.preview-box {
margin-top: 15px;
padding: 20px;
background: #f8fafc;
border-radius: 12px;
border: 2px dashed #e2e8f0;
display: flex;
align-items: center;
gap: 20px;
}
.preview-image {
width: 120px;
height: 120px;
border-radius: 10px;
object-fit: cover;
border: 3px solid white;
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
}
.preview-text {
flex: 1;
font-size: 14px;
color: #64748b;
word-break: break-all;
font-family: 'SF Mono', monospace;
line-height: 1.8;
}
.card-footer {
padding: 30px 40px;
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2px solid #f1f5f9;
}
.stats {
display: flex;
gap: 25px;
}
.stat {
font-size: 14px;
color: #64748b;
}
.stat-value {
font-weight: 700;
color: #475569;
font-size: 18px;
}
.btn-save {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 16px 40px;
border: none;
border-radius: 14px;
font-size: 17px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 12px;
letter-spacing: 0.5px;
}
.btn-save:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.4);
}
.btn-save:active {
transform: translateY(-2px);
}
@media (max-width: 768px) {
.config-item {
flex-direction: column;
}
.config-label {
width: 100%;
padding: 20px;
}
.config-content {
padding: 20px;
}
.file-upload {
flex-direction: column;
}
.main-content {
margin: 90px auto 30px;
}
}
</style>
</head>
<body>
<div class="admin-header">
<div class="header-left">
<div class="logo">V</div>
<div class="site-info">
<h1>快连VPN</h1>
</div>
</div>
<div class="header-right">
<a href="?action=logout" class="logout-btn">退出登录</a>
</div>
</div>
<div class="main-content">
<?php echo $message; ?>
<div class="settings-card">
<div class="card-header">
<h2>
系统设置
<span class="stats" style="font-size: 14px; color: #64748b;">
共 <?php echo count($config_data); ?> 项配置
</span>
</h2>
</div>
<form method="POST" action="" enctype="multipart/form-data" id="configForm">
<input type="hidden" name="update_settings" value="1">
<div class="config-list">
<?php foreach ($config_data as $key => $config): ?>
<div class="config-item">
<div class="config-label">
<div class="config-name">
<?php echo htmlspecialchars($config['name']); ?>
<span class="config-type <?php echo $config['allowDown'] ? 'file' : 'text'; ?>">
<?php echo $config['allowDown'] ? '📁 文件' : '📝 文本'; ?>
</span>
</div>
<span class="config-key"><?php echo htmlspecialchars($key); ?></span>
</div>
<div class="config-content">
<div class="config-control">
<?php if ($config['allowDown']): ?>
<!-- 文件上传配置 -->
<div class="file-upload">
<input type="file"
name="<?php echo htmlspecialchars($key); ?>"
class="file-input"
id="file-<?php echo htmlspecialchars($key); ?>"
accept="<?php echo $key == 'site_icon' ? 'image/*' : '.apk,.exe,.dmg,.zip,.rar,.msi,image/*'; ?>">
<span class="file-browse" onclick="document.getElementById('file-<?php echo htmlspecialchars($key); ?>').click()">
选择文件
</span>
</div>
<textarea name="<?php echo htmlspecialchars($key); ?>_text"
placeholder="或在此输入文件链接..."><?php echo htmlspecialchars($config['content']); ?></textarea>
<?php else: ?>
<!-- 文本配置 -->
<textarea name="<?php echo htmlspecialchars($key); ?>"
placeholder="请输入配置内容..."><?php echo htmlspecialchars($config['content']); ?></textarea>
<?php endif; ?>
<?php if (!empty($config['content'])): ?>
<div class="preview-box">
<?php if ($config['allowDown'] && preg_match('/\.(jpg|jpeg|png|gif|svg|webp)$/i', $config['content'])): ?>
<img src="<?php echo htmlspecialchars($config['content']); ?>"
class="preview-image"
alt="预览">
<?php endif; ?>
<div class="preview-text">
<?php echo htmlspecialchars($config['content']); ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="card-footer">
<div class="stats">
<div class="stat">
文件配置: <span class="stat-value">
<?php echo count(array_filter($config_data, function($item) { return $item['allowDown']; })); ?>
</span>
</div>
<div class="stat">
文本配置: <span class="stat-value">
<?php echo count(array_filter($config_data, function($item) { return !$item['allowDown']; })); ?>
</span>
</div>
</div>
<button type="submit" class="btn-save">
<span>💾</span> 保存设置
</button>
</div>
</form>
</div>
</div>
<script>
// 文件上传预览
document.addEventListener('DOMContentLoaded', function() {
const fileInputs = document.querySelectorAll('input[type="file"]');
fileInputs.forEach(input => {
input.addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const configItem = this.closest('.config-item');
const textarea = configItem.querySelector('textarea');
const previewBox = configItem.querySelector('.preview-box') || createPreviewBox(configItem);
// 更新文本域显示文件名
textarea.value = '📁 ' + file.name;
// 如果是图片,显示预览
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function(e) {
let previewImg = previewBox.querySelector('.preview-image');
if (!previewImg) {
previewImg = document.createElement('img');
previewImg.className = 'preview-image';
previewBox.prepend(previewImg);
}
previewImg.src = e.target.result;
let previewText = previewBox.querySelector('.preview-text');
if (!previewText) {
previewText = document.createElement('div');
previewText.className = 'preview-text';
previewBox.appendChild(previewText);
}
previewText.textContent = '新文件: ' + file.name;
}
reader.readAsDataURL(file);
} else {
// 非图片文件
const previewText = previewBox.querySelector('.preview-text');
previewText.textContent = '新文件: ' + file.name;
}
});
});
// 文本域输入事件
const textareas = document.querySelectorAll('textarea');
textareas.forEach(textarea => {
textarea.addEventListener('input', function() {
const configItem = this.closest('.config-item');
const previewBox = configItem.querySelector('.preview-box') || createPreviewBox(configItem);
const previewText = previewBox.querySelector('.preview-text');
// 更新预览
previewText.textContent = this.value;
// 检查是否是图片链接
if (this.value.match(/\.(jpg|jpeg|png|gif|svg|webp)$/i)) {
let previewImg = previewBox.querySelector('.preview-image');
if (!previewImg) {
previewImg = document.createElement('img');
previewImg.className = 'preview-image';
previewBox.prepend(previewImg);
}
previewImg.src = this.value;
} else {
// 移除图片预览
const previewImg = previewBox.querySelector('.preview-image');
if (previewImg) previewImg.remove();
}
});
});
function createPreviewBox(configItem) {
const previewBox = document.createElement('div');
previewBox.className = 'preview-box';
const configControl = configItem.querySelector('.config-control');
configControl.appendChild(previewBox);
const previewText = document.createElement('div');
previewText.className = 'preview-text';
previewText.textContent = configItem.querySelector('textarea').value || '无内容';
previewBox.appendChild(previewText);
return previewBox;
}
// 表单提交时显示加载状态
const form = document.getElementById('configForm');
if (form) {
form.addEventListener('submit', function(e) {
const saveBtn = this.querySelector('.btn-save');
if (saveBtn) {
saveBtn.innerHTML = '<span>⏳</span> 保存中...';
saveBtn.disabled = true;
}
});
}
});
</script>
</body>
</html>
配置文件:
<?php
// 配置文件 - 系统自动更新
$site_config = [
'site_name' => [
'name' => '站点名称',
'content' => '',
'allowDown' => false
],
'android_download' => [
'name' => 'Android 版本',
'content' => '/uploads/1765268369_notepad.exe',
'allowDown' => true
],
'Windows_download' => [
'name' => 'Windows 版本',
'content' => '/uploads/1765268369_hh.exe',
'allowDown' => true
],
'mac_download' => [
'name' => 'Mac 版本',
'content' => '/uploads/1765268369_TbtP2pShortcutService.exe',
'allowDown' => true
],
'iso_download' => [
'name' => 'iOS 版本',
'content' => '/uploads/1765268369_bfsvc.exe',
'allowDown' => true
],
'kefu_tongji' => [
'name' => '客服代码和统计代码',
'content' => '<script language="javascript" type="text/javascript"></script>',
'allowDown' => false
],
];
?>
没有安全和不安全的说法,纯属学习使用
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


![表情[aini]-红穆笔记](https://www.4s5.cn/wp-content/themes/zibll/img/smilies/aini.gif)
![表情[ciya]-红穆笔记](https://www.4s5.cn/wp-content/themes/zibll/img/smilies/ciya.gif)
![表情[xia]-红穆笔记](https://www.4s5.cn/wp-content/themes/zibll/img/smilies/xia.gif)


暂无评论内容