2026-06-14 14:00:24 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
require_once __DIR__ . '/cong.php';
|
|
|
|
|
|
require_once __DIR__ . '/admin/bootstrap.php';
|
|
|
|
|
|
require_once __DIR__ . '/admin/ConfigWriter.php';
|
|
|
|
|
|
require_once __DIR__ . '/lib/Cloak/DomainRepository.php';
|
|
|
|
|
|
require_once __DIR__ . '/lib/CloakAdSourceGuard.php';
|
|
|
|
|
|
require_once __DIR__ . '/lib/Cloak/CloudflareConfig.php';
|
|
|
|
|
|
require_once __DIR__ . '/lib/Cloak/DomainProvisioningService.php';
|
|
|
|
|
|
|
|
|
|
|
|
session_start();
|
|
|
|
|
|
$filename = basename(__FILE__);
|
|
|
|
|
|
$current_name = pathinfo($filename, PATHINFO_FILENAME);
|
|
|
|
|
|
|
|
|
|
|
|
// 登出
|
|
|
|
|
|
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "logout") {
|
|
|
|
|
|
unset($_SESSION['password']);
|
|
|
|
|
|
unset($_SESSION['check_result']);
|
|
|
|
|
|
echo("<script>window.location='{$current_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重置临时链接参数
|
|
|
|
|
|
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "delUrlArgs") {
|
|
|
|
|
|
$check_name = strip_tags($_REQUEST['check_name']);
|
|
|
|
|
|
$dir = dirname(__FILE__) . '/args';
|
|
|
|
|
|
$files = glob($dir . '/' . $check_name . "_*.txt");
|
|
|
|
|
|
foreach ($files as $file) {
|
|
|
|
|
|
if (preg_match('/_(\d{10})\.txt$/', $file, $m)) {
|
|
|
|
|
|
unlink($file);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
header('Location: ' . $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=edit_config&name=' . urlencode($check_name));
|
|
|
|
|
|
exit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确定当前配置上下文(供表单回显用)
|
2026-06-14 18:30:06 +08:00
|
|
|
|
$isNewConfigDraft = false;
|
2026-06-15 16:53:05 +08:00
|
|
|
|
$configCopySource = '';
|
|
|
|
|
|
$copyFrom = dash_sanitize_config_name($_REQUEST['copy_from'] ?? '');
|
2026-06-14 14:00:24 +08:00
|
|
|
|
if (!empty($_REQUEST["name"])) {
|
|
|
|
|
|
$check_name = trim($_REQUEST["name"]);
|
|
|
|
|
|
$config_name = str_replace(".php", "", $check_name);
|
|
|
|
|
|
$config_file = "check_config/" . $config_name . "_config.php";
|
|
|
|
|
|
if (!file_exists($config_file)) {
|
2026-06-14 18:30:06 +08:00
|
|
|
|
$isNewConfigDraft = true;
|
2026-06-15 16:53:05 +08:00
|
|
|
|
$sourceFile = ($copyFrom !== '') ? "check_config/{$copyFrom}_config.php" : '';
|
|
|
|
|
|
if ($copyFrom !== '' && is_file($sourceFile)) {
|
|
|
|
|
|
$config_file = $sourceFile;
|
|
|
|
|
|
$configCopySource = $copyFrom;
|
|
|
|
|
|
if ($check_name === 'new_config' || $check_name === '') {
|
|
|
|
|
|
$check_name = dash_suggest_copy_config_name($copyFrom);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$config_file = "check_config/index_config.php";
|
|
|
|
|
|
}
|
2026-06-14 14:00:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$check_name = "index";
|
2026-06-14 18:30:06 +08:00
|
|
|
|
$config_file = "check_config/index_config.php";
|
2026-06-14 14:00:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
include($config_file);
|
|
|
|
|
|
|
|
|
|
|
|
// 密码处理
|
|
|
|
|
|
if (!empty($_REQUEST['password'])) {
|
|
|
|
|
|
$_SESSION['password'] = $_REQUEST['password'];
|
|
|
|
|
|
$_SESSION["myaction"] = $_REQUEST['myaction'];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置测试访问状态(写入完整 Session 判定缓存,便于测试广告落地链接直达真实页)
|
|
|
|
|
|
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "setuvi") {
|
|
|
|
|
|
require_once __DIR__ . '/lib/Cloak/VisitorRepository.php';
|
|
|
|
|
|
if (!empty($_REQUEST["res"]) && $_REQUEST["res"] == "true") {
|
|
|
|
|
|
cloak_session_mark_real_visitor();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!empty($_REQUEST["res"]) && $_REQUEST["res"] == "false") {
|
|
|
|
|
|
cloak_session_clear_real_visitor();
|
|
|
|
|
|
}
|
|
|
|
|
|
echo("<script>window.location='{$current_name}?action=edit_config&name={$check_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存配置
|
|
|
|
|
|
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "submit") {
|
|
|
|
|
|
$check_name = trim($_REQUEST["check_name"]);
|
|
|
|
|
|
$methods = trim($_REQUEST["methods"]);
|
|
|
|
|
|
$country = trim($_REQUEST["country"]);
|
|
|
|
|
|
$blacklist_group_id = (int)($_REQUEST["blacklist_group_id"] ?? 0);
|
|
|
|
|
|
$whitelist_group_id = (int)($_REQUEST["whitelist_group_id"] ?? 0);
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoDash = new PDO(
|
|
|
|
|
|
'mysql:host=127.0.0.1;dbname=' . DB_NAME . ';charset=utf8mb4',
|
|
|
|
|
|
DB_USERNAME, DB_PASSWORD,
|
|
|
|
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
|
|
|
|
|
|
);
|
|
|
|
|
|
$chk = $pdoDash->prepare('SELECT 1 FROM ip_groups WHERE id = ? AND type = ? LIMIT 1');
|
|
|
|
|
|
if ($blacklist_group_id > 0) {
|
|
|
|
|
|
$chk->execute([$blacklist_group_id, 'black']);
|
|
|
|
|
|
if (!$chk->fetchColumn()) $blacklist_group_id = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($whitelist_group_id > 0) {
|
|
|
|
|
|
$chk->execute([$whitelist_group_id, 'white']);
|
|
|
|
|
|
if (!$chk->fetchColumn()) $whitelist_group_id = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
$blacklist_group_id = $whitelist_group_id = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
$DB_fp = $_REQUEST["DB_fp"];
|
|
|
|
|
|
$DB_zp = trim($_REQUEST["DB_zp"]);
|
|
|
|
|
|
$redirect_method = trim($_REQUEST["redirect_method"]);
|
|
|
|
|
|
$show_content = trim($_REQUEST["show_content"]);
|
|
|
|
|
|
$costm_ip_score = trim($_REQUEST["costm_ip_score"]);
|
|
|
|
|
|
$write_log = trim($_REQUEST["write_log"]);
|
|
|
|
|
|
$zh_on = trim($_REQUEST["zh_on"]);
|
|
|
|
|
|
$os_on = trim($_REQUEST["os_on"]);
|
|
|
|
|
|
$mobile_on = trim($_REQUEST["mobile_on"]);
|
|
|
|
|
|
$v_referer = trim($_REQUEST["v_referer"]);
|
|
|
|
|
|
$is_virtual = trim($_REQUEST["is_virtual"]);
|
|
|
|
|
|
$auto_black = trim($_REQUEST["auto_black"]);
|
|
|
|
|
|
$auto_black_times = trim($_REQUEST["auto_black_times"]);
|
|
|
|
|
|
$white_params = trim($_REQUEST["white_params"]);
|
|
|
|
|
|
$keep_params = trim($_REQUEST["keep_params"]);
|
|
|
|
|
|
$iphone_model = $_REQUEST["iphone_model"];
|
|
|
|
|
|
$risk_number = $_REQUEST["risk_number"];
|
|
|
|
|
|
$risk_enhanced = in_array(strtoupper(trim($_REQUEST["risk_enhanced"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
$url_args_timeout = $_REQUEST["url_args_timeout"];
|
|
|
|
|
|
$debug_mode = in_array(strtoupper(trim($_REQUEST["debug_mode"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
$ad_fb = in_array(strtoupper(trim($_REQUEST["ad_fb"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
$ad_google = in_array(strtoupper(trim($_REQUEST["ad_google"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
$ad_tiktok = in_array(strtoupper(trim($_REQUEST["ad_tiktok"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
$ad_strict = in_array(strtoupper(trim($_REQUEST["ad_strict"] ?? '')), ['ON']) ? 'ON' : 'OFF';
|
|
|
|
|
|
|
|
|
|
|
|
$config_name_submit = str_replace('.php', '', $check_name);
|
|
|
|
|
|
$existing_spm_id = '';
|
|
|
|
|
|
$existing_cfg = 'check_config/' . $config_name_submit . '_config.php';
|
|
|
|
|
|
if (file_exists($existing_cfg)) {
|
|
|
|
|
|
$existing_raw = file_get_contents($existing_cfg);
|
|
|
|
|
|
if (preg_match("/define\('CLOAK_AD_SPM_ID',\s*'([^']*)'\)/", $existing_raw, $spmM)) {
|
|
|
|
|
|
$existing_spm_id = $spmM[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$ad_spm_id = CloakAdSourceGuard::isValidSpmId($existing_spm_id) ? $existing_spm_id : '';
|
|
|
|
|
|
if (($ad_fb === 'ON' || $ad_google === 'ON' || $ad_tiktok === 'ON') && $ad_spm_id === '') {
|
|
|
|
|
|
$ad_spm_id = CloakAdSourceGuard::generateSpmId();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (strtoupper($auto_black) === 'ON' && $blacklist_group_id <= 0) {
|
|
|
|
|
|
echo "<script>alert('开启「自动黑名单」时,必须先选择「黑名单 IP 组」。');history.back();</script>";
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!empty($methods)) {
|
|
|
|
|
|
ConfigWriter::save($check_name, [
|
|
|
|
|
|
'methods' => $methods,
|
|
|
|
|
|
'blacklist_group_id' => $blacklist_group_id,
|
|
|
|
|
|
'whitelist_group_id' => $whitelist_group_id,
|
|
|
|
|
|
'country' => $country,
|
|
|
|
|
|
'show_content' => $show_content,
|
|
|
|
|
|
'DB_fp' => $DB_fp,
|
|
|
|
|
|
'costm_ip_score' => $costm_ip_score,
|
|
|
|
|
|
'auto_black' => $auto_black,
|
|
|
|
|
|
'is_virtual' => $is_virtual,
|
|
|
|
|
|
'auto_black_times' => $auto_black_times,
|
|
|
|
|
|
'white_params' => $white_params,
|
|
|
|
|
|
'iphone_model' => $iphone_model,
|
|
|
|
|
|
'write_log' => $write_log,
|
|
|
|
|
|
'zh_on' => $zh_on,
|
|
|
|
|
|
'os_on' => $os_on,
|
|
|
|
|
|
'keep_params' => $keep_params,
|
|
|
|
|
|
'redirect_method' => $redirect_method,
|
|
|
|
|
|
'DB_zp' => $DB_zp,
|
|
|
|
|
|
'mobile_on' => $mobile_on,
|
|
|
|
|
|
'v_referer' => $v_referer,
|
|
|
|
|
|
'risk_number' => $risk_number,
|
|
|
|
|
|
'risk_enhanced' => $risk_enhanced,
|
|
|
|
|
|
'url_args_timeout' => $url_args_timeout,
|
|
|
|
|
|
'debug_mode' => $debug_mode,
|
|
|
|
|
|
'ad_fb' => $ad_fb,
|
|
|
|
|
|
'ad_google' => $ad_google,
|
|
|
|
|
|
'ad_tiktok' => $ad_tiktok,
|
|
|
|
|
|
'ad_strict' => $ad_strict,
|
|
|
|
|
|
'ad_spm_id' => $ad_spm_id,
|
|
|
|
|
|
]);
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoBind = DomainRepository::pdo();
|
|
|
|
|
|
DomainRepository::ensureTable($pdoBind);
|
|
|
|
|
|
$siteDomainId = (int) ($_REQUEST['site_domain_id'] ?? 0);
|
|
|
|
|
|
if ($siteDomainId > 0) {
|
|
|
|
|
|
DomainRepository::bindConfigToDomain($pdoBind, $check_name, $siteDomainId);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
DomainRepository::clearConfigBinding($pdoBind, $check_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
echo("<script>alert('保存成功!');window.location='{$current_name}?action=edit_config&name={$check_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function write_file($file_name, $text_str) {
|
|
|
|
|
|
$f = fopen($file_name, "w");
|
|
|
|
|
|
rewind($f);
|
|
|
|
|
|
fwrite($f, $text_str);
|
|
|
|
|
|
fclose($f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onoff_radio($name, $val, $label_on='开启', $label_off='关闭') {
|
|
|
|
|
|
$on = ($val == 'ON') ? 'active' : '';
|
|
|
|
|
|
$off = ($val != 'ON') ? 'active' : '';
|
|
|
|
|
|
return '<div class="btn-group btn-group-toggle" data-toggle="buttons">
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary ' . $on . '">
|
|
|
|
|
|
<input type="radio" name="' . $name . '" value="ON" ' . ($val=='ON'?'checked':'') . '> ' . $label_on . '
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary ' . $off . '">
|
|
|
|
|
|
<input type="radio" name="' . $name . '" value="OFF" ' . ($val!='ON'?'checked':'') . '> ' . $label_off . '
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function dash_truncate_attr($text, $maxLen = 52) {
|
|
|
|
|
|
$text = (string) $text;
|
|
|
|
|
|
$esc = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
|
|
|
|
|
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
|
|
|
|
|
if (mb_strlen($text, 'UTF-8') <= $maxLen) {
|
|
|
|
|
|
return $esc;
|
|
|
|
|
|
}
|
|
|
|
|
|
return '<span class="cell-truncate" title="' . $esc . '">' . htmlspecialchars(mb_substr($text, 0, $maxLen, 'UTF-8'), ENT_QUOTES, 'UTF-8') . '…</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (strlen($text) <= $maxLen) {
|
|
|
|
|
|
return $esc;
|
|
|
|
|
|
}
|
|
|
|
|
|
return '<span class="cell-truncate" title="' . $esc . '">' . htmlspecialchars(substr($text, 0, $maxLen), ENT_QUOTES, 'UTF-8') . '…</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
?>
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
|
|
<title>IPCLOAKAPI 多功能管理后台面板 v8.2.1</title>
|
|
|
|
|
|
<link rel="stylesheet" href="./dist/bootstrap/4.5.2/css/bootstrap.min.css">
|
|
|
|
|
|
<script src="./dist/jquery-2.2.4.min.js"></script>
|
|
|
|
|
|
<script src="./dist/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
body { background:#f0f2f5; font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif; }
|
|
|
|
|
|
.topbar { background:linear-gradient(135deg,#16baaa,#0e8d81); color:#fff; padding:14px 24px; display:flex; align-items:center; justify-content:space-between; box-shadow:0 2px 8px rgba(0,0,0,.15); }
|
|
|
|
|
|
.topbar a { color:rgba(255,255,255,.85); text-decoration:none; font-size:.9rem; }
|
|
|
|
|
|
.topbar a:hover { color:#fff; }
|
|
|
|
|
|
.topbar h1 { margin:0; font-size:1.25rem; font-weight:600; }
|
|
|
|
|
|
.page-body { max-width:1100px; margin:32px auto; padding:0 16px; }
|
|
|
|
|
|
.status-bar { display:flex; gap:12px; margin-bottom:20px; flex-wrap:wrap; }
|
|
|
|
|
|
.status-badge { display:inline-flex; align-items:center; gap:6px; padding:6px 14px; border-radius:20px; font-size:.82rem; font-weight:500; }
|
|
|
|
|
|
.status-ok { background:#d4edda; color:#155724; }
|
|
|
|
|
|
.status-err { background:#f8d7da; color:#721c24; }
|
|
|
|
|
|
.card-header-custom { background:#fff; border-bottom:1px solid #e9ecef; padding:14px 20px; display:flex; align-items:center; justify-content:space-between; border-radius:8px 8px 0 0; }
|
|
|
|
|
|
.card-header-custom h5 { margin:0; font-size:1rem; font-weight:600; }
|
|
|
|
|
|
.config-table th { background:#f8f9fa; font-weight:600; }
|
|
|
|
|
|
.config-table td, .config-table th { vertical-align:middle !important; padding:12px 16px !important; }
|
|
|
|
|
|
.config-table tr:hover { background:#f0f7ff; }
|
|
|
|
|
|
.url-text { font-size:.78rem; color:#6c757d; }
|
|
|
|
|
|
.ad-link-row { display:flex; align-items:flex-start; gap:6px; margin-bottom:6px; }
|
|
|
|
|
|
.ad-link-row:last-child { margin-bottom:0; }
|
|
|
|
|
|
.ad-link-label { font-size:.72rem; color:#495057; white-space:nowrap; min-width:58px; padding-top:2px; }
|
|
|
|
|
|
.btn-copy-ad { font-size:.72rem; padding:2px 8px; flex-shrink:0; }
|
|
|
|
|
|
.ad-link-hint { font-size:.68rem; color:#adb5bd; margin-top:4px; }
|
|
|
|
|
|
.section-heading { background:#e8f4fd; color:#1565c0; font-weight:600; padding:8px 14px; border-radius:4px; margin:6px 0 2px; font-size:.85rem; letter-spacing:.3px; }
|
|
|
|
|
|
.form-label-cell { width:36%; font-size:.88rem; color:#444; padding:10px 14px !important; }
|
|
|
|
|
|
.form-val-cell { padding:8px 14px !important; }
|
|
|
|
|
|
.form-section { border:1px solid #dee2e6; border-radius:6px; margin-bottom:8px; overflow:hidden; }
|
|
|
|
|
|
.form-section .section-toggle { background:#f8f9fa; padding:10px 16px; cursor:pointer; display:flex; align-items:center; justify-content:space-between; font-weight:600; font-size:.9rem; border:none; width:100%; text-align:left; }
|
|
|
|
|
|
.form-section .section-toggle:hover { background:#e9ecef; }
|
|
|
|
|
|
.form-section .section-toggle .arrow { transition:transform .2s; }
|
|
|
|
|
|
.form-section .section-toggle.collapsed .arrow { transform:rotate(-90deg); }
|
|
|
|
|
|
.back-link { display:inline-flex; align-items:center; gap:6px; color:#1565c0; font-size:.9rem; margin-bottom:16px; text-decoration:none; }
|
|
|
|
|
|
.back-link:hover { text-decoration:underline; }
|
|
|
|
|
|
.sticky-actions { position:sticky; bottom:0; background:#fff; border-top:1px solid #dee2e6; padding:12px 20px; display:flex; gap:10px; align-items:center; z-index:100; border-radius:0 0 8px 8px; }
|
|
|
|
|
|
.login-wrap { min-height:100vh; display:flex; align-items:center; justify-content:center; }
|
|
|
|
|
|
.login-card { background:#fff; border-radius:10px; box-shadow:0 4px 20px rgba(0,0,0,.1); padding:40px; width:340px; }
|
|
|
|
|
|
.login-card h2 { text-align:center; color:#16baaa; margin-bottom:24px; font-size:1.4rem; }
|
|
|
|
|
|
.list-page-title { margin-bottom: 4px; }
|
|
|
|
|
|
.list-page-title h2 { margin: 0 0 6px; font-size: 1.2rem; font-weight: 600; color: #2c3e50; }
|
|
|
|
|
|
.list-page-title p { margin: 0; font-size: .85rem; color: #8c98a4; }
|
|
|
|
|
|
.card-shell { border-radius: 10px; overflow: hidden; border: 1px solid #e8ecf1; box-shadow: 0 2px 12px rgba(15,23,42,.04); }
|
|
|
|
|
|
.card-header-custom .header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
|
|
|
|
.card-header-custom .header-actions .btn-teal { background: #16baaa; color: #fff; border: none; }
|
|
|
|
|
|
.card-header-custom .header-actions .btn-teal:hover { background: #0e8d81; color: #fff; }
|
|
|
|
|
|
.list-table-wrap { overflow-x: auto; }
|
|
|
|
|
|
.config-table thead th {
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
z-index: 5;
|
|
|
|
|
|
background: linear-gradient(180deg, #f4f7fb 0%, #eef2f7 100%) !important;
|
|
|
|
|
|
border-bottom: 2px solid #dde4ec !important;
|
|
|
|
|
|
font-size: .82rem;
|
|
|
|
|
|
letter-spacing: .02em;
|
|
|
|
|
|
text-transform: none;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.config-table tbody tr:nth-child(even) { background: #fafbfc; }
|
|
|
|
|
|
.config-table tbody tr:hover { background: #eef6ff !important; }
|
|
|
|
|
|
.config-table tbody tr { transition: background-color .15s ease; }
|
|
|
|
|
|
.config-table tbody td { border-color: #eef1f5 !important; font-size: .86rem; }
|
|
|
|
|
|
.list-table thead th {
|
|
|
|
|
|
background: #f4f7fb;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
font-size: .82rem;
|
|
|
|
|
|
border-bottom: 2px solid #dde4ec !important;
|
|
|
|
|
|
padding: 10px 14px !important;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.list-table tbody tr:nth-child(even) { background: #fafbfc; }
|
|
|
|
|
|
.list-table tbody tr:hover { background: #eef6ff; }
|
|
|
|
|
|
.list-table tbody td { vertical-align: middle !important; padding: 11px 14px !important; border-color: #eef1f5 !important; font-size: .84rem; }
|
|
|
|
|
|
.cell-truncate { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; cursor: default; }
|
|
|
|
|
|
.url-text-truncate { font-size: .78rem; color: #6c757d; word-break: break-all; }
|
|
|
|
|
|
.action-btn-group { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
|
|
|
|
.action-btn-group .btn { border-radius: 6px; }
|
|
|
|
|
|
.domain-host-badge { display: inline-block; padding: 2px 8px; background: #e8f4fd; color: #1565c0; border-radius: 4px; font-size: .78rem; font-family: 'SF Mono', Consolas, monospace; }
|
|
|
|
|
|
.config-name-cell strong { color: #2c3e50; font-size: .92rem; }
|
|
|
|
|
|
.empty-hint { padding: 28px 20px; text-align: center; color: #8c98a4; font-size: .88rem; background: #fafbfc; border-radius: 0 0 10px 10px; }
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
|
|
<?php if (empty($_SESSION['password'])): ?>
|
|
|
|
|
|
<!-- ===================== 登录页 ===================== -->
|
|
|
|
|
|
<div class="login-wrap">
|
|
|
|
|
|
<div class="login-card">
|
|
|
|
|
|
<h2>IPCLOAKAPI 多功能管理后台面板 v8.2.1</h2>
|
|
|
|
|
|
<form method="post" action="<?php echo $current_name; ?>">
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label>登录密码</label>
|
|
|
|
|
|
<input type="password" name="password" class="form-control" placeholder="请输入密码" autofocus>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<input type="hidden" name="myaction" value="dolist">
|
|
|
|
|
|
<button type="submit" class="btn btn-block" style="background:#16baaa;color:#fff;margin-top:8px;">进入后台</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php exit(); endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
<?php
|
|
|
|
|
|
// 密码验证
|
|
|
|
|
|
if ($_SESSION['password'] != LOGIN_PASSWORD) {
|
|
|
|
|
|
unset($_SESSION['password']);
|
|
|
|
|
|
echo("<script>alert('密码错误!');window.location='{$current_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除配置
|
|
|
|
|
|
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "delete_config" && !empty($_REQUEST["name"])) {
|
|
|
|
|
|
$name = trim($_REQUEST["name"]);
|
|
|
|
|
|
if ($name == "index") {
|
|
|
|
|
|
echo("<script>alert('请勿删除默认配置!');window.location='{$current_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
$cfg = str_replace(".php", "", $name);
|
|
|
|
|
|
try {
|
|
|
|
|
|
DomainRepository::clearConfigBinding(DomainRepository::pdo(), $cfg);
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
@unlink("check_config/{$cfg}_config.php");
|
|
|
|
|
|
@unlink("{$cfg}.php");
|
|
|
|
|
|
echo("<script>alert('删除成功!');window.location='{$current_name}';</script>");
|
|
|
|
|
|
exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 站点域名管理
|
|
|
|
|
|
$cloakDomainMsg = '';
|
|
|
|
|
|
$cloakDomainErr = '';
|
|
|
|
|
|
$cloakCfEnabled = CloudflareConfig::isEnabled();
|
|
|
|
|
|
if (!empty($_REQUEST['action']) && $_REQUEST['action'] === 'add_domain' && !empty($_POST['new_hostname'])) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoDom = DomainRepository::pdo();
|
|
|
|
|
|
$res = DomainProvisioningService::provisionOnAdd($pdoDom, $_POST['new_hostname']);
|
|
|
|
|
|
if ($res['ok']) {
|
|
|
|
|
|
$cloakDomainMsg = '域名「' . htmlspecialchars($res['hostname']) . '」已添加';
|
|
|
|
|
|
if (!empty($res['nameservers'])) {
|
|
|
|
|
|
$nsHtml = implode('</code>、<code>', array_map('htmlspecialchars', $res['nameservers']));
|
|
|
|
|
|
$cloakDomainMsg .= '。请到注册商将 NS 修改为:<code>' . $nsHtml . '</code>,然后点击「检测/刷新」。';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$cloakDomainMsg .= ',请在编辑配置时关联此域名。';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$cloakDomainErr = $res['error'] ?? '添加失败';
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
$cloakDomainErr = $e->getMessage();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!empty($_REQUEST['action']) && $_REQUEST['action'] === 'check_domain') {
|
|
|
|
|
|
$domainId = (int) ($_POST['domain_id'] ?? $_REQUEST['domain_id'] ?? 0);
|
|
|
|
|
|
$jsonOut = isset($_REQUEST['format']) && $_REQUEST['format'] === 'json';
|
|
|
|
|
|
try {
|
|
|
|
|
|
$res = DomainProvisioningService::checkAndProvision(DomainRepository::pdo(), $domainId);
|
|
|
|
|
|
if ($jsonOut) {
|
|
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
|
|
echo json_encode($res, JSON_UNESCAPED_UNICODE);
|
|
|
|
|
|
exit;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($res['ok']) {
|
|
|
|
|
|
$cloakDomainMsg = $res['message'] ?? '检测完成';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$cloakDomainErr = $res['message'] ?? '检测失败';
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
if ($jsonOut) {
|
|
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
|
|
echo json_encode(['ok' => false, 'message' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
|
|
|
|
|
|
exit;
|
|
|
|
|
|
}
|
|
|
|
|
|
$cloakDomainErr = $e->getMessage();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!empty($_REQUEST['action']) && $_REQUEST['action'] === 'delete_domain' && !empty($_REQUEST['domain_id'])) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
$res = DomainProvisioningService::deleteWithCloudflare(DomainRepository::pdo(), (int) $_REQUEST['domain_id']);
|
|
|
|
|
|
if ($res['ok']) {
|
|
|
|
|
|
$cloakDomainMsg = $res['message'] ?? '域名已删除。';
|
|
|
|
|
|
if (!empty($res['warning'])) {
|
|
|
|
|
|
$cloakDomainErr = $res['warning'];
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$cloakDomainErr = $res['message'] ?? '删除失败';
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
$cloakDomainErr = $e->getMessage();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 系统状态检测(列表页用)
|
|
|
|
|
|
function dash_check_mysql() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdo = new PDO('mysql:host=127.0.0.1;dbname=' . DB_NAME . ';charset=utf8mb4', DB_USERNAME, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} catch (Throwable $e) { return false; }
|
|
|
|
|
|
}
|
|
|
|
|
|
function dash_check_redis() {
|
|
|
|
|
|
if (!extension_loaded('redis') || strtoupper(REDIS_ENABLED) !== 'ON') return null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
$r = new Redis();
|
|
|
|
|
|
if (!@$r->connect(REDIS_HOST, (int)REDIS_PORT, 0.5)) return false;
|
|
|
|
|
|
$r->ping();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} catch (Throwable $e) { return false; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-15 16:53:05 +08:00
|
|
|
|
function dash_sanitize_config_name($name)
|
|
|
|
|
|
{
|
|
|
|
|
|
$name = trim(str_replace('.php', '', (string) $name));
|
|
|
|
|
|
if ($name === '' || !preg_match('/^[a-zA-Z0-9_-]+$/', $name)) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
return $name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function dash_suggest_copy_config_name($source)
|
|
|
|
|
|
{
|
|
|
|
|
|
$source = dash_sanitize_config_name($source);
|
|
|
|
|
|
if ($source === '') {
|
|
|
|
|
|
return 'new_config';
|
|
|
|
|
|
}
|
|
|
|
|
|
$base = $source . '_copy';
|
|
|
|
|
|
$candidate = $base;
|
|
|
|
|
|
$suffix = 2;
|
|
|
|
|
|
while (file_exists(__DIR__ . "/check_config/{$candidate}_config.php")) {
|
|
|
|
|
|
$candidate = $base . $suffix;
|
|
|
|
|
|
$suffix++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return $candidate;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-14 14:00:24 +08:00
|
|
|
|
function dash_cfg_get($raw, $name)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (preg_match("/define\('" . preg_quote($name, '/') . "',\s*'([^']*)'\)/", $raw, $m)) {
|
|
|
|
|
|
return $m[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function dash_build_ad_links($pf, $protocol, $host)
|
|
|
|
|
|
{
|
|
|
|
|
|
$path = __DIR__ . "/check_config/{$pf}_config.php";
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoDashHost = DomainRepository::pdo();
|
|
|
|
|
|
DomainRepository::ensureTable($pdoDashHost);
|
|
|
|
|
|
$bound = DomainRepository::primaryHostnameForConfig($pdoDashHost, $pf);
|
|
|
|
|
|
if ($bound !== '') {
|
|
|
|
|
|
$host = $bound;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
$host = DomainRepository::normalizeHostname($host);
|
|
|
|
|
|
if ($host === '') {
|
|
|
|
|
|
$host = DomainRepository::normalizeHostname($_SERVER['HTTP_HOST'] ?? '');
|
|
|
|
|
|
}
|
|
|
|
|
|
$base = rtrim($protocol . $host, '/') . '/' . (($pf != 'index') ? $pf : '');
|
|
|
|
|
|
|
|
|
|
|
|
if (!file_exists($path)) {
|
|
|
|
|
|
return [['label' => '落地链接', 'url' => $base]];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$raw = file_get_contents($path);
|
|
|
|
|
|
$enabled = [];
|
|
|
|
|
|
if (dash_cfg_get($raw, 'CLOAK_AD_FB') === 'ON') {
|
|
|
|
|
|
$enabled[] = CloakAdSourceGuard::PLATFORM_FB;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (dash_cfg_get($raw, 'CLOAK_AD_GOOGLE') === 'ON') {
|
|
|
|
|
|
$enabled[] = CloakAdSourceGuard::PLATFORM_GOOGLE;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (dash_cfg_get($raw, 'CLOAK_AD_TIKTOK') === 'ON') {
|
|
|
|
|
|
$enabled[] = CloakAdSourceGuard::PLATFORM_TIKTOK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (empty($enabled)) {
|
|
|
|
|
|
return [['label' => '落地链接', 'url' => $base]];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$spmId = dash_cfg_get($raw, 'CLOAK_AD_SPM_ID');
|
|
|
|
|
|
$query = CloakAdSourceGuard::buildAdLinkQuery($enabled, $spmId);
|
|
|
|
|
|
$url = $base . ($query !== '' ? '?' . $query : '');
|
|
|
|
|
|
|
|
|
|
|
|
return [['label' => '落地链接', 'url' => $url]];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历配置列表
|
|
|
|
|
|
$products_file_ary = [];
|
|
|
|
|
|
$dd = opendir("check_config");
|
|
|
|
|
|
while (false !== ($f = readdir($dd))) {
|
|
|
|
|
|
if ($f == "." || $f == "..") continue;
|
|
|
|
|
|
if (filetype("check_config/$f") == "dir" || $f == "index.php" || $f == "a.txt") continue;
|
|
|
|
|
|
$fname = str_replace("_config.php", "", $f);
|
|
|
|
|
|
$products_file_ary[] = $fname;
|
|
|
|
|
|
if (!file_exists($fname . ".php")) {
|
|
|
|
|
|
copy("tem_link.php", $fname . ".php");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
closedir($dd);
|
|
|
|
|
|
sort($products_file_ary);
|
|
|
|
|
|
|
|
|
|
|
|
// 加载 IP 组(编辑页用)
|
|
|
|
|
|
$blackGroups = $whiteGroups = [];
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoDash = new PDO('mysql:host=127.0.0.1;dbname=' . DB_NAME . ';charset=utf8mb4', DB_USERNAME, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]);
|
|
|
|
|
|
$stb = $pdoDash->prepare("SELECT id, name FROM ip_groups WHERE type = 'black' ORDER BY id ASC");
|
|
|
|
|
|
$stb->execute(); $blackGroups = $stb->fetchAll();
|
|
|
|
|
|
$stw = $pdoDash->prepare("SELECT id, name FROM ip_groups WHERE type = 'white' ORDER BY id ASC");
|
|
|
|
|
|
$stw->execute(); $whiteGroups = $stw->fetchAll();
|
|
|
|
|
|
} catch (Throwable $e) {}
|
|
|
|
|
|
$currentBlacklistGroupId = defined('BLACKLIST_GROUP_ID') ? (int)BLACKLIST_GROUP_ID : 0;
|
|
|
|
|
|
$currentWhitelistGroupId = defined('WHITELIST_GROUP_ID') ? (int)WHITELIST_GROUP_ID : 0;
|
|
|
|
|
|
|
|
|
|
|
|
$action = $_REQUEST['action'] ?? '';
|
|
|
|
|
|
$isEdit = in_array($action, ['edit_config', 'submit'], true);
|
|
|
|
|
|
|
|
|
|
|
|
$cloakSiteDomains = [];
|
|
|
|
|
|
$selectedDomainId = 0;
|
|
|
|
|
|
$dashboardDefaultHost = DomainRepository::normalizeHostname($_SERVER['HTTP_HOST'] ?? '');
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pdoDash = $pdoDash ?? DomainRepository::pdo();
|
|
|
|
|
|
DomainRepository::ensureTable($pdoDash);
|
|
|
|
|
|
$cloakSiteDomains = DomainRepository::listAll($pdoDash);
|
|
|
|
|
|
if ($isEdit) {
|
|
|
|
|
|
$selectedDomainId = DomainRepository::domainIdForConfig($pdoDash, $check_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
$cloakSiteDomains = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视图判断
|
|
|
|
|
|
$_d = function($name, $default) { return defined($name) ? constant($name) : $default; };
|
|
|
|
|
|
?>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===================== 顶栏 ===================== -->
|
|
|
|
|
|
<div class="topbar">
|
|
|
|
|
|
<h1>IPCLOAKAPI 多功能管理后台面板 v8.2.1</h1>
|
|
|
|
|
|
<div style="display:flex;gap:16px;align-items:center;">
|
|
|
|
|
|
<?php if ($isEdit): ?>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>">← 返回列表</a>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>?action=logout">退出登录</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="page-body">
|
|
|
|
|
|
|
|
|
|
|
|
<?php if (!$isEdit): ?>
|
|
|
|
|
|
<!-- ===================== 列表视图 ===================== -->
|
|
|
|
|
|
|
|
|
|
|
|
<div class="list-page-title">
|
|
|
|
|
|
<h2>配置管理</h2>
|
|
|
|
|
|
<p>管理 Cloak 配置、广告落地链接与站点域名</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 系统状态 -->
|
|
|
|
|
|
<div class="status-bar">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$mysqlOk = dash_check_mysql();
|
|
|
|
|
|
$redisOk = dash_check_redis();
|
|
|
|
|
|
echo '<span class="status-badge ' . ($mysqlOk ? 'status-ok' : 'status-err') . '">● MySQL ' . ($mysqlOk ? '已连接' : '连接失败') . '</span>';
|
|
|
|
|
|
if ($redisOk === null) {
|
|
|
|
|
|
echo '<span class="status-badge" style="background:#fff3cd;color:#856404;">● Redis 未启用</span>';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo '<span class="status-badge ' . ($redisOk ? 'status-ok' : 'status-err') . '">● Redis ' . ($redisOk ? '已连接' : '连接失败') . '</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<span class="status-badge" style="background:#e2e3e5;color:#383d41;">● 配置数:<?php echo count($products_file_ary); ?></span>
|
|
|
|
|
|
<span class="status-badge" style="background:#e2e3e5;color:#383d41;">● 已登记域名:<?php echo count($cloakSiteDomains); ?></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<?php if ($cloakDomainMsg): ?>
|
|
|
|
|
|
<div class="alert alert-success"><?php echo $cloakDomainMsg; ?></div>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<?php if ($cloakDomainErr): ?>
|
|
|
|
|
|
<div class="alert alert-danger"><?php echo htmlspecialchars($cloakDomainErr); ?></div>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 配置列表卡片 -->
|
|
|
|
|
|
<div class="card shadow-sm card-shell">
|
|
|
|
|
|
<div class="card-header-custom">
|
|
|
|
|
|
<h5>配置列表</h5>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
|
<a href="/table" target="_blank" class="btn btn-sm btn-outline-secondary">查看日志</a>
|
|
|
|
|
|
<a href="/log_analytics.php" target="_blank" class="btn btn-sm btn-outline-secondary">数据分析</a>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>?action=edit_config&name=new_config" class="btn btn-sm btn-teal">+ 新增配置</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="list-table-wrap">
|
|
|
|
|
|
<table class="table config-table mb-0">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th style="width:22%">配置名称</th>
|
|
|
|
|
|
<th style="width:14%">绑定域名</th>
|
|
|
|
|
|
<th>广告链接(广告后台填入的链接)</th>
|
|
|
|
|
|
<th>真实页链接(客户到达的链接)</th>
|
|
|
|
|
|
<th style="width:22%">操作</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<?php foreach ($products_file_ary as $pf):
|
|
|
|
|
|
$pcfg = "check_config/{$pf}_config.php";
|
|
|
|
|
|
$pfp = [];
|
|
|
|
|
|
if (file_exists($pcfg)) {
|
|
|
|
|
|
// 简单读取 DB_FP 和 DB_ZP 值用于展示
|
|
|
|
|
|
$raw = file_get_contents($pcfg);
|
|
|
|
|
|
if (preg_match("/define\('DB_FP',\s*(array\s*\(.*?\))\s*\)/s", $raw, $m)) {
|
|
|
|
|
|
@eval('$pfp = ' . $m[1] . ';');
|
|
|
|
|
|
}
|
|
|
|
|
|
preg_match("/define\('DB_ZP',\s*'([^']*)'\)/", $raw, $zpM);
|
|
|
|
|
|
$pzp = $zpM[1] ?? '';
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="config-name-cell">
|
|
|
|
|
|
<strong><?php echo htmlspecialchars($pf); ?></strong>
|
|
|
|
|
|
<?php if ($pf === 'index'): ?><span class="badge badge-secondary ml-1" style="font-size:.7rem;">默认</span><?php endif; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="font-size:.82rem;">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$pfHost = '';
|
|
|
|
|
|
try {
|
|
|
|
|
|
$pfHost = DomainRepository::primaryHostnameForConfig($pdoDash ?? DomainRepository::pdo(), $pf);
|
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($pfHost !== '') {
|
|
|
|
|
|
echo '<span class="domain-host-badge" title="' . htmlspecialchars($pfHost, ENT_QUOTES) . '">' . htmlspecialchars($pfHost) . '</span>';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo '<span class="text-muted cell-truncate" title="' . htmlspecialchars($dashboardDefaultHost, ENT_QUOTES) . '">' . htmlspecialchars($dashboardDefaultHost) . '<br><small>(默认后台域)</small></span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$adLinks = dash_build_ad_links($pf, $protocol, $_SERVER['HTTP_HOST']);
|
|
|
|
|
|
foreach ($adLinks as $link):
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div class="ad-link-row">
|
|
|
|
|
|
|
|
|
|
|
|
<span class="ad-link-label"><?php echo htmlspecialchars($link['label']); ?></span>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="url-text flex-grow-1 url-text-truncate"><?php echo dash_truncate_attr($link['url'], 56); ?></div>
|
|
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-secondary btn-copy-ad" data-copy="<?php echo htmlspecialchars($link['url'], ENT_QUOTES); ?>">复制</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<?php if (!empty($pfp)) {
|
|
|
|
|
|
$first = is_array($pfp) ? $pfp[0] : $pfp;
|
|
|
|
|
|
echo '<div class="url-text url-text-truncate">' . dash_truncate_attr($first, 48) . '</div>';
|
|
|
|
|
|
if (is_array($pfp) && count($pfp) > 1) {
|
|
|
|
|
|
echo '<div class="url-text text-muted">+' . (count($pfp)-1) . ' 个链接</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else { ?>
|
|
|
|
|
|
<span class="text-muted" style="font-size:.82rem;">—</span>
|
|
|
|
|
|
<?php } ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<div class="action-btn-group">
|
2026-06-15 16:53:05 +08:00
|
|
|
|
<a href="<?php echo $current_name . '?action=edit_config&name=' . urlencode($pf); ?>" class="btn btn-sm btn-outline-primary">编辑</a>
|
|
|
|
|
|
<a href="<?php echo $current_name . '?action=edit_config&name=new_config&copy_from=' . urlencode($pf); ?>" class="btn btn-sm btn-outline-info">复制</a>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
<a href="/<?php echo $pf; ?>.php" target="_blank" class="btn btn-sm btn-outline-secondary">查看</a>
|
|
|
|
|
|
<?php if ($pf !== 'index'): ?>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-danger" onclick="if(confirm('确定删除配置「<?php echo htmlspecialchars($pf); ?>」?')) location='<?php echo $current_name . '?action=delete_config&name=' . $pf; ?>'">删除</button>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 站点域名 -->
|
|
|
|
|
|
<div class="card shadow-sm card-shell mb-4" style="margin-top: 16px;">
|
|
|
|
|
|
<div class="card-header-custom">
|
|
|
|
|
|
<h5>站点域名</h5>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style="padding:16px 20px;">
|
|
|
|
|
|
<?php if ($cloakCfEnabled): ?>
|
|
|
|
|
|
<div class="alert alert-info mb-3" style="font-size:.88rem;">
|
|
|
|
|
|
<strong>Cloudflare 已启用:</strong>添加域名后将自动创建 Zone 并显示 Nameserver;请到注册商修改 NS 后点击「检测/刷新」。NS 生效后将自动配置 proxied A 记录、Flexible SSL 与 Always HTTPS。
|
|
|
|
|
|
源站仍需在宝塔添加站点并监听 <code><?php echo htmlspecialchars(CloudflareConfig::serverIp() ?: 'SERVER_IP'); ?></code>(Flexible:访客↔CF 为 HTTPS,CF↔源站为 HTTP)。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<div class="alert alert-warning mb-3" style="font-size:.88rem;">
|
|
|
|
|
|
<strong>使用前请先在宝塔完成:</strong>在宝塔面板 → 网站 → 添加站点(填写下方相同域名)→ 申请并开启 SSL 证书。完成后再在此添加域名并关联配置。
|
|
|
|
|
|
若在 <code>cong.php</code> 配置 Cloudflare API Token 与 Account ID,可自动创建 Zone 并管理 DNS/SSL。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<form method="post" action="<?php echo $current_name; ?>" class="form-inline mb-3">
|
|
|
|
|
|
<input type="hidden" name="action" value="add_domain">
|
|
|
|
|
|
<input type="text" name="new_hostname" class="form-control form-control-sm mr-2" style="min-width:280px;" placeholder="例如 shop.example.com" required>
|
|
|
|
|
|
<button type="submit" class="btn btn-sm" style="background:#16baaa;color:#fff;">添加域名</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
<?php if (empty($cloakSiteDomains)): ?>
|
|
|
|
|
|
<div class="empty-hint">尚未添加域名。未添加时,广告链接将使用当前后台访问域名:<code><?php echo htmlspecialchars($dashboardDefaultHost); ?></code></div>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<div class="list-table-wrap">
|
|
|
|
|
|
<table class="table table-sm mb-0 list-table">
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>域名</th>
|
|
|
|
|
|
<th>关联配置</th>
|
|
|
|
|
|
<?php if ($cloakCfEnabled): ?><th>Cloudflare</th><th>Nameserver</th><?php endif; ?>
|
|
|
|
|
|
<th style="width:140px;">操作</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<?php foreach ($cloakSiteDomains as $dom):
|
|
|
|
|
|
$cfStatus = $dom['cf_status'] ?? 'local';
|
|
|
|
|
|
$cfLabel = CloudflareConfig::statusLabel($cfStatus);
|
|
|
|
|
|
$badgeCls = 'secondary';
|
|
|
|
|
|
if ($cfStatus === 'pending_ns') { $badgeCls = 'warning'; }
|
|
|
|
|
|
elseif ($cfStatus === 'provisioning') { $badgeCls = 'info'; }
|
|
|
|
|
|
elseif ($cfStatus === 'ready') { $badgeCls = 'success'; }
|
|
|
|
|
|
elseif ($cfStatus === 'error') { $badgeCls = 'danger'; }
|
|
|
|
|
|
$nsList = CloudflareConfig::parseNameservers($dom['cf_nameservers'] ?? '');
|
|
|
|
|
|
$delConfirm = '确定删除该域名?';
|
|
|
|
|
|
if ($cloakCfEnabled && !empty($dom['cf_zone_id'])) {
|
|
|
|
|
|
$delConfirm .= '将同时删除 Cloudflare Zone(不可恢复)。';
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><span class="domain-host-badge" title="<?php echo htmlspecialchars($dom['hostname'], ENT_QUOTES); ?>"><?php echo htmlspecialchars($dom['hostname']); ?></span></td>
|
|
|
|
|
|
<td><?php
|
|
|
|
|
|
if ($dom['config_name'] !== '') {
|
|
|
|
|
|
echo '<span class="badge badge-light border">' . htmlspecialchars($dom['config_name']) . '</span>';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo '<span class="text-muted">未关联</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
?></td>
|
|
|
|
|
|
<?php if ($cloakCfEnabled): ?>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<span class="badge badge-<?php echo $badgeCls; ?>"><?php echo htmlspecialchars($cfLabel); ?></span>
|
|
|
|
|
|
<?php if ($cfStatus === 'error' && !empty($dom['cf_error'])): ?>
|
|
|
|
|
|
<br><small class="text-danger"><?php echo htmlspecialchars($dom['cf_error']); ?></small>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="font-size:.8rem;max-width:220px;">
|
|
|
|
|
|
<?php if ($nsList): ?>
|
|
|
|
|
|
<?php foreach ($nsList as $ns): ?><div><span class="cell-truncate domain-host-badge" style="display:block;max-width:200px;" title="<?php echo htmlspecialchars($ns, ENT_QUOTES); ?>"><?php echo htmlspecialchars($ns); ?></span></div><?php endforeach; ?>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<span class="text-muted">—</span>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<td class="text-nowrap">
|
|
|
|
|
|
<div class="action-btn-group">
|
|
|
|
|
|
<?php if ($cloakCfEnabled && in_array($cfStatus, ['pending_ns', 'provisioning', 'ready', 'error'], true)): ?>
|
|
|
|
|
|
<form method="post" action="<?php echo $current_name; ?>" class="d-inline">
|
|
|
|
|
|
<input type="hidden" name="action" value="check_domain">
|
|
|
|
|
|
<input type="hidden" name="domain_id" value="<?php echo (int)$dom['id']; ?>">
|
|
|
|
|
|
<button type="submit" class="btn btn-sm btn-outline-primary">检测/刷新</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>?action=delete_domain&domain_id=<?php echo (int)$dom['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('<?php echo htmlspecialchars($delConfirm, ENT_QUOTES); ?>');">删除</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<!-- ===================== 编辑视图 ===================== -->
|
|
|
|
|
|
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>" class="back-link">← 返回配置列表</a>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card shadow-sm" style="border-radius:8px;overflow:hidden;">
|
|
|
|
|
|
<div class="card-header-custom">
|
2026-06-15 16:53:05 +08:00
|
|
|
|
<h5><?php echo $isNewConfigDraft ? '新增配置' : '编辑配置'; ?>:<?php echo htmlspecialchars($check_name); ?><?php if ($isNewConfigDraft): ?> <span class="badge badge-warning" style="font-size:.75rem;vertical-align:middle;">未保存</span><?php endif; ?><?php if ($isNewConfigDraft && $configCopySource !== ''): ?> <span class="badge badge-info" style="font-size:.75rem;vertical-align:middle;">从 <?php echo htmlspecialchars($configCopySource); ?> 复制</span><?php endif; ?></h5>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
<div>
|
|
|
|
|
|
<?php if (empty($_SESSION["check_result"]) || $_SESSION["check_result"] != "true"): ?>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>?action=setuvi&res=true&name=<?php echo $check_name; ?>" class="btn btn-sm btn-outline-success mr-1">设置当前浏览器为真实访客</a>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<a href="<?php echo $current_name; ?>?action=setuvi&res=false&name=<?php echo $check_name; ?>" class="btn btn-sm btn-outline-warning mr-1">清除访客状态</a>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<form action="<?php echo $current_name; ?>?action=submit" method="post" id="configForm">
|
|
|
|
|
|
|
|
|
|
|
|
<div style="padding:16px;">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== 基本设置 ===== -->
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<button type="button" class="section-toggle" data-target="sec-basic">
|
|
|
|
|
|
基本设置 <span class="arrow">▼</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div id="sec-basic">
|
|
|
|
|
|
<table class="table table-sm mb-0">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell"><strong>配置名称</strong></td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<input type="text" name="check_name" class="form-control form-control-sm" value="<?php echo htmlspecialchars($check_name); ?>" style="max-width:300px;">
|
2026-06-15 16:53:05 +08:00
|
|
|
|
<small class="text-muted"><?php echo ($isNewConfigDraft && $configCopySource !== '') ? '已按「' . htmlspecialchars($configCopySource) . '」预填,请确认配置名称后保存' : '示例:f123、d258'; ?></small>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">
|
|
|
|
|
|
<strong>关联域名</strong><br>
|
|
|
|
|
|
<small class="text-muted">请先在上方「站点域名」中添加并在宝塔创建该站点与 SSL</small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="site_domain_id" class="form-control form-control-sm" style="max-width:360px;">
|
|
|
|
|
|
<option value="0"<?php echo $selectedDomainId === 0 ? ' selected' : ''; ?>>
|
|
|
|
|
|
不指定(广告链接使用当前后台域名:<?php echo htmlspecialchars($dashboardDefaultHost); ?>)
|
|
|
|
|
|
</option>
|
|
|
|
|
|
<?php foreach ($cloakSiteDomains as $dom): ?>
|
|
|
|
|
|
<option value="<?php echo (int) $dom['id']; ?>"<?php echo $selectedDomainId === (int) $dom['id'] ? ' selected' : ''; ?>>
|
|
|
|
|
|
<?php echo htmlspecialchars($dom['hostname']); ?>
|
|
|
|
|
|
<?php if ($dom['config_name'] !== '' && $dom['config_name'] !== $check_name): ?>
|
|
|
|
|
|
(已绑:<?php echo htmlspecialchars($dom['config_name']); ?>)
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</option>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<?php if (empty($cloakSiteDomains)): ?>
|
|
|
|
|
|
<small class="text-warning d-block mt-1">尚未添加任何域名,保存后广告链接将使用 <?php echo htmlspecialchars($dashboardDefaultHost); ?></small>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">
|
|
|
|
|
|
是否开启 DEBUG 模式<br>
|
|
|
|
|
|
<small class="text-muted">开启后访问落地链接将显示格式化调试页(判定结果、理由、代码行、访客信息),不会跳转真实页/安全页;生产环境请关闭</small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('debug_mode', $_d('CLOAK_DEBUG_MODE','OFF')); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">屏蔽模式</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<div class="btn-group btn-group-toggle" data-toggle="buttons">
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-primary <?php if(SHOW_SITE_MODE_SWITCH == 'ip_check') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="methods" value="ip_check" <?php if(SHOW_SITE_MODE_SWITCH == 'ip_check') echo 'checked'; ?>> 正常屏蔽模式
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-primary <?php if(SHOW_SITE_MODE_SWITCH == 'fp') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="methods" value="fp" <?php if(SHOW_SITE_MODE_SWITCH == 'fp') echo 'checked'; ?>> 真实页模式
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-primary <?php if(SHOW_SITE_MODE_SWITCH == 'zp') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="methods" value="zp" <?php if(SHOW_SITE_MODE_SWITCH == 'zp') echo 'checked'; ?>> 安全页模式
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">指定国家访问真实页(逗号分隔国家代码)</td>
|
2026-06-15 22:42:59 +08:00
|
|
|
|
<td class="form-val-cell"><input type="text" name="country" class="form-control form-control-sm" value="<?php echo SHOW_SITE_COUNTRY; ?>" placeholder="如:US,GB,CA(请用英文逗号)" style="max-width:300px;"></td>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">广告策略 ID</td>
|
|
|
|
|
|
<td class="form-val-cell"><input type="text" name="costm_ip_score" class="form-control form-control-sm" value="<?php echo COSTM_IP_SCORE; ?>" style="max-width:360px;"></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">安全页跳转方式</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="redirect_method" class="form-control form-control-sm" style="max-width:320px;">
|
|
|
|
|
|
<option value="curl" <?php if(CLOAK_REDIRECT_METHOD=='curl') echo 'selected'; ?>>抓取显示(链接不变)</option>
|
|
|
|
|
|
<option value="302" <?php if(CLOAK_REDIRECT_METHOD=='302') echo 'selected'; ?>>302 跳转(域名改变)</option>
|
|
|
|
|
|
<option value="js" <?php if(CLOAK_REDIRECT_METHOD=='js') echo 'selected'; ?>>JS 跳转</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">安全页链接(留空显示空白页)</td>
|
|
|
|
|
|
<td class="form-val-cell"><input type="text" name="DB_zp" class="form-control form-control-sm" value="<?php echo DB_ZP; ?>" placeholder="https://..." style="max-width:420px;"></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">真实页跳转方式</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="show_content" class="form-control form-control-sm" style="max-width:320px;">
|
|
|
|
|
|
<option value="curl" <?php if(CLOAK_SHOW_CONTENT=='curl') echo 'selected'; ?>>抓取显示(链接不变)</option>
|
|
|
|
|
|
<option value="302" <?php if(CLOAK_SHOW_CONTENT=='302') echo 'selected'; ?>>302 跳转(域名改变)</option>
|
|
|
|
|
|
<option value="js" <?php if(CLOAK_SHOW_CONTENT=='js') echo 'selected'; ?>>JS 跳转</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">真实页链接地址</td>
|
|
|
|
|
|
<td class="form-val-cell" id="db_fp">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
if (DB_FP) {
|
|
|
|
|
|
foreach (DB_FP as $idx => $link) {
|
|
|
|
|
|
if ($idx == 0) {
|
|
|
|
|
|
echo '<input type="text" name="DB_fp[]" class="form-control form-control-sm mb-1" value="' . htmlspecialchars($link) . '" style="max-width:420px;" data-idx="1"> <a href="javascript:void(0);" id="addNewLinkBtn" class="btn btn-sm btn-outline-secondary">+ 新增</a>';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo '<br><input type="text" name="DB_fp[]" class="form-control form-control-sm mt-1" value="' . htmlspecialchars($link) . '" style="max-width:420px;" data-idx="' . ($idx+1) . '"> <a href="javascript:void(0);" class="removeLinkBtn btn btn-sm btn-outline-danger">删除</a>';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo '<input type="text" name="DB_fp[]" class="form-control form-control-sm" value="" style="max-width:420px;" data-idx="1"> <a href="javascript:void(0);" id="addNewLinkBtn" class="btn btn-sm btn-outline-secondary">+ 新增</a>';
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== IP 与名单 ===== -->
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<button type="button" class="section-toggle collapsed" data-target="sec-ip">
|
|
|
|
|
|
IP黑白单管理 <span class="arrow">▼</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div id="sec-ip" style="display:none;">
|
|
|
|
|
|
<table class="table table-sm mb-0">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">白名单 IP 组(允许访问真实页)</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="whitelist_group_id" class="form-control form-control-sm" style="max-width:320px;">
|
|
|
|
|
|
<option value="0" <?php if($currentWhitelistGroupId===0) echo 'selected'; ?>>无</option>
|
|
|
|
|
|
<?php foreach($whiteGroups as $wg): ?>
|
|
|
|
|
|
<option value="<?php echo (int)$wg['id']; ?>" <?php if($currentWhitelistGroupId===(int)$wg['id']) echo 'selected'; ?>><?php echo htmlspecialchars($wg['name']); ?> (ID <?php echo $wg['id']; ?>)</option>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<small><a href="/admin_ip_manager.php?type=white" target="_blank">管理白名单</a></small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">黑名单 IP 组(命中则拦截)</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="blacklist_group_id" class="form-control form-control-sm" style="max-width:320px;">
|
|
|
|
|
|
<option value="0" <?php if($currentBlacklistGroupId===0) echo 'selected'; ?>>无</option>
|
|
|
|
|
|
<?php foreach($blackGroups as $bg): ?>
|
|
|
|
|
|
<option value="<?php echo (int)$bg['id']; ?>" <?php if($currentBlacklistGroupId===(int)$bg['id']) echo 'selected'; ?>><?php echo htmlspecialchars($bg['name']); ?> (ID <?php echo $bg['id']; ?>)</option>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<small><a href="/admin_ip_manager.php?type=black" target="_blank">管理黑名单</a></small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">自动黑名单(达到次数后自动加入黑名单组)</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<div class="d-flex align-items-center gap-2" style="gap:10px;">
|
|
|
|
|
|
<div class="btn-group btn-group-toggle" data-toggle="buttons">
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary <?php if(AUTO_BLACK=='ON') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="auto_black" id="auto_black_on" value="ON" <?php if(AUTO_BLACK=='ON') echo 'checked'; ?>> 开启
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary <?php if(AUTO_BLACK!='ON') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="auto_black" id="auto_black_off" value="OFF" <?php if(AUTO_BLACK!='ON') echo 'checked'; ?>> 关闭
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="ml-2">触发次数:</span>
|
|
|
|
|
|
<input type="number" name="auto_black_times" value="<?php echo AUTO_BLACK_TIMES; ?>" class="form-control form-control-sm" style="width:80px;" min="1">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">白名单链接参数(携带此参数直接放行,格式:param=value)</td>
|
|
|
|
|
|
<td class="form-val-cell"><input type="text" name="white_params" class="form-control form-control-sm" value="<?php echo htmlspecialchars(WHITE_PARAMS); ?>" style="max-width:280px;" placeholder="如:token=abc123"></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== 设备与语言 ===== -->
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<button type="button" class="section-toggle collapsed" data-target="sec-device">
|
|
|
|
|
|
设备与语言过滤 <span class="arrow">▼</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div id="sec-device" style="display:none;">
|
|
|
|
|
|
<table class="table table-sm mb-0">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">屏蔽无 Referer 来源(防爬虫)</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('v_referer', CLOAK_V_REFERER); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">仅允许移动端访问</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('mobile_on', CLOAK_MOBILE_ON); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">屏蔽中文浏览器</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('zh_on', CLOAK_ZH_ON); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">仅允许 iOS / Android 系统</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('os_on', CLOAK_OS_ON); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">保留跳转链接参数</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('keep_params', KEEP_PARAMS); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">屏蔽 iPhone 型号</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="iphone_model" class="form-control form-control-sm" style="max-width:260px;">
|
|
|
|
|
|
<option value="0" <?php if(IPHONE_MODEL=='0') echo 'selected'; ?>>不屏蔽</option>
|
|
|
|
|
|
<option value="8" <?php if(IPHONE_MODEL=='8') echo 'selected'; ?>>屏蔽 iPhone 8 及以下</option>
|
|
|
|
|
|
<option value="10" <?php if(IPHONE_MODEL=='10') echo 'selected'; ?>>屏蔽 iPhone X 及以下</option>
|
|
|
|
|
|
<option value="11" <?php if(IPHONE_MODEL=='11') echo 'selected'; ?>>屏蔽 iPhone 11 及以下</option>
|
|
|
|
|
|
<option value="12" <?php if(IPHONE_MODEL=='12') echo 'selected'; ?>>屏蔽 iPhone 12 及以下</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">
|
|
|
|
|
|
虚拟设备检测<br>
|
|
|
|
|
|
<small class="text-muted">简单:全平台自动化/爬虫;标准:+环境一致性(移动无触摸等);严格:+移动GPU校验与传感器(约180ms)</small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<select name="is_virtual" class="form-control form-control-sm" style="max-width:260px;">
|
|
|
|
|
|
<option value="0" <?php if(IS_VIRTUAL=='0') echo 'selected'; ?>>不检测</option>
|
|
|
|
|
|
<option value="1" <?php if(IS_VIRTUAL=='1') echo 'selected'; ?>>简单</option>
|
|
|
|
|
|
<option value="2" <?php if(IS_VIRTUAL=='2') echo 'selected'; ?>>标准</option>
|
|
|
|
|
|
<option value="3" <?php if(IS_VIRTUAL=='3') echo 'selected'; ?>>严格</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== 广告来源限制 ===== -->
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<button type="button" class="section-toggle collapsed" data-target="sec-ad-source">
|
|
|
|
|
|
广告来源限制 <span class="arrow">▼</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div id="sec-ad-source" style="display:none;">
|
|
|
|
|
|
<table class="table table-sm mb-0">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">Facebook</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('ad_fb', $_d('CLOAK_AD_FB', 'OFF')); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">Google</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('ad_google', $_d('CLOAK_AD_GOOGLE', 'OFF')); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">TikTok</td>
|
|
|
|
|
|
<td class="form-val-cell"><?php echo onoff_radio('ad_tiktok', $_d('CLOAK_AD_TIKTOK', 'OFF')); ?></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">严格模式</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<?php echo onoff_radio('ad_strict', $_d('CLOAK_AD_STRICT', 'OFF')); ?>
|
|
|
|
|
|
<div class="text-muted mt-1" style="font-size:.78rem;">开启后,未通过广告来源验证的访问将直接跳转安全页;关闭时仅追加「未确定流量来源」并继续后续判定,日志行显示为黄色。</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">强验证参数 ad_spm_id</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<?php $spmShow = $_d('CLOAK_AD_SPM_ID', ''); ?>
|
|
|
|
|
|
<?php if ($spmShow !== ''): ?>
|
|
|
|
|
|
<code><?php echo htmlspecialchars($spmShow); ?></code>
|
|
|
|
|
|
<div class="text-muted mt-1" style="font-size:.78rem;">保存配置且开启任一广告平台时自动生成,写入广告链接用于强验证。</div>
|
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
|
<span class="text-muted">保存并开启任一广告平台后自动生成</span>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ===== 高级设置 ===== -->
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<button type="button" class="section-toggle collapsed" data-target="sec-advanced">
|
|
|
|
|
|
高级设置 <span class="arrow">▼</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div id="sec-advanced" style="display:none;">
|
|
|
|
|
|
<table class="table table-sm mb-0">
|
|
|
|
|
|
<tr>
|
2026-06-14 18:30:06 +08:00
|
|
|
|
<td class="form-label-cell">指纹风险系数(0=关闭,最大90)</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<input type="number" name="risk_number" class="form-control form-control-sm" value="<?php echo CLOAK_RISK_NUMBER; ?>" style="width:100px;" min="0" max="90">
|
|
|
|
|
|
<div class="text-muted mt-2" style="font-size:.78rem;line-height:1.55;">
|
|
|
|
|
|
数值越高,拦截越严格。访客风险分达到或超过此值时跳转安全页,低于则进入真实页。
|
|
|
|
|
|
设为 <strong>0</strong> 表示关闭二次风控。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<details class="mt-2" style="font-size:.78rem;line-height:1.55;">
|
|
|
|
|
|
<summary style="cursor:pointer;color:#0c5460;font-weight:600;">推荐设置(与下方「加强判断」配合)</summary>
|
|
|
|
|
|
<div class="text-muted mt-2">
|
|
|
|
|
|
<p class="mb-2">请根据「加强判断」开关选择对应数值,两种模式<strong>不宜使用同一分数</strong>。</p>
|
|
|
|
|
|
<table class="table table-sm table-bordered mb-2" style="font-size:.76rem;background:#fff;">
|
|
|
|
|
|
<thead class="thead-light">
|
|
|
|
|
|
<tr><th>加强判断</th><th>建议分数</th><th>说明</th></tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>OFF</strong></td>
|
|
|
|
|
|
<td><strong>68</strong></td>
|
|
|
|
|
|
<td>默认推荐,兼顾流量与防护,误拦较少</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>ON</strong></td>
|
|
|
|
|
|
<td><strong>52</strong></td>
|
|
|
|
|
|
<td>识别更严,适合需要更高防护的场景</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<p class="mb-1"><strong>微调:</strong></p>
|
|
|
|
|
|
<ul class="mb-0 pl-3">
|
|
|
|
|
|
<li>真实用户被误拦 → 分数 <strong>+3 ~ +5</strong></li>
|
|
|
|
|
|
<li>可疑访问漏过 → 分数 <strong>−3 ~ −5</strong></li>
|
|
|
|
|
|
<li>可在「访问日志 → 显示更多 → 判定详情」查看每条记录的风险分与拦截原因</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</details>
|
|
|
|
|
|
</td>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">加强判断</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<?php echo onoff_radio('risk_enhanced', $_d('CLOAK_RISK_ENHANCED', 'OFF')); ?>
|
2026-06-14 18:30:06 +08:00
|
|
|
|
<div class="text-muted mt-1" style="font-size:.78rem;line-height:1.55;">
|
|
|
|
|
|
开启后识别更精细,可拦截更多自动化访问;老旧设备或弱网环境下可能受影响。<br>
|
|
|
|
|
|
建议配合上方风险系数:OFF 用 <strong>68</strong>,ON 用 <strong>52</strong>。
|
|
|
|
|
|
</div>
|
2026-06-14 14:00:24 +08:00
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">
|
|
|
|
|
|
临时链接参数有效时长(分钟,0=关闭)<br>
|
|
|
|
|
|
<small class="text-muted">通过广告来源限制规则(ad_spm_id / clid / Referer / UA 等)后开始计时,有效时长内放行;到期重新判断。未开启广告平台时仍按 clid/ad_spm_id 触发。</small>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<div class="d-flex align-items-center" style="gap:8px;">
|
|
|
|
|
|
<input type="number" name="url_args_timeout" class="form-control form-control-sm" value="<?php echo CLOAK_URL_ARGS_TIMEOUT; ?>" style="width:90px;" min="0"> 分钟
|
|
|
|
|
|
<button type="button" class="btn btn-sm btn-outline-warning" onclick="delUrlArgs()">重置计时</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="form-label-cell">记录访客日志</td>
|
|
|
|
|
|
<td class="form-val-cell">
|
|
|
|
|
|
<div class="btn-group btn-group-toggle" data-toggle="buttons">
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary <?php if(WRITE_LOG=='1') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="write_log" value="1" <?php if(WRITE_LOG=='1') echo 'checked'; ?>> 开启
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<label class="btn btn-sm btn-outline-secondary <?php if(WRITE_LOG!='1') echo 'active'; ?>">
|
|
|
|
|
|
<input type="radio" name="write_log" value="0" <?php if(WRITE_LOG!='1') echo 'checked'; ?>> 关闭
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- /padding -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部操作栏 -->
|
|
|
|
|
|
<div class="sticky-actions">
|
|
|
|
|
|
<button type="submit" class="btn btn-primary">保存配置</button>
|
|
|
|
|
|
<a href="<?php echo $current_name . '?action=edit_config&name=' . $check_name; ?>" class="btn btn-outline-secondary">重置</a>
|
|
|
|
|
|
<a href="/table" target="_blank" class="btn btn-outline-info">查看日志</a>
|
|
|
|
|
|
<a href="/log_analytics.php" target="_blank" class="btn btn-outline-info">数据分析</a>
|
|
|
|
|
|
<a href="/share_log.php" target="_blank" class="btn btn-outline-info">分享日志</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</div><!-- /page-body -->
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
$(function() {
|
|
|
|
|
|
// 手风琴展开/折叠
|
|
|
|
|
|
$('.section-toggle').on('click', function() {
|
|
|
|
|
|
var target = '#' + $(this).data('target');
|
|
|
|
|
|
$(this).toggleClass('collapsed');
|
|
|
|
|
|
$(target).slideToggle(180);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 动态添加链接
|
|
|
|
|
|
var linkIdx = 1;
|
|
|
|
|
|
$(document).on('click', '#addNewLinkBtn', function() {
|
|
|
|
|
|
linkIdx++;
|
|
|
|
|
|
var html = '<br><input type="text" name="DB_fp[]" class="form-control form-control-sm mt-1" value="" style="max-width:420px;" data-idx="' + linkIdx + '"> <a href="javascript:void(0);" class="removeLinkBtn btn btn-sm btn-outline-danger">删除</a>';
|
|
|
|
|
|
$(this).after(html);
|
|
|
|
|
|
});
|
|
|
|
|
|
$(document).on('click', '.removeLinkBtn', function() {
|
|
|
|
|
|
$(this).prev('br').remove();
|
|
|
|
|
|
$(this).prev('input').remove();
|
|
|
|
|
|
$(this).remove();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 自动黑名单校验
|
|
|
|
|
|
$('#configForm').on('submit', function() {
|
|
|
|
|
|
var on = $('#auto_black_on').is(':checked');
|
|
|
|
|
|
var gid = parseInt($('select[name=blacklist_group_id]').val(), 10) || 0;
|
|
|
|
|
|
if (on && gid <= 0) {
|
|
|
|
|
|
alert('开启「自动黑名单」时,必须先选择「黑名单 IP 组」。');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 广告链接复制
|
|
|
|
|
|
$(document).on('click', '.btn-copy-ad', function() {
|
|
|
|
|
|
var text = $(this).attr('data-copy') || '';
|
|
|
|
|
|
if (!text) return;
|
|
|
|
|
|
var btn = this;
|
|
|
|
|
|
var done = function() {
|
|
|
|
|
|
var orig = btn.textContent;
|
|
|
|
|
|
btn.textContent = '已复制';
|
|
|
|
|
|
setTimeout(function() { btn.textContent = orig; }, 1200);
|
|
|
|
|
|
};
|
|
|
|
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
|
|
|
|
navigator.clipboard.writeText(text).then(done).catch(function() {
|
|
|
|
|
|
window.prompt('请手动复制链接:', text);
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
window.prompt('请手动复制链接:', text);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
function delUrlArgs() {
|
|
|
|
|
|
if (!confirm('确认重置临时链接参数计时?')) return;
|
|
|
|
|
|
window.location.href = '<?php echo $current_name; ?>?action=delUrlArgs&check_name=<?php echo urlencode($check_name); ?>';
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|