<?php
declare(strict_types=1);
require dirname(__DIR__) . '/app/bootstrap.php';

$lock = dirname(__DIR__) . '/storage/installed.lock';
if (!is_file($lock)) redirect('install.php');
$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    verify_csrf();
    $action = (string) ($_POST['action'] ?? '');
    if ($action === 'login') {
        $now = time();
        if ((int) ($_SESSION['login_locked_until'] ?? 0) > $now) {
            $error = '登录暂时锁定，请稍后再试。';
        } else {
            $q = db()->prepare('SELECT * FROM admins WHERE username = :username LIMIT 1');
            $q->execute([':username' => mb_substr(trim((string) ($_POST['username'] ?? '')), 0, 80)]);
            $admin = $q->fetch();
            if ($admin && password_verify((string) ($_POST['password'] ?? ''), $admin['password_hash'])) {
                session_regenerate_id(true); $_SESSION['admin_id'] = $admin['id']; unset($_SESSION['login_attempts'], $_SESSION['login_locked_until']); redirect('admin.php');
            }
            $_SESSION['login_attempts'] = (int) ($_SESSION['login_attempts'] ?? 0) + 1;
            if ($_SESSION['login_attempts'] >= 5) $_SESSION['login_locked_until'] = $now + 300;
            $error = '用户名或密码错误。';
        }
    } else {
        require_admin();
        if ($action === 'logout') { $_SESSION = []; session_destroy(); redirect('admin.php'); }
        if ($action === 'settings') {
            $q = db()->prepare('INSERT INTO settings(setting_key,setting_value,updated_at) VALUES(:key,:value,CURRENT_TIMESTAMP) ON CONFLICT(setting_key) DO UPDATE SET setting_value=excluded.setting_value,updated_at=CURRENT_TIMESTAMP');
            foreach ((array) ($_POST['settings'] ?? []) as $key => $value) if (preg_match('/^[A-Z0-9_]{1,100}$/', (string) $key)) { $q->execute([':key' => $key, ':value' => mb_substr(trim((string) $value), 0, 5000)]); }
        }
        if ($action === 'category') {
            $q = db()->prepare('INSERT INTO categories(parent_id,name,slug,sort_order) VALUES(:parent,:name,:slug,:sort) ON CONFLICT(slug) DO UPDATE SET parent_id=excluded.parent_id,name=excluded.name,sort_order=excluded.sort_order');
            $q->execute([':parent' => max(0, (int) ($_POST['parent_id'] ?? 0)), ':name' => post_text('name', 160), ':slug' => preg_replace('/[^a-zA-Z0-9_-]/', '-', post_text('slug', 160)), ':sort' => (int) ($_POST['sort_order'] ?? 0)]);
        }
        if ($action === 'article') {
            $slug = preg_replace('/[^a-zA-Z0-9_-]/', '-', post_text('slug', 180));
            $q = db()->prepare('INSERT INTO articles(category_id,title,slug,summary,cover_image,content,published,sort_order,published_at) VALUES(:category,:title,:slug,:summary,:cover,:content,:published,:sort,:published_at) ON CONFLICT(slug) DO UPDATE SET category_id=excluded.category_id,title=excluded.title,summary=excluded.summary,cover_image=excluded.cover_image,content=excluded.content,published=excluded.published,sort_order=excluded.sort_order,published_at=excluded.published_at,updated_at=CURRENT_TIMESTAMP');
            $q->execute([':category' => max(0, (int) ($_POST['category_id'] ?? 0)), ':title' => post_text('title', 255), ':slug' => $slug, ':summary' => post_text('summary', 5000), ':cover' => post_text('cover_image', 500), ':content' => (string) ($_POST['content'] ?? ''), ':published' => isset($_POST['published']) ? 1 : 0, ':sort' => (int) ($_POST['sort_order'] ?? 0), ':published_at' => post_text('published_at', 30) ?: null]);
        }
        if ($action === 'slide') { $q=db()->prepare('INSERT INTO slides(title,image_url,link_url,sort_order,enabled) VALUES(:title,:image,:link,:sort,:enabled)'); $q->execute([':title'=>post_text('title',255),':image'=>post_text('image_url',500),':link'=>post_text('link_url',500),':sort'=>(int)($_POST['sort_order']??0),':enabled'=>isset($_POST['enabled'])?1:0]); }
        if ($action === 'link') { $q=db()->prepare('INSERT INTO links(name,url,logo_url,sort_order,enabled) VALUES(:name,:url,:logo,:sort,:enabled)'); $q->execute([':name'=>post_text('name',160),':url'=>post_text('url',500),':logo'=>post_text('logo_url',500),':sort'=>(int)($_POST['sort_order']??0),':enabled'=>isset($_POST['enabled'])?1:0]); }
        if ($action === 'delete') { $table = (string) ($_POST['table'] ?? ''); if (in_array($table, ['categories','articles','slides','links'], true)) { $q=db()->prepare('DELETE FROM ' . $table . ' WHERE id = :id'); $q->execute([':id'=>max(0,(int)($_POST['id']??0))]); } }
        if ($action === 'upload_media' && isset($_FILES['media'])) {
            $file = $_FILES['media']; $allowed = ['image/jpeg'=>'jpg','image/png'=>'png','image/gif'=>'gif','image/webp'=>'webp'];
            if ($file['error'] !== UPLOAD_ERR_OK || $file['size'] > 10 * 1024 * 1024) exit('Invalid upload.');
            $mime = (new finfo(FILEINFO_MIME_TYPE))->file($file['tmp_name']);
            if (!isset($allowed[$mime]) || @getimagesize($file['tmp_name']) === false) exit('Only valid JPG, PNG, GIF or WebP images are allowed.');
            $name = bin2hex(random_bytes(16)) . '.' . $allowed[$mime]; $dir = dirname(__DIR__) . '/public/uploads';
            if (!is_dir($dir)) mkdir($dir, 0750, true); if (!move_uploaded_file($file['tmp_name'], $dir . '/' . $name)) exit('Could not store upload.');
            $q=db()->prepare('INSERT INTO media(original_name,file_name,mime_type,file_size) VALUES(:original,:file,:mime,:size)'); $q->execute([':original'=>mb_substr((string)$file['name'],0,255),':file'=>$name,':mime'=>$mime,':size'=>(int)$file['size']]);
        }
        redirect('admin.php?saved=1');
    }
}
if (!is_admin()): ?><!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>CMS 登录</title><style>body{font:16px system-ui;max-width:420px;margin:70px auto;padding:0 20px}input{display:block;width:100%;box-sizing:border-box;padding:10px;margin:8px 0 16px}button{padding:10px 18px}.error{color:#b00}</style><h1>CMS 管理后台</h1><?php if ($error): ?><p class="error"><?=e($error)?></p><?php endif; ?><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="login"><label>用户名<input name="username" autocomplete="username" required></label><label>密码<input type="password" name="password" autocomplete="current-password" required></label><button>登录</button></form></html><?php exit; endif;
$settings = ['SITE_NAME','SITE_KEYWORDS','SITE_DESCRIPTION','LOGO','PHONE','COURSE_PHONE','ADDRESS_1','ADDRESS_2','ADDRESS_3','WECHAT_QR','COPYRIGHT'];
$cats = db()->query('SELECT * FROM categories ORDER BY sort_order,id')->fetchAll(); $articles = db()->query('SELECT * FROM articles ORDER BY id DESC LIMIT 50')->fetchAll(); $slides = db()->query('SELECT * FROM slides ORDER BY sort_order,id')->fetchAll(); $links = db()->query('SELECT * FROM links ORDER BY sort_order,id')->fetchAll(); $media = db()->query('SELECT * FROM media ORDER BY id DESC LIMIT 50')->fetchAll();
?><!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>CMS 管理后台</title><style>body{font:14px system-ui;margin:0;background:#f5f6f8;color:#222}.top{background:#18212b;color:#fff;padding:14px 24px;display:flex;justify-content:space-between}.wrap{max-width:1180px;margin:24px auto;padding:0 20px}.panel{background:#fff;border:1px solid #e3e6ea;padding:20px;margin-bottom:20px}h2{margin:0 0 14px}label{display:block;margin:10px 0 4px}input,textarea,select{width:100%;box-sizing:border-box;padding:8px;border:1px solid #ccd2d8}textarea{min-height:100px}button{padding:8px 14px;margin-top:12px}table{width:100%;border-collapse:collapse}td,th{border-bottom:1px solid #e6e8eb;text-align:left;padding:8px;vertical-align:top}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}.danger{color:#b00}@media(max-width:700px){.grid{grid-template-columns:1fr}}</style><div class="top"><strong>通用 CMS 管理后台</strong><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="logout"><button>退出</button></form></div><div class="wrap"><p><?=isset($_GET['saved'])?'已保存。':''?> 每个网站可以复制同一套 CMS 核心，前台主题独立部署。</p>
<section class="panel"><h2>站点设置</h2><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="settings"><div class="grid"><?php foreach($settings as $key): ?><label><?=e($key)?><input name="settings[<?=e($key)?>]" value="<?=e(site_setting($key))?>"></label><?php endforeach; ?></div><button>保存站点设置</button></form></section>
<section class="panel"><h2>新增或更新栏目</h2><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="category"><div class="grid"><label>名称<input name="name" required></label><label>slug<input name="slug" required></label><label>父级 ID<input name="parent_id" value="0" type="number"></label><label>排序<input name="sort_order" value="0" type="number"></label></div><button>保存栏目</button></form><table><tr><th>ID</th><th>名称</th><th>slug</th><th>操作</th></tr><?php foreach($cats as $cat): ?><tr><td><?=e((string)$cat['id'])?></td><td><?=e($cat['name'])?></td><td><?=e($cat['slug'])?></td><td><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete"><input type="hidden" name="table" value="categories"><input type="hidden" name="id" value="<?=e((string)$cat['id'])?>"><button class="danger">删除</button></form></td></tr><?php endforeach; ?></table></section>
<section class="panel"><h2>新增或更新文章</h2><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="article"><div class="grid"><label>栏目 ID<input name="category_id" value="0" type="number"></label><label>标题<input name="title" required></label><label>slug<input name="slug" required></label><label>封面图 URL<input name="cover_image"></label><label>发布时间<input name="published_at" type="datetime-local"></label><label>排序<input name="sort_order" value="0" type="number"></label></div><label>摘要<textarea name="summary"></textarea></label><label>正文<textarea name="content" required></textarea></label><label><input name="published" type="checkbox" checked> 发布</label><button>保存文章</button></form><table><tr><th>ID</th><th>标题</th><th>slug</th><th>操作</th></tr><?php foreach($articles as $row): ?><tr><td><?=e((string)$row['id'])?></td><td><?=e($row['title'])?></td><td><?=e($row['slug'])?></td><td><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete"><input type="hidden" name="table" value="articles"><input type="hidden" name="id" value="<?=e((string)$row['id'])?>"><button class="danger">删除</button></form></td></tr><?php endforeach; ?></table></section>
<section class="panel"><h2>轮播图</h2><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="slide"><div class="grid"><label>标题<input name="title" required></label><label>图片 URL<input name="image_url" required></label><label>链接<input name="link_url"></label><label>排序<input name="sort_order" value="0" type="number"></label></div><label><input name="enabled" type="checkbox" checked> 启用</label><button>保存轮播图</button></form><table><tr><th>标题</th><th>图片</th><th>操作</th></tr><?php foreach($slides as $row): ?><tr><td><?=e($row['title'])?></td><td><?=e($row['image_url'])?></td><td><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete"><input type="hidden" name="table" value="slides"><input type="hidden" name="id" value="<?=e((string)$row['id'])?>"><button class="danger">删除</button></form></td></tr><?php endforeach; ?></table></section>
<section class="panel"><h2>友情链接</h2><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="link"><div class="grid"><label>名称<input name="name" required></label><label>网址<input name="url" required></label><label>Logo URL<input name="logo_url"></label><label>排序<input name="sort_order" value="0" type="number"></label></div><label><input name="enabled" type="checkbox" checked> 启用</label><button>保存友情链接</button></form><table><tr><th>名称</th><th>网址</th><th>操作</th></tr><?php foreach($links as $row): ?><tr><td><?=e($row['name'])?></td><td><?=e($row['url'])?></td><td><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete"><input type="hidden" name="table" value="links"><input type="hidden" name="id" value="<?=e((string)$row['id'])?>"><button class="danger">删除</button></form></td></tr><?php endforeach; ?></table></section>
<section class="panel"><h2>媒体库</h2><form method="post" enctype="multipart/form-data"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="upload_media"><input type="file" name="media" accept="image/jpeg,image/png,image/gif,image/webp" required><button>上传图片</button></form><table><tr><th>原文件名</th><th>URL</th><th>大小</th></tr><?php foreach($media as $row): ?><tr><td><?=e($row['original_name'])?></td><td><?=e('uploads/' . $row['file_name'])?></td><td><?=e((string)$row['file_size'])?> bytes</td></tr><?php endforeach; ?></table></section>
</div></html>
