From 47ae07946d6825fde1bd4b875d692aabb242f5e5 Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 17 Mar 2026 09:44:26 +0100 Subject: [PATCH] =?UTF-8?q?[F=C3=81ZE-1][install]=20V=C3=ADcekrokov=C3=BD?= =?UTF-8?q?=20pr=C5=AFb=C4=9Bh=20instalace=20pro=20omezen=C3=A1=20DB=20pr?= =?UTF-8?q?=C3=A1va=20(Wedos)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth/install.php | 453 +++++++++++++++++++++++++++++------------------ 1 file changed, 276 insertions(+), 177 deletions(-) diff --git a/auth/install.php b/auth/install.php index 5c2bde1..e40a0ae 100644 --- a/auth/install.php +++ b/auth/install.php @@ -6,11 +6,14 @@ // Vytvoří všechny potřebné tabulky v databázi a prvního // administrátora. // +// Průběh: +// Krok 1 – pokus o automatické vytvoření tabulek +// Krok 2 – pokud selže, zobrazí SQL pro ruční zadání do phpMyAdmin +// Krok 3 – ověření, že tabulky existují a mají správnou strukturu +// Krok 4 – formulář pro vytvoření prvního admina + zámek +// // 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'; @@ -23,131 +26,187 @@ require_once __DIR__ . '/db.php'; $lock_soubor = __DIR__ . '/install.lock'; if (file_exists($lock_soubor)) { - die('

Instalace již proběhla. Pokud chceš instalaci opakovat, smaž soubor auth/install.lock. Pozor – tím přijdeš o všechna data!

'); + die(' + Instalace +

Instalace již proběhla.

+

Pokud chceš instalaci opakovat, smaž soubor + auth/install.lock. Pozor – tím přijdeš o všechna data!

