Przejdź do głównej treści
EE.09-01-25.01-SGStyczeń 2025 · 35 kroków · ok. 76 min · 38 kryteriów z klucza

Rozwiązanie krok po kroku: Rozgrywki futbolowe i reprezentacja Polski (Nowoczesny kod (flex, PDO))

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

  • flex zamiast float: blok mecze jest kontenerem, który sam układa bloki z rozgrywkami w rzędzie i zawija je do nowej linii, a bloki lewy i prawy stoją w pojemniku z display: flex - bez clear,
  • zmienne CSS dla kolorów z arkusza, klasa dla bloku z rozgrywką, etykieta <label> połączona z polem liczbowym,
  • PHP na PDO na górze pliku futbol.php, przed HTML-em: najpierw pobranie danych, potem HTML tylko je wypisuje (szablon foreach / endforeach),
  • zapytanie przygotowane dla liczby z formularza, sprawdzenie, że to numer pozycji 1-4, i htmlspecialchars przy każdym wypisaniu danych,
  • wybrana pozycja zostaje w polu po wysłaniu formularza (na obrazie 2 w polu stoi 4 obok wyniku).

To arkusz EE.09 ze stycznia 2025 - kwalifikacji formuły 2017, którą zastąpiła INF.03 (zadanie powtarza arkusz ze stycznia 2021 z dopisanymi wymaganiami HTML5, jawnego kodowania i języka strony). Archiwum dane.7z tej sesji nie jest opublikowane w materiałach CKE/OKE - baza i grafiki pochodzą z identycznego archiwum CKE z1.zip z pierwszego wydania zadania (arkusz EE.09-01-21.01), 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 przyjmuje zarówno mysqli, jak i PDO.

  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 z materiałami

    ok. 2 min
    Polecenie z arkusza

    Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie dane.7z zabezpieczone hasłem: !Futboi& Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu należy użyć numeru zdającego. Umieść w tym folderze rozpakowane pliki. Po skończonej pracy wyniki zapisz również w tym folderze.

    Folder na pulpicie nazwany numerem zdającego (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum dane.7z rozpakowane 7-Zipem z hasłem !Futboi& (przed ostatnim znakiem litera i). W środku: egzamin.sql, obraz1.jpg i zad1.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 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: mecze drużyny EVG

    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 Wykonano zapytanie 1 wybierające jedynie pola zespol1, zespol2, wynik, data_rozgrywki z tabeli rozgrywka dla wartości pola zespol1 równego „EVG”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = "EVG"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie 5 rekordów, jedynie pola zespol1, zespol2, wynik, data_rozgrywki; w polu zespol1 widnieje tylko "EVG"

    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 zdającego. 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 zespol1, zespol2, wynik, data_rozgrywki z tabeli rozgrywka dla rekordów o wartości pola zespol1 równej „EVG”

    Każda klauzula w osobnej linii - tak zapytanie czyta się jak zdanie: co (SELECT z czterema kolumnami - „jedynie” wyklucza *), skąd (FROM rozgrywka), które wiersze (WHERE zespol1 = 'EVG'). Wynik: 5 meczów, te same co w blokach na obrazie 2. Zapytanie trafia do kwerendy.txt, zrzut do kw1.jpg.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT zespol1, zespol2, wynik, data_rozgrywki
    FROM rozgrywka
    WHERE zespol1 = 'EVG';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: zawodnicy z pozycji 3

    Kryteria:

    R.1.4 Wykonano zapytanie 2 wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisano id pozycji równe 3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 3; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dane: Grzegorz Krychowiak i Kamil Grosicki

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, dla których przypisane jest id pozycji równe 3

    „Id pozycji” to kolumna pozycja_id (klucz obcy do tabeli pozycja). Wynik: Grzegorz Krychowiak i Kamil Grosicki, zrzut kw2.jpg. W skrypcie w miejscu 3 stanie parametr z formularza.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT zespol1, zespol2, wynik, data_rozgrywki
    FROM rozgrywka
    WHERE zespol1 = 'EVG';
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 3;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: zawodnicy z nazwą pozycji

    Kryteria:

    R.1.5 Wykonano zapytanie 3 wybierające jedynie pola id zawodnika, nazwisko, oraz nazwę pozycji z tabel zawodnik i pozycja dla zawodników, których id jest równe 1, 2 lub 3. 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 < 4; (możliwe inne zapisy warunku, INNER JOIN lub bez JOIN - porównanie kluczy w warunku oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie trzy rekordy, jedynie pola id, nazwisko, nazwa, dla id = 1, 2, 3, uwaga: jeżeli zapytanie bez JOIN to alternatywa (OR) obowiązkowo w nawiasie

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola id, nazwisko z tabeli zawodnik oraz nazwę pozycji z tabeli pozycja dla zawodników, którym przypisane jest id równe 1, 2 lub 3

    Złączenie z aliasami tabel: zawodnik AS z i pozycja AS p - krótsze nazwy w całym zapytaniu, 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ę, IN (1, 2, 3) wybiera trzech zawodników. Wynik: 1 Szczesny bramkarz, 2 Pietrzak obronca, 3 Bednarek obronca - zrzut kw3.jpg. Nagłówki kolumn wyniku to id, nazwisko, nazwa: aliasy tabel ich nie zmieniają.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT zespol1, zespol2, wynik, data_rozgrywki
    FROM rozgrywka
    WHERE zespol1 = 'EVG';
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 3;
    
    -- 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 (1, 2, 3);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: usunięcie tabeli liga

    Kryteria:

    R.1.6 Wykonano zapytanie 4 usuwające tabelę liga. W pliku z kwerendami lub na zrzucie istnieje zapis np.: DROP TABLE liga; oraz wynik działania zapytania udokumentowano zrzutem wskazującym na poprawne wykonanie zapytania

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: usuwające tabelę liga

    DROP TABLE liga; usuwa tabelę razem ze strukturą (DELETE i TRUNCATE usuwają tylko wiersze). Potwierdzenie w phpMyAdmin, komunikat „MySQL zwrócił pusty wynik”, zrzut kw4.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT zespol1, zespol2, wynik, data_rozgrywki
    FROM rozgrywka
    WHERE zespol1 = 'EVG';
    
    -- Zapytanie 2
    SELECT imie, nazwisko
    FROM zawodnik
    WHERE pozycja_id = 3;
    
    -- 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 (1, 2, 3);
    
    -- Zapytanie 4
    DROP TABLE liga;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika zad1.png: szerokość 150 px z przezroczystością

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

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

    GIMP: Obraz → Skaluj obraz, łańcuch zamknięty, szerokość 150 px - wysokość wychodzi 165 px (402 × 150 / 366). 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 futbol.php: szkielet HTML5

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie futbol.php. Zapisana w języku HTML 5. Ustawiony język zawartości strony na polski

    Plik futbol.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.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  10. Krok 10: Kodowanie polskich znaków

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie futbol oraz zastosowano jawnie właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwszy element <head> - kodowanie zapisane jawnie w kodzie strony; plik zapisany w UTF-8. Razem z nazwą pliku: R.2.2.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.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: "Rozgrywki futbolowe”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Rozgrywki futbolowe”

    <title>Rozgrywki futbolowe</title> - napis na karcie przeglądarki.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>

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

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

    Kryteria:

    R.3.4 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css, formatowanie CSS 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.css prawidłowo połączony z kodem strony

    <link rel="stylesheet" href="styl.css"> - całe formatowanie strony pochodzi z tego pliku (R.3.4).

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.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

    Kryteria:

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, blok mecze, poniżej blok główny, lewy i prawy. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: baner, poniżej blok mecze zawierający zmienną liczbę bloków z informacją o rozgrywkach. Bloki informacyjne generowane są skryptem, a ich liczba zależy od danych w bazie. Poniżej blok główny, poniżej bloki lewy i prawy. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2

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

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
        </section>
        <section id="matches">
        </section>
        <section id="main">
        </section>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  14. Krok 14: Baner: nagłówek i zdjęcie stadionu

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku banera: Nagłówek drugiego stopnia o treści „Światowe rozgrywki piłkarskie”. Obraz obraz1.jpg z tekstem alternatywnym o treści: „boisko”

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

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
        </section>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  15. Krok 15: Blok główny: nagłówek „Reprezentacja Polski”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku mecze: Efekt działania skryptu 1. Zawartość bloku głównego: nagłówek drugiego stopnia o treści: „Reprezentacja Polski”

    Drugi <h2>. Blok mecze zostaje pusty do kroku ze skryptem 1.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  16. Krok 16: Blok lewy: paragraf jako etykieta pola

    Kryteria:

    R.2.5 W bloku banera zapisano nagłówek h2: "Światowe rozgrywki piłkarskie", w bloku głównym nagłówek h2: "Reprezentacja Polski" oraz zapisano przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Paragraf (akapit) o treści: „Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):”

    Paragraf <p> z arkusza, a jego tekst w <label for="position"> - to opis pola, które za chwilę dostanie id="position". Kliknięcie w tekst ustawia kursor w polu, a czytnik ekranu odczyta opis razem z polem. Oba nagłówki i paragraf: R.2.5.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  17. Krok 17: Formularz z polem liczbowym i przyciskiem „Sprawdź”

    Kryteria: , , ,

    R.2.7 W bloku lewym umieszczono formularz

    R.2.8 Na stronie umieszczono pole edycyjne oraz przycisk "Sprawdź"

    R.3.2 Przycisk wysyła dane z formularza oraz pole do wprowadzania danych jest typu liczbowego

    R.3.3 Formularz wysyła dane metodą POST do tego samego pliku

    ok. 3 min
    Polecenie z arkusza

    Formularz wysyłający dane metodą POST do tej samej strony, zawierający: Pole edycyjne typu numerycznego. Przycisk wysyłający zawartość formularza z opisem „Sprawdź”

    • <form method="post"> bez action - dane wracają do futbol.php (R.2.7, R.3.3),
    • type="number" z min="1" i max="4" - strzałki pola nie wyjdą poza numery pozycji z tabeli pozycja, a przeglądarka podpowie błąd przy innej liczbie. To tylko wygoda: skrypt i tak sprawdzi liczbę sam,
    • <button type="submit"> - przycisk z napisem jako treścią znacznika (przyjąłby też ikonę albo pogrubienie); działa tak samo jak <input type="submit"> (R.2.8, R.3.2).

    Pole nie ma required: arkusz mówi, co ma się stać przy pustym polu (nic), więc puste wysłanie musi być możliwe.

    futbol.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  18. Krok 18: Lista punktowana na wynik skryptu 2

    Kryteria:

    R.2.9 W bloku lewym umieszczono jedną listę punktowaną, zastosowano znaczniki <ul>, <li>, (generowana skryptem lub HTML)

    ok. 1 min
    Polecenie z arkusza

    Lista punktowana (nieuporządkowana), a w niej efekt działania skryptu 2

    <ul> - zawodników wypisze skrypt 2 (R.2.9).

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  19. Krok 19: Blok prawy: grafika i autor

    Kryteria:

    R.2.6 W bloku banera umieszczono obraz obraz1.jpg z tekstem alternatywnym: "boisko" lub w bloku prawym umieszczono obraz z piłkarzem z tekstem alternatywnym: "piłkarz"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Obraz zad1.png z tekstem alternatywnym o treści: „piłkarz”. Paragraf (akapit) o treści: „Autor: ”, dalej wstawiony numer zdającego

    Przeskalowany zad1.png z tekstem alternatywnym (oba obrazy z alt: R.2.6) i akapit z autorem - na egzaminie numer zdającego, tutaj Bartosz Bryniarski.

    futbol.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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  20. Etap 3: Styl CSS

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

    Krok 20: Zmienne z kolorami i styl body

    Kryteria:

    R.4.1 Ustawiono krój czcionki Tahoma dla body

    ok. 2 min
    Polecenie z arkusza

    Dla znacznika body: krój czcionki Tahoma, kolor tła Crimson

    Na początku styl.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 - WhiteSmoke występuje w trzech blokach, biel w trzech regułach.

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

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

    Kryteria:

    R.4.3 Ustawiono biały kolor czcionki dla banera

    ok. 1 min
    Polecenie z arkusza

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

    #banner z białym tekstem, wyśrodkowaniem i wysokością 370 px (R.4.3).

    styl.css CSS zmienione: 5 linii
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    Podgląd strony po tym kroku (futbol.php)
  22. Krok 22: Blok z rozgrywką: klasa match

    Kryteria: ,

    R.4.7 Dla pojedynczego bloku z informacją o rozgrywkach ustawiono: biały kolor czcionki, szerokość 200px, wyrównanie tekstu do środka, marginesy zewnętrzne (margin) 10px

    R.4.8 Dla pojedynczego bloku z informacją o rozgrywkach ustawiono obramowanie o szerokości 1px linią ciągłą, czarną (wartość domyślna nie musi być zapisana) oraz nadano zaokrąglenie rogów ramki 10px (border-radius)

    ok. 2 min
    Polecenie z arkusza

    Dla pojedynczego bloku z informacją o rozgrywkach: biały kolor czcionki, wyrównanie tekstu do środka, szerokość 200 px, marginesy zewnętrzne 10 px, obramowanie: 1 px, linia ciągła, kolor czarny, zaokrąglenie rogów obramowania 10 px

    Skrypt 1 nada każdemu blokowi z meczem klasę match - selektor .match 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, 200 px szerokości, 10 px marginesu (R.4.7), ramka 1px solid black i zaokrąglenie 10 px (R.4.8).

    styl.css CSS zmienione: 8 linii
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    .match {
        color: var(--light);
        text-align: center;
        width: 200px;
        margin: 10px;
        border: 1px solid black;
        border-radius: 10px;
    }
    Podgląd strony po tym kroku (futbol.php)
  23. Krok 23: Biała ramka po najechaniu kursorem

    Kryteria:

    R.4.9 W momencie najechania kursorem na pojedynczy blok z informacją o rozgrywkach kolor jego ramki zmienia się na biały (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 rozgrywkach, kolor jego ramki zmienia się na biały

    .match:hover zmienia tylko border-color - grubość i styl linii zostają (R.4.9).

    styl.css CSS zmienione: 3 linie
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    .match {
        color: var(--light);
        text-align: center;
        width: 200px;
        margin: 10px;
        border: 1px solid black;
        border-radius: 10px;
    }
    .match:hover {
        border-color: var(--light);
    }
    Podgląd strony po tym kroku (futbol.php)
  24. Krok 24: Bloki główny, lewy i prawy

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła Crimson dla body, oraz WhiteSmoke dla bloków głównego, lewego i prawego

    R.4.4 Ustawiono wysokość banera na 370px, bloku głównego: 50px, lewego i prawego: 230px

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

    ok. 2 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła WhiteSmoke, wysokość 50 px. Dla bloku lewego: kolor tła WhiteSmoke, szerokość 70%, wysokość 230 px. Dla bloku prawego: kolor tła WhiteSmoke, szerokość 30%, wysokość 230 px, wyrównanie tekstu do prawej strony

    Trzy reguły z tłem var(--panel) (WhiteSmoke). Szerokości 70% i 30% zostają na blokach - tak je sprawdza klucz (R.4.5). Wysokości banera i trzech bloków (R.4.4), tła (R.4.2) i wyrównanie do prawej w bloku prawym są ustawione.

    styl.css CSS zmienione: 15 linii
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    .match {
        color: var(--light);
        text-align: center;
        width: 200px;
        margin: 10px;
        border: 1px solid black;
        border-radius: 10px;
    }
    .match:hover {
        border-color: var(--light);
    }
    #main {
        background-color: var(--panel);
        height: 50px;
    }
    #left {
        background-color: var(--panel);
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: var(--panel);
        width: 30%;
        height: 230px;
        text-align: right;
    }
    Podgląd strony po tym kroku (futbol.php)
  25. Krok 25: Nagłówki h2: wyśrodkowanie, odstęp liter, wielkie litery

    Kryteria: ,

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera i nagłówka h2 oraz wyrównanie do prawej strony dla bloku prawego

    R.4.10 Ustawiono styl nagłówka h2: odległość między literami (letter-spacing) 7px oraz kapitaliki (text- transform: capitalize;)

    ok. 2 min
    Polecenie z arkusza

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

    text-align: center (R.4.6), letter-spacing: 7px 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 z tej sesji wymienia tylko capitalize.

    styl.css CSS zmienione: 5 linii
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    .match {
        color: var(--light);
        text-align: center;
        width: 200px;
        margin: 10px;
        border: 1px solid black;
        border-radius: 10px;
    }
    .match:hover {
        border-color: var(--light);
    }
    #main {
        background-color: var(--panel);
        height: 50px;
    }
    #left {
        background-color: var(--panel);
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: var(--panel);
        width: 30%;
        height: 230px;
        text-align: right;
    }
    h2 {
        text-align: center;
        letter-spacing: 7px;
        text-transform: capitalize;
    }
    Podgląd strony po tym kroku (futbol.php)
  26. Krok 26: Układ bloków na flexie

    Kryteria:

    R.3.1 Układ 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 generowanych skryptem (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float albo display flex albo grid albo position)

    ok. 3 min
    Polecenie z arkusza

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

    Dwie reguły zamiast float i clear:

    • #matches { display: flex; flex-wrap: wrap; } - blok mecze układa swoje dzieci (bloki z rozgrywkami) w rzędzie, a gdy się nie mieszczą, zawija je do nowej linii. Blok mecze ma przy tym prawdziwą wysokość (otacza bloki), więc blok główny sam staje pod nim - bez clear,
    • .columns { display: flex; } - blok lewy (70%) i prawy (30%) obok siebie. Oba mają podaną wysokość 230 px, więc stoją równo.

    Podgląd: kolumny stoją już obok siebie; bloki meczów dojdą ze skryptem 1 (R.3.1).

    Typowe błędy

    display: flex na samym #left albo #right ustawia w rzędzie ich zawartość, nie same bloki - flex działa na dzieci elementu, któremu się go nada.

    styl.css CSS zmienione: 7 linii
    :root {
        --page: Crimson;
        --panel: WhiteSmoke;
        --light: white;
    }
    body {
        font-family: Tahoma;
        background-color: var(--page);
    }
    #banner {
        color: var(--light);
        text-align: center;
        height: 370px;
    }
    .match {
        color: var(--light);
        text-align: center;
        width: 200px;
        margin: 10px;
        border: 1px solid black;
        border-radius: 10px;
    }
    .match:hover {
        border-color: var(--light);
    }
    #main {
        background-color: var(--panel);
        height: 50px;
    }
    #left {
        background-color: var(--panel);
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: var(--panel);
        width: 30%;
        height: 230px;
        text-align: right;
    }
    h2 {
        text-align: center;
        letter-spacing: 7px;
        text-transform: capitalize;
    }
    #matches {
        display: flex;
        flex-wrap: wrap;
    }
    .columns {
        display: flex;
    }
    Podgląd strony po tym kroku (futbol.php)
  27. Etap 4: Skrypty PHP

    Kroki 27-33 · po tym etapie masz 38 z 38 kryteriów (pkt)

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

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP i zawiera przynajmniej jedną instrukcję zgodną ze składnią

    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 futbol.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 futbol.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,
    • $matches = [] - 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.

    PDO zamiast funkcji mysqli z tabeli 1 - klucz przyjmuje obie biblioteki (uwaga przy R.5). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    futbol.php PHP zmienione: 18 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  28. Krok 28: Skrypt 1: zapytanie 1 do bazy

    Kryteria:

    R.5.5 Skrypt 1 wysyła do bazy danych zapytanie 1 lub Skrypt 2 wysyła do bazy zmodyfikowane zapytanie 2 tak, że w warunku id pozycji jest równe wartości z pola edycyjnego

    ok. 2 min
    Polecenie z arkusza

    Działanie skryptu 1: Wysyła do bazy danych zapytanie 1

    $pdo->query("…") wysyła zapytanie 1, a ->fetchAll() od razu pobiera wszystkie wiersze do tablicy $matches - pięć meczów, każdy jako tablica ['zespol1' => 'EVG', 'zespol2' => 'FCB', …] (R.5.5). Zapytanie nie ma żadnych danych od użytkownika, więc nie musi być przygotowane. Na stronie jeszcze nic nie widać.

    futbol.php PHP zmienione: 1 linia
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>

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

  29. Krok 29: Skrypt 1: blok sekcji z nagłówkiem dla każdego meczu

    Kryteria: ,

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

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

    ok. 4 min
    Polecenie z arkusza

    Definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane zwrócone zapytaniem dotyczące jednego wiersza: W nagłówku trzeciego stopnia tekst: „<zespół 1> - <zespół 2>”, gdzie pola w nawiasach <> oznaczają dane pobrane zapytaniem. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    W bloku mecze szablon: foreach ($matches as $match): … endforeach; - zapis z dwukropkiem, wygodny między znacznikami HTML. Wszystko między nimi powtarza się dla każdego meczu, więc bloków <section class="match"> jest tyle, ile wierszy zwróciła baza (R.5.6, R.5.8). Krótki znacznik <?= … ?> wypisuje wartość; każda przechodzi przez e().

    Podgląd: pięć bloków „EVG - FCB”, „EVG - FCB”, „EVG - JUV”, „EVG - RM”, „EVG - FCB”, od razu w ramkach i w rzędzie.

    futbol.php PHP zmienione: 5 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  30. Krok 30: Skrypt 1: wynik w h4 i data w paragrafie

    Kryteria:

    R.5.7 Skrypt 1 wyświetla dane wg wzoru: "<zespół 1> - <zespół 2>" w nagłówku h3, następnie "<wynik>" w nagłówku h4, następnie paragraf "w dniu: <data rozgrywki>", gdzie pole w nawiasach <> oznacza dane pobrane skryptem

    ok. 2 min
    Polecenie z arkusza

    W nagłówku czwartego stopnia wynik pobrany zapytaniem. W paragrafie tekst: „w dniu: <data rozgrywki>”, gdzie pole w nawiasach <> oznacza dane pobrane zapytaniem

    Dwie linie szablonu: <h4> z wynikiem i paragraf „w dniu: ” z datą. Kolumny odczytuje się po nazwach ($match['wynik']), a nie po numerach - kolejność kolumn w zapytaniu przestaje mieć znaczenie (R.5.7).

    futbol.php PHP zmienione: 2 linie
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
                <h4><?= e($match['wynik']) ?></h4>
                <p>w dniu: <?= e($match['data_rozgrywki']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  31. Krok 31: Skrypt 2: odbiór i sprawdzenie liczby z formularza

    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 2, który odbiera dane przesłane z formularza: Odbiera dane z pola edycyjnego. Jeśli pole edycyjne jest puste nie jest wykonywana żadna akcja

    • $_POST['position'] ?? '' - wartość pola z formularza, 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; puste pole, abc czy 9 dają false. Pole type="number" pilnuje tego tylko w przeglądarce - dane da się wysłać z pominięciem formularza,
    • pole dostało value="<?= e($positionText) ?>" - po wysłaniu wpisana liczba wraca do pola (na obrazie 2 w polu stoi 4 obok wyniku); e() chroni przed tekstem z cudzysłowem.

    Podgląd: wysłana liczba 4 - stoi w polu, lista jeszcze pusta.

    futbol.php PHP zmienione: 4 linie
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $players = [];
    $positionText = $_POST['position'] ?? '';
    $position = filter_var($positionText, 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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
                <h4><?= e($match['wynik']) ?></h4>
                <p>w dniu: <?= e($match['data_rozgrywki']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4" value="<?= e($positionText) ?>">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  32. Krok 32: Skrypt 2: zapytanie przygotowane i lista zawodników

    Kryteria:

    R.5.9 Skrypt 2 wyświetla przynajmniej jedno imię i nazwisko jeśli wypełniono pole do wprowadzania danych

    ok. 4 min
    Polecenie z arkusza

    Jeżeli wpisano dane skrypt wysyła do bazy danych zmodyfikowane zapytanie 2 tak, że w warunku id pozycji jest równe wartości z pola edycyjnego. Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy punktowanej

    • if ($position !== false) - zapytanie tylko dla poprawnego numeru pozycji; przy pustym polu nic się nie dzieje,
    • $pdo->prepare(…) z parametrem :position w miejscu 3 z zapytania 2, potem execute z wartością - baza dostaje treść zapytania i liczbę osobno, więc tekst z formularza nigdy nie stanie się kodem SQL,
    • w liście szablon foreach ($players as $player): każdy zawodnik jako <li> z paragrafem <p> z imieniem i nazwiskiem.

    Podgląd: pozycja 4 - Arkadiusz Milik i Adam Buksa, jak na obrazie 2 (R.5.9).

    futbol.php PHP zmienione: 9 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $players = [];
    $positionText = $_POST['position'] ?? '';
    $position = filter_var($positionText, 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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->fetchAll();
    
        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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
                <h4><?= e($match['wynik']) ?></h4>
                <p>w dniu: <?= e($match['data_rozgrywki']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4" value="<?= e($positionText) ?>">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  33. Krok 33: 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 mecze doszedł warunek wypisujący w paragrafie komunikat $error, gdy baza nie odpowiedziała. Sprawdzone przy wyłączonym serwerze bazy: strona się wyświetla, a zamiast meczów stoi „Nie udało się połączyć z bazą danych.” Podgląd: stan z obrazu 2.

    futbol.php PHP zmienione: 6 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $players = [];
    $positionText = $_POST['position'] ?? '';
    $position = filter_var($positionText, 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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->fetchAll();
    
        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.';
    } 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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php if ($error !== null): ?>
            <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
                <h4><?= e($match['wynik']) ?></h4>
                <p>w dniu: <?= e($match['data_rozgrywki']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4" value="<?= e($positionText) ?>">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>

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

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

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

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

    ok. 2 min
    Polecenie z arkusza

    Napisany w języku PHP, w pliku futbol.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 mecze ma prawdziwą wysokość,
    • 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 liczba z formularza trafia do zapytania wprost (wstrzyknięcie 0 OR 1=1 pokazuje wszystkich zawodników), tutaj jest sprawdzana (filter_var, zakres 1-4) i przekazywana parametrem zapytania przygotowanego; każdy tekst przechodzi przez htmlspecialchars,
    • wygoda: wybrana pozycja zostaje w polu, etykieta jest połączona z polem, 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.

    futbol.php PHP zmienione: 0 linii
    <?php
    function e($text)
    {
        return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
    }
    
    $matches = [];
    $players = [];
    $positionText = $_POST['position'] ?? '';
    $position = filter_var($positionText, 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,
        ]);
        $matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->fetchAll();
    
        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.';
    } 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>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
            <img src="obraz1.jpg" alt="boisko" width="930" height="310">
        </section>
        <section id="matches">
    <?php if ($error !== null): ?>
            <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($matches as $match): ?>
            <section class="match">
                <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3>
                <h4><?= e($match['wynik']) ?></h4>
                <p>w dniu: <?= e($match['data_rozgrywki']) ?></p>
            </section>
    <?php endforeach; ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <div class="columns">
            <section id="left">
                <p><label for="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p>
                <form method="post">
                    <input type="number" id="position" name="position" min="1" max="4" value="<?= e($positionText) ?>">
                    <button type="submit">Sprawdź</button>
                </form>
                <ul>
    <?php foreach ($players as $player): ?>
                    <li><p><?= e($player['imie']) ?> <?= e($player['nazwisko']) ?></p></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
                <img src="zad1.png" alt="piłkarz" width="150" height="165">
                <p>Autor: Bartosz Bryniarski</p>
            </section>
        </div>
    </body>
    </html>

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

  35. Etap 6: Oddanie pracy

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

    Krok 35: 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 zdającego, 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 zdającego: import.png, futbol.php, kw1.jpg - kw4.jpg, kwerendy.txt, obraz1.jpg, przeglądarka.txt, styl.css, zad1.png. Płytę nagrywasz, sprawdzasz jej odczyt i opisujesz numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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