Przejdź do głównej treści
INF.03-10-25.01-SGStyczeń 2025 · 36 kroków · ok. 83 min · 38 kryteriów z klucza

Rozwiązanie krok po kroku: Portal szkolnego koła szachowego (Nowoczesny kod (grid, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza szachy z czterema zapytaniami, logo złożone z dwóch grafik i strona szachy.php z tabelą najlepszych graczy i losowaniem pary do rozgrywki - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • siatka CSS na całej stronie: grid-template-areas rozkłada nagłówek, blok lewy, blok prawy i stopkę, a szerokości 25% i 75% stoją w grid-template-columns (klucz R.4.4 przyjmuje je wprost) - bez float i clear,
  • kolory w zmiennych CSS: każdy kolor z arkusza zapisany raz, w :root,
  • znaczniki od treści: blok lewy to <aside> (dodatki), blok prawy to <main> (tabela graczy), tabela ma <thead> i <tbody>,
  • PHP na PDO: oba zapytania na górze pliku, połączenie zamknięte, zanim zacznie się HTML, tabela wypisywana pętlą foreach w szablonie,
  • bezpieczeństwo: funkcja escape() przy każdej wartości z bazy, try/catch zamiast białej strony przy awarii bazy, losowanie formularzem GET (niczego nie zapisuje).

Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza i grafiki pochodzą z prawdziwego archiwum pliki3, zapytania zostały wykonane na tej bazie w MariaDB z XAMPP-a, a podgląd strony od etapu PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2. Zapytanie 2 losuje, więc w podglądzie stoi para z ilustracji 2 (WalSał 2A i MicKra 4B).

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

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych szachy

    ok. 2 min
    Polecenie z arkusza

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

    Archiwum pliki3.7z rozpakuj hasłem Sz4chm4t! do folderu z numerem zdającego: szachy.sql, board.jpg, chess.jpg i legenda.txt. W phpMyAdmin Nowa → szachy, porównywanie utf8_unicode_ci, albo zapytaniem:

    CREATE DATABASE szachy CHARACTER SET utf8 COLLATE utf8_unicode_ci;
    
    Typowe błędy

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

  2. Krok 2: Import tabeli z pliku szachy.sql

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabelę z pliku szachy.sql do utworzonej bazy.

    Import → szachy.sql. Tabela zawodnicy z ilustracji 1: 94 członków koła z pseudonimem, tytułem (AM, SM, PM, KM, OM albo pusty napis), datą zdobycia tytułu, rankingiem i klasą.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabeli do bazy danych szachy , co jest udokumentowane w pliku import.png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą 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.

    Cały ekran z paskiem zadań, a na nim komunikat phpMyAdmin o udanym imporcie albo tabela zawodnicy w drzewku bazy. Zapis jako import.png.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: gracze z rankingiem powyżej 2787

    Kryteria: ,

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

    R.1.3 Wykonane zapytanie 1 wybierające jedynie pseudonim, tytuł, ranking i klasę dla rankingów większych od 2787, posortowane malejąco według rankingu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT pseudonim, tytul, ranking, klasa FROM zawodnicy WHERE ranking > 2787 ORDER BY ranking DESC; oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 10 rekordów zawierających jedynie pola pseudonim, tytul, ranking, klasa

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pseudonim, tytuł, ranking i klasę dla rankingów większych od 2787, posortowane malejąco według rankingu.

    Każda klauzula w osobnej linii: SELECT (cztery kolumny), FROM, WHERE ranking > 2787 („większych od” - sama liczba 2787 nie przechodzi) i ORDER BY ranking DESC. Taki zapis czyta się z góry na dół jak zdanie z arkusza. Wynik: 10 wierszy, od LiLa (2901) do So What (2788) - te same, które pokaże tabela na stronie. Zapytanie zapisz w kwerendy.txt, zrzut jako kw1.png.

    Typowe błędy

    >= zamiast > to inny warunek niż w arkuszu - zapytanie ma być poprawne dla każdego zestawu danych, nie tylko dla tego.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT pseudonim, tytul, ranking, klasa
    FROM zawodnicy
    WHERE ranking > 2787
    ORDER BY ranking DESC;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: dwóch losowych graczy

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające losowo dokładnie dwa rekordy złożone z pól pseudonim i klasa z tabeli zawodnicy . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT pseudonim, klasa FROM zawodnicy ORDER BY RAND() LIMIT 2; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dokładnie 2 rekordy zawierające jedynie pola pseudonim i klasa (rekordy są losowe)

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające losowo dokładnie dwa rekordy złożone z pól pseudonim i klasa z tabeli zawodnicy.

    ORDER BY RAND() tasuje wiersze (każdy dostaje liczbę losową i tabela jest po niej sortowana), a LIMIT 2 zostawia dwa pierwsze. Na 94 wierszach to nic nie kosztuje; przy milionach wierszy serwer musiałby wylosować liczbę dla każdego, więc duże serwisy losują inaczej. Zrzut kw2.png: dokładnie dwa wiersze, przy każdym wykonaniu inne. To zapytanie wyśle Skrypt 2.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT pseudonim, tytul, ranking, klasa
    FROM zawodnicy
    WHERE ranking > 2787
    ORDER BY ranking DESC;
    
    -- Zapytanie 2
    SELECT pseudonim, klasa
    FROM zawodnicy
    ORDER BY RAND()
    LIMIT 2;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: klasa 4A staje się 5A

    Kryteria:

    R.1.5 Wykonane zapytanie 3 aktualizujące dane w kolumnie klasa. Klasa „4A” jest aktualizowana do „5A”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE zawodnicy SET klasa = "5A" WHERE klasa = "4A"; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczny jest komunikat potwierdzający wykonanie aktualizacji lub tabela ze zmienionymi wartościami (brak 4A, są wpisy z 5A)

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: aktualizujące dane w kolumnie klasa. Klasa „4A” jest aktualizowana do „5A”.

    UPDATE ... SET klasa = '5A' WHERE klasa = '4A'. Napisy w apostrofach - tak zapisuje je standard SQL; cudzysłów z przykładu w kluczu MariaDB też przyjmie, ale w innych bazach (np. PostgreSQL) cudzysłów oznacza nazwę kolumny. phpMyAdmin pokaże komunikat o 15 zmienionych wierszach. Zrzut: kw3.png.

    Typowe błędy

    UPDATE bez WHERE zmienia klasę wszystkim 94 zawodnikom - phpMyAdmin wykona to bez pytania. Przed takim zapytaniem warto uruchomić SELECT z tym samym WHERE i sprawdzić, które wiersze się zmienią.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT pseudonim, tytul, ranking, klasa
    FROM zawodnicy
    WHERE ranking > 2787
    ORDER BY ranking DESC;
    
    -- Zapytanie 2
    SELECT pseudonim, klasa
    FROM zawodnicy
    ORDER BY RAND()
    LIMIT 2;
    
    -- Zapytanie 3
    UPDATE zawodnicy
    SET klasa = '5A'
    WHERE klasa = '4A';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: ile dni minęło od zdobycia tytułu

    Kryteria:

    R.1.6 Wykonane zapytanie 4 wybierające dla zawodników z niepustym tytułem jedynie pseudonim i datę zdobycia oraz obliczające ile minęło dni od daty zdobycia tytułu do dnia dzisiejszego. Obliczenie liczby dni zapisane pod nazwą kolumny (aliasem) „dni”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT pseudonim, data_zdobycia, DATEDIFF(CURRENT_DATE(), data_zdobycia) AS dni FROM zawodnicy WHERE tytul <> ''; możliwe też CURDATE() i NOW() oraz wynik działania zapytania udokumentowany zrzutem, na którym jest komunikat o 30 pokazanych wierszach. Jedynie pola pseudonim, data_zdobycia, dni

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 4: wybierające dla zawodników z niepustym tytułem jedynie pseudonim i datę zdobycia oraz obliczające ile minęło dni od daty zdobycia tytułu do dnia dzisiejszego. Obliczona liczba dni powinna być zapisana pod nazwą kolumny (aliasem) „dni”.

    DATEDIFF(CURDATE(), data_zdobycia) - dni od daty zdobycia do dziś (dzisiejsza data pierwsza, więc wynik dodatni), AS dni - alias. „Niepusty tytuł” to w tej tabeli tytul <> '': brak tytułu zapisano pustym napisem, nie NULL. Wynik: 30 wierszy, jak w kluczu; liczba dni zależy od dnia wykonania (zrzut kw4.png powstał 2026-10-02).

    Typowe błędy

    WHERE tytul IS NOT NULL przepuszcza puste napisy - wyjdą wszystkie 94 wiersze zamiast 30.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT pseudonim, tytul, ranking, klasa
    FROM zawodnicy
    WHERE ranking > 2787
    ORDER BY ranking DESC;
    
    -- Zapytanie 2
    SELECT pseudonim, klasa
    FROM zawodnicy
    ORDER BY RAND()
    LIMIT 2;
    
    -- Zapytanie 3
    UPDATE zawodnicy
    SET klasa = '5A'
    WHERE klasa = '4A';
    
    -- Zapytanie 4
    SELECT pseudonim, data_zdobycia,
           DATEDIFF(CURDATE(), data_zdobycia) AS dni
    FROM zawodnicy
    WHERE tytul <> '';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Logo: figury na szachownicy, 320 px

    Kryteria: ,

    R.2.1 Grafika logo.png zawiera szachownicę i cztery figury, z czego czarna wieża znajduje się na skrajnym - prawym polu szachownicy oraz tło jest przezroczyste

    R.2.2 Grafika przeskalowana do szerokości 320 px, odpowiadająca temu wysokość wynosi 267 px (± 5 px)

    ok. 8 min
    Polecenie z arkusza

    Cechy grafiki: Nazwa pliku logo.png. Tło przezroczyste. Grafika powstała z połączenia plików board.jpg i chess.jpg w ten sposób, że figury zostały wklejone na szachownicę w miejscu zgodnym z ilustracją 2. Grafika przeskalowana z zachowaniem proporcji do szerokości 320 px.

    Grafika jest taka sama jak w wersji podstawowej. W GIMP-ie:

    1. board.jpg, Warstwa → Przezroczystość → Dodaj kanał alfa, Zaznaczanie według koloru na białym tle i Delete - znika tło i białe pola szachownicy,
    2. Plik → Otwórz jako warstwy chess.jpg, kanał alfa, Różdżka na szarym tle i Delete - zostają cztery figury,
    3. Przesunięcie: czarna wieża na skrajnym prawym polu (to sprawdza klucz R.2.1), reszta figur jak na ilustracji 2,
    4. Obraz → Skaluj obraz: szerokość 320 z zamkniętym łańcuchem - wysokość 267 px (R.2.2),
    5. Eksportuj jako logo.png (PNG zachowuje przezroczystość).
    Typowe błędy

    Skalowanie przed złożeniem warstw zmienia tylko jedną z nich - figury wyjdą nie w tej skali co szachownica.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik szachy.php: HTML5, język, kodowanie

    Kryteria:

    R.2.3 Witryna internetowa zapisana w pliku szachy.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz stronie nadany tytuł "KOŁO SZACHOWE”. Strona zawiera sekcje head i body

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze strony o nazwie szachy.php. Zapisana w języku HTML5. Zadeklarowany polski język zawartości witryny. Jawnie zastosowany właściwy standard kodowania polskich znaków.

    Plik szachy.php: <!DOCTYPE html>, <html lang="pl"> i <meta charset="UTF-8"> jako pierwszy element <head> - przeglądarka musi poznać kodowanie, zanim przeczyta pierwszą polską literę. Rozszerzenie .php, bo strona pobierze dane z bazy; otwierasz ją przez http://localhost/....

    szachy.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  10. Krok 10: Tytuł strony i arkusz stylów

    Kryteria: ,

    R.2.3 Witryna internetowa zapisana w pliku szachy.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl"> oraz stronie nadany tytuł "KOŁO SZACHOWE”. Strona zawiera sekcje head i body

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

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „KOŁO SZACHOWE” widoczny na karcie przeglądarki. Arkusz stylów w pliku o nazwie styles.css prawidłowo połączony z kodem strony.

    <title> (tekst na karcie przeglądarki) i <link> do styles.css - z „s” na końcu (R.3.2). Do tego viewport: bez niego telefon wyświetla stronę jak pomniejszony ekran komputera.

    Typowe błędy

    style.css zamiast styles.css odcina wszystkie style, a z nimi R.3.2 i ocenę stylów w przeglądarce.

    szachy.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  11. Krok 11: Bloki semantyczne

    Kryteria:

    R.2.4 Zdefiniowany układ strony dzieląc ją na bloki: nagłówkowy, lewy, prawy i stopki przy pomocy semantycznych znaczników sekcji języka HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, do stopki - footer. Dopuszcza się dodatkowe użycie bloków div lub section

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: nagłówkowy, poniżej lewy i prawy, na dole blok stopki. Podział zrealizowany za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 2.

    Znaczniki wybrane od treści bloków, nie od położenia:

    • <header> i <footer> - nagłówek i stopka (klucz R.2.4 wymienia je wprost),
    • <aside> - blok lewy: odnośniki do zrzutów i logo, czyli dodatki obok głównej treści,
    • <main> - blok prawy: tabela najlepszych graczy i losowanie, czyli to, po co ktoś wchodzi na stronę.

    Każdy z tych znaczników występuje na stronie raz, więc CSS trafi w nie samym selektorem znacznika - bez identyfikatorów. Ułożenie lewego i prawego obok siebie zrobi siatka CSS.

    szachy.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
        </header>
        <aside>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  12. Krok 12: Nagłówek z tekstem uwypuklonym

    Kryteria:

    R.2.10 Zastosowany znacznik <em> do zapisu w bloku nagłówkowym

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: Nagłówek drugiego stopnia o treści: „Koło szachowe gambit piona”. Pochylenie jest realizowane za pomocą znacznika semantycznego oznaczającego tekst uwypuklony.

    Pochylone są tylko słowa „gambit piona”. Znacznik tekstu uwypuklonego to <em> (emphasis): niesie znaczenie, a kursywę dodaje przeglądarka (R.2.10).

    Typowe błędy

    <i> też pochyla, ale nie oznacza uwypuklenia - R.2.10 wymaga <em>.

    szachy.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>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  13. Krok 13: Blok lewy: nagłówek i lista odnośników

    Kryteria: ,

    R.2.7 W bloku lewym umieszczona jedna lista punktowana z czterema elementami, zastosowane znaczniki <ul>, <li>

    R.3.3 Utworzone 4 odnośniki nazwane: kwerenda1, kwerenda2, kwerenda3, kwerenda4. Po wybraniu przynajmniej jednego odnośnika otwiera/pobiera się plik graficzny

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek czwartego stopnia o treści: „Polecane linki”. Lista punktowana (nieuporządkowana) o elementach: kwerenda1, kwerenda2, kwerenda3, kwerenda4, które są odnośnikami do plików zawierających odpowiadające im zrzuty ekranu.

    <h4> i <ul> z czterema <li>, a w każdym <a> ze ścieżką do zrzutu (R.2.7). Zrzuty leżą w tym samym folderze co strona, więc w href wystarczy nazwa pliku - kliknięcie otworzy obraz (R.3.3). W podglądzie kliknięcia są zablokowane.

    szachy.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  14. Krok 14: Blok lewy: logo

    Kryteria:

    R.2.6 W bloku lewym umieszczona grafika z logo z tekstem alternatywnym "Logo koła"

    ok. 1 min
    Polecenie z arkusza

    Grafika logo.png z tekstem alternatywnym o treści: „Logo koła”.

    Obraz pod listą; alt to tekst, który przeczyta czytnik ekranu i który pojawi się, gdy plik się nie wczyta (R.2.6). HTML5: bez ukośnika na końcu <img>.

    szachy.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>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  15. Krok 15: Blok prawy: nagłówek i tabela z wierszem nagłówkowym

    Kryteria:

    R.2.9 Pierwszy wiersz tabeli zawiera komórki nagłówkowe zastosowany znacznik <th>

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek trzeciego stopnia o treści: „Najlepsi gracze naszego koła”. Tabela o pięciu kolumnach z wierszem o komórkach nagłówkowych: Pozycja, Pseudonim, Tytuł, Ranking, Klasa. Wypełniona przez skrypt 1.

    • <h3> z tytułem bloku,
    • tabela podzielona na <thead> (wiersz nagłówkowy z pięcioma <th>, R.2.9) i <tbody> - pusty, wiersze z graczami wypisze Skrypt 1. Podział pomaga czytnikom ekranu i drukowaniu (przy długiej tabeli nagłówek powtarza się na każdej stronie wydruku),
    • scope="col" mówi, że komórka nagłówkowa opisuje kolumnę pod sobą.
    szachy.php PHP zmienione: 14 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  16. Krok 16: Formularz z przyciskiem losowania

    Kryteria:

    R.3.4 Kliknięcie przycisku „Losuj nową parę graczy”, powoduje uruchomienie skryptu (input lub button z typem submit lub button bez typu)

    ok. 2 min
    Polecenie z arkusza

    Formularz zawierający przycisk z tekstem „Losuj nową parę graczy”, którego wciśnięcie powoduje wykonanie skryptu 2.

    Formularz bez action wysyła się do tego samego pliku, więc kliknięcie ładuje stronę ponownie i PHP może wylosować parę (R.3.4 - przycisk z typem submit).

    Metoda get: losowanie niczego w bazie nie zmienia, tylko czyta, a do takich żądań służy GET. Adres dostaje końcówkę ?draw=1, odświeżenie (F5) losuje nową parę bez pytania o „ponowne przesłanie formularza”. POST zostaje dla formularzy, które coś zapisują. Arkusz metody nie narzuca.

    szachy.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  17. Krok 17: Paragraf z legendą i stopka

    Kryteria:

    R.2.5 Umieszczony w bloku nagłówkowym nagłówek <h2>: „Koło szachowe gambit piona”, w bloku lewym <h4>: „Polecane linki", w bloku prawym <h3>: „Najlepsi gracze naszego koła” oraz przynajmniej jeden paragraf

    ok. 2 min
    Polecenie z arkusza

    Paragraf zawierający tekst, który należy przekopiować z pliku legenda.txt z wypakowanego archiwum. Zawartość stopki: paragraf o treści „Stronę wykonał: ”, dalej wstawiony numer zdającego.

    Treść legenda.txt skopiuj do <p> pod formularzem - objaśnia skróty z kolumny „Tytuł”. Komplet nagłówków i paragrafów to R.2.5. W stopce akapit: na egzaminie po „Stronę wykonał:” wpisujesz swój numer zdającego (PESEL), tu stoi autor rozwiązania.

    szachy.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>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  18. Etap 3: Styl CSS

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

    Krok 18: Plik styles.css: krój dla wszystkich elementów

    Kryteria:

    R.4.1 Ustawiony domyślnie dla wszystkich selektorów (*): krój czcionki Helvetica

    ok. 1 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: krój czcionki Helvetica.

    Selektor uniwersalny * i Helvetica jako pierwszy krój (R.4.1). Dalsze kroje to zapas: na Windows Helvetiki zwykle nie ma, więc przeglądarka weźmie Arial, a gdy i jego zabraknie - dowolny krój bezszeryfowy. Bez zapasu wybrałaby krój domyślny, często szeryfowy.

    styles.css CSS nowy plik
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    Podgląd strony po tym kroku (szachy.php)
  19. Krok 19: Kolory z arkusza w zmiennych

    ok. 1 min

    Każdy kolor z arkusza zapisany raz, w zmiennych CSS (custom properties) na :root. Żółć #FFD966 występuje w trzech blokach - w regułach stanie var(--yellow), a zmiana odcienia to jedna linia. Nazwy mówią, czym kolor jest. Klucz ocenia kolor, który blok faktycznie dostaje, a var() daje dokładnie tę wartość.

    styles.css CSS zmienione: 7 linii
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    Podgląd strony po tym kroku (szachy.php)
  20. Krok 20: Układ strony na siatce

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 2 w arkuszu egzaminacyjnym (prawidłowo zastosowane właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid albo position )

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki: nagłówkowy, poniżej lewy i prawy, na dole blok stopki, tak aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 2.

    <body> staje się siatką o dwóch kolumnach: grid-template-columns: 25% 75% - to od razu szerokości bloku lewego i prawego (klucz R.4.4 przyjmuje je w tej postaci). grid-template-areas rysuje układ z ilustracji 2 słowami: nagłówek na dwie kolumny, pod nim aside i main, na dole stopka na dwie kolumny. Każdy blok dostaje swoje pole przez grid-area (R.3.1).

    Siatka nie wyjmuje bloków z przepływu, więc nie ma float ani clear w stopce, a dodatkowy padding bloku nie zepchnie bloku prawego pod lewy.

    styles.css CSS zmienione: 25 linii
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    aside {
        grid-area: aside;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
    }
    Podgląd strony po tym kroku (szachy.php)
  21. Krok 21: Nagłówek i stopka: kolory, odstępy, cień tekstu

    Kryteria: , , , ,

    R.4.2 Ustawiony kolor tła dla: bloku nagłówkowego, lewego i stopki: #FFD966 oraz dla bloku prawego: #C5E0B4

    R.4.3 Ustawiony kolor czcionki: biały dla bloku nagłówkowego i stopki, SeaGreen dla selektora a oraz selektora h4

    R.4.5 Ustawione wyrównanie tekstu do środka dla bloku nagłówkowego, prawego i stopki

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

    R.4.8 Ustawiony dla bloku nagłówkowego i stopki cień tekstu (text-shadow: 5px 5px 10px black;) oraz cień wewnętrzny bloku prawego (box-shadow: 0 0 15px black inset;)

    ok. 3 min
    Polecenie z arkusza

    Wspólne dla bloku nagłówkowego i stopki: kolor tła #FFD966, biały kolor czcionki, marginesy wewnętrzne 20 px, wyrównanie tekstu do środka, cień tekstu z przesunięciem w poziomie i pionie o 5 px, promieniem rozmycia 10 px i czarnym kolorem.

    Jedna reguła na dwa selektory, każdy w osobnej linii. text-shadow: 5px 5px 10px - przesunięcie poziome, pionowe, rozmycie, kolor (kolejność z tabeli 2 arkusza). Biały tekst na jasnożółtym tle jest czytelny dzięki ciemnemu cieniowi.

    styles.css CSS zmienione: 9 linii
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
    }
    Podgląd strony po tym kroku (szachy.php)
  22. Krok 22: Stopka: większa czcionka

    Kryteria:

    R.4.10 Ustawiony rozmiar czcionki 120% dla stopki

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo dla bloku stopki: rozmiar czcionki 120%.

    Cecha tylko stopki trafia do reguły footer obok jej pola siatki (R.4.10).

    styles.css CSS zmienione: 1 linia
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    Podgląd strony po tym kroku (szachy.php)
  23. Krok 23: Blok lewy

    Kryteria: ,

    R.4.2 Ustawiony kolor tła dla: bloku nagłówkowego, lewego i stopki: #FFD966 oraz dla bloku prawego: #C5E0B4

    R.4.4 Ustawiona wysokość bloku lewego i prawego 450px oraz szerokość bloku lewego 25%, bloku prawego 75% (width lub grid-template-columns lub flex), tabeli na 70%

    ok. 1 min
    Polecenie z arkusza

    Dla bloku lewego: kolor tła #FFD966, szerokość 25%, wysokość 450 px.

    Tło i wysokość. Szerokości 25% tu nie ma - daje ją pierwsza kolumna siatki. Wpisanie dodatkowo width: 25% byłoby błędem: procent liczyłby się od kolumny, więc blok zająłby ćwierć z ćwierci.

    styles.css CSS zmienione: 2 linie
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
        background-color: var(--yellow);
        height: 450px;
    }
    
    main {
        grid-area: main;
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    Podgląd strony po tym kroku (szachy.php)
  24. Krok 24: Blok prawy: cień wewnętrzny

    Kryteria: , , ,

    R.4.2 Ustawiony kolor tła dla: bloku nagłówkowego, lewego i stopki: #FFD966 oraz dla bloku prawego: #C5E0B4

    R.4.4 Ustawiona wysokość bloku lewego i prawego 450px oraz szerokość bloku lewego 25%, bloku prawego 75% (width lub grid-template-columns lub flex), tabeli na 70%

    R.4.5 Ustawione wyrównanie tekstu do środka dla bloku nagłówkowego, prawego i stopki

    R.4.8 Ustawiony dla bloku nagłówkowego i stopki cień tekstu (text-shadow: 5px 5px 10px black;) oraz cień wewnętrzny bloku prawego (box-shadow: 0 0 15px black inset;)

    ok. 2 min
    Polecenie z arkusza

    Dla bloku prawego: kolor tła #C5E0B4, szerokość 75%, wysokość 450 px, wyrównanie tekstu do środka, cień wewnętrzny bez przesunięcia w obu osiach (wartość 0), z promieniem rozmycia 15 px i czarnym kolorem.

    box-shadow: inset 0 0 15px - słowo inset zamienia cień zewnętrzny na wewnętrzny; może stać na początku albo na końcu (klucz R.4.8 podaje go na końcu - oba zapisy są poprawne). Przesunięcia 0, rozmycie 15 px: ciemna poświata wzdłuż krawędzi bloku. Szerokość 75% daje druga kolumna siatki.

    styles.css CSS zmienione: 4 linie
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
        background-color: var(--yellow);
        height: 450px;
    }
    
    main {
        grid-area: main;
        background-color: var(--green);
        height: 450px;
        text-align: center;
        box-shadow: inset 0 0 15px var(--shadow);
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    Podgląd strony po tym kroku (szachy.php)
  25. Krok 25: Tabela: obramowanie, wyśrodkowanie i szerokość

    Kryteria: , ,

    R.4.4 Ustawiona wysokość bloku lewego i prawego 450px oraz szerokość bloku lewego 25%, bloku prawego 75% (width lub grid-template-columns lub flex), tabeli na 70%

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

    R.4.9 Ustawione dla tabeli, komórki nagłówkowej i komórki tabeli obramowanie 1px solid black oraz połączono linie tabeli (border-collapse: collapse;)

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla tabeli, komórek nagłówkowych i zwykłych komórek: obramowanie o szerokości 1 px linią ciągłą czarną, połączone linie tabeli. Dodatkowo dla tabeli: marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość 70%.

    border-collapse: collapse łączy ramki sąsiednich komórek w jedną linię (R.4.9). margin: auto dzieli wolne miejsce po równo na boki - tabela staje na środku bloku prawego, a 70% liczy się od jego szerokości (R.4.4, R.4.6).

    styles.css CSS zmienione: 12 linii
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
        background-color: var(--yellow);
        height: 450px;
    }
    
    main {
        grid-area: main;
        background-color: var(--green);
        height: 450px;
        text-align: center;
        box-shadow: inset 0 0 15px var(--shadow);
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    
    table,
    th,
    td {
        border: 1px solid black;
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 70%;
    }
    Podgląd strony po tym kroku (szachy.php)
  26. Krok 26: Lista, odnośniki i nagłówek czwartego stopnia

    Kryteria: ,

    R.4.3 Ustawiony kolor czcionki: biały dla bloku nagłówkowego i stopki, SeaGreen dla selektora a oraz selektora h4

    R.4.7 Ustawione dla selektora ul: typ punktora kwadrat oraz interlinia 1.5

    ok. 2 min
    Polecenie z arkusza

    Dla selektora listy punktowanej: typ punktora kwadrat, wysokość wiersza (interlinia) 1.5. Dla selektora odnośnika i selektora nagłówka czwartego stopnia: kolor czcionki SeaGreen.

    Tu nie ma wyboru techniki: arkusz każe użyć wyłącznie selektorów znaczników, a klucz R.4.3 i R.4.7 nie uzna klasy ani selektora potomka (aside ul). line-height: 1.5 bez jednostki - półtora rozmiaru czcionki, także dla elementów potomnych. Kolor SeaGreen dostanie też <h4> z wylosowaną parą.

    styles.css CSS zmienione: 10 linii
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
        background-color: var(--yellow);
        height: 450px;
    }
    
    main {
        grid-area: main;
        background-color: var(--green);
        height: 450px;
        text-align: center;
        box-shadow: inset 0 0 15px var(--shadow);
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    
    table,
    th,
    td {
        border: 1px solid black;
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 70%;
    }
    
    ul {
        list-style-type: square;
        line-height: 1.5;
    }
    
    a,
    h4 {
        color: var(--link);
    }
    Podgląd strony po tym kroku (szachy.php)
  27. Krok 27: Logo mieści się w bloku lewym

    ok. 1 min

    Dodatek spoza arkusza. Logo ma 320 px, a blok lewy to 25% szerokości strony - w oknie węższym niż ok. 1300 px kolumna jest węższa od obrazu i logo wystaje pod blok prawy (tak jest w wersji podstawowej). max-width: 100% pozwala obrazowi zmniejszyć się do szerokości bloku, a w szerokim oknie zostaje on w pełnych 320 px. Plik logo.png nadal ma 320 px, więc R.2.2 się nie zmienia.

    styles.css CSS zmienione: 4 linie
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    :root {
        --yellow: #FFD966;
        --green: #C5E0B4;
        --link: SeaGreen;
        --shadow: black;
    }
    
    body {
        display: grid;
        grid-template-columns: 25% 75%;
        grid-template-areas:
            "header header"
            "aside  main"
            "footer footer";
    }
    
    header {
        grid-area: header;
    }
    
    header,
    footer {
        background-color: var(--yellow);
        color: white;
        padding: 20px;
        text-align: center;
        text-shadow: 5px 5px 10px var(--shadow);
    }
    
    aside {
        grid-area: aside;
        background-color: var(--yellow);
        height: 450px;
    }
    
    main {
        grid-area: main;
        background-color: var(--green);
        height: 450px;
        text-align: center;
        box-shadow: inset 0 0 15px var(--shadow);
    }
    
    footer {
        grid-area: footer;
        font-size: 120%;
    }
    
    table,
    th,
    td {
        border: 1px solid black;
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 70%;
    }
    
    ul {
        list-style-type: square;
        line-height: 1.5;
    }
    
    a,
    h4 {
        color: var(--link);
    }
    
    aside img {
        max-width: 100%;
    }
    Podgląd strony po tym kroku (szachy.php)
  28. Etap 4: Skrypty PHP

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

    Krok 28: Połączenie PDO na górze pliku

    Kryteria: , ,

    R.5.1 Skrypt jest napisany w języku PHP i zawiera przynajmniej jedną zgodną z treścią zadania instrukcję

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

    R.5.3 Ostatnią operacją na bazie jest jej zamknięcie

    ok. 4 min
    Polecenie z arkusza

    Napisane w języku PHP. Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim. Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie szachy. Na końcu zamykane jest połączenie z serwerem.

    Cała praca z bazą stoi przed <!DOCTYPE html>: najpierw dane, potem HTML, który je tylko wypisuje. Połączenie przez PDO (klucz R.5 przyjmuje MySQLi i PDO):

    • napis DSN 'mysql:host=localhost;dbname=szachy;charset=utf8mb4' - serwer, baza i kodowanie, potem użytkownik root i puste hasło (R.5.1, R.5.2),
    • ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze jako tablice z nazwami kolumn,
    • $pdo = null zamyka połączenie (PDO nie ma osobnej funkcji „zamknij”). Zapytania trafią między te dwie linie, więc zamknięcie zostanie ostatnią operacją na bazie (R.5.3),
    • try / catch (PDOException $exception) - gdy baza nie odpowiada, szczegóły idą do dziennika serwera (error_log), a strona dostaje ogólny komunikat w $dbError,
    • funkcja escape() to htmlspecialchars(..., ENT_QUOTES) pod nazwą, która mówi, co robi; stanie przy każdej wartości z bazy.

    Zmienne $topPlayers, $drawnPair, $dbError mają wartości początkowe, żeby szablon działał także po błędzie. Od tego kroku podgląd to wynik prawdziwego uruchomienia.

    szachy.php PHP zmienione: 21 linii
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  29. Krok 29: Skrypt 1: zapytanie 1

    Kryteria:

    R.5.4 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub Skrypt 2 zawiera instrukcję wysyłającą do bazy danych zapytanie 2

    ok. 2 min
    Polecenie z arkusza

    Skrypt 1: Wysyła do bazy danych zapytanie 1.

    $pdo->query(...) wysyła zapytanie 1, a ->fetchAll() od razu odbiera wszystkie 10 wierszy do tablicy $topPlayers (R.5.4). Zapytanie w kodzie ma te same linie co w kwerendy.txt. query wystarcza, bo w zapytaniu nie ma żadnej wartości od użytkownika - gdyby próg rankingu wpisywał użytkownik, byłoby prepare i execute z parametrem.

    szachy.php PHP zmienione: 9 linii
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  30. Krok 30: Skrypt 1: wiersz tabeli z numerem pozycji

    Kryteria:

    R.5.5 Skrypt 1 wyświetla kolejne liczby począwszy od 1 w pierwszej kolumnie tabeli oraz wyświetlanie jest zrealizowane z wykorzystaniem pętli

    ok. 3 min
    Polecenie z arkusza

    W każdym wierszu tabeli wpisywany jest obliczony przez skrypt kolejny numer wiersza począwszy od 1.

    W <tbody> pętla foreach ($topPlayers as $index => $player): ... endforeach; w składni alternatywnej - HTML wiersza zostaje zwykłym HTML-em, a nie napisem w echo. <?= ... ?> to skrót od <?php echo ... ?>.

    fetchAll() zwraca listę numerowaną od 0, więc pozycja to $index + 1: pierwszy gracz dostaje 1, dziesiąty 10 (R.5.5). Osobny licznik nie jest potrzebny - numer wynika z miejsca w liście. Podgląd: dziesięć wierszy z numerami, na razie tylko pierwsza kolumna.

    Typowe błędy

    Samo $index wypisze pozycje od 0 do 9 - arkusz każe liczyć od 1.

    szachy.php PHP zmienione: 5 linii
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($topPlayers as $index => $player): ?>
                        <tr>
                            <td><?= $index + 1 ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  31. Krok 31: Skrypt 1: pola rekordu w kolejnych komórkach

    Kryteria: ,

    R.2.8 W bloku prawym umieszczona tabela o 5 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>

    R.5.6 Skrypt 1 wyświetla zwrócone zapytaniem rekordy w osobnych wierszach tabeli zgodnie z przeznaczeniem kolumn

    ok. 3 min
    Polecenie z arkusza

    W każdym wierszu tabeli wpisywany jest obliczony przez skrypt kolejny numer wiersza począwszy od 1 oraz zwrócone zapytaniem pola kolejnego rekordu.

    Cztery komórki <td> po nazwach kolumn ($player['pseudonim']), każda przez escape() (R.2.8, R.5.6). Nazwy zamiast numerów [0]-[3]: kod mówi sam, co wypisuje, a zmiana kolejności w SELECT niczego nie przestawi. Podgląd: tabela jak na ilustracji 2, od LiLa (2901) do So What (2788).

    szachy.php PHP zmienione: 4 linie
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($topPlayers as $index => $player): ?>
                        <tr>
                            <td><?= $index + 1 ?></td>
                            <td><?= escape($player['pseudonim']) ?></td>
                            <td><?= escape($player['tytul']) ?></td>
                            <td><?= escape($player['ranking']) ?></td>
                            <td><?= escape($player['klasa']) ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  32. Krok 32: Skrypt 2: zapytanie 2 po kliknięciu przycisku

    ok. 3 min
    Polecenie z arkusza

    Skrypt 2: Wysyła do bazy danych zapytanie 2.

    • filter_has_var(INPUT_GET, 'draw') - prawda tylko wtedy, gdy w adresie jest parametr draw, czyli po kliknięciu przycisku. Funkcja czyta to, co naprawdę przyszło w żądaniu, a nie tablicę $_GET, którą kod mógłby wcześniej zmienić. Przy zwykłym wejściu na stronę losowanie się nie wykonuje,
    • w środku zapytanie 2: dwa wiersze trafiają do $drawnPair.

    $pdo = null nadal stoi za oboma skryptami - zamknięcie zostaje ostatnią operacją na bazie. Podgląd: strona po kliknięciu, para jeszcze nie jest wypisana.

    szachy.php PHP zmienione: 5 linii
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        // Skrypt 2: losowanie pary po kliknięciu przycisku
        if (filter_has_var(INPUT_GET, 'draw')) {
            $drawnPair = $pdo->query('SELECT pseudonim, klasa FROM zawodnicy ORDER BY RAND() LIMIT 2')->fetchAll();
        }
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($topPlayers as $index => $player): ?>
                        <tr>
                            <td><?= $index + 1 ?></td>
                            <td><?= escape($player['pseudonim']) ?></td>
                            <td><?= escape($player['tytul']) ?></td>
                            <td><?= escape($player['ranking']) ?></td>
                            <td><?= escape($player['klasa']) ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  33. Krok 33: Skrypt 2: para graczy w nagłówku czwartego stopnia

    Kryteria: ,

    R.5.7 Skrypt 2 wyświetla zwrócone zapytaniem dwa rekordy

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

    ok. 3 min
    Polecenie z arkusza

    W nagłówku czwartego stopnia wyświetla oba pobrane rekordy oddzielając je spacją.

    • funkcja playerLabel() zamienia jeden rekord w napis „pseudonim klasa”; typy array i string w nagłówku mówią, co przyjmuje i co zwraca,
    • array_map('playerLabel', $drawnPair) robi z dwóch rekordów dwa napisy, a implode(' ', ...) skleja je spacją - bez spacji na końcu, którą zostawiłaby pętla z echo,
    • <?php if ($drawnPair !== []): ?> - nagłówek powstaje tylko po kliknięciu, gdy jest co pokazać.

    Wynik: „WalSał 2A MicKra 4B” w jednym <h4> (R.5.7), w kolorze SeaGreen z reguły a, h4. Nazwy funkcji i zmiennych po angielsku mówią, co przechowują (R.5.8). Podgląd: strona po kliknięciu; na egzaminie każde kliknięcie daje inną parę, w podglądzie jest para z ilustracji 2.

    szachy.php PHP zmienione: 8 linii
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    function playerLabel(array $player): string
    {
        return $player['pseudonim'] . ' ' . $player['klasa'];
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        // Skrypt 2: losowanie pary po kliknięciu przycisku
        if (filter_has_var(INPUT_GET, 'draw')) {
            $drawnPair = $pdo->query('SELECT pseudonim, klasa FROM zawodnicy ORDER BY RAND() LIMIT 2')->fetchAll();
        }
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($topPlayers as $index => $player): ?>
                        <tr>
                            <td><?= $index + 1 ?></td>
                            <td><?= escape($player['pseudonim']) ?></td>
                            <td><?= escape($player['tytul']) ?></td>
                            <td><?= escape($player['ranking']) ?></td>
                            <td><?= escape($player['klasa']) ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <?php if ($drawnPair !== []): ?>
                <h4><?= escape(implode(' ', array_map('playerLabel', $drawnPair))) ?></h4>
            <?php endif; ?>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  34. Krok 34: Komunikat, gdy baza nie odpowiada

    ok. 3 min
    Polecenie z arkusza

    Na końcu zamykane jest połączenie z serwerem.

    Pod tabelą akapit z $dbError - tylko wtedy, gdy catch coś do niego wpisał. Sprawdzone uruchomieniem z błędną nazwą bazy: strona się wyświetla, tabela ma sam wiersz nagłówkowy, pod nią stoi „Nie udało się pobrać danych o zawodnikach…”, a w treści nie ma ani nazwy bazy, ani kodu błędu SQL. Bez try/catch PHP przerwałby stronę w połowie komunikatem „Fatal error: Uncaught PDOException” z pełną ścieżką pliku na serwerze.

    W normalnym działaniu połączenie jest zamykane ($pdo = null) zaraz po obu zapytaniach, przed pierwszą linią HTML. Podgląd: strona po kliknięciu, bez komunikatu.

    szachy.php PHP zmienione: 3 linie
    <?php
    function escape(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES);
    }
    
    $topPlayers = [];
    $drawnPair = [];
    $dbError = '';
    
    function playerLabel(array $player): string
    {
        return $player['pseudonim'] . ' ' . $player['klasa'];
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=szachy;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: najlepsi gracze
        $topPlayers = $pdo->query(
            'SELECT pseudonim, tytul, ranking, klasa
             FROM zawodnicy
             WHERE ranking > 2787
             ORDER BY ranking DESC'
        )->fetchAll();
    
        // Skrypt 2: losowanie pary po kliknięciu przycisku
        if (filter_has_var(INPUT_GET, 'draw')) {
            $drawnPair = $pdo->query('SELECT pseudonim, klasa FROM zawodnicy ORDER BY RAND() LIMIT 2')->fetchAll();
        }
    
        $pdo = null;
    } catch (PDOException $exception) {
        error_log($exception->getMessage());
        $dbError = 'Nie udało się pobrać danych o zawodnikach. Spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>KOŁO SZACHOWE</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>Koło szachowe <em>gambit piona</em></h2>
        </header>
        <aside>
            <h4>Polecane linki</h4>
            <ul>
                <li><a href="kw1.png">kwerenda1</a></li>
                <li><a href="kw2.png">kwerenda2</a></li>
                <li><a href="kw3.png">kwerenda3</a></li>
                <li><a href="kw4.png">kwerenda4</a></li>
            </ul>
            <img src="logo.png" alt="Logo koła">
        </aside>
        <main>
            <h3>Najlepsi gracze naszego koła</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Pozycja</th>
                        <th scope="col">Pseudonim</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Ranking</th>
                        <th scope="col">Klasa</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($topPlayers as $index => $player): ?>
                        <tr>
                            <td><?= $index + 1 ?></td>
                            <td><?= escape($player['pseudonim']) ?></td>
                            <td><?= escape($player['tytul']) ?></td>
                            <td><?= escape($player['ranking']) ?></td>
                            <td><?= escape($player['klasa']) ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            <?php if ($dbError !== ''): ?>
                <p><?= escape($dbError) ?></p>
            <?php endif; ?>
            <form method="get">
                <button type="submit" name="draw" value="1">Losuj nową parę graczy</button>
            </form>
            <?php if ($drawnPair !== []): ?>
                <h4><?= escape(implode(' ', array_map('playerLabel', $drawnPair))) ?></h4>
            <?php endif; ?>
            <p>Legenda: AM - Absolutny Mistrz, SM - Szkolny Mistrz, PM - Mistrz Poziomu, KM - Mistrz Klasowy</p>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szachy.php)
  35. Etap 5: Porównanie z wersją podstawową

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

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

    ok. 2 min

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

    wersja podstawowawersja nowoczesna
    układfloat: left sekcji + clear: both w stopcedisplay: grid i grid-template-areas na <body>
    szerokości blokówwidth w regułach #left, #rightgrid-template-columns: 25% 75%
    kolorywpisane w każdej regulezmienne CSS w :root
    bloki bocznedwie <section> z id<aside> i <main>, selektory znaczników
    bazamysqli_connect, mysqli_fetch_row, $row[0]PDO z wyjątkami, fetchAll, $player['pseudonim']
    numer pozycjiosobny licznik $position++$index + 1 z listy
    losowanieformularz POST (w dobrych praktykach GET)formularz GET od początku, filter_has_var
    dane na stroniewprost (w dobrych praktykach htmlspecialchars)escape() przy każdej wartości
    awaria bazybiała strona z błędemkomunikat pod tabelą, szczegóły w error_log

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 arkusza i jest szybsza do napisania. Nowoczesna oddziela pobieranie danych od wyglądu i przy większej stronie łatwiej ją zmieniać. Czego tu świadomie nie ma: pliku config.php z danymi logowania do bazy (klucz szuka połączenia w kodzie strony) i zapytań przygotowanych - żadna wartość od użytkownika nie trafia do SQL.

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

  36. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego.

    W przeglądarka.txt nazwa przeglądarki, w której strona była sprawdzana przez http://localhost/.... W folderze: szachy.php, styles.css, kwerendy.txt, import.png, kw1.png - kw4.png, logo.png i przeglądarka.txt. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.