Przejdź do głównej treści
INF.03-08-25.06-SGCzerwiec 2025 · 50 kroków · ok. 96 min · 41 kryteriów z klucza

Rozwiązanie krok po kroku: Portal hobbystyczny o smokach (Nowoczesny kod (grid, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza smoki z czterema zapytaniami, przeskalowana grafika, strona smoki.php z przełączanymi sekcjami, listą krajów i tabelą smoków - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • siatka CSS z nazwanymi obszarami na <body> zamiast float i clear, selektory strukturalne zamiast identyfikatorów (.block:first-child, section + section),
  • JavaScript bez atrybutów onclick: querySelectorAll, forEach, addEventListener, numer sekcji w atrybucie data-section, obsługa klawiatury i skrypt ładowany z defer,
  • PHP na PDO: zapytania na początku pliku, biała lista kraju (tylko kraje z bazy), zapytanie przygotowane, funkcja e() przy każdym wypisaniu i dane logowania w config.php.

Tam, gdzie klucz wymaga konkretnej formy - JavaScript zmienia styl bloków przez style.backgroundColor i style.display - ta forma zostaje, a krok mówi dlaczego. Na końcu krótkie porównanie z wersją podstawową (zakładka obok).

Grafiki, opisy i baza pochodzą z prawdziwego archiwum pliki7 (załącznik na stronie arkusza), a podgląd kroków z PHP to wynik prawdziwego uruchomienia strony na serwerze z tą bazą.

Jak liczą się punkty. Klucz ma 41 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania to 75%, czyli 31 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.

  1. Etap 1: Baza danych

    Kroki 1-7 · po tym etapie masz 6 z 41 kryteriów (pkt)

    Krok 1: Baza danych smoki

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie smoki, z zestawem polskich znaków (np. utf8_polish_ci).

    phpMyAdmin → Nowa → nazwa smoki, porównywanie utf8_polish_ci. W SQL:

    CREATE DATABASE smoki CHARACTER SET utf8 COLLATE utf8_polish_ci;
    
    Typowe błędy

    Smoki albo smok zamiast smoki odcina też punkty za skrypty - połączenie podaje nazwę bazy.

  2. Krok 2: Import tabel z pliku bazasmoki.sql

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabele z pliku bazasmoki.sql do utworzonej bazy.

    Zaznacz bazę smoki, karta Import, plik bazasmoki.sql, Wykonaj. Trzy tabele z ilustracji 1: smok (44), parada (48) i łącząca je udzial (127) - relacja wiele do wielu.

  3. Krok 3: Zrzut ekranu import.jpg

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie JPEG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.

    Cały ekran z paskiem zadań, zapis jako import.jpg. Zrzuty zapytań w tym arkuszu są w PNG.

    Typowe błędy

    Wykadrowany zrzut nie jest oceniany.

  4. Krok 4: Zapytanie 1: smoki z Polski

    Kryteria: ,

    R.1.2 Zapisany plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające jedynie nazwę, długość i szerokość smoka, dla smoków z Polski. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska"; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dokładnie 23 rekordy zawierające jedynie pola nazwa, dlugosc, szerokosc

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie nazwę, długość i szerokość smoka, dla smoków z Polski.

    Każda klauzula w osobnej linii, napis w apostrofach (standard SQL). Wynik: 23 smoki, trzy kolumny (R.1.3); zapytanie do kwerendy.txt, zrzut kw1.png.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa, dlugosc, szerokosc
    FROM smok
    WHERE pochodzenie = 'Polska';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: kraje pochodzenia bez powtórzeń

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające niepowtarzające się kraje pochodzenia smoków, posortowane rosnąco według nazwy kraju pochodzenia. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie; (opcjonalnie ASC; możliwe też GROUP BY, wtedy ORDER BY opcjonalne) oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dane: Bułgaria, Chiny, Francja, Japonia, Polska

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające niepowtarzające się kraje pochodzenia smoków, posortowane rosnąco według kraju pochodzenia.

    DISTINCT i jawne ASC. Wynik: Bułgaria, Chiny, Francja, Japonia, Polska (R.1.4), zrzut kw2.png. Ta lista wypełni listę rozwijaną i będzie białą listą krajów w skrypcie 2.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT nazwa, dlugosc, szerokosc
    FROM smok
    WHERE pochodzenie = 'Polska';
    
    -- Zapytanie 2
    SELECT DISTINCT pochodzenie
    FROM smok
    ORDER BY pochodzenie ASC;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: średnia długość smoków w paradach po 2005 roku

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające jedynie rok z tabeli parada i odpowiadającą mu średnią wartość długości z tabeli smok nazwaną (alias) „Średnia długość” tylko dla lat po 2005 roku. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT rok, AVG(dlugosc) AS "Średnia długość" FROM parada JOIN udzial ON parada.id = id_parada JOIN smok ON id_smok = smok.id WHERE rok > 2005 GROUP BY rok; (możliwe INNER JOIN lub porównanie kluczy po WHERE; AS opcjonalne) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest 5 rekordów: 2006 4.6; 2013 7.6; 2014 5.5; 2021 7.625; 2025 6.4091 (dowolne zaokrąglenie)

    ok. 5 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie rok z tabeli parada i obliczającą odpowiadającą mu średnią wartość długości z tabeli smok, nazwa kolumny (alias) „Średnia długość” tylko dla lat po 2005 roku. Należy posłużyć się relacją i zgrupować rekordy względem roku.

    Trzy tabele z krótkimi aliasami (p, u, s): parada → wpisy w tabeli łączącej → smoki. Każdy warunek ON łączy klucz obcy z kluczem głównym, a przedrostki (p.rok, s.dlugosc) mówią, skąd jest kolumna - w tej bazie trzy tabele mają kolumnę id, więc bez przedrostków zapytanie byłoby niejednoznaczne.

    Alias ze spacją w odwrotnych apostrofach `Średnia długość` - właściwy w MySQL znak dla nazw. WHERE p.rok > 2005 odcina lata przed grupowaniem, GROUP BY p.rok liczy średnią dla każdego roku, a ORDER BY p.rok ustala kolejność wprost.

    Wynik: 2006 4,6; 2013 7,6; 2014 5,5; 2021 7,625; 2025 6,4091 (R.1.5), zrzut kw3.png.

    Typowe błędy

    HAVING p.rok > 2005 też zadziała, ale warunek na zwykłej kolumnie należy do WHERE - HAVING jest dla warunków na wynikach funkcji grupujących.

    kwerendy.txt Tekst zmienione: 9 linii
    -- Zapytanie 1
    SELECT nazwa, dlugosc, szerokosc
    FROM smok
    WHERE pochodzenie = 'Polska';
    
    -- Zapytanie 2
    SELECT DISTINCT pochodzenie
    FROM smok
    ORDER BY pochodzenie ASC;
    
    -- Zapytanie 3
    SELECT p.rok, AVG(s.dlugosc) AS `Średnia długość`
    FROM parada AS p
    JOIN udzial AS u ON u.id_parada = p.id
    JOIN smok AS s ON s.id = u.id_smok
    WHERE p.rok > 2005
    GROUP BY p.rok
    ORDER BY p.rok;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowa kolumna w tabeli parada

    Kryteria:

    R.1.6 Wykonane zapytanie 4 zmieniające strukturę tabeli parada, przez wstawienie nowej kolumny lokalizacja typu napisowego o maksymalnej długości 100 znaków. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE parada ADD COLUMN lokalizacja VARCHAR(100); oraz wynik działania zapytania udokumentowany zrzutem, na którym jest komunikat o pomyślnie wykonanym zapytaniu lub zmieniona struktura tabeli

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: zmieniające strukturę tabeli parada, przez wstawienie nowej kolumny lokalizacja typu napisowego o maksymalnej długości 100 znaków.

    ALTER TABLE … ADD COLUMN zmienia strukturę; „maksymalna długość” to VARCHAR(100) (R.1.6), zrzut kw4.png.

    Typowe błędy

    CHAR(100) ma stałą długość - arkusz mówi o maksymalnej.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT nazwa, dlugosc, szerokosc
    FROM smok
    WHERE pochodzenie = 'Polska';
    
    -- Zapytanie 2
    SELECT DISTINCT pochodzenie
    FROM smok
    ORDER BY pochodzenie ASC;
    
    -- Zapytanie 3
    SELECT p.rok, AVG(s.dlugosc) AS `Średnia długość`
    FROM parada AS p
    JOIN udzial AS u ON u.id_parada = p.id
    JOIN smok AS s ON s.id = u.id_smok
    WHERE p.rok > 2005
    GROUP BY p.rok
    ORDER BY p.rok;
    
    -- Zapytanie 4
    ALTER TABLE parada
    ADD COLUMN lokalizacja VARCHAR(100);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-26 · po tym etapie masz 19 z 41 kryteriów (pkt)

    Krok 8: Przeskalowanie grafiki smok1.jpg

    Kryteria:

    R.2.1 Grafika smok1.jpg przeskalowana z zachowaniem proporcji do wysokości 300 px , odpowiadająca temu szerokość wynosi 448 (±5 px)

    ok. 3 min
    Polecenie z arkusza

    Cechy grafiki smok1.jpg: przeskalowana z zachowaniem proporcji do wysokości 300 px.

    smok1.jpg ma 3872 × 2592 px (2,6 MB). Skaluj obraz do wysokości 300 px przy zamkniętym łańcuchu - szerokość 448 px (R.2.1). Plik zmniejsza się do kilkudziesięciu kilobajtów, więc strona ładuje się szybciej.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik smoki.php w HTML5

    Kryteria:

    R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"

    ok. 1 min
    Polecenie z arkusza

    Składa się ze strony o nazwie smoki.php. Zapisana w języku HTML5.

    Plik smoki.php w folderze zdającego. <!DOCTYPE html> włącza tryb standardów HTML5, dalej szkielet: <html>, <head> i <body>. Rozszerzenie .php, bo na początku pliku stanie kod PHP.

    smoki.php PHP nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  10. Krok 10: Język strony

    Kryteria:

    R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    lang="pl" w <html> - czytnik ekranu czyta polską wymową, przeglądarka dobiera słownik i dzielenie wyrazów.

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  11. Krok 11: Kodowanie polskich znaków

    Kryteria:

    R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"

    ok. 1 min
    Polecenie z arkusza

    Jawnie zastosowany właściwy standard kodowania polskich znaków.

    <meta charset="UTF-8"> jako pierwszy element <head>. Ten sam standard ustawi połączenie z bazą (charset=utf8mb4 w PDO), więc polskie litery przejdą bez zmian całą drogę: baza → PHP → przeglądarka.

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  12. Krok 12: Tytuł strony

    Kryteria:

    R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „Smoki”.

    <title>Smoki</title> - napis na karcie przeglądarki. Obok <meta name="viewport">: bez niego telefon pokazałby stronę pomniejszoną jak na monitorze. Arkusz tego nie wymaga, a w każdym współczesnym szablonie ta linia jest.

    smoki.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  13. Krok 13: Podpięcie arkusza stylów

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza (nie dotyczy stylów ustawianych skryptem JS)

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony.

    <link rel="stylesheet" href="styl.css"> - nazwa dokładnie z arkusza. Cały wygląd będzie w tym pliku, w HTML nie ma ani jednego atrybutu style.

    Typowe błędy

    Zła nazwa w href to brak stylów, a wtedy cały rezultat R.4 przepada.

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  14. Krok 14: Bloki semantyczne

    Kryteria:

    R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header, nav, main, footer

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3.

    Cztery znaczniki z klucza R.2.3: <header>, <nav>, <main>, <footer>. Nawigację i blok główny postawi obok siebie siatka w CSS.

    Typowe błędy

    Zwykłe <div> z identyfikatorami wyglądają tak samo, ale R.2.3 wymaga znaczników semantycznych.

    smoki.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <nav>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  15. Krok 15: Nagłówek strony

    Kryteria:

    R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: nagłówek drugiego stopnia o treści „Poznaj smoki!”.

    <h2> - drugiego stopnia, jak w arkuszu (R.2.5).

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  16. Krok 16: Blok 1 „Baza” w nawigacji

    Kryteria:

    R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku nawigacyjnego to trzy bloki: blok 1 z treścią „Baza”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.

    Blok to <div> z klasą block - wspólną dla trzech bloków. Zamiast identyfikatora block1 blok niesie atrybut danych data-section="1": numer sekcji, którą ma pokazać. Atrybuty data-* są w HTML5 przeznaczone właśnie na takie informacje dla skryptu, a JavaScript odczyta je jako block.dataset.section.

    Dwa atrybuty dla dostępności: role="button" mówi czytnikowi ekranu, że to przycisk, a tabindex="0" pozwala dojść do bloku klawiszem Tab. Zwykły <div> nie jest ani jednym, ani drugim - a klikalny element musi działać też bez myszy.

    Typowe błędy

    <button> byłby tu najwłaściwszym znacznikiem, ale arkusz każe stylować listę i „przycisk” formularza regułą z marginesem 20 px - selektor button objąłby wtedy także bloki nawigacji. Dlatego <div> z role="button".

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  17. Krok 17: Bloki 2 „Opisy” i 3 „Galeria”

    Kryteria:

    R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)

    ok. 1 min
    Polecenie z arkusza

    Blok 2 z treścią „Opisy”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript. Blok 3 z treścią „Galeria”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.

    Ten sam wzorzec z data-section="2" i "3". W nawigacji są trzy bloki (R.2.4).

    smoki.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  18. Krok 18: Sekcja 1 z nagłówkiem

    Kryteria: ,

    R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)

    R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego to trzy sekcje (w jednym momencie jest widoczna tylko jedna sekcja). Sekcja 1: nagłówek trzeciego stopnia o treści „Baza Smoków”.

    <section> z <h3>. Sekcje nie dostają identyfikatorów: skrypt znajdzie je po kolejności w <main>, a CSS ukryje drugą i trzecią selektorem strukturalnym (R.2.4, R.2.5).

    smoki.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  19. Krok 19: Formularz

    Kryteria:

    R.3.3 Formularz wysyła dane metodą POST do tego samego pliku (poprawne również bez atrybutu action)

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyłający dane do tego samego pliku metodą bezpieczną, z elementami: lista rozwijana, przycisk.

    method="post" bez action - dane w treści żądania, na adres bieżącej strony (R.3.3).

    Typowe błędy

    Brak method to GET - skrypt czytający dane POST nic nie dostanie.

    smoki.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  20. Krok 20: Lista rozwijana

    Kryteria:

    R.2.10 Na stronie umieszczony formularz z listą rozwijaną i przyciskiem, zastosowano znaczniki <select> i <option>

    ok. 1 min
    Polecenie z arkusza

    Lista rozwijana wypełniona przez skrypt 1.

    name="country" - klucz w danych POST. Arkusz nie przewiduje etykiety, więc aria-label="Kraj pochodzenia" podpowiada czytnikowi ekranu, czego dotyczy lista. Opcje wstawi skrypt 1 (R.2.10).

    Typowe błędy

    Lista bez name nie jest wysyłana z formularzem.

    smoki.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  21. Krok 21: Przycisk „Szukaj”

    Kryteria: ,

    R.2.10 Na stronie umieszczony formularz z listą rozwijaną i przyciskiem, zastosowano znaczniki <select> i <option>

    R.3.4 Przycisk realizuje funkcję wysłania danych z formularza (input lub button z typem submit lub button bez typu)

    ok. 1 min
    Polecenie z arkusza

    Przycisk „Szukaj”, wysyłający dane z formularza do skryptu 2.

    <button type="submit"> (R.2.10, R.3.4).

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  22. Krok 22: Tabela z wierszem nagłówkowym

    Kryteria: ,

    R.2.8 Na stronie umieszczona tabela o 3 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>

    R.2.9 Pierwszy wiersz tabeli zawiera komórki nagłówkowe zastosowano znaczniki <tr> i <th>

    ok. 2 min
    Polecenie z arkusza

    Tabela o trzech kolumnach. Pierwszy wiersz jest wierszem z komórkami nagłówkowymi: „Nazwa”, „Długość”, „Szerokość”. Kolejne wiersze są wypełnione przez skrypt 2.

    Wiersz z komórkami <th> w <thead>, a miejsce na wiersze skryptu 2 w <tbody> - przeglądarka i czytnik ekranu wiedzą, który wiersz jest nagłówkiem (R.2.8, R.2.9).

    smoki.php PHP zmienione: 11 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  23. Krok 23: Sekcja 2 z nagłówkiem

    Kryteria: ,

    R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)

    R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce

    ok. 1 min
    Polecenie z arkusza

    Sekcja 2: nagłówek trzeciego stopnia o treści „Opisy smoków”.

    Druga <section> z <h3> (R.2.4, R.2.5).

    smoki.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  24. Krok 24: Lista definicji z opisami smoków

    Kryteria:

    R.2.7 Na stronie umieszczona jedna lista definicji z trzema definicjami, zastosowane znaczniki <dl>, <dt>, <dd>, w <dt> umieszczone kolejno: Smok czerwony, Smok zielony, Smok niebieski

    ok. 3 min
    Polecenie z arkusza

    Lista definicji wypełniona danymi, które należy skopiować z pliku opis.txt. Nazwa smoka jest terminem, a pozostałe dane - opisem definicji, zgodnie z ilustracją 5.

    <dl> z parami <dt> (nazwa) i <dd> (opis), w kolejności: Smok czerwony, zielony, niebieski (R.2.7). Opisy skopiowane z opis.txt.

    Typowe błędy

    <ul> z pogrubioną nazwą wygląda podobnie, ale R.2.7 wymaga <dl>, <dt>, <dd>.

    smoki.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  25. Krok 25: Sekcja 3: galeria

    Kryteria: , ,

    R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)

    R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce

    R.2.6 Na stronie umieszczone trzy grafiki z tekstami alternatywnymi: smok1.jpg - "Smok czerwony", smok2.jpg - "Smok wielki", smok3.jpg - "Skrzydlaty łaciaty"

    ok. 2 min
    Polecenie z arkusza

    Sekcja 3: nagłówek trzeciego stopnia o treści „Galeria”. Obraz smok1.jpg z tekstem alternatywnym „Smok czerwony”. Obraz smok2.jpg z tekstem alternatywnym „Smok wielki”. Obraz smok3.jpg z tekstem alternatywnym „Skrzydlaty łaciaty”.

    Trzecia sekcja z <h3> i trzema obrazami; teksty alternatywne dokładnie z arkusza (R.2.4, R.2.5, R.2.6).

    smoki.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  26. Krok 26: Stopka z numerem zdającego

    Kryteria:

    R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: paragraf o treści „Stronę opracował: ”, dalej wstawiony numer zdającego.

    Tu nazwisko autora rozwiązania - na egzaminie wpisujesz swój numer zdającego (PESEL), bo tego sprawdza klucz R.2.5.

    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  27. Etap 3: Styl CSS

    Kroki 27-34 · po tym etapie masz 30 z 41 kryteriów (pkt)

    Krok 27: Plik styl.css: domyślne wyrównanie i krój

    Kryteria:

    R.4.1 Ustawione domyślnie dla wszystkich selektorów (*): wyrównanie tekstu do środka, krój czcionki Georgia

    ok. 1 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: wyrównanie tekstu do środka, krój czcionki Georgia.

    Selektor uniwersalny * (R.4.1).

    styl.css CSS nowy plik
    * {
        text-align: center;
        font-family: Georgia;
    }
    Podgląd strony po tym kroku (smoki.php)
  28. Krok 28: Nagłówek i stopka

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5

    R.4.3 Ustawiony kolor czcionki dla bloku nagłówkowego i stopki: MistyRose

    R.4.6 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego i stopki 10px oraz ustawione marginesy zewnętrzne (margin) dla listy rozwijanej i przycisku 20 px, auto dla tabeli

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloku nagłówkowego i stopki: kolor tła Tomato, kolor czcionki MistyRose, marginesy wewnętrzne 10 px.

    Jedna reguła dla dwóch bloków, margines wewnętrzny to padding (R.4.2, R.4.3, R.4.6).

    styl.css CSS zmienione: 7 linii
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    Podgląd strony po tym kroku (smoki.php)
  29. Krok 29: Układ bloków: siatka z nazwanymi obszarami

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (nie należy brać pod uwagę bloków wewnątrz bloków nawigacyjnego i głównego) (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position)

    ok. 3 min
    Polecenie z arkusza

    Dla bloku nawigacyjnego: szerokość 20%.

    Ilustracja 3 zapisana wprost jako plan: <body> staje się siatką o dwóch kolumnach 20% i 80%, a grid-template-areas rysuje wiersze - nagłówek na całą szerokość, nawigacja obok bloku głównego, stopka na całą szerokość. Każdy blok trafia do swojego obszaru przez grid-area.

    Szerokość nawigacji (20%) i bloku głównego (80%) jest zapisana raz, w grid-template-columns - klucz R.4.4 wymienia tę właściwość obok width. Stopka jest w osobnym wierszu siatki, więc nie potrzebuje clear (R.3.1).

    Typowe błędy

    Nazwa obszaru w grid-area musi być dokładnie taka jak w grid-template-areas - literówka stawia blok w dodatkowym, automatycznym wierszu pod siatką.

    styl.css CSS zmienione: 25 linii
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
    }
    Podgląd strony po tym kroku (smoki.php)
  30. Krok 30: Bloki 1, 2, 3 i wyróżniony blok 1

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5

    R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%

    R.4.7 Ustawiony dla bloku 1, 2, i 3 rozmiar czcionki 200% oraz dla selektora dt czcionka pogrubiona i pochylona

    ok. 2 min
    Polecenie z arkusza

    Dla bloku 1, bloku 2, bloku 3: kolor tła #FFAEA5, wysokość 170 px, rozmiar czcionki 200%. Jedynie dla bloku 1: kolor tła MistyRose.

    Wspólna klasa .block dla trzech bloków (R.4.2, R.4.4, R.4.7) i cursor: pointer - kursor „rączki” podpowiada, że blok da się kliknąć. Blok 1 bez identyfikatora: .block:first-child wybiera blok, który jest pierwszym dzieckiem swojego rodzica (<nav>). Reguła jest bardziej szczegółowa niż sama klasa (klasa + pseudoklasa), więc wygrywa i tło bloku 1 jest jasne.

    styl.css CSS zmienione: 11 linii
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
    }
    
    .block {
        background-color: #FFAEA5;
        height: 170px;
        font-size: 200%;
        cursor: pointer;
    }
    
    .block:first-child {
        background-color: MistyRose;
    }
    Podgląd strony po tym kroku (smoki.php)
  31. Krok 31: Blok główny: tło, wysokość, paski przewijania

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5

    R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%

    R.4.5 Ustawiony dla bloku głównego styl overflow: auto;

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła MistyRose, szerokość 80%, wysokość 510 px, paski przewijania widoczne tylko w przypadku przepełnienia zawartością.

    Do reguły main dochodzą tło, wysokość 510 px (trzy bloki po 170 px) i overflow: auto (R.4.2, R.4.4, R.4.5). Szerokość 80% ma już kolumna siatki.

    Typowe błędy

    overflow: scroll pokazuje paski zawsze.

    styl.css CSS zmienione: 3 linie
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
        background-color: MistyRose;
        height: 510px;
        overflow: auto;
    }
    
    footer {
        grid-area: footer;
    }
    
    .block {
        background-color: #FFAEA5;
        height: 170px;
        font-size: 200%;
        cursor: pointer;
    }
    
    .block:first-child {
        background-color: MistyRose;
    }
    Podgląd strony po tym kroku (smoki.php)
  32. Krok 32: Sekcje 2 i 3 ukryte na starcie

    Kryteria:

    R.4.8 Ustawiony dla sekcji 2 i 3 styl display: none;

    ok. 1 min
    Polecenie z arkusza

    Jedynie dla sekcji 2 i sekcji 3: sekcje są usunięte z DOM (patrz tabela 3).

    section + section to selektor sąsiada: „sekcja, przed którą stoi inna sekcja”. Pierwsza sekcja nie ma sekcji przed sobą, więc zostaje widoczna; druga i trzecia dostają display: none (R.4.8) - bez identyfikatorów. display: none (tabela 3 arkusza) usuwa element z układu strony.

    styl.css CSS zmienione: 4 linie
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
        background-color: MistyRose;
        height: 510px;
        overflow: auto;
    }
    
    footer {
        grid-area: footer;
    }
    
    .block {
        background-color: #FFAEA5;
        height: 170px;
        font-size: 200%;
        cursor: pointer;
    }
    
    .block:first-child {
        background-color: MistyRose;
    }
    
    section + section {
        display: none;
    }
    Podgląd strony po tym kroku (smoki.php)
  33. Krok 33: Tabela, lista rozwijana i przycisk

    Kryteria: , ,

    R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%

    R.4.6 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego i stopki 10px oraz ustawione marginesy zewnętrzne (margin) dla listy rozwijanej i przycisku 20 px, auto dla tabeli

    R.4.9 Ustawione dla tabeli obramowanie 1px dashed Indigo

    ok. 2 min
    Polecenie z arkusza

    Dla selektora tabeli: marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość 60%, obramowanie linią kreskowaną o szerokości 1 px i kolorze Indigo. Dla listy rozwijanej i przycisku: marginesy zewnętrzne 20 px.

    Selektor znacznika table (uwaga arkusza): wyśrodkowanie margin: auto, szerokość, border: 1px dashed Indigo (R.4.4, R.4.6, R.4.9). Lista i przycisk - margin: 20px (R.4.6).

    styl.css CSS zmienione: 11 linii
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
        background-color: MistyRose;
        height: 510px;
        overflow: auto;
    }
    
    footer {
        grid-area: footer;
    }
    
    .block {
        background-color: #FFAEA5;
        height: 170px;
        font-size: 200%;
        cursor: pointer;
    }
    
    .block:first-child {
        background-color: MistyRose;
    }
    
    section + section {
        display: none;
    }
    
    table {
        margin: auto;
        width: 60%;
        border: 1px dashed Indigo;
    }
    
    select,
    button {
        margin: 20px;
    }
    Podgląd strony po tym kroku (smoki.php)
  34. Krok 34: Terminy listy definicji

    Kryteria: ,

    R.4.7 Ustawiony dla bloku 1, 2, i 3 rozmiar czcionki 200% oraz dla selektora dt czcionka pogrubiona i pochylona

    R.4.10 W momencie gdy kursor znajdzie się na napisie: Smok czerwony lub Smok zielony, lub Smok niebieski jego rozmiar czcionki zmienia się na 180%

    ok. 1 min
    Polecenie z arkusza

    Dla selektora terminu w liście definicji (dt): czcionka pogrubiona i pochylona. W momencie gdy kursor znajdzie się na terminie w liście definicji jego rozmiar czcionki zmienia się na 180%.

    Selektor znacznika dt (uwaga arkusza) i dt:hover (R.4.7, R.4.10). Efekt widać po kliknięciu „Opisy”.

    styl.css CSS zmienione: 9 linii
    * {
        text-align: center;
        font-family: Georgia;
    }
    
    header,
    footer {
        background-color: Tomato;
        color: MistyRose;
        padding: 10px;
    }
    
    body {
        display: grid;
        grid-template-columns: 20% 80%;
        grid-template-areas:
            "header header"
            "nav    main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    nav {
        grid-area: nav;
    }
    
    main {
        grid-area: main;
        background-color: MistyRose;
        height: 510px;
        overflow: auto;
    }
    
    footer {
        grid-area: footer;
    }
    
    .block {
        background-color: #FFAEA5;
        height: 170px;
        font-size: 200%;
        cursor: pointer;
    }
    
    .block:first-child {
        background-color: MistyRose;
    }
    
    section + section {
        display: none;
    }
    
    table {
        margin: auto;
        width: 60%;
        border: 1px dashed Indigo;
    }
    
    select,
    button {
        margin: 20px;
    }
    
    dt {
        font-weight: bold;
        font-style: italic;
    }
    
    dt:hover {
        font-size: 180%;
    }
    Podgląd strony po tym kroku (smoki.php)
  35. Etap 4: JavaScript

    Kroki 35-39 · po tym etapie masz 36 z 41 kryteriów (pkt)

    Krok 35: Plik script.js: bloki i sekcje w stałych

    Kryteria:

    R.5.10 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 3 min
    Polecenie z arkusza

    Skrypt jest napisany w języku JavaScript. Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.

    Skrypt podpięty w <head> z atrybutem defer: przeglądarka pobiera go równolegle ze stroną, a uruchamia dopiero po wczytaniu całego HTML-u - wszystkie bloki i sekcje już istnieją. To samo daje skrypt na końcu <body>, ale defer trzyma wszystkie odwołania w jednym miejscu, w <head>.

    Dwie stałe (const - nie zostaną przypisane drugi raz):

    • document.querySelectorAll('.block') - wszystkie elementy z klasą block, czyli trzy bloki nawigacji (selektor jak w CSS),
    • document.querySelectorAll('main section') - trzy sekcje bloku głównego, w kolejności z HTML.
    Typowe błędy

    <script src="script.js"> w <head> bez defer uruchomi się przed powstaniem bloków - querySelectorAll zwróci pustą listę i kliknięcia nic nie zrobią.

    script.js JavaScript nowy plik
    const blocks = document.querySelectorAll('.block');
    const sections = document.querySelectorAll('main section');
    smoki.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  36. Krok 36: Funkcja showSection: kolory bloków

    Kryteria: ,

    R.5.6 Skrypt JS zawiera przynajmniej jedną funkcję oraz przynajmniej dla jednego bloku stosuje metody obiektu document aby modyfikować jego styl np. document.getElementById('prawy1').style.display = "block"; document.getElementById('lewy1').style.backgroundColor = "MistyRose";

    R.5.7 Po kliknięciu na blok lewy jego kolor tła zamienia się na MistyRose, kolor tła pozostałych bloków lewych na "#FFAEA5" (wystarczy że spełnione dla jednego bloku innego niż "Baza")

    ok. 3 min
    Polecenie z arkusza

    Gdy zostanie kliknięty Blok 1: kolor tła bloku 1 zmienia się na MistyRose, pozostałe na #FFAEA5.

    Jedna funkcja showSection(number) dla trzech bloków. forEach wykonuje funkcję strzałkową dla każdego bloku i podaje jego numer w liście (index - od zera, więc blok 1 ma index 0). Operator warunkowy warunek ? a : b wybiera kolor w jednej linii: kliknięty blok dostaje MistyRose, pozostałe #FFAEA5 - bez osobnego „zerowania” wszystkich bloków.

    Kolor zmienia się przez style.backgroundColor - to forma, którą podaje klucz (R.5.6: metody obiektu document modyfikujące styl). Przełączanie klasy CSS (classList.toggle) byłoby czystsze, ale nie zmienia stylu bloku wprost, więc tu zostaje style.

    Typowe błędy

    index === number (bez + 1) przesuwa wszystko o jeden: kliknięcie „Baza” rozjaśniłoby „Opisy”.

    script.js JavaScript zmienione: 6 linii
    const blocks = document.querySelectorAll('.block');
    const sections = document.querySelectorAll('main section');
    
    function showSection(number) {
        blocks.forEach((block, index) => {
            block.style.backgroundColor = index + 1 === number ? 'MistyRose' : '#FFAEA5';
        });
    }
    Podgląd strony po tym kroku (smoki.php)
  37. Krok 37: Funkcja showSection: widoczna jedna sekcja

    Kryteria: ,

    R.5.8 Po kliknięciu na blok lewy wyświetlona jest w bloku prawym tylko sekcja z nim skojarzona (wystarczy że spełnione dla jednego bloku innego niż "Baza")

    R.5.9 Po wykonaniu R.5.7, R.5.8, a następnie po kliknięciu na blok lewy "Baza" strona wraca do stanu początkowego (kolor i sekcja)

    ok. 2 min
    Polecenie z arkusza

    Sposób wyświetlania Sekcji 1 zmienia się na blokowy, pozostałe są usunięte.

    Ta sama konstrukcja dla sekcji: sekcja o numerze klikniętego bloku dostaje display: block, pozostałe none (R.5.8). Funkcja zawsze ustawia wszystkie bloki i sekcje, więc każda sekwencja kliknięć kończy się poprawnym stanem - także powrót do „Baza” (R.5.9).

    script.js JavaScript zmienione: 3 linie
    const blocks = document.querySelectorAll('.block');
    const sections = document.querySelectorAll('main section');
    
    function showSection(number) {
        blocks.forEach((block, index) => {
            block.style.backgroundColor = index + 1 === number ? 'MistyRose' : '#FFAEA5';
        });
        sections.forEach((section, index) => {
            section.style.display = index + 1 === number ? 'block' : 'none';
        });
    }
    Podgląd strony po tym kroku (smoki.php)
  38. Krok 38: Kliknięcie w dowolny blok wywołuje funkcję

    Kryteria: , , ,

    R.3.5 Kliknięcie na dowolnym bloku w bloku nawigacyjnym powoduje wywołanie funkcji skryptu

    R.5.7 Po kliknięciu na blok lewy jego kolor tła zamienia się na MistyRose, kolor tła pozostałych bloków lewych na "#FFAEA5" (wystarczy że spełnione dla jednego bloku innego niż "Baza")

    R.5.8 Po kliknięciu na blok lewy wyświetlona jest w bloku prawym tylko sekcja z nim skojarzona (wystarczy że spełnione dla jednego bloku innego niż "Baza")

    R.5.9 Po wykonaniu R.5.7, R.5.8, a następnie po kliknięciu na blok lewy "Baza" strona wraca do stanu początkowego (kolor i sekcja)

    ok. 2 min
    Polecenie z arkusza

    Gdy zostanie kliknięty Blok 1, Blok 2 albo Blok 3: kolor tła klikniętego bloku zmienia się na MistyRose, pozostałe na #FFAEA5, a sposób wyświetlania jego sekcji zmienia się na blokowy, pozostałe są usunięte.

    Każdy blok dostaje nasłuchiwacz addEventListener('click', ...) - HTML nie ma ani jednego atrybutu onclick, całe zachowanie jest w skrypcie. Funkcja strzałkowa odczytuje numer sekcji z atrybutu data-section (block.dataset.section) i przekazuje go do showSection. Wartość atrybutu to zawsze napis, a funkcja porównuje ściśle (===) z liczbą - stąd Number(...).

    Sprawdź w podglądzie sekwencję z klucza: „Galeria”, „Opisy”, „Baza” (R.3.5, R.5.7, R.5.8, R.5.9).

    Typowe błędy

    addEventListener('click', showSection(1)) wywołuje funkcję od razu przy rejestracji - przekazuje się funkcję, nie jej wynik.

    script.js JavaScript zmienione: 4 linie
    const blocks = document.querySelectorAll('.block');
    const sections = document.querySelectorAll('main section');
    
    function showSection(number) {
        blocks.forEach((block, index) => {
            block.style.backgroundColor = index + 1 === number ? 'MistyRose' : '#FFAEA5';
        });
        sections.forEach((section, index) => {
            section.style.display = index + 1 === number ? 'block' : 'none';
        });
    }
    
    blocks.forEach((block) => {
        block.addEventListener('click', () => showSection(Number(block.dataset.section)));
    });
    Podgląd strony po tym kroku (smoki.php)
  39. Krok 39: Obsługa klawiatury

    ok. 2 min
    Polecenie z arkusza

    Składa się z jednej lub trzech funkcji wywoływanych po kliknięciu na jednym z bloków w bloku nawigacyjnym.

    Blok z role="button" i tabindex="0" da się zaznaczyć klawiszem Tab, ale <div> sam nie reaguje na klawisze jak prawdziwy przycisk. Drugi nasłuchiwacz, na zdarzenie keydown, wywołuje tę samą funkcję po wciśnięciu Enter albo spacji; preventDefault() blokuje przewinięcie strony spacją. Arkusz i klucz tego nie wymagają - bez tego nawigacja działa tylko myszą.

    script.js JavaScript zmienione: 6 linii
    const blocks = document.querySelectorAll('.block');
    const sections = document.querySelectorAll('main section');
    
    function showSection(number) {
        blocks.forEach((block, index) => {
            block.style.backgroundColor = index + 1 === number ? 'MistyRose' : '#FFAEA5';
        });
        sections.forEach((section, index) => {
            section.style.display = index + 1 === number ? 'block' : 'none';
        });
    }
    
    blocks.forEach((block) => {
        block.addEventListener('click', () => showSection(Number(block.dataset.section)));
        block.addEventListener('keydown', (event) => {
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                showSection(Number(block.dataset.section));
            }
        });
    });
    Podgląd strony po tym kroku (smoki.php)
  40. Etap 5: Skrypty PHP

    Kroki 40-48 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 40: Dane połączenia w pliku config.php

    Kryteria:

    R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie

    ok. 2 min
    Polecenie z arkusza

    Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie smoki.

    Dane logowania do bazy w osobnym pliku config.php, który tylko zwraca tablicę (return [...]). W prawdziwym projekcie hasło do bazy jest inne na każdym serwerze i nie trafia do repozytorium razem z kodem strony - wystarczy podmienić jeden plik. Arkusz dopuszcza dodatkowe pliki („ewentualnie inne przygotowane pliki”).

    DSN (mysql:host=localhost;dbname=smoki;charset=utf8mb4) to adres bazy dla PDO w jednym napisie: rodzaj serwera, host, nazwa bazy i kodowanie połączenia. Plik bez HTML-u nie ma końcowego ?> - nic po nim nie wypisze się przypadkiem.

    Typowe błędy

    Plik config.php musi trafić do folderu z rezultatami - bez niego strona się nie połączy, a egzaminator nie znajdzie nazwy bazy.

    config.php PHP nowy plik
    <?php
    // Dane połączenia z bazą - w jednym miejscu, poza plikiem strony
    return [
        'dsn' => 'mysql:host=localhost;dbname=smoki;charset=utf8mb4',
        'user' => 'root',
        'password' => '',
    ];

    Podgląd strony bez zmian - taki jak po kroku 39.

  41. Krok 41: Połączenie z bazą przez PDO

    Kryteria: ,

    R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie

    R.5.10 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 3 min
    Polecenie z arkusza

    Skrypty 1 i 2 są napisane w języku PHP. Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie smoki.

    Kod PHP stoi na samym początku pliku, przed <!DOCTYPE html>: najpierw wszystkie operacje na bazie, potem szablon strony, który tylko wypisuje gotowe dane. Klucz R.5 przyjmuje PDO tak samo jak MySQLi.

    • require 'config.php' - dane połączenia trafiają do $config,
    • new PDO(...) - połączenie i wybór bazy; opcja ERRMODE_EXCEPTION sprawia, że każdy błąd SQL zatrzymuje skrypt wyjątkiem, zamiast po cichu zwracać false, a FETCH_ASSOC - że wiersze przychodzą jako tablice z nazwami kolumn ($row['nazwa'] zamiast $row[1]),
    • try … catch (PDOException $error) - gdy baza nie działa, użytkownik widzi zwykły komunikat, a nie treść błędu z nazwą serwera i ścieżkami; http_response_code(500) mówi przeglądarce, że to błąd serwera.

    Od tego kroku podgląd to prawdziwy wynik strony z serwera - na razie bez zmian.

    Typowe błędy

    catch wypisujący $error->getMessage() pokazałby użytkownikowi szczegóły serwera.

    smoki.php PHP zmienione: 13 linii
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  42. Krok 42: Funkcja e(): bezpieczne wypisywanie tekstu

    ok. 2 min
    Polecenie z arkusza

    Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.

    Każdy napis z bazy albo z formularza, który trafi do HTML-u, przejdzie przez e() (od escape). htmlspecialchars zamienia <, >, & i - dzięki ENT_QUOTES - oba cudzysłowy na encje, więc napis <script> zapisany kiedyś w bazie wyświetli się jako tekst, a nie wykona (ochrona przed XSS). Escapowanie robi się na wyjściu, tuż przed wypisaniem - w bazie zostają dane surowe.

    Krótka nazwa to świadomy wyjątek od „znaczącego nazewnictwa”: e() występuje w szablonie wiele razy i jest powszechnie znaną konwencją (tak samo nazywa się w Laravelu). Typy string przy parametrze i wyniku mówią, czego funkcja oczekuje; liczby PHP zamieni na tekst sam.

    smoki.php PHP zmienione: 5 linii
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 41.

  43. Krok 43: Skrypt 1: zapytanie 2 do bazy

    Kryteria:

    R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 lub skrypt 2 - zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza

    ok. 2 min
    Polecenie z arkusza

    Skrypt 1: wysyła do bazy danych zapytanie 2.

    Zapytanie 2 przez query; PDO::FETCH_COLUMN zwraca od razu listę krajów (R.5.2). Ta lista posłuży też jako biała lista w skrypcie 2.

    smoki.php PHP zmienione: 2 linie
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 41.

  44. Krok 44: Skrypt 1: kraje jako opcje listy

    Kryteria:

    R.5.4 Skrypt 1 wyświetla w opcjach listy rozwijanej wszystkie zwrócone zapytaniem wiersze

    ok. 2 min
    Polecenie z arkusza

    Wszystkie zwrócone zapytaniem wiersze są zapisywane jako opcje listy rozwijanej, zgodnie z ilustracją 4.

    Pętla w składni szablonu (foreach … : / endforeach;), jeden <option> na kraj (R.5.4): Bułgaria, Chiny, Francja, Japonia, Polska.

    smoki.php PHP zmienione: 3 linie
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
    <?php foreach ($countries as $countryName): ?>
                        <option><?= e($countryName) ?></option>
    <?php endforeach; ?>
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  45. Krok 45: Skrypt 2: tylko gdy formularz wysłał dane

    Kryteria:

    R.5.3 Skrypt 2 wykonywany jest tylko, gdy formularz wysłał dane i zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)

    ok. 3 min
    Polecenie z arkusza

    Skrypt 2, wykonywany tylko, gdy formularz wysłał dane.

    $_POST['country'] ?? null - wartość z formularza (R.5.3: dane z tablicy odpowiadającej metodzie), a null, gdy formularza nie wysłano. Warunek przepuszcza tylko kraj z białej listy - z listy $countries wczytanej przed chwilą z bazy; napis spoza bazy (ręcznie podrobione żądanie) nie uruchomi zapytania.

    Na liście opcja równa wysłanemu krajowi dostaje selected - po wyszukaniu lista pokazuje Francję, a nie wraca do Bułgarii. Podgląd od tego kroku: stan po wybraniu Francji (ilustracja 4).

    smoki.php PHP zmienione: 6 linii
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    
        $dragons = [];
        $country = $_POST['country'] ?? null;
        if ($country !== null && in_array($country, $countries, true)) {
        }
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
    <?php foreach ($countries as $countryName): ?>
                        <option<?= $countryName === $country ? ' selected' : '' ?>><?= e($countryName) ?></option>
    <?php endforeach; ?>
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  46. Krok 46: Skrypt 2: zapytanie 1 przygotowane z krajem z formularza

    Kryteria:

    R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 lub skrypt 2 - zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza

    ok. 3 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza.

    Zapytanie 1 z parametrem :country w miejscu „Polska”, wartość osobno w execute - nie staje się częścią polecenia SQL (R.5.2). Biała lista i parametr to dwie niezależne warstwy ochrony.

    smoki.php PHP zmienione: 3 linie
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    
        $dragons = [];
        $country = $_POST['country'] ?? null;
        if ($country !== null && in_array($country, $countries, true)) {
            $query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');
            $query->execute(['country' => $country]);
            $dragons = $query->fetchAll();
        }
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
    <?php foreach ($countries as $countryName): ?>
                        <option<?= $countryName === $country ? ' selected' : '' ?>><?= e($countryName) ?></option>
    <?php endforeach; ?>
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 45.

  47. Krok 47: Skrypt 2: smoki jako wiersze tabeli

    Kryteria:

    R.5.5 Skrypt 2 wyświetla każdy zwrócony zapytaniem wiersz jako kolejny wiersz tabeli, komórki tabeli są wypełnione zgodnie z nagłówkami

    ok. 2 min
    Polecenie z arkusza

    Każdy zwrócony zapytaniem wiersz jest zapisywany jako kolejny wiersz tabeli, zgodnie z ilustracją 4.

    W <tbody> jeden <tr> na smoka, komórki po nazwach kolumn - nazwa, długość, szerokość pod swoimi nagłówkami (R.5.5). Podgląd: dziesięć smoków z Francji.

    Typowe błędy

    Komórki w innej kolejności niż nagłówki to strata R.5.5.

    smoki.php PHP zmienione: 7 linii
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    
        $dragons = [];
        $country = $_POST['country'] ?? null;
        if ($country !== null && in_array($country, $countries, true)) {
            $query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');
            $query->execute(['country' => $country]);
            $dragons = $query->fetchAll();
        }
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
    <?php foreach ($countries as $countryName): ?>
                        <option<?= $countryName === $country ? ' selected' : '' ?>><?= e($countryName) ?></option>
    <?php endforeach; ?>
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
    <?php foreach ($dragons as $dragon): ?>
                        <tr>
                            <td><?= e($dragon['nazwa']) ?></td>
                            <td><?= e($dragon['dlugosc']) ?></td>
                            <td><?= e($dragon['szerokosc']) ?></td>
                        </tr>
    <?php endforeach; ?>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (smoki.php)
  48. Krok 48: Zamknięcie połączenia z bazą

    Kryteria:

    R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie

    ok. 1 min
    Polecenie z arkusza

    Na końcu działania skrypt zamyka połączenie z serwerem.

    $db = null; na końcu bloku try zamyka połączenie PDO - ostatnia operacja na bazie (R.5.1). Szablon używa już tylko gotowych tablic.

    Typowe błędy

    $db->close() nie istnieje w PDO.

    smoki.php PHP zmienione: 2 linie
    <?php
    $config = require 'config.php';
    
    try {
        $db = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);
    
        $dragons = [];
        $country = $_POST['country'] ?? null;
        if ($country !== null && in_array($country, $countries, true)) {
            $query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');
            $query->execute(['country' => $country]);
            $dragons = $query->fetchAll();
        }
    
        $db = null;
    } catch (PDOException $error) {
        http_response_code(500);
        exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');
    }
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smoki</title>
        <link rel="stylesheet" href="styl.css">
        <script src="script.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Poznaj smoki!</h2>
        </header>
        <nav>
            <div class="block" data-section="1" role="button" tabindex="0">Baza</div>
            <div class="block" data-section="2" role="button" tabindex="0">Opisy</div>
            <div class="block" data-section="3" role="button" tabindex="0">Galeria</div>
        </nav>
        <main>
            <section>
                <h3>Baza Smoków</h3>
                <form method="post">
                    <select name="country" aria-label="Kraj pochodzenia">
    <?php foreach ($countries as $countryName): ?>
                        <option<?= $countryName === $country ? ' selected' : '' ?>><?= e($countryName) ?></option>
    <?php endforeach; ?>
                    </select>
                    <button type="submit">Szukaj</button>
                </form>
                <table>
                    <thead>
                        <tr>
                            <th>Nazwa</th>
                            <th>Długość</th>
                            <th>Szerokość</th>
                        </tr>
                    </thead>
                    <tbody>
    <?php foreach ($dragons as $dragon): ?>
                        <tr>
                            <td><?= e($dragon['nazwa']) ?></td>
                            <td><?= e($dragon['dlugosc']) ?></td>
                            <td><?= e($dragon['szerokosc']) ?></td>
                        </tr>
    <?php endforeach; ?>
                    </tbody>
                </table>
            </section>
            <section>
                <h3>Opisy smoków</h3>
                <dl>
                    <dt>Smok czerwony</dt>
                    <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd>
                    <dt>Smok zielony</dt>
                    <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd>
                    <dt>Smok niebieski</dt>
                    <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd>
                </dl>
            </section>
            <section>
                <h3>Galeria</h3>
                <img src="smok1.jpg" alt="Smok czerwony">
                <img src="smok2.jpg" alt="Smok wielki">
                <img src="smok3.jpg" alt="Skrzydlaty łaciaty">
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 47.

  49. Etap 6: Porównanie z wersją podstawową

    Krok 49 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 49: Co jest inaczej i którą wersję wybrać na egzaminie

    ok. 2 min

    Obie wersje dają komplet 41 punktów. Różnice:

    wersja podstawowawersja nowoczesna
    układfloat: left + clear: bothsiatka z grid-template-areas na <body>
    blok 1, sekcje 2 i 3#block1, #section2, #section3.block:first-child, section + section
    kliknięcieonclick="showSection(1)" w HTMLaddEventListener, numer w data-section
    pętla w JSfor (let i = 1; i <= 3; i++)forEach i operator warunkowy
    klawiaturabrakrole="button", tabindex, keydown
    bazamysqli_*, kraj sklejony z SQLPDO, biała lista, zapytanie przygotowane

    Klucz wymusza zmianę stylu przez style.backgroundColor i style.display (R.5.6) - obie wersje to robią. Na egzaminie onclick z identyfikatorami jest krótszy i łatwiejszy do sprawdzenia wzrokiem; selektory strukturalne i data-* opłacają się, gdy bloków przybywa - nowy blok nie wymaga zmian w skrypcie ani w CSS.

    Podgląd strony bez zmian - taki jak po kroku 47.

  50. Etap 7: Oddanie pracy

    Krok 50 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 50: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Nagraj płytę z rezultatami pracy.

    W folderze z numerem zdającego: config.php, import.jpg, kw1.png … kw4.png, kwerendy.txt, przeglądarka.txt, script.js, smok1.jpg … smok3.jpg, smoki.php, styl.css. Płytę sprawdź po nagraniu.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

    Podgląd strony bez zmian - taki jak po kroku 47.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.