Your IP : 216.73.217.78


Current Path : /home/seto/888mirror.pm/admin/
Upload File :
Current File : /home/seto/888mirror.pm/admin/settings.php

<?php
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/helpers.php';

auth_check();

$msg = [];
$err = [];

// OpenAI настройки
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_openai']) && auth_can('openai_key')) {
    $key   = trim($_POST['openai_key'] ?? '');
    $model = trim($_POST['openai_model'] ?? 'gpt-4o');
    setting_set('openai_key', $key);
    setting_set('openai_model', $model);
    $msg['openai'] = 'OpenAI настройки сохранены.';
}

// Название сайта
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_site'])) {
    $site_name = trim($_POST['site_name'] ?? '');
    if ($site_name) {
        setting_set('site_name', $site_name);
        $msg['site'] = 'Название сайта сохранено.';
    } else {
        $err['site'] = 'Название не может быть пустым.';
    }
}

// Excluded IPs
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_excluded_ips'])) {
    $raw_ips = $_POST['excluded_ips'] ?? '';
    $lines   = array_filter(array_map('trim', explode("\n", str_replace("\r", "\n", $raw_ips))));
    $valid   = array_filter($lines, function($entry) {
        if (str_contains($entry, '/')) {
            [$ip, $bits] = explode('/', $entry, 2);
            $is_ipv6  = str_contains($ip, ':');
            $max_bits = $is_ipv6 ? 128 : 32;
            return filter_var($ip, FILTER_VALIDATE_IP) && ctype_digit($bits) && (int)$bits >= 0 && (int)$bits <= $max_bits;
        }
        return (bool)filter_var($entry, FILTER_VALIDATE_IP);
    });
    setting_set('excluded_ips', implode("\n", $valid));
    $msg['ips'] = 'Сохранено. Записей в списке: ' . count($valid) . '.';
}

// Смена пароля
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['change_password'])) {
    $cur  = $_POST['current_password'] ?? '';
    $new  = $_POST['new_password'] ?? '';
    $conf = $_POST['confirm_password'] ?? '';

    $user = db()->prepare("SELECT id, password_hash FROM users WHERE id = ?");
    $user->execute([$_SESSION['user_id']]);
    $user = $user->fetch();

    if (!$cur || !$new || !$conf) {
        $err['pwd'] = 'Заполните все поля.';
    } elseif (!password_verify($cur, $user['password_hash'])) {
        $err['pwd'] = 'Текущий пароль неверный.';
    } elseif (strlen($new) < 6) {
        $err['pwd'] = 'Новый пароль должен быть не менее 6 символов.';
    } elseif ($new !== $conf) {
        $err['pwd'] = 'Пароли не совпадают.';
    } else {
        $hash = password_hash($new, PASSWORD_DEFAULT);
        db()->prepare("UPDATE users SET password_hash = ? WHERE id = ?")->execute([$hash, $user['id']]);
        $msg['pwd'] = 'Пароль успешно изменён.';
    }
}

