INF.03-08-26.01-SGStyczeń 2026 · 48 kroków · ok. 91 min · 40 kryteriów z klucza
Rozwiązanie krok po kroku: Portal korony gór polskich (Nowoczesny kod (grid, PDO))
To drugi sposób rozwiązania tego samego arkusza: portal korony gór polskich z bazą korona, logo z przezroczystym tłem, krojem Lato z @font-face i dwiema stronami - index.php z listą 28 szczytów i szczyty.php z opisem jednego szczytu. Obie wersje spełniają wszystkie 40 kryteriów klucza - różni je sposób pisania kodu, nie wynik.
Czym ta wersja różni się od podstawowej:
siatka CSS zamiast float + clear: kolumny 30% 70% na <body> dają naraz szerokości bloków nagłówkowych i stopek, a blok główny i sekcja rozciągają się na cały wiersz,
kolory w zmiennych CSS, font-display: swap w @font-face, pary rozmiarów zapisane przez :is(),
nazwy szczytów w bloku <nav> - numeracja :nth-child liczy tylko spany, niezależnie od reszty bloku głównego,
zapytanie 2 z ORDER BY id, zapytanie 3 z aliasami tabel,
PHP na PDO: w obu plikach dane pobierane na górze, połączenie zamknięte przed HTML-em, w HTML tylko pętle foreach,
identyfikator szczytu z adresu sprawdzony filter_var i wstawiony do zapytania przygotowanego, komunikat dla nieistniejącego szczytu, opis podzielony na akapity, wartości z bazy przez escape().
Kroki nadal idą zdanie po zdaniu za treścią arkusza. Podgląd w każdym kroku z PHP to wynik prawdziwego uruchomienia kodu z tego kroku w PHP 8.2 na bazie z arkusza; szczyty.php pokazuje Rysy, jak na ilustracji 5. Baza, zdjęcia, logo i czcionki pochodzą z prawdziwego archiwum pliki13 (załącznik do arkusza, hasło w treści zadania).
Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
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 40 kryteriów (pkt)
Krok 1: Baza danych korona
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie korona, z zestawem polskich znaków (np. utf8_polish_ci)
Archiwum pliki13.7z ma hasło Gory^PoLskie! (daszek ^ w środku, wykrzyknik na końcu); w środku korona.sql, logo.png, zdjęcia gór i folder czcionka. W phpMyAdmin: Nowa, nazwa korona, porównywanie utf8_polish_ci, albo w zakładce SQL:
CREATE DATABASE korona CHARACTER SET utf8 COLLATE utf8_polish_ci;
Typowe błędy
Skrypty łączą się z bazą po nazwie - literówka w korona zabiera także punkt za połączenie (R.5.1).
Krok 2: Import tabel z pliku korona.sql
ok. 2 min
Polecenie z arkusza
Z rozpakowanego archiwum zaimportuj tabele z pliku korona.sql do utworzonej bazy
Zaznacz bazę korona, potem Import → korona.sql → Wykonaj. Powstają dwie tabele z ilustracji 1: szczyty (nazwa, wysokość, pasmo, lokator, plik zdjęcia) i opis - każdy opis wskazuje swój szczyt kluczem obcym szczyty_id.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonany import tabel do bazy danych korona - plik 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
Print Screen (cały ekran z paskiem zadań), wklej do edytora grafiki i zapisz jako import.png. Zrzuty zapytań w tym arkuszu są w formacie JPEG - tylko import idzie do PNG.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: szczyty od najwyższego
Kryteria: ,
R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonane zapytanie 1: wybierające jedynie id oraz nazwy szczytów posortowane malejąco według ich wysokości. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC; oraz na zrzucie widoczny jest komunikat o wybranych 28 rekordach oraz pierwsze trzy rekordy to 1 Rysy, 9 Babia Góra, 26 Śnieżka
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie id oraz nazwy wszystkich szczytów posortowane malejąco według ich wysokości
SELECT id, nazwa - dwa pola,
FROM szczyty,
ORDER BY wysokosc DESC - sortowanie po polu spoza listy SELECT jest dozwolone; DESC to kolejność malejąca.
Wynik: 28 wierszy - 1 Rysy, 9 Babia Góra, 26 Śnieżka, …, Łysica. Każda klauzula w osobnej linii - SQL nie zwraca uwagi na znaki nowej linii, a zapytanie czyta się od góry. Zapisz w kwerendy.txt, zrzut jako kw1.jpg (z komunikatem o liczbie rekordów).
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT id, nazwaFROM szczytyORDER BY wysokosc DESC;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: pierwsze 10 rekordów
Kryteria:
R.1.4 Wykonane zapytanie 2: wybierające jedynie nazwy plików i nazwy szczytów dla pierwszych 10 rekordów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT plik, nazwa FROM szczyty LIMIT 10; oraz na zrzucie widocznych jest dokładnie 10 rekordów, ostatni to gora.jpg , Czupel
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie nazwy plików i nazwy szczytów dla pierwszych 10 rekordów
LIMIT 10 obcina wynik do dziesięciu wierszy. Bez ORDER BY baza może oddać wiersze w dowolnej kolejności - w praktyce MariaDB podaje je według klucza głównego, ale to nie jest gwarancja. ORDER BY id mówi wprost, które rekordy są „pierwsze”: identyfikatory 1 - 10. Ostatni to gora.jpg, Czupel - kilka szczytów korzysta z tego samego zdjęcia zastępczego. Wynik ten sam co w wersji podstawowej. Zrzut: kw2.jpg.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT id, nazwaFROM szczytyORDER BY wysokosc DESC;-- Zapytanie 2SELECT plik, nazwaFROM szczytyORDER BY idLIMIT 10;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: szczyt o id 1 z opisem
Kryteria:
R.1.5 Wykonane zapytanie 3: wybierające jedynie nazwę pliku, nazwę szczytu, wysokość i pasmo oraz odpowiadający im opis dla szczytu o id równym 1. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT plik, nazwa, wysokosc, pasmo, opis FROM szczyty JOIN opis ON szczyty.id = szczyty_id WHERE szczyty.id = 1; (lub porównanie kluczy po WHERE. lub szczyty_id = 1 ) oraz na zrzucie widoczny jest dokładnie 1 rekord dla szczytu Rysy
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie nazwę pliku, nazwę szczytu, wysokość i pasmo oraz odpowiadający im opis dla szczytu o id równym 1. Należy posłużyć się relacją
FROM szczyty AS s JOIN opis AS o - aliasy tabel; przy tabeli opis z polem opis alias szczególnie pomaga: o.opis zamiast opis.opis,
ON o.szczyty_id = s.id - relacja: opis wskazuje swój szczyt,
WHERE s.id = 1 - Rysy,
SELECT s.plik, s.nazwa, s.wysokosc, s.pasmo, o.opis - pięć pól, każde z prefiksem tabeli.
Wynik: dokładnie jeden wiersz. phpMyAdmin skraca długi opis - pełny pokaże strona. Zrzut: kw3.jpg.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT id, nazwaFROM szczytyORDER BY wysokosc DESC;-- Zapytanie 2SELECT plik, nazwaFROM szczytyORDER BY idLIMIT 10;-- Zapytanie 3SELECT s.plik, s.nazwa, s.wysokosc, s.pasmo, o.opisFROM szczyty AS sJOIN opis AS o ON o.szczyty_id = s.idWHERE s.id = 1;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: szczyty w Beskidach
Kryteria:
R.1.6 Wykonane zapytanie 4: wybierające jedynie nazwy szczytów, wysokości oraz pasma gór, dla których nazwa pasma rozpoczyna się od „Beskid”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, wysokosc, pasmo FROM szczyty WHERE pasmo LIKE "Beskid%"; (Wielkość litery B nie ma znaczenia ) oraz na zrzucie widocznych jest dokładnie 7 rekordów dla: Beskid Niski, Beskid Sądecki, Beskid Wyspowy, Beskid Makowski, Beskid Żywiecki, Beskid Mały, Beskid Śląski
ok. 2 min
Polecenie z arkusza
Zapytanie 4: wybierające jedynie nazwy szczytów, wysokości oraz pasma gór w Beskidach (nazwa pasma rozpoczyna się od „Beskid”)
„Rozpoczyna się od” to LIKE 'Beskid%' - % zastępuje dowolny ciąg znaków, ale tylko po słowie „Beskid”. Wynik: 7 wierszy - Beskid Niski, Sądecki, Wyspowy, Makowski, Żywiecki, Mały i Śląski. Zrzut: kw4.jpg.
Typowe błędy
LIKE '%Beskid%' szuka słowa w dowolnym miejscu nazwy - tu wynik byłby ten sam, ale zapytanie nie odpowiada poleceniu „rozpoczyna się od”.
kwerendy.txtTekstzmienione: 5 linii
-- Zapytanie 1SELECT id, nazwaFROM szczytyORDER BY wysokosc DESC;-- Zapytanie 2SELECT plik, nazwaFROM szczytyORDER BY idLIMIT 10;-- Zapytanie 3SELECT s.plik, s.nazwa, s.wysokosc, s.pasmo, o.opisFROM szczyty AS sJOIN opis AS o ON o.szczyty_id = s.idWHERE s.id = 1;-- Zapytanie 4SELECT nazwa, wysokosc, pasmoFROM szczytyWHERE pasmo LIKE 'Beskid%';
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-22 · po tym etapie masz 16 z 40 kryteriów (pkt)
Krok 8: Logo: białe tło na przezroczystość
Kryteria:
R.2.2 Grafika ma przezroczyste tło (akceptowalne niedokładności pojedynczych pikseli )
ok. 3 min
Polecenie z arkusza
Przygotowanie grafiki logo.png: Białe tło grafiki należy zastąpić przezroczystością (drobne niedokładności pojedynczych pikseli są akceptowalne)
Grafika jest taka sama w obu wersjach. W GIMP-ie: Warstwa → Przezroczystość → Dodaj kanał alfa, potem Kolory → Kolor na alfę z kolorem białym. Biel znika w całym obrazie - także wewnątrz zboczy, a szare piksele wygładzenia dostają częściową przezroczystość, więc linie nie mają białej obwódki.
Typowe błędy
Różdżka zaznaczająca samo zewnętrzne tło zostawia białe wnętrza gór.
Krok 9: Logo: kadr do szczytu po prawej i wysokość 100 px
Kryteria:
R.2.1 Grafika logo.png skadrowana, tak że widoczny jest jedynie szczyt po prawej stronie, a krawędzie grafiki przylegają do kształtu (widoczne na niepowiększonym obrazie ) oraz przeskalowana do wysokości 100 px
ok. 3 min
Polecenie z arkusza
Skadrować grafikę tak, aby był widoczny jedynie szczyt po prawej stronie. Kadr powinien obejmować cały szczyt oraz krawędzie grafiki powinny przylegać do kształtu (ilustracja 3). Skadrowaną grafikę należy przeskalować z zachowaniem proporcji do wysokości 100 px
Zaznacz prostokątem szczyt z prawego górnego rogu z zapasem, Obraz → Przytnij do zaznaczenia, potem Obraz → Przytnij do zawartości - krawędzie dosuną się do linii. Kadr 227 × 144 px. Obraz → Skaluj obraz z zamkniętym łańcuchem: wysokość 100 px, szerokość wychodzi 158 px. Eksport jako logo.png.
Podgląd strony po tym kroku
Krok 10: Plik index.php w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze stron index.php oraz szczyty.php. Cechy wspólne dla obu stron: Zapisane w języku HTML5
Najpierw strona główna: <!DOCTYPE html> i szkielet. Część wspólna obu stron powstaje raz - szczyty.php będzie kopią gotowego szkieletu.
R.2.3 W pliku index.php lub szczyty.php , znajduje się deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości witryny: polski np. <html lang="pl">. W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony „Korona gór polskich”
ok. 1 min
Polecenie z arkusza
Tytuł strony „Korona gór polskich”
<title> w <head>. Deklaracja HTML5, język, kodowanie i tytuł to razem jedno kryterium (R.2.3).
index.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Korona gór polskich</title></head><body></body></html>
Podgląd strony po tym kroku (index.php)
Krok 14: Podpięcie arkusza stylów
Kryteria:
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 należy brać pod uwagę @font- face)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony
Plik styl.css (nie style.css). Całe formatowanie pochodzi z tego pliku.
index.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Korona gór polskich</title> <linkrel="stylesheet"href="styl.css"></head><body></body></html>
Podgląd strony po tym kroku (index.php)
Krok 15: Bloki: dwa nagłówki, główny, sekcja, dwie stopki
Kryteria:
R.2.4 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header+header, main, section, footer+footer (dopuszcza się zastosowanie bloków pomocniczych)
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ą 4
Klucz wymaga wprost dwóch <header>, <main>, <section> i dwóch <footer> (R.2.4). Sekcja stoi poza blokiem głównym - na ilustracji 4 zajmuje osobny pas pod nim. Bloki nie dostają identyfikatorów: siatka CSS ustawi pierwszy z pary w kolumnie 30%, a drugi w kolumnie 70% według kolejności w kodzie.
Lista punktowana (nieuporządkowana) zawierająca dwa elementy: „Zadzwoń do nas: 111 222 333”
Lista punktowana to <ul>. Numer telefonu jest odnośnikiem tel: - na telefonie dotknięcie od razu wybiera numer (w formacie międzynarodowym, bez spacji). Treść elementu zostaje taka jak w arkuszu.
Krok 22: Plik szczyty.php: kopia wspólnego szkieletu
ok. 1 min
Polecenie z arkusza
Cechy bloku głównego dla strony index.php: Efekt działania skryptu 1. Cechy bloku głównego dla strony szczyty.php: Efekt działania skryptu 3
Obie strony mają te same bloki, nagłówki i stopki - różnią się zawartością bloku głównego. Gotowy plik zapisz jeszcze raz jako szczyty.php. Blok główny wypełni skrypt 1 na stronie głównej i skrypt 3 na stronie szczytu.
Kroki 23-33 · po tym etapie masz 27 z 40 kryteriów (pkt)
Krok 23: Krój Lato: reguły @font-face
Kryteria:
R.4.10 czcionka Lato: w stylach zdefiniowana przynajmniej raz dyrektywa @font-face z rzeczywistymi ścieżkami URL
ok. 3 min
Polecenie z arkusza
Styl CSS korzysta z kroju czcionki Lato znajdującej się w folderze czcionka z rozpakowanego archiwum. Czcionkę należy dodać do projektu i zdefiniować jej stosowanie dla wariantu regular i bold. W pliku styl.css należy dodać reguły dla czcionki. Przykład umieszczono w pliku przyklad.css
Folder czcionka z archiwum trafia do folderu z numerem zdającego. Dwie reguły @font-face pod tą samą nazwą 'Lato' - zwykła i pogrubiona - ze ścieżkami do podfolderu czcionka/ (R.4.10). Różnice wobec przyklad.css:
grubości liczbami: 400 to normal, 700 to bold - ta sama skala, której używają nagłówki,
font-display: swap - zanim plik kroju się pobierze, tekst wyświetla się krojem zapasowym, zamiast być niewidoczny; potem przeglądarka podmienia krój.
woff2 stoi pierwszy, bo jest mniejszy; woff to zapas dla starszych przeglądarek.
Typowe błędy
Ścieżka z przykładu bez folderu czcionka/ nie znajdzie pliku - strona ładuje się krojem zastępczym. Sprawdź w narzędziach przeglądarki, zakładka Sieć.
Krok 24: Zmienne kolorów, krój, wyrównanie i kolor dla wszystkich
Kryteria:
R.4.1 domyślne formatowanie selektorów (*): krój czcionki Lato, sans-serif (dozwolona tylko taka kolejność) , wyrównanie tekstu do środka oraz kolor czcionki #333
ok. 2 min
Polecenie z arkusza
Domyślnie dla wszystkich selektorów: krój czcionki Lato, w przypadku braku sans-serif, wyrównanie tekstu do środka, kolor czcionki #333
Kolory z arkusza stoją w zmiennych CSS w :root - w jednym miejscu na górze pliku, z nazwami mówiącymi, do czego służą. Reguła *: Lato, sans-serif w tej kolejności (klucz innej nie uznaje), środkowanie i kolor var(--text) (R.4.1).
R.4.5 szerokość: blok nagłówkowy 1, stopka 1: 30%, blok nagłówkowy 2, stopka 2: 70% (width lub grid-template-columns lub flex )
ok. 2 min
Polecenie z arkusza
Dodatkowo dla bloku nagłówkowego 1 i bloku stopki 1: szerokość 30%. Dodatkowo dla bloku nagłówkowego 2 i bloku stopki 2: szerokość 70%
<body> staje się siatką o dwóch kolumnach: grid-template-columns: 30% 70%. Bloki układają się w komórkach po kolei, więc pierwszy nagłówek i pierwsza stopka trafiają do kolumny 30%, a drugie z pary - do kolumny 70%. Jedna linia daje oba zdania arkusza naraz; klucz dopuszcza szerokości z grid-template-columns (R.4.5).
Blok główny i sekcja wpadają na razie do pojedynczych komórek - rozciągnie je następny krok.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 4 w arkuszu egzaminacyjnym (prawidłowo zastosowano 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. 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ą 4
grid-column: 1 / -1 rozciąga blok główny i sekcję od pierwszej do ostatniej linii siatki - każde zajmuje cały wiersz. Stopki wracają do pary 30% / 70% w ostatnim wierszu, jak na ilustracji 4 (R.3.1). Bez float nie trzeba clear ani pilnować, czy bloki nie zachodzą na siebie.
Typowe błędy
Bez tej reguły blok główny zostaje w kolumnie 30%, a sekcja w kolumnie 70% - układ nie zgadza się z ilustracją.
Krok 29: Blok sekcji: wysokość i ukrywanie nadmiaru
Kryteria: ,
R.4.3 wysokość: bloki nagłówkowe, stopki 100px, blok sekcji 90px
R.4.6 przepełnienie bloków: blok sekcji - overfow: hidden
ok. 1 min
Polecenie z arkusza
Dla bloku sekcji: wysokość 90 px, w przypadku przepełnienia bloku zawartość, która się w nim nie mieści jest ukryta
overflow: hidden obcina to, co wystaje poza 90 px - z dziesięciu miniatur widać pierwszy rząd, jak na ilustracji 2. Komplet wysokości (R.4.3). Druga reguła section w tym samym pliku nie przeszkadza - przeglądarka łączy właściwości obu.
Styl dla kolejnych potomków selektora span: dla 2 i 11: rozmiar czcionki 200%, dla 3 i 15: rozmiar czcionki 150%, dla 4 i 17: rozmiar czcionki 120%, dla 5 i 21: rozmiar czcionki 170%, dla 7 i 27: rozmiar czcionki 130%, dla 9 i 25: rozmiar czcionki 160%
:nth-child(n) wybiera element, który jest n-tym dzieckiem swojego rodzica (tabela 4 arkusza). Para o tym samym rozmiarze to jedna reguła z pseudoklasą :is(): span:is(:nth-child(2), :nth-child(11)) znaczy „span, który jest drugim albo jedenastym dzieckiem”. Działa jak lista span:nth-child(2), span:nth-child(11), ale span pisze się raz (R.4.9).
Spany wypisze skrypt 1 do bloku <nav> - poza nimi nic tam nie będzie, więc drugi span to drugie dziecko.
Typowe błędy
Klucz nazywa :nth-child pseudoelementem, ale to pseudoklasa (jeden dwukropek); pseudoelementy, jak ::first-letter, mają dwa.
Kroki 34-45 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 34: index.php: połączenie PDO na górze pliku
Kryteria:
R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy korona oraz ostatnią operacją na bazie jest jej zamknięcie
ok. 4 min
Polecenie z arkusza
Napisane w języku PHP. Należy stosować znaczące nazewnictwo zmiennych w języku polskim lub angielskim. Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie korona. Na końcu skrypt zamyka połączenie z bazą
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):
DSN 'mysql:host=localhost;dbname=korona;charset=utf8mb4' - serwer, baza i kodowanie; 'root', '' - użytkownik i puste hasło,
ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze jako tablice z nazwami kolumn,
$pdo = null zamyka połączenie - zapytania trafią przed tę linię, więc zamknięcie zostanie ostatnią operacją na bazie (R.5.1),
try / catch - gdy baza nie działa, szczegóły idą do dziennika serwera (error_log), a w bloku głównym stoi ogólny komunikat z $dbError,
funkcja escape() to krótka nazwa htmlspecialchars(..., ENT_QUOTES) - posłuży każdej wartości z bazy.
Zmienne $peaks, $thumbnails i $dbError mają wartości początkowe, żeby HTML działał także po błędzie bazy.
R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub skrypt 2 zawiera instrukcję wysyłającą do bazy danych zapytanie 2
ok. 2 min
Polecenie z arkusza
Skrypt 1, na stronie index.php: Wysyła do bazy danych zapytanie 1
$pdo->query(...) wysyła zapytanie 1, a ->fetchAll() od razu odbiera wszystkie 28 wierszy do tablicy $peaks (R.5.2). Zapytanie nie zawiera danych od użytkownika, więc wystarcza query.
Krok 36: Skrypt 1: nazwy szczytów w znacznikach span
Kryteria: ,
R.2.9 Na stronie index.php znajduje się przynajmniej jeden znacznik <span> (w HTML lub skrypcie )
R.5.3 Skrypt 1 wyświetla wszystkie zwrócone zapytaniem nazwy szczytów zapisanych w kolejnych znacznikach <span> (od Rysów do Łysicy)
ok. 3 min
Polecenie z arkusza
Każdą zwróconą zapytaniem nazwę szczytu wyświetla w znaczniku <span>, tak że jest ona odnośnikiem do pliku szczyty.php oraz przekazuje do tego pliku metodą GET id szczytu
Najpierw same nazwy. W bloku głównym stoi <nav> z opisem aria-label (czytnik ekranu ogłosi „nawigacja: Szczyty Korony Gór Polskich”), a w nim pętla foreach ($peaks as $peak): w składni alternatywnej: jeden <span> na szczyt, od Rysów do Łysicy (R.2.9, R.5.3). <?= ... ?> to skrót od <?php echo ... ?>.
Blok <nav> ma też zaletę dla CSS: rodzicem spanów jest <nav>, a nie <main>, więc komunikat o błędzie bazy nad nim nie przesunie numeracji :nth-child - Babia Góra i Rudawiec są największe.
Krok 37: Skrypt 1: odnośnik z identyfikatorem w adresie
Kryteria: ,
R.3.4 Przynajmniej jeden odnośnik ze strony głównej otwiera stronę szczyty.php (w skrypcie lub w HTML )
R.5.4 Po kliknięciu nazwy szczytu na stronie głównej otwierana jest podstrona, do której przekazywany jest parametr metodą GET. Adres URL ma postać: szczyty.php?id=<wartość> i działa co najmniej dla 2 szczytów
ok. 2 min
Polecenie z arkusza
Każdą zwróconą zapytaniem nazwę szczytu wyświetla w znaczniku <span>, tak że jest ona odnośnikiem do pliku szczyty.php oraz przekazuje do tego pliku metodą GET id szczytu
Nazwa w <a> wewnątrz spana, parametr GET po znaku zapytania: szczyty.php?id=1 dla Rysów (tabela 2 arkusza; R.3.4, R.5.4). (int) przy identyfikatorze gwarantuje, że do adresu trafi liczba. W szablonie HTML cudzysłowy atrybutu stoją zwyczajnie - nie trzeba ich poprzedzać ukośnikiem jak w napisie PHP. Odnośnik jest ciemnoszary, bo selektor * ustawia kolor #333 każdemu elementowi, także <a>.
Drugie zapytanie przy otwartym połączeniu, przed $pdo = null: dziesięć par plik - nazwa do tablicy $thumbnails. Wszystkie dane strony są już pobrane, zanim zacznie się HTML.
R.2.10 Przynajmniej jedna grafika z bloku sekcji ma przypisaną klasę miniatury (w HTML lub skrypcie )
R.5.5 Skrypt 2 zawiera pętlę działającą na wszystkich rekordach zwróconych zapytaniem
R.5.6 Na stronie głównej są wyświetlane obrazy z plików o nazwach zwróconych w wyniku zapytania oraz tekstach alternatywnych zawierających nazwę szczytu (część obrazów może być ukryta)
ok. 2 min
Polecenie z arkusza
Dla każdego zwróconego zapytaniem rekordu wyświetla obraz, w którym nazwa pliku jest źródłem a nazwa szczytu – tekstem alternatywnym. Każdy obraz ma przypisaną klasę miniatury
W sekcji pętla foreach po $thumbnails (R.5.5): src z pola plik, alt z pola nazwa, klasa miniatury (R.2.10, R.5.6). Obie wartości przez escape() - stoją w atrybutach w cudzysłowach, więc cudzysłów w nazwie rozbiłby znacznik. Drugi rząd zdjęć znika za overflow: hidden, jak na ilustracji 2.
Krok 40: szczyty.php: połączenie i ten sam skrypt 2
ok. 2 min
Polecenie z arkusza
Zawartość bloku sekcji: Efekt działania skryptu 2
Sekcja jest wspólna dla obu stron, więc do szczyty.php trafia ta sama górna część PHP (funkcja escape(), połączenie, zapytanie 2) i ta sama pętla miniatur. Podgląd pokazuje stronę szczytu z pustym blokiem głównym i paskiem miniatur.
Krok 41: Skrypt 3: id z adresu i zapytanie przygotowane
Kryteria:
R.5.7 Skrypt 3 (podstrona) zawiera instrukcję wysyłającą do bazy danych zapytanie 3, zmodyfikowane w ten sposób, że wybierany jest rekord o id przesłanym do strony
ok. 4 min
Polecenie z arkusza
Skrypt 3, na stronie szczyty.php (ilustracja 5): Wysyła do bazy danych zapytanie 3, zmodyfikowane w ten sposób, że sprawdzane jest id wysłane z pliku index.php metodą GET
Identyfikator przychodzi w adresie (szczyty.php?id=1), czyli w $_GET['id']. Najpierw filter_var z FILTER_VALIDATE_INT i minimum 1: oddaje liczbę albo false (dla abc, -3, 1 OR 1=1). Operator ?? podstawia pusty napis, gdy parametru nie ma wcale - wtedy też wychodzi false, bez ostrzeżenia „Undefined array key”.
Zapytanie 3 z aliasami, w którym zamiast 1 stoi parametr :id: prepare wysyła strukturę zapytania, execute(['id' => $peakId]) - wartość osobno (R.5.7). fetch() oddaje jeden wiersz albo false, gdy szczytu nie ma; ?: null zamienia false na null, które czytelniej znaczy „brak”. Od tego kroku podgląd to strona otwarta kliknięciem „Rysy”.
Wyświetla dane zwrócone zapytaniem: Obraz z pliku, którego nazwa została zwrócona, z tekstem alternatywnym „szczyt”
W bloku głównym warunek if ($peak !== null): - dane szczytu trafiają na stronę tylko wtedy, gdy rekord się znalazł. Zdjęcie z pola plik (rysy.jpg), tekst alternatywny stały: „szczyt”. Bez klasy miniatury, więc w naturalnym rozmiarze, jak na ilustracji 5.
R.5.9 Na podstronie nazwa szczytu jest wyświetlana w <h2>, oraz w <h3>: "wysokość: <wysokosc> metrów n.p.m." i "pasmo górskie: <pasmo>", wartości w <> są pobrane z bazy danych
ok. 2 min
Polecenie z arkusza
Nagłówek drugiego stopnia z nazwą szczytu. Nagłówek trzeciego stopnia o treści: „wysokość: <wysokosc> metrów n.p.m.”. Nagłówek trzeciego stopnia o treści: „pasmo górskie: <pasmo>”, pola <> zostały pobrane z bazy danych
Pola po nazwach kolumn: $peak['nazwa'] w <h2>, wysokość i pasmo w dwóch <h3> ze stałym tekstem dookoła (R.5.9). Dla Rysów: „wysokość: 2499 metrów n.p.m.” i „pasmo górskie: Tatry”.
R.5.8 Na podstronie wyświetlany jest obraz z pliku o nazwie zwróconej w wyniku zapytania i tekście alternatywnym "szczyt" oraz opis szczytu
R.5.10 W skryptach zastosowana przynajmniej jedna zmienna oraz nazwy wszystkich zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania
ok. 1 min
Polecenie z arkusza
Paragraf z opisem
Opis z tabeli opis w <p> - strona szczytu wygląda jak na ilustracji 5 (R.5.8). Nazwy zmiennych i funkcji mówią, co przechowują (R.5.10): $pdo, $peaks, $peak, $peakId, $thumbnails, $thumbnail, $statement, $dbError, escape().
10 opisów ma w środku puste wiersze, ale HTML zamienia znaki końca linii na spacje - opis Babiej Góry zlewa się w jeden blok. preg_split('/\R+/u', ...) dzieli tekst w miejscach końców linii (\R to dowolny koniec linii: \n, \r\n), a pętla daje każdemu kawałkowi własny <p>. trim usuwa puste wiersze na brzegach.
Flaga u na końcu wzorca jest konieczna: każe czytać tekst jako UTF-8. Bez niej \R pasuje też do pojedynczego bajtu 0x85, a ten bajt jest drugą połową litery „ą” w UTF-8 - wzorzec przecinał „znajdujący” w środku litery, a htmlspecialchars zwracało pusty napis dla uszkodzonego kawałka. Z opisu Rysów zostawał sam koniec (sprawdzone).
Gałąź else obsługuje adres bez szczytu: ?id=99, ?id=abc, ?id=1 OR 1=1 i samo szczyty.php dają „Nie znaleziono szczytu” zamiast pustych nagłówków albo ostrzeżeń PHP (sprawdzone). Podgląd: Babia Góra (?id=9). Klucz tego nie sprawdza.
Kroki 46-47 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 46: Co jest inaczej i dlaczego
ok. 3 min
Polecenie z arkusza
Ocenie podlegać będzie 5 rezultatów: operacje na bazie danych, zawartość witryny internetowej, działanie witryny internetowej, styl CSS witryny internetowej, skrypt połączenia z bazą.
Obie wersje dają te same punkty. Różnice:
wersja podstawowa
ta wersja
układ
float: left + clear: both, szerokości przez #logo, #contact…
siatka 30% 70% na <body>, grid-column: 1 / -1
identyfikatory bloków
logo, title, contact, author
niepotrzebne
rozmiary nazw
span:nth-child(2), span:nth-child(11)
span:is(:nth-child(2), :nth-child(11))
spany
prosto w <main>
w <nav> - numeracja niezależna od reszty bloku
zapytanie 2
LIMIT 10
ORDER BY id LIMIT 10
baza
mysqli_* w miejscu wypisywania
PDO na górze każdego pliku
id z adresu
wstawiony do SQL
filter_var i parametr :id
zły adres
ostrzeżenia PHP, puste nagłówki
„Nie znaleziono szczytu”
opis
jeden akapit
akapity z preg_split
Obie wersje powtarzają w dwóch plikach połączenie i skrypt 2. W większym projekcie trafiłyby do osobnego pliku dołączanego przez require - tu arkusz każe pisać skrypty na stronach, a klucz sprawdza je w kodzie strony.
Czas przeznaczony na wykonanie zadania wynosi 150 minut.
Wersja podstawowa, gdy liczy się czas albo PDO i siatka nie są opanowane: funkcje mysqli_* są w tabeli 1 arkusza, a każdy skrypt stoi tam, gdzie widać jego efekt.
Ta wersja, gdy PDO i siatka są pisane z pamięci. :is() warto znać, ale zwykła lista selektorów po przecinku daje ten sam punkt.
Mieszanie też daje pełne punkty: siatka z tej wersji i mysqli_* z podstawowej. Zdjęcie zastępcze dla szczytu bez pliku (file_exists) jest pokazane w etapie „Dobre praktyki” wersji podstawowej.
Krok 48 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 48: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
UWAGA: 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. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt nazwa przeglądarki, w której strona była sprawdzana przez http://localhost/…/index.php.
W folderze z numerem zdającego: folder czcionka z plikami Lato, zdjęcia gór, import.png, index.php, kw1.jpg - kw4.jpg, kwerendy.txt, logo.png, przeglądarka.txt, styl.css, szczyty.php. Po nagraniu sprawdź odczyt płyty.
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.