INF.03-05-25.01-SGStyczeń 2025 · 32 kroki · ok. 71 min · 37 kryteriów z klucza
Rozwiązanie krok po kroku: Firma szkoleniowa (Nowoczesny kod (grid, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza firma z czterema zapytaniami, baner, statyczna index.html i szkolenia.php, która wypisuje szkolenia z bazy i zapisuje je do pliku harmonogram.txt - i tak samo spełnia każde kryterium klucza. Inna jest droga:
siatka CSS w kontenerze: dwie kolumny 20% 80% w grid-template-columns (klucz R.4.4 przyjmuje je wprost) zamiast float: left i clear: both, a kolory z arkusza zapisane raz, w zmiennych CSS,
PHP na PDO: zapytanie wykonane nad HTML-em, połączenie zamknięte, zanim zacznie się strona, a akapity wypisywane pętlą foreach w szablonie,
jedna lista linii, dwa użycia: tekst „data temat” powstaje raz i trafia i do akapitów, i do pliku - zapisanego jednym poleceniem file_put_contents ze sprawdzeniem, czy zapis się udał,
bezpieczeństwo: htmlspecialchars na wszystkim, co trafia z bazy na stronę, try/catch zamiast białej strony przy awarii bazy,
zapytania z aliasami i złączeniem JOIN ... ON.
Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza i obraz z kodem pochodzą z prawdziwego archiwum pliki8, zapytania zostały wykonane na tej bazie w MariaDB z XAMPP-a, a podgląd strony PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 - plik harmonogram.txt pokazany w krokach to dokładnie to, co zapisał skrypt.
Jak liczą się punkty. Klucz ma 37 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania to 75%, czyli 28 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-7 · po tym etapie masz 6 z 37 kryteriów (pkt)
Krok 1: Baza danych firma
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie firma, z zestawem polskich znaków (np. utf8_unicode_ci).
Archiwum pliki8.7z rozpakuj hasłem SzkoL3Nia% do folderu z numerem zdającego: firma.sql i obraz kod.jpg. W phpMyAdmin Nowa → firma, porównywanie utf8_unicode_ci, albo zapytaniem:
CREATE DATABASE firma CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Typowe błędy
Nazwa bazy musi być dokładnie firma - skrypt łączy się z nią po nazwie (R.5.2).
Krok 2: Import tabel z pliku firma.sql
ok. 2 min
Polecenie z arkusza
Do utworzonej bazy zaimportuj tabele z pliku firma.sql z rozpakowanego archiwum.
Import → firma.sql. Cztery tabele z ilustracji 1: trenerzy (6) → szkolenia (18, klucz obcy Id_trenera) → zapisy (Id_szkolenia) ← sluchacze (Id_klienta). Nazwy kolumn zaczynają się wielką literą (Data, Temat, Imie) - w zapytaniach i w PHP pisz je tak samo.
Krok 3: Zrzut ekranu import.jpg
Kryteria:
R.1.1 Wykonany import tabel do bazy danych firma , co jest udokumentowane w pliku import w formacie JPEG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie JPEG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.
Cały ekran z paskiem zadań. Uwaga na formaty: import w JPEG (import.jpg), zrzuty zapytań w PNG.
Typowe błędy
Wykadrowany zrzut albo zrzut importu zapisany jako PNG to strata R.1.1.
Krok 4: Zapytanie 1: szkolenia według daty
Kryteria: ,
R.1.2 Zapisany plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonane zapytanie 1 wybierające jedynie daty i tematy szkoleń posortowane rosnąco według daty szkolenia. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT Data, Temat FROM szkolenia ORDER BY Data; (opcjonalnie ASC ) oraz wynik działania udokumentowany zrzutem informującym o wybraniu dokładnie 18 rekordów, pierwszym jest 2021-09-20 Podstawy języka C++; nie wszystkie rekordy muszą być widoczne
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie daty i tematy szkoleń posortowane rosnąco według daty szkolenia.
Dwie kolumny i ORDER BY Data - rosnąco jest domyślnie (ASC można dopisać dla czytelności). Klauzule w osobnych liniach czyta się łatwiej niż jeden długi wiersz - MySQL nie zwraca uwagi na nowe linie. Wynik: 18 wierszy, pierwszy 2021-09-20 „Podstawy języka C++”. Zapytania zapisuj w kwerendy.txt, zrzut jako kw1.png. To zapytanie wyśle skrypt PHP.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT Data, TematFROM szkoleniaORDER BY Data;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: szkolenia z trenerami
Kryteria:
R.1.4 Wykonane zapytanie 2 wybierające jedynie daty i tematy szkoleń oraz odpowiadające im nazwiska i imiona trenerów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT Data, Temat, Nazwisko, Imie FROM szkolenia JOIN trenerzy ON trenerzy.Id = szkolenia.Id_trenera; (możliwe również INNER JOIN lub porównanie kluczy po WHERE ) oraz wynik działania udokumentowany zrzutem informującym o wybraniu dokładnie 18 rekordów; nie wszystkie rekordy muszą być widoczne
ok. 3 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie daty i tematy szkoleń oraz odpowiadające im nazwiska i imiona trenerów. Należy posłużyć się relacją.
Aliasy s (szkolenia) i t (trenerzy): przy każdej kolumnie widać, z której tabeli pochodzi, a ON t.Id = s.Id_trenera pokazuje parę kluczy relacji. Kolumna Id jest w obu tabelach, więc bez przedrostka byłaby niejednoznaczna. Wynik: 18 wierszy - każde szkolenie z jednym trenerem. Zrzut: kw2.png.
kwerendy.txtTekstzmienione: 5 linii
-- Zapytanie 1SELECT Data, TematFROM szkoleniaORDER BY Data;-- Zapytanie 2SELECT s.Data, s.Temat, t.Nazwisko, t.ImieFROM szkolenia AS sJOIN trenerzy AS t ON t.Id = s.Id_trenera;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: liczba szkoleń każdego trenera
Kryteria:
R.1.5 Wykonane zapytanie 3 wybierające dla każdego trenera jedynie jego imię i nazwisko oraz zliczające liczbę jego szkoleń. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT Imie, Nazwisko, COUNT(*) FROM trenerzy JOIN szkolenia ON trenerzy.Id = Id_trenera GROUP BY trenerzy.Id; (po GROUP BY też poprawne pole Nazwisko ) oraz wynik działania udokumentowany zrzutem, na którym znajdują się jedynie rekordy: Tomasz Duda 2, Mateusz Kossakowski 3, Sebastian Królik 3, Maria Przepiórkowska 5, Nikodem Ptak 3, Kinga Stopyra 2
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające dla każdego trenera jedynie jego imię i nazwisko oraz zliczające liczbę jego szkoleń. Należy posłużyć się relacją.
JOIN ... ON s.Id_trenera = t.Id - każde szkolenie przy swoim trenerze,
GROUP BY t.Id, t.Imie, t.Nazwisko - jedna grupa na trenera; klucz t.Id rozdziela dwóch trenerów o tym samym nazwisku, a imię i nazwisko na liście grupowania sprawiają, że zapytanie przejdzie też na serwerze z trybem ONLY_FULL_GROUP_BY (w nowszych MySQL włączonym domyślnie),
COUNT(*) AS z nazwą w odwrotnych apostrofach - ze spacją i polską literą.
Wynik: Duda 2, Kossakowski 3, Królik 3, Przepiórkowska 5, Ptak 3, Stopyra 2 - jak w kluczu. Zrzut: kw3.png.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT Data, TematFROM szkoleniaORDER BY Data;-- Zapytanie 2SELECT s.Data, s.Temat, t.Nazwisko, t.ImieFROM szkolenia AS sJOIN trenerzy AS t ON t.Id = s.Id_trenera;-- Zapytanie 3SELECT t.Imie, t.Nazwisko, COUNT(*) AS `Liczba szkoleń`FROM trenerzy AS tJOIN szkolenia AS s ON s.Id_trenera = t.IdGROUP BY t.Id, t.Imie, t.Nazwisko;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowa nazwa kolumny
Kryteria:
R.1.6 Wykonane zapytanie 4 zmieniające w tabeli zapisy nazwę kolumny id_klienta na id_sluchacza. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE zapisy CHANGE COLUMN Id_klienta Id_sluchacza INT; oraz wynik działania udokumentowany zrzutem, na którym jest widoczny komunikat o pomyślnie wykonanej kwerendzie lub widoczna zmieniona struktura tabeli
ok. 3 min
Polecenie z arkusza
Zapytanie 4: zmieniające w tabeli zapisy nazwę kolumny Id_klienta na Id_sluchacza.
Tu nowoczesna składnia nie zadziała: RENAME COLUMN Id_klienta TO Id_sluchacza pojawiło się w MariaDB 10.5, a XAMPP ma 10.4 - kończy się błędem składni 1064 (sprawdzone). Zostaje CHANGE COLUMN stara nowa typ, w którym typ trzeba podać na nowo - przepisz go z budowy tabeli (INT(11) DEFAULT NULL), żeby kolumna nie zmieniła niczego poza nazwą. Zrzut kw4.png: komunikat albo struktura tabeli z kolumną Id_sluchacza.
Typowe błędy
CHANGE COLUMN Id_klienta Id_sluchacza bez typu to błąd składni - typ jest w CHANGE obowiązkowy.
kwerendy.txtTekstzmienione: 4 linie
-- Zapytanie 1SELECT Data, TematFROM szkoleniaORDER BY Data;-- Zapytanie 2SELECT s.Data, s.Temat, t.Nazwisko, t.ImieFROM szkolenia AS sJOIN trenerzy AS t ON t.Id = s.Id_trenera;-- Zapytanie 3SELECT t.Imie, t.Nazwisko, COUNT(*) AS `Liczba szkoleń`FROM trenerzy AS tJOIN szkolenia AS s ON s.Id_trenera = t.IdGROUP BY t.Id, t.Imie, t.Nazwisko;-- Zapytanie 4ALTER TABLE zapisyCHANGE COLUMN Id_klienta Id_sluchacza INT(11) DEFAULT NULL;
Podgląd strony po tym kroku
Etap 2: Grafika i strony HTML
Kroki 8-16 · po tym etapie masz 18 z 37 kryteriów (pkt)
Krok 8: Baner: gradient, kod w perspektywie, napis
Kryteria: , ,
R.2.1 Utworzony plik o nazwie baner.jpg o szerokości 1000 px, wysokości 150 px i tle - gradiencie od koloru czarnego po lewej do białego po prawej stronie
R.2.2 Na grafice banera po lewej stronie jest widoczny fragment kodu, widać jedynie dwie sekcje case. Fragment jest transponowany tak, że widać perspektywę
R.2.3 Na grafice banera po prawej stronie jest umieszczony tekst o treści "Firma szkoleniowa" w czarnym kolorze
ok. 8 min
Polecenie z arkusza
Na potrzeby strony należy przygotować grafikę z banerem o nazwie baner.jpg i cechach: szerokość grafiki 1000 px, wysokość 150 px, tło baneru w formie gradientu od czarnego koloru z lewej do białego przy prawej krawędzi banera. Na pierwszym planie po lewej stronie umieszczona grafika z pliku kod.jpg. Grafika jest skalowana – widoczne dokładnie dwie sekcje case oraz jest transformowana jak na ilustracji 2, tworząc efekt perspektywy. Na pierwszym planie po prawej stronie umieszczony napis o treści „Firma szkoleniowa” w kolorze czarnym.
Grafika jest taka sama w obu wersjach rozwiązania. W GIMP-ie, warstwa po warstwie:
Plik → Nowy1000 × 150; Gradient od czarnego (pierwszy plan) do białego (tło), przeciągnięty od lewej do prawej krawędzi z wciśniętym Ctrl,
Plik → Otwórz jako warstwykod.jpg; zaznaczeniem prostokątnym zostaw dokładnie dwie sekcjecase ('+' i '-') i przeskaluj warstwę, żeby zmieściła się po lewej,
Perspektywa (Shift+P): prawe narożniki do środka - kod „ucieka” w głąb jak na ilustracji 2,
Tekst: „Firma szkoleniowa”, czarny, po prawej,
Eksportuj jakobaner.jpg.
Typowe błędy
Kadr z kawałkiem trzeciej sekcji (case '*') nie spełnia „dokładnie dwie sekcje case” (R.2.2).
Podgląd strony po tym kroku
Krok 9: Plik index.html: HTML5, język, kodowanie
Kryteria:
R.2.4 Witryna internetowa zapisana w plikach index.html i szkolenia.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE html>, zadeklarowany język witryny: polski np. <html lang="pl">. Strona zawiera sekcje head i body
ok. 2 min
Polecenie z arkusza
Składa się z dwóch stron o nazwach index.html i szkolenia.php. Cechy wspólne dla obu stron: Zapisane w języku HTML5. Zadeklarowany polski język zawartości witryny. Jawnie zastosowany właściwy standard kodowania polskich znaków.
Szkielet od razu z lang="pl" w <html> i <meta charset="UTF-8"> jako pierwszym elementem <head> - przeglądarka powinna poznać kodowanie, zanim przeczyta jakikolwiek polski znak (R.2.4). Najpierw powstaje index.html, a szkolenia.php będzie jej kopią z innym blokiem głównym.
R.3.4 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie style.css formatowanie CSS pochodzi jedynie z tego arkusza. Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Tytuł strony widoczny na karcie przeglądarki: „Firma szkoleniowa”. Arkusz stylów w pliku o nazwie style.css prawidłowo połączony z kodem strony.
<title> (R.2.5), <link> do style.css - całe formatowanie z tego pliku (R.3.4) - i viewport, żeby telefon nie pomniejszał strony do miniatury.
R.2.6 Zdefiniowany układ strony dzielący ją na bloki: nagłówkowy, menu, główny i stopki przy pomocy semantycznych znaczników sekcji języka HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, do stopki - footer. Dopuszcza się dodatkowe użycie bloków div lub section
ok. 2 min
Polecenie z arkusza
Strona składa się z kontenera, a w nim podział na bloki: nagłówkowy, poniżej obok siebie menu i główny, na dole stopka. Podział zrealizowany za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 2.
Kontener to zwykły <div class="container"> - nie niesie żadnego znaczenia, tylko obejmuje stronę, więc semantyczny znacznik nie byłby tu prawdziwszy. W środku bloki o znaczeniu: <header>, <nav> (menu), <main> i <footer> (R.2.6).
Klasa zamiast identyfikatora: kontener może się pojawić na stronie więcej niż raz, a klasa ma w CSS niższą „wagę” niż #id, więc łatwiej ją potem nadpisać. Rozmieszczenie bloków zrobi siatka CSS.
R.2.9 W bloku menu umieszczona jedna lista punktowana z dwoma elementami, zastosowane znaczniki <ul> i <li>
R.3.2 Po kliknięciu na odnośnik "Szkolenia" otwiera się strona szkolenia.php
R.3.3 Po kliknięciu na odnośnik "Strona główna" otwiera się strona index.html
ok. 2 min
Polecenie z arkusza
Zawartość bloku menu: Lista punktowana (nieuporządkowana) z dwoma elementami: odnośnik do pliku index.html o treści „Strona główna” i odnośnik do pliku szkolenia.php o treści „Szkolenia”.
<ul> z dwoma <li>, w każdym odnośnik (R.2.9, R.3.2, R.3.3). aria-label nazywa menu dla czytnika ekranu - przy kilku blokach <nav> na stronie użytkownik niewidomy wie, który jest który. Strona szkolenia.php działa tylko przez serwer: otwieraj witrynę przez http://localhost/..., nie dwuklikiem z dysku.
R.2.7 W stopce umieszczony <h2>: „Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa” oraz paragraf z numerem zdającego. Na stronie głównej w bloku głównym umieszczony <h1>: „Zapraszamy do udziału w szkoleniach z branży IT” z dwoma łamaniami wiersza
ok. 1 min
Polecenie z arkusza
Zawartość bloku stopki: Nagłówek drugiego stopnia zawierający napis „Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa”. Akapit (paragraf) zawierający napis „Autor: ”, dalej wstawiony numer zdającego.
<h2> i <p>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tu stoi imię i nazwisko autora rozwiązania.
R.2.7 W stopce umieszczony <h2>: „Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa” oraz paragraf z numerem zdającego. Na stronie głównej w bloku głównym umieszczony <h1>: „Zapraszamy do udziału w szkoleniach z branży IT” z dwoma łamaniami wiersza
ok. 1 min
Polecenie z arkusza
Zawartość bloku głównego dla strony index.html: Nagłówek pierwszego stopnia o treści „Zapraszamy do udziału w szkoleniach z branży IT”. Łamanie wiersza po słowie „udziału” oraz po słowie „szkoleniach”.
Łamanie wiersza wewnątrz nagłówka to <br> - dwa razy, dokładnie po wskazanych słowach (R.2.7). Tu <br> jest na miejscu: to część treści (podział tytułu), a nie sposób na odstęp między blokami.
Kroki 17-25 · po tym etapie masz 29 z 37 kryteriów (pkt)
Krok 17: Plik style.css: kolory w zmiennych i krój czcionki
Kryteria:
R.4.1 Ustawiony styl domyślny dla wszystkich selektorów (*): krój czcionki Tahoma
ok. 2 min
Polecenie z arkusza
Domyślnie dla wszystkich selektorów: krój czcionki Tahoma.
Najpierw cztery kolory z arkusza jako zmienne CSS w :root: pomarańczowy pojawia się w kontenerze i w elementach listy, grafitowy w menu i w odnośnikach. Zmiana odcienia to potem jedna linia, a nazwa --graphite mówi więcej niż #232323. W regułach kolor wstawia się przez var(--orange) - przeglądarka i tak liczy z niego ten sam kolor, który egzaminator zobaczy w narzędziach deweloperskich.
Krok 18: Kontener: tło i siatka z dwiema kolumnami
Kryteria: , ,
R.3.1 Układ bloków na stronie po uruchomieniu w przeglądarce jest zgodny z ilustracją 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid albo position )
R.4.2 Ustawiony kolor tła #FB8E02 dla kontenera całej strony oraz selektora li, #232323 dla bloku menu, #AEC6E6 dla bloku głównego
R.4.4 Ustawiona szerokość 20% dla bloku menu, 80% dla bloku głównego (width lub grid-template- columns lub flex ) oraz 100% dla obrazu, 95% dla elementu listy
ok. 3 min
Polecenie z arkusza
Dla kontenera głównego strony: kolor tła #FB8E02.
Tło kontenera z arkusza (R.4.2) i od razu cały układ strony:
display: grid i grid-template-columns: 20% 80% - dwie kolumny; to szerokości menu i bloku głównego, które klucz R.4.4 przyjmuje zapisane właśnie tu („width lub grid-template-columns lub flex”),
header, footer { grid-column: 1 / -1; } - nagłówek i stopka od pierwszej do ostatniej linii siatki, czyli na całą szerokość; -1 znaczy „ostatnia linia”, więc reguła zadziała też przy innej liczbie kolumn,
menu i blok główny wpadają do kolumn same, w kolejności z HTML-u - obok siebie, pod nagłówkiem (R.3.1).
Bez float nie trzeba clear w stopce: siatka nie wyjmuje elementów z przepływu.
R.4.2 Ustawiony kolor tła #FB8E02 dla kontenera całej strony oraz selektora li, #232323 dla bloku menu, #AEC6E6 dla bloku głównego
R.4.5 Ustawiona wysokość 450px dla bloków menu i głównego
ok. 1 min
Polecenie z arkusza
Dla bloku menu: kolor tła #232323, szerokość 20%, wysokość 450 px.
Grafitowe tło (R.4.2) i wysokość 450 px (R.4.5). Szerokości 20% nie powtarzaj w width: stoi już w kolumnie siatki, a width: 20% na elemencie siatki liczyłby się od jego kolumny - menu zajęłoby 20% z 20%.
Typowe błędy
width: 20% i width: 80% dopisane do bloków w siatce 20% 80% zwężają je do 4% i 64% strony - procent liczy się od kolumny siatki.
R.4.2 Ustawiony kolor tła #FB8E02 dla kontenera całej strony oraz selektora li, #232323 dla bloku menu, #AEC6E6 dla bloku głównego
R.4.5 Ustawiona wysokość 450px dla bloków menu i głównego
R.4.8 Ustawione dla bloku głównego paski przewijania na scroll
ok. 1 min
Polecenie z arkusza
Dla bloku głównego: kolor tła #AEC6E6, szerokość 80%, wysokość 450 px, paski przewijania zawsze widoczne.
„Zawsze widoczne” to overflow: scroll - paski są nawet przy krótkiej treści (auto pokazałoby je tylko w razie potrzeby) (R.4.8). Tło R.4.2, wysokość R.4.5, a szerokość 80% - jak w menu - w kolumnie siatki.
R.4.6 Ustawione marginesy wewnętrzne (padding) 2px dla stopki, 50px dla nagłówka stopnia pierwszego, 5px dla elementu listy, oraz margines zewnętrzny górny (margin-top) 10px dla elementu listy
R.4.7 Ustawione wyrównanie tekstu do prawej strony dla stopki
ok. 1 min
Polecenie z arkusza
Dla bloku stopki: marginesy wewnętrzne 2 px, wyrównanie tekstu do prawej strony.
Stopka nie ma własnego tła - widać pomarańczowy kontener (R.4.6, R.4.7). To druga reguła dla footer (pierwsza ustawia miejsce w siatce): jedna mówi o układzie, druga o wyglądzie.
R.4.4 Ustawiona szerokość 20% dla bloku menu, 80% dla bloku głównego (width lub grid-template- columns lub flex ) oraz 100% dla obrazu, 95% dla elementu listy
ok. 1 min
Polecenie z arkusza
Dla obrazu: szerokość 100%.
Baner rozciąga się na szerokość nagłówka (R.4.4). display: block usuwa kilkupikselową szparę pod obrazem: obraz jest domyślnie elementem liniowym i stoi na linii pisma, pod którą przeglądarka zostawia miejsce na „ogonki” liter.
R.4.3 Ustawiony kolor czcionki Maroon dla selektora h1 oraz #232323 dla selektora a
R.4.6 Ustawione marginesy wewnętrzne (padding) 2px dla stopki, 50px dla nagłówka stopnia pierwszego, 5px dla elementu listy, oraz margines zewnętrzny górny (margin-top) 10px dla elementu listy
ok. 1 min
Polecenie z arkusza
Dla selektora nagłówka pierwszego stopnia: marginesy wewnętrzne 50 px, kolor czcionki Maroon.
Selektor znacznika h1 - uwaga pod listą stylów wymaga go dla nagłówka, elementu listy i odnośnika, więc tu nie ma miejsca na klasy (R.4.3, R.4.6).
R.4.2 Ustawiony kolor tła #FB8E02 dla kontenera całej strony oraz selektora li, #232323 dla bloku menu, #AEC6E6 dla bloku głównego
R.4.4 Ustawiona szerokość 20% dla bloku menu, 80% dla bloku głównego (width lub grid-template- columns lub flex ) oraz 100% dla obrazu, 95% dla elementu listy
R.4.6 Ustawione marginesy wewnętrzne (padding) 2px dla stopki, 50px dla nagłówka stopnia pierwszego, 5px dla elementu listy, oraz margines zewnętrzny górny (margin-top) 10px dla elementu listy
R.4.9 Ustawiony dla listy punktowanej brak symboli punktorów oraz dla odnośnika brak podkreślenia i rozmiar czcionki 110%
ok. 2 min
Polecenie z arkusza
Dla listy punktowanej: brak symboli punktorów. Dla selektora elementu listy: kolor tła #FB8E02, szerokość 95%, marginesy wewnętrzne 5 px, margines zewnętrzny – górny 10 px.
list-style-type: none usuwa punktory (R.4.9); li stają się pomarańczowymi paskami - tym samym kolorem z var(--orange) co kontener (R.4.2, R.4.4, R.4.6). Tu width: 95% jest potrzebne: lista nie jest elementem siatki, więc procent liczy się od szerokości listy.
R.4.3 Ustawiony kolor czcionki Maroon dla selektora h1 oraz #232323 dla selektora a
R.4.9 Ustawiony dla listy punktowanej brak symboli punktorów oraz dla odnośnika brak podkreślenia i rozmiar czcionki 110%
R.4.10 Gdy kursor myszy znajdzie się na elemencie listy, jego tło zmienia się na #B36501
ok. 2 min
Polecenie z arkusza
Dla selektora odnośnika: brak podkreślenia, kolor czcionki #232323, rozmiar czcionki 110%. Gdy kursor myszy znajdzie się na elemencie listy, jego tło zmienia się na #B36501.
li:hover - pod kursorem ciemnieje cały pasek elementu listy, nie tylko napis (R.4.10). Kolor odnośnika to ta sama zmienna co tło menu - grafitowy napis na pomarańczowym pasku (R.4.3, R.4.9).
Kroki 26-30 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 26: Połączenie PDO na górze pliku
Kryteria: , , ,
R.5.1 Skrypt jest napisany w języku PHP w pliku szkolenia.php i zawiera przynajmniej jedną zgodną z treścią zadania instrukcję
R.5.2 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy firma
R.5.3 Ostatnią operacją na bazie jest jej zamknięcie
R.5.8 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania
ok. 4 min
Polecenie z arkusza
Napisany w języku PHP, działa na stronie szkolenia.php. Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim. Łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie firma. Na końcu działania skrypt zamyka połączenie z serwerem.
Praca z bazą stoi przed<!DOCTYPE html>: najpierw dane, potem HTML, który je tylko wypisuje. Połączenie przez PDO (klucz R.5 przyjmuje MySQLi i PDO):
napis DSN 'mysql:host=localhost;dbname=firma;charset=utf8mb4' - serwer, baza i kodowanie; 'root', '' - użytkownik i puste hasło (R.5.1, R.5.2),
ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze jako tablice z nazwami kolumn,
$pdo = null zamyka połączenie (PDO nie ma osobnej funkcji „zamknij”); zapytanie trafi między te dwie linie, więc zamknięcie zostanie ostatnią operacją na bazie (R.5.3),
try / catch (PDOException $exception) - gdy serwer bazy nie odpowiada, szczegóły idą do dziennika serwera (error_log), a strona dostaje zwykły komunikat w $message,
funkcja e() to krótka nazwa htmlspecialchars(..., ENT_QUOTES) - będzie przy każdej wartości z bazy.
Nazwy po angielsku mówią, co przechowują (R.5.8). Od tego kroku podgląd to wynik prawdziwego uruchomienia.
R.5.4 Skrypt zawiera instrukcję wysyłającą zapytanie 1
ok. 1 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 1.
$pdo->query(...) wysyła zapytanie 1, a ->fetchAll() od razu odbiera wszystkie 18 wierszy do tablicy $trainings (R.5.4). Zwykłe query wystarcza, bo w zapytaniu nie ma niczego od użytkownika; dane z formularza szłyby przez prepare i execute. Na stronie jeszcze nic nie widać - tablica czeka na wypisanie.
szkolenia.phpPHPzmienione: 1 linia
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES);}$trainings = [];$message = '';try {$pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$trainings = $pdo->query('SELECT Data, Temat FROM szkolenia ORDER BY Data')->fetchAll();$pdo = null;} catch (PDOException $exception) {error_log($exception->getMessage());$message = 'Nie udało się pobrać harmonogramu szkoleń. Spróbuj ponownie za chwilę.';}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Firma szkoleniowa</title> <linkrel="stylesheet"href="style.css"></head><body> <divclass="container"> <header> <imgsrc="baner.jpg"alt="Szkolenia"> </header> <navaria-label="Menu główne"> <ul> <li><ahref="index.html">Strona główna</a></li> <li><ahref="szkolenia.php">Szkolenia</a></li> </ul> </nav> <main> </main> <footer> <h2>Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa</h2> <p>Autor: Bartosz Bryniarski</p> </footer> </div></body></html>
R.5.5 Zwrócone zapytaniem data i temat szkolenia są wyświetlane w kolejnych paragrafach w bloku głównym
ok. 3 min
Polecenie z arkusza
Zwrócone zapytaniem data i temat szkolenia są oddzielone spacją i wyświetlane jeden pod drugim w osobnych paragrafach w bloku głównym – ilustracja 3.
Dwie części:
nad HTML-em array_map zamienia każdy wiersz w napis „data temat” - funkcja strzałkowa fn(array $training): string => ... mówi, co przyjmuje i co zwraca. Lista $lines przyda się drugi raz w kolejnym kroku, przy zapisie pliku,
w bloku głównym pętla foreach ($lines as $line): ... endforeach; w składni alternatywnej, a w niej <p> z linią przepuszczoną przez e() - <?= ... ?> to skrót od <?php echo ... ?>.
Akapity są blokowe, więc stoją jeden pod drugim. Podgląd: 18 szkoleń od 2021-09-20 „Podstawy języka C++” i paski przewijania bloku głównego - jak na ilustracji 3 (R.5.5).
szkolenia.phpPHPzmienione: 5 linii
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES);}$trainings = [];$message = '';try {$pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$trainings = $pdo->query('SELECT Data, Temat FROM szkolenia ORDER BY Data')->fetchAll();$pdo = null;} catch (PDOException $exception) {error_log($exception->getMessage());$message = 'Nie udało się pobrać harmonogramu szkoleń. Spróbuj ponownie za chwilę.';}$lines = array_map(fn(array$training): string => $training['Data'] . ' ' . $training['Temat'], $trainings);?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Firma szkoleniowa</title> <linkrel="stylesheet"href="style.css"></head><body> <divclass="container"> <header> <imgsrc="baner.jpg"alt="Szkolenia"> </header> <navaria-label="Menu główne"> <ul> <li><ahref="index.html">Strona główna</a></li> <li><ahref="szkolenia.php">Szkolenia</a></li> </ul> </nav> <main><?phpforeach ($linesas$line): ?> <p><?= e($line) ?></p><?phpendforeach; ?> </main> <footer> <h2>Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa</h2> <p>Autor: Bartosz Bryniarski</p> </footer> </div></body></html>
Podgląd strony po tym kroku (szkolenia.php)
Krok 29: Plik harmonogram.txt jednym poleceniem
Kryteria: ,
R.5.6 Skrypt tworzy / otwiera do zapisu plik harmonogam.txt
R.5.7 Zwrócone zapytaniem rekordy danych są zapisywane jako osobne linie w utworzonym pliku. Należy sprawdzić działanie na pliku
ok. 3 min
Polecenie z arkusza
Dodatkowo zwrócone zapytaniem wiersze są zapisywane jako osobne linie w pliku tekstowym o nazwie harmonogram.txt.
file_put_contents(plik, treść) sam tworzy plik (albo czyści istniejący), zapisuje treść i go zamyka - to samo, co fopen z trybem "w", pętla fwrite i fclose, ale bez ryzyka, że plik zostanie otwarty (R.5.6, R.5.7):
treść to te same linie co w akapitach, sklejone implode(PHP_EOL, $lines) - PHP_EOL to znak końca linii systemu serwera (na Windows \r\n), dopisany też po ostatniej linii,
__DIR__ . '/harmonogram.txt' - plik zawsze obok skryptu, niezależnie od tego, z jakiego katalogu serwer go uruchomił,
LOCK_EX blokuje plik na czas zapisu, gdy dwie osoby otworzą stronę w tej samej chwili,
wynik false oznacza błąd zapisu (np. brak uprawnień do folderu) - wtedy komunikat w $message,
warunek $lines !== [] chroni plik przed nadpisaniem pustą treścią, gdy baza nie odpowie.
Obok kodu widać plik dokładnie taki, jaki zapisał skrypt: 18 linii - te same co w wersji podstawowej.
harmonogram.txtTekstnowy plik
2021-09-20 Podstawy języka C++2021-09-30 Photoshop dla zaawansowanych2021-10-01 Podstawy języka Python2021-10-02 Systemy operacyjne2021-10-07 Aplikacje Webowe2021-10-15 Python dla zaawansowanych2021-10-21 Techologia druku 3D2021-10-22 PHP - poziom podstawowy2021-11-10 Animacje komputerowe2021-11-15 Administracja systemem Linux2021-11-21 PHP - poziom średniozaawansowany2021-11-28 HTML i CSS dla zaawansowanych2021-11-30 Programowanie obiektowe w C++2021-12-06 Windows Serwer - usługi2021-12-07 PHP - poziom zaawansowany2021-12-10 C++ dla zaawansowanych2021-12-15 Obsługa drukarek 3D2021-12-16 Obsługa programu GIMP
szkolenia.phpPHPzmienione: 7 linii
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES);}$trainings = [];$message = '';try {$pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$trainings = $pdo->query('SELECT Data, Temat FROM szkolenia ORDER BY Data')->fetchAll();$pdo = null;} catch (PDOException $exception) {error_log($exception->getMessage());$message = 'Nie udało się pobrać harmonogramu szkoleń. Spróbuj ponownie za chwilę.';}$lines = array_map(fn(array$training): string => $training['Data'] . ' ' . $training['Temat'], $trainings);if ($lines !== []) {$saved = file_put_contents(__DIR__ . '/harmonogram.txt', implode(PHP_EOL, $lines) . PHP_EOL, LOCK_EX);if ($saved === false) {$message = 'Nie udało się zapisać pliku harmonogram.txt.'; }}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Firma szkoleniowa</title> <linkrel="stylesheet"href="style.css"></head><body> <divclass="container"> <header> <imgsrc="baner.jpg"alt="Szkolenia"> </header> <navaria-label="Menu główne"> <ul> <li><ahref="index.html">Strona główna</a></li> <li><ahref="szkolenia.php">Szkolenia</a></li> </ul> </nav> <main><?phpforeach ($linesas$line): ?> <p><?= e($line) ?></p><?phpendforeach; ?> </main> <footer> <h2>Firma szkoleniowa, ul. Główna 1, 23-456 Warszawa</h2> <p>Autor: Bartosz Bryniarski</p> </footer> </div></body></html>
Napisany w języku PHP, działa na stronie szkolenia.php.
Pod akapitami wiersz z komunikatem z $message - tylko wtedy, gdy catch albo nieudany zapis pliku coś do niego wpisały. Sprawdzone uruchomieniem z błędną nazwą bazy: strona się wyświetla, w bloku głównym stoi „Nie udało się pobrać harmonogramu szkoleń…”, a w treści nie ma ani nazwy bazy, ani kodu błędu SQL. Bez try/catch PHP przerwałby stronę w połowie komunikatem „Fatal error: Uncaught PDOException” razem ze ścieżką pliku na serwerze.
W normalnym działaniu połączenie jest zamykane zaraz po zapytaniu - jak chce arkusz, na końcu pracy z bazą. Podgląd: strona po prawdziwym uruchomieniu, bez komunikatu.
harmonogram.txtTekstzmienione: 0 linii
2021-09-20 Podstawy języka C++2021-09-30 Photoshop dla zaawansowanych2021-10-01 Podstawy języka Python2021-10-02 Systemy operacyjne2021-10-07 Aplikacje Webowe2021-10-15 Python dla zaawansowanych2021-10-21 Techologia druku 3D2021-10-22 PHP - poziom podstawowy2021-11-10 Animacje komputerowe2021-11-15 Administracja systemem Linux2021-11-21 PHP - poziom średniozaawansowany2021-11-28 HTML i CSS dla zaawansowanych2021-11-30 Programowanie obiektowe w C++2021-12-06 Windows Serwer - usługi2021-12-07 PHP - poziom zaawansowany2021-12-10 C++ dla zaawansowanych2021-12-15 Obsługa drukarek 3D2021-12-16 Obsługa programu GIMP
Krok 31 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 31: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 2 min
Obie wersje dają komplet 37 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
układ
float: left + clear: both
grid-template-columns: 20% 80% w kontenerze
kolory
wpisane w każdej regule
zmienne CSS w :root
baza
mysqli_connect, mysqli_fetch_row, $row[0]
PDO z wyjątkami, fetchAll, $training['Data']
gdzie PHP
w bloku głównym, połączenie zamykane na końcu bloku
dane nad HTML-em, połączenie zamknięte przed stroną
plik
fopen, fwrite w pętli, fclose
file_put_contents z kontrolą wyniku i blokadą
dane na stronie
wprost (w dobrych praktykach htmlspecialchars)
e() przy każdej wartości
awaria bazy
biała strona z błędem
komunikat w bloku głównym, szczegóły w error_log
Na egzaminie wersja podstawowa trzyma się dosłownie funkcji z tabeli 1 arkusza i łatwo ją sprawdzić krok po kroku z kluczem (fopen - R.5.6, fwrite - R.5.7). Nowoczesna pisze się nie dłużej, ale wymaga pewności, że file_put_contents i $pdo = null to te same operacje innymi słowami. Czego tu świadomie nie ma: pliku config.php z danymi logowania (egzaminator szuka połączenia w szkolenia.php) i zapytań przygotowanych - strona nie przyjmuje żadnych danych od użytkownika.
Krok 32 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 32: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego, powinny znajdować się pliki: baner.jpg, import.jpg, index.html, kw1.png, kw2.png, kw3.png, kw4.png, kwerendy.txt, przeglądarka.txt, style.css, szkolenia.php, ewentualnie inne przygotowane pliki.
Przed nagraniem otwórz szkolenia.php przez http://localhost/..., żeby skrypt utworzył harmonogram.txt - egzaminator sprawdza ten plik (R.5.7). W przeglądarka.txt wpisz nazwę przeglądarki, nagraj płytę i sprawdź jej odczyt.
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.