+ '); } // ------------------------------------------------------------ -// ZPRACOVÁNÍ FORMULÁŘE (pokud byl odeslán) +// SQL PŘÍKAZY PRO VYTVOŘENÍ TABULEK +// ------------------------------------------------------------ +// Definujeme je jako pole – použijeme je jak pro automatické +// spuštění, tak pro zobrazení uživateli k ručnímu zadání. + +$sql_tabulky = [ + + 'auth_users' => "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", + + 'auth_remember_tokens' => "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", + + 'auth_brute_force' => "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", + + 'auth_password_resets' => "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 služby je volitelná +if (DB_TABULKA_SLUZBA !== '') { + $sql_tabulky['sluzba'] = "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"; +} + +// ------------------------------------------------------------ +// POMOCNÁ FUNKCE: Ověření existence tabulek +// ------------------------------------------------------------ +// Zkontroluje, zda všechny potřebné tabulky existují v DB. +// Vrací pole chybějících tabulek (prázdné = vše OK). + +function zkontroluj_tabulky(PDO $pdo): array +{ + // Zjistíme, které tabulky existují v aktuální databázi + $stmt = $pdo->query("SHOW TABLES"); + $existuje = $stmt->fetchAll(PDO::FETCH_COLUMN); + + $potrebne = [ + DB_TABULKA_UZIVATELE, + DB_TABULKA_TOKENY, + DB_TABULKA_BRUTE, + DB_TABULKA_RESET, + ]; + + if (DB_TABULKA_SLUZBA !== '') { + $potrebne[] = DB_TABULKA_SLUZBA; + } + + // Vrátíme seznam tabulek, které chybí + return array_diff($potrebne, $existuje); +} + +// ------------------------------------------------------------ +// URČENÍ AKTUÁLNÍHO KROKU // ------------------------------------------------------------ -$chyba = ''; -$uspech = false; +$krok = 1; // výchozí krok +$chyba = ''; +$zprava = ''; -if ($_SERVER['REQUEST_METHOD'] === 'POST') { +// Krok se přenáší přes skryté pole ve formuláři +$krok_z_post = (int) ($_POST['krok'] ?? 0); + +// ------------------------------------------------------------ +// ZPRACOVÁNÍ AKCÍ +// ------------------------------------------------------------ + +// == KROK 1: Pokus o automatické vytvoření tabulek ============ +if ($krok_z_post === 0 || $krok_z_post === 1) { + + $auto_ok = true; + + foreach ($sql_tabulky as $nazev => $sql) { + try { + $pdo->exec($sql); + } catch (PDOException $e) { + // Automatické vytvoření selhalo – uživatel nemá práva + $auto_ok = false; + break; + } + } + + if ($auto_ok) { + // Tabulky byly vytvořeny automaticky – přeskočíme na krok 4 + $krok = 4; + } else { + // Nemáme práva – přejdeme na krok 2 (ruční SQL) + $krok = 2; + } +} + +// == KROK 3: Ověření tabulek po ručním zadání SQL ============= +elseif ($krok_z_post === 3) { + + $chybejici = zkontroluj_tabulky($pdo); + + if (empty($chybejici)) { + // Všechny tabulky existují – přejdeme na krok 4 + $krok = 4; + } else { + // Stále chybí tabulky – zůstaneme na kroku 2/3 + $krok = 3; + $chyba = 'Následující tabulky stále chybí: ' + . implode(', ', $chybejici) + . '. Zkontroluj, zda jsi SQL správně zadal do phpMyAdmin.'; + } +} + +// == KROK 4: Vytvoření prvního admina ========================= +elseif ($krok_z_post === 4) { - // Načtení hodnot z formuláře $email = trim($_POST['email'] ?? ''); $heslo = $_POST['heslo'] ?? ''; $heslo2 = $_POST['heslo2'] ?? ''; - // Validace emailu + // Validace 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)) { + } elseif (empty($heslo)) { $chyba = 'Heslo nesmí být prázdné.'; - } elseif (empty($chyba) && mb_strlen($heslo) < HESLO_MIN_DELKA) { + } elseif (mb_strlen($heslo) < HESLO_MIN_DELKA) { $chyba = 'Heslo musí mít alespoň ' . HESLO_MIN_DELKA . ' znaků.'; - } elseif (empty($chyba) && $heslo !== $heslo2) { + } elseif ($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í (IP adresa, email, čas) - $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 jednorázový a platí 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 v config.php) - // Tato tabulka slouží pro data specifická pro tvůj projekt. - // Zatím obsahuje jen vazbu na auth_users – sloupce si přidáš sám. - 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 zahashujeme pomocí bcrypt – nikdy neukládáme plaintext! $heslo_hash = password_hash($heslo, PASSWORD_DEFAULT); $stmt = $pdo->prepare(" @@ -161,9 +220,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ':heslo' => $heslo_hash, ]); - $novy_uzivatel_id = $pdo->lastInsertId(); + $novy_id = $pdo->lastInsertId(); - // Pokud existuje tabulka služby, vytvoříme k novému uživateli prázdný řádek if (DB_TABULKA_SLUZBA !== '') { $stmt2 = $pdo->prepare(" INSERT INTO `" . DB_TABULKA_SLUZBA . "` @@ -171,33 +229,34 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { VALUES (:uzivatel_id) "); - $stmt2->execute([':uzivatel_id' => $novy_uzivatel_id]); + $stmt2->execute([':uzivatel_id' => $novy_id]); } - // ------------------------------------------------ - // VYTVOŘENÍ ZÁMKU – zabránění opakované instalaci - // ------------------------------------------------ - + // Vytvoříme zámek – instalace je hotová file_put_contents($lock_soubor, 'Instalace proběhla: ' . date('Y-m-d H:i:s')); - $uspech = true; + $krok = 5; // krok 5 = úspěšné dokončení } 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ě.'; + error_log('Chyba při instalaci (admin): ' . $e->getMessage()); + $chyba = 'Při vytváření admina došlo k chybě databáze. Zkontroluj PHP error log.'; + $krok = 4; } + + } else { + // Validace selhala – zůstaneme na kroku 4 + $krok = 4; } } // ------------------------------------------------------------ -// HTML VÝSTUP +// SESTAVENÍ SQL TEXTU PRO ZOBRAZENÍ UŽIVATELI (krok 2) // ------------------------------------------------------------ -// Poznámka: žádné stylování – vše je záměrně prosté, -// aby žádný prvek nebyl skrytý nebo překrytý. + +$sql_pro_zobrazeni = implode(";\n\n", $sql_tabulky) . ';'; + +// ------------------------------------------------------------ +// HTML VÝSTUP // ------------------------------------------------------------ ?> @@ -211,23 +270,70 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

Instalace systému přihlašování

- + +

Chyba:

+ -

Instalace proběhla úspěšně!

-

Tabulky byly vytvořeny a první administrátor byl založen.

-

Byl vytvořen soubor auth/install.lock – instalaci již nelze spustit znovu.

-

Přejít na přihlášení

+ - +

Nepodařilo se automaticky vytvořit tabulky v databázi – + pravděpodobně nemá databázový uživatel dostatečná oprávnění + (CREATE TABLE).

-

Tento skript vytvoří potřebné tabulky v databázi a založí prvního administrátora.

-

Spusť ho pouze jednou. Po instalaci bude zablokován souborem install.lock.

+

Postup:

+
    +
  1. Zkopíruj SQL níže.
  2. +
  3. Otevři phpMyAdmin a vyber svou databázi + ().
  4. +
  5. Klikni na záložku SQL, vlož SQL a spusť ho.
  6. +
  7. Vrať se sem a klikni na tlačítko níže.
  8. +
- -

Chyba:

- + + +

+

+ + +
+

+ + + +

Tabulky ještě nejsou v pořádku. Zkontroluj phpMyAdmin a zkus to znovu.

+ + + +

+

+ + +
+

+ + + +

Tabulky jsou připraveny. + Nyní vytvoř prvního administrátora.

+


@@ -249,7 +355,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { required >
- Síla hesla: zadej heslo

@@ -264,66 +369,60 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

- (čekám na dostatečně silné heslo)

+ + +

Instalace proběhla úspěšně!

+

Tabulky byly vytvořeny a první administrátor byl založen.

+

Byl vytvořen soubor auth/install.lock – + instalaci již nelze spustit znovu.

+

Přejít na přihlášení

+ -