$openai_key   = setting('openai_key');
$openai_model = setting('openai_model') ?: 'gpt-4o';
$site_name    = setting('site_name') ?: '888mirror.pm';
$excluded_ips = setting('excluded_ips');
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Настройки — Admin</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<?= admin_nav('settings') ?>
<div class="container" style="max-width:680px">
    <h5 class="mb-4">Настройки</h5>

    <!-- OpenAI -->
    <?php if (auth_can('openai_key')): ?>
    <div class="card shadow-sm mb-4">
        <div class="card-header fw-semibold">🤖 OpenAI</div>
        <div class="card-body">
            <?php if (!empty($msg['openai'])): ?>
                <div class="alert alert-success py-2"><?= h($msg['openai']) ?></div>
            <?php endif ?>
            <?php if (!$openai_key): ?>
                <div class="alert alert-warning py-2">⚠ API ключ не задан — генерация контента недоступна.</div>
            <?php endif ?>
            <form method="post">
                <div class="mb-3">
                    <label class="form-label">API Key</label>
                    <input type="text" name="openai_key" class="form-control font-monospace"
                           value="<?= h($openai_key) ?>" placeholder="sk-...">
                    <div class="form-text">Получить на <a href="https://platform.openai.com/api-keys" target="_blank">platform.openai.com</a></div>
                </div>
                <div class="mb-3">
                    <label class="form-label">Модель</label>
                    <select name="openai_model" class="form-select">
                        <?php foreach (['gpt-4o' => 'gpt-4o (умная)', 'gpt-4o-mini' => 'gpt-4o-mini (дешевле)', 'gpt-4-turbo' => 'gpt-4-turbo'] as $val => $label): ?>
                            <option value="<?= $val ?>" <?= $openai_model === $val ? 'selected' : '' ?>><?= $label ?></option>
                        <?php endforeach ?>
                    </select>
                </div>
                <button type="submit" name="save_openai" class="btn btn-primary btn-sm">Сохранить</button>
            </form>
        </div>
    </div>
    <?php endif ?>

    <!-- Название сайта -->
    <div class="card shadow-sm mb-4">
        <div class="card-header fw-semibold">🌐 Название сайта</div>
        <div class="card-body">
            <?php if (!empty($msg['site'])): ?>
                <div class="alert alert-success py-2"><?= h($msg['site']) ?></div>
            <?php endif ?>
            <?php if (!empty($err['site'])): ?>
                <div class="alert alert-danger py-2"><?= h($err['site']) ?></div>
            <?php endif ?>
            <form method="post">
                <div class="mb-3">
                    <label class="form-label">Название</label>
                    <input type="text" name="site_name" class="form-control"
                           value="<?= h($site_name) ?>" placeholder="888mirror.pm">
                    <div class="form-text">Используется в title и footer публичной страницы.</div>
                </div>
                <button type="submit" name="save_site" class="btn btn-primary btn-sm">Сохранить</button>
            </form>
        </div>
    </div>

    <!-- Excluded IPs -->
    <div class="card shadow-sm mb-4">
        <div class="card-header fw-semibold">🚫 Исключённые IP-адреса</div>
        <div class="card-body">
            <?php if (!empty($msg['ips'])): ?>
                <div class="alert alert-success py-2"><?= h($msg['ips']) ?></div>
            <?php endif ?>
            <form method="post">
                <div class="mb-3">
                    <label class="form-label">Список IP <span class="text-muted fw-normal">(один адрес на строку)</span></label>
                    <textarea name="excluded_ips" class="form-control font-monospace" rows="5"
                              placeholder="192.168.1.1&#10;10.0.0.0/8&#10;2a01:4f9:3090:2163::2&#10;2a01:4f9:3090:2163::/64"><?= h($excluded_ips) ?></textarea>
                    <div class="form-text">Показы и клики с этих IP не будут записываться в статистику. Поддерживаются IPv4, IPv6 и CIDR-диапазоны (например <code>2a01:4f9::/32</code>).</div>
                </div>
                <button type="submit" name="save_excluded_ips" class="btn btn-primary btn-sm">Сохранить</button>
                <?php
                $ip_count = count(array_filter(array_map('trim', explode("\n", $excluded_ips))));
                if ($ip_count > 0): ?>
                    <span class="text-muted small ms-2"><?= $ip_count ?> запис<?= $ip_count >= 5 ? 'ей' : ($ip_count >= 2 ? 'и' : 'ь') ?> в списке</span>
                <?php endif ?>
            </form>
        </div>
    </div>

    <!-- Внешний вид -->
    <div class="card shadow-sm mb-4">
        <div class="card-header fw-semibold">🎨 Внешний вид админки</div>
        <div class="card-body">
            <p class="text-muted small mb-3">Тема применяется только в вашем браузере (localStorage).</p>
            <div class="row g-2" id="theme-picker">
                <?php
                $themes = [
                    'default' => ['Default',  'Стандартный Bootstrap',       '#0d6efd', '#fff'],
                    'flatly'  => ['Flatly',   'Плоский, современный стиль',  '#2c3e50', '#18bc9c'],
                    'darkly'  => ['Darkly',   'Тёмная версия Flatly',        '#222',    '#375a7f'],
                    'cyborg'  => ['Cyborg',   'Тёмная sci-fi тема',          '#060606', '#2a9fd6'],
                    'minty'   => ['Minty',    'Свежая, мятно-зелёная',       '#fff',    '#78c2ad'],
                ];
                foreach ($themes as $key => [$name, $desc, $bg, $accent]): ?>
                <div class="col-6 col-md-4">
                    <button type="button"
                        class="btn w-100 p-0 border-2 rounded-3 overflow-hidden theme-btn"
                        data-theme="<?= $key ?>"
                        style="border-color: transparent">
                        <div style="background:<?= $bg ?>;height:40px;display:flex;align-items:center;justify-content:center;gap:6px">
                            <div style="width:12px;height:12px;border-radius:50%;background:<?= $accent ?>"></div>
                            <span style="color:<?= $bg === '#fff' ? '#333' : '#fff' ?>;font-size:13px;font-weight:600"><?= $name ?></span>
                        </div>
                        <div class="px-2 py-1 bg-body-tertiary">
                            <small class="text-muted"><?= $desc ?></small>
                        </div>
                    </button>
                </div>
                <?php endforeach ?>
            </div>
        </div>
    </div>

    <!-- Смена пароля -->
    <div class="card shadow-sm mb-4">
        <div class="card-header fw-semibold">🔒 Смена пароля</div>
        <div class="card-body">
            <?php if (!empty($msg['pwd'])): ?>
                <div class="alert alert-success py-2"><?= h($msg['pwd']) ?></div>
            <?php endif ?>
            <?php if (!empty($err['pwd'])): ?>
                <div class="alert alert-danger py-2"><?= h($err['pwd']) ?></div>
            <?php endif ?>
            <form method="post" autocomplete="off">
                <div class="mb-2">
                    <label class="form-label">Текущий пароль</label>
                    <input type="password" name="current_password" class="form-control" required>
                </div>
                <div class="mb-2">
                    <label class="form-label">Новый пароль</label>
                    <input type="password" name="new_password" class="form-control" required minlength="6">
                </div>
                <div class="mb-3">
                    <label class="form-label">Повторите новый пароль</label>
                    <input type="password" name="confirm_password" class="form-control" required minlength="6">
                </div>
                <button type="submit" name="change_password" class="btn btn-warning btn-sm">Сменить пароль</button>
            </form>
        </div>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
