INF.03-08-25.06-SGCzerwiec 2025 · 50 kroków · ok. 96 min · 41 kryteriów z klucza
Rozwiązanie krok po kroku: Portal hobbystyczny o smokach (Nowoczesny kod (grid, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza smoki z czterema zapytaniami, przeskalowana grafika, strona smoki.php z przełączanymi sekcjami, listą krajów i tabelą smoków - i tak samo spełnia każde kryterium klucza. Inna jest droga:
siatka CSS z nazwanymi obszarami na <body> zamiast float i clear, selektory strukturalne zamiast identyfikatorów (.block:first-child, section + section),
JavaScript bez atrybutów onclick: querySelectorAll, forEach, addEventListener, numer sekcji w atrybucie data-section, obsługa klawiatury i skrypt ładowany z defer,
PHP na PDO: zapytania na początku pliku, biała lista kraju (tylko kraje z bazy), zapytanie przygotowane, funkcja e() przy każdym wypisaniu i dane logowania w config.php.
Tam, gdzie klucz wymaga konkretnej formy - JavaScript zmienia styl bloków przez style.backgroundColor i style.display - ta forma zostaje, a krok mówi dlaczego. Na końcu krótkie porównanie z wersją podstawową (zakładka obok).
Grafiki, opisy i baza pochodzą z prawdziwego archiwum pliki7 (załącznik na stronie arkusza), a podgląd kroków z PHP to wynik prawdziwego uruchomienia strony na serwerze z tą bazą.
Jak liczą się punkty. Klucz ma 41 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania to 75%, czyli 31 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 41 kryteriów (pkt)
Krok 1: Baza danych smoki
Kryteria:
R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie smoki, z zestawem polskich znaków (np. utf8_polish_ci).
phpMyAdmin → Nowa → nazwa smoki, porównywanie utf8_polish_ci. W SQL:
CREATE DATABASE smoki CHARACTER SET utf8 COLLATE utf8_polish_ci;
Typowe błędy
Smoki albo smok zamiast smoki odcina też punkty za skrypty - połączenie podaje nazwę bazy.
Krok 2: Import tabel z pliku bazasmoki.sql
Kryteria:
R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg
ok. 2 min
Polecenie z arkusza
Z rozpakowanego archiwum zaimportuj tabele z pliku bazasmoki.sql do utworzonej bazy.
Zaznacz bazę smoki, karta Import, plik bazasmoki.sql, Wykonaj. Trzy tabele z ilustracji 1: smok (44), parada (48) i łącząca je udzial (127) - relacja wiele do wielu.
Krok 3: Zrzut ekranu import.jpg
Kryteria:
R.1.1 Wykonany import tabel do bazy danych smoki , czynność udokumentowana w pliku import.jpg
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie JPEG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.
Cały ekran z paskiem zadań, zapis jako import.jpg. Zrzuty zapytań w tym arkuszu są w PNG.
Typowe błędy
Wykadrowany zrzut nie jest oceniany.
Krok 4: Zapytanie 1: smoki z Polski
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 nazwę, długość i szerokość smoka, dla smoków z Polski. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska"; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dokładnie 23 rekordy zawierające jedynie pola nazwa, dlugosc, szerokosc
ok. 3 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie nazwę, długość i szerokość smoka, dla smoków z Polski.
Każda klauzula w osobnej linii, napis w apostrofach (standard SQL). Wynik: 23 smoki, trzy kolumny (R.1.3); zapytanie do kwerendy.txt, zrzut kw1.png.
Krok 5: Zapytanie 2: kraje pochodzenia bez powtórzeń
Kryteria:
R.1.4 Wykonane zapytanie 2 wybierające niepowtarzające się kraje pochodzenia smoków, posortowane rosnąco według nazwy kraju pochodzenia. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie; (opcjonalnie ASC; możliwe też GROUP BY, wtedy ORDER BY opcjonalne) oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczne są dane: Bułgaria, Chiny, Francja, Japonia, Polska
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające niepowtarzające się kraje pochodzenia smoków, posortowane rosnąco według kraju pochodzenia.
DISTINCT i jawne ASC. Wynik: Bułgaria, Chiny, Francja, Japonia, Polska (R.1.4), zrzut kw2.png. Ta lista wypełni listę rozwijaną i będzie białą listą krajów w skrypcie 2.
Krok 6: Zapytanie 3: średnia długość smoków w paradach po 2005 roku
Kryteria:
R.1.5 Wykonane zapytanie 3 wybierające jedynie rok z tabeli parada i odpowiadającą mu średnią wartość długości z tabeli smok nazwaną (alias) „Średnia długość” tylko dla lat po 2005 roku. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT rok, AVG(dlugosc) AS "Średnia długość" FROM parada JOIN udzial ON parada.id = id_parada JOIN smok ON id_smok = smok.id WHERE rok > 2005 GROUP BY rok; (możliwe INNER JOIN lub porównanie kluczy po WHERE; AS opcjonalne) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest 5 rekordów: 2006 4.6; 2013 7.6; 2014 5.5; 2021 7.625; 2025 6.4091 (dowolne zaokrąglenie)
ok. 5 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie rok z tabeli parada i obliczającą odpowiadającą mu średnią wartość długości z tabeli smok, nazwa kolumny (alias) „Średnia długość” tylko dla lat po 2005 roku. Należy posłużyć się relacją i zgrupować rekordy względem roku.
Trzy tabele z krótkimi aliasami (p, u, s): parada → wpisy w tabeli łączącej → smoki. Każdy warunek ON łączy klucz obcy z kluczem głównym, a przedrostki (p.rok, s.dlugosc) mówią, skąd jest kolumna - w tej bazie trzy tabele mają kolumnę id, więc bez przedrostków zapytanie byłoby niejednoznaczne.
Alias ze spacją w odwrotnych apostrofach`Średnia długość` - właściwy w MySQL znak dla nazw. WHERE p.rok > 2005 odcina lata przed grupowaniem, GROUP BY p.rok liczy średnią dla każdego roku, a ORDER BY p.rok ustala kolejność wprost.
HAVING p.rok > 2005 też zadziała, ale warunek na zwykłej kolumnie należy do WHERE - HAVING jest dla warunków na wynikach funkcji grupujących.
kwerendy.txtTekstzmienione: 9 linii
-- Zapytanie 1SELECT nazwa, dlugosc, szerokoscFROM smokWHERE pochodzenie = 'Polska';-- Zapytanie 2SELECT DISTINCT pochodzenieFROM smokORDER BY pochodzenie ASC;-- Zapytanie 3SELECT p.rok, AVG(s.dlugosc) AS `Średnia długość`FROM parada AS pJOIN udzial AS u ON u.id_parada = p.idJOIN smok AS s ON s.id = u.id_smokWHERE p.rok > 2005GROUP BY p.rokORDER BY p.rok;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowa kolumna w tabeli parada
Kryteria:
R.1.6 Wykonane zapytanie 4 zmieniające strukturę tabeli parada, przez wstawienie nowej kolumny lokalizacja typu napisowego o maksymalnej długości 100 znaków. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE parada ADD COLUMN lokalizacja VARCHAR(100); oraz wynik działania zapytania udokumentowany zrzutem, na którym jest komunikat o pomyślnie wykonanym zapytaniu lub zmieniona struktura tabeli
ok. 2 min
Polecenie z arkusza
Zapytanie 4: zmieniające strukturę tabeli parada, przez wstawienie nowej kolumny lokalizacja typu napisowego o maksymalnej długości 100 znaków.
ALTER TABLE … ADD COLUMN zmienia strukturę; „maksymalna długość” to VARCHAR(100) (R.1.6), zrzut kw4.png.
Typowe błędy
CHAR(100) ma stałą długość - arkusz mówi o maksymalnej.
kwerendy.txtTekstzmienione: 4 linie
-- Zapytanie 1SELECT nazwa, dlugosc, szerokoscFROM smokWHERE pochodzenie = 'Polska';-- Zapytanie 2SELECT DISTINCT pochodzenieFROM smokORDER BY pochodzenie ASC;-- Zapytanie 3SELECT p.rok, AVG(s.dlugosc) AS `Średnia długość`FROM parada AS pJOIN udzial AS u ON u.id_parada = p.idJOIN smok AS s ON s.id = u.id_smokWHERE p.rok > 2005GROUP BY p.rokORDER BY p.rok;-- Zapytanie 4ALTER TABLE paradaADD COLUMN lokalizacja VARCHAR(100);
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-26 · po tym etapie masz 19 z 41 kryteriów (pkt)
Krok 8: Przeskalowanie grafiki smok1.jpg
Kryteria:
R.2.1 Grafika smok1.jpg przeskalowana z zachowaniem proporcji do wysokości 300 px , odpowiadająca temu szerokość wynosi 448 (±5 px)
ok. 3 min
Polecenie z arkusza
Cechy grafiki smok1.jpg: przeskalowana z zachowaniem proporcji do wysokości 300 px.
smok1.jpg ma 3872 × 2592 px (2,6 MB). Skaluj obraz do wysokości 300 px przy zamkniętym łańcuchu - szerokość 448 px (R.2.1). Plik zmniejsza się do kilkudziesięciu kilobajtów, więc strona ładuje się szybciej.
Podgląd strony po tym kroku
Krok 9: Plik smoki.php w HTML5
Kryteria:
R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"
ok. 1 min
Polecenie z arkusza
Składa się ze strony o nazwie smoki.php. Zapisana w języku HTML5.
Plik smoki.php w folderze zdającego. <!DOCTYPE html> włącza tryb standardów HTML5, dalej szkielet: <html>, <head> i <body>. Rozszerzenie .php, bo na początku pliku stanie kod PHP.
R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"
ok. 1 min
Polecenie z arkusza
Zadeklarowany polski język zawartości witryny.
lang="pl" w <html> - czytnik ekranu czyta polską wymową, przeglądarka dobiera słownik i dzielenie wyrazów.
R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"
ok. 1 min
Polecenie z arkusza
Jawnie zastosowany właściwy standard kodowania polskich znaków.
<meta charset="UTF-8"> jako pierwszy element <head>. Ten sam standard ustawi połączenie z bazą (charset=utf8mb4 w PDO), więc polskie litery przejdą bez zmian całą drogę: baza → PHP → przeglądarka.
R.2.2 W pliku smoki.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków oraz tytuł strony "Smoki"
ok. 1 min
Polecenie z arkusza
Tytuł strony „Smoki”.
<title>Smoki</title> - napis na karcie przeglądarki. Obok <meta name="viewport">: bez niego telefon pokazałby stronę pomniejszoną jak na monitorze. Arkusz tego nie wymaga, a w każdym współczesnym szablonie ta linia jest.
R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza (nie dotyczy stylów ustawianych skryptem JS)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony.
<link rel="stylesheet" href="styl.css"> - nazwa dokładnie z arkusza. Cały wygląd będzie w tym pliku, w HTML nie ma ani jednego atrybutu style.
Typowe błędy
Zła nazwa w href to brak stylów, a wtedy cały rezultat R.4 przepada.
R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header, nav, main, footer
ok. 2 min
Polecenie z arkusza
Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3.
Cztery znaczniki z klucza R.2.3: <header>, <nav>, <main>, <footer>. Nawigację i blok główny postawi obok siebie siatka w CSS.
Typowe błędy
Zwykłe <div> z identyfikatorami wyglądają tak samo, ale R.2.3 wymaga znaczników semantycznych.
R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce
ok. 1 min
Polecenie z arkusza
Zawartość bloku nagłówkowego: nagłówek drugiego stopnia o treści „Poznaj smoki!”.
R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)
ok. 2 min
Polecenie z arkusza
Zawartość bloku nawigacyjnego to trzy bloki: blok 1 z treścią „Baza”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
Blok to <div> z klasą block - wspólną dla trzech bloków. Zamiast identyfikatora block1 blok niesie atrybut danychdata-section="1": numer sekcji, którą ma pokazać. Atrybuty data-* są w HTML5 przeznaczone właśnie na takie informacje dla skryptu, a JavaScript odczyta je jako block.dataset.section.
Dwa atrybuty dla dostępności: role="button" mówi czytnikowi ekranu, że to przycisk, a tabindex="0" pozwala dojść do bloku klawiszem Tab. Zwykły <div> nie jest ani jednym, ani drugim - a klikalny element musi działać też bez myszy.
Typowe błędy
<button> byłby tu najwłaściwszym znacznikiem, ale arkusz każe stylować listę i „przycisk” formularza regułą z marginesem 20 px - selektor button objąłby wtedy także bloki nawigacji. Dlatego <div> z role="button".
R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)
ok. 1 min
Polecenie z arkusza
Blok 2 z treścią „Opisy”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript. Blok 3 z treścią „Galeria”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
Ten sam wzorzec z data-section="2" i "3". W nawigacji są trzy bloki (R.2.4).
R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)
R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce
ok. 1 min
Polecenie z arkusza
Zawartość bloku głównego to trzy sekcje (w jednym momencie jest widoczna tylko jedna sekcja). Sekcja 1: nagłówek trzeciego stopnia o treści „Baza Smoków”.
<section> z <h3>. Sekcje nie dostają identyfikatorów: skrypt znajdzie je po kolejności w <main>, a CSS ukryje drugą i trzecią selektorem strukturalnym (R.2.4, R.2.5).
R.2.10 Na stronie umieszczony formularz z listą rozwijaną i przyciskiem, zastosowano znaczniki <select> i <option>
ok. 1 min
Polecenie z arkusza
Lista rozwijana wypełniona przez skrypt 1.
name="country" - klucz w danych POST. Arkusz nie przewiduje etykiety, więc aria-label="Kraj pochodzenia" podpowiada czytnikowi ekranu, czego dotyczy lista. Opcje wstawi skrypt 1 (R.2.10).
R.2.8 Na stronie umieszczona tabela o 3 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>
R.2.9 Pierwszy wiersz tabeli zawiera komórki nagłówkowe zastosowano znaczniki <tr> i <th>
ok. 2 min
Polecenie z arkusza
Tabela o trzech kolumnach. Pierwszy wiersz jest wierszem z komórkami nagłówkowymi: „Nazwa”, „Długość”, „Szerokość”. Kolejne wiersze są wypełnione przez skrypt 2.
Wiersz z komórkami <th> w <thead>, a miejsce na wiersze skryptu 2 w <tbody> - przeglądarka i czytnik ekranu wiedzą, który wiersz jest nagłówkiem (R.2.8, R.2.9).
R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)
R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce
ok. 1 min
Polecenie z arkusza
Sekcja 2: nagłówek trzeciego stopnia o treści „Opisy smoków”.
R.2.7 Na stronie umieszczona jedna lista definicji z trzema definicjami, zastosowane znaczniki <dl>, <dt>, <dd>, w <dt> umieszczone kolejno: Smok czerwony, Smok zielony, Smok niebieski
ok. 3 min
Polecenie z arkusza
Lista definicji wypełniona danymi, które należy skopiować z pliku opis.txt. Nazwa smoka jest terminem, a pozostałe dane - opisem definicji, zgodnie z ilustracją 5.
<dl> z parami <dt> (nazwa) i <dd> (opis), w kolejności: Smok czerwony, zielony, niebieski (R.2.7). Opisy skopiowane z opis.txt.
Typowe błędy
<ul> z pogrubioną nazwą wygląda podobnie, ale R.2.7 wymaga <dl>, <dt>, <dd>.
smoki.phpPHPzmienione: 8 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 25: Sekcja 3: galeria
Kryteria: , ,
R.2.4 W bloku nawigacyjnym i bloku głównym znajdują się po trzy bloki (np. <div>, <section>)
R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce
R.2.6 Na stronie umieszczone trzy grafiki z tekstami alternatywnymi: smok1.jpg - "Smok czerwony", smok2.jpg - "Smok wielki", smok3.jpg - "Skrzydlaty łaciaty"
ok. 2 min
Polecenie z arkusza
Sekcja 3: nagłówek trzeciego stopnia o treści „Galeria”. Obraz smok1.jpg z tekstem alternatywnym „Smok czerwony”. Obraz smok2.jpg z tekstem alternatywnym „Smok wielki”. Obraz smok3.jpg z tekstem alternatywnym „Skrzydlaty łaciaty”.
Trzecia sekcja z <h3> i trzema obrazami; teksty alternatywne dokładnie z arkusza (R.2.4, R.2.5, R.2.6).
smoki.phpPHPzmienione: 6 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 26: Stopka z numerem zdającego
Kryteria:
R.2.5 Na stronie umieszczony <h2>: „Poznaj smoki!”, przynajmniej jeden <h3> z : "Baza Smoków", "Opisy smoków", "Galeria", oraz paragraf z numerem zdającego w stopce
ok. 1 min
Polecenie z arkusza
Zawartość stopki: paragraf o treści „Stronę opracował: ”, dalej wstawiony numer zdającego.
Tu nazwisko autora rozwiązania - na egzaminie wpisujesz swój numer zdającego (PESEL), bo tego sprawdza klucz R.2.5.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Etap 3: Styl CSS
Kroki 27-34 · po tym etapie masz 30 z 41 kryteriów (pkt)
Krok 27: Plik styl.css: domyślne wyrównanie i krój
Kryteria:
R.4.1 Ustawione domyślnie dla wszystkich selektorów (*): wyrównanie tekstu do środka, krój czcionki Georgia
ok. 1 min
Polecenie z arkusza
Domyślnie dla wszystkich selektorów: wyrównanie tekstu do środka, krój czcionki Georgia.
Selektor uniwersalny * (R.4.1).
styl.cssCSSnowy plik
* {text-align: center;font-family: Georgia;}
Podgląd strony po tym kroku (smoki.php)
Krok 28: Nagłówek i stopka
Kryteria: , ,
R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5
R.4.3 Ustawiony kolor czcionki dla bloku nagłówkowego i stopki: MistyRose
R.4.6 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego i stopki 10px oraz ustawione marginesy zewnętrzne (margin) dla listy rozwijanej i przycisku 20 px, auto dla tabeli
ok. 1 min
Polecenie z arkusza
Wspólne dla bloku nagłówkowego i stopki: kolor tła Tomato, kolor czcionki MistyRose, marginesy wewnętrzne 10 px.
Jedna reguła dla dwóch bloków, margines wewnętrzny to padding (R.4.2, R.4.3, R.4.6).
Krok 29: Układ bloków: siatka z nazwanymi obszarami
Kryteria:
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (nie należy brać pod uwagę bloków wewnątrz bloków nawigacyjnego i głównego) (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position)
ok. 3 min
Polecenie z arkusza
Dla bloku nawigacyjnego: szerokość 20%.
Ilustracja 3 zapisana wprost jako plan: <body> staje się siatką o dwóch kolumnach 20% i 80%, a grid-template-areas rysuje wiersze - nagłówek na całą szerokość, nawigacja obok bloku głównego, stopka na całą szerokość. Każdy blok trafia do swojego obszaru przez grid-area.
Szerokość nawigacji (20%) i bloku głównego (80%) jest zapisana raz, w grid-template-columns - klucz R.4.4 wymienia tę właściwość obok width. Stopka jest w osobnym wierszu siatki, więc nie potrzebuje clear (R.3.1).
Typowe błędy
Nazwa obszaru w grid-area musi być dokładnie taka jak w grid-template-areas - literówka stawia blok w dodatkowym, automatycznym wierszu pod siatką.
R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5
R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%
R.4.7 Ustawiony dla bloku 1, 2, i 3 rozmiar czcionki 200% oraz dla selektora dt czcionka pogrubiona i pochylona
ok. 2 min
Polecenie z arkusza
Dla bloku 1, bloku 2, bloku 3: kolor tła #FFAEA5, wysokość 170 px, rozmiar czcionki 200%. Jedynie dla bloku 1: kolor tła MistyRose.
Wspólna klasa .block dla trzech bloków (R.4.2, R.4.4, R.4.7) i cursor: pointer - kursor „rączki” podpowiada, że blok da się kliknąć. Blok 1 bez identyfikatora: .block:first-child wybiera blok, który jest pierwszym dzieckiem swojego rodzica (<nav>). Reguła jest bardziej szczegółowa niż sama klasa (klasa + pseudoklasa), więc wygrywa i tło bloku 1 jest jasne.
R.4.2 Ustawiony kolor tła dla bloku nagłówkowego i stopki Tomato, dla bloku głównego i Bloku 1 MistyRose, Bloku 2 i 3 #FFAEA5
R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%
R.4.5 Ustawiony dla bloku głównego styl overflow: auto;
ok. 1 min
Polecenie z arkusza
Dla bloku głównego: kolor tła MistyRose, szerokość 80%, wysokość 510 px, paski przewijania widoczne tylko w przypadku przepełnienia zawartością.
Do reguły main dochodzą tło, wysokość 510 px (trzy bloki po 170 px) i overflow: auto (R.4.2, R.4.4, R.4.5). Szerokość 80% ma już kolumna siatki.
R.4.8 Ustawiony dla sekcji 2 i 3 styl display: none;
ok. 1 min
Polecenie z arkusza
Jedynie dla sekcji 2 i sekcji 3: sekcje są usunięte z DOM (patrz tabela 3).
section + section to selektor sąsiada: „sekcja, przed którą stoi inna sekcja”. Pierwsza sekcja nie ma sekcji przed sobą, więc zostaje widoczna; druga i trzecia dostają display: none (R.4.8) - bez identyfikatorów. display: none (tabela 3 arkusza) usuwa element z układu strony.
R.4.4 Ustawiona wysokość bloków 1, 2, 3: 170px, bloku głównego 510px oraz szerokość bloku nawigacyjnego 20%, głównego 80% (width lub grid-template-columns lub flex) , selektora table 60%
R.4.6 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego i stopki 10px oraz ustawione marginesy zewnętrzne (margin) dla listy rozwijanej i przycisku 20 px, auto dla tabeli
R.4.9 Ustawione dla tabeli obramowanie 1px dashed Indigo
ok. 2 min
Polecenie z arkusza
Dla selektora tabeli: marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość 60%, obramowanie linią kreskowaną o szerokości 1 px i kolorze Indigo. Dla listy rozwijanej i przycisku: marginesy zewnętrzne 20 px.
Selektor znacznika table (uwaga arkusza): wyśrodkowanie margin: auto, szerokość, border: 1px dashed Indigo (R.4.4, R.4.6, R.4.9). Lista i przycisk - margin: 20px (R.4.6).
R.4.7 Ustawiony dla bloku 1, 2, i 3 rozmiar czcionki 200% oraz dla selektora dt czcionka pogrubiona i pochylona
R.4.10 W momencie gdy kursor znajdzie się na napisie: Smok czerwony lub Smok zielony, lub Smok niebieski jego rozmiar czcionki zmienia się na 180%
ok. 1 min
Polecenie z arkusza
Dla selektora terminu w liście definicji (dt): czcionka pogrubiona i pochylona. W momencie gdy kursor znajdzie się na terminie w liście definicji jego rozmiar czcionki zmienia się na 180%.
Selektor znacznika dt (uwaga arkusza) i dt:hover (R.4.7, R.4.10). Efekt widać po kliknięciu „Opisy”.
Kroki 35-39 · po tym etapie masz 36 z 41 kryteriów (pkt)
Krok 35: Plik script.js: bloki i sekcje w stałych
Kryteria:
R.5.10 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
Skrypt jest napisany w języku JavaScript. Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.
Skrypt podpięty w <head> z atrybutem defer: przeglądarka pobiera go równolegle ze stroną, a uruchamia dopiero po wczytaniu całego HTML-u - wszystkie bloki i sekcje już istnieją. To samo daje skrypt na końcu <body>, ale defer trzyma wszystkie odwołania w jednym miejscu, w <head>.
Dwie stałe (const - nie zostaną przypisane drugi raz):
document.querySelectorAll('.block') - wszystkie elementy z klasą block, czyli trzy bloki nawigacji (selektor jak w CSS),
document.querySelectorAll('main section') - trzy sekcje bloku głównego, w kolejności z HTML.
Typowe błędy
<script src="script.js"> w <head>bezdefer uruchomi się przed powstaniem bloków - querySelectorAll zwróci pustą listę i kliknięcia nic nie zrobią.
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 36: Funkcja showSection: kolory bloków
Kryteria: ,
R.5.6 Skrypt JS zawiera przynajmniej jedną funkcję oraz przynajmniej dla jednego bloku stosuje metody obiektu document aby modyfikować jego styl np. document.getElementById('prawy1').style.display = "block"; document.getElementById('lewy1').style.backgroundColor = "MistyRose";
R.5.7 Po kliknięciu na blok lewy jego kolor tła zamienia się na MistyRose, kolor tła pozostałych bloków lewych na "#FFAEA5" (wystarczy że spełnione dla jednego bloku innego niż "Baza")
ok. 3 min
Polecenie z arkusza
Gdy zostanie kliknięty Blok 1: kolor tła bloku 1 zmienia się na MistyRose, pozostałe na #FFAEA5.
Jedna funkcja showSection(number) dla trzech bloków. forEach wykonuje funkcję strzałkową dla każdego bloku i podaje jego numer w liście (index - od zera, więc blok 1 ma index 0). Operator warunkowywarunek ? a : b wybiera kolor w jednej linii: kliknięty blok dostaje MistyRose, pozostałe #FFAEA5 - bez osobnego „zerowania” wszystkich bloków.
Kolor zmienia się przez style.backgroundColor - to forma, którą podaje klucz (R.5.6: metody obiektu document modyfikujące styl). Przełączanie klasy CSS (classList.toggle) byłoby czystsze, ale nie zmienia stylu bloku wprost, więc tu zostaje style.
Typowe błędy
index === number (bez + 1) przesuwa wszystko o jeden: kliknięcie „Baza” rozjaśniłoby „Opisy”.
Krok 37: Funkcja showSection: widoczna jedna sekcja
Kryteria: ,
R.5.8 Po kliknięciu na blok lewy wyświetlona jest w bloku prawym tylko sekcja z nim skojarzona (wystarczy że spełnione dla jednego bloku innego niż "Baza")
R.5.9 Po wykonaniu R.5.7, R.5.8, a następnie po kliknięciu na blok lewy "Baza" strona wraca do stanu początkowego (kolor i sekcja)
ok. 2 min
Polecenie z arkusza
Sposób wyświetlania Sekcji 1 zmienia się na blokowy, pozostałe są usunięte.
Ta sama konstrukcja dla sekcji: sekcja o numerze klikniętego bloku dostaje display: block, pozostałe none (R.5.8). Funkcja zawsze ustawia wszystkie bloki i sekcje, więc każda sekwencja kliknięć kończy się poprawnym stanem - także powrót do „Baza” (R.5.9).
Krok 38: Kliknięcie w dowolny blok wywołuje funkcję
Kryteria: , , ,
R.3.5 Kliknięcie na dowolnym bloku w bloku nawigacyjnym powoduje wywołanie funkcji skryptu
R.5.7 Po kliknięciu na blok lewy jego kolor tła zamienia się na MistyRose, kolor tła pozostałych bloków lewych na "#FFAEA5" (wystarczy że spełnione dla jednego bloku innego niż "Baza")
R.5.8 Po kliknięciu na blok lewy wyświetlona jest w bloku prawym tylko sekcja z nim skojarzona (wystarczy że spełnione dla jednego bloku innego niż "Baza")
R.5.9 Po wykonaniu R.5.7, R.5.8, a następnie po kliknięciu na blok lewy "Baza" strona wraca do stanu początkowego (kolor i sekcja)
ok. 2 min
Polecenie z arkusza
Gdy zostanie kliknięty Blok 1, Blok 2 albo Blok 3: kolor tła klikniętego bloku zmienia się na MistyRose, pozostałe na #FFAEA5, a sposób wyświetlania jego sekcji zmienia się na blokowy, pozostałe są usunięte.
Każdy blok dostaje nasłuchiwaczaddEventListener('click', ...) - HTML nie ma ani jednego atrybutu onclick, całe zachowanie jest w skrypcie. Funkcja strzałkowa odczytuje numer sekcji z atrybutu data-section (block.dataset.section) i przekazuje go do showSection. Wartość atrybutu to zawsze napis, a funkcja porównuje ściśle (===) z liczbą - stąd Number(...).
Sprawdź w podglądzie sekwencję z klucza: „Galeria”, „Opisy”, „Baza” (R.3.5, R.5.7, R.5.8, R.5.9).
Typowe błędy
addEventListener('click', showSection(1)) wywołuje funkcję od razu przy rejestracji - przekazuje się funkcję, nie jej wynik.
Składa się z jednej lub trzech funkcji wywoływanych po kliknięciu na jednym z bloków w bloku nawigacyjnym.
Blok z role="button" i tabindex="0" da się zaznaczyć klawiszem Tab, ale <div> sam nie reaguje na klawisze jak prawdziwy przycisk. Drugi nasłuchiwacz, na zdarzenie keydown, wywołuje tę samą funkcję po wciśnięciu Enter albo spacji; preventDefault() blokuje przewinięcie strony spacją. Arkusz i klucz tego nie wymagają - bez tego nawigacja działa tylko myszą.
Kroki 40-48 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 40: Dane połączenia w pliku config.php
Kryteria:
R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie
ok. 2 min
Polecenie z arkusza
Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie smoki.
Dane logowania do bazy w osobnym pliku config.php, który tylko zwraca tablicę (return [...]). W prawdziwym projekcie hasło do bazy jest inne na każdym serwerze i nie trafia do repozytorium razem z kodem strony - wystarczy podmienić jeden plik. Arkusz dopuszcza dodatkowe pliki („ewentualnie inne przygotowane pliki”).
DSN (mysql:host=localhost;dbname=smoki;charset=utf8mb4) to adres bazy dla PDO w jednym napisie: rodzaj serwera, host, nazwa bazy i kodowanie połączenia. Plik bez HTML-u nie ma końcowego ?> - nic po nim nie wypisze się przypadkiem.
Typowe błędy
Plik config.php musi trafić do folderu z rezultatami - bez niego strona się nie połączy, a egzaminator nie znajdzie nazwy bazy.
config.phpPHPnowy plik
<?php// Dane połączenia z bazą - w jednym miejscu, poza plikiem stronyreturn ['dsn' => 'mysql:host=localhost;dbname=smoki;charset=utf8mb4','user' => 'root','password' => '',];
R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie
R.5.10 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
Skrypty 1 i 2 są napisane w języku PHP. Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie smoki.
Kod PHP stoi na samym początku pliku, przed <!DOCTYPE html>: najpierw wszystkie operacje na bazie, potem szablon strony, który tylko wypisuje gotowe dane. Klucz R.5 przyjmuje PDO tak samo jak MySQLi.
require 'config.php' - dane połączenia trafiają do $config,
new PDO(...) - połączenie i wybór bazy; opcja ERRMODE_EXCEPTION sprawia, że każdy błąd SQL zatrzymuje skrypt wyjątkiem, zamiast po cichu zwracać false, a FETCH_ASSOC - że wiersze przychodzą jako tablice z nazwami kolumn ($row['nazwa'] zamiast $row[1]),
try … catch (PDOException $error) - gdy baza nie działa, użytkownik widzi zwykły komunikat, a nie treść błędu z nazwą serwera i ścieżkami; http_response_code(500) mówi przeglądarce, że to błąd serwera.
Od tego kroku podgląd to prawdziwy wynik strony z serwera - na razie bez zmian.
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 42: Funkcja e(): bezpieczne wypisywanie tekstu
ok. 2 min
Polecenie z arkusza
Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.
Każdy napis z bazy albo z formularza, który trafi do HTML-u, przejdzie przez e() (od escape). htmlspecialchars zamienia <, >, & i - dzięki ENT_QUOTES - oba cudzysłowy na encje, więc napis <script> zapisany kiedyś w bazie wyświetli się jako tekst, a nie wykona (ochrona przed XSS). Escapowanie robi się na wyjściu, tuż przed wypisaniem - w bazie zostają dane surowe.
Krótka nazwa to świadomy wyjątek od „znaczącego nazewnictwa”: e() występuje w szablonie wiele razy i jest powszechnie znaną konwencją (tak samo nazywa się w Laravelu). Typy string przy parametrze i wyniku mówią, czego funkcja oczekuje; liczby PHP zamieni na tekst sam.
smoki.phpPHPzmienione: 5 linii
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 lub skrypt 2 - zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza
ok. 2 min
Polecenie z arkusza
Skrypt 1: wysyła do bazy danych zapytanie 2.
Zapytanie 2 przez query; PDO::FETCH_COLUMN zwraca od razu listę krajów (R.5.2). Ta lista posłuży też jako biała lista w skrypcie 2.
smoki.phpPHPzmienione: 2 linie
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
R.5.4 Skrypt 1 wyświetla w opcjach listy rozwijanej wszystkie zwrócone zapytaniem wiersze
ok. 2 min
Polecenie z arkusza
Wszystkie zwrócone zapytaniem wiersze są zapisywane jako opcje listy rozwijanej, zgodnie z ilustracją 4.
Pętla w składni szablonu (foreach … : / endforeach;), jeden <option> na kraj (R.5.4): Bułgaria, Chiny, Francja, Japonia, Polska.
smoki.phpPHPzmienione: 3 linie
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"><?phpforeach ($countriesas$countryName): ?> <option><?= e($countryName) ?></option><?phpendforeach; ?> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 45: Skrypt 2: tylko gdy formularz wysłał dane
Kryteria:
R.5.3 Skrypt 2 wykonywany jest tylko, gdy formularz wysłał dane i zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)
ok. 3 min
Polecenie z arkusza
Skrypt 2, wykonywany tylko, gdy formularz wysłał dane.
$_POST['country'] ?? null - wartość z formularza (R.5.3: dane z tablicy odpowiadającej metodzie), a null, gdy formularza nie wysłano. Warunek przepuszcza tylko kraj z białej listy - z listy $countries wczytanej przed chwilą z bazy; napis spoza bazy (ręcznie podrobione żądanie) nie uruchomi zapytania.
Na liście opcja równa wysłanemu krajowi dostaje selected - po wyszukaniu lista pokazuje Francję, a nie wraca do Bułgarii. Podgląd od tego kroku: stan po wybraniu Francji (ilustracja 4).
smoki.phpPHPzmienione: 6 linii
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);$dragons = [];$country = $_POST['country'] ?? null;if ($country !== null && in_array($country, $countries, true)) { }} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"><?phpforeach ($countriesas$countryName): ?> <option<?= $countryName === $country ? ' selected' : ''?>><?= e($countryName) ?></option><?phpendforeach; ?> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 46: Skrypt 2: zapytanie 1 przygotowane z krajem z formularza
Kryteria:
R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 lub skrypt 2 - zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza.
Zapytanie 1 z parametrem :country w miejscu „Polska”, wartość osobno w execute - nie staje się częścią polecenia SQL (R.5.2). Biała lista i parametr to dwie niezależne warstwy ochrony.
smoki.phpPHPzmienione: 3 linie
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);$dragons = [];$country = $_POST['country'] ?? null;if ($country !== null && in_array($country, $countries, true)) {$query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');$query->execute(['country' => $country]);$dragons = $query->fetchAll(); }} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"><?phpforeach ($countriesas$countryName): ?> <option<?= $countryName === $country ? ' selected' : ''?>><?= e($countryName) ?></option><?phpendforeach; ?> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
R.5.5 Skrypt 2 wyświetla każdy zwrócony zapytaniem wiersz jako kolejny wiersz tabeli, komórki tabeli są wypełnione zgodnie z nagłówkami
ok. 2 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz jest zapisywany jako kolejny wiersz tabeli, zgodnie z ilustracją 4.
W <tbody> jeden <tr> na smoka, komórki po nazwach kolumn - nazwa, długość, szerokość pod swoimi nagłówkami (R.5.5). Podgląd: dziesięć smoków z Francji.
Typowe błędy
Komórki w innej kolejności niż nagłówki to strata R.5.5.
smoki.phpPHPzmienione: 7 linii
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);$dragons = [];$country = $_POST['country'] ?? null;if ($country !== null && in_array($country, $countries, true)) {$query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');$query->execute(['country' => $country]);$dragons = $query->fetchAll(); }} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"><?phpforeach ($countriesas$countryName): ?> <option<?= $countryName === $country ? ' selected' : ''?>><?= e($countryName) ?></option><?phpendforeach; ?> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody><?phpforeach ($dragonsas$dragon): ?> <tr> <td><?= e($dragon['nazwa']) ?></td> <td><?= e($dragon['dlugosc']) ?></td> <td><?= e($dragon['szerokosc']) ?></td> </tr><?phpendforeach; ?> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 48: Zamknięcie połączenia z bazą
Kryteria:
R.5.1 Skrypt PHP realizuje połączenie z serwerem bazy danych i wybór bazy smoki oraz ostatnią operacją na bazie jest jej zamknięcie
ok. 1 min
Polecenie z arkusza
Na końcu działania skrypt zamyka połączenie z serwerem.
$db = null; na końcu bloku try zamyka połączenie PDO - ostatnia operacja na bazie (R.5.1). Szablon używa już tylko gotowych tablic.
Typowe błędy
$db->close() nie istnieje w PDO.
smoki.phpPHPzmienione: 2 linie
<?php$config = require'config.php';try {$db = new PDO($config['dsn'], $config['user'], $config['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$countries = $db->query('SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie')->fetchAll(PDO::FETCH_COLUMN);$dragons = [];$country = $_POST['country'] ?? null;if ($country !== null && in_array($country, $countries, true)) {$query = $db->prepare('SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = :country');$query->execute(['country' => $country]);$dragons = $query->fetchAll(); }$db = null;} catch (PDOException $error) {http_response_code(500);exit('Baza danych jest chwilowo niedostępna. Spróbuj ponownie później.');}functione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"> <scriptsrc="script.js"defer></script></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divclass="block"data-section="1"role="button"tabindex="0">Baza</div> <divclass="block"data-section="2"role="button"tabindex="0">Opisy</div> <divclass="block"data-section="3"role="button"tabindex="0">Galeria</div> </nav> <main> <section> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"aria-label="Kraj pochodzenia"><?phpforeach ($countriesas$countryName): ?> <option<?= $countryName === $country ? ' selected' : ''?>><?= e($countryName) ?></option><?phpendforeach; ?> </select> <buttontype="submit">Szukaj</button> </form> <table> <thead> <tr> <th>Nazwa</th> <th>Długość</th> <th>Szerokość</th> </tr> </thead> <tbody><?phpforeach ($dragonsas$dragon): ?> <tr> <td><?= e($dragon['nazwa']) ?></td> <td><?= e($dragon['dlugosc']) ?></td> <td><?= e($dragon['szerokosc']) ?></td> </tr><?phpendforeach; ?> </tbody> </table> </section> <section> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <section> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Krok 49 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 49: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 2 min
Obie wersje dają komplet 41 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
układ
float: left + clear: both
siatka z grid-template-areas na <body>
blok 1, sekcje 2 i 3
#block1, #section2, #section3
.block:first-child, section + section
kliknięcie
onclick="showSection(1)" w HTML
addEventListener, numer w data-section
pętla w JS
for (let i = 1; i <= 3; i++)
forEach i operator warunkowy
klawiatura
brak
role="button", tabindex, keydown
baza
mysqli_*, kraj sklejony z SQL
PDO, biała lista, zapytanie przygotowane
Klucz wymusza zmianę stylu przez style.backgroundColor i style.display (R.5.6) - obie wersje to robią. Na egzaminieonclick z identyfikatorami jest krótszy i łatwiejszy do sprawdzenia wzrokiem; selektory strukturalne i data-* opłacają się, gdy bloków przybywa - nowy blok nie wymaga zmian w skrypcie ani w CSS.
Krok 50 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 50: 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. Nagraj płytę z rezultatami pracy.
W folderze z numerem zdającego: config.php, import.jpg, kw1.png … kw4.png, kwerendy.txt, przeglądarka.txt, script.js, smok1.jpg … smok3.jpg, smoki.php, styl.css. Płytę sprawdź po nagraniu.
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.