INF.03-05-24.06-SGCzerwiec 2024 · 53 kroki · ok. 94 min · 41 kryteriów z klucza
Rozwiązanie krok po kroku: Aplikacja komisu samochodowego (Wersja podstawowa)
Aplikacja internetowa komisu samochodowego: baza kupauto (marki i samochody połączone relacją jeden do wielu) i cztery zapytania - lista marek, jeden samochód po identyfikatorze, złączenie JOIN dla ofert wyróżnionych z ograniczeniem LIMIT 4 i złączenie z warunkiem na nazwę marki - potem strona KupAuto.php z banerem, trzema blokami jeden pod drugim i stopką oraz cztery skrypty PHP: oferta dnia, cztery oferty wyróżnione, lista rozwijana marek z bazy i wyszukiwanie samochodów wybranej marki.
Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty powstają najpierw najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row, isset), a na końcu przechodzą do wersji z prawdziwych projektów: zapytanie przygotowane, zapamiętana marka na liście, htmlspecialchars i jedna funkcja zamiast dwóch kopii bloku oferty.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: bloki ofert w kontenerze flex, kolory w zmiennych i PHP na PDO z danymi pobranymi przed HTML-em, z marką sprawdzaną na liście dozwolonych - obie wersje są zgodne z kluczem.
Baza i zdjęcia pochodzą z prawdziwego archiwum pliki5 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robi się je samemu, z całego ekranu. Podgląd strony od kroków z PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 na bazie z arkusza; od kroku ze Skryptem 4 pokazuje stan z obrazu 3, czyli po wybraniu marki „Opel” i kliknięciu „Wyszukaj”.
Jak liczą się punkty. Klucz ma 41 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 31 punktów - można stracić 10 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
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 kupauto
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie kupauto, z zestawem polskich znaków (np. utf8_unicode_ci)
Najpierw archiwum pliki5.zip z pulpitu (hasło S@moCHody^ - małpa zamiast „a” i daszek na końcu) rozpakowuje się do folderu nazwanego numerem zdającego. W phpMyAdmin: Nowa, nazwa kupauto, porównywanie utf8_unicode_ci. Zestaw utf8 przyjmuje polskie litery, a porównywanie decyduje o sortowaniu i o tym, czy „audi” równa się „Audi” (w _ci - tak, bo ignoruje wielkość liter). Dla tabel z baza.sql liczy się jednak ich własne porównywanie utf8_unicode_ci, zapisane w definicji tabel - porównywanie bazy dziedziczą tylko tabele zakładane później bez własnego ustawienia.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie kupauto - skrypty łączą się z bazą po nazwie, więc literówka zabiera też punkty za skrypty (R.5.1).
Krok 2: Import tabel z pliku baza.sql
ok. 2 min
Polecenie z arkusza
Do bazy zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum
Zaznaczona baza kupauto, potem Import → baza.sql → Wykonaj. Powstają dwie tabele z obrazu 1: marki (9 marek) i samochody (17 samochodów). Pole marki_id w samochodach wskazuje identyfikator marki - to jest relacja 1..n z arkusza: jedna marka, wiele samochodów. Pole wyrozniony ma typ TINYINT(1): 1 - samochód wyróżniony, 0 - zwykły.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych kupauto czynność udokumentowano plikiem o nazwie import w formacie PNG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG i nazwij import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.
Print Screen, wklejenie do edytora grafiki i zapis jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: nazwy marek
Kryteria: ,
R.1.2 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonano zapytanie 1 wybierające jedynie nazwy marek samochodów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM marki; oraz wynik działania udokumentowano zrzutem, na którym jest widocznych dokładnie 9 wierszy, nazwy wszystkich marek: Audi, BMW, Volkswagen, Opel, Ford, Mercedes, Toyota, Fiat, Jeep
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie nazwy marek samochodów
SELECT nazwa - jedno pole, bez identyfikatora („jedynie nazwy”),
FROM marki - tabela marek.
Wynik: 9 wierszy - Audi, BMW, Volkswagen, Opel, Ford, Mercedes, Toyota, Fiat, Jeep, zgodnie z kluczem. Zapytania zapisuje się w kwerendy.txt, zrzut wyniku jako kw1.jpg. To zapytanie wypełni później listę rozwijaną (Skrypt 3).
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT nazwa FROM marki;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: samochód o identyfikatorze 10
Kryteria:
R.1.4 Wykonano zapytanie 2 wybierające jedynie pola: model, rocznik, przebieg, paliwo, cena, zdjecie dla samochodu o id równym 10. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id=10; oraz wynik działania udokumentowano zrzutem, na którym jest widoczny dokładnie 1 wiersz: Yaris 2022 0 Benzyna 94000 ToyotaYaris.jpg
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pola: model, rocznik, przebieg, paliwo, cena, zdjecie dla samochodu o id równym 10
SELECT model, rocznik, przebieg, paliwo, cena, zdjecie - sześć pól w kolejności z arkusza; ta kolejność wyznaczy numery komórek w Skrypcie 1,
FROM samochody,
WHERE id = 10 - dokładnie jeden samochód, bo id jest kluczem głównym.
Wynik: Yaris 2022 0 Benzyna 94000 ToyotaYaris.jpg, jak w kluczu. Zrzut: kw2.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM marki;-- Zapytanie 2SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id = 10;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: cztery oferty wyróżnione z nazwą marki
Kryteria:
R.1.5 Wykonano zapytanie 3 wybierające jedynie pole nazwa z tabeli marki i odpowiadające jej pola: model, rocznik, cena, zdjecie z tabeli samochody jedynie dla samochodów wyróżnionych. Wybierane są dokładnie 4 wiersze. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, model, rocznik, cena, zdjecie FROM samochody JOIN marki ON marki_id = marki.id WHERE wyrozniony=1 LIMIT 4; (możliwe również INNER JOIN lub bez JOIN porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie 4 wiersze, jedynie pola nazwa, model, rocznik, cena, zdjecie dla modeli: A8 TDI QUattro, A8, Astra, Corsa
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pole nazwa z tabeli marki i odpowiadające jej pola: model, rocznik, cena, zdjecie z tabeli samochody jedynie dla samochodów wyróżnionych. Zapytanie wybiera dokładnie 4 wiersze. Należy posłużyć się relacją
SELECT nazwa, model, rocznik, cena, zdjecie - nazwa marki pochodzi z tabeli marki, reszta z samochody,
FROM samochody JOIN marki ON samochody.marki_id = marki.id - relacja: do każdego samochodu dołączany jest wiersz marki o identyfikatorze zapisanym w marki_id,
WHERE wyrozniony = 1 - tylko samochody wyróżnione,
LIMIT 4 - najwyżej cztery wiersze.
Bez LIMIT zapytanie zwraca 6 wierszy - w bazie jest sześć samochodów wyróżnionych (doszłyby Toyota Yaris i Corolla). Arkusz wymaga „dokładnie 4 wierszy”, a klucz wprost podaje LIMIT 4, więc ograniczenie jest częścią rozwiązania. Wynik: A8 TDI QUattro, A8, Astra, Corsa - jak w kluczu. Zrzut: kw3.jpg.
Typowe błędy
Zapytanie bez LIMIT 4 zwraca 6 wierszy, a klucz wymaga na zrzucie dokładnie 4. Bez złączenia (sam marki_id zamiast nazwy) nie ma nazwy marki.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM marki;-- Zapytanie 2SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id = 10;-- Zapytanie 3SELECT nazwa, model, rocznik, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE wyrozniony = 1 LIMIT 4;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: samochody marki Audi
Kryteria:
R.1.6 Wykonano zapytanie 4 wybierające jedynie pola: model, cena, zdjecie z tabeli samochody dla samochodów o nazwie marki Audi. Należy wykorzystać relację. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT model, cena, zdjecie FROM samochody JOIN marki ON marki_id = marki.id WHERE nazwa = "Audi"; (możliwe również INNER JOIN lub bez JOIN porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym są widoczne są dokładnie 4 wiersze, jedynie pola model, cena, zdjecie, dla modeli: A3, A8 TDI QUattro, A3, A8
ok. 2 min
Polecenie z arkusza
Zapytanie 4: wybierające jedynie pola: model, cena, zdjecie z tabeli samochody dla samochodów o nazwie marki Audi. Należy posłużyć się relacją
SELECT model, cena, zdjecie - trzy pola z samochodów,
FROM samochody JOIN marki ON samochody.marki_id = marki.id - to samo złączenie co w zapytaniu 3,
WHERE nazwa = 'Audi' - warunek na nazwę marki, a nie na marki_id = 1: arkusz każe posłużyć się relacją, a w Skrypcie 4 z listy przyjdzie właśnie nazwa.
Wynik: 4 wiersze - A3, A8 TDI QUattro, A3, A8, zgodnie z kluczem. Zrzut: kw4.jpg.
Typowe błędy
WHERE marki_id = 1 daje ten sam wynik, ale nie korzysta z relacji, o którą prosi arkusz.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM marki;-- Zapytanie 2SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id = 10;-- Zapytanie 3SELECT nazwa, model, rocznik, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE wyrozniony = 1 LIMIT 4;-- Zapytanie 4SELECT model, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE nazwa = 'Audi';
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-23 · po tym etapie masz 16 z 41 kryteriów (pkt)
Krok 8: ToyotaYaris.jpg: szerokość 500 px
Kryteria:
R.2.1 Grafikę ToyotaYaris.jpg przeskalowano z zachowaniem proporcji do szerokości, dokładnie 500 px, odpowiadająca temu wysokość wynosi 332 px (±5 px)
ok. 3 min
Polecenie z arkusza
Grafikę ToyotaYaris.jpg, wypakowaną z archiwum, należy przeskalować z zachowaniem proporcji do szerokości, dokładnie 500 px
W GIMP-ie: Obraz → Skaluj obraz, łańcuch między szerokością a wysokością zamknięty (to jest zachowanie proporcji), szerokość 500. Oryginał ma 640×425 px, więc wysokość wychodzi 425 · 500 / 640 ≈ 332 px - dokładnie tyle, ile podaje klucz. Zapis pod tą samą nazwą (Plik → Nadpisz ToyotaYaris.jpg), bo tę nazwę ma pole zdjecie w bazie.
Typowe błędy
Zapis pod nową nazwą (np. ToyotaYaris-500.jpg) - strona i tak wczyta oryginał, bo nazwę pliku bierze z bazy.
Podgląd strony po tym kroku
Krok 9: Plik KupAuto.php w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie KupAuto.php zapisanej w języku HTML5
Deklaracja <!DOCTYPE html> i szkielet strony z sekcjami head i body. Nazwa pliku z wielkimi literami K i A, dokładnie jak w arkuszu. Rozszerzenie .php, bo dojdą skrypty; na egzaminie plik leży w htdocs XAMPP-a i otwiera się go przez http://localhost/....
R.2.2 Witrynę internetową zapisano w pliku KupAuto.php oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> i zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body
ok. 1 min
Polecenie z arkusza
Jawnie zastosowany właściwy standard kodowania polskich znaków
<meta charset="UTF-8"> jako pierwszy element <head>. Z deklaracją HTML5, językiem i nazwą pliku to jedno kryterium klucza.
R.3.6 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css , formatowanie CSS pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony
Nazwa pliku: styl.css (nie style.css). Całe formatowanie ma pochodzić z tego pliku - bez atrybutów style w HTML-u i bez <style> w nagłówku.
Typowe błędy
Klucz odbiera R.3.6 także wtedy, gdy choć jeden selektor nie trafia w blok (np. kropka zamiast # przy identyfikatorze).
R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: banera, trzy główne oraz stopkę. Zastosowano semantyczne znaczniki sekcji HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, stopki - footer, dopuszcza się zagnieżdżenie bloków div w znacznikach semantycznych
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: baner, trzy bloki główne umiejscowione jeden pod drugim, na dole blok stopki. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2
Baner to <header>, stopka to <footer>, a trzy bloki główne to trzy <section> - klucz (R.2.4) wymaga wprost header i footer. Każda sekcja dostaje identyfikator po angielsku: day (oferta dnia), featured (oferty wyróżnione), search (wyszukiwanie). Po nich arkusz stylów rozróżni bloki - zwłaszcza pierwszy, który ma własne tło i wysokość.
R.2.6 Frazę „KupAuto!” zapisano za pomocą znacznika semantycznego <em>
ok. 1 min
Polecenie z arkusza
Zawartość banera: nagłówek pierwszego stopnia o treści „KupAuto! Internetowy Komis Samochodowy”. Fraza „KupAuto!” jest zapisana za pomocą znacznika semantycznego oznaczającego uwydatnienie i zapisywanego czcionką pochyłą
Nagłówek pierwszego stopnia to <h1>. Znacznik semantyczny uwydatnienia to <em> (ang. emphasis) - przeglądarka pisze go kursywą. <i> też daje kursywę, ale nie niesie znaczenia „uwydatnione”, więc nie spełnia polecenia.
Typowe błędy
<i>KupAuto!</i> wygląda tak samo, ale klucz (R.2.6) wymaga znacznika <em>.
Krok 16: Pierwszy blok główny: miejsce na Skrypt 1
ok. 1 min
Polecenie z arkusza
Zawartość pierwszego bloku głównego: efekt działania skryptu 1
W sekcji day nie ma żadnego stałego tekstu - cała zawartość (zdjęcie, nagłówki, akapit) przyjdzie z bazy. Sekcja zostaje na razie pusta; Skrypt 1 dopisze się w niej w części o PHP.
R.3.5 Formularz wysyła dane metodą POST do skryptu
ok. 1 min
Polecenie z arkusza
Formularz wysyłający dane metodą bezpieczną, zawierający listę rozwijalną i przycisk
method="post" - „metoda bezpieczna” z arkusza: wybrana marka jedzie w treści żądania, nie w adresie strony. W specyfikacji HTTP „bezpieczne” są co prawda metody, które niczego nie zmieniają na serwerze (GET i HEAD), ale arkusz używa tego słowa w innym sensie, a klucz wymaga POST. Atrybut action można pominąć - formularz bez niego wysyła dane do bieżącego pliku, czyli do KupAuto.php, gdzie czeka Skrypt 4.
<select> z atrybutem name="brand" - pod tą nazwą wybrana marka trafi do $_POST. Elementów <option> nie wpisuje się ręcznie: dopisze je Skrypt 3 z zapytania 1, więc lista sama się zaktualizuje, gdy komis doda nową markę.
Typowe błędy
Lista bez name nic nie wysyła - Skrypt 4 nigdy nie dostanie marki.
R.2.5 W banerze zapisano nagłówek h1: "KupAuto! Internetowy Komis Samochodowy" , w drugim bloku głównym h2: "Oferty Wyróżnione" , w trzecim bloku głównym h2: "Wybierz markę" oraz w stopce dwa paragrafy z numerem zdającego i z odnośnikiem
R.3.4 Odnośnik o treści "Znajdź nas także" inicjuje otwarcie strony "http://firmy.pl/komis"
ok. 1 min
Polecenie z arkusza
Paragraf z odnośnikiem o treści „Znajdź nas także”, prowadzącym do strony http://firmy.pl/komis
Drugi akapit, a w nim <a href="http://firmy.pl/komis">. Adres przepisany dokładnie, z http:// - bez protokołu przeglądarka szukałaby pliku firmy.pl/komis obok strony. Z tym krokiem są wszystkie nagłówki i akapity z R.2.5: <h1> w banerze, dwa <h2> i dwa akapity w stopce.
Kroki 24-34 · po tym etapie masz 28 z 41 kryteriów (pkt)
Krok 24: Plik styl.css: krój Roboto albo szeryfowy
Kryteria:
R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (dla *): krój czcionki Roboto, Serif (tylko taka kolejność jest prawidłowa)
ok. 1 min
Polecenie z arkusza
Domyślne formatowanie wszystkich selektorów: krój czcionki Roboto, w przypadku jej braku - Serif
Selektor uniwersalny * i lista krojów: najpierw Roboto, a gdy go nie ma na komputerze, ogólna rodzina serif. Kolejność ma znaczenie - przeglądarka bierze pierwszy dostępny krój. Na komputerze bez Roboto przeglądarka weźmie krój szeryfowy - tak wygląda obraz 2 z arkusza.
Typowe błędy
font-family: serif, Roboto - odwrotna kolejność; klucz uznaje tylko Roboto, potem serif.
styl.cssCSSnowy plik
* {font-family: Roboto, serif;}
Podgląd strony po tym kroku (KupAuto.php)
Krok 25: Baner: kolory, wyśrodkowanie, odstępy liter i słów
ok. 2 min
Polecenie z arkusza
Dla banera: kolor tła Crimson, biały kolor czcionki, wyrównanie tekstu do środka, odległości pomiędzy literami 5 px, odległości pomiędzy słowami 30 px, marginesy wewnętrzne 10 px
Odległość między literami to letter-spacing, między słowami - word-spacing; stąd szeroki, rozstrzelony napis z obrazu 2. Marginesy wewnętrzne to padding. Kolory i wyśrodkowanie liczą się do kryteriów razem ze stopką i nagłówkami h4, więc punkty za nie przyjdą w kolejnych regułach.
Krok 26: Pierwszy blok główny: tło, wysokość, marginesy, ramka
Kryteria: ,
R.4.7 Ustawiono marginesy wewnętrzne (padding) 10px dla banera i pierwszego bloku głównego oraz marginesy zewnętrzne (margin) górny i dolny 10px, lewy i prawy 50px dla pierwszego bloku głównego
R.4.9 Ustawiono obramowanie dla pierwszego bloku głównego: 1px solid Crimson
ok. 2 min
Polecenie z arkusza
Dla pierwszego bloku głównego: kolor tła MistyRose, wysokość 300 px, marginesy wewnętrzne 10 px, zewnętrzne górny i dolny 10 px, lewy i prawy 50 px, obramowanie linią ciągłą o szerokości 1 px i kolorze Crimson
Selektor #day trafia tylko w pierwszą sekcję. Skrót margin: 10px 50px ma dwie wartości: pierwsza to góra i dół, druga - lewa i prawa strona; stąd odsunięcie bloku od krawędzi okna na obrazie 2. Obramowanie 1px solid Crimson: grubość, linia ciągła, kolor.
Typowe błędy
margin: 10px 50px 10px - trzy wartości znaczą góra, boki, dół; działa, ale łatwo pomylić z margin: 10px 50px 10px 50px. Dwie wartości są krótsze i jednoznaczne.
Krok 27: Zdjęcie oferty dnia: po lewej, na całą wysokość
Kryteria: ,
R.4.4 Ustawiono wysokość pierwszego bloku głównego 300px oraz 100% jedynie dla obrazu z pierwszego bloku głównego
R.3.3 W głównym bloku pierwszym obraz wyświetla się po lewej stronie tekstu
ok. 2 min
Polecenie z arkusza
Dla obrazu jedynie z pierwszego bloku głównego: oblewanie tekstem po prawej stronie (obraz jest po lewej stronie) wysokość 100%
Selektor potomka #day img dotyczy tylko obrazów w pierwszej sekcji - zdjęcia ofert w pozostałych blokach go nie dostaną. float: left przesuwa obraz do lewej, a tekst (nagłówki i akapit) opływa go z prawej strony. height: 100% liczy się od wysokości bloku, czyli 300 px - zdjęcie wypełni blok od góry do dołu, jak na obrazie 2. Efekt pojawi się, gdy Skrypt 1 wypisze zdjęcie.
Typowe błędy
Samo img { height: 100% } rozciągnęłoby także zdjęcia w blokach ofert do wysokości bloku 450 px.
R.4.8 Ustawiono styl bloków z ofertami w drugim i trzecim bloku głównym: kolor tła Snow, wysokość 450 px, szerokość 21%, marginesy zewnętrzne 1%, wyrównanie tekstu do środka, obramowanie linią ciągłą o szerokości 1 px i kolorze Crimson (np. za pomocą klasy, id jest błędem)
ok. 2 min
Polecenie z arkusza
Dla bloków z ofertami generowanych skryptem w drugim i trzecim bloku głównym: kolor tła Snow, wysokość 450 px, szerokość 21%, marginesy zewnętrzne 1%, wyrównanie tekstu do środka, obramowanie linią ciągłą o szerokości 1 px i kolorze Crimson
Bloków ofert jest wiele (cztery w drugiej sekcji, kilka w trzeciej), więc styl dostaje klasa.offer - identyfikator musi być na stronie jedyny (klucz przy R.4.8: „id jest błędem”). Skrypty 2 i 4 będą wypisywać <div class="offer">. Rachunek: 21% szerokości plus po 1% marginesu z każdej strony to 23% na blok, cztery bloki zajmują 92% wiersza.
Selektor znacznika img, jak każe uwaga arkusza. max-width: 100% nie powiększa obrazu - tylko nie pozwala mu wyjść poza blok, w którym stoi. Zdjęcia w blokach ofert (21% szerokości strony) zmniejszą się do szerokości bloku.
R.4.5 Ustawiono cechy tekstu banera: odległości pomiędzy literami (letter-spacing) 5px, odległości pomiędzy słowami (word-spacing) 30px oraz rozmiar czcionki nagłówka czwartego stopnia 180%
R.4.6 Ustawiono wyrównanie tekstu do środka dla banera i nagłówka czwartego stopnia
ok. 1 min
Polecenie z arkusza
Dla selektora nagłówka czwartego stopnia: rozmiar czcionki 180%, wyrównanie tekstu do środka, kolor czcionki Crimson
Znowu selektor znacznika (h4), nie klasa - uwaga arkusza i klucza przy R.4.3 i R.4.10. Nagłówki <h4> wypiszą skrypty: model i cena w ofercie dnia i w każdym bloku oferty. Ta reguła zamyka kryteria tekstu: wyśrodkowanie banera i h4 (R.4.6) oraz odstępy liter i słów z rozmiarem 180% (R.4.5).
R.4.3 Ustawiono biały kolor czcionki dla banera, stopki i odnośnika oraz Crimson dla selektora h4
ok. 1 min
Polecenie z arkusza
Dla odnośnika: biały kolor czcionki
Bez tej reguły odnośnik w stopce byłby domyślnie niebieski (a po kliknięciu fioletowy) na tle Crimson - prawie nieczytelny. Biały kolor odnośnika zamyka R.4.3: biel banera, stopki i odnośnika oraz Crimson nagłówków h4.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu - nie należy brać pod uwagę bloków z ofertami (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid)
ok. 1 min
Polecenie z arkusza
Podział strony na bloki: baner, trzy bloki główne umiejscowione jeden pod drugim, na dole blok stopki. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2
Tu nie trzeba dopisywać żadnej reguły: header, section i footer są elementami blokowymi, więc same stają jeden pod drugim i zajmują całą szerokość - dokładnie układ z obrazu 2. Jedyny element wyjęty z normalnego układu to zdjęcie z float: left, a ono siedzi w bloku o stałej wysokości 300 px, więc nie wystaje pod drugi blok. Gdyby blok nie miał wysokości, trzeba by zamknąć opływanie (overflow: auto albo clear: both), inaczej nagłówek „Oferty Wyróżnione” stanąłby obok zdjęcia.
Typowe błędy
float: left dla całych sekcji ustawiłby trzy bloki główne obok siebie zamiast jeden pod drugim.
Każdy zwrócony wiersz jest wyświetlony w osobnym bloku, co razem daje cztery bloki. Bloki są wyświetlone obok siebie w jednej linii.
<div> domyślnie zajmuje cały wiersz, więc bloki ofert stałyby jeden pod drugim. display: inline-block zostawia im szerokość i wysokość z poprzedniej reguły, ale ustawia je w linii jak słowa w tekście - cztery bloki po 23% mieszczą się w jednym wierszu, a piąty (w wynikach wyszukiwania) przejdzie do następnego, jak na obrazie 3. vertical-align: top wyrównuje bloki do górnej krawędzi. Tej właściwości arkusz nie wymienia, ale bez niej polecenie „obok siebie” nie byłoby spełnione; float: left też by zadziałał, tylko trzeba by potem zamknąć opływanie przed stopką.
Kroki 35-49 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 35: Połączenie z bazą i zamknięcie na końcu
Kryteria: ,
R.5.1 Skrypt zawiera instrukcje połączenia z serwerem bazy danych i wyboru bazy kupauto
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie
ok. 2 min
Polecenie z arkusza
Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie kupauto
Pierwszy skrypt na stronie stoi w pierwszym bloku głównym, więc tam otwiera się połączenie: mysqli_connect z czterema argumentami łączy się z serwerem i od razu wybiera bazę. Uchwyt w zmiennej $connection posłuży wszystkim czterem skryptom. Ostatni blok PHP, pod formularzem w trzecim bloku, na razie tylko zamyka połączenie (polecenie z końca listy skryptów: „Na końcu jest zamykane połączenie z serwerem”) - Skrypt 4 stanie nad tą linią. Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
R.5.3 Skrypt 1 zawiera instrukcje wysyłające do bazy danych zapytanie 2 lub skrypt 2: zapytanie 3 lub skrypt 3: zapytanie 1
ok. 2 min
Polecenie z arkusza
Skrypt 1 wysyła do bazy danych zapytanie 2
Zapytanie 2 w zmiennej $query, mysqli_query wysyła je do bazy. Wynik ma dokładnie jeden wiersz, więc pętla nie jest potrzebna: jedno wywołanie mysqli_fetch_row oddaje go jako tablicę numerowaną od zera w kolejności pól z SELECT - $car[0] to model, [1] rocznik, [2] przebieg, [3] paliwo, [4] cena, [5] zdjęcie. Na stronie jeszcze nic nie widać.
Obraz, którego źródłem jest pole zdjecie, a tekstem alternatywnym „oferta dnia”
Źródło obrazu to nazwa pliku z bazy (ToyotaYaris.jpg) - plik leży obok strony, więc sama nazwa wystarcza. Cudzysłowy atrybutów wewnątrz napisu PHP w cudzysłowach poprzedza się ukośnikiem (\"). W podglądzie widać już przeskalowane zdjęcie z lewej strony bloku, na całą jego wysokość.
Nagłówek czwartego stopnia o treści „Oferta Dnia: Toyota ”, następnie pole model
Słowo „Toyota” jest częścią stałego tekstu, bo zapytanie 2 nie pobiera nazwy marki. PHP wstawia wartość zmiennej $car[0] w miejsce zapisu w napisie w cudzysłowach. Nagłówek staje z prawej strony zdjęcia - to działa opływanie z float: left.
Krok 39: Skrypt 1: akapit z rocznikiem, przebiegiem i paliwem
ok. 1 min
Polecenie z arkusza
Paragraf o treści „Rocznik: <rocznik>, przebieg: <przebieg>, rodzaj paliwa: <paliwo>”, gdzie pola w nawiasach <> są pobrane z bazy danych
Trzy wartości w jednym napisie, przecinki i dwukropki jak w arkuszu. Podgląd: „Rocznik: 2022, przebieg: 0, rodzaj paliwa: Benzyna” - zgodnie z obrazem 2.
Skrypt 2 stoi w drugiej sekcji, pod nagłówkiem „Oferty Wyróżnione” - to, co wypisze, pojawi się właśnie tam. Połączenie $connection z pierwszego bloku nadal jest otwarte, a zmienne $query i $result używa się ponownie, bo oferta dnia jest już wypisana.
R.3.2 W głównym bloku drugim lub trzecim każda oferta jest umieszczona w osobnym bloku, bloki są wyświetlone obok siebie (w skrypcie lub HTML), dopuszcza się że bloki są puste
ok. 3 min
Polecenie z arkusza
Każdy zwrócony wiersz jest wyświetlony w osobnym bloku, co razem daje cztery bloki. Bloki są wyświetlone obok siebie w jednej linii. W każdym bloku znajduje się obraz, którego nazwą pliku źródłowego jest pole zdjecie, a tekstem alternatywnym pole model
Pętla while pobiera kolejne wiersze; po czwartym mysqli_fetch_row zwraca null i pętla się kończy. Każdy wiersz to osobny <div class="offer"> - klasa z arkusza stylów daje mu tło Snow, ramkę i szerokość 21%, a inline-block ustawia cztery bloki w jednej linii. Kolejność pól z zapytania 3: $car[0] marka, [1] model, [2] rocznik, [3] cena, [4] zdjęcie - stąd src z [4] i alt z [1].
Nagłówek czwartego stopnia z nazwą marki i modelem, pobranymi z bazy
Marka i model rozdzielone spacją: „Audi A8 TDI QUattro”, „Audi A8”, „Opel Astra”, „Opel Corsa”. Marka pochodzi z tabeli marki - to dzięki złączeniu w zapytaniu 3.
R.5.6 Skrypt 2 wyświetla w drugim bloku głównym dane zwrócone z bazy danych dotyczące czterech samochodów: zdjęcie, markę, model, rocznik oraz cenę
R.2.7 W pierwszym i drugim bloku głównym umieszczono przynajmniej dla jednej oferty nazwę i model samochodu oraz cenę w nagłówku h4 oraz inne dane w paragrafie (w skrypcie lub HTML)
R.2.8 W pierwszym i drugim bloku głównym umieszczono przynajmniej jedno zdjęcie z tekstem alternatywnym (w skrypcie lub HTML)
ok. 2 min
Polecenie z arkusza
Paragraf o treści „Rocznik: ”, następnie pole rocznik. Nagłówek czwartego stopnia o treści „Cena: ” następnie pole cena
Akapit z rocznikiem i drugi <h4> z ceną. Drugi blok wygląda jak na obrazie 2: cztery bloki ofert w jednej linii. Ten krok zamyka też kryteria treści pierwszego i drugiego bloku: nazwa, model i cena w <h4>, inne dane w akapicie (R.2.7) oraz zdjęcia z tekstem alternatywnym (R.2.8).
R.5.7 Skrypt 3 dodaje do listy rozwijalnej jako elementy <option> nazwy marek samochodów zwrócone zapytaniem
ok. 2 min
Polecenie z arkusza
Zwrócone zapytaniem nazwy marek samochodów są wyświetlone jako elementy listy rozwijalnej
Każda marka to jeden <option>. Bez atrybutu value przeglądarka wysyła treść elementu, czyli nazwę marki - dokładnie to, czego potrzebuje warunek w Skrypcie 4. Na liście jest 9 marek, pierwsza to Audi (jak na obrazie 2).
R.5.8 Skrypt 4 jest wykonywany tylko, gdy wybrano opcję z listy rozwijalnej
ok. 2 min
Polecenie z arkusza
Skrypt 4: po zatwierdzeniu formularza tylko, gdy użytkownik wybrał element listy rozwijalnej wysyła do bazy danych zapytanie
Przy pierwszym wejściu na stronę formularza nikt nie wysłał i w $_POST nie ma klucza brand. isset sprawdza, czy marka przyszła - dopiero wtedy skrypt pyta bazę. Zamknięcie połączenia stoi pod blokiem if, poza nim: wykona się zawsze, jako ostatnia operacja na bazie. Od tego kroku podgląd pokazuje stronę po wybraniu „Opel” i kliknięciu „Wyszukaj”.
R.5.4 Skrypt 4 zawiera instrukcje wysyłające do bazy danych zmodyfikowane zapytanie 4, w ten sposób, że jest w nim sprawdzana nazwa marki wybrana w liście
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 4, w ten sposób, że jest w nim sprawdzana nazwa marki wybrana w liście
W warunku zapytania 4 zamiast 'Audi' stoi zmienna $selectedBrand z formularza - apostrofy zostają, bo w SQL to nadal tekst. Druga zmiana: na początek listy pól trafia nazwa. Zapytanie 4 pobiera tylko model, cenę i zdjęcie, a polecenie do Skryptu 4 każe wypisać w nagłówku markę i model „pobrane z bazy danych” (klucz R.5.9 też mówi o nazwie marki zwróconej z bazy). Złączenie z tabelą marki i tak jest w zapytaniu, więc dodatkowe pole nic nie kosztuje.
KupAuto.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Komis aut</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1><em>KupAuto!</em> Internetowy Komis Samochodowy</h1> </header> <sectionid="day"><?php$connection = mysqli_connect("localhost", "root", "", "kupauto");$query = "SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id = 10;";$result = mysqli_query($connection, $query);$car = mysqli_fetch_row($result);echo"<img src=\"$car[5]\" alt=\"oferta dnia\">";echo"<h4>Oferta Dnia: Toyota $car[0]</h4>";echo"<p>Rocznik: $car[1], przebieg: $car[2], rodzaj paliwa: $car[3]</p>";echo"<h4>Cena: $car[4]</h4>";?> </section> <sectionid="featured"> <h2>Oferty Wyróżnione</h2><?php$query = "SELECT nazwa, model, rocznik, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE wyrozniony = 1 LIMIT 4;";$result = mysqli_query($connection, $query);while ($car = mysqli_fetch_row($result)) {echo"<div class=\"offer\">";echo"<img src=\"$car[4]\" alt=\"$car[1]\">";echo"<h4>$car[0]$car[1]</h4>";echo"<p>Rocznik: $car[2]</p>";echo"<h4>Cena: $car[3]</h4>";echo"</div>"; }?> </section> <sectionid="search"> <h2>Wybierz markę</h2> <formmethod="post"> <selectname="brand"><?php$query = "SELECT nazwa FROM marki;";$result = mysqli_query($connection, $query);while ($brand = mysqli_fetch_row($result)) {echo"<option>$brand[0]</option>"; }?> </select> <buttontype="submit">Wyszukaj</button> </form><?phpif (isset($_POST["brand"])) {$selectedBrand = $_POST["brand"];$query = "SELECT nazwa, model, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE nazwa = '$selectedBrand';";$result = mysqli_query($connection, $query); } mysqli_close($connection);?> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> <p><ahref="http://firmy.pl/komis">Znajdź nas także</a></p> </footer></body></html>
Krok 49: Skrypt 4: bloki samochodów wybranej marki
Kryteria: ,
R.5.9 Skrypt 4 wyświetla w trzecim bloku głównym dane zwrócone z bazy danych dotyczące samochodów wybranej marki: zdjęcie, nazwę marki, model i cenę
R.5.10 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych lub funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania
ok. 3 min
Polecenie z arkusza
Każdy zwrócony wiersz jest wyświetlony w osobnym bloku. Bloki są wyświetlone obok siebie. W każdym bloku znajduje się: obraz, którego nazwą pliku źródłowego jest pole zdjecie, a tekstem alternatywnym pole model, nagłówek czwartego stopnia z nazwą marki i modelem, pobranymi z bazy danych, nagłówek czwartego stopnia o treści „Cena: ” następnie pole cena
Ta sama pętla i ta sama klasa offer co w Skrypcie 2, ale bez rocznika i z innym układem pól: $car[0] marka, [1] model, [2] cena, [3] zdjęcie. Podgląd po wybraniu „Opel”: pięć bloków - Astra 11500, Corsa 21900, Vectra 29900, Corsa 23900 w pierwszym wierszu i Corsa 20000 w drugim, jak na obrazie 3. Nazwy zmiennych mówią, co przechowują ($connection, $query, $result, $car, $brand, $selectedBrand) - to kryterium R.5.10.
Kroki 50-52 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 50: Skrypt 4: zapytanie przygotowane
ok. 4 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 4, w ten sposób, że jest w nim sprawdzana nazwa marki wybrana w liście
Wersja z egzaminu sprawdzona dwoma wysłaniami z pominięciem listy (żądanie POST można zbudować samemu): wartość ' OR '1'='1 zamienia warunek w nazwa = '' OR '1'='1' i strona pokazuje 17 samochodów - całą bazę, a marka z apostrofem (Alfa'Romeo) urywa stronę błędem „Uncaught mysqli_sql_exception”. Poprawka: zapytanie przygotowane - w SQL zostaje znak ?, a mysqli_stmt_bind_param z typem "s" (tekst) przekazuje markę osobno, więc baza nigdy nie potraktuje jej jak kodu. mysqli_stmt_get_result oddaje zwykły wynik, więc pętla zostaje bez zmian. Stare linie zostają w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
KupAuto.phpPHPzmienione: 6 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Komis aut</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1><em>KupAuto!</em> Internetowy Komis Samochodowy</h1> </header> <sectionid="day"><?php$connection = mysqli_connect("localhost", "root", "", "kupauto");$query = "SELECT model, rocznik, przebieg, paliwo, cena, zdjecie FROM samochody WHERE id = 10;";$result = mysqli_query($connection, $query);$car = mysqli_fetch_row($result);echo"<img src=\"$car[5]\" alt=\"oferta dnia\">";echo"<h4>Oferta Dnia: Toyota $car[0]</h4>";echo"<p>Rocznik: $car[1], przebieg: $car[2], rodzaj paliwa: $car[3]</p>";echo"<h4>Cena: $car[4]</h4>";?> </section> <sectionid="featured"> <h2>Oferty Wyróżnione</h2><?php$query = "SELECT nazwa, model, rocznik, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE wyrozniony = 1 LIMIT 4;";$result = mysqli_query($connection, $query);while ($car = mysqli_fetch_row($result)) {echo"<div class=\"offer\">";echo"<img src=\"$car[4]\" alt=\"$car[1]\">";echo"<h4>$car[0]$car[1]</h4>";echo"<p>Rocznik: $car[2]</p>";echo"<h4>Cena: $car[3]</h4>";echo"</div>"; }?> </section> <sectionid="search"> <h2>Wybierz markę</h2> <formmethod="post"> <selectname="brand"><?php$query = "SELECT nazwa FROM marki;";$result = mysqli_query($connection, $query);while ($brand = mysqli_fetch_row($result)) {echo"<option>$brand[0]</option>"; }?> </select> <buttontype="submit">Wyszukaj</button> </form><?phpif (isset($_POST["brand"])) {$selectedBrand = $_POST["brand"];$statement = mysqli_prepare($connection, "SELECT nazwa, model, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE nazwa = ?"); mysqli_stmt_bind_param($statement, "s", $selectedBrand); mysqli_stmt_execute($statement);$result = mysqli_stmt_get_result($statement);// $query = "SELECT nazwa, model, cena, zdjecie FROM samochody JOIN marki ON samochody.marki_id = marki.id WHERE nazwa = '$selectedBrand';";// $result = mysqli_query($connection, $query);while ($car = mysqli_fetch_row($result)) {echo"<div class=\"offer\">";echo"<img src=\"$car[3]\" alt=\"$car[1]\">";echo"<h4>$car[0]$car[1]</h4>";echo"<h4>Cena: $car[2]</h4>";echo"</div>"; } } mysqli_close($connection);?> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> <p><ahref="http://firmy.pl/komis">Znajdź nas także</a></p> </footer></body></html>
Zwrócone zapytaniem nazwy marek samochodów są wyświetlone jako elementy listy rozwijalnej
Po kliknięciu „Wyszukaj” strona ładuje się od nowa i lista wraca do pierwszej marki - pod listą widać Ople, a w liście stoi „Audi”. Obraz 3 pokazuje w liście „Opel”, czyli stan, w którym lista pamięta wybór. Wystarczy w Skrypcie 3 porównać każdą markę z tą, która przyszła w $_POST (operator ?? daje pusty napis przy pierwszym wejściu) i dopisać jej atrybut selected. Nazwa marki przechodzi przez htmlspecialchars, żeby znak < albo " w bazie nie rozbił znacznika. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Krok 52: Jedna funkcja zamiast dwóch kopii bloku oferty
ok. 4 min
Polecenie z arkusza
Należy stosować znaczące nazewnictwo wszystkich zmiennych lub funkcji
Skrypty 2 i 4 wypisują prawie ten sam blok oferty - różni się tylko akapit z rocznikiem. Przy każdej zmianie wyglądu oferty trzeba by poprawiać dwa miejsca. Funkcja showOffer($car) na początku pierwszego bloku PHP wypisuje blok raz; akapit z rocznikiem pojawia się tylko wtedy, gdy wiersz go zawiera (zapytanie 3 ma rocznik, zapytanie Skryptu 4 - nie). mysqli_fetch_assoc oddaje wiersz z kluczami takimi jak nazwy kolumn, więc ta sama funkcja działa dla obu zapytań, choć pola stoją w nich w innej kolejności. Dane z bazy przechodzą przez htmlspecialchars. Sprawdzone: bloki ofert w podglądzie są identyczne z wersją egzaminacyjną. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Krok 53 · po tym etapie masz 41 z 41 kryteriów (pkt)
Krok 53: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wpisuje się nazwę przeglądarki, w której sprawdzana była strona.
W folderze z numerem zdającego: AudiA3.jpg, AudiA8.jpg, import.png, KupAuto.php, kw1.jpg - kw4.jpg, kwerendy.txt, OpelAstra.jpg, OpelCorsa.jpg, OpelVectra.jpg, przeglądarka.txt, styl.css, ToyotaCorolla.jpg, ToyotaRav.jpg, ToyotaYaris.jpg (przeskalowany). Płytę trzeba nagrać, sprawdzić jej odczyt i opisać numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.