272 lines
13 KiB
PHP
272 lines
13 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
session_start();
|
|
require_once __DIR__ . '/db/config.php';
|
|
require_once __DIR__ . '/languages/helper.php';
|
|
|
|
// Authentication and Authorization check
|
|
if (!isset($_SESSION['user_id'])) {
|
|
header('Location: login.php');
|
|
exit;
|
|
}
|
|
|
|
if (($_SESSION['role'] ?? 'user') !== 'admin') {
|
|
header('Location: index.php');
|
|
exit;
|
|
}
|
|
|
|
$message = '';
|
|
$pdo = db();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
if (isset($_POST['logout'])) {
|
|
session_destroy();
|
|
header('Location: login.php');
|
|
exit;
|
|
}
|
|
|
|
$head_ads = $_POST['head_ads'] ?? '';
|
|
$body_ads = $_POST['body_ads'] ?? '';
|
|
$openai_api_key = $_POST['openai_api_key'] ?? '';
|
|
$openai_model = $_POST['openai_model'] ?? 'gpt-4o-mini';
|
|
$site_name = $_POST['site_name'] ?? 'TikTok Live AI Assistant';
|
|
$default_language = $_POST['default_language'] ?? 'en';
|
|
|
|
// Handle File Uploads
|
|
$upload_dir = 'assets/images/';
|
|
if (!is_dir($upload_dir)) {
|
|
mkdir($upload_dir, 0775, true);
|
|
}
|
|
|
|
$site_icon = $_POST['current_site_icon'] ?? 'assets/images/logo.png';
|
|
if (!empty($_FILES['site_icon']['name'])) {
|
|
$icon_name = 'logo_' . time() . '.' . pathinfo($_FILES['site_icon']['name'], PATHINFO_EXTENSION);
|
|
if (move_uploaded_file($_FILES['site_icon']['tmp_name'], $upload_dir . $icon_name)) {
|
|
$site_icon = $upload_dir . $icon_name;
|
|
}
|
|
}
|
|
|
|
$site_favicon = $_POST['current_site_favicon'] ?? 'favicon.ico';
|
|
if (!empty($_FILES['site_favicon']['name'])) {
|
|
$fav_name = 'favicon_' . time() . '.' . pathinfo($_FILES['site_favicon']['name'], PATHINFO_EXTENSION);
|
|
if (move_uploaded_file($_FILES['site_favicon']['tmp_name'], $upload_dir . $fav_name)) {
|
|
$site_favicon = $upload_dir . $fav_name;
|
|
}
|
|
}
|
|
|
|
$settings_to_update = [
|
|
'head_ads' => $head_ads,
|
|
'body_ads' => $body_ads,
|
|
'openai_api_key' => $openai_api_key,
|
|
'openai_model' => $openai_model,
|
|
'site_name' => $site_name,
|
|
'site_icon' => $site_icon,
|
|
'site_favicon' => $site_favicon,
|
|
'default_language' => $default_language
|
|
];
|
|
|
|
foreach ($settings_to_update as $key => $value) {
|
|
$stmt = $pdo->prepare("INSERT INTO site_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
|
|
$stmt->execute([$key, $value, $value]);
|
|
}
|
|
|
|
$message = "Settings updated successfully!";
|
|
}
|
|
|
|
// Fetch current settings
|
|
$stmt = $pdo->query("SELECT setting_key, setting_value FROM site_settings");
|
|
$settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
$head_ads = $settings['head_ads'] ?? '';
|
|
$body_ads = $settings['body_ads'] ?? '';
|
|
$openai_api_key = $settings['openai_api_key'] ?? '';
|
|
$openai_model = $settings['openai_model'] ?? 'gpt-4o-mini';
|
|
$site_name = $settings['site_name'] ?? 'TikTok Live AI Assistant';
|
|
$site_icon = $settings['site_icon'] ?? 'assets/images/logo.png';
|
|
$site_favicon = $settings['site_favicon'] ?? 'favicon.ico';
|
|
$default_language = $settings['default_language'] ?? 'en';
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= get_lang() ?>">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title><?= __('admin') ?> - <?= htmlspecialchars($site_name) ?></title>
|
|
<link rel="icon" type="image/x-icon" href="<?= htmlspecialchars($site_favicon) ?>">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time() ?>">
|
|
<style>
|
|
body { font-family: 'Inter', sans-serif; background-color: #0f0f0f; color: #fff; }
|
|
.card-admin { background-color: #1a1a1a; border: 1px solid #333; border-radius: 12px; }
|
|
.form-control, .form-select { background-color: #262626; border-color: #444; color: #fff; }
|
|
.form-control:focus, .form-select:focus { background-color: #2d2d2d; border-color: #00f2ea; color: #fff; box-shadow: 0 0 0 0.25rem rgba(0, 242, 234, 0.25); }
|
|
.btn-save { background-color: #00f2ea; color: #000; font-weight: 700; border-radius: 8px; border: none; padding: 12px 24px; }
|
|
.btn-save:hover { background-color: #00d8d1; color: #000; }
|
|
.text-tiktok-cyan { color: #00f2ea; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="navbar navbar-dark bg-black border-bottom border-secondary mb-5">
|
|
<div class="container">
|
|
<a class="navbar-brand fw-bold" href="/">
|
|
<span class="text-tiktok-cyan">TikTok</span> Live Admin
|
|
</a>
|
|
<div class="d-flex align-items-center">
|
|
<span class="text-secondary small me-3"><?= __('hi') ?>, <?= htmlspecialchars($_SESSION['username']) ?></span>
|
|
<a href="/" class="btn btn-outline-light btn-sm me-2"><?= __('back_to_home') ?></a>
|
|
<form action="admin.php" method="POST" class="m-0 d-inline">
|
|
<button type="submit" name="logout" class="btn btn-danger btn-sm"><?= __('logout') ?></button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="container mb-5">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-10">
|
|
<div class="card-admin p-4 shadow-lg mb-4">
|
|
<h2 class="mb-4 fw-bold"><?= __('site_settings') ?></h2>
|
|
|
|
<?php if ($message): ?>
|
|
<div class="alert alert-success bg-dark text-success border-success"><?= $message ?></div>
|
|
<?php endif; ?>
|
|
|
|
<form method="POST" enctype="multipart/form-data">
|
|
<div class="row g-4">
|
|
<div class="col-md-6">
|
|
<label for="site_name" class="form-label fw-semibold text-secondary small"><?= __('site_name') ?></label>
|
|
<input type="text" name="site_name" id="site_name" class="form-control" value="<?= htmlspecialchars($site_name) ?>">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="default_language" class="form-label fw-semibold text-secondary small"><?= __('language') ?></label>
|
|
<select name="default_language" id="default_language" class="form-select">
|
|
<option value="en" <?= $default_language === 'en' ? 'selected' : '' ?>>English</option>
|
|
<option value="id" <?= $default_language === 'id' ? 'selected' : '' ?>>Indonesia</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="site_icon" class="form-label fw-semibold text-secondary small"><?= __('site_icon') ?></label>
|
|
<input type="file" name="site_icon" id="site_icon" class="form-control">
|
|
<input type="hidden" name="current_site_icon" value="<?= htmlspecialchars($site_icon) ?>">
|
|
<?php if ($site_icon): ?>
|
|
<div class="mt-2 small text-secondary">Current: <img src="<?= $site_icon ?>" height="30" class="ms-2"></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="site_favicon" class="form-label fw-semibold text-secondary small"><?= __('site_favicon') ?></label>
|
|
<input type="file" name="site_favicon" id="site_favicon" class="form-control">
|
|
<input type="hidden" name="current_site_favicon" value="<?= htmlspecialchars($site_favicon) ?>">
|
|
<?php if ($site_favicon): ?>
|
|
<div class="mt-2 small text-secondary">Current: <img src="<?= $site_favicon ?>" height="20" class="ms-2"></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<hr class="border-secondary my-2">
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="openai_api_key" class="form-label fw-semibold text-secondary small"><?= __('openai_key') ?></label>
|
|
<input type="password" name="openai_api_key" id="openai_api_key" class="form-control" placeholder="sk-..." value="<?= htmlspecialchars($openai_api_key) ?>">
|
|
<div class="form-text text-muted">If left empty, the application will use the Flatlogic AI Proxy.</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="openai_model" class="form-label fw-semibold text-secondary small"><?= __('openai_model') ?></label>
|
|
<select name="openai_model" id="openai_model" class="form-select">
|
|
<option value="gpt-4o-mini" <?= $openai_model === 'gpt-4o-mini' ? 'selected' : '' ?>>GPT-4o Mini (Default)</option>
|
|
<option value="o3-mini" <?= $openai_model === 'o3-mini' ? 'selected' : '' ?>>o3-mini (Reasoning)</option>
|
|
<option value="gpt-4o" <?= $openai_model === 'gpt-4o' ? 'selected' : '' ?>>GPT-4o (High Quality)</option>
|
|
</select>
|
|
<div class="form-text text-muted">Choose which model to use with your API Key.</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="head_ads" class="form-label fw-semibold text-secondary small"><?= __('head_scripts') ?></label>
|
|
<textarea name="head_ads" id="head_ads" rows="4" class="form-control" placeholder="Paste your <head> scripts here..."><?= htmlspecialchars($head_ads) ?></textarea>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<label for="body_ads" class="form-label fw-semibold text-secondary small"><?= __('body_scripts') ?></label>
|
|
<textarea name="body_ads" id="body_ads" rows="4" class="form-control" placeholder="Paste your <body> scripts here..."><?= htmlspecialchars($body_ads) ?></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid mt-5">
|
|
<button type="submit" class="btn btn-save"><?= __('save_settings') ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Diagnostics Card -->
|
|
<div class="card-admin p-4 shadow-lg border-warning border-opacity-25">
|
|
<h4 class="mb-3 fw-bold text-warning"><i class="fa-solid fa-microchip me-2"></i> System Diagnostics</h4>
|
|
<p class="text-secondary small">Check if your hosting (cPanel/Other) is compatible with the TikTok Bridge.</p>
|
|
|
|
<div id="diagnosticsOutput" class="p-3 bg-black rounded border border-secondary mb-3" style="font-family: monospace; font-size: 0.85rem; max-height: 300px; overflow-y: auto;">
|
|
Loading diagnostics...
|
|
</div>
|
|
|
|
<button class="btn btn-outline-warning btn-sm" id="runDiagnosticsBtn">
|
|
<i class="fa-solid fa-rotate me-1"></i> Run Diagnostics
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const diagOutput = document.getElementById('diagnosticsOutput');
|
|
const runBtn = document.getElementById('runDiagnosticsBtn');
|
|
|
|
async function runDiagnostics() {
|
|
diagOutput.innerHTML = '<span class="text-secondary">Running diagnostics...</span>';
|
|
try {
|
|
const resp = await fetch('api/bridge_control.php?action=debug&username=admin'); // username doesn't matter for debug
|
|
const data = await resp.json();
|
|
|
|
if (data.success && data.env) {
|
|
let html = '<table class="table table-dark table-sm table-borderless mb-0">';
|
|
for (const [key, value] of Object.entries(data.env)) {
|
|
let valDisplay = value;
|
|
let colorClass = '';
|
|
|
|
if (value === true) { valDisplay = '<span class="text-success">YES</span>'; }
|
|
else if (value === false) { valDisplay = '<span class="text-danger">NO</span>'; }
|
|
else if (!value) { valDisplay = '<span class="text-secondary">N/A</span>'; }
|
|
|
|
html += `<tr><td class="text-secondary" style="width: 40%">${key}:</td><td>${valDisplay}</td></tr>`;
|
|
}
|
|
html += '</table>';
|
|
|
|
if (!data.env.shell_exec_enabled) {
|
|
html += '<div class="mt-3 text-danger small"><strong>Warning:</strong> shell_exec is disabled. The TikTok bridge cannot start. Please enable it in cPanel MultiPHP INI Editor or contact your host.</div>';
|
|
}
|
|
if (!data.env.node_path || data.env.node_path === 'node') {
|
|
html += '<div class="mt-2 text-warning small"><strong>Notice:</strong> Node binary not explicitly found. Ensure "node" is in your system PATH.</div>';
|
|
}
|
|
if (!data.env.node_modules_exists) {
|
|
html += '<div class="mt-2 text-danger small"><strong>Warning:</strong> node_modules folder is missing. Run "npm install" on your server.</div>';
|
|
}
|
|
|
|
diagOutput.innerHTML = html;
|
|
} else {
|
|
diagOutput.innerHTML = '<span class="text-danger">Error fetching diagnostics: ' + (data.error || 'Unknown error') + '</span>';
|
|
}
|
|
} catch (err) {
|
|
diagOutput.innerHTML = '<span class="text-danger">Network Error: Could not reach bridge control API.</span>';
|
|
}
|
|
}
|
|
|
|
runBtn.addEventListener('click', runDiagnostics);
|
|
runDiagnostics(); // Run on load
|
|
});
|
|
</script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
|
|
</body>
|
|
</html>
|