(function(){
    var THEMES = {
        'default': 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css',
        'flatly':  'https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/flatly/bootstrap.min.css',
        'darkly':  'https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/darkly/bootstrap.min.css',
        'cyborg':  'https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/cyborg/bootstrap.min.css',
        'minty':   'https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/minty/bootstrap.min.css',
    };
    var current = localStorage.getItem('admin_theme') || 'default';

    function applyActive() {
        document.querySelectorAll('.theme-btn').forEach(function(btn) {
            var t = btn.dataset.theme;
            btn.style.borderColor = (t === current) ? '#0d6efd' : 'transparent';
            btn.style.boxShadow   = (t === current) ? '0 0 0 3px rgba(13,110,253,.35)' : '';
        });
    }

    function applyTheme(t) {
        current = t;
        localStorage.setItem('admin_theme', t);
        var link = document.querySelector('link[rel="stylesheet"][href*="bootstrap"]');
        if (link) {
            document.documentElement.style.opacity = '0';
            link.href = THEMES[t];
            link.addEventListener('load', function() {
                document.documentElement.style.opacity = '';
            }, {once: true});
            setTimeout(function(){ document.documentElement.style.opacity = ''; }, 400);
        }
        applyActive();
    }

    document.querySelectorAll('.theme-btn').forEach(function(btn) {
        btn.addEventListener('click', function() { applyTheme(btn.dataset.theme); });
    });

    applyActive();
})();
</script>
</body>
</html>