Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-05-21.01-SGStyczeń 2021 · 42 kroki · ok. 78 min · 37 kryteriów z klucza
Rozwiązanie krok po kroku: Tablica przylotów portu lotniczego (Wersja podstawowa)
Aplikacja internetowa portu lotniczego: baza egzamin z tabelami przyloty, samoloty i odloty, cztery zapytania (sortowanie ORDER BY, zliczanie COUNT w przedziale godzin, relacja JOIN i aktualizacja UPDATE), logo samolotu przeskalowane z zachowaniem przezroczystości oraz strona lotnisko.php: trzy bloki banera, tablica przylotów wypełniana skryptem PHP z bazy i stopka, w której drugi skrypt na podstawie ciasteczka wita gościa przy pierwszej wizycie albo wita go ponownie.
To arkusz EE.09 ze stycznia 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. W styczniu 2024 to samo zadanie wróciło jako EE.09-02 z dwoma dodatkowymi wymaganiami - ma własne rozwiązanie na swojej stronie. 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 są najpierw napisane najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzone na prawdziwych błędach i zabezpieczone.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: znaczniki <header>, <main> i <footer> z układem flex, zmienne CSS, PDO z obsługą wyjątków i ciasteczko z flagami bezpieczeństwa - obie wersje są zgodne z kluczem.
Baza i grafika pochodzą z oryginalnego archiwum CKE z5.zip (załącznik do pobrania na stronie arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2, także z ciasteczkiem zapamiętanym między dwoma wejściami na stronę.
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: Folder zdającego i archiwum z5.zip
ok. 2 min
Polecenie z arkusza
Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie z5.zip zabezpieczone hasłem: LotniSko%7 Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Umieść w tym folderze rozpakowane pliki.
Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum z5.zip otwierasz programem 7-Zip i rozpakowujesz do tego folderu, podając hasło LotniSko%7 (wielkość liter i znaki specjalne mają znaczenie). W środku są dwa pliki: egzamin.sql (baza do importu) i zad5.png (logo z samolotem).
Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, lotnisko.php, styl5.css i przeskalowana grafika.
Typowe błędy
Pliki zapisane poza folderem zdającego nie trafią na płytę - a ocenia się tylko to, co jest na płycie.
Krok 2: XAMPP, baza egzamin i import egzamin.sql
ok. 2 min
Polecenie z arkusza
Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie egzamin. Do bazy egzamin zaimportuj plik egzamin.sql z rozpakowanego archiwum
W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa egzamin, Utwórz. Następnie zaznaczasz bazę egzamin, karta Import, Wybierz plik → egzamin.sql, Wykonaj.
Plik tworzy siedem tabel z danymi. Do zadania potrzebne są trzy z obrazu 1: przyloty (8 lotów), odloty (10 lotów) i samoloty (4 typy samolotów z liniami). Pole samoloty_id w obu tabelach lotów wskazuje id samolotu - to relacja, z której skorzysta zapytanie 3.
Typowe błędy
Plik importujesz do bazy egzamin - zaznaczonej w lewym panelu. Import bez zaznaczonej bazy kończy się błędem „Nie wybrano bazy danych”.
Krok 3: Zrzut import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych egzamin , czynność udokumentowano plikiem o nazwie import w formacie PNG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL, 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
Po imporcie kliknij bazę egzamin - karta Struktura pokazuje listę tabel z liczbą rekordów (przyloty 8, odloty 10, samoloty 4). Zielony komunikat o udanym imporcie i lista tabel to „elementy wskazujące na poprawnie wykonany import”. Zrzut całego ekranu (Print Screen, wklejenie do edytora grafiki) zapisujesz jako import.png.
Typowe błędy
Ten zrzut jest w PNG, a zrzuty kwerend w JPG - zły format albo wykadrowany zrzut bez paska zadań nie jest oceniany.
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: przyloty posortowane według czasu
Kryteria: ,
R.1.2 Zapisano plik tekstowy o nazwie kwerendy z zapytaniami SQL zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Utworzono zapytanie 1 wybierające jedynie pola czas, kierunek, nr_rejsu i status_lotu z tabeli przyloty posortowane rosnąco według czasu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT czas, kierunek, nr_rejsu, status_lotu FROM przyloty ORDER BY czas; (też gdy zapisano ASC) oraz wynik działania zapytania udokumentowano zrzutem, na którym jest widocznych dokładnie 8 rekordów, jedynie pola czas, kierunek, nr_rejsu, status_lotu. Rekordy są posortowane rosnąco wg. czasu
ok. 3 min
Polecenie z arkusza
Zapisz i wykonaj zapytania SQL działające na bazie egzamin. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie JPG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające jedynie pola czas, kierunek, nr_rejsu i status_lotu z tabeli przyloty posortowane rosnąco według czasu
Zaznacz bazę egzamin, karta SQL. Zapytanie klauzula po klauzuli:
SELECT czas, kierunek, nr_rejsu, status_lotu - „jedynie” te cztery pola, w tej kolejności (tak samo ułożone będą kolumny tablicy na stronie),
FROM przyloty - tabela przylotów,
ORDER BY czas - sortowanie według czasu; bez słowa DESC porządek jest rosnący (można dopisać ASC).
Wynik: 8 przylotów od 09:45:00 (Warszawa) do 10:33:00 (Zurych). Zapytanie wklejasz do pliku kwerendy.txt w folderze zdającego, zrzut całego ekranu z wynikiem - kw1.jpg. To samo zapytanie wyśle później skrypt 1.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT czas, kierunek, nr_rejsu, status_lotu FROM przyloty ORDER BY czas;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: przyloty między 10:00 a 10:59
Kryteria:
R.1.4 Utworzono zapytanie 2 zliczające przyloty, które odbyły się w godzinach 10:00 – 10:59. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT COUNT(*) FROM przyloty WHERE czas LIKE "10%"; możliwe inne warianty, np. z BETWEEN oraz wynik działania zapytania udokumentowano zrzutem, na którym jest widoczna wartość 7, wynikająca z zadanego zapytania
ok. 2 min
Polecenie z arkusza
Zapytanie 2: zliczające przyloty, które odbyły się w godzinach 10:00 ÷ 10:59
SELECT COUNT(*) - funkcja agregująca: zamiast wierszy zwraca ich liczbę,
FROM przyloty,
WHERE czas BETWEEN '10:00:00' AND '10:59:59' - kolumna czas ma typ TIME, więc porównujesz ją z godzinami; BETWEEN obejmuje oba końce przedziału.
Wynik: 7 (wszystkie przyloty poza warszawskim z 09:45). Klucz przyjmuje też zapis WHERE czas LIKE '10%' - porównanie z wzorcem tekstowym działa, bo czas jest wtedy zamieniany na napis 10:03:00. Zrzut: kw2.jpg.
Typowe błędy
BETWEEN '10:00' AND '10:59' pomija przyloty z 10:59:30 - koniec przedziału to 10:59:59. COUNT(czas) zamiast COUNT(*) też jest poprawne, bo żaden przylot nie ma pustego czasu.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT czas, kierunek, nr_rejsu, status_lotu FROM przyloty ORDER BY czas;-- Zapytanie 2SELECT COUNT(*) FROM przyloty WHERE czas BETWEEN '10:00:00' AND '10:59:59';
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: relacja przyloty - samoloty
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające jedynie pola nr_rejsu z tabeli przyloty oraz typ z tabeli samoloty , dla lotów których kierunkiem jest Warszawa. Wykorzystano relację. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nr_rejsu, samoloty.typ FROM przyloty JOIN samoloty ON przyloty.samoloty_id = samoloty.id WHERE kierunek = "Warszawa"; możliwe INNER JOIN lub bez JOIN (porównanie kluczy w warunku) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest dokładnie jeden rekord jedynie z danymi: W63454, Boening 737
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pola nr_rejsu z tabeli przyloty oraz typ z tabeli samoloty dla lotów, których kierunkiem jest Warszawa; zapytanie wykorzystuje relację
SELECT nr_rejsu, typ - numer rejsu jest w tabeli przyloty, typ samolotu w tabeli samoloty,
FROM przyloty JOIN samoloty - złączenie dwóch tabel,
ON przyloty.samoloty_id = samoloty.id - warunek relacji z obrazu 1: klucz obcy przylotu wskazuje klucz główny samolotu,
WHERE kierunek = 'Warszawa'.
Wynik: jeden wiersz - W63454, Boening 737 (pisownia „Boening” pochodzi z bazy CKE). Zrzut: kw3.jpg.
Typowe błędy
Bez warunku ON (samo FROM przyloty, samoloty WHERE kierunek = ...) baza łączy przylot z każdym samolotem - wynik ma 4 wiersze zamiast jednego. Klucz przyjmuje też porównanie kluczy w WHERE zamiast JOIN.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT czas, kierunek, nr_rejsu, status_lotu FROM przyloty ORDER BY czas;-- Zapytanie 2SELECT COUNT(*) FROM przyloty WHERE czas BETWEEN '10:00:00' AND '10:59:59';-- Zapytanie 3SELECT nr_rejsu, typ FROM przyloty JOIN samoloty ON przyloty.samoloty_id = samoloty.id WHERE kierunek = 'Warszawa';
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: zmiana statusu odlotu LX5673
Kryteria:
R.1.6 Utworzono zapytanie 4 aktualizujące w tabeli odloty pole status_lotu na: „opoznienie 20 min” dla lotu o numerze rejsu LX5673. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE odloty SET status_lotu="opoznienie 20 min" WHERE nr_rejsu="LX5673"; oraz wynik działania zapytania udokumentowano zrzutem na którym widoczne jest poprawne zapytanie lub widoczne są rekordy ze zmienionymi danymi
ok. 2 min
Polecenie z arkusza
Zapytanie 4: aktualizujące w tabeli odloty pole status_lotu na: „opoznienie 20 min” dla lotu o numerze rejsu LX5673
Uwaga na tabelę: ta jedyna kwerenda dotyczy odlotów, nie przylotów.
UPDATE odloty - która tabela,
SET status_lotu = 'opoznienie 20 min' - nowa wartość pola, napis w apostrofach (bez polskich liter, dosłownie jak w arkuszu),
WHERE nr_rejsu = 'LX5673' - którego wiersza dotyczy zmiana (lot na Maltę).
phpMyAdmin odpowiada „1 wiersz zmieniony” - zrzut kw4.jpg z zapytaniem i komunikatem. Plik kwerendy.txt ma komplet czterech zapytań. Tablica przylotów na stronie się nie zmienia, bo zmieniony został odlot.
Typowe błędy
UPDATEbez WHERE zmieniłby status wszystkich dziesięciu odlotów. Przed wykonaniem przeczytaj zapytanie jeszcze raz - phpMyAdmin nie ma przycisku „cofnij”.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT czas, kierunek, nr_rejsu, status_lotu FROM przyloty ORDER BY czas;-- Zapytanie 2SELECT COUNT(*) FROM przyloty WHERE czas BETWEEN '10:00:00' AND '10:59:59';-- Zapytanie 3SELECT nr_rejsu, typ FROM przyloty JOIN samoloty ON przyloty.samoloty_id = samoloty.id WHERE kierunek = 'Warszawa';-- Zapytanie 4UPDATE odloty SET status_lotu = 'opoznienie 20 min' WHERE nr_rejsu = 'LX5673';
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-19 · po tym etapie masz 15 z 37 kryteriów (pkt)
Krok 8: Grafika: wysokość 200 px z przezroczystością
Kryteria:
R.2.1 Plik zad5.png przeskalowano z zachowaniem proporcji do wysokości 200 px, odpowiadająca temu szerokość wynosi 305 px (± 5 px); przezroczystość została zachowana
ok. 2 min
Polecenie z arkusza
Plik zad5.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 200 px. Należy zachować przezroczystość obrazu
Oryginał ma 457 × 300 px i przezroczyste tło (kanał alfa). W GIMP-ie: Obraz → Skaluj obraz, łańcuch między szerokością a wysokością zamknięty (to jest „zachowanie proporcji”), wysokość 200 px - szerokość przelicza się sama: 457 × 200 / 300 = 304,7, czyli 305 px (klucz: 305 px ±5).
Zapis: Plik → Nadpisz zad5.png albo Eksportuj jako z formatem PNG - tylko on zachowa przezroczystość (JPEG zamieniłby tło na białe albo czarne).
Typowe błędy
Eksport do JPG albo spłaszczenie obrazu (Obraz → Spłaszcz) usuwa przezroczystość - na niebieskim tle strony pojawi się białe pole wokół samolotu.
Podgląd strony po tym kroku
Krok 9: Plik lotnisko.php
ok. 1 min
Polecenie z arkusza
Składa się ze strony o nazwie lotnisko.php
Plik lotnisko.php w folderze zdającego, obok zad5.png. Rozszerzenie .php, bo dojdą skrypty - na razie to czysty HTML. <!DOCTYPE html> oznacza HTML5, a lang="pl" mówi przeglądarce i czytnikom ekranu, że treść jest po polsku (arkusz tego nie wymaga, ale to jedna krótka linia).
R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie lotnisko oraz zastosowano właściwy standard kodowania polskich znaków
ok. 1 min
Polecenie z arkusza
Zastosowany właściwy standard kodowania polskich znaków
<meta charset="UTF-8"> jako pierwsza rzecz w <head>. Plik trzeba też zapisać w UTF-8 (w Notepad++ menu Kodowanie). Klucz ocenia nazwę pliku i kodowanie razem (R.2.2) - lotnisko.html albo index.php to strata punktu.
R.3.4 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl5.css formatowanie pochodzi jedynie z tego arkusza (poza pochyleniem i pogrubieniem) 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 styl5.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl5.css"> w <head>. Nazwa ma w sobie cyfrę: styl5.css. Plik stylów powstanie po HTML-u.
Typowe błędy
Klucz uznaje R.3.4 tylko przy działającym połączeniu, w którym wszystkie selektory trafiają w bloki - kropka zamiast # (albo literówka w identyfikatorze) też odbiera punkt.
Krok 13: Sześć bloków: trzy banera, główny, dwa stopki
Kryteria:
R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: trzy bloki banera, blok główny, dwa bloki stopki. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: trzy bloki banera, poniżej blok główny, następnie dwa bloki stopki. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Sześć znaczników <section> w kolejności z obrazu 2. Bloki różnią się wymiarami, więc każdy dostaje identyfikator (nazwy po angielsku - arkusz ich nie narzuca): bloki banera logo, title i links, blok główny main, bloki stopki status (tu skrypt 2 wypisze komunikat o ciasteczku) i author. Na razie stoją jeden pod drugim; obok siebie ustawi je CSS.
Krok 14: Pierwszy blok banera: logo z tekstem alternatywnym
Kryteria:
R.2.6 W pierwszym bloku banera umieszczono obraz zad5.png z tekstem alternatywnym: "logo lotnisko", gdy obraz nie istnieje powinien wyświetlać się tekst alternatywny
ok. 1 min
Polecenie z arkusza
Zawartość pierwszego bloku banera: obraz zad5.png z tekstem alternatywnym „logo lotnisko”
<img> z atrybutami src (przeskalowany plik z folderu zdającego) i alt - tekst, który czytnik ekranu przeczyta zamiast obrazu i który pokaże się, gdy plik się nie wczyta. W HTML5 <img> nie ma znacznika zamykającego ani ukośnika na końcu.
R.3.2 Na stronie umieszczono odnośnik, którego wybranie prowadzi do pliku tekstowego zawierającego kwerendy
R.3.3 Odnośnik otwiera się w nowym oknie lub karcie
ok. 1 min
Polecenie z arkusza
Odnośnik o treści „Pobierz…” otwierający plik kwerendy.txt w nowym oknie
<a href="kwerendy.txt"> prowadzi do pliku zapytań z tego samego folderu (R.3.2), a atrybut target="_blank" otwiera go w nowym oknie albo karcie (R.3.3). Przeglądarka pokaże plik tekstowy wprost - nie trzeba go pobierać.
Typowe błędy
target="blank" (bez podkreślnika) też otwiera nową kartę, ale przy każdym kliknięciu tę samą o nazwie „blank”. Właściwa wartość to _blank.
Krok 18: Blok główny: tabela z wierszem nagłówkowym
Kryteria:
R.2.8 Umieszczono w tabeli wiersz nagłówkowy, zastosowano cztery znaczniki <th> (opcjonalnie <thead> i <td>) oraz ich zamknięcia wewnątrz pierwszego wiersza tabeli
ok. 2 min
Polecenie z arkusza
Zawartość bloku głównego: Tabela o czterech kolumnach. Nagłówki kolumn mają podpisy: „czas”, „kierunek”, „numer rejsu”, „status”
<table>, w nim pierwszy wiersz <tr> z czterema komórkami nagłówkowymi <th> - przeglądarka domyślnie pogrubia je i wyśrodkowuje. Kolejność kolumn jest taka jak pól w zapytaniu 1 (czas, kierunek, numer rejsu, status), więc skrypt wstawi komórki po kolei. Podpisy wpisujesz małymi literami, jak w arkuszu - na obrazie 2 są wielkie, bo zamieni je CSS.
Kolejne wiersze („Zawartość tabeli jest wypełniana skryptem 1”) wstawi skrypt PHP przed </table>.
Zawartość drugiego bloku stopki: tekst: „Autor: ”, dalej wstawiony numer PESEL zdającego
Na egzaminie po „Autor: ” wpisujesz swój numer PESEL. W tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora: Bartosz Bryniarski. Pierwszy blok stopki zostaje pusty - wypełni go skrypt 2 („Zawartość pierwszego bloku stopki: efekt działania skryptu 2”).
Kroki 20-30 · po tym etapie masz 26 z 37 kryteriów (pkt)
Krok 20: Plik styl5.css: pierwszy i trzeci blok banera
ok. 1 min
Polecenie z arkusza
Cechy formatowania CSS: Dla pierwszego i trzeciego bloku banera: szerokość 25%, wysokość 200 px
Nowy plik styl5.css w folderze zdającego - od teraz każda reguła trafia tylko tutaj, bez atrybutów style w HTML-u. Selektory identyfikatorów z krzyżykiem #, dwa rozdzielone przecinkiem dostają wspólną regułę. Wysokość 200 px to dokładnie wysokość logo.
styl5.cssCSSnowy plik
#logo, #links {width: 25%;height: 200px;}
Podgląd strony po tym kroku (lotnisko.php)
Krok 21: Drugi blok banera: wyśrodkowanie, szerokość, wysokość, czcionka
Kryteria:
R.4.4 Ustawiono wysokość wszystkich bloków banera na 200px
ok. 1 min
Polecenie z arkusza
Dla drugiego bloku banera: wyrównanie tekstu do środka, szerokość 50%, wysokość 200 px, rozmiar czcionki 250%
Szerokości banera sumują się do 100% (25 + 50 + 25), a wszystkie trzy bloki mają po 200 px wysokości (R.4.4). font-size: 250% liczy się od czcionki rodzica, a nagłówek <h1> ma domyślnie 2em - jest więc dwa razy większy od tekstu bloku.
Krok 22: Blok główny: tło, marginesy wewnętrzne, wielkie litery
ok. 2 min
Polecenie z arkusza
Dla bloku głównego: tło koloru RGB 0, 0, 128; marginesy wewnętrzne 60 px, tekst wielkimi literami (niezależnie od tego jak tekst został zapisany w HTML, wymagana transformacja na wielkie litery)
Kolor zapisany funkcją rgb(0, 0, 128) - granat (klucz przyjmuje też #000080). padding: 60px odsuwa tabelę od brzegów bloku ze wszystkich stron. text-transform: uppercase to „transformacja na wielkie litery”: w HTML-u i w bazie tekst zostaje bez zmian, a przeglądarka wyświetla go wielkimi literami - dlatego „Warszawa” z bazy wygląda na obrazie 2 jak WARSZAWA.
Typowe błędy
Przepisanie tekstu wielkimi literami w HTML-u nie spełnia wymagania - arkusz wprost żąda transformacji w CSS, a dane z bazy i tak przyszłyby małymi literami.
Krok 24: Drugi blok stopki: do prawej, szerokość, margines górny
Kryteria:
R.4.6 Ustawiono wyrównanie tekstu do środka dla drugiego bloku banera, pierwszego bloku stopki oraz wyrównanie do prawej strony dla drugiego bloku stopki
ok. 1 min
Polecenie z arkusza
Dla drugiego bloku stopki: wyrównanie tekstu do prawej strony, szerokość 50%, margines wewnętrzny górny: 100 px (tylko górny)
„Tylko górny” to padding-top - właściwość jednej krawędzi. Napis „Autor” zjeżdża dzięki niemu na wysokość dołu paragrafu z lewego bloku, jak na obrazie 2. Wyrównania tekstu banera i obu bloków stopki są gotowe (R.4.6).
Typowe błędy
Skrót padding: 100px ustawiłby 100 px ze wszystkich czterech stron - blok miałby wtedy 50% + 200 px szerokości i nie zmieściłby się obok pierwszego.
Reguła body na początku pliku - dotyczy całej strony i dziedziczą ją wszystkie bloki. rgb(30, 144, 255) to jasny niebieski (nazwa CSS DodgerBlue, szesnastkowo #1E90FF), color: white - biały tekst. Tło bloku głównego (granat) już jest, więc R.4.2 ma oba kolory.
R.4.10 Ustawiono rozmiar czcionki 250% dla drugiego bloku banera, 200% dla selektora p oraz tekst wielkimi literami (text-transform: uppercase;) dla bloku głównego
Selektor znacznika p - jedyny paragraf na stronie wypisze skrypt 2 w pierwszym bloku stopki. Skrót border: 1px solid rgb(192, 192, 192) zawiera grubość, rodzaj linii (solid = ciągła) i kolor - jasnoszary (#C0C0C0, nazwa silver). Rozmiary czcionek banera, paragrafu i wielkie litery bloku głównego są ustawione (R.4.10).
Krok 28: Tabela: szerokość i połączone obramowanie
Kryteria:
R.4.5 Ustawiono szerokość pierwszego i trzeciego bloku banera na 25%, drugiego bloku banera oraz obu bloków stopki na 50% oraz szerokość tabeli na 100%
ok. 1 min
Polecenie z arkusza
Dla selektora tabeli: szerokość 100%, obramowanie tabeli i komórki ma być połączone (collapse)
Tabela zajmuje całą szerokość bloku głównego (wewnątrz marginesów 60 px). border-collapse: collapse sprawia, że sąsiednie komórki mają jedną wspólną linię zamiast dwóch z odstępem. Szerokości banera, stopki i tabeli są gotowe (R.4.5).
R.4.7 Ustawiono marginesy wewnętrzne (padding) na: 60px dla bloku głównego, 20px dla selektora paragrafu, 10px dla selektora td lub th oraz jedynie margines wewnętrzny górny (padding-top) 100px dla drugiego bloku stopki
R.4.8 Ustawiono obramowanie selektora p oraz td lub th: 1px linią ciągłą rgb(192, 192, 192) oraz połączone obramowanie dla selektora tabeli (border-collapse: collapse;)
ok. 1 min
Polecenie z arkusza
Dla selektora komórki danych i komórki nagłówkowej tabeli: obramowanie 1 px, linią ciągłą o kolorze RGB 192, 192, 192; marginesy wewnętrzne 10 px
Dwa selektory - td (komórka danych) i th (komórka nagłówkowa) - z jedną regułą. Obramowanie (R.4.8) i marginesy wewnętrzne wszystkich elementów (R.4.7) są ustawione.
R.3.1 Wygląd układu bloków po uruchomieniu strony w przeglądarce jest w pełni zgodny z obrazem 2 w arkuszu egzaminacyjnym
ok. 3 min
Polecenie z arkusza
Podział strony na bloki: trzy bloki banera, poniżej blok główny, następnie dwa bloki stopki. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Pięć bloków o zadanej szerokości dostaje float: left: trzy bloki banera stają w jednym rzędzie (25% + 50% + 25%), a dwa bloki stopki - w drugim (50% + 50%). Blok główny nie pływa i ma clear: both - zaczyna się dopiero pod banerem i zajmuje całą szerokość, a bloki stopki ustawiają się pod nim.
Klucz R.3.1 ocenia wygląd w przeglądarce, więc dowolny sposób daje punkt - wersja nowoczesna pokazuje ten sam układ na flex.
Typowe błędy
Bloki o sumie szerokości 100% nie mogą mieć bocznych marginesów, padding ani obramowań - każdy piksel więcej zepchnie ostatni blok rzędu niżej. Dlatego blok #author ma wyłącznie padding-top.
Kroki 31-38 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 31: Skrypt 1: połączenie z bazą egzamin
Kryteria: ,
R.5.1 Skrypt napisano w języku PHP i zawiera on co najmniej jedną instrukcję poprawną składniowo
R.5.2 Skrypt 1 realizuje połączenie z serwerem bazy danych i wybór bazy egzamin
ok. 3 min
Polecenie z arkusza
Oba skrypty napisane w języku PHP, w pliku lotnisko.php. Działanie skryptu 1: Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie egzamin
Skrypt 1 ma wypełnić tabelę, więc jego blok PHP stoi wewnątrz<table>, zaraz pod wierszem nagłówkowym - to, co wypisze, trafi dokładnie tam. Kod piszesz między <?php a ?>; serwer wykona go, zanim strona trafi do przeglądarki.
Pierwsza instrukcja: mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy egzamin (połączenie i wybór bazy w jednej funkcji). Połączenie trafia do zmiennej $connection, z której skorzystają kolejne funkcje (R.5.1, R.5.2).
Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2) - na razie wygląda jak wcześniej. Stronę sprawdzasz przez http://localhost/…, a nie otwierając plik z dysku: przeglądarka sama nie wykona PHP.
mysqli_query wysyła do bazy zapytanie 1 przepisane z kwerendy.txt (R.5.4). Wynik - zbiór ośmiu wierszy - trafia do zmiennej $result. Samo zapytanie niczego jeszcze nie wypisuje: wiersze trzeba z wyniku pobrać.
Krok 33: Skrypt 1: pętla po wierszach i pierwsza komórka
ok. 3 min
Polecenie z arkusza
Dane otrzymane z bazy są umieszczane w kolejnych wierszach tabeli, w odpowiednich komórkach, tak jak na Obrazie 2
mysqli_fetch_row($result) pobiera kolejny wiersz wyniku jako tablicę numerowaną od zera: $row[0] to czas, $row[1] kierunek, $row[2] numer rejsu, $row[3] status - w kolejności pól z zapytania,
while powtarza to, dopóki funkcja zwraca wiersz; po ostatnim zwraca null i pętla się kończy,
echo wypisuje wiersz tabeli <tr> z pierwszą komórką <td>. Napis jest w cudzysłowie "…", więc PHP podstawia w nim wartość $row[0], a \n dokłada znak nowej linii (czytelne źródło strony).
Podgląd: osiem wierszy z samym czasem, od 09:45:00 - kolejne kolumny dojdą w następnym kroku.
R.2.7 W bloku głównym umieszczono tabelę o czterech kolumnach, zastosowano znaczniki <table>, <tr>, <td> i ich zamknięcia, tabela generowana skryptem lub HTML
R.5.5 Dane otrzymane z bazy są wyświetlane w kolejnych wierszach tabeli, w odpowiednich komórkach, tak jak na Obrazie 2
ok. 2 min
Polecenie z arkusza
Dane otrzymane z bazy są umieszczane w kolejnych wierszach tabeli, w odpowiednich komórkach, tak jak na Obrazie 2
Do wiersza dochodzą trzy kolejne komórki: kierunek, numer rejsu i status. Każdy wiersz tabeli ma teraz cztery komórki <td> pod czterema nagłówkami (R.2.7), a dane stoją w odpowiednich kolumnach - jak na obrazie 2 (R.5.5). Puste statusy z bazy dają puste komórki.
R.5.7 Gdy odwiedzający jest na stronie pierwszy raz zakładane jest ciasteczko z czasem trwania 2 godziny od utworzenia, np. time() + 7200
ok. 3 min
Polecenie z arkusza
Działanie skryptu 2: W oparciu o mechanizm ciasteczek skrypt wypisuje na stronie komunikaty: Gdy odwiedzający wejdzie na stronę pierwszy raz zakładane jest ciasteczko z czasem trwania 2 godziny od utworzenia oraz wyświetlany jest w paragrafie, czcionką pogrubioną, komunikat: „Dzień dobry! Strona lotniska używa ciasteczek”
Ciasteczko to mała porcja danych, którą serwer zapisuje w przeglądarce, a przeglądarka odsyła przy każdym kolejnym wejściu na stronę. W PHP przysłane ciasteczka są w tablicy $_COOKIE.
isset($_COOKIE['lotnisko']) - prawdziwe, gdy przeglądarka przysłała ciasteczko o nazwie lotnisko, czyli gość już tu był. Wykrzyknik ! odwraca warunek: blok wykona się przy pierwszej wizycie,
setcookie('lotnisko', 'odwiedzono', time() + 7200) - nazwa, wartość i czas wygaśnięcia. Funkcja time() zwraca bieżący czas w sekundach, a 2 godziny to 2 × 60 × 60 = 7200 sekund (R.5.7).
Ten blok stoi na samej górze pliku, przed <!DOCTYPE html>. Opis funkcji na ostatniej stronie arkusza mówi wprost: ciasteczko jest nagłówkiem HTTP, więc trzeba je wysłać przed jakąkolwiek treścią strony. Komunikaty wypisze drugi blok skryptu, w stopce. Podgląd bez zmian.
Typowe błędy
time() + 2 albo samo 7200 (bez time()) to data z 1970 roku - ciasteczko wygaśnie od razu i każda wizyta będzie „pierwsza”.
Krok 37: Skrypt 2: komunikat przy pierwszej wizycie
Kryteria:
R.2.5 W drugim bloku banera zapisano nagłówek h1: "Przyloty", w trzecim bloku banera nagłówek h3: "przydatne linki" oraz w pierwszym bloku stopki zapisano paragraf (w kodzie HTML lub skrypcie)
ok. 2 min
Polecenie z arkusza
Gdy odwiedzający wejdzie na stronę pierwszy raz zakładane jest ciasteczko z czasem trwania 2 godziny od utworzenia oraz wyświetlany jest w paragrafie, czcionką pogrubioną, komunikat: „Dzień dobry! Strona lotniska używa ciasteczek”
W pierwszym bloku stopki drugi blok PHP z tym samym warunkiem: ciasteczka jeszcze nie ma, więc echo wypisuje komunikat w paragrafie <p> (R.2.5 - paragraf w pierwszym bloku stopki), a pogrubienie daje znacznik <b>.
Ten sam warunek działa w obu blokach, bo setcookie nie zmienia tablicy $_COOKIE w trakcie bieżącego wykonania - ciasteczko wróci od przeglądarki dopiero przy następnym wejściu. Podgląd: pierwsza wizyta, „Dzień dobry! Strona lotniska używa ciasteczek” pogrubionym krojem.
Krok 38: Skrypt 2: komunikat przy kolejnej wizycie
Kryteria: , ,
R.2.9 W pierwszym bloku stopki gdy wyświetlany jest tekst "Dzień dobry!..." czcionka jest pogrubiona lub gdy wyświetlony jest tekst "Witaj ponownie..." czcionka jest pochylona (dowolną metodą)
R.5.6 Skrypt 2 wykorzystuje mechanizm ciasteczek, zastosowano funkcje setcookie, isset oraz tablicę $_COOKIE, zapis musi być poprawny składniowo i logicznie
R.5.8 Gdy odwiedzający jest na stronie pierwszy raz wyświetlany jest komunikat "Dzień dobry! Strona lotniska używa ciasteczek” w przeciwnym wypadku komunikat „Witaj ponownie na stronie lotniska"
ok. 3 min
Polecenie z arkusza
Jeżeli odwiedzający w ciągu 2 godzin od poprzedniego wejścia wejdzie ponownie na stronę wyświetlany jest w paragrafie, czcionką pochyloną, komunikat „Witaj ponownie na stronie lotniska”
Gałąź else - ciasteczko jest, czyli gość wrócił w ciągu 2 godzin. Komunikat w paragrafie, pochylony znacznikiem <i>. Skrypt korzysta z setcookie, isset i $_COOKIE (R.5.6), wypisuje oba komunikaty (R.5.8), a jeden z nich pogrubiony, drugi pochylony (R.2.9).
Sprawdzone na prawdziwym serwerze dwoma wejściami tej samej przeglądarki: pierwsze dało „Dzień dobry! Strona lotniska używa ciasteczek”, drugie - „Witaj ponownie na stronie lotniska”. Podgląd pokazuje drugą wizytę, jak na obrazie 2. W przeglądarce test powtórzysz odświeżeniem strony (F5), a „pierwszą wizytę” - usuwając ciasteczko w narzędziach deweloperskich (F12, karta Aplikacja / Pamięć) albo w oknie prywatnym.
Typowe błędy
setcookie w stopce zamiast na górze pliku zadziała w XAMPP tylko dlatego, że PHP buforuje pierwsze 4 KB strony (output_buffering w php.ini) - przy wyłączonym buforze dostaniesz ostrzeżenie „Cannot modify header information - headers already sent” i ciasteczko się nie zapisze.
Kroki 39-41 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 39: Zabezpieczenie: htmlspecialchars na danych z bazy
ok. 3 min
Polecenie z arkusza
Dane otrzymane z bazy są umieszczane w kolejnych wierszach tabeli, w odpowiednich komórkach, tak jak na Obrazie 2
Skrypt wkleja do strony wszystko, co jest w bazie - także znaczniki HTML. Sprawdzone: status lotu LX3447 zmieniony na opoznienie <s>10</s> 20 min wersja z poprzednich kroków wyświetla jako „opoznienie ~~10~~ 20 min” z przekreśloną liczbą. Przekreślenie jest niegroźne, ale tak samo trafiłby na stronę znacznik <script> - kod JavaScript wykonany u każdego gościa tablicy przylotów (atak XSS). Dane w bazie wpisuje wiele osób i programów, więc traktujesz je jak dane od użytkownika.
Lekarstwo: htmlspecialchars zamienia <, >, & i cudzysłowy na encje (< itd.) - przeglądarka pokazuje je jako tekst. array_map przepuszcza przez tę funkcję wszystkie cztery komórki wiersza naraz. Podgląd: ten sam status widać dosłownie, ze znacznikami jako tekstem. Stara linia zostaje w komentarzu; na egzaminie klucz tego nie sprawdza.
Krok 40: Zabezpieczenie: błąd bazy bez szczegółów serwera
ok. 3 min
Polecenie z arkusza
Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie egzamin
Od PHP 8.1 funkcje mysqli przy błędzie rzucają wyjątek. Sprawdzone: gdy bazy egzamin nie ma (np. na innym komputerze, bez importu), strona urywa się w połowie tabeli, a zamiast reszty pojawia się „Fatal error: Uncaught mysqli_sql_exception: Unknown database 'egzamin'” razem z pełną ścieżką do pliku na serwerze i numerem linii. Takie informacje pomagają włamywaczowi, a gościom strony nic nie mówią.
Cały skrypt 1 trafia do bloku try, a catch (mysqli_sql_exception $exception) łapie błąd i wypisuje jeden wiersz tabeli z neutralnym komunikatem (colspan="4" - komórka na całą szerokość). Reszta strony - stopka i komunikat o ciasteczku - działa dalej. Podgląd: strona uruchomiona bez bazy. Na serwerze produkcyjnym dodatkowo wyłącza się display_errors, a błędy trafiają do dziennika.
Gdy odwiedzający wejdzie na stronę pierwszy raz zakładane jest ciasteczko z czasem trwania 2 godziny od utworzenia
Opis setcookie na ostatniej stronie arkusza wymienia parametr httponly: ciasteczko z tą flagą jest dostępne tylko dla serwera, a skrypty JavaScript na stronie go nie odczytają - wstrzyknięty skrypt (patrz dwa kroki wcześniej) nie wykradnie go. Od PHP 7.3 parametry podaje się czytelniej, jako tablicę opcji: expires (te same time() + 7200), httponly i samesite - Lax sprawia, że przeglądarka nie dołącza ciasteczka do żądań wysyłanych z obcych stron.
Sprawdzone w zapisie ciasteczek przeglądarki testowej: przed zmianą zwykły wpis lotnisko, po zmianie wpis z oznaczeniem HttpOnly. Dwie zasady na przyszłość: w ciasteczku nie zapisuje się danych poufnych (arkusz też to mówi), a jego wartości nie wolno ufać - gość może ją dowolnie zmienić. Tu skrypt sprawdza tylko, czy ciasteczko istnieje, więc podmiana niczego nie psuje. Podgląd: druga wizyta, jak na obrazie 2.
Krok 42 · po tym etapie masz 37 z 37 kryteriów (pkt)
Krok 42: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny, zapisz go w folderze z numerem PESEL, jako przeglądarka.txt. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….
W folderze zdającego muszą być: import.png, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, lotnisko.php, przeglądarka.txt, styl5.css i przeskalowany zad5.png (plik egzamin.sql może zostać). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.
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.