Przejdź do głównej treści
EE.09-01-22.01-SGStyczeń 2022 · 44 kroki · ok. 81 min · 31 kryteriów z klucza

Rozwiązanie krok po kroku: Zgłoszenie na kartę wędkarską (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza wedkowanie z czterema zapytaniami, zdjęcie wędki o wysokości 220 px, strona karta.html z formularzem zgłoszenia i skrypt zapisz.php zapisujący dane w bazie - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • semantyczne znaczniki: baner w <header>, blok główny w <main>, trzy dolne bloki w <section>,
  • flexbox zamiast float: dolne bloki stoją w kontenerze display: flex, a szerokości 20%, 40% i 40% zostają na blokach - tak, jak ocenia je klucz,
  • zmienne CSS dla kolorów z arkusza, etykiety <label for>, przyciski <button>, pola z required i autocomplete,
  • PHP na PDO z zapytaniem przygotowanym, sprawdzeniem metody żądania i pustych pól, obsługą błędów w try / catch i zamknięciem połączenia w finally,
  • strona z potwierdzeniem zamiast pustej strony po zapisie, z danymi przepuszczonymi przez htmlspecialchars, oraz przekierowanie po zapisie - odświeżenie nie doda drugiej karty.

To arkusz EE.09 ze stycznia 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i zdjęcie pochodzą z oryginalnego archiwum CKE pliki1.zip (załącznik na stronie arkusza), zapytania i zrzuty są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.0.7 - użyte konstrukcje działają w obu wersjach).

Jak liczą się punkty. Klucz ma 31 kryteriów (R.1.1 - R.5.4), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 24 punkty. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.

  1. Etap 1: Baza danych

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

    Krok 1: Folder zdającego i archiwum pliki1.zip

    ok. 2 min
    Polecenie z arkusza

    Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu.

    Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum pliki1.zip rozpakowane z hasłem K@RTY*. W środku: baza.sql i wedka.jpg. Do tego folderu trafiają wszystkie rezultaty pracy.

  2. Krok 2: XAMPP i baza wedkowanie

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie wedkowanie

    Start przy Apache i MySQL, potem http://localhost/phpmyadmin, Nowa, nazwa wedkowanie, porównywanie np. utf8mb4_polish_ci.

  3. Krok 3: Import pliku baza.sql i zrzut import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych wedkowanie , czynność udokumentowano plikiem o nazwie import w formacie PNG. Zrzut zawiera cały obszar ekranu z widocznym paskiem zadań

    ok. 3 min
    Polecenie z arkusza

    Do bazy wedkowanie zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL, lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie PNG i nazwij import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel

    Baza wedkowanie, karta Import, plik baza.sql, Wykonaj. Po komunikacie „Import zakończył się sukcesem” w lewym panelu jest 11 tabel; zadanie używa trzech: karty_wedkarskie, lowisko i zawody_wedkarskie. Zrzut całego ekranu z paskiem zadań: import.png.

    Typowe błędy

    Ten zrzut zapisz jako PNG, zrzuty zapytań (kw1 - kw4) - jako JPEG.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: karta Grzegorza Niemczyka

    Kryteria: ,

    R.1.2 Zapisano plik tekstowy o nazwie kwerendy zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Utworzono zapytanie 1 dodające rekord do tabeli karty_wedkarskie dla Grzegorza Niemczyka, adres="Gdynia, Batorego 14/5", z datą "2018-02-23", punkty=0. Baza powinna sama nadać wartość pola id dla tabeli. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO `karty_wedkarskie` VALUES (NULL, 'Grzegorz', 'Niemczyk', 'Gdynia, Batorego 14/5', '2018-02-23', '0'); oraz wynik działania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie lub tabela z dodanym rekordem

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: dodające rekord do tabeli Karty_wedkarskie dla Grzegorza Niemczyka, zamieszkałego pod adresem „Gdynia, Batorego 14/5”, z datą „2018-02-23”; wartość punktów: 0. Baza powinna sama nadać wartość pola id dla tabeli

    Wartości dla wszystkich sześciu kolumn w kolejności z tabeli. NULL w kolumnie id z AUTO_INCREMENT - numer nada baza (Grzegorz dostaje 3). Data w formacie RRRR-MM-DD, punkty jako liczba. Zapytanie trafia do kwerendy.txt (R.1.2), zrzut z dodanym rekordem - do kw1.jpg. To samo zapytanie, z parametrami w miejscu danych, wykona później skrypt.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    INSERT INTO karty_wedkarskie VALUES (NULL, 'Grzegorz', 'Niemczyk', 'Gdynia, Batorego 14/5', '2018-02-23', 0);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: wędkarze z liczbą punktów większą niż 20

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola imie i nazwisko z tabeli karty_wedkarskie dla wędkarzy, dla których liczba punktów jest większa niż 20. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM `karty_wedkarskie` WHERE punkty > 20; oraz wynik działania udokumentowano zrzutem, na którym widoczny jest dokładnie 1 rekord: Jan Kowalski; jedynie pola imie, nazwisko

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola imie i nazwisko z tabeli Karty_wedkarskie dla wędkarzy, dla których liczba punktów jest większa niż 20

    Dwie kolumny, warunek punkty > 20 (ostro większa). Wynik: jeden wędkarz, Jan Kowalski. Zrzut: kw2.jpg. Każda klauzula w osobnej linii - przy dłuższych zapytaniach łatwiej wtedy znaleźć błąd.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    INSERT INTO karty_wedkarskie VALUES (NULL, 'Grzegorz', 'Niemczyk', 'Gdynia, Batorego 14/5', '2018-02-23', 0);
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM karty_wedkarskie
    WHERE punkty > 20;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: akwen, gdzie sędzią jest Krzysztof Dobrowolski

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pole akwen z tabeli lowisko dla łowisk, gdzie sędzią zawodów jest Krzysztof Dobrowolski. Zapytanie wykorzystuje relację. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT akwen FROM lowisko JOIN zawody_wedkarskie ON lowisko.id = zawody_wedkarskie.Lowisko_id WHERE sedzia= "Krzysztof Dobrowolski"; możliwe INNER JOIN lub SELECT akwen FROM lowisko, zawody_wedkarskie WHERE lowisko.id = zawody_wedkarskie.Lowisko_id AND sedzia= "Krzysztof Dobrowolski"; oraz wynik działania udokumentowano zrzutem, na którym widoczny jest dokładnie 1 rekord: Zalew Wegrowski; jedynie pole akwen

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pole akwen z tabeli Lowisko dla łowisk, gdzie sędzią zawodów jest Krzysztof Dobrowolski, należy użyć relacji

    Relacja łączy zawody z łowiskiem przez kolumnę Lowisko_id: JOIN zawody_wedkarskie ON lowisko.id = zawody_wedkarskie.Lowisko_id, a WHERE zostawia zawody jednego sędziego. Wynik: Zalew Wegrowski. Zrzut: kw3.jpg.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    INSERT INTO karty_wedkarskie VALUES (NULL, 'Grzegorz', 'Niemczyk', 'Gdynia, Batorego 14/5', '2018-02-23', 0);
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM karty_wedkarskie
    WHERE punkty > 20;
    
    -- Zapytanie 3
    SELECT akwen
    FROM lowisko
    JOIN zawody_wedkarskie ON lowisko.id = zawody_wedkarskie.Lowisko_id
    WHERE sedzia = 'Krzysztof Dobrowolski';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: użytkownik anna

    Kryteria:

    R.1.6 Utworzono zapytanie 4 tworzące użytkownika anna na localhost z hasłem anna123. W pliku z kwerendami lub na zrzucie istnieje zapis np.: CREATE USER "anna"@"localhost" IDENTIFIED BY "anna123"; oraz wynik działania udokumentowano zrzutem wskazującym na prawidłowo dodanego użytkownika

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: tworzące użytkownika anna na localhost z hasłem anna123

    Nazwa i host w osobnych apostrofach: 'anna'@'localhost', hasło po IDENTIFIED BY. Żeby zrzut kw4.jpg pokazywał nowe konto, pod zapytaniem 4 w tej samej karcie SQL dopisz SELECT User, Host, Password FROM mysql.user WHERE User = 'anna'; - do kwerendy.txt trafia tylko zapytanie 4.

    Typowe błędy

    anna123 to hasło do ćwiczeń - na prawdziwym serwerze konto dostaje długie losowe hasło.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO karty_wedkarskie VALUES (NULL, 'Grzegorz', 'Niemczyk', 'Gdynia, Batorego 14/5', '2018-02-23', 0);
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM karty_wedkarskie
    WHERE punkty > 20;
    
    -- Zapytanie 3
    SELECT akwen
    FROM lowisko
    JOIN zawody_wedkarskie ON lowisko.id = zawody_wedkarskie.Lowisko_id
    WHERE sedzia = 'Krzysztof Dobrowolski';
    
    -- Zapytanie 4
    CREATE USER 'anna'@'localhost' IDENTIFIED BY 'anna123';
    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 18 z 31 kryteriów (pkt)

    Krok 8: Grafika: wysokość 220 px z zachowaniem proporcji

    Kryteria:

    R.2.1 Plik wedka.jpg przeskalowano z zachowaniem proporcji tak, że jego wysokość wynosi dokładnie 220 px, odpowiadająca temu szerokość wynosi 330 px ±5 px

    ok. 2 min
    Polecenie z arkusza

    Plik wedka.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 220 px

    GIMP, Obraz → Skaluj obraz, łańcuch zamknięty, wysokość 220 px - szerokość przelicza się na 330 px (500 × 220 / 333). Plik → Nadpisz wedka.jpg.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik karta.html

    ok. 1 min
    Polecenie z arkusza

    Składa się ze strony o nazwie karta.html oraz skryptu zapisz.php. Poniższe wymagania dotyczą tylko pliku karta.html

    Szkielet HTML5 w pliku karta.html. <meta name="viewport"> każe telefonom wyświetlić stronę w naturalnej szerokości ekranu, zamiast pomniejszać widok komputerowy.

    karta.html HTML nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  10. Krok 10: Kodowanie polskich znaków

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku karta.html oraz zastosowano standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwsza linia <head> i plik zapisany w UTF-8 (R.2.2).

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  11. Krok 11: Tytuł strony

    Kryteria:

    R.2.3 Nadano tytuł strony: "Karty wędkarskie”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Karty wędkarskie”

    <title>Karty wędkarskie</title> (R.2.3).

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  12. Krok 12: Podpięcie arkusza stylów styl_1.css

    Kryteria:

    R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl_1.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy źle przypisano co najmniej jeden selektor do bloku (np. kropka zamiast #)

    ok. 1 min
    Polecenie z arkusza

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

    <link rel="stylesheet" href="styl_1.css"> - nazwa z podkreśleniem i cyfrą (R.3.5).

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  13. Krok 13: Bloki: header, main i trzy sekcje

    Kryteria:

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, główny, trzy bloki: lewy, środkowy i prawy. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze blok banera, poniżej blok główny, na dole trzy bloki: lewy, środkowy i prawy. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z Obrazem 2

    Każdy blok dostaje znacznik, który mówi, czym jest:

    • <header> - baner strony,
    • <main> - główna treść, czyli formularz; na stronie jest jeden <main>, więc nie potrzebuje identyfikatora,
    • trzy <section> z klasami left, middle i right - dolne bloki.

    Dolne sekcje stoją we wspólnym kontenerze <div class="bottom">. div nie ma znaczenia dla treści - służy wyłącznie do ułożenia trzech bloków obok siebie (R.2.4).

    karta.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  14. Krok 14: Baner: nagłówek drugiego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku banera: nagłówek drugiego stopnia o treści „Zgłoszenie na kartę wędkarską”

    <h2> w <header>. Punkt R.2.5 przyjdzie razem z paragrafem w bloku prawym.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  15. Krok 15: Blok główny: nagłówek czwartego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: Nagłówek czwartego stopnia o treści: „Formularz - karta wędkarska”

    <h4> na początku <main>.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  16. Krok 16: Formularz wysyłający dane metodą POST do zapisz.php

    Kryteria:

    R.3.4 Formularz wysyła dane metodą POST do pliku zapisz.php

    ok. 2 min
    Polecenie z arkusza

    Formularz wysyłający dane metodą POST do pliku zapisz.php zawierający pola

    action="zapisz.php" - dokąd, method="post" - jak: dane jadą w treści żądania i trafią do $_POST (R.3.4). Stronę otwierasz przez http://localhost/…, żeby serwer wykonał skrypt.

    karta.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  17. Krok 17: Pole „imię: ” z etykietą powyżej

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne podpisane powyżej tekstem: „imię: ”

    Napis to <label for="first-name">, a pole ma ten sam id="first-name" - etykieta jest powiązana z polem: kliknięcie napisu ustawia kursor w polu, a czytnik ekranu odczytuje go jako nazwę pola. Napis stanie nad polem dzięki regule CSS dla wiersza .row - bez <br> w HTML-u.

    • name="imie" - klucz w $_POST, taki jak nazwa kolumny,
    • required - przeglądarka nie wyśle formularza z pustym polem,
    • autocomplete="given-name" - przeglądarka podpowie zapamiętane imię.
    karta.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  18. Krok 18: Pole „nazwisko: ” z etykietą powyżej

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne podpisane powyżej tekstem: „nazwisko: ”

    Ten sam wiersz: etykieta for="last-name", pole name="nazwisko", podpowiedź family-name.

    karta.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  19. Krok 19: Pole „adres: ” o rozmiarze 30

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne podpisane powyżej tekstem: „adres: ”; pole ma rozmiar 30

    size="30" - szerokość pola na około 30 znaków, dokładnie to, co mówi arkusz. Klucz przyjmuje też szerokość w CSS, ale atrybut jest najprostszy i widać go od razu w kodzie (R.2.8).

    karta.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  20. Krok 20: Przycisk „CZYŚĆ”

    ok. 1 min
    Polecenie z arkusza

    Przycisk czyszczący zawartość formularza z etykietą „CZYŚĆ”

    <button type="reset"> - napis stoi między znacznikami, więc można w nim umieścić także ikonę albo pogrubienie. Typ trzeba podać jawnie: <button> bez type w formularzu domyślnie wysyła dane.

    karta.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  21. Krok 21: Przycisk „ZAPISZ”

    Kryteria: ,

    R.2.8 W bloku głównym umieszczono formularz z trzema polami edycyjnymi w tym pole do wpisania adresu ma rozmiar 30 (size lub maxlength lub width lub w CSS) oraz dwoma przyciskami "CZYŚĆ" i "ZAPISZ"

    R.3.3 Pierwszy przycisk czyści zawartość formularza, drugi przycisk wysyła dane z formularza (input z typem submit lub button)

    ok. 1 min
    Polecenie z arkusza

    Przycisk wysyłający zawartość formularza z etykietą „ZAPISZ”

    <button type="submit"> - drugi przycisk wysyła formularz. Klucz wprost przyjmuje button (R.3.3). Formularz ma komplet: trzy pola, pole adresu o rozmiarze 30 i dwa przyciski (R.2.8).

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  22. Krok 22: Blok lewy: nagłówek „Typy łowisk”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek czwartego stopnia o treści: „Typy łowisk”

    <h4> w sekcji left.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
                <h4>Typy łowisk</h4>
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  23. Krok 23: Lista punktowana typów łowisk

    Kryteria:

    R.2.6 W bloku lewym umieszczono listę punktowaną (nieuporządkowaną) z czterema elementami: Zalewy, Stawy, Jeziora, Rzeki, zastosowano znaczniki <ul>, <li> oraz ich zamknięcia

    ok. 1 min
    Polecenie z arkusza

    Lista punktowana (nieuporządkowana) zawierająca elementy: Zalewy, Stawy, Jeziora, Rzeki

    <ul> z czterema <li> (R.2.6).

    karta.html HTML zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
                <h4>Typy łowisk</h4>
                <ul>
                    <li>Zalewy</li>
                    <li>Stawy</li>
                    <li>Jeziora</li>
                    <li>Rzeki</li>
                </ul>
            </section>
            <section class="middle">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  24. Krok 24: Blok środkowy: zdjęcie z tekstem alternatywnym

    Kryteria:

    R.2.7 W bloku środkowym umieszczono obraz wedka.jpg oraz ma on tekst alternatywny "karta wędkarska"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku środkowego: obraz wedka.jpg z tekstem alternatywnym o treści: „karta wędkarska”

    <img> z alt="karta wędkarska" (R.2.7). Atrybuty width i height z wymiarami pliku po skalowaniu rezerwują miejsce na zdjęcie, zanim się wczyta - strona nie „skacze” przy ładowaniu.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
                <h4>Typy łowisk</h4>
                <ul>
                    <li>Zalewy</li>
                    <li>Stawy</li>
                    <li>Jeziora</li>
                    <li>Rzeki</li>
                </ul>
            </section>
            <section class="middle">
                <img src="wedka.jpg" alt="karta wędkarska" width="330" height="220">
            </section>
            <section class="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  25. Krok 25: Blok prawy: paragraf z autorem strony

    Kryteria:

    R.2.5 W banerze zapisano nagłówek h2: "Zgłoszenie na kartę wędkarską" oraz zapisano przynajmniej jeden nagłówek h4 z: "Formularz - karta wędkarska" w bloku głównym lub "Typy łowisk" w lewym oraz w bloku prawym paragraf z numerem PESEL lub innym numerem, którym został podpisany arkusz

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Akapit (paragraf) o treści: „Stronę przygotował: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz

    Na egzaminie po dwukropku wpisujesz PESEL; tu w jego miejscu stoi Bartosz Bryniarski. Z nagłówkami <h2> i <h4> daje to R.2.5.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
                <h4>Typy łowisk</h4>
                <ul>
                    <li>Zalewy</li>
                    <li>Stawy</li>
                    <li>Jeziora</li>
                    <li>Rzeki</li>
                </ul>
            </section>
            <section class="middle">
                <img src="wedka.jpg" alt="karta wędkarska" width="330" height="220">
            </section>
            <section class="right">
                <p>Stronę przygotował: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  26. Krok 26: Odnośnik do strony kartawedkarska.pl

    Kryteria:

    R.3.2 Wybranie odnośnika "Karta wędkarska" inicjuje otwarcie strony http://www.kartawedkarska.pl/

    ok. 1 min
    Polecenie z arkusza

    Odnośnik do strony „http://www.kartawedkarska.pl/” o treści: „Karta wędkarska”

    Adres z arkusza z http:// na początku (R.3.2). Strona HTML jest gotowa.

    karta.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <form action="zapisz.php" method="post">
                <div class="row">
                    <label for="first-name">imię:</label>
                    <input type="text" id="first-name" name="imie" required autocomplete="given-name">
                </div>
                <div class="row">
                    <label for="last-name">nazwisko:</label>
                    <input type="text" id="last-name" name="nazwisko" required autocomplete="family-name">
                </div>
                <div class="row">
                    <label for="address">adres:</label>
                    <input type="text" id="address" name="adres" size="30" required autocomplete="street-address">
                </div>
                <div class="buttons">
                    <button type="reset">CZYŚĆ</button>
                    <button type="submit">ZAPISZ</button>
                </div>
            </form>
        </main>
        <div class="bottom">
            <section class="left">
                <h4>Typy łowisk</h4>
                <ul>
                    <li>Zalewy</li>
                    <li>Stawy</li>
                    <li>Jeziora</li>
                    <li>Rzeki</li>
                </ul>
            </section>
            <section class="middle">
                <img src="wedka.jpg" alt="karta wędkarska" width="330" height="220">
            </section>
            <section class="right">
                <p>Stronę przygotował: Bartosz Bryniarski</p>
                <a href="http://www.kartawedkarska.pl/">Karta wędkarska</a>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (karta.html)
  27. Etap 3: Styl CSS

    Kroki 27-35 · po tym etapie masz 27 z 31 kryteriów (pkt)

    Krok 27: Plik styl_1.css i zmienne z kolorami arkusza

    ok. 2 min
    Polecenie z arkusza

    Cechy formatowania CSS: Są zawarte wyłącznie w zewnętrznym arkuszu stylów

    Nowy plik styl_1.css. Na początku zmienne CSS w :root: kolor DodgerBlue powtarza się w czterech blokach, a wysokość 220 px w trzech. Każdą wartość wpisujesz raz, a reguły odwołują się do niej przez var(--blue) - zmiana koloru to zmiana jednej linii. Wartości to nazwy z arkusza, więc egzaminator znajdzie je w pliku.

    styl_1.css CSS nowy plik
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    Podgląd strony po tym kroku (karta.html)
  28. Krok 28: Krój Georgia dla całej strony

    Kryteria:

    R.4.1 Ustawiono domyślny krój czcionki dla całej strony na Georgia (dla selektora * lub body lub html lub kontenera całej strony)

    ok. 1 min
    Polecenie z arkusza

    Domyślne dla całej strony: krój czcionki Georgia

    Selektor * - obejmuje też pola i przyciski, które nie dziedziczą kroju po body (R.4.1).

    styl_1.css CSS zmienione: 4 linie
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    Podgląd strony po tym kroku (karta.html)
  29. Krok 29: Baner: tło, kolor tekstu, marginesy wewnętrzne, wyrównanie

    ok. 1 min
    Polecenie z arkusza

    Dla bloku banera: kolor tła DodgerBlue, biały kolor czcionki, marginesy wewnętrzne 10 px, wyrównanie tekstu do środka

    Selektor header, kolory ze zmiennych, padding: 10px, text-align: center.

    styl_1.css CSS zmienione: 7 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    Podgląd strony po tym kroku (karta.html)
  30. Krok 30: Blok główny: tło LightBlue i marginesy wewnętrzne

    Kryteria:

    R.4.7 Ustawiono marginesy wewnętrzne (padding) dla banera na 10px i bloku głównego na 100px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła LightBlue, marginesy wewnętrzne 100 px

    Selektor znacznika main. Marginesy wewnętrzne banera i bloku głównego: R.4.7.

    styl_1.css CSS zmienione: 5 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    Podgląd strony po tym kroku (karta.html)
  31. Krok 31: Etykiety nad polami formularza

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne podpisane powyżej tekstem: „imię: ”

    Etykieta i pole są elementami w linii - bez stylu stanęłyby obok siebie. Wiersz .row jako kolumna flex (flex-direction: column) układa je jeden pod drugim, jak na obrazie 2, a align-items: flex-start zostawia polom ich naturalną szerokość z size (bez tej linii rozciągnęłyby się na całą szerokość bloku). Arkusz nie podaje stylu formularza, a obraz 2 pokazuje pola pod napisami - ta reguła tylko to odtwarza.

    styl_1.css CSS zmienione: 6 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    
    .row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }
    Podgląd strony po tym kroku (karta.html)
  32. Krok 32: Kontener flex dla trzech dolnych bloków

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)

    ok. 2 min
    Polecenie z arkusza

    Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z Obrazem 2

    display: flex na kontenerze .bottom ustawia jego dzieci - trzy sekcje - w jednym rzędzie, bez float i bez clear (R.3.1). Szerokości dostaną same bloki w kolejnych krokach: arkusz z 2022 roku i jego klucz oceniają szerokość bloków (20% i 40%), więc tam zostaje width, a kontener tylko je układa.

    styl_1.css CSS zmienione: 4 linie
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    
    .row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }
    
    .bottom {
        display: flex;
    }
    Podgląd strony po tym kroku (karta.html)
  33. Krok 33: Blok lewy: tło, kolor tekstu, szerokość, wysokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloku lewego: kolor tła DodgerBlue, biały kolor czcionki, szerokość 20%, wysokość 220 px

    width: 20% liczy się od szerokości kontenera .bottom, czyli od szerokości strony. Wysokość ze zmiennej - 220 px, tyle co zdjęcie.

    styl_1.css CSS zmienione: 7 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    
    .row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }
    
    .bottom {
        display: flex;
    }
    
    .left {
        background-color: var(--blue);
        color: var(--text-light);
        width: 20%;
        height: var(--block-height);
    }
    Podgląd strony po tym kroku (karta.html)
  34. Krok 34: Blok środkowy i prawy: wspólna reguła

    Kryteria: , , , ,

    R.4.2 Ustawiono kolor tła DodgerBlue dla banera i trzech bloków dolnych oraz kolor LightBlue dla bloku głównego

    R.4.3 Ustawiono biały kolor czcionki dla banera i trzech bloków dolnych

    R.4.4 Ustawiono wysokość trzech bloków dolnych na 220px

    R.4.5 Ustawiono szerokość dolnych bloków: lewego na 20% oraz środkowego i prawego na 40%

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera, bloku środkowego i prawego

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla bloku środkowego i bloku prawego: kolor tła DodgerBlue, biały kolor czcionki, szerokość 40%, wysokość 220 px, wyrównanie tekstu do środka

    Dwa selektory po przecinku, jedna reguła. Komplet: kolory tła (R.4.2), biały tekst (R.4.3), wysokości (R.4.4), szerokości 20 + 40 + 40 = 100% (R.4.5) i wyśrodkowanie banera, bloku środkowego i prawego (R.4.6). Flex nie zawija bloków do nowego wiersza, więc nawet zaokrąglenia pikseli nie zepchną bloku prawego pod pozostałe.

    styl_1.css CSS zmienione: 9 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    
    .row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }
    
    .bottom {
        display: flex;
    }
    
    .left {
        background-color: var(--blue);
        color: var(--text-light);
        width: 20%;
        height: var(--block-height);
    }
    
    .middle,
    .right {
        background-color: var(--blue);
        color: var(--text-light);
        width: 40%;
        height: var(--block-height);
        text-align: center;
    }
    Podgląd strony po tym kroku (karta.html)
  35. Krok 35: Odnośnik: obramowanie kreskowane, tło i kolor tekstu

    Kryteria:

    R.4.8 Ustawiono styl odnośnika: obramowanie 1px dashed DimGray, kolor tła Gold, kolor czcionki DarkRed, marginesy wewnętrzne 10px (selektor a lub klasa lub identyfikator)

    ok. 1 min
    Polecenie z arkusza

    Dla znacznika odnośnika: obramowanie linią kreskowaną o szerokości 1 px i kolorze DimGray, kolor tła Gold, kolor czcionki DarkRed, marginesy wewnętrzne 10 px

    border: 1px dashed DimGray - szerokość, linia kreskowana, kolor (R.4.8). Te kolory występują w pliku raz, więc zostają wpisane wprost.

    styl_1.css CSS zmienione: 7 linii
    :root {
        --blue: DodgerBlue;
        --light-blue: LightBlue;
        --text-light: white;
        --block-height: 220px;
    }
    
    * {
        font-family: Georgia;
    }
    
    header {
        background-color: var(--blue);
        color: var(--text-light);
        padding: 10px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-blue);
        padding: 100px;
    }
    
    .row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }
    
    .bottom {
        display: flex;
    }
    
    .left {
        background-color: var(--blue);
        color: var(--text-light);
        width: 20%;
        height: var(--block-height);
    }
    
    .middle,
    .right {
        background-color: var(--blue);
        color: var(--text-light);
        width: 40%;
        height: var(--block-height);
        text-align: center;
    }
    
    a {
        border: 1px dashed DimGray;
        background-color: Gold;
        color: DarkRed;
        padding: 10px;
    }
    Podgląd strony po tym kroku (karta.html)
  36. Etap 4: Skrypt PHP

    Kroki 36-42 · po tym etapie masz 31 z 31 kryteriów (pkt)

    Krok 36: Plik zapisz.php, metoda żądania i połączenie PDO z bazą

    Kryteria:

    R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy wedkowanie

    ok. 3 min
    Polecenie z arkusza

    Skrypt połączenia z bazą. Napisany w języku PHP, w pliku zapisz.php. Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie wedkowanie

    Plik zapisz.php zaczyna się od sprawdzenia, jak go otwarto:

    • $_SERVER['REQUEST_METHOD'] !== 'POST' - ktoś wszedł na adres skryptu wprost (z historii, z zakładki, robot). Wtedy header('Location: karta.html') odsyła go do formularza, a exit kończy skrypt - sam nagłówek go nie zatrzymuje. Sprawdzone: takie wejście dostaje odpowiedź 302 i nic nie trafia do bazy,
    • new PDO(...) - adres serwera localhost, baza wedkowanie i kodowanie w jednym napisie, potem użytkownik root i puste hasło (R.5.1). ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek, który obsłuży jeden blok catch.

    PDO zamiast funkcji mysqli z tabeli 1 - klucz ocenia połączenie, a nie bibliotekę. Podgląd do kroku z zapytaniem pokazuje formularz.

    zapisz.php PHP nowy plik
    <?php
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);

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

  37. Krok 37: Dane z formularza w tablicy $_POST

    Kryteria:

    R.5.3 Skrypt pobiera dane z formularza za pomocą tablicy $_POST (lub $_REQUEST gdy sprawdzono, że REQUEST_METHOD jest równe POST)

    ok. 2 min
    Polecenie z arkusza

    Skrypt działa na danych przesłanych z formularza

    Trzy wartości z $_POST (R.5.3), od razu oczyszczone:

    • ?? '' - gdy pola w ogóle nie wysłano, zmienna dostaje pusty napis zamiast ostrzeżenia „Undefined array key”,
    • trim() - zdejmuje spacje z brzegów: „ Marek ” zapisze się jako „Marek”, a pole z samych spacji stanie się puste.

    Nazwy zmiennych po angielsku ($firstName), klucze tablicy - takie, jak atrybuty name w formularzu.

    zapisz.php PHP zmienione: 4 linie
    <?php
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $firstName = trim($_POST['imie'] ?? '');
    $lastName = trim($_POST['nazwisko'] ?? '');
    $address = trim($_POST['adres'] ?? '');
    
    $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);

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

  38. Krok 38: Zapytanie 1 jako zapytanie przygotowane

    Kryteria:

    R.5.4 Skrypt wysyła do bazy danych zapytanie 1 wstawiające dane do bazy: pola data_zezwolenia i punkty = NULL, pozostałe wartości wypełnione są danymi z formularza. Należy sprawdzić w bazie czy rekord został dodany

    ok. 3 min
    Polecenie z arkusza

    Skrypt wysyła do bazy danych zmodyfikowane zapytanie 1, które w polach data_zezwolenia i punkty zawiera wartość NULL, pozostałe wartości wypełnione są danymi z formularza

    Zapytanie 1, w którym dane z formularza zastępują parametry :imie, :nazwisko, :adres, a datę i punkty - NULL:

    • $pdo->prepare(...) - baza dostaje samą treść zapytania,
    • $statement->execute([...]) - osobno przychodzą wartości parametrów.

    Dane nigdy nie staną się kodem SQL: nazwisko O'Brien zapisuje się bez błędu, a wpisany w pole fragment zapytania zostaje zwykłym tekstem jednego rekordu. Sprawdzenie, jak każe klucz (R.5.4): formularz z danymi Marek, Lis, „Sopot, Morska 3” i w tabeli nowy wiersz 3 z NULL w kolumnach data_zezwolenia i punkty.

    Typowe błędy

    Tabela z archiwum ma kodowanie latin1 - litery ą, ć, ę, ł, ń, ś, ź, ż zapisują się jako „?” także przez PDO z charset=utf8mb4. Klucz sprawdza import pliku bez zmian, więc kodowania tabeli nie zmieniasz.

    zapisz.php PHP zmienione: 6 linii
    <?php
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $firstName = trim($_POST['imie'] ?? '');
    $lastName = trim($_POST['nazwisko'] ?? '');
    $address = trim($_POST['adres'] ?? '');
    
    $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    ]);
    $statement = $pdo->prepare('INSERT INTO karty_wedkarskie VALUES (NULL, :imie, :nazwisko, :adres, NULL, NULL);');
    $statement->execute([
        'imie' => $firstName,
        'nazwisko' => $lastName,
        'adres' => $address,
    ]);
    Podgląd strony po tym kroku (karta.html)
    Podgląd strony po kroku 38
  39. Krok 39: Obsługa błędów i zamknięcie połączenia w finally

    Kryteria:

    R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)

    ok. 3 min
    Polecenie z arkusza

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

    Połączenie i zapis trafiają do bloku try:

    • catch (PDOException $exception) - gdy baza nie działa albo zapytanie się nie powiedzie, skrypt ustawia zwykłe zdanie dla użytkownika zamiast komunikatu PHP z danymi serwera,
    • finally wykonuje się zawsze - po udanym zapisie i po wyjątku. Stoją w nim $statement = null i $pdo = null: PDO nie ma funkcji close, połączenie zamyka się, gdy znika ostatnie odwołanie do obiektu. Zamknięcie jest więc ostatnią operacją na bazie w każdej gałęzi (R.5.2).

    Zmienna $message z komunikatem dla użytkownika - udany zapis albo błąd - wyświetli się na stronie w następnym kroku.

    zapisz.php PHP zmienione: 17 linii
    <?php
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $firstName = trim($_POST['imie'] ?? '');
    $lastName = trim($_POST['nazwisko'] ?? '');
    $address = trim($_POST['adres'] ?? '');
    
    $message = 'Zapisano zgłoszenie na kartę wędkarską: ' . $firstName . ' ' . $lastName . '.';
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
        $statement = $pdo->prepare('INSERT INTO karty_wedkarskie VALUES (NULL, :imie, :nazwisko, :adres, NULL, NULL);');
        $statement->execute([
            'imie' => $firstName,
            'nazwisko' => $lastName,
            'adres' => $address,
        ]);
    } catch (PDOException $exception) {
        $message = 'Nie udało się zapisać zgłoszenia, spróbuj ponownie za chwilę.';
    } finally {
        $statement = null;
        $pdo = null;
    }

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

  40. Krok 40: Strona z potwierdzeniem i funkcja e()

    ok. 3 min

    Dodatek spoza arkusza - klucz go nie ocenia. Wersja podstawowa po zapisie pokazuje pustą stronę i użytkownik nie wie, czy coś się stało. Tu pod skryptem stoi krótka strona w tym samym wyglądzie (te same header, main i styl_1.css) z komunikatem i odnośnikiem z powrotem do formularza.

    Komunikat zawiera imię i nazwisko wpisane przez użytkownika, więc przed wypisaniem przechodzi przez e() - krótką funkcję z htmlspecialchars. Sprawdzone: imię <b>Ola</b> wyświetla się dosłownie jako tekst ze znacznikami, a nie jako pogrubienie - tak samo nie wykona się wpisany w pole <script>. Gdy baza nie odpowiada (sprawdzone na złym haśle), strona pokazuje zdanie z catch, bez nazwy serwera i treści błędu. Podgląd: strona po zapisaniu karty Marka Lisa.

    zapisz.php PHP zmienione: 25 linii
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $firstName = trim($_POST['imie'] ?? '');
    $lastName = trim($_POST['nazwisko'] ?? '');
    $address = trim($_POST['adres'] ?? '');
    
    $message = 'Zapisano zgłoszenie na kartę wędkarską: ' . $firstName . ' ' . $lastName . '.';
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
        $statement = $pdo->prepare('INSERT INTO karty_wedkarskie VALUES (NULL, :imie, :nazwisko, :adres, NULL, NULL);');
        $statement->execute([
            'imie' => $firstName,
            'nazwisko' => $lastName,
            'adres' => $address,
        ]);
    } catch (PDOException $exception) {
        $message = 'Nie udało się zapisać zgłoszenia, spróbuj ponownie za chwilę.';
    } finally {
        $statement = null;
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <p><?= e($message) ?></p>
            <a href="karta.html">Wróć do formularza</a>
        </main>
    </body>
    </html>
    Podgląd strony po tym kroku (zapisz.php)
  41. Krok 41: Puste pola nie trafiają do bazy

    ok. 2 min

    Pola mają required, ale to zabezpieczenie przeglądarki - dane da się wysłać z pominięciem formularza (np. poleceniem curl albo po usunięciu atrybutu w narzędziach przeglądarki). Dlatego skrypt sprawdza je jeszcze raz: gdy po trim() któreś pole jest puste, zamiast zapisu ustawia komunikat „Wypełnij wszystkie pola formularza.” i w ogóle nie łączy się z bazą. Porównanie === '' zamiast empty() - empty('0') jest prawdziwe, więc adres „0” uznano by za puste pole.

    Sprawdzone: nazwisko z samych spacji nie dodaje rekordu. Podgląd: ten przypadek.

    zapisz.php PHP zmienione: 20 linii
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        header('Location: karta.html');
        exit;
    }
    
    $firstName = trim($_POST['imie'] ?? '');
    $lastName = trim($_POST['nazwisko'] ?? '');
    $address = trim($_POST['adres'] ?? '');
    
    if ($firstName === '' || $lastName === '' || $address === '') {
        $message = 'Wypełnij wszystkie pola formularza.';
    } else {
        $message = 'Zapisano zgłoszenie na kartę wędkarską: ' . $firstName . ' ' . $lastName . '.';
        try {
            $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            ]);
            $statement = $pdo->prepare('INSERT INTO karty_wedkarskie VALUES (NULL, :imie, :nazwisko, :adres, NULL, NULL);');
            $statement->execute([
                'imie' => $firstName,
                'nazwisko' => $lastName,
                'adres' => $address,
            ]);
        } catch (PDOException $exception) {
            $message = 'Nie udało się zapisać zgłoszenia, spróbuj ponownie za chwilę.';
        } finally {
            $statement = null;
            $pdo = null;
        }
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <p><?= e($message) ?></p>
            <a href="karta.html">Wróć do formularza</a>
        </main>
    </body>
    </html>
    Podgląd strony po tym kroku (zapisz.php)
  42. Krok 42: Odświeżenie po zapisie nie dodaje drugiej karty

    ok. 4 min

    Strona z potwierdzeniem jest wynikiem żądania POST, więc odświeżenie (F5) pyta, czy wysłać dane ponownie - a ponowne wysłanie dopisałoby drugą identyczną kartę. Wzorzec PRG (Post/Redirect/Get):

    • session_start() na początku pliku - sesja przechowa komunikat między dwoma żądaniami,
    • po udanym zapisie ($saved = true ustawiane zaraz po execute) i po bloku finally komunikat trafia do $_SESSION, a header('Location: zapisz.php') z exit każe przeglądarce otworzyć skrypt jeszcze raz zwykłym żądaniem GET,
    • żądanie GET z komunikatem w sesji wyświetla go i od razu usuwa (unset); GET bez komunikatu - jak wcześniej - wraca do formularza.

    Sprawdzone na prawdziwym PHP: wysłanie formularza daje odpowiedź 302, potem stronę z potwierdzeniem, a kolejne odświeżenie - powrót do formularza, bez drugiego rekordu w tabeli. Błąd (puste pole) nie przekierowuje - komunikat zostaje na stronie. Podgląd: stan po przekierowaniu.

    zapisz.php PHP zmienione: 41 linii
    <?php
    session_start();
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        // po przekierowaniu: komunikat zapisany w sesji wyświetla się jeden raz
        if (!isset($_SESSION['message'])) {
            header('Location: karta.html');
            exit;
        }
        $message = $_SESSION['message'];
        unset($_SESSION['message']);
    } else {
        $firstName = trim($_POST['imie'] ?? '');
        $lastName = trim($_POST['nazwisko'] ?? '');
        $address = trim($_POST['adres'] ?? '');
    
        if ($firstName === '' || $lastName === '' || $address === '') {
            $message = 'Wypełnij wszystkie pola formularza.';
        } else {
            $saved = false;
            $message = 'Zapisano zgłoszenie na kartę wędkarską: ' . $firstName . ' ' . $lastName . '.';
            try {
                $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                ]);
                $statement = $pdo->prepare('INSERT INTO karty_wedkarskie VALUES (NULL, :imie, :nazwisko, :adres, NULL, NULL);');
                $statement->execute([
                    'imie' => $firstName,
                    'nazwisko' => $lastName,
                    'adres' => $address,
                ]);
                $saved = true;
            } catch (PDOException $exception) {
                $message = 'Nie udało się zapisać zgłoszenia, spróbuj ponownie za chwilę.';
            } finally {
                $statement = null;
                $pdo = null;
            }
    
            if ($saved) {
                // PRG: komunikat do sesji i przekierowanie - odświeżenie strony nie zapisze karty drugi raz
                $_SESSION['message'] = $message;
                header('Location: zapisz.php');
                exit;
            }
        }
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Karty wędkarskie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h2>Zgłoszenie na kartę wędkarską</h2>
        </header>
        <main>
            <h4>Formularz - karta wędkarska</h4>
            <p><?= e($message) ?></p>
            <a href="karta.html">Wróć do formularza</a>
        </main>
    </body>
    </html>
    Podgląd strony po tym kroku (zapisz.php)
  43. Etap 5: Porównanie z wersją podstawową

    Krok 43 · po tym etapie masz 31 z 31 kryteriów (pkt)

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

    ok. 3 min

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

    wersja podstawowawersja nowoczesna
    blokiheader i cztery section z idheader, main, trzy section z klasami
    dolny rządfloat: left na blokachkontener display: flex, width na blokach
    kolorywpisane w każdej regulezmienne --blue, --light-blue
    formularznapis, <br>, pole, input type="reset"label for, wiersze w div, button, required, autocomplete
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami
    wejście bez formularzaostrzeżenia PHP i pusty rekordprzekierowanie do formularza
    INSERTdane wklejone w treść zapytaniaparametry :imie, :nazwisko, :adres
    puste polazapisują siękomunikat, bez połączenia z bazą
    zamknięcie bazymysqli_close na końcu$pdo = null w finally
    po zapisiepusta strona, F5 dodaje drugą kartępotwierdzenie, przekierowanie

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 i łatwiej ją napisać bez dokumentacji. Nowoczesna nie wywraca się na apostrofie, nie zapisuje pustych kart i nie dubluje ich po odświeżeniu - a klucz przyjmuje obie. Na prawdziwym serwerze skrypt nie łączyłby się kontem root bez hasła, tylko kontem z prawem INSERT do jednej tabeli, a dane logowania leżałyby w osobnym pliku poza katalogiem strony.

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

  44. Etap 6: Oddanie pracy

    Krok 44 · po tym etapie masz 31 z 31 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    UWAGA: po zakończeniu pracy utwórz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowano poprawność działania witryny. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. W folderze z numerem zdającego: import.png, karta.html, kw1.jpg - kw4.jpg, kwerendy.txt, przeglądarka.txt, styl_1.css, wedka.jpg i zapisz.php. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.

Potwierdzenie

Informacja