Przejdź do głównej treści
EE.09-02-21.01-SGStyczeń 2021 · 34 kroki · ok. 75 min · 38 kryteriów z klucza

Rozwiązanie krok po kroku: Liga piłkarska i skład reprezentacji (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza egzamin z czterema zapytaniami, przeskalowana grafika z piłką i strona liga.php z listą zawodników wybranej pozycji i blokami drużyn Ligi Mistrzów - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • flex zamiast float: bloki lewy i prawy stoją w pojemniku z display: flex, a blok liga sam układa bloki drużyn w rzędzie i zawija je do nowej linii - bez clear,
  • zmienne CSS dla kolorów z arkusza, klasa dla bloku z drużyną, opis listy rozwijalnej dla czytników ekranu,
  • PHP na PDO na górze pliku liga.php, przed HTML-em: najpierw pobranie danych, potem HTML tylko je wypisuje (szablon foreach / endforeach),
  • zapytanie przygotowane dla numeru pozycji z formularza, sprawdzenie, że to liczba 1-4, i htmlspecialchars przy każdym wypisaniu danych,
  • wybrana pozycja zostaje zaznaczona na liście po wysłaniu formularza.

To arkusz EE.09 ze stycznia 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i grafiki pochodzą z oryginalnego archiwum CKE z2.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.

Jak liczą się punkty. Klucz ma 38 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 29 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz nie narzuca biblioteki PHP do obsługi bazy.

  1. Etap 1: Baza danych

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

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

    ok. 2 min
    Polecenie z arkusza

    Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie z2.zip zabezpieczone hasłem: $piLkaRze% Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Umieść w tym folderze rozpakowane pliki. Po skończonej pracy wyniki zapisz również w tym folderze.

    Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum z2.zip rozpakowane z hasłem $piLkaRze% (wielkie L i R). W środku: egzamin.sql, obraz1.jpg i zad2.png. Do tego folderu trafiają wszystkie rezultaty pracy.

  2. Krok 2: XAMPP i pusta baza egzamin

    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 egzamin

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

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

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych egzamin , czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 3 min
    Polecenie z arkusza

    Do bazy egzamin zaimportuj plik egzamin.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL, 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 egzamin zaznaczona, karta Import, plik egzamin.sql, Wykonaj. Plik tworzy osiem tabel - cztery z obrazu 1 i cztery niepotrzebne w zadaniu (typy, uslugi, wyniki, zdjecia). Zrzut całego ekranu z komunikatem o sukcesie i listą tabel: import.png.

    Typowe błędy

    Zrzut importu w PNG, zrzuty zapytań w JPG - zły format to strata punktu.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: napastnicy

    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 wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisano id pozycji równe 4 . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 4; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 2 rekordy: Arkadiusz Milik, Adam Buksa

    ok. 3 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie egzamin. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie JPG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisane jest id pozycji równe 4

    Każda klauzula w osobnej linii - zapytanie czyta się jak zdanie: co (SELECT imie, nazwisko - „jedynie” wyklucza *), skąd (FROM zawodnik), które wiersze (WHERE pozycja_id = 4, „id pozycji” to klucz obcy do tabeli pozycja). Wynik: Arkadiusz Milik i Adam Buksa. Zapytanie trafia do kwerendy.txt, zrzut do kw1.jpg. W skrypcie 1 w miejscu 4 stanie parametr z listy.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 4;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: tabela ligi według punktów

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola zespol, punkty, grupa z tabeli liga sortowane malejąco według punktów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie sześć rekordów: dla zespołów EVG, ARS, FCB, CHL, JUV, RM, jedynie kolumny zespol, punkty, grupa

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola zespol, punkty, grupa z tabeli liga sortowane malejąco według punktów

    ORDER BY punkty DESC - od największej liczby punktów. Wynik: sześć drużyn od EVG (34) do RM (5), zrzut kw2.jpg. To zapytanie wykona skrypt 2.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 4;
    
    -- Zapytanie 2
    SELECT zespol, punkty, grupa
    FROM liga
    ORDER BY punkty DESC;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: zawodnicy 3 i 5 z nazwą pozycji

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pola id, nazwisko z tabeli zawodnik, oraz nazwę z tabeli pozycja dla zawodników, których id jest równe 3 lub 5. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zawodnik.id, nazwisko, pozycja.nazwa FROM zawodnik JOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.id=3 OR zawodnik.id=5; lub SELECT zawodnik.id, nazwisko, pozycja.nazwa FROM zawodnik, pozycja WHERE zawodnik.pozycja_id = pozycja.id AND (zawodnik.id=3 OR zawodnik.id=5); (nawias wymagany) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dwa rekordy, jedynie pola id, nazwisko, nazwa, dla id = 3 oraz id = 5

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola id, nazwisko z tabeli zawodnik oraz nazwę z tabeli pozycja dla zawodników, których id jest równe 3 lub 5

    Złączenie z aliasami tabel: zawodnik AS z i pozycja AS p - krótsze nazwy, a z.id jednoznacznie wskazuje kolumnę id zawodnika (jest w obu tabelach). JOIN … ON p.id = z.pozycja_id dołącza do zawodnika jego pozycję, a IN (3, 5) to krótszy zapis warunku z.id = 3 OR z.id = 5 - nie wymaga nawiasów przy łączeniu z innymi warunkami. Wynik: 3 Bednarek obronca, 5 Grosicki pomocnik - zrzut kw3.jpg.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 4;
    
    -- Zapytanie 2
    SELECT zespol, punkty, grupa
    FROM liga
    ORDER BY punkty DESC;
    
    -- Zapytanie 3
    SELECT z.id, z.nazwisko, p.nazwa
    FROM zawodnik AS z
    JOIN pozycja AS p ON p.id = z.pozycja_id
    WHERE z.id IN (3, 5);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: wyczyszczenie tabeli rozgrywka

    Kryteria:

    R.1.6 Utworzono zapytanie 4 usuwające za pomocą jednej kwerendy SQL wszystkie dane z tabeli rozgrywka (sama tabela nie jest usuwana). W pliku z kwerendami lub na zrzucie istnieje zapis np.: TRUNCATE rozgrywka; lub DELETE FROM rozgrywka; oraz wynik działania zapytania udokumentowano zrzutem z widocznym poprawnym zapytaniem lub pustą tabelą rozgrywka

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: usuwające jedną kwerendą SQL wszystkie dane z tabeli rozgrywka (sama tabela nie jest usuwana)

    TRUNCATE TABLE rozgrywka; usuwa wszystkie wiersze, tabela zostaje pusta (klucz przyjmuje też DELETE FROM rozgrywka;). DROP TABLE usunąłby tabelę - arkusz tego zabrania. Zrzut kw4.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 4;
    
    -- Zapytanie 2
    SELECT zespol, punkty, grupa
    FROM liga
    ORDER BY punkty DESC;
    
    -- Zapytanie 3
    SELECT z.id, z.nazwisko, p.nazwa
    FROM zawodnik AS z
    JOIN pozycja AS p ON p.id = z.pozycja_id
    WHERE z.id IN (3, 5);
    
    -- Zapytanie 4
    TRUNCATE TABLE rozgrywka;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-18 · po tym etapie masz 17 z 38 kryteriów (pkt)

    Krok 8: Grafika zad2.png: szerokość 50 px z przezroczystością

    Kryteria:

    R.2.1 Plik zad2.png przeskalowano z zachowaniem proporcji do szerokości 50 px, odpowiadająca temu wysokość wynosi 71 px (± 5 px); przezroczystość została zachowana

    ok. 2 min
    Polecenie z arkusza

    Plik zad2.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 50 px. Należy zachować przezroczystość obrazu

    GIMP: Obraz → Skaluj obraz, łańcuch zamknięty, szerokość 50 px - wysokość wychodzi 71 px (589 × 50 / 414). Eksport jako PNG, który zachowuje kanał alfa - tło zostaje przezroczyste.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik liga.php: szkielet HTML5

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie liga.php

    Plik liga.php od razu z kompletnym nagłówkiem dokumentu: <!DOCTYPE html> (HTML5), lang="pl" (język treści) i znacznik viewport - na telefonie strona nie będzie pomniejszana do rozmiaru ekranu komputera. Kolejne trzy linie <head> to osobne wymagania arkusza, opisane w następnych krokach.

    liga.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  10. Krok 10: Kodowanie polskich znaków

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie liga oraz zastosowano właściwy 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 pierwszy element <head>, plik zapisany w UTF-8. Razem z nazwą pliku: R.2.2.

    liga.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>

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

  11. Krok 11: Tytuł strony

    Kryteria:

    R.2.3 Nadano tytuł strony: "piłka nożna”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „piłka nożna”

    <title>piłka nożna</title> - małymi literami, jak w arkuszu.

    liga.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>

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

  12. Krok 12: Podpięcie arkusza stylów styl2.css

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

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

    <link rel="stylesheet" href="styl2.css"> - nazwa z cyfrą 2; całe formatowanie strony pochodzi z tego pliku (R.3.4).

    liga.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>

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

  13. Krok 13: Bloki strony i pojemnik na dwie kolumny

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: baner, blok lewy i prawy, blok główny, blok liga zawierający zmienną liczbę bloków z informacją o drużynach. Bloki informacyjne generowane są skryptem, ich liczba zależy od liczby rekordów. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2

    Pięć bloków z arkusza to znaczniki <section> z identyfikatorami banner, left, right, main, league. Bloki lewy i prawy stoją dodatkowo w <div class="columns"> - pojemniku bez znaczenia treściowego (dlatego div, nie section), który w CSS dostanie display: flex i ustawi oba bloki obok siebie. Bloki z drużynami wygeneruje skrypt wewnątrz #league.

    liga.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
        </section>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
        <section id="main">
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  14. Krok 14: Baner: nagłówek i zdjęcie reprezentacji

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku banera: Nagłówek trzeciego stopnia o treści „Reprezentacja polski w piłce nożnej”. Obraz obraz1.jpg z tekstem alternatywnym o treści: „reprezentacja”

    <h3> i <img> z tekstem alternatywnym. Atrybuty width i height z prawdziwym rozmiarem zdjęcia (930 × 272) pozwalają przeglądarce zarezerwować miejsce, zanim plik się wczyta - treść poniżej nie „podskakuje”.

    liga.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>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
        <section id="main">
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  15. Krok 15: Formularz z listą rozwijalną i przyciskiem „Zobacz”

    Kryteria: , , ,

    R.2.7 W bloku lewym umieszczono formularz, zastosowano znacznik <form> oraz jego zamknięcie

    R.2.8 W formularzu umieszczono listę rozwijalną z czterema elementami oraz przycisk "Zobacz"

    R.3.2 Przycisk wysyła dane z formularza

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

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku lewego: Formularz wysyłający dane metodą POST do tej samej strony, zawierający: Listę rozwijalną z wpisami: Bramkarze, Obrońcy, Pomocnicy, Napastnicy. Przycisk wysyłający zawartość formularza z opisem „Zobacz”

    • <form method="post"> bez action - dane wracają do liga.php (R.2.7, R.3.3),
    • <select> z czterema <option>: tekst widzi użytkownik, a value z numerem 1-4 (jak id w tabeli pozycja) trafia do PHP,
    • aria-label - arkusz nie przewiduje widocznego opisu listy, więc opis „Pozycja zawodników” dostaje tylko czytnik ekranu; wygląd zostaje jak na obrazie 2,
    • <button type="submit"> - przycisk z napisem jako treścią znacznika; działa tak samo jak <input type="submit"> (R.2.8, R.3.2).
    liga.php PHP zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
            </section>
            <section id="right">
            </section>
        </div>
        <section id="main">
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  16. Krok 16: Blok lewy: grafika i autor

    Kryteria:

    R.2.6 W bloku banera umieszczono obraz obraz1.jpg oraz w bloku lewym umieszczono obraz zad2.png. Przynajmniej jeden z obrazów ma tekst alternatywny: "reprezentacja" (dla obraz1.jpg ) lub "piłka" (dla zad2.png ) gdy obraz nie istnieje powinien wyświetlić się tekst alternatywny

    ok. 1 min
    Polecenie z arkusza

    Obraz zad2.png z tekstem alternatywnym o treści: „piłka”. Paragraf (akapit) o treści: „Autor: ”, dalej wstawiony numer PESEL zdającego

    Przeskalowany zad2.png z tekstem alternatywnym i wymiarami (oba obrazy z alt: R.2.6) oraz akapit z autorem - na egzaminie numer PESEL, tutaj Bartosz Bryniarski.

    liga.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>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
            </section>
        </div>
        <section id="main">
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  17. Krok 17: Blok prawy: lista numerowana na wynik skryptu 1

    Kryteria:

    R.2.9 W bloku prawym umieszczono listę numerowaną, zapisano znaczniki <ol>, <li> oraz ich zamknięcia (generowaną skryptem lub HTML)

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Lista numerowana (uporządkowana) a w niej efekt działania skryptu 1

    <ol> - zawodników wybranej pozycji wypisze skrypt 1 (R.2.9).

    liga.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>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
                </ol>
            </section>
        </div>
        <section id="main">
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  18. Krok 18: Blok główny: nagłówek „Liga mistrzów”

    Kryteria:

    R.2.5 W bloku banera zapisano nagłówek h3: "Reprezentacja polski w piłce nożnej", w bloku głównym nagłówek h3: "Liga mistrzów" oraz zapisano paragraf z numerem PESEL

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: nagłówek trzeciego stopnia o treści: „Liga mistrzów”. Zawartość bloku liga: Efekt działania skryptu 2

    Drugi <h3>. Oba nagłówki i paragraf z autorem: R.2.5. Blok liga zostaje pusty do kroku ze skryptem 2.

    liga.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>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  19. Etap 3: Styl CSS

    Kroki 19-25 · po tym etapie masz 28 z 38 kryteriów (pkt)

    Krok 19: Zmienne z kolorami i styl body

    Kryteria:

    R.4.1 Ustawiono krój czcionki Verdana dla selektora body lub kontenera całej strony

    ok. 2 min
    Polecenie z arkusza

    Dla znacznika body: krój czcionki Verdana, kolor tła SeaGreen

    Na początku styl2.css trzy zmienne CSS w :root (cały dokument): kolor strony, kolor szarych bloków i biel. Nazwa zmiennej zaczyna się od dwóch myślników, a odczytuje się ją funkcją var(). Zmiana koloru w jednym miejscu zmienia go na całej stronie - biel występuje w czterech regułach.

    body dostaje krój Verdana i tło var(--page), czyli SeaGreen (R.4.1).

    styl2.css CSS nowy plik
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    Podgląd strony po tym kroku (liga.php)
  20. Krok 20: Baner: biały tekst, wyśrodkowanie, wysokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloku banera: biały kolor czcionki, wyrównanie tekstu do środka, wysokość 330 px

    #banner z białym tekstem, wyśrodkowaniem i wysokością 330 px.

    styl2.css CSS zmienione: 5 linii
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    Podgląd strony po tym kroku (liga.php)
  21. Krok 21: Blok z drużyną: klasa team

    Kryteria: ,

    R.4.7 Ustawiono dla pojedynczego bloku z informacją o drużynach marginesy zewnętrzne (margin) 5px, biały kolor czcionki, szerokość 170px, wyrównanie tekstu do środka

    R.4.8 Ustawiono obramowanie o szerokości 1px linią ciągłą, białą oraz nadano zaokrąglenie rogów ramki 15px (border-radius) dla pojedynczego bloku z informacją o drużynach

    ok. 2 min
    Polecenie z arkusza

    Dla pojedynczego bloku z informacją o drużynach: biały kolor czcionki, wyrównanie tekstu do środka, szerokość 170 px, marginesy zewnętrzne 5 px, obramowanie: 1 px, linia ciągła, kolor biały, zaokrąglenie rogów obramowania 15 px

    Skrypt 2 nada każdemu blokowi z drużyną klasę team - selektor .team mówi wprost, czego dotyczy, i nie zależy od tego, gdzie blok stoi. Wszystkie cechy z arkusza w jednej regule: biały tekst, wyśrodkowanie, 170 px szerokości, 5 px marginesu (R.4.7), ramka 1px solid w kolorze var(--light) i zaokrąglenie 15 px (R.4.8).

    styl2.css CSS zmienione: 8 linii
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    .team {
        color: var(--light);
        text-align: center;
        width: 170px;
        margin: 5px;
        border: 1px solid var(--light);
        border-radius: 15px;
    }
    Podgląd strony po tym kroku (liga.php)
  22. Krok 22: Biały blok z czarnym tekstem po najechaniu kursorem

    Kryteria:

    R.4.9 W momencie najechania kursorem na pojedynczy blok z informacją o drużynach kolor jego tła zmienia się na biały, a czcionki na czarny (np. ustawiony kolor dla pseudoklasy hover lub inne rozwiązania)

    ok. 1 min
    Polecenie z arkusza

    W momencie najechania kursorem na pojedynczy blok z informacją o drużynach, kolor tła zmienia się na biały a kolor czcionki na czarny

    .team:hover - tło białe, tekst czarny tylko wtedy, gdy kursor jest nad blokiem (R.4.9).

    styl2.css CSS zmienione: 4 linie
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    .team {
        color: var(--light);
        text-align: center;
        width: 170px;
        margin: 5px;
        border: 1px solid var(--light);
        border-radius: 15px;
    }
    .team:hover {
        background-color: var(--light);
        color: black;
    }
    Podgląd strony po tym kroku (liga.php)
  23. Krok 23: Bloki główny, lewy i prawy

    Kryteria: , , ,

    R.4.2 Ustawiono kolor tła SeaGreen dla selektora body lub kontenera całej strony oraz WhiteSmoke dla bloku lewego i prawego

    R.4.3 Ustawiono biały kolor czcionki dla banera i bloku głównego

    R.4.4 Ustawiono wysokość banera na 330px, bloku lewego i prawego: 150px

    R.4.5 Ustawiono szerokość bloku lewego na 30% i prawego na 70%

    ok. 2 min
    Polecenie z arkusza

    Dla bloku głównego: biały kolor czcionki. Dla bloku lewego: kolor tła WhiteSmoke, szerokość 30%, wyrównanie tekstu do środka, wysokość 150 px. Dla bloku prawego: kolor tła WhiteSmoke, szerokość 70%, wysokość 150 px

    Blok główny tylko z białym tekstem (biel banera i bloku głównego: R.4.3). Bloki lewy i prawy z tłem var(--panel) (WhiteSmoke, R.4.2) i wysokością 150 px (R.4.4). Szerokości 30% i 70% zostają na blokach - tak je sprawdza klucz (R.4.5).

    styl2.css CSS zmienione: 14 linii
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    .team {
        color: var(--light);
        text-align: center;
        width: 170px;
        margin: 5px;
        border: 1px solid var(--light);
        border-radius: 15px;
    }
    .team:hover {
        background-color: var(--light);
        color: black;
    }
    #main {
        color: var(--light);
    }
    #left {
        background-color: var(--panel);
        width: 30%;
        text-align: center;
        height: 150px;
    }
    #right {
        background-color: var(--panel);
        width: 70%;
        height: 150px;
    }
    Podgląd strony po tym kroku (liga.php)
  24. Krok 24: Nagłówki h3: wyśrodkowanie, odstęp liter, wielkie litery

    Kryteria: ,

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera, bloku lewego i selektora h3

    R.4.10 Ustawiono styl selektora h3: odległość między literami 6px (letter-spacing) oraz kapitaliki (np. text-transform: capitalize; lub font-variant: small-caps;)

    ok. 2 min
    Polecenie z arkusza

    Dla znacznika nagłówka trzeciego stopnia: wyrównanie tekstu do środka, odległość między literami 6 px, tekst napisany kapitalikami (capitalize)

    text-align: center (razem z banerem i blokiem lewym: R.4.6), letter-spacing: 6px i text-transform: capitalize - wielka pierwsza litera każdego słowa, jak na obrazie 2 (R.4.10).

    ⚠️ Uwaga o nazewnictwie: „kapitaliki” to w typografii font-variant: small-caps, ale arkusz w nawiasie i obraz 2 wskazują capitalize. Klucz przyjmuje obie właściwości.

    styl2.css CSS zmienione: 5 linii
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    .team {
        color: var(--light);
        text-align: center;
        width: 170px;
        margin: 5px;
        border: 1px solid var(--light);
        border-radius: 15px;
    }
    .team:hover {
        background-color: var(--light);
        color: black;
    }
    #main {
        color: var(--light);
    }
    #left {
        background-color: var(--panel);
        width: 30%;
        text-align: center;
        height: 150px;
    }
    #right {
        background-color: var(--panel);
        width: 70%;
        height: 150px;
    }
    h3 {
        text-align: center;
        letter-spacing: 6px;
        text-transform: capitalize;
    }
    Podgląd strony po tym kroku (liga.php)
  25. Krok 25: Układ bloków na flexie

    Kryteria:

    R.3.1 Widok układu bloków po uruchomieniu strony w przeglądarce jest w pełni zgodny z obrazem 2 w arkuszu egzaminacyjnym (nie należy brać pod uwagę bloków zawierających informacje o drużynach)

    ok. 3 min
    Polecenie z arkusza

    Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2

    Dwie reguły zamiast float i clear:

    • .columns { display: flex; } - blok lewy (30%) i prawy (70%) obok siebie, oba o wysokości 150 px. Pojemnik otacza oba bloki, więc blok główny sam staje pod nimi - bez clear,
    • #league { display: flex; flex-wrap: wrap; } - blok liga układa swoje dzieci (bloki z drużynami) w rzędzie, a gdy się nie mieszczą, zawija je do nowej linii.

    Podgląd: kolumny stoją obok siebie, nagłówek „Liga Mistrzów” pod nimi; bloki drużyn dojdą ze skryptem 2 (R.3.1).

    Typowe błędy

    display: flex na samym #left ustawia w rzędzie jego zawartość (formularz, grafikę, akapit), nie same bloki - flex działa na dzieci elementu, któremu się go nada.

    styl2.css CSS zmienione: 7 linii
    :root {
        --page: SeaGreen;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Verdana;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 330px;
    }
    .team {
        color: var(--light);
        text-align: center;
        width: 170px;
        margin: 5px;
        border: 1px solid var(--light);
        border-radius: 15px;
    }
    .team:hover {
        background-color: var(--light);
        color: black;
    }
    #main {
        color: var(--light);
    }
    #left {
        background-color: var(--panel);
        width: 30%;
        text-align: center;
        height: 150px;
    }
    #right {
        background-color: var(--panel);
        width: 70%;
        height: 150px;
    }
    h3 {
        text-align: center;
        letter-spacing: 6px;
        text-transform: capitalize;
    }
    .columns {
        display: flex;
    }
    #league {
        display: flex;
        flex-wrap: wrap;
    }
    Podgląd strony po tym kroku (liga.php)
  26. Etap 4: Skrypty PHP

    Kroki 26-32 · po tym etapie masz 38 z 38 kryteriów (pkt)

    Krok 26: Skrypt na górze pliku i połączenie przez PDO

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP oraz zawiera on co najmniej jedną instrukcję poprawną składniowo

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

    ok. 4 min
    Polecenie z arkusza

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

    Kod PHP stoi na samej górze liga.php, przed <!DOCTYPE html>: najpierw pobiera dane z bazy do zmiennych, a HTML niżej tylko je wypisuje. Logika i wygląd strony są rozdzielone, a połączenie z bazą jest jedno dla obu skryptów.

    • e() - krótka funkcja z htmlspecialchars: każdy tekst wypisywany na stronie zamienia <, >, & i cudzysłowy na encje, więc nic z bazy ani z formularza nie zamieni się w kod strony,
    • $teams = [] - pusta lista na start: gdy baza nie odpowie, strona i tak się zbuduje,
    • new PDO(...) - serwer localhost, baza egzamin i kodowanie w jednym napisie, potem użytkownik root i puste hasło (R.5.1, R.5.2). ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze jako tablice z nazwami kolumn,
    • try / catch - gdy baza nie działa, zamiast komunikatu PHP z danymi serwera będzie zwykłe zdanie.

    Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    liga.php PHP zmienione: 18 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  27. Krok 27: Skrypt 1: odbiór i sprawdzenie pozycji z listy

    Kryteria:

    R.5.4 W skrypcie działającym na danych przesłanych z formularza zastosowano tablicę $_POST, zapis musi być poprawny składniowo i logicznie

    ok. 3 min
    Polecenie z arkusza

    Działanie skryptu 1, który odbiera dane przesłane z formularza: Odbiera dane z pola listy wyboru. Jeśli nic nie jest wybrane nie jest wykonywana żadna akcja

    • $_POST['position'] ?? '' - wartość wybranego wpisu listy, a gdy formularza nie wysłano - pusty napis zamiast ostrzeżenia (R.5.4),
    • filter_var(…, FILTER_VALIDATE_INT, …) zwraca liczbę tylko wtedy, gdy tekst jest liczbą całkowitą z zakresu 1-4; brak wyboru, abc czy 9 dają false. Lista rozwijalna podsuwa cztery wartości tylko w przeglądarce - dane da się wysłać z pominięciem formularza.

    Podgląd: wysłany wpis „Pomocnicy” (wartość 3) - lista jeszcze pusta.

    liga.php PHP zmienione: 2 linie
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
        </section>
    </body>
    </html>

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

  28. Krok 28: Skrypt 1: zapytanie przygotowane i lista zawodników

    Kryteria: ,

    R.5.5 Skrypt 1 wysyła do bazy danych zmodyfikowane zapytanie 1 tak, że w warunku id pozycji jest zgodne z wyborem w liście rozwijalnej lub Skrypt 2 wysyła do bazy zapytanie 2

    R.5.6 Skrypt 1 wyświetla zwrócone zapytaniem imiona i nazwiska, które zostały przesłane przez formularz

    ok. 4 min
    Polecenie z arkusza

    W innym przypadku skrypt wysyła do bazy danych zmodyfikowane zapytanie 1 tak, że w warunku id pozycji jest zgodne z wyborem w liście. Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy numerowanej

    • if ($position !== false) - zapytanie tylko dla poprawnego numeru pozycji; bez wyboru nic się nie dzieje,
    • $pdo->prepare(…) z parametrem :position w miejscu 4 z zapytania 1, potem execute z wartością - baza dostaje treść zapytania i liczbę osobno, więc tekst z formularza nigdy nie stanie się kodem SQL (R.5.5),
    • w liście szablon foreach ($players as $player): … endforeach; - zapis z dwukropkiem, wygodny między znacznikami HTML; każdy zawodnik jako <li> z paragrafem <p>, każda wartość przez e().

    Podgląd: Pomocnicy - Grzegorz Krychowiak i Kamil Grosicki, jak na obrazie 2 (R.5.6).

    liga.php PHP zmienione: 9 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1">Bramkarze</option>
                        <option value="2">Obrońcy</option>
                        <option value="3">Pomocnicy</option>
                        <option value="4">Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  29. Krok 29: Wybrana pozycja zostaje zaznaczona na liście

    ok. 2 min
    Polecenie z arkusza

    Listę rozwijalną z wpisami: Bramkarze, Obrońcy, Pomocnicy, Napastnicy

    Po wysłaniu formularza strona wczytuje się od nowa i lista wraca do pierwszego wpisu - na obrazie 2 stoi „Bramkarze”, choć lista pokazuje pomocników. Klucz tego nie ocenia, ale to mylące: każdy <option> dostaje atrybut selected, gdy jego numer równa się sprawdzonej pozycji ($position === 3). Porównanie === z liczbą działa, bo filter_var zwraca liczbę całkowitą, a nie tekst.

    Podgląd: po wysłaniu „Pomocnicy” lista pokazuje „Pomocnicy” obok wyniku.

    liga.php PHP zmienione: 4 linie
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1"<?= $position === 1 ? ' selected' : '' ?>>Bramkarze</option>
                        <option value="2"<?= $position === 2 ? ' selected' : '' ?>>Obrońcy</option>
                        <option value="3"<?= $position === 3 ? ' selected' : '' ?>>Pomocnicy</option>
                        <option value="4"<?= $position === 4 ? ' selected' : '' ?>>Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  30. Krok 30: Skrypt 2: zapytanie 2 i blok sekcji dla każdej drużyny

    Kryteria: , ,

    R.5.7 Skrypt 2 definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane zapytaniem dotyczące jednego rekordu

    R.5.9 Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, blok lewy i prawy, blok główny, blok liga zawierający przynajmniej jeden blok z informacją o drużynach (w skrypcie lub HTML). Zastosowano znaczniki sekcji

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 2: Wysyła do bazy danych zapytanie 2. Definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane zapytaniem dotyczące jednego rekordu: W nagłówku drugiego stopnia nazwę zespołu pobraną z bazy danych. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    $pdo->query("…")->fetchAll() wysyła zapytanie 2 i pobiera wszystkie wiersze do tablicy $teams - zapytanie nie ma danych od użytkownika, więc nie musi być przygotowane. W bloku liga szablon foreach ($teams as $team): powtarza <section class="team"> z nagłówkiem <h2> dla każdej drużyny - bloków jest tyle, ile wierszy zwróciła baza (R.5.7, R.5.9). Blok liga ma bloki z informacją o drużynach (R.2.4).

    Podgląd: sześć bloków od EVG do RM, od razu w ramkach i w rzędzie.

    liga.php PHP zmienione: 7 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    
        $teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1"<?= $position === 1 ? ' selected' : '' ?>>Bramkarze</option>
                        <option value="2"<?= $position === 2 ? ' selected' : '' ?>>Obrońcy</option>
                        <option value="3"<?= $position === 3 ? ' selected' : '' ?>>Pomocnicy</option>
                        <option value="4"<?= $position === 4 ? ' selected' : '' ?>>Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
    <?php foreach ($teams as $team): ?>
            <section class="team">
                <h2><?= e($team['zespol']) ?></h2>
            </section>
    <?php endforeach; ?>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  31. Krok 31: Skrypt 2: punkty w h1 i grupa w paragrafie

    Kryteria:

    R.5.8 Skrypt 2 wyświetla dane wg wzoru: nazwa zespołu pobrana skryptem w h2, punkty pobrane skryptem w h1, w paragrafie tekst: „grupa: <grupa>”, gdzie <grupa> oznacza daną pobraną skryptem z bazy danych

    ok. 2 min
    Polecenie z arkusza

    W nagłówku pierwszego stopnia punkty pobrane skryptem. W paragrafie tekst: „grupa: <grupa>”, gdzie <grupa> oznacza daną pobraną skryptem

    Dwie linie szablonu: <h1> z punktami i paragraf „grupa: ” z literą grupy. Kolumny odczytuje się po nazwach ($team['punkty']), a nie po numerach - kolejność kolumn w zapytaniu przestaje mieć znaczenie (R.5.8).

    liga.php PHP zmienione: 2 linie
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    
        $teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1"<?= $position === 1 ? ' selected' : '' ?>>Bramkarze</option>
                        <option value="2"<?= $position === 2 ? ' selected' : '' ?>>Obrońcy</option>
                        <option value="3"<?= $position === 3 ? ' selected' : '' ?>>Pomocnicy</option>
                        <option value="4"<?= $position === 4 ? ' selected' : '' ?>>Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
    <?php foreach ($teams as $team): ?>
            <section class="team">
                <h2><?= e($team['zespol']) ?></h2>
                <h1><?= e($team['punkty']) ?></h1>
                <p>grupa: <?= e($team['grupa']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (liga.php)
  32. Krok 32: Zamknięcie połączenia i komunikat o błędzie bazy

    Kryteria:

    R.5.3 Po wykonaniu operacji na bazie zastosowano funkcję zamknięcia bazy

    ok. 3 min
    Polecenie z arkusza

    Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem

    Blok finally wykonuje się zawsze - po udanych zapytaniach i po błędzie. $statement = null i $pdo = null zamykają połączenie: PDO nie ma osobnej funkcji close, połączenie znika, gdy żadna zmienna go nie trzyma (R.5.3). Połączenie trwa tylko tyle, ile zapytania - HTML wypisuje się już bez niego.

    W bloku liga doszedł warunek wypisujący w paragrafie komunikat $error, gdy baza nie odpowiedziała. Sprawdzone przy niedostępnej bazie: strona się wyświetla, a zamiast drużyn stoi „Nie udało się połączyć z bazą danych.” Podgląd: stan z obrazu 2.

    liga.php PHP zmienione: 6 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    
        $teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    } finally {
        $statement = null;
        $pdo = null;    // zamknięcie połączenia - po ostatniej operacji na bazie
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1"<?= $position === 1 ? ' selected' : '' ?>>Bramkarze</option>
                        <option value="2"<?= $position === 2 ? ' selected' : '' ?>>Obrońcy</option>
                        <option value="3"<?= $position === 3 ? ' selected' : '' ?>>Pomocnicy</option>
                        <option value="4"<?= $position === 4 ? ' selected' : '' ?>>Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
    <?php if ($error !== null): ?>
            <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($teams as $team): ?>
            <section class="team">
                <h2><?= e($team['zespol']) ?></h2>
                <h1><?= e($team['punkty']) ?></h1>
                <p>grupa: <?= e($team['grupa']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
    </body>
    </html>

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

  33. Etap 5: Porównanie z wersją podstawową

    Krok 33 · po tym etapie masz 38 z 38 kryteriów (pkt)

    Krok 33: Co różni tę wersję od podstawowej

    ok. 2 min
    Polecenie z arkusza

    Napisany w języku PHP, w pliku liga.php

    Obie wersje dają tę samą stronę i te same punkty. Różnice:

    • układ: float + clear kontra display: flex - flex nie wymaga pamiętania o clear, a blok liga ma prawdziwą wysokość (otacza bloki drużyn),
    • PHP: mysqli w dwóch blokach w środku HTML-u kontra PDO na górze pliku i szablon foreach / endforeach - kod bazy w jednym miejscu, HTML prawie bez PHP,
    • bezpieczeństwo: w wersji podstawowej wartość z listy trafia do zapytania wprost (wstrzyknięcie 0 OR 1=1 pokazuje wszystkich zawodników, UNION - dane z innej tabeli), tutaj jest sprawdzana (filter_var, zakres 1-4) i przekazywana parametrem zapytania przygotowanego; każdy tekst przechodzi przez htmlspecialchars,
    • wygoda: wybrana pozycja zostaje zaznaczona, lista ma opis dla czytnika ekranu, przycisk to <button>.

    PRG (przekierowanie po wysłaniu formularza) nie jest tu potrzebne: formularz niczego nie zapisuje w bazie, tylko wyszukuje - ponowne wysłanie po odświeżeniu strony niczego nie psuje.

    liga.php PHP zmienione: 0 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $teams = [];
    $players = [];
    $position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        if ($position !== false) {
            $statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');
            $statement->execute(['position' => $position]);
            $players = $statement->fetchAll();
        }
    
        $teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Nie udało się połączyć z bazą danych.';
    } finally {
        $statement = null;
        $pdo = null;    // zamknięcie połączenia - po ostatniej operacji na bazie
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>piłka nożna</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner">
            <h3>Reprezentacja polski w piłce nożnej</h3>
            <img src="obraz1.jpg" alt="reprezentacja" width="930" height="272">
        </section>
        <div class="columns">
            <section id="left">
                <form method="post">
                    <select name="position" aria-label="Pozycja zawodników">
                        <option value="1"<?= $position === 1 ? ' selected' : '' ?>>Bramkarze</option>
                        <option value="2"<?= $position === 2 ? ' selected' : '' ?>>Obrońcy</option>
                        <option value="3"<?= $position === 3 ? ' selected' : '' ?>>Pomocnicy</option>
                        <option value="4"<?= $position === 4 ? ' selected' : '' ?>>Napastnicy</option>
                    </select>
                    <button type="submit">Zobacz</button>
                </form>
                <img src="zad2.png" alt="piłka" width="50" height="71">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
            <section id="right">
                <ol>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ol>
            </section>
        </div>
        <section id="main">
            <h3>Liga mistrzów</h3>
        </section>
        <section id="league">
    <?php if ($error !== null): ?>
            <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($teams as $team): ?>
            <section class="team">
                <h2><?= e($team['zespol']) ?></h2>
                <h1><?= e($team['punkty']) ?></h1>
                <p>grupa: <?= e($team['grupa']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
    </body>
    </html>

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

  34. Etap 6: Oddanie pracy

    Krok 34 · po tym etapie masz 38 z 38 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny, zapisz go w folderze z numerem PESEL, jako przeglądarka.txt. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzasz stronę. W folderze z numerem PESEL: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, liga.php, obraz1.jpg, przeglądarka.txt, styl2.css, zad2.png. Płytę nagrywasz, sprawdzasz jej odczyt i opisujesz numerem PESEL.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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