INF.03-07-24.06-SGCzerwiec 2024 · 49 kroków · ok. 85 min · 37 kryteriów z klucza
Rozwiązanie krok po kroku: Witryna ważenia pojazdów (Wersja podstawowa)
Testowa aplikacja miejskiego ważenia pojazdów: baza wazenietirow (lokalizacje wag i pomiary nacisku na oś) i cztery operacje - UPDATE z aktualną datą i czasem, prosty wybór ulic, INSERT z losową wagą (FLOOR i RAND) oraz złączenie JOIN z warunkiem „powyżej 5 t” - potem dwie grafiki (cyfra na znaku drogowym i odbite zdjęcie ciężarówki) i strona wazenie.php: dwa banery obok siebie, trzy bloki i stopka, a w nich trzy skrypty PHP: lista ulic, tabela alertów i testowy pomiar dopisywany przy każdym odświeżeniu strony co 10 sekund.
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), a na końcu przechodzą do wersji z prawdziwych projektów: nagłówek odświeżania na początku pliku (sprawdzone: w wersji egzaminacyjnej odświeżanie po pewnym czasie przestaje działać) oraz mysqli_fetch_assoc z htmlspecialchars.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: bloki na siatce CSS, kolory w zmiennych i PHP na PDO z danymi pobranymi przed HTML-em, z nagłówkiem odświeżania przed treścią strony - obie wersje są zgodne z kluczem.
Baza i grafiki pochodzą z prawdziwego archiwum pliki7 (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 po zapytaniu 1 (dlatego część pomiarów ma datę i godzinę wykonania zapytania 1 - tu 2026-10-04, 11:17:40 - tak jak na obrazie 2 część ma godzinę 10:41:36).
Jak liczą się punkty. Klucz ma 37 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 28 punktów - można stracić 9 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 37 kryteriów (pkt)
Krok 1: Baza danych wazenietirow
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie wazenietirow, z zestawem polskich znaków (np. utf8_unicode_ci)
Najpierw archiwum pliki7.zip z pulpitu (hasło %WAg@Poj@zdoW - procent na początku, dwie małpy zamiast „a”) rozpakowuje się do folderu nazwanego numerem zdającego. W phpMyAdmin: Nowa, nazwa wazenietirow (jedno słowo, bez polskich liter), porównywanie utf8_unicode_ci.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie wazenietirow - skrypty łączą się z bazą po nazwie (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 wazenietirow, potem Import → baza.sql → Wykonaj. Powstają dwie tabele z obrazu 1: lokalizacje (6 ulic, na których stoją wagi) i wagi (22 pomiary: identyfikator lokalizacji, nacisk na oś w tonach, numer rejestracyjny, dzień i czas). Relacja 1..n: jedna lokalizacja, wiele pomiarów.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych wazenietirow 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. Zrzuty zapytań idą później 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: aktualna data i czas dla lokalizacji 2-4
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 aktualizujące tabelę wagi . Rekordy, w których pole lokalizacje_id jest równe 2, 3, 4 mają zmienione datę i czas na wartości aktualne. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE wagi SET dzien=CURRENT_DATE,czas=CURRENT_TIME WHERE lokalizacje_id BETWEEN 2 AND 4; (dowolne funkcje wstawiające aktualną datę/czas, lub także z pustymi nawiasami; dowolny warunek sprawdzający przedział 2..4) oraz wynik działania udokumentowano zrzutem, na którym jest widoczny komunikat o poprawnie wykonanym zapytaniu lub wiersze z lokalizacje_id równym 2, 3, 4 mają datę i czas zgodny z terminem egzaminu
ok. 3 min
Polecenie z arkusza
Zapytanie 1: aktualizujące tabelę wagi. Rekordy, w których pole lokalizacje_id jest równe: 2, 3, 4 mają zmienione datę i czas na wartości aktualne. Zapytanie ma charakter uniwersalny, zawsze zmienia wartość na aktualną datę / czas
UPDATE wagi - zmiana danych w tabeli pomiarów,
SET dzien = CURDATE(), czas = CURTIME() - dwie kolumny naraz, rozdzielone przecinkiem; funkcje z tabeli 2 arkusza zwracają bieżącą datę i bieżący czas w chwili wykonania - to jest „charakter uniwersalny”,
WHERE lokalizacje_id BETWEEN 2 AND 4 - przedział domknięty: 2, 3 i 4 (klucz uznaje każdy warunek na ten przedział, np. IN (2, 3, 4)).
Zmienionych rekordów: 13 - wszystkie dostały datę 2026-10-04 i ten sam czas. Zapytania zapisuje się w kwerendy.txt, zrzut z komunikatem albo ze zmienionymi wierszami jako kw1.jpg.
Typowe błędy
Data wpisana ręcznie ('2024-06-20') nie jest uniwersalna - jutro zapytanie wstawiłoby wczorajszy dzień. Bez WHERE zmieniłyby się wszystkie 22 pomiary.
kwerendy.txtTekstnowy plik
-- Zapytanie 1UPDATE wagi SET dzien = CURDATE(), czas = CURTIME() WHERE lokalizacje_id BETWEEN 2 AND 4;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: ulice
Kryteria:
R.1.4 Wykonano zapytanie 2 wybierające jedynie ulicę z tabeli lokalizacje . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT ulica FROM lokalizacje; oraz wynik działania udokumentowano zrzutem, na którym są widoczne jedynie dane: Ślężna, Tyska, Średzka, Wilanowska, Żmigrodzka, Karkonowska
ok. 1 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie ulicę z tabeli lokalizacje
SELECT ulica - jedno pole, bez identyfikatora,
FROM lokalizacje.
Wynik: Ślężna, Tyska, Średzka, Wilanowska, Żmigrodzka, Karkonowska - jak w kluczu. Zrzut: kw2.jpg. To zapytanie wypełni listę w bloku lewym (Skrypt 1).
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1UPDATE wagi SET dzien = CURDATE(), czas = CURTIME() WHERE lokalizacje_id BETWEEN 2 AND 4;-- Zapytanie 2SELECT ulica FROM lokalizacje;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: pomiar z losową wagą
Kryteria:
R.1.5 Wykonano zapytanie 3 wstawiające rekord do tabeli wagi z danymi: lokalizacje_id: 5, waga: liczba pseudolosowa z przedziału 1..10, rejestracja: DW12345, aktualna data i czas. Klucz główny nadawany automatycznie. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO `wagi`(`lokalizacje_id`, `waga`, `rejestracja`, `dzien`, `czas`) VALUES ('5', FLOOR(1+RAND()*10), 'DW12345', CURRENT_DATE, CURRENT_TIME); (dowolny sposób liczenia liczby pseudolosowej z przedziału 1..10; dowolne funkcje wstawiające aktualny czas/datę, też z pustymi nawiasami) oraz wynik działania udokumentowano zrzutem, na którym jest widoczny komunikat o poprawnie wykonanym zapytaniu lub wstawiony do tabeli wiersz
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wstawiające do tabeli wagi rekord z danymi: lokalizacje_id: 5, waga: losowa liczba z przedziału 1..10 (wygenerowana funkcją), rejestracja: DW12345, aktualna data (do pola dzien) i aktualny czas (do pola czas). Klucz główny nadawany automatycznie. Zapytanie ma charakter uniwersalny, zawsze wstawia wartość aktualnej daty i czasu
INSERT INTO wagi (lokalizacje_id, waga, rejestracja, dzien, czas) - pięć kolumn; id pominięte, więc baza nada je sama,
FLOOR(1 + RAND() * 10) - wzór z pomocy do RAND w arkuszu: RAND() daje liczbę od 0 do 1 (bez 1), po pomnożeniu przez 10 - od 0 do 9,99..., po dodaniu 1 - od 1 do 10,99..., a FLOOR obcina część ułamkową. Wychodzą liczby całkowite od 1 do 10, każda z tym samym prawdopodobieństwem,
'DW12345', CURDATE(), CURTIME() - numer rejestracyjny jako tekst i bieżąca data oraz czas.
Wstawiony pomiar dostał identyfikator 23 i wagę 5 - przy każdym wykonaniu będzie inna. Zrzut: kw3.jpg.
Typowe błędy
ROUND(RAND() * 10) daje także 0 (i rzadziej 10 niż pozostałe liczby) - przedział z arkusza to 1..10.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1UPDATE wagi SET dzien = CURDATE(), czas = CURTIME() WHERE lokalizacje_id BETWEEN 2 AND 4;-- Zapytanie 2SELECT ulica FROM lokalizacje;-- Zapytanie 3INSERT INTO wagi (lokalizacje_id, waga, rejestracja, dzien, czas) VALUES (5, FLOOR(1 + RAND() * 10), 'DW12345', CURDATE(), CURTIME());
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: pomiary powyżej 5 t z nazwą ulicy
Kryteria:
R.1.6 Wykonano zapytanie 4 wybierające jedynie pola rejestracja, waga, dzien, czas z tabeli wagi i odpowiadające mu pole ulica z tabeli lokalizacje dla pojazdów, których waga na oś przekracza 5 t. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT rejestracja, ulica, waga, dzien, czas FROM wagi JOIN lokalizacje ON wagi.lokalizacje_id = lokalizacje.id WHERE waga > 5; (możliwe również INNER JOIN lub bez JOIN i porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym widoczne są rekordy z wagą powyżej 5; jedynie pola: rejestracja, waga, dzien, czas, ulica. Liczba wierszy dowolna, w zależności od wykonania zapytań 1 i 3
ok. 3 min
Polecenie z arkusza
Zapytanie 4: wybierające jedynie pola rejestracja, waga, dzien, czas z tabeli wagi i odpowiadające mu pole ulica z tabeli lokalizacje dla pojazdów, których waga na oś przekracza 5 t. Należy posłużyć się relacją
SELECT rejestracja, ulica, waga, dzien, czas - kolejność pól jak w tabeli na obrazie 3 (arkusz wymaga jej przy Skrypcie 2), więc to samo zapytanie od razu nadaje się do skryptu,
FROM wagi JOIN lokalizacje ON wagi.lokalizacje_id = lokalizacje.id - relacja: do pomiaru dołączana jest jego lokalizacja z nazwą ulicy,
WHERE waga > 5 - „przekracza 5 t”, czyli ostro większe; pomiary z wagą równą 5 (DWTKU32, DW54874) się nie łapią.
Wynik: 9 wierszy - dziewięć pomiarów z obrazu 2 (od DW54U32 do DW54N32) i ewentualnie wstawiony DW12345, jeśli wylosował więcej niż 5 (tutaj wylosował 5). Klucz dopuszcza dowolną liczbę wierszy, bo zależy ona od zapytań 1 i 3. Zrzut: kw4.jpg.
Typowe błędy
waga >= 5 dorzuca dwa pomiary z wagą dokładnie 5 t, które limitu nie przekraczają.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1UPDATE wagi SET dzien = CURDATE(), czas = CURTIME() WHERE lokalizacje_id BETWEEN 2 AND 4;-- Zapytanie 2SELECT ulica FROM lokalizacje;-- Zapytanie 3INSERT INTO wagi (lokalizacje_id, waga, rejestracja, dzien, czas) VALUES (5, FLOOR(1 + RAND() * 10), 'DW12345', CURDATE(), CURTIME());-- Zapytanie 4SELECT rejestracja, ulica, waga, dzien, czas FROM wagi JOIN lokalizacje ON wagi.lokalizacje_id = lokalizacje.id WHERE waga > 5;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-25 · po tym etapie masz 16 z 37 kryteriów (pkt)
Krok 8: obraz1.png: 5T zamiast 8T
Kryteria:
R.2.1 Plik obraz1.png zmodyfikowano w ten sposób że przy samochodzie widnieje tonaż 5T. Napis 8T nie jest widoczny
ok. 4 min
Polecenie z arkusza
Plik obraz1.png, wypakowany z archiwum, należy zmodyfikować w ten sposób, że zamiast informacji 8T na przedstawionym znaku powinna być zapisana wartość 5T. Zmodyfikowany obraz jest widoczny na obrazie 2.
W GIMP-ie: zaznaczenie prostokątne wokół cyfry 8, wypełnienie bielą (Edycja → Wypełnij kolorem tła przy białym tle), potem narzędzie Tekst: cyfra 5 czarna, krój bezszeryfowy o wąskich znakach, rozmiar dobrany tak, by cyfra miała wysokość litery T obok (ok. 21 px). Tutaj użyty jest krój Bahnschrift, wzorowany na kroju DIN ze znaków drogowych. Litera T zostaje bez zmian. Zapis pod tą samą nazwą (Plik → Nadpisz obraz1.png), z przezroczystością wokół znaku. Podgląd pokazuje znak przed i po, powiększony trzy razy.
Typowe błędy
Cyfra 5 dopisana obok ósemki albo na niej bez zamalowania - klucz wymaga, żeby napis 8T nie był widoczny.
Podgląd strony po tym kroku
Krok 9: obraz2.jpg: odbicie i szerokość 350 px
Kryteria:
R.2.2 Plik obraz2.jpg odbito wzdłuż osi pionowej oraz przeskalowano z zachowaniem proporcji do szerokości 350 px. Odpowiadająca temu wysokość wynosi 285 px (± 5 px)
ok. 3 min
Polecenie z arkusza
Plik obraz2.jpg odbić wzdłuż osi pionowej oraz przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 350 px. Zmodyfikowany obraz jest widoczny na obrazie 2.
Odbicie „wzdłuż osi pionowej” zamienia lewą stronę z prawą: w GIMP-ie Obraz → Przekształć → Odbij poziomo (nazwa menu mówi o kierunku ruchu pikseli, a arkusz - o osi, wokół której obraz się obraca). Kabina ciężarówki przechodzi z prawej strony na lewą - tak jak na obrazie 2. Potem Obraz → Skaluj obraz z zamkniętym łańcuchem: szerokość 350, wysokość wychodzi 407 · 350 / 500 ≈ 285 px (klucz: 285 px ± 5).
Typowe błędy
Odbij pionowo stawia ciężarówkę kołami do góry - obraz 2 pokazuje odbicie lewo-prawo.
Podgląd strony po tym kroku
Krok 10: Plik wazenie.php w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie wazenie.php zapisanej w języku HTML5
Deklaracja <!DOCTYPE html> i szkielet z sekcjami head i body. Rozszerzenie .php, bo dojdą skrypty; na egzaminie plik leży w htdocs XAMPP-a i otwiera się go przez http://localhost/....
R.2.3 Witrynę internetową zapisano w pliku wazenie.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> - inaczej „Ślężna” i „Żmigrodzka” z bazy mogą wyjść krzakami. Z deklaracją HTML5, językiem i nazwą pliku to jedno kryterium klucza.
R.2.4 Nadano tytuł stronie: Ważenie samochodów ciężarowych
ok. 1 min
Polecenie z arkusza
Tytuł strony widoczny na karcie przeglądarki: „Ważenie samochodów ciężarowych”
<title> w <head>. Uwaga: tytuł karty mówi o samochodach ciężarowych, a nagłówek strony - o pojazdach; to dwa różne teksty.
wazenie.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Ważenie samochodów ciężarowych</title></head><body></body></html>
Podgląd strony po tym kroku (wazenie.php)
Krok 14: Podpięcie arkusza stylów
Kryteria:
R.3.3 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. Całe formatowanie ma pochodzić z tego pliku.
Typowe błędy
Klucz odbiera R.3.3 także wtedy, gdy choć jeden selektor nie trafia w blok (np. kropka zamiast #).
wazenie.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Ważenie samochodów ciężarowych</title> <linkrel="stylesheet"href="styl.css"></head><body></body></html>
Podgląd strony po tym kroku (wazenie.php)
Krok 15: Bloki: dwa banery, trzy bloki, stopka
Kryteria:
R.2.5 Układ strony zdefiniowano dzieląc ją na bloki: dwa bloki banera, blok lewy, środkowy, prawy 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: na górze dwa bloki banera, poniżej trzy bloki: lewy, środkowy i prawy, 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
Oba banery to <header> (znacznik może wystąpić kilka razy), trzy bloki środkowe to <section>, stopka - <footer>; klucz (R.2.5) wymaga wprost header i footer. Identyfikatory po angielsku: banner1, banner2, left, middle, right - banery i bloki mają wspólne cechy (selektory znaczników), ale różne szerokości, które rozróżnią identyfikatory.
Zawartość drugiego banera: obraz1.png z tekstem alternatywnym o treści: „waga”
Znacznik <img> z plikiem przerobionym w GIMP-ie. Tekst alternatywny (alt) czytają czytniki ekranu i widać go, gdy obraz się nie wczyta. Znak ma 150 px wysokości - tyle samo co baner.
Krok 22: Blok środkowy: tabela z wierszem nagłówkowym
Kryteria:
R.2.9 Pierwszy wiersz tabeli zawiera komórki nagłówkowe o treści, kolejno: „rejestracja”, „ulica”, „waga”, „dzień”, „czas”, zastosowano znaczniki <th>
ok. 2 min
Polecenie z arkusza
Tabela o pięciu kolumnach wypełniona danymi: pierwszy wiersz zawiera komórki nagłówkowe o treści kolejno: „rejestracja”, „ulica”, „waga”, „dzień”, „czas”, kolejne wiersze wypełnione są przez skrypt 2 zgodnie z obrazem 2
Pierwszy wiersz <tr> z pięcioma komórkami nagłówkowymi <th> - małymi literami, jak w arkuszu („dzień” z polską literą, choć kolumna w bazie to dzien). Wiersze z danymi dopisze Skrypt 2 przed </table>.
R.2.10 W drugim banerze umieszczono obraz z limitem wagi z tekstem alternatywnym "waga" oraz w bloku prawym umieszczono obraz z ciężarówką z tekstem alternatywnym "tir"
ok. 1 min
Polecenie z arkusza
Zawartość bloku prawego: obraz2.jpg z tekstem alternatywnym o treści: „tir”
Obraz dostaje identyfikator truck - arkusz stylów ma dać szerokość i marginesy „jedynie dla obrazu o nazwie obraz2.jpg”, a znak w banerze to też <img>. Ten krok zamyka R.2.10: znak z tekstem „waga” i ciężarówka z tekstem „tir”.
R.2.6 W pierwszym banerze zapisano nagłówek h1: "Ważenie pojazdów we Wrocławiu" , w bloku lewym h2: "Lokalizacje wag" i "Kontakt" , w bloku środkowym h2: "Alerty" oraz w stopce paragraf z numerem zdającego
ok. 1 min
Polecenie z arkusza
Zawartość stopki: akapit (paragraf) o treści: „Stronę wykonał: ”, następnie numer zdającego.
Akapit w <footer>. Na egzaminie po dwukropku wpisuje się swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Z tym krokiem są wszystkie nagłówki i akapit z R.2.6.
Domyślne formatowanie wszystkich selektorów: krój czcionki Tahoma
Selektor uniwersalny *.
styl.cssCSSnowy plik
* {font-family: Tahoma;}
Podgląd strony po tym kroku (wazenie.php)
Krok 27: Banery: wspólne cechy
ok. 1 min
Polecenie z arkusza
Wspólne dla obu bloków banera: kolor tła #519657, biały kolor czcionki, wyrównanie tekstu do środka, wysokość 150 px
Selektor znacznika header łapie oba banery naraz. text-align: center wyśrodkowuje także obraz w drugim banerze - <img> jest elementem liniowym, więc zachowuje się jak tekst.
Krok 31: Blok środkowy: szerokość i paski przewijania
Kryteria:
R.4.7 Ustawiono dla bloku środkowego automatyczne paski przewijania (overflow: auto lub scroll )
ok. 2 min
Polecenie z arkusza
Dodatkowo blok środkowy ma szerokość 50% oraz paski przewijania, które pojawiają się jedynie, gdy zawartość nie mieści się w bloku
overflow: auto - pasek przewijania pojawia się tylko wtedy, gdy treść jest wyższa (albo szersza) niż blok. Tutaj to realna potrzeba: Skrypt 3 co 10 sekund dopisuje pomiar, więc tabela alertów rośnie i po kilku minutach przestaje się mieścić w 450 px. overflow: scroll pokazywałby paski zawsze, także przy krótkiej tabeli.
R.4.2 Ustawiono kolor tła #519657 dla obu banerów, #E1E1E1 dla bloku lewego, środkowego i prawego oraz #80C683 dla stopki oraz biały kolor czcionki dla obu banerów
R.4.5 Ustawiono wyrównanie tekstu do środka dla obu banerów i stopki
ok. 1 min
Polecenie z arkusza
Dla stopki: kolor tła #80C683, wyrównanie tekstu do środka
Z tą regułą są wszystkie kolory z R.4.2 (tło banerów, bloków i stopki oraz biel czcionki banerów) i wyśrodkowanie tekstu banerów i stopki (R.4.5).
R.4.4 Ustawiono szerokość pierwszego banera 70%, drugiego banera 30%, bloku lewego i prawego na 25%, bloku środkowego 50% (width lub grid-template-columns lub flex ) oraz 100% szerokości jedynie dla obrazu o nazwie obraz2.jpg
ok. 2 min
Polecenie z arkusza
Jedynie dla obrazu o nazwie obraz2.jpg: szerokość 100%, marginesy wewnętrzne górny i dolny 100 px, pozostałe 0
Selektor #truck trafia tylko w zdjęcie ciężarówki. Skrót padding: 100px 0 - pierwsza wartość to góra i dół, druga to lewa i prawa strona. Dopełnienie odsuwa zdjęcie od górnej krawędzi bloku, więc ciężarówka stoi mniej więcej na środku wysokości - jak na obrazie 2. Ta reguła zamyka szerokości z R.4.4: banery 70% i 30%, bloki 25%, 50%, 25% i zdjęcie 100%.
Typowe błędy
Reguła dla selektora img objęłaby też znak w banerze - rozciągnęłaby go na całą szerokość drugiego banera.
R.4.10 Ostatni wiersz tabeli ma tło czerwone np. dla tr:nth-last-child(1)
ok. 2 min
Polecenie z arkusza
Ostatni wiersz tabeli ma tło czerwone
Pseudoklasa :last-child wybiera element, który jest ostatnim dzieckiem swojego rodzica - tu ostatni wiersz tabeli (klucz podaje równoważne tr:nth-last-child(1)). Wiersze dopisuje skrypt, więc nie da się nadać klasy „ostatniemu” w HTML-u - pseudoklasa sama znajdzie ten, który akurat jest na końcu. Kiedy Skrypt 3 doda pomiar powyżej 5 t, czerwień przejdzie na nowy wiersz (obraz 3).
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: na górze dwa bloki banera, poniżej trzy bloki: lewy, środkowy i prawy, 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
float: left dla banerów i bloków: każdy przesuwa się do lewej i staje obok poprzedniego, dopóki mieści się w wierszu. Banery mają razem 100% szerokości, więc trzeci element (blok lewy) nie zmieści się obok nich i przejdzie do nowego wiersza - tam bloki 25% + 50% + 25% znowu wypełniają całą szerokość. clear: both dla stopki każe jej stanąć pod wszystkimi pływającymi blokami; bez tego wjechałaby pod nie, na samą górę strony.
Typowe błędy
Marginesy albo obramowania bloków przy szerokościach sumujących się do 100% - prawy blok spada do następnego wiersza.
Kroki 39-46 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 39: Połączenie z bazą i zamknięcie na końcu
Kryteria: ,
R.5.1 Skrypt zawiera działające połączenie z serwerem bazy danych i wybór bazy wazenietirow
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)
ok. 2 min
Polecenie z arkusza
Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie wazenietirow. Na końcu jest zamykane połączenie z serwerem.
Pierwszy skrypt na stronie stoi w liście bloku lewego, więc tam otwiera się połączenie: mysqli_connect łączy się z serwerem i od razu wybiera bazę. Uchwyt w zmiennej $connection posłuży wszystkim trzem skryptom. Ostatni blok PHP, pod tabelą w bloku środkowym, na razie tylko zamyka połączenie - Skrypt 3 stanie nad tą linią. Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 2 lub skrypt 2 wysyła zapytanie 4 lub skrypt 3 wysyła zapytanie 3
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, a wynik czeka w $result. Skrypt stoi między <ol> a </ol> - to, co wypisze, stanie się elementami listy.
R.5.4 Skrypt 1 wyświetla zwrócone zapytaniem nazwy ulic według wzoru: ”ulica <nazwa_ulicy>”, gdzie nawiasy <> oznaczają wartość pobraną z bazy danych
R.2.7 W bloku lewym umieszczono jedną listę numerowaną z elementami, zastosowano znaczniki <ol>, <li> (listę wygenerowano skryptem lub w HTML)
ok. 2 min
Polecenie z arkusza
Zwrócone nazwy ulic są wyświetlane w elementach listy numerowanej z bloku lewego, według wzoru: ”ulica <nazwa_ulicy>”, gdzie nawiasy <> oznaczają wartość pobraną z bazy danych
Pętla while pobiera kolejne wiersze; mysqli_fetch_row oddaje wiersz jako tablicę, a $street[0] to jedyne pole - ulica. Słowo „ulica ” jest stałym tekstem przed wartością z bazy. Podgląd: „1. ulica Ślężna”, „2. ulica Tyska” i dalej - numery dopisuje sama lista <ol>.
Skrypt 2 wysyła do bazy danych zapytanie 4 (kolejność wybieranych pól w zapytaniu zgodna z obrazem 3)
Skrypt 2 stoi w tabeli, pod wierszem nagłówkowym - wiersze, które wypisze, trafią do środka <table>. Kolejność pól w zapytaniu (rejestracja, ulica, waga, dzień, czas) to kolejność kolumn tabeli, więc komórki wypisze się po prostu po kolei.
Krok 43: Skrypt 2: wiersze z numerem rejestracyjnym
ok. 2 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym wierszu tabeli z bloku środkowego
Każdy pomiar to jeden <tr>. Na razie jedna komórka, żeby sprawdzić pętlę: dziewięć numerów rejestracyjnych, ostatni (DW54N32) na czerwono - działa już reguła tr:last-child.
R.5.5 Skrypt 2 wyświetla zwrócone zapytaniem dane z każdego wybranego z bazy wiersza
R.2.8 W bloku środkowym umieszczono jedną tabelę o pięciu kolumnach, zastosowano znaczniki <table>, <tr>, <td> (tabelę wygenerowano skryptem lub w HTML)
ok. 2 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym wierszu tabeli z bloku środkowego
Pozostałe cztery komórki w kolejności pól z SELECT. Tabela wygląda jak na obrazie 2; pomiary z ulic Tyskiej, Średzkiej i Wilanowskiej mają datę i godzinę wykonania zapytania 1 (tu 2026-10-04, 11:17:40). Ta tabela ma pięć kolumn ze znacznikami <table>, <tr>, <td> (R.2.8).
R.5.7 Skrypt 3 wstawia rekord do bazy (sprawdzić w phpMyAdmin)
ok. 2 min
Polecenie z arkusza
Skrypt 3 wysyła do bazy danych zapytanie 3
Zapytanie 3 bez zmian: przy każdym wejściu na stronę baza dopisuje pomiar DW12345 z losową wagą. Na stronie nic się nie zmienia - Skrypt 3 stoi pod tabelą, więc nowy pomiar zobaczy dopiero następne wejście (i tylko wtedy, gdy wylosował więcej niż 5 t). Dopisany wiersz sprawdza się w phpMyAdmin.
R.5.6 Skrypt 3 odświeża aktualną stronę co 10 sekund, np. header("refresh: 10");
R.5.8 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych lub funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania
ok. 2 min
Polecenie z arkusza
Odświeża aktualną stronę co 10 sekund.
header("refresh: 10") wysyła przeglądarce nagłówek HTTP „wczytaj tę stronę ponownie za 10 sekund”. Każde odświeżenie to nowe wejście, więc Skrypt 3 dopisuje kolejny pomiar, a Skrypt 2 pokazuje te z wagą powyżej 5 t - tabela rośnie jak na obrazie 3, a czerwony jest zawsze ostatni wiersz. Podgląd pokazuje stronę po 5 odświeżeniach (pomiary losowe: 2 z nich przekroczyło 5 t). Nagłówek HTTP musi wyjść, zanim strona wypisze treść; tutaj działa, bo XAMPP ma w php.ini bufor wyjścia 4096 bajtów (output_buffering) i wstrzymuje wysyłanie treści, dopóki bufor się nie zapełni. Nazwy zmiennych mówią, co przechowują ($connection, $query, $result, $street, $measurement) - kryterium R.5.8.
Kroki 47-48 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 47: Nagłówek odświeżania na początku pliku
ok. 3 min
Polecenie z arkusza
Odświeża aktualną stronę co 10 sekund.
Wersja z egzaminu ma ukrytą wadę, którą widać dopiero po kilku minutach: header() stoi w środku strony i działa tylko dzięki buforowi wyjścia XAMPP-a (4096 bajtów). Każde odświeżenie dopisuje pomiar, tabela rośnie, a treść przed Skryptem 3 w końcu przekracza bufor. Sprawdzone na tej bazie: przy 55. wejściu (tabela miała już 35 wierszy) PHP zgłasza „Cannot modify header information - headers already sent” i strona przestaje się odświeżać. Na serwerze bez bufora błąd pojawiłby się od razu. Poprawka: nagłówek wysyła osobny blok PHP na samym początku pliku, przed <!DOCTYPE html> - wtedy zawsze idzie przed treścią (sprawdzone: 75 wejść z rzędu bez ostrzeżenia). Spacja albo pusta linia przed <?php też jest treścią i zepsułaby nagłówek. Na egzaminie wystarczy wersja wcześniejsza - klucz sprawdza samo odświeżanie.
Typowe błędy
Pusta linia albo BOM (znak kodowania zapisany przez edytor) przed <?php - nagłówek nie wychodzi, a strona się nie odświeża.
Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym wierszu tabeli z bloku środkowego
Pięć prawie identycznych linii echo w Skrypcie 2 zastępuje pętla foreach po polach wiersza - kolumn jest tyle, ile pól w zapytaniu, więc po dodaniu pola do SELECT tabela sama dostanie nową komórkę. Wartości z bazy przechodzą przez htmlspecialchars: numer rejestracyjny wpisuje obsługa wagi, a znak < w takim polu rozbiłby tabelę. W Skrypcie 1 mysqli_fetch_assoc pozwala pisać $street["ulica"] zamiast $street[0]. Stare linie zostają w komentarzu. Tabela w podglądzie wygląda tak samo. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
wazenie.phpPHPzmienione: 7 linii
<?phpheader("refresh: 10"); // nagłówek HTTP przed jakąkolwiek treścią strony?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Ważenie samochodów ciężarowych</title> <linkrel="stylesheet"href="styl.css"></head><body> <headerid="banner1"> <h1>Ważenie pojazdów we Wrocławiu</h1> </header> <headerid="banner2"> <imgsrc="obraz1.png"alt="waga"> </header> <sectionid="left"> <h2>Lokalizacje wag</h2> <ol><?php$connection = mysqli_connect("localhost", "root", "", "wazenietirow");$query = "SELECT ulica FROM lokalizacje;";$result = mysqli_query($connection, $query);while ($street = mysqli_fetch_assoc($result)) {echo"<li>ulica " . htmlspecialchars($street["ulica"]) . "</li>"; }// while ($street = mysqli_fetch_row($result)) { echo "<li>ulica $street[0]</li>"; }?> </ol> <h2>Kontakt</h2> <ahref="mailto:[email protected]">napisz</a> </section> <sectionid="middle"> <h2>Alerty</h2> <table> <tr> <th>rejestracja</th> <th>ulica</th> <th>waga</th> <th>dzień</th> <th>czas</th> </tr><?php$query = "SELECT rejestracja, ulica, waga, dzien, czas FROM wagi JOIN lokalizacje ON wagi.lokalizacje_id = lokalizacje.id WHERE waga > 5;";$result = mysqli_query($connection, $query);while ($measurement = mysqli_fetch_row($result)) {echo"<tr>";foreach ($measurementas$value) {echo"<td>" . htmlspecialchars($value) . "</td>"; }echo"</tr>"; }// pięć osobnych linii echo "<td>$measurement[0]</td>"; ... "<td>$measurement[4]</td>";?> </table><?php$query = "INSERT INTO wagi (lokalizacje_id, waga, rejestracja, dzien, czas) VALUES (5, FLOOR(1 + RAND() * 10), 'DW12345', CURDATE(), CURTIME());"; mysqli_query($connection, $query);// header("refresh: 10"); przeniesione na początek pliku, przed <!DOCTYPE html> mysqli_close($connection);?> </section> <sectionid="right"> <imgsrc="obraz2.jpg"alt="tir"id="truck"> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Krok 49 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 49: 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: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, obraz1.png (z 5T), obraz2.jpg (odbity, 350 px), przeglądarka.txt, styl.css, wazenie.php. Płytę trzeba nagrać, sprawdzić jej odczyt i opisać numerem zdającego. Uwaga z klucza: przed oceną egzaminator usuwa pomiary dopisane przez stronę (DELETE FROM wagi WHERE id > 22), więc strona może dopisywać je do woli.
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.