INF.03-11-25.01-SGStyczeń 2025 · 32 kroki · ok. 78 min · 37 kryteriów z klucza
Rozwiązanie krok po kroku: Losowanie nagród wolontariatu (Nowoczesny kod (grid, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza konkurs z czterema zapytaniami, puchar z cieniem i strona konkurs.php z tabelą pięciu losowych nagród - 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 79% i 20% stoją w grid-template-columns (klucz R.4.6 przyjmuje je wprost) - bez float i clear,
kolory w zmiennych CSS: pięć kolorów z arkusza zapisanych raz, w :root,
znaczniki od treści: blok lewy to <main> (losowane nagrody), blok prawy to <aside> (puchar i odnośniki),
PHP na PDO: zapytanie na górze pliku, połączenie zamknięte, zanim zacznie się HTML, tabela wypisywana pętlą foreach w szablonie,
bezpieczeństwo i porządek w danych: escape() przy każdej wartości z bazy, try/catch przy awarii bazy, cena po polsku (1 230,00 zł) i „brak ceny” zamiast „0,00 zł” dla nagród bez ceny,
zapytanie 4 przedziałem dat zamiast porównywania daty jak tekstu.
Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza i grafika pochodzą z prawdziwego archiwum pliki2, 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 1 losuje, więc w podglądzie stoi pięć nagród z ilustracji 2, w tej samej kolejności.
Jak liczą się punkty. Klucz ma 37 kryteriów (R.1.1 - R.5.7), każde za 1 punkt. Próg zdania to 75%, czyli 28 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-7 · po tym etapie masz 6 z 37 kryteriów (pkt)
Krok 1: Baza danych konkurs
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie konkurs, z zestawem polskich znaków (np. utf8_unicode_ci).
Archiwum pliki2.7z rozpakuj hasłem ^WolonTari@t (daszek na początku, małpa zamiast „a”) do folderu z numerem zdającego: baza.sql i puchar.bmp. W phpMyAdmin Nowa → konkurs, porównywanie utf8_unicode_ci, albo zapytaniem:
CREATE DATABASE konkurs CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Typowe błędy
Nazwa bazy musi być dokładnie konkurs - skrypt łączy się z bazą po nazwie (R.5.2).
Krok 2: Import tabeli z pliku baza.sql
ok. 2 min
Polecenie z arkusza
Z rozpakowanego archiwum zaimportuj tabelę z pliku baza.sql do utworzonej bazy.
Import → baza.sql. Tabela nagrody z ilustracji 1: 25 nagród z nazwą, opisem, ceną (decimal(19,2), pole może być puste - NULL), liczbą sztuk i datą dodania (typ date).
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonany import tabeli do bazy danych konkurs , 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 nagrody 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).
Krok 4: Zapytanie 1: pięć losowych nagród
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 losowo dokładnie pięć rekordów z tabeli nagrody zawierających jedynie pola nazwa, opis i cena. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, opis, cena FROM nagrody ORDER BY RAND() LIMIT 5; oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 5 dowolnych rekordów zawierających jedynie pola nazwa, opis, cena
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające losowo dokładnie pięć rekordów z tabeli nagrody zawierających jedynie pola nazwa, opis i cena.
Każda klauzula w osobnej linii: trzy kolumny, ORDER BY RAND() tasuje wiersze (każdy dostaje liczbę losową), LIMIT 5 zostawia pięć pierwszych. Przy każdym wykonaniu inne nagrody - klucz to przewiduje. Zapytanie zapisz w kwerendy.txt, zrzut jako kw1.png. To zapytanie wyśle skrypt na stronie.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT nazwa, opis, cenaFROM nagrodyORDER BY RAND()LIMIT 5;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: cena od 100 do 1000 zł i dwie sztuki
Kryteria:
R.1.4 Wykonane zapytanie 2 wybierające wszystkie pola z tabeli nagrody , dla których cena mieści się w przedziale <100, 1000>, oraz ilość jest równa 2 sztuki. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT * FROM nagrody WHERE cena BETWEEN 100 AND 1000 AND ilosc_sztuk = 2; (dopuszczalne inne rozwiązania ) oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dokładnie dwa rekordy o id 7 i 14
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające wszystkie pola z tabeli nagrody, dla których cena mieści się w przedziale <100, 1000>, oraz których ilość jest równa 2 sztuki.
Nawiasy ostre <100, 1000> w matematyce oznaczają przedział domknięty - i dokładnie tak działa BETWEEN 100 AND 1000 (to samo co cena >= 100 AND cena <= 1000). Drugi warunek w osobnej linii z AND - oba muszą być spełnione. Wynik: dwie nagrody o id 7 i 14, jak w kluczu. Zrzut: kw2.png.
Typowe błędy
cena > 100 AND cena < 1000 pomija granice przedziału.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT nazwa, opis, cenaFROM nagrodyORDER BY RAND()LIMIT 5;-- Zapytanie 2SELECT *FROM nagrodyWHERE cena BETWEEN 100 AND 1000 AND ilosc_sztuk = 2;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: usunięcie nagród bez ceny
Kryteria:
R.1.5 Wykonane zapytanie 3 usuwające te rekordy, w których cena nie została wpisana lub wynosi 0 zł. W pliku z kwerendami lub na zrzucie istnieje zapis np.: DELETE FROM nagrody WHERE cena IS NULL OR cena = 0; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczny jest komunikat o zmodyfikowaniu 5 rekordów lub tabela z usuniętymi rekordami
ok. 3 min
Polecenie z arkusza
Zapytanie 3: usuwające te rekordy, w których cena nie została wpisana lub wynosi 0 zł.
„Nie została wpisana” to w SQL IS NULL - wartości NULL nie da się porównać znakiem =, bo każde porównanie z nią daje „nieznane”, a nie prawdę. „Wynosi 0 zł” to zwykłe cena = 0. phpMyAdmin pokaże komunikat o 5 usuniętych wierszach (cztery nagrody bez ceny i zatyczki do uszu za 0,00 zł). Zrzut: kw3.png.
Typowe błędy
WHERE cena = NULL nie usunie niczego. Przed każdym DELETE warto uruchomić SELECT z tym samym WHERE i zobaczyć, które wiersze znikną.
kwerendy.txtTekstzmienione: 5 linii
-- Zapytanie 1SELECT nazwa, opis, cenaFROM nagrodyORDER BY RAND()LIMIT 5;-- Zapytanie 2SELECT *FROM nagrodyWHERE cena BETWEEN 100 AND 1000 AND ilosc_sztuk = 2;-- Zapytanie 3DELETE FROM nagrodyWHERE cena IS NULL OR cena = 0;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nagrody dodane w sierpniu 2021
Kryteria:
R.1.6 Wykonane zapytanie 4 wybierające jedynie nazwę, cenę i datę dodania nagród, które zostały dodane w sierpniu 2021 roku. Wyniki powinny być posortowane rosnąco według daty. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, cena, data_dodania FROM nagrody WHERE data_dodania LIKE '2021-08-%' ORDER BY data_dodania ASC; (dopuszczalne inne rozwiązania, ASC opcjonalne ) oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są wyłącznie rekordy zawierające nazwę, cenę i datę dodania z sierpnia 2021 posortowane wg daty rosnąco (w zależności od wykonania / niewykonania kwerendy 3 może być różna liczba zwróconych rekordów: 14, 10 lub inna gdy kwerenda 3 jest błędna)
ok. 3 min
Polecenie z arkusza
Zapytanie 4: wybierające jedynie nazwę, cenę i datę dodania nagród, które zostały dodane w sierpniu 2021 roku. Wyniki powinny być posortowane rosnąco według daty.
Sierpień 2021 jako przedział dat: od '2021-08-01' włącznie do '2021-09-01' wyłącznie. Kolumna data_dodania ma typ date, więc porównanie jest porównaniem dat - działałoby też dla typu z godziną (datetime), gdzie <= '2021-08-31' zgubiłoby cały ostatni dzień. Taki warunek może też korzystać z indeksu na kolumnie, a LIKE '2021-08-%' z klucza najpierw zamienia datę na tekst. Klucz przyjmuje inne rozwiązania.
ORDER BY data_dodania - rosnąco (ASC jest domyślne). Po zapytaniu 3 wychodzi 10 wierszy, przed nim 14 - klucz przyjmuje oba wyniki. Zrzut: kw4.png (po zapytaniu 3).
Typowe błędy
Samo MONTH(data_dodania) = 8 łapie sierpień z każdego roku.
kwerendy.txtTekstzmienione: 7 linii
-- Zapytanie 1SELECT nazwa, opis, cenaFROM nagrodyORDER BY RAND()LIMIT 5;-- Zapytanie 2SELECT *FROM nagrodyWHERE cena BETWEEN 100 AND 1000 AND ilosc_sztuk = 2;-- Zapytanie 3DELETE FROM nagrodyWHERE cena IS NULL OR cena = 0;-- Zapytanie 4SELECT nazwa, cena, data_dodaniaFROM nagrodyWHERE data_dodania >= '2021-08-01' AND data_dodania < '2021-09-01'ORDER BY data_dodania;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-16 · po tym etapie masz 18 z 37 kryteriów (pkt)
R.2.1 Grafika puchar.png zawiera cień przesunięty w prawo i w dół oraz tło jest przezroczyste
R.2.2 Grafika przeskalowana dokładnie do rozmiaru 260 x 260 px
ok. 8 min
Polecenie z arkusza
Cechy grafiki: Nazwa pliku puchar.png. Tło przezroczyste. Puchar rzuca cień przesunięty jednocześnie w prawo i w dół. Przeskalowana do rozmiaru 260 px na 260 px.
Grafika jest taka sama jak w wersji podstawowej. W GIMP-ie, na puchar.bmp:
Warstwa → Przezroczystość → Dodaj kanał alfa, Różdżka na białym tle i Delete. Białe prześwity w uchwytach nie łączą się z tłem - dodaj je do zaznaczenia z klawiszem Shift,
Filtry → Światło i cień → Cień: przesunięcie X i Y dodatnie (np. 20 i 20) - w prawo i w dół (R.2.1),
Obraz → Skaluj obraz: 260 × 260 - źródło jest kwadratem 745 × 745, więc proporcje zostają (R.2.2),
Eksportuj jakopuchar.png.
Typowe błędy
Ujemne przesunięcie cienia (w lewo lub w górę) nie spełnia R.2.1. JPG nie ma przezroczystości.
Podgląd strony po tym kroku
Krok 9: Plik konkurs.php: HTML5, język, kodowanie
Kryteria:
R.2.3 Witryna internetowa zapisana w pliku konkurs.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl">. Tytuł strony „WOLONTARIAT SZKOLNY”. Strona zawiera sekcje head i body
ok. 2 min
Polecenie z arkusza
Cechy witryny: Składa się ze strony o nazwie konkurs.php. Zapisana w języku HTML5. Zadeklarowany polski język zawartości witryny. Jawnie zastosowany właściwy standard kodowania polskich znaków.
Plik konkurs.php: <!DOCTYPE html>, <html lang="pl"> i <meta charset="UTF-8"> jako pierwszy element <head>. Rozszerzenie .php, bo strona pobierze nagrody z bazy - otwierasz ją przez http://localhost/....
R.2.3 Witryna internetowa zapisana w pliku konkurs.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl">. Tytuł strony „WOLONTARIAT SZKOLNY”. 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 „WOLONTARIAT SZKOLNY” 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, żeby telefon nie pomniejszał strony do szerokości ekranu komputera.
R.2.4 Zdefiniowany układ strony dzielący 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 oraz 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:
<header> i <footer> - nagłówek i stopka (klucz R.2.4 wymienia je wprost),
<main> - blok lewy: losowane nagrody, czyli główna treść strony,
<aside> - blok prawy: puchar i odnośniki do zrzutów, dodatki obok treści.
Każdy występuje raz, więc CSS trafi w nie samym selektorem znacznika. Ułożenie obok siebie zrobi siatka CSS.
Zawartość bloku nagłówkowego: Nagłówek pierwszego stopnia o treści: „KONKURS - WOLONTARIAT SZKOLNY”. Zawartość bloku lewego: Nagłówek trzeciego stopnia o treści: „Konkursowe nagrody”.
R.2.9 Utworzony w bloku lewym przycisk o treści „Losuj nowe nagrody”
R.3.4 Kliknięcie przycisku przeładowuje stronę
ok. 2 min
Polecenie z arkusza
Przycisk o treści „Losuj nowe nagrody”, jego wybranie przeładowuje stronę.
Formularz bez atrybutów z jednym <button>: przycisk w formularzu bez atrybutu type jest przyciskiem wysyłającym (klucz to przyjmuje), formularz bez action wysyła się pod adres tej samej strony, a bez method - metodą GET. Przeglądarka pobiera więc konkurs.php jeszcze raz, serwer wykonuje PHP i losuje nowe nagrody (R.2.9, R.3.4).
Bez JavaScriptu działa to także wtedy, gdy skrypty są w przeglądarce wyłączone. <button onclick="location.reload()"> też przeładowałby stronę, ale potrzebuje JavaScriptu do czegoś, co HTML robi sam.
R.2.6 Tabela zawiera wiersz z komórkami nagłówkowymi, zastosowany znacznik <th>
ok. 2 min
Polecenie z arkusza
Tabela o czterech kolumnach, z wierszem nagłówkowym o komórkach: „Nr”, „Nazwa”, „Opis”, „Wartość”. Wypełniona przez skrypt.
Pierwszy wiersz z czterema <th> (R.2.6); wiersze z nagrodami dopisze skrypt.
Tu świadomie nie ma podziału na <thead> i <tbody>, choć w innych tabelach to dobry zwyczaj. Arkusz każe pokolorować parzyste wiersze tabeli, a ilustracja 2 pokazuje żółte pierwszą, trzecią i piątą nagrodę - czyli wiersze liczone razem z nagłówkowym. Z <tbody> reguła tr:nth-child(even) liczyłaby wiersze od pierwszej nagrody i żółte byłyby druga i czwarta.
Krok 15: Blok prawy: puchar, nagłówek i lista odnośników
Kryteria: , ,
R.2.7 W bloku prawym umieszczona grafika z pucharem z tekstem alternatywnym "Puchar dla wolontariusza"
R.2.8 W bloku prawym umieszczona jedna lista punktowana o czterech elementach, 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 prawego: Grafika puchar.png z tekstem alternatywnym o treści: „Puchar dla wolontariusza”. Nagłówek czwartego stopnia o treści: „Polecane linki”. Lista punktowana (nieuporządkowana), której poszczególne elementy: „Kwerenda1”, „Kwerenda2”, „Kwerenda3”, „Kwerenda4” są odnośnikami do plików zawierających zrzuty ekranu wykonanych kwerend.
Obraz z alt (R.2.7), <h4> i <ul> z czterema <li>, a w każdym <a> do zrzutu (R.2.8, R.3.3). Zrzuty leżą w tym samym folderze co strona, więc w href wystarczy nazwa pliku. W podglądzie kliknięcia są zablokowane.
R.2.10 Utworzony w bloku nagłówkowym nagłówek <h1> o treści: „KONKURS - WOLONTARIAT SZKOLNY”, w bloku lewym <h3>: „Konkursowe nagrody”, w bloku prawym <h4>: „Polecane linki" oraz w stopce paragraf z numerem zdającego
ok. 1 min
Polecenie z arkusza
Zawartość stopki: paragraf o treści „Numer zdającego: ”, dalej wstawiony numer zdającego.
Akapit w <footer>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL), tu stoi autor rozwiązania. Z nagłówkami h1, h3 i h4 to komplet R.2.10.
Kroki 17-24 · po tym etapie masz 29 z 37 kryteriów (pkt)
Krok 17: Plik styles.css: kolory z arkusza w zmiennych
ok. 1 min
Pięć kolorów z arkusza zapisanych raz, w zmiennych CSS na :root. Kremowy #FDFAAA i zielony #5BBB77 występują w kilku blokach i w gradiencie - w regułach stanie var(--cream) i var(--green), a zmiana odcienia to jedna linia. Klucz ocenia kolor, który blok faktycznie dostaje.
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 )
R.4.1 Dla ciała strony (body lub kontenera całej strony) ustawiony krój czcionki Verdana, wyrównanie tekstu do środka, marginesy wewnętrzne górny i dolny 0, prawy i lewy 3%
R.4.6 Ustawiona szerokość bloku lewego na 79% oraz bloku prawego na 20% (width lub grid- template-columns lub flex) oraz szerokość selektora table na 80%
ok. 3 min
Polecenie z arkusza
Dla ciała strony: krój czcionki Verdana, wyrównanie tekstu do środka, marginesy wewnętrzne górny i dolny 0, prawy i lewy 3%.
Najpierw cechy z arkusza: Verdana (z zapasowym krojem bezszeryfowym), tekst do środka i padding: 0 3% - góra i dół 0, boki 3% (R.4.1).
Ta sama reguła robi z <body>siatkę: grid-template-columns: 79% 20% to od razu szerokości bloku lewego i prawego (R.4.6), a grid-template-areas rysuje układ z ilustracji 2 słowami - nagłówek na dwie kolumny, pod nim main i aside, na dole stopka (R.3.1). Procenty liczą się od szerokości treści <body>, czyli bez marginesów 3%; 79% + 20% zostawia 1% luzu po prawej. Bez float i bez clear w stopce.
R.4.3 Ustawiony kolor czcionki dla: selektora a #680808, dla selektora h4 zielony, bloku nagłówkowego #5BBB77, stopki: #FFF555
R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 10px, stopki 15px oraz marginesy zewnętrzne (margin) dla bloku lewego górny i dolny 15px, prawy i lewy 0, auto dla tabeli
R.4.8 Ustawiony cień tekstu w bloku nagłówkowym: text-shadow: 5px 5px 10px black; oraz cień bloku lewego: box-shadow: 5px 6px 10px black;
ok. 2 min
Polecenie z arkusza
Dla bloku nagłówkowego: kolor tła #FDFAAA, kolor czcionki #5BBB77, marginesy wewnętrzne 10 px, cień tekstu o cechach: przesunięcie w poziomie i pionie: 5 px, promień rozmycia: 10 px, czarny kolor cienia.
Cechy dopisane do reguły header, obok jej pola siatki. text-shadow: 5px 5px 10px black - przesunięcie poziome, pionowe, rozmycie, kolor (kolejność z tabeli 2 arkusza).
R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 10px, stopki 15px oraz marginesy zewnętrzne (margin) dla bloku lewego górny i dolny 15px, prawy i lewy 0, auto dla tabeli
R.4.8 Ustawiony cień tekstu w bloku nagłówkowym: text-shadow: 5px 5px 10px black; oraz cień bloku lewego: box-shadow: 5px 6px 10px black;
ok. 3 min
Polecenie z arkusza
Dla bloku lewego: kolor tła #FFA6A6, szerokość 79%, wysokość 600 px, marginesy zewnętrzne górny i dolny 15 px, prawy i lewy 0, cień bloku o cechach: przesunięcie w poziomie 5 px, w pionie 6 px, promień rozmycia: 10 px, kolor czarny.
margin: 15px 0 - góra i dół 15 px, boki 0; w siatce margines odsuwa blok od krawędzi jego pola. box-shadow: 5px 6px 10px black - cień całego bloku (tabela 2). Szerokości 79% tu nie ma, bo daje ją kolumna siatki - dodatkowe width: 79% liczyłoby się od kolumny i zwęziło blok.
Dla bloku prawego: tło będące gradientem liniowym od koloru #FDFAAA do koloru #5BBB77, szerokość 20%, wysokość 630 px.
linear-gradient to obraz tła, więc stoi we właściwości background, nie background-color. Bez kierunku biegnie z góry na dół - od kremowego do zielonego, jak na ilustracji 2. Wysokość 630 px = 600 px bloku lewego + jego marginesy 2 × 15 px, więc oba bloki kończą się równo.
Typowe błędy
background-color: linear-gradient(...) jest błędne - przeglądarka pominie całą deklarację.
R.4.3 Ustawiony kolor czcionki dla: selektora a #680808, dla selektora h4 zielony, bloku nagłówkowego #5BBB77, stopki: #FFF555
R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 10px, stopki 15px oraz marginesy zewnętrzne (margin) dla bloku lewego górny i dolny 15px, prawy i lewy 0, auto dla tabeli
R.4.9 Ustawiona czcionka pogrubiona, w rozmiar 120% dla bloku stopki
ok. 2 min
Polecenie z arkusza
Dla bloku stopki: kolor tła #5BBB77, kolor czcionki #FFF555, czcionka pogrubiona w rozmiarze 120%, marginesy wewnętrzne 15 px.
Krok 23: Tabela: wyśrodkowanie, komórki nagłówkowe, parzyste wiersze
Kryteria: , , ,
R.4.4 Ustawione dla selektora ul: interlinia 1.5, typ punktora kwadrat oraz dla komórki nagłówkowej tabeli: kolor tła #5BBB77, wysokość 40px, rozmiar czcionki 16px
R.4.6 Ustawiona szerokość bloku lewego na 79% oraz bloku prawego na 20% (width lub grid- template-columns lub flex) oraz szerokość selektora table na 80%
R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 10px, stopki 15px oraz marginesy zewnętrzne (margin) dla bloku lewego górny i dolny 15px, prawy i lewy 0, auto dla tabeli
R.4.10 Ustawiony dla parzystych wierszy tabeli (np. tr:nth-child(even)): kolor tła #FDFAAA
ok. 2 min
Polecenie z arkusza
Dla selektora tabeli: marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość: 80%. Dla komórek nagłówkowych tabeli: kolor tła #5BBB77, rozmiar czcionki 16 px, wysokość komórki 40 px. Dla parzystych wierszy tabeli: kolor tła #FDFAAA.
Selektory znaczników table i th, jak każe uwaga arkusza (R.4.4, R.4.6, R.4.7). Pseudoklasa :nth-child(even) wybiera co drugi wiersz - drugi, czwarty, szósty; wiersz nagłówkowy jest pierwszy, więc żółte tło dostają pierwsza, trzecia i piąta nagroda (R.4.10).
Krok 24: Lista, odnośniki i nagłówek czwartego stopnia
Kryteria: ,
R.4.3 Ustawiony kolor czcionki dla: selektora a #680808, dla selektora h4 zielony, bloku nagłówkowego #5BBB77, stopki: #FFF555
R.4.4 Ustawione dla selektora ul: interlinia 1.5, typ punktora kwadrat oraz dla komórki nagłówkowej tabeli: kolor tła #5BBB77, wysokość 40px, rozmiar czcionki 16px
ok. 2 min
Polecenie z arkusza
Dla selektora listy punktowanej: typ punktora kwadrat, interlinia 1.5. Dla selektora odnośnika: kolor czcionki #680808. Dla selektora nagłówka czwartego stopnia: zielony kolor czcionki.
Tu nie ma wyboru techniki: arkusz każe użyć wyłącznie selektorów znacznikówul, a, h4, a klucz nie uzna klasy ani selektora potomka (aside ul). Zielony to nazwa koloru green.
Kroki 25-30 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 25: 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 konkurs
R.5.3 Ostatnią operacją na bazie jest jej zamknięcie
ok. 4 min
Polecenie z arkusza
Napisany w języku PHP. Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim. Łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie konkurs. Na końcu zamykane jest połączenie z serwerem.
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=konkurs;charset=utf8mb4' - serwer, baza i kodowanie, potem root i puste hasło (R.5.1, R.5.2),
ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze z nazwami kolumn,
$pdo = null zamyka połączenie; zapytanie trafi przed tę linię, więc zamknięcie zostanie ostatnią operacją na bazie (R.5.3),
try / catch (PDOException $exception) - przy awarii bazy szczegóły idą do dziennika serwera, a strona dostaje ogólny komunikat w $dbError,
funkcja escape() to htmlspecialchars(..., ENT_QUOTES) pod nazwą, która mówi, co robi.
Od tego kroku podgląd to wynik prawdziwego uruchomienia.
R.5.4 Skrypt zawiera instrukcję wysyłającą do bazy danych zapytanie 1
R.5.7 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. 2 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 1.
$pdo->query(...) wysyła zapytanie 1, a ->fetchAll() odbiera pięć wylosowanych nagród do tablicy $prizes (R.5.4). W zapytaniu nie ma żadnej wartości od użytkownika, więc query wystarcza - przy wartości z formularza byłoby prepare i execute. Nazwy zmiennych po angielsku mówią, co przechowują (R.5.7).
konkurs.phpPHPzmienione: 1 linia
<?phpfunctionescape(?string $text): string{returnhtmlspecialchars($text ?? '', ENT_QUOTES);}$prizes = [];$dbError = '';try {$pdo = new PDO('mysql:host=localhost;dbname=konkurs;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$prizes = $pdo->query('SELECT nazwa, opis, cena FROM nagrody ORDER BY RAND() LIMIT 5')->fetchAll();$pdo = null;} catch (PDOException $exception) {error_log($exception->getMessage());$dbError = 'Nie udało się wylosować nagród. Spróbuj ponownie za chwilę.';}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>WOLONTARIAT SZKOLNY</title> <linkrel="stylesheet"href="styles.css"></head><body> <header> <h1>KONKURS - WOLONTARIAT SZKOLNY</h1> </header> <main> <h3>Konkursowe nagrody</h3> <form> <button>Losuj nowe nagrody</button> </form> <table> <tr> <th>Nr</th> <th>Nazwa</th> <th>Opis</th> <th>Wartość</th> </tr> </table> </main> <aside> <imgsrc="puchar.png"alt="Puchar dla wolontariusza"> <h4>Polecane linki</h4> <ul> <li><ahref="kw1.png">Kwerenda1</a></li> <li><ahref="kw2.png">Kwerenda2</a></li> <li><ahref="kw3.png">Kwerenda3</a></li> <li><ahref="kw4.png">Kwerenda4</a></li> </ul> </aside> <footer> <p>Numer zdającego: Bartosz Bryniarski</p> </footer></body></html>
R.5.5 Skrypt wyświetla w tabeli wartości od 1 do 5 w kolumnie Nr
ok. 3 min
Polecenie z arkusza
W każdym wierszu tabeli wpisywany jest obliczony przez skrypt kolejny numer wiersza począwszy od 1.
Pod wierszem nagłówkowym pętla foreach ($prizes as $index => $prize): ... endforeach; w składni alternatywnej - HTML wiersza zostaje zwykłym HTML-em. <?= ... ?> to skrót od <?php echo ... ?>.
fetchAll() numeruje listę od 0, więc numer wiersza to $index + 1 - od 1 do 5 (R.5.5). Podgląd: pięć wierszy z numerami, na razie tylko pierwsza kolumna.
Typowe błędy
Samo $index daje numery od 0 do 4 - arkusz każe liczyć od 1.
konkurs.phpPHPzmienione: 5 linii
<?phpfunctionescape(?string $text): string{returnhtmlspecialchars($text ?? '', ENT_QUOTES);}$prizes = [];$dbError = '';try {$pdo = new PDO('mysql:host=localhost;dbname=konkurs;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$prizes = $pdo->query('SELECT nazwa, opis, cena FROM nagrody ORDER BY RAND() LIMIT 5')->fetchAll();$pdo = null;} catch (PDOException $exception) {error_log($exception->getMessage());$dbError = 'Nie udało się wylosować nagród. Spróbuj ponownie za chwilę.';}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>WOLONTARIAT SZKOLNY</title> <linkrel="stylesheet"href="styles.css"></head><body> <header> <h1>KONKURS - WOLONTARIAT SZKOLNY</h1> </header> <main> <h3>Konkursowe nagrody</h3> <form> <button>Losuj nowe nagrody</button> </form> <table> <tr> <th>Nr</th> <th>Nazwa</th> <th>Opis</th> <th>Wartość</th> </tr><?phpforeach ($prizesas$index => $prize): ?> <tr> <td><?= $index + 1?></td> </tr><?phpendforeach; ?> </table> </main> <aside> <imgsrc="puchar.png"alt="Puchar dla wolontariusza"> <h4>Polecane linki</h4> <ul> <li><ahref="kw1.png">Kwerenda1</a></li> <li><ahref="kw2.png">Kwerenda2</a></li> <li><ahref="kw3.png">Kwerenda3</a></li> <li><ahref="kw4.png">Kwerenda4</a></li> </ul> </aside> <footer> <p>Numer zdającego: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (konkurs.php)
Krok 28: Pola rekordu w kolejnych komórkach
Kryteria: ,
R.2.5 W bloku lewym zapisana tabela o 4 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>
R.5.6 Skrypt 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.
Trzy komórki <td> po nazwach kolumn ($prize['opis']), każda przez escape(): opis nagrody wpisuje człowiek, a znak < albo & w opisie przeglądarka wzięłaby za początek znacznika (R.2.5, R.5.6). Podgląd: tabela jak na ilustracji 2, ceny jeszcze w zapisie z bazy (1230.00).
Dodatek spoza arkusza - klucz go nie ocenia. Funkcja formatPrice():
number_format((float) $price, 2, ',', "\u{a0}") - zapis dla ludzi: przecinek dziesiętny, odstęp między tysiącami i waluta: 1230.00 z bazy staje się „1 230,00 zł”. Odstępem jest spacja nierozdzielająca"\u{a0}" (w HTML-u to samo co ) - w wąskiej kolumnie cena nie rozpadnie się na dwie linie. PDO oddaje liczby z bazy jako napisy, a jawne (float) mówi, że tu zaczyna się liczba,
null → „brak ceny”: strona działa na bazie po imporcie, a zapytanie 3 (usunięcie nagród bez ceny) jest osobnym ćwiczeniem. Losowanie może trafić na Skarpety ALPAKA z pustą ceną - bez tego warunku number_format(null, ...) wypisałby „0,00 zł”, jakby nagroda była darmowa, i zgłosił ostrzeżenie Deprecated (PHP 8.1+).
Sprawdzone uruchomieniem z nagrodami 21 (brak ceny) i 20 (0,00 zł): w tabeli stoi odpowiednio „brak ceny” i „0,00 zł”. Podgląd: ceny po polsku.
Nad tabelą akapit z $dbError - tylko gdy catch coś do niego wpisał. Sprawdzone uruchomieniem z błędną nazwą bazy: strona się wyświetla, pod przyciskiem stoi „Nie udało się wylosować nagród…”, tabela ma sam wiersz nagłówkowy, a w treści nie ma nazwy bazy ani kodu błędu SQL. W normalnym działaniu połączenie jest zamykane ($pdo = null) zaraz po zapytaniu, przed pierwszą linią HTML.
Krok 31 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 31: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 2 min
Obie wersje dają komplet 37 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
układ
float: left sekcji + clear: both w stopce
display: grid i grid-template-areas na <body>
szerokości bloków
width: 79% i width: 20%
grid-template-columns: 79% 20%
kolory
wpisane w każdej regule
zmienne CSS w :root
bloki boczne
dwie <section> z id
<main> i <aside>, selektory znaczników
zapytanie 4
LIKE '2021-08-%'
przedział dat >= ... AND < ...
baza
mysqli_connect, mysqli_fetch_row, $row[0]
PDO z wyjątkami, fetchAll, $prize['nazwa']
numer wiersza
licznik $number++
$index + 1
cena
z bazy (1230.00; w dobrych praktykach number_format)
formatPrice(): „1 230,00 zł” albo „brak ceny”
awaria bazy
biała strona z błędem
komunikat nad 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 lepiej znosi dane, które odbiegają od normy (pusta cena, awaria bazy). Czego tu świadomie nie ma: <thead>/<tbody> (zmieniłyby liczenie parzystych wierszy) i pliku config.php z danymi logowania (klucz szuka połączenia w kodzie strony).
Krok 32 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 32: 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: konkurs.php, styles.css, kwerendy.txt, import.png, kw1.png - kw4.png, puchar.png i przeglądarka.txt. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
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: Bartosz Bryniarski. 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.