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

Rozwiązanie krok po kroku: Rozgrywki futbolowe i reprezentacja Polski (Wersja podstawowa)

Strona o rozgrywkach piłkarskich: baza egzamin zaimportowana z pliku, cztery zapytania (mecze drużyny EVG, pomocnicy, złączenie zawodników z pozycjami i usunięcie tabeli liga), grafika z piłkarzem przeskalowana z zachowaniem przezroczystości, strona futbol.php ze stylami w styl.css oraz dwa skrypty PHP: pierwszy generuje z bazy bloki z wynikami meczów, drugi po wysłaniu formularza wypisuje zawodników grających na wybranej pozycji.

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 kilkoma dopisanymi wymaganiami (HTML5, jawne kodowanie, język strony). Ten sam arkusz był też w styczniu 2026. Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty są najpierw napisane najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzone na prawdziwym wstrzyknięciu SQL i zabezpieczone.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: układ na display: flex, zmienne CSS, PDO z zapytaniem przygotowanym na górze pliku i wybrana pozycja zostająca w polu formularza - obie wersje są zgodne z kluczem.

Archiwum dane.7z z tej sesji nie jest opublikowane w materiałach CKE/OKE. Jego zawartość (egzamin.sql, obraz1.jpg, zad1.png) jest identyczna z oryginalnym archiwum CKE z1.zip z pierwszego wydania zadania (arkusz EE.09-01-21.01, załącznik na stronie tamtego arkusza) i z tych plików korzysta rozwiązanie. Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. 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 - można stracić 9 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  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.

    Na pulpicie tworzysz folder nazwany numerem zdającego (numerem PESEL, a bez niego numerem paszportu) - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum dane.7z (arkusz nazywa je „archiwum ZIP”, ale to format 7z) otwierasz programem 7-Zip i rozpakowujesz do tego folderu, podając hasło !Futboi& - dokładnie tak, przed ostatnim znakiem jest litera i, nie l. W środku są trzy pliki: egzamin.sql (baza do importu), obraz1.jpg (zdjęcie stadionu do banera) i zad1.png (sylwetka piłkarza na przezroczystym tle).

    Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, plik strony i stylów.

    Typowe błędy

    Pliki zapisane poza folderem zdającego (np. tylko w htdocs) nie trafią na płytę - a ocenia się tylko to, co jest na płycie.

  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

    W XAMPP Control Panel klikasz Start przy Apache i MySQL (nazwy modułów robią się zielone), potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa egzamin, porównywanie np. utf8mb4_polish_ci (arkusz go nie narzuca), Utwórz.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie egzamin - skrypt PHP łączy się z bazą po nazwie (R.5.2).

  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

    Zaznacz bazę egzamin w lewym panelu, karta Import, Wybierz plik → egzamin.sql z folderu zdającego, Wykonaj. phpMyAdmin odpowiada „Import zakończył się sukcesem” i wypisuje liczbę wykonanych zapytań.

    Plik zawiera 8 tabel: oprócz czterech z obrazu 1 (liga, pozycja, rozgrywka, zawodnik) także typy, uslugi, wyniki i zdjecia - nie są potrzebne w zadaniu, ale import ich nie omija. Na zrzucie widać komunikat o sukcesie i listę tabel z liczbą rekordów - to są „elementy wskazujące na poprawnie wykonany import”. Cały ekran z paskiem zadań zapisujesz jako import.png.

    Typowe błędy

    Zrzut importu ma format PNG, a zrzuty zapytań - JPG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

    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. 4 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”

    Zaznacz bazę egzamin i otwórz kartę SQL. Zapytanie klauzula po klauzuli:

    • SELECT zespol1, zespol2, wynik, data_rozgrywki - cztery kolumny wymienione w arkuszu; „jedynie” wyklucza SELECT * (tabela ma jeszcze id),
    • FROM rozgrywka,
    • WHERE zespol1 = 'EVG' - tylko mecze, w których EVG jest pierwszym zespołem. Napis w apostrofach (cudzysłów "EVG" z przykładu w kluczu MariaDB też przyjmie).

    Wynik: 5 meczów, od EVG FCB 3:1 2019-05-14 do EVG FCB 1:1 2019-05-22 - te same, które na obrazie 2 stoją w blokach pod banerem. Zapytanie kopiujesz do pliku kwerendy.txt, a zrzut całego ekranu zapisujesz jako kw1.jpg (Print Screen, wklejenie do edytora grafiki, eksport do JPEG).

    Tego zapytania użyje skrypt 1.

    Typowe błędy

    WHERE zespol2 = 'EVG' albo OR zespol2 = 'EVG' zmienia wynik - klucz wymaga dokładnie 5 rekordów i tylko „EVG” w kolumnie zespol1.

    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

    • SELECT imie, nazwisko - dwie kolumny,
    • FROM zawodnik,
    • WHERE pozycja_id = 3 - „id pozycji” to w tabeli zawodnik kolumna pozycja_id (klucz obcy do tabeli pozycja, gdzie 3 to pomocnik). Liczba bez apostrofów - kolumna jest liczbowa.

    Wynik: Grzegorz Krychowiak i Kamil Grosicki. Zrzut: kw2.jpg. Skrypt 2 użyje tego zapytania, wstawiając w miejsce 3 liczbę wpisaną w formularz.

    Typowe błędy

    WHERE id = 3 sprawdza identyfikator zawodnika, nie jego pozycję - wynikiem byłby tylko Jan Bednarek.

    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;
    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. 4 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

    Dane z dwóch tabel, więc potrzebne jest złączenie:

    • SELECT zawodnik.id, zawodnik.nazwisko, pozycja.nazwa - kolumna id jest w obu tabelach, więc trzeba podać, z której (inaczej błąd #1052 „niejednoznaczna kolumna”); przy pozostałych nazwa tabeli jest dla czytelności,
    • FROM zawodnik JOIN pozycja ON zawodnik.pozycja_id = pozycja.id - do każdego zawodnika dołączany jest wiersz pozycji o numerze z jego kolumny pozycja_id,
    • WHERE zawodnik.id IN (1, 2, 3) - IN to krótszy zapis zawodnik.id = 1 OR zawodnik.id = 2 OR zawodnik.id = 3 (klucz przyjmuje też < 4).

    Wynik: 1 Szczesny bramkarz, 2 Pietrzak obronca, 3 Bednarek obronca (dane w bazie są bez polskich liter). Zrzut: kw3.jpg.

    Typowe błędy

    Bez warunku złączenia (FROM zawodnik, pozycja WHERE zawodnik.id IN (1, 2, 3)) każdy zawodnik połączy się z każdą z 4 pozycji - 12 wierszy zamiast 3. Warunek z OR bez JOIN trzeba ująć w nawias: WHERE zawodnik.pozycja_id = pozycja.id AND (zawodnik.id = 1 OR …).

    kwerendy.txt Tekst zmienione: 4 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 zawodnik.id, zawodnik.nazwisko, pozycja.nazwa FROM zawodnik
    JOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.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 całą tabelę - strukturę razem z danymi. phpMyAdmin przed wykonaniem pyta „Czy na pewno chcesz wykonać DROP TABLE liga?” - potwierdzasz, a odpowiedź to „MySQL zwrócił pusty wynik”: znak, że polecenie się wykonało. Zrzut: kw4.jpg. Tabela liga znika z listy tabel bazy; strona z niej nie korzysta, więc skryptom to nie przeszkadza.

    Plik kwerendy.txt ma komplet czterech zapytań.

    Typowe błędy

    DELETE FROM liga i TRUNCATE liga usuwają tylko wiersze - tabela zostaje w bazie, a arkusz każe usunąć tabelę.

    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 zawodnik.id, zawodnik.nazwisko, pozycja.nazwa FROM zawodnik
    JOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.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-24 · 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

    Oryginał ma 366 × 402 px i przezroczyste tło (kanał alfa). W GIMP-ie: Obraz → Skaluj obraz, łańcuch między szerokością a wysokością zamknięty (to jest „zachowanie proporcji”), szerokość 150 px - wysokość przelicza się sama: 402 × 150 / 366 = 164,8, czyli 165 px (klucz: 165 px ±5).

    Zapis: Plik → Nadpisz zad1.png albo Eksportuj jako z rozszerzeniem .png. Format PNG zachowuje kanał alfa - tło zostaje przezroczyste i na stronie pod piłkarzem będzie widać szare tło bloku prawego.

    Typowe błędy

    Eksport do JPEG (np. zad1.jpg) zamieni przezroczyste tło na białe albo czarne - klucz wymaga zachowania przezroczystości. Zwykłe Zapisz w GIMP-ie zapisuje format .xcf.

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

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie futbol.php. Zapisana w języku HTML 5

    Plik futbol.php w folderze zdającego, obok grafik. Rozszerzenie .php, bo dojdą skrypty - na razie to czysty HTML. Pierwsza linia <!DOCTYPE html> to deklaracja HTML5 - krótka, bez adresu definicji typu dokumentu, jaki miały HTML 4 i XHTML.

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

    ok. 1 min
    Polecenie z arkusza

    Ustawiony język zawartości strony na polski

    Atrybut lang="pl" w znaczniku <html> (jest już w szkielecie z poprzedniego kroku). Przeglądarka dobiera po nim np. dzielenie wyrazów i słownik sprawdzania pisowni, a czytnik ekranu - wymowę.

    futbol.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>

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

  11. Krok 11: 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 pierwsza rzecz w <head> - to jest „jawne” podanie kodowania: zapisane w kodzie strony, a nie zgadywane przez przeglądarkę. Bez tej linii „Światowe”, „piłkarskie” i „obrońcy” mogą wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8 (w Notepad++ menu Kodowanie). Nazwa pliku i kodowanie dają razem R.2.2.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  12. Krok 12: 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> w <head> - napis na karcie przeglądarki. Nagłówek banera to inny tekst („Światowe rozgrywki piłkarskie”).

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Rozgrywki futbolowe</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  13. Krok 13: 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"> w <head>. Plik stylów powstanie po HTML-u; całe formatowanie trafi tylko do niego, bez atrybutów style w HTML-u (R.3.4).

    Typowe błędy

    Klucz nie uznaje R.3.4 także wtedy, gdy choć jeden selektor źle trafia w blok (np. kropka zamiast # przy identyfikatorze).

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  14. Krok 14: Bloki: baner, mecze, główny, lewy i prawy

    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ęć znaczników <section> w kolejności z obrazu 2, każdy z identyfikatorem, bo każdy blok ma inne style: banner, matches (blok mecze), main (blok główny), left i right - nazwy po angielsku, arkusz ich nie narzuca. Bloków z wynikami meczów nie piszesz w HTML-u: wygeneruje je skrypt 1, po jednym <section> na mecz, wewnątrz bloku matches.

    Na razie bloki są puste i stoją jeden pod drugim - lewy obok prawego ustawi CSS. Podział na bloki daje R.2.4 (klucz z tej sesji nie wymaga bloku z meczem w HTML-u).

    futbol.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
        </section>
        <section id="matches">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  15. Krok 15: Baner: nagłówek drugiego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku banera: Nagłówek drugiego stopnia o treści „Światowe rozgrywki piłkarskie”

    Drugiego stopnia to <h2> - na tej stronie nie ma żadnego <h1>. Tekst wpisujesz małymi literami jak w arkuszu; wielkie litery na początku słów (obraz 2) doda CSS.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Rozgrywki futbolowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <section id="banner">
            <h2>Światowe rozgrywki piłkarskie</h2>
        </section>
        <section id="matches">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  16. Krok 16: Baner: zdjęcie stadionu z tekstem alternatywnym

    ok. 1 min
    Polecenie z arkusza

    Obraz obraz1.jpg z tekstem alternatywnym o treści: „boisko”

    <img> z atrybutami src (nazwa pliku z folderu zdającego) i alt - tekst, który czytnik ekranu przeczyta zamiast zdjęcia i który pokaże się, gdy plik się nie wczyta. Zdjęcie ma 930 × 310 px i zostaje w tym rozmiarze - arkusz go nie zmienia.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  17. Krok 17: 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”

    Blok mecze zostaje na razie pusty - wypełni go skrypt 1. W bloku głównym drugi nagłówek <h2>; oba nagłówki strony dostaną te same style przez selektor h2.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  18. Krok 18: Blok lewy: paragraf z opisem pozycji

    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):”

    Akapit <p> z instrukcją dla użytkownika - numery pozycji odpowiadają tabeli pozycja z obrazu 1. Strona ma już oba nagłówki <h2> i pierwszy paragraf (R.2.5).

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  19. Krok 19: Formularz wysyłający dane metodą POST

    Kryteria: ,

    R.2.7 W bloku lewym umieszczono formularz

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

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyłający dane metodą POST do tej samej strony, zawierający:

    <form method="post"> - bez atrybutu action formularz wysyła dane do tego samego adresu, z którego został wczytany, czyli do futbol.php. Metoda POST przesyła dane w treści żądania, nie w adresie strony; w PHP odczytasz je z tablicy $_POST. Znacznik z zamknięciem stoi w bloku lewym (R.2.7, R.3.3).

    Typowe błędy

    method="get" dopisze wartość do adresu (futbol.php?position=4) - skrypt czytający $_POST niczego nie dostanie.

    futbol.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
            </form>
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  20. Krok 20: Pole edycyjne typu numerycznego

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne typu numerycznego

    type="number" - przeglądarka przyjmie tylko liczbę i dorysuje strzałki zmiany wartości (widać je na obrazie 2). Atrybut name="position" to klucz, pod którym wartość trafi do PHP: $_POST['position'].

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
            </form>
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  21. Krok 21: Przycisk „Sprawdź”

    Kryteria: ,

    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

    ok. 1 min
    Polecenie z arkusza

    Przycisk wysyłający zawartość formularza z opisem „Sprawdź”

    <input type="submit" value="Sprawdź"> - przycisk, który wysyła formularz; napis to wartość value. Formularz ma komplet: pole liczbowe i przycisk wysyłający (R.2.8, R.3.2).

    Typowe błędy

    <input type="button"> wygląda tak samo, ale niczego nie wysyła - brak punktu R.3.2 i skrypt 2 nigdy nie dostanie danych.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  22. Krok 22: 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

    Lista nieuporządkowana to <ul> (unordered list). Na razie pusta - elementy <li> z imionami i nazwiskami wypisze skrypt 2, dlatego jego kod stanie między <ul> a </ul> (R.2.9 przyjmuje listę generowaną skryptem).

    futbol.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  23. Krok 23: Blok prawy: grafika piłkarza

    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”

    Przeskalowany zad1.png (150 × 165 px) z tekstem alternatywnym. Oba obrazy strony są na miejscu i oba mają alt (R.2.6).

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  24. Krok 24: Blok prawy: akapit z autorem

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Paragraf (akapit) o treści: „Autor: ”, dalej wstawiony numer zdającego

    Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL). W tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora: Bartosz Bryniarski.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  25. Etap 3: Styl CSS

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

    Krok 25: Plik styl.css: krój i tło strony

    Kryteria:

    R.4.1 Ustawiono krój czcionki Tahoma dla body

    ok. 1 min
    Polecenie z arkusza

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

    Nowy plik styl.css w folderze zdającego - od teraz każda reguła trafia tylko tutaj. Selektor znacznika body: krój Tahoma dziedziczą wszystkie elementy strony, a Crimson to nazwa koloru CSS (karmazynowa czerwień). Pola formularza kroju nie dziedziczą - arkusz tego nie wymaga.

    styl.css CSS nowy plik
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    Podgląd strony po tym kroku (futbol.php)
  26. Krok 26: 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

    Selektor identyfikatora #banner - z krzyżykiem, bo w HTML-u jest id="banner". text-align: center wyśrodkowuje nagłówek i zdjęcie (obraz jest elementem w linii, więc słucha wyrównania tekstu). 370 px mieści nagłówek i zdjęcie wysokie na 310 px. Biały tekst banera - R.4.3.

    styl.css CSS zmienione: 5 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    Podgląd strony po tym kroku (futbol.php)
  27. Krok 27: Pojedynczy blok z rozgrywką: tekst, szerokość, marginesy

    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

    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

    Bloki z meczami to znaczniki <section> wewnątrz bloku matches, więc selektor jest potomny: #matches section - spacja znaczy „każdy section w środku #matches”. Pięć głównych bloków strony też jest sekcjami, ale nie leżą w #matches, więc ta reguła ich nie dotyczy (R.4.7).

    Bloków jeszcze nie ma na stronie - pojawią się z wynikiem skryptu 1, od razu w tym stylu.

    Typowe błędy

    Sam selektor section objąłby wszystkie bloki strony - baner, blok główny i lewy też dostałyby szerokość 200 px.

    styl.css CSS zmienione: 6 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    Podgląd strony po tym kroku (futbol.php)
  28. Krok 28: Pojedynczy blok z rozgrywką: obramowanie i zaokrąglenie

    Kryteria:

    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. 1 min
    Polecenie z arkusza

    Obramowanie: 1 px, linia ciągła, kolor czarny, zaokrąglenie rogów obramowania 10 px

    Skrót border: 1px solid black - grubość, styl linii (solid = ciągła) i kolor w jednej właściwości. border-radius: 10px zaokrągla rogi ramki (R.4.8). To osobna reguła dla tego samego selektora - mogłaby też trafić do poprzedniej.

    styl.css CSS zmienione: 4 linie
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    Podgląd strony po tym kroku (futbol.php)
  29. Krok 29: 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

    Pseudoklasa :hover działa, gdy kursor jest nad elementem. Zmienia się tylko kolor ramki (border-color) - grubość i styl zostają z poprzedniej reguły, więc blok nie „skacze”. Na obrazie 2 tak wygląda drugi blok (R.4.9).

    styl.css CSS zmienione: 3 linie
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    Podgląd strony po tym kroku (futbol.php)
  30. Krok 30: Blok główny: tło i wysokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła WhiteSmoke, wysokość 50 px

    WhiteSmoke to bardzo jasna szarość (prawie biel). Nazwy kolorów z arkusza wpisujesz dosłownie - przeglądarka zna je bez zamiany na kod szesnastkowy.

    styl.css CSS zmienione: 4 linie
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    #main {
        background-color: WhiteSmoke;
        height: 50px;
    }
    Podgląd strony po tym kroku (futbol.php)
  31. Krok 31: Blok lewy: tło, szerokość, wysokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloku lewego: kolor tła WhiteSmoke, szerokość 70%, wysokość 230 px

    Szerokość w procentach liczy się od szerokości rodzica, czyli body - blok lewy zajmie 70% okna bez marginesów strony.

    styl.css CSS zmienione: 5 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    #main {
        background-color: WhiteSmoke;
        height: 50px;
    }
    #left {
        background-color: WhiteSmoke;
        width: 70%;
        height: 230px;
    }
    Podgląd strony po tym kroku (futbol.php)
  32. Krok 32: Blok prawy: tło, szerokość, wysokość, wyrównanie do prawej

    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 prawego: kolor tła WhiteSmoke, szerokość 30%, wysokość 230 px, wyrównanie tekstu do prawej strony

    70% + 30% = 100% - oba bloki zmieszczą się obok siebie, jeśli nie dostaną marginesów ani ramek. text-align: right dosuwa do prawej krawędzi i akapit z autorem, i grafikę piłkarza (obraz 2). Tła trzech szarych bloków i body (R.4.2), wysokości banera, bloku głównego, lewego i prawego (R.4.4) i szerokości (R.4.5) są ustawione.

    Typowe błędy

    Bloki o sumie szerokości 100% nie mogą mieć padding, margin ani border - każdy piksel więcej zepchnie blok prawy pod lewy.

    styl.css CSS zmienione: 6 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    #main {
        background-color: WhiteSmoke;
        height: 50px;
    }
    #left {
        background-color: WhiteSmoke;
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: WhiteSmoke;
        width: 30%;
        height: 230px;
        text-align: right;
    }
    Podgląd strony po tym kroku (futbol.php)
  33. Krok 33: 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 - nagłówek na środku bloku (razem z banerem i blokiem prawym: R.4.6),
    • letter-spacing: 7px - dodatkowe 7 px po każdej literze, stąd „rozstrzelone” nagłówki z obrazu 2,
    • text-transform: capitalize - pierwsza litera każdego słowa wielka: „Światowe Rozgrywki Piłkarskie”, jak na obrazie 2 (R.4.10).

    ⚠️ Uwaga o nazewnictwie: arkusz nazywa to „kapitalikami”, ale kapitaliki to co innego - wszystkie litery w kształcie wielkich, małe zmniejszone (font-variant: small-caps). Wartość w nawiasie i obraz 2 rozstrzygają: chodzi o capitalize. Klucz z tej sesji wymienia tylko text-transform: capitalize.

    Typowe błędy

    text-transform: uppercase zamieni cały napis na wielkie litery - obraz 2 pokazuje wielką tylko pierwszą literę słowa.

    styl.css CSS zmienione: 5 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    #main {
        background-color: WhiteSmoke;
        height: 50px;
    }
    #left {
        background-color: WhiteSmoke;
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: WhiteSmoke;
        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)
  34. Krok 34: Układ bloków zgodny z obrazem 2

    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

    Trzy reguły układu:

    • #matches section { float: left; } - bloki z meczami stają obok siebie w rzędzie (każdy zajmuje 200 + 2 × 1 + 2 × 10 = 222 px; pięć bloków to 1110 px),
    • #main { clear: both; } - blok główny zaczyna się dopiero pod wszystkimi pływającymi blokami meczów. Bez tego wsunąłby się pod nie, bo blok matches z samymi pływającymi elementami ma wysokość 0,
    • #left, #right { float: left; } - blok lewy (70%) przy lewej krawędzi, prawy (30%) tuż obok niego.

    Klucz R.3.1 ocenia układ pięciu głównych bloków, bez bloków z rozgrywkami{'' if STARA else ' (przyjmuje float i clear, flex, grid albo position)'}. Podgląd: blok lewy i prawy stoją już obok siebie; bloki meczów dojdą ze skryptem 1.

    Typowe błędy

    Bez clear: both przy bloku głównym jego szare tło wjedzie pod bloki meczów, a nagłówek „Reprezentacja Polski” stanie za nimi.

    styl.css CSS zmienione: 9 linii
    body {
        font-family: Tahoma;
        background-color: Crimson;
    }
    #banner {
        color: white;
        text-align: center;
        height: 370px;
    }
    #matches section {
        color: white;
        text-align: center;
        width: 200px;
        margin: 10px;
    }
    #matches section {
        border: 1px solid black;
        border-radius: 10px;
    }
    #matches section:hover {
        border-color: white;
    }
    #main {
        background-color: WhiteSmoke;
        height: 50px;
    }
    #left {
        background-color: WhiteSmoke;
        width: 70%;
        height: 230px;
    }
    #right {
        background-color: WhiteSmoke;
        width: 30%;
        height: 230px;
        text-align: right;
    }
    h2 {
        text-align: center;
        letter-spacing: 7px;
        text-transform: capitalize;
    }
    #matches section {
        float: left;
    }
    #main {
        clear: both;
    }
    #left, #right {
        float: left;
    }
    Podgląd strony po tym kroku (futbol.php)
  35. Etap 4: Skrypty PHP

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

    Krok 35: Miejsce skryptu 1 i połączenie z bazą egzamin

    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. 3 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

    Efekt skryptu 1 ma się pojawić w bloku mecze - tam więc piszesz blok PHP, między <?php a ?>. Serwer wykona go, zanim strona trafi do przeglądarki.

    Pierwsza instrukcja: mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy egzamin (połączenie i wybór bazy w jednym wywołaniu). Połączenie trafia do zmiennej $connection, z której skorzystają oba skrypty - skrypt 2 stoi niżej w tym samym pliku, więc zmienna jest dla niego dostępna (R.5.1, R.5.2).

    Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2) - na razie wygląda jak wcześniej. Stronę sprawdzasz przez http://localhost/…/futbol.php, a nie otwierając plik z dysku: przeglądarka sama nie wykona PHP.

    futbol.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  36. Krok 36: 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

    mysqli_query($connection, "…") wysyła do bazy zapytanie 1 przepisane z kwerendy.txt i zwraca wynik - zbiór wierszy, który trafia do zmiennej $result. Zapytanie stoi w cudzysłowie "…", a napis 'EVG' w środku - w apostrofach: dwa różne znaki się nie gryzą (R.5.5).

    Na stronie jeszcze nic nie widać - wiersze trzeba wypisać.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>

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

  37. Krok 37: 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

    • while ($row = mysqli_fetch_row($result)) - mysqli_fetch_row zwraca kolejny wiersz wyniku jako tablicę numerowaną od zera: $row[0] to zespol1, $row[1] - zespol2, $row[2] - wynik, $row[3] - data_rozgrywki (kolejność kolumn z zapytania). Gdy wierszy zabraknie, funkcja zwraca false i pętla się kończy,
    • w każdym obrocie pętli echo '<section>' i echo '</section>' - jeden blok na jeden wiersz, więc bloków jest dokładnie tyle, ile meczów zwróciła baza (R.5.6, R.5.8),
    • echo "<h3>$row[0] - $row[1]</h3>" - w cudzysłowie PHP podstawia wartości zmiennych, także elementów tablicy zapisanych bez apostrofów w nawiasie.

    Podgląd: pięć bloków z nagłówkami „EVG - FCB”, „EVG - FCB”, „EVG - JUV”, „EVG - RM”, „EVG - FCB” - od razu w ramkach i obok siebie, bo style były gotowe wcześniej.

    Typowe błędy

    echo '<h3>$row[0] - $row[1]</h3>' w apostrofach wypisze dosłownie $row[0] - $row[1] - PHP podstawia zmienne tylko w cudzysłowie "…".

    futbol.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  38. Krok 38: 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 w pętli, po nagłówku <h3>: <h4> z wynikiem meczu ($row[2]) i paragraf z napisem „w dniu: ” i datą ($row[3]). Podgląd: bloki wyglądają jak na obrazie 2 - od „3:1, w dniu: 2019-05-14” do „1:1, w dniu: 2019-05-22” (R.5.7).

    futbol.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  39. Krok 39: Skrypt 2: odbiór 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

    Drugi blok PHP stoi wewnątrz listy <ul> - to, co wypisze, stanie się jej elementami.

    • $_POST['position'] - wartość pola o nazwie position (R.5.4),
    • empty() jest prawdziwe, gdy klucza w ogóle nie ma (pierwsze wejście na stronę, formularz nie był wysłany) albo gdy pole wysłano puste. Wykrzyknik ! odwraca warunek: kod w klamrach wykona się tylko wtedy, gdy wpisano liczbę - przy pustym polu nie dzieje się nic, jak każe arkusz.

    Podgląd: wysłana liczba 4 - lista jest jeszcze pusta, zapytanie dojdzie w następnym kroku.

    Typowe błędy

    Samo $_POST['position'] bez sprawdzenia przy pierwszym wejściu na stronę daje ostrzeżenie „Undefined array key” - formularz jeszcze nie był wysłany.

    futbol.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    if (!empty($_POST['position'])) {
        $position = $_POST['position'];
    }
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>

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

  40. Krok 40: Skrypt 2: zapytanie 2 z pozycją z formularza 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

    • zapytanie 2 z kwerendy.txt, w którym zamiast 3 stoi $position - liczba z formularza. Cudzysłów sprawia, że PHP wstawi jej wartość, a wynik znów trafia do $result,
    • pętla while z mysqli_fetch_row - $row[0] to imię, $row[1] nazwisko,
    • każdy zawodnik jako element listy <li>, a w nim paragraf <p> z imieniem i nazwiskiem.

    Podgląd: wpisano 4 (napastnicy) - lista pokazuje Arkadiusz Milik i Adam Buksa, jak na obrazie 2 (R.5.9). Pole po wysłaniu jest puste: strona wczytuje się od nowa, a arkusz nie wymaga, żeby liczba w nim została.

    futbol.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    if (!empty($_POST['position'])) {
        $position = $_POST['position'];
        $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");
        while ($row = mysqli_fetch_row($result)) {
            echo "<li><p>$row[0] $row[1]</p></li>";
        }
    }
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  41. Krok 41: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

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

    mysqli_close($connection) na końcu drugiego bloku PHP, poza warunkiem - wykona się zawsze, także gdy pole formularza jest puste. Zamknięcie po skrypcie 1 odcięłoby skrypt 2 od bazy (R.5.3).

    Strona spełnia wszystkie kryteria arkusza. Dalej trzy kroki o zabezpieczeniach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close w bloku skryptu 1 sprawia, że mysqli_query w skrypcie 2 dostaje zamknięte połączenie - PHP 8 kończy się wtedy błędem „mysqli object is already closed”.

    futbol.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    if (!empty($_POST['position'])) {
        $position = $_POST['position'];
        $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");
        while ($row = mysqli_fetch_row($result)) {
            echo "<li><p>$row[0] $row[1]</p></li>";
        }
    }
    mysqli_close($connection);
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>

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

  42. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 42-44 · po tym etapie masz 38 z 38 kryteriów (pkt)

    Krok 42: Zabezpieczenie: zapytanie przygotowane w skrypcie 2

    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

    Pole type="number" pilnuje liczby tylko w przeglądarce. Formularz można wysłać z pominięciem strony (np. programem curl albo narzędziami deweloperskimi), a wtedy w $_POST['position'] stoi dowolny tekst - i trafia wprost do zapytania. To SQL injection, sprawdzone na wersji z poprzednich kroków:

    • 0 OR 1=1 - warunek jest zawsze prawdziwy i lista pokazuje wszystkich 7 zawodników,
    • 0 UNION SELECT nazwa, cena FROM uslugi - do wyniku doklejają się wiersze z zupełnie innej tabeli (dziesięć usług z cenami, np. „Piling enzymatyczny 45”); tak samo dałoby się odczytać np. tabelę z hasłami,
    • abc - błąd składni SQL, PHP 8.1 i nowsze zgłaszają wyjątek mysqli_sql_exception i zamiast strony widać „Fatal error” z fragmentem zapytania.

    Lekarstwo to zapytanie przygotowane: mysqli_prepare ze znakiem ? w miejscu liczby, mysqli_stmt_bind_param z typem 'i' (liczba całkowita), mysqli_stmt_execute i mysqli_stmt_get_result - wynik czyta się dalej tą samą pętlą. Baza dostaje treść zapytania i dane osobno, więc dane nigdy nie staną się kodem SQL. Podgląd: ten sam atak z UNION - lista jest pusta (tekst zamieniony na liczbę daje 0, a pozycji 0 nie ma). Stara linia zostaje w komentarzu.

    Typowe błędy

    Liczba liter w 'i' musi równać się liczbie znaków ? i liczbie zmiennych - inaczej mysqli_stmt_bind_param zgłosi błąd.

    futbol.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    if (!empty($_POST['position'])) {
        $position = $_POST['position'];
        // $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");
        $statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;');
        mysqli_stmt_bind_param($statement, 'i', $position);
        mysqli_stmt_execute($statement);
        $result = mysqli_stmt_get_result($statement);
        while ($row = mysqli_fetch_row($result)) {
            echo "<li><p>$row[0] $row[1]</p></li>";
        }
    }
    mysqli_close($connection);
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  43. Krok 43: Zabezpieczenie: sprawdzenie liczby z formularza

    ok. 3 min
    Polecenie z arkusza

    Odbiera dane z pola edycyjnego. Jeśli pole edycyjne jest puste nie jest wykonywana żadna akcja

    Zapytanie przygotowane chroni bazę, ale skrypt nadal przyjmuje wszystko: abc, -5, 4.7. Lepiej odrzucić złe dane, zanim w ogóle dojdzie do zapytania:

    • filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, …) czyta pole z formularza i zwraca liczbę całkowitą tylko wtedy, gdy tekst nią jest i mieści się w zakresie 1-4 (min_range, max_range - tyle pozycji jest w tabeli pozycja),
    • w każdym innym przypadku zwraca false, a gdy pola w ogóle nie wysłano - null. Oba są fałszywe, więc if ($position) przepuszcza wyłącznie poprawne numery pozycji; pusty formularz dalej nie robi nic.

    Podgląd: wysłana liczba 9 - zapytanie się nie wykonuje i lista jest pusta. Dwie stare linie zostają w komentarzu.

    futbol.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    // if (!empty($_POST['position'])) {
    //     $position = $_POST['position'];
    $position = filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    if ($position) {
        // $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");
        $statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;');
        mysqli_stmt_bind_param($statement, 'i', $position);
        mysqli_stmt_execute($statement);
        $result = mysqli_stmt_get_result($statement);
        while ($row = mysqli_fetch_row($result)) {
            echo "<li><p>$row[0] $row[1]</p></li>";
        }
    }
    mysqli_close($connection);
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>

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

  44. Krok 44: Zabezpieczenie: htmlspecialchars przy wypisywaniu danych

    ok. 3 min
    Polecenie z arkusza

    Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy punktowanej

    Oba skrypty wklejają w kod strony tekst prosto z bazy. Gdy w tabeli znajdzie się znak <, przeglądarka potraktuje go jak początek znacznika. Sprawdzone: po dopisaniu do tabeli rozgrywka meczu z wynikiem zapisanym jako <i>1:0 wersja z poprzednich kroków zamienia ten tekst w znacznik kursywy, który rozlewa się na resztę strony - a w miejscu <i> mógłby stać skrypt.

    htmlspecialchars zamienia <, >, & i cudzysłowy na encje (&lt; itd.), więc przeglądarka pokaże je jako zwykłe znaki. array_map('htmlspecialchars', $row) robi to naraz dla wszystkich pól wiersza - w obu pętlach, tuż przed echo. Zasada: dane z bazy i z formularza zabezpiecza się przy wypisywaniu, nie przy zapisie. Podgląd: strona wygląda tak samo jak na obrazie 2 - na zwykłych danych zmiana jest niewidoczna.

    Na egzaminie wystarczy wersja wcześniejsza - klucz nie sprawdza żadnego z trzech zabezpieczeń.

    futbol.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
        </section>
        <section id="matches">
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin');
    $result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");
    while ($row = mysqli_fetch_row($result)) {
        echo '<section>';
        // echo "<h3>$row[0] - $row[1]</h3>";
        $row = array_map('htmlspecialchars', $row);
        echo "<h3>$row[0] - $row[1]</h3>";
        echo "<h4>$row[2]</h4>";
        echo "<p>w dniu: $row[3]</p>";
        echo '</section>';
    }
    ?>
        </section>
        <section id="main">
            <h2>Reprezentacja Polski</h2>
        </section>
        <section id="left">
            <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p>
            <form method="post">
                <input type="number" name="position">
                <input type="submit" value="Sprawdź">
            </form>
            <ul>
    <?php
    // if (!empty($_POST['position'])) {
    //     $position = $_POST['position'];
    $position = filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);
    if ($position) {
        // $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");
        $statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;');
        mysqli_stmt_bind_param($statement, 'i', $position);
        mysqli_stmt_execute($statement);
        $result = mysqli_stmt_get_result($statement);
        while ($row = mysqli_fetch_row($result)) {
            $row = array_map('htmlspecialchars', $row);
            echo "<li><p>$row[0] $row[1]</p></li>";
        }
    }
    mysqli_close($connection);
    ?>
            </ul>
        </section>
        <section id="right">
            <img src="zad1.png" alt="piłkarz">
            <p>Autor: Bartosz Bryniarski</p>
        </section>
    </body>
    </html>
    Podgląd strony po tym kroku (futbol.php)
  45. Etap 6: Oddanie pracy

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

    Krok 45: 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 wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….

    W folderze z numerem zdającego muszą być: import.png, futbol.php, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, obraz1.jpg, przeglądarka.txt, styl.css i zad1.png (plik egzamin.sql z archiwum może zostać). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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