[FÁZE-1][config] Přidán konfigurační soubor systému přihlašování
[FÁZE-1][db] Přidáno připojení k databázi přes PDO [FÁZE-1][install] Přidán instalační skript s tvorbou tabulek a prvního admina
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
// ============================================================
|
||||
// INSTALAČNÍ SKRIPT
|
||||
// ============================================================
|
||||
// Tento skript spusť JEDNOU po nahrání souborů na server.
|
||||
// Vytvoří všechny potřebné tabulky v databázi a prvního
|
||||
// administrátora.
|
||||
//
|
||||
// Po úspěšné instalaci se vytvoří soubor install.lock
|
||||
// a tento skript již nepůjde spustit znovu.
|
||||
//
|
||||
// BEZPEČNOST: Po instalaci můžeš install.php smazat,
|
||||
// nebo ho nechat – install.lock ho zablokuje.
|
||||
// ============================================================
|
||||
|
||||
require_once __DIR__ . '/config.php';
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// KONTROLA: Proběhla už instalace?
|
||||
// ------------------------------------------------------------
|
||||
|
||||
$lock_soubor = __DIR__ . '/install.lock';
|
||||
|
||||
if (file_exists($lock_soubor)) {
|
||||
die('<p>Instalace již proběhla. Pokud chceš instalaci opakovat, smaž soubor <code>auth/install.lock</code>. Pozor – tím přijdeš o všechna data!</p>');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// ZPRACOVÁNÍ FORMULÁŘE (pokud byl odeslán)
|
||||
// ------------------------------------------------------------
|
||||
|
||||
$chyba = '';
|
||||
$uspech = false;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Načtení hodnot z formuláře
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$heslo = $_POST['heslo'] ?? '';
|
||||
$heslo2 = $_POST['heslo2'] ?? '';
|
||||
|
||||
// Základní validace emailu
|
||||
if (empty($email)) {
|
||||
$chyba = 'Email nesmí být prázdný.';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$chyba = 'Email není platná emailová adresa.';
|
||||
}
|
||||
|
||||
// Validace hesla
|
||||
if (empty($chyba) && empty($heslo)) {
|
||||
$chyba = 'Heslo nesmí být prázdné.';
|
||||
} elseif (empty($chyba) && mb_strlen($heslo) < HESLO_MIN_DELKA) {
|
||||
$chyba = 'Heslo musí mít alespoň ' . HESLO_MIN_DELKA . ' znaků.';
|
||||
} elseif (empty($chyba) && $heslo !== $heslo2) {
|
||||
$chyba = 'Hesla se neshodují.';
|
||||
}
|
||||
|
||||
// Pokud není chyba, spustíme instalaci
|
||||
if (empty($chyba)) {
|
||||
|
||||
try {
|
||||
|
||||
// ------------------------------------------------
|
||||
// VYTVOŘENÍ TABULEK
|
||||
// ------------------------------------------------
|
||||
|
||||
// Tabulka uživatelů přihlašovacího systému
|
||||
// utf8mb4 = plná podpora Unicode (diakritika, emoji)
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `" . DB_TABULKA_UZIVATELE . "` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`heslo` VARCHAR(255) NOT NULL,
|
||||
`admin` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`vytvoreno` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
|
||||
// Tabulka remember me tokenů
|
||||
// selector = veřejný identifikátor pro vyhledání záznamu v DB
|
||||
// token_hash = bcrypt hash tajného tokenu (samotný token je jen v cookie)
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `" . DB_TABULKA_TOKENY . "` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`uzivatel_id` INT UNSIGNED NOT NULL,
|
||||
`selector` VARCHAR(32) NOT NULL,
|
||||
`token_hash` VARCHAR(255) NOT NULL,
|
||||
`expiruje` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `selector` (`selector`),
|
||||
FOREIGN KEY (`uzivatel_id`) REFERENCES `" . DB_TABULKA_UZIVATELE . "` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
|
||||
// Tabulka brute force záznamů
|
||||
// Ukládají se neúspěšné pokusy o přihlášení
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `" . DB_TABULKA_BRUTE . "` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ip_adresa` VARCHAR(45) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`cas` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ip_adresa` (`ip_adresa`),
|
||||
KEY `email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
|
||||
// Tabulka tokenů pro obnovu hesla
|
||||
// Token je platný jen omezenou dobu (viz config.php)
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `" . DB_TABULKA_RESET . "` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`uzivatel_id` INT UNSIGNED NOT NULL,
|
||||
`token_hash` VARCHAR(255) NOT NULL,
|
||||
`expiruje` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
FOREIGN KEY (`uzivatel_id`) REFERENCES `" . DB_TABULKA_UZIVATELE . "` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
|
||||
// Tabulka uživatelů konkrétní služby (pokud je nastavena)
|
||||
// Tato tabulka slouží pro data specifická pro tvůj projekt
|
||||
// (jméno, nastavení, kontaktní údaje apod.)
|
||||
if (DB_TABULKA_SLUZBA !== '') {
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `" . DB_TABULKA_SLUZBA . "` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`uzivatel_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uzivatel_id` (`uzivatel_id`),
|
||||
FOREIGN KEY (`uzivatel_id`) REFERENCES `" . DB_TABULKA_UZIVATELE . "` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// VYTVOŘENÍ PRVNÍHO ADMIN UŽIVATELE
|
||||
// ------------------------------------------------
|
||||
|
||||
$heslo_hash = password_hash($heslo, PASSWORD_DEFAULT);
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO `" . DB_TABULKA_UZIVATELE . "`
|
||||
(`email`, `heslo`, `admin`)
|
||||
VALUES
|
||||
(:email, :heslo, 1)
|
||||
");
|
||||
$stmt->execute([
|
||||
':email' => $email,
|
||||
':heslo' => $heslo_hash,
|
||||
]);
|
||||
|
||||
$novy_uzivatel_id = $pdo->lastInsertId();
|
||||
|
||||
// Pokud existuje tabulka služby, vytvoříme prázdný řádek
|
||||
if (DB_TABULKA_SLUZBA !== '') {
|
||||
$stmt2 = $pdo->prepare("
|
||||
INSERT INTO `" . DB_TABULKA_SLUZBA . "`
|
||||
(`uzivatel_id`)
|
||||
VALUES
|
||||
(:uzivatel_id)
|
||||
");
|
||||
$stmt2->execute([':uzivatel_id' => $novy_uzivatel_id]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// VYTVOŘENÍ ZÁMKU – zabránění opakované instalaci
|
||||
// ------------------------------------------------
|
||||
|
||||
file_put_contents($lock_soubor, 'Instalace proběhla: ' . date('Y-m-d H:i:s'));
|
||||
|
||||
$uspech = true;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Chybu zalogujeme, uživateli zobrazíme obecnou hlášku
|
||||
error_log('Chyba při instalaci: ' . $e->getMessage());
|
||||
$chyba = 'Při instalaci došlo k chybě databáze. Zkontroluj nastavení v config.php a PHP error log.';
|
||||
} catch (Exception $e) {
|
||||
error_log('Chyba při instalaci: ' . $e->getMessage());
|
||||
$chyba = 'Při instalaci došlo k neočekávané chybě.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// HTML VÝSTUP
|
||||
// ------------------------------------------------------------
|
||||
// Poznámka: žádné stylování – vše je záměrně prosté,
|
||||
// aby žádný prvek nebyl skrytý nebo překrytý.
|
||||
// ------------------------------------------------------------
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Instalace – <?php echo htmlspecialchars(PROJEKT_NAZEV); ?></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Instalace systému přihlašování</h1>
|
||||
<h2><?php echo htmlspecialchars(PROJEKT_NAZEV); ?></h2>
|
||||
|
||||
<?php if ($uspech): ?>
|
||||
|
||||
<p><strong>Instalace proběhla úspěšně!</strong></p>
|
||||
<p>Tabulky byly vytvořeny a první administrátor byl založen.</p>
|
||||
<p>Byl vytvořen soubor <code>auth/install.lock</code> – instalaci již nelze spustit znovu.</p>
|
||||
<p><a href="<?php echo htmlspecialchars(AUTH_LOGIN_URL); ?>">Přejít na přihlášení</a></p>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<p>Tento skript vytvoří potřebné tabulky v databázi a založí prvního administrátora.</p>
|
||||
<p>Spusť ho pouze jednou. Po instalaci bude zablokován souborem <code>install.lock</code>.</p>
|
||||
|
||||
<?php if (!empty($chyba)): ?>
|
||||
<p><strong>Chyba: <?php echo htmlspecialchars($chyba); ?></strong></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="">
|
||||
|
||||
<p>
|
||||
<label for="email">Email administrátora:</label><br>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>"
|
||||
required
|
||||
>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="heslo">Heslo administrátora:</label><br>
|
||||
<input
|
||||
type="password"
|
||||
id="heslo"
|
||||
name="heslo"
|
||||
required
|
||||
>
|
||||
<br>
|
||||
<!-- Indikátor síly hesla – vyplní ho zxcvbn přes JavaScript -->
|
||||
<span id="heslo-sila">Síla hesla: zadej heslo</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="heslo2">Heslo znovu (pro ověření):</label><br>
|
||||
<input
|
||||
type="password"
|
||||
id="heslo2"
|
||||
name="heslo2"
|
||||
required
|
||||
>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<!-- Tlačítko je ve výchozím stavu zakázané.
|
||||
JavaScript ho povolí, až heslo dosáhne požadované síly. -->
|
||||
<button type="submit" id="tlacitko-odeslat" disabled>
|
||||
Spustit instalaci
|
||||
</button>
|
||||
<span id="tlacitko-duvod"> (čekám na dostatečně silné heslo)</span>
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ============================================================
|
||||
zxcvbn – knihovna pro hodnocení síly hesla od Dropboxu
|
||||
Načítáme z CDN. Pokud chceš offline použití, stáhni soubor
|
||||
a změň src na lokální cestu.
|
||||
============================================================ -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
|
||||
<script>
|
||||
// Minimální požadovaná síla hesla (přebíráme z PHP konfigurace)
|
||||
const MIN_SILA = <?php echo (int) HESLO_MIN_SILA; ?>;
|
||||
|
||||
// Popisky síly hesla (0 = nejslabší, 4 = nejsilnější)
|
||||
const POPISKY_SILY = [
|
||||
'Velmi slabé',
|
||||
'Slabé',
|
||||
'Průměrné',
|
||||
'Silné',
|
||||
'Velmi silné'
|
||||
];
|
||||
|
||||
const inputHeslo = document.getElementById('heslo');
|
||||
const spanSila = document.getElementById('heslo-sila');
|
||||
const tlacitko = document.getElementById('tlacitko-odeslat');
|
||||
const spanDuvod = document.getElementById('tlacitko-duvod');
|
||||
|
||||
inputHeslo.addEventListener('input', function () {
|
||||
const hodnota = this.value;
|
||||
|
||||
if (hodnota.length === 0) {
|
||||
spanSila.textContent = 'Síla hesla: zadej heslo';
|
||||
tlacitko.disabled = true;
|
||||
spanDuvod.textContent = ' (čekám na dostatečně silné heslo)';
|
||||
return;
|
||||
}
|
||||
|
||||
// Spuštění zxcvbn hodnocení
|
||||
const vysledek = zxcvbn(hodnota);
|
||||
const skore = vysledek.score; // 0–4
|
||||
|
||||
spanSila.textContent = 'Síla hesla: ' + POPISKY_SILY[skore] + ' (' + skore + '/4)';
|
||||
|
||||
if (skore >= MIN_SILA) {
|
||||
tlacitko.disabled = false;
|
||||
spanDuvod.textContent = '';
|
||||
} else {
|
||||
tlacitko.disabled = true;
|
||||
spanDuvod.textContent = ' (heslo je příliš slabé, potřebuji alespoň ' + MIN_SILA + '/4)';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user