Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-03-22.06-SGCzerwiec 2022 · 44 kroki · ok. 84 min · 36 kryteriów z klucza
Rozwiązanie krok po kroku: Opinie klientów hurtowni spożywczej (Wersja podstawowa)
Fragment aplikacji hurtowni z opiniami klientów: baza hurtownia zaimportowana z pliku baza.sql (tabele klienci, opinie, typy) i cztery zapytania - trzech klientów z największą liczbą punktów (ORDER BY … DESC LIMIT 3), liczba klientów każdego typu (COUNT z GROUP BY), opinie klientów złotych i platynowych (JOIN) oraz nowa kolumna adres (ALTER TABLE). Do tego zdjęcie ewa.jpg przeskalowane do szerokości 150 px, strona opinie.php z banerem, przewijanym blokiem opinii i czterema blokami stopki, arkusz styl3.css z cieniem bloków i zaokrąglonymi zdjęciami oraz dwa skrypty PHP: bloki opinii i lista najlepszych klientów.
To arkusz EE.09 z czerwca 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. 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ą. Style bloków opinii są dopisane po skryptach, bo dopiero skrypt tworzy te bloki i dopiero wtedy w podglądzie widać efekt. Skrypty są napisane najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzone na prawdziwym ataku (skrypt wpisany w treść opinii i w nazwę zdjęcia) i na awarii bazy - i zabezpieczone.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: siatka CSS, zmienne CSS, PDO z obsługą błędów na górze pliku i htmlspecialchars przy każdym wypisaniu - obie wersje są zgodne z kluczem.
Baza i zdjęcia pochodzą z oryginalnego archiwum CKE zad3.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 (klucz każe sprawdzać w XAMPP 8.1.2 - użyte funkcje działają w obu wersjach tak samo).
Jak liczą się punkty. Klucz ma 36 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 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 36 kryteriów (pkt)
Krok 1: Folder zdającego i archiwum zad3.zip
ok. 2 min
Polecenie z arkusza
Na pulpicie znajduje się archiwum o nazwie zad3.zip zabezpieczone hasłem: #_Opini3% Archiwum należy rozpakować. Na pulpicie konta Egzamin należy utworzyć folder. Jako nazwy folderu należy użyć numeru zdającego, którym został podpisany arkusz. Rozpakowane pliki należy umieścić w tym folderze.
Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum zad3.zip rozpakowujesz do tego folderu z hasłem #_Opini3% (krzyżyk na początku i procent na końcu należą do hasła, w środku jest cyfra 3, nie litera). W środku: baza.sql i pięć zdjęć klientów - anna.jpg, ewa.jpg, janek.jpg, john.jpg, judy.jpg.
Arkusz zaleca, żeby zdjęcia leżały w tym samym folderze co strona - skrypt wpisze ich nazwy z bazy wprost do atrybutu src. Stronę uruchamiasz przez XAMPP, więc folder kopiujesz też do C:\xampp\htdocs (albo pracujesz w htdocs i na koniec kopiujesz wyniki do folderu zdającego).
Typowe błędy
Pliki zapisane tylko w htdocs nie trafią na płytę - a ocenia się wyłącznie to, co jest na płycie.
Krok 2: XAMPP i pusta baza hurtownia
ok. 2 min
Polecenie z arkusza
Za pomocą narzędzia phpMyAdmin należy wykonać operacje na bazie danych: Utworzenie bazy danych o nazwie: hurtownia z zestawem polskich znaków (np. utf8_unicode_ci)
W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa hurtownia, porównywanie napisów utf8_unicode_ci, Utwórz.
Porównywanie decyduje o tym, jak baza zapisuje i sortuje polskie litery - typy klientów to „zwykły” i „złoty”, a opinie są pełne „ś” i „ż”.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie hurtownia - skrypt PHP wybiera bazę po nazwie (R.5.1).
Krok 3: Import pliku baza.sql i zrzut import.jpg
Kryteria:
R.1.1 Wykonano import tabel do bazy danych hurtownia , czynność udokumentowano plikiem o nazwie import w formacie JPEG
ok. 3 min
Polecenie z arkusza
Import tabel do bazy hurtownia z pliku baza.sql. Czynność należy udokumentować zrzutem ekranu, na którym powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel. Zrzut należy zapisać w formacie JPEG, pod nazwą import. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.
Zaznacz bazę hurtownia w lewym panelu, karta Import, Wybierz plik → baza.sql, Wykonaj. Plik tworzy trzy tabele, wypełnia je danymi i ustawia klucze główne z AUTO_INCREMENT.
Po imporcie na karcie Struktura bazy widać: klienci (9 rekordów), opinie (6) i typy (3). Zrzut całego ekranu z zielonym komunikatem o sukcesie i paskiem zadań zapisujesz jako import.jpg (R.1.1).
Typowe błędy
Ten zrzut ma format JPEG, a zrzuty zapytań - PNG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: trzech klientów z największą liczbą punktów
Kryteria: ,
R.1.2 Zapisano plik tekstowy o nazwie kwerendy zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Utworzono zapytanie 1 wybierające posortowane malejąco według punktów jedynie imię, nazwisko i punkty trzech klientów, których liczba punktów jest najwyższa. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko, punkty FROM klienci ORDER BY punkty DESC LIMIT 3; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie 3 wiersze w kolejności: Jan Nowak 3305, Judy Beck 3055, Ewa Nowakowska 2045
ok. 3 min
Polecenie z arkusza
Zapytania SQL na bazie hurtownia zapisane do pliku kwerendy.txt. Wykonanie kwerend należy udokumentować zrzutami w formacie PNG o nazwach kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające z tabeli Klienci posortowane malejąco według punktów jedynie imię, nazwisko i punkty trzech klientów, których liczba punktów jest najwyższa
Karta SQL bazy hurtownia, zapytanie klauzula po klauzuli:
SELECT imie, nazwisko, punkty - tylko trzy kolumny,
FROM klienci,
ORDER BY punkty DESC - sortowanie według punktów, malejąco (DESC, od największej liczby),
LIMIT 3 - z posortowanej listy tylko trzy pierwsze wiersze, czyli trzech klientów z największą liczbą punktów.
Wynik: Jan Nowak 3305, Judy Beck 3055, Ewa Nowakowska 2045 - jak w kluczu. Zapytanie kopiujesz do nowego pliku kwerendy.txt (R.1.2), a cały ekran zapisujesz jako kw1.png (R.1.3). To zapytanie wykona skrypt 2.
Typowe błędy
Bez DESC sortowanie jest rosnące, a LIMIT 3 bierze klientów z najmniejszą liczbą punktów (Kris Smith, Jacek Jackowski, Krystyna Nowakowska).
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT imie, nazwisko, punktyFROM klienciORDER BY punkty DESCLIMIT 3;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: liczba klientów każdego typu
Kryteria:
R.1.4 Utworzono zapytanie 2 wybierające nazwę z tabeli Typy oraz liczbę klientów przypisanych do każdego typu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, COUNT(nazwa) FROM klienci JOIN typy ON Typy_id = typy.id GROUP BY nazwa; (możliwe COUNT(*), GROUP BY(Typy_id), GROUP BY (Typy.id), porównanie kluczy w WHERE) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 3 wiersze: platynowy 2, złoty 3, zwykły 4
ok. 3 min
Polecenie z arkusza
Zapytanie 2: wybierające nazwę z tabeli Typy oraz liczbę klientów przypisanych do każdego typu. Należy posłużyć się relacją
„Posłużyć się relacją” znaczy połączyć tabele po kluczach: pole Typy_id w tabeli klienci wskazuje id w tabeli typy.
SELECT nazwa, COUNT(*) - nazwa typu i funkcja agregującaCOUNT, która liczy wiersze,
FROM typy JOIN klienci ON typy.id = klienci.Typy_id - każdy klient dostaje swój typ,
GROUP BY nazwa - wiersze z tą samą nazwą typu tworzą jedną grupę, a COUNT(*) liczy klientów w każdej grupie osobno.
Bez GROUP BY funkcja COUNT(*) liczy wszystkich klientów naraz - wynik to jeden wiersz z liczbą 9 i przypadkową nazwą typu.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT imie, nazwisko, punktyFROM klienciORDER BY punkty DESCLIMIT 3;-- Zapytanie 2SELECT nazwa, COUNT(*)FROM typyJOIN klienci ON typy.id = klienci.Typy_idGROUP BY nazwa;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: zdjęcia, imiona i opinie klientów typu 2 i 3
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające jedynie pola zdjecie, imie z tabeli klienci oraz odpowiadające im pole opinia z tabeli opinie dla klientów, których typ ma id o wartości 2, 3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zdjecie, imie, opinia FROM klienci JOIN opinie ON klienci.id = klienci_id WHERE Typy_id=2 OR Typy_id=3; (lub porównanie kluczy po WHERE) oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie 5 wierszy, jedynie pola zdjecie, imie, opinia dla imion: Anna, Ewa, Jan, John, Judy
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pola zdjecie, imie z tabeli Klienci oraz odpowiadające im pole opinia z tabeli opinie dla klientów, których typ ma id o wartościach 2, 3. Należy posłużyć się relacją
Relacja tabel klienci i opinie: pole Klienci_id w tabeli opinie wskazuje id klienta.
SELECT zdjecie, imie, opinia - dwie kolumny z klienci, jedna z opinie,
FROM klienci JOIN opinie ON klienci.id = opinie.Klienci_id - każda opinia z jej autorem,
WHERE Typy_id IN (2, 3) - tylko klienci typu 2 (złoty) i 3 (platynowy); IN to krótszy zapis Typy_id = 2 OR Typy_id = 3.
Wynik: 5 wierszy - Anna, Ewa, Jan, John i Judy z nazwami plików zdjęć i treścią opinii. Krystyna też ma opinię, ale jest klientką typu 1. Zrzut: kw3.png (R.1.5). To zapytanie wykona skrypt 1.
Typowe błędy
WHERE Typy_id = 2 AND Typy_id = 3 nie zwraca nic - klient ma jeden typ, więc nie może mieć naraz obu. Potrzebne jest OR albo IN.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT imie, nazwisko, punktyFROM klienciORDER BY punkty DESCLIMIT 3;-- Zapytanie 2SELECT nazwa, COUNT(*)FROM typyJOIN klienci ON typy.id = klienci.Typy_idGROUP BY nazwa;-- Zapytanie 3SELECT zdjecie, imie, opiniaFROM klienciJOIN opinie ON klienci.id = opinie.Klienci_idWHERE Typy_id IN (2, 3);
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowa kolumna adres
Kryteria:
R.1.6 Utworzono zapytanie 4 dodające do tabeli klienci kolumnę o nazwie adres i typie napisowym, maksymalnie 50-znakowym. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE klienci ADD adres VARCHAR(50); (lub ADD COLUMN, typ text jest błędem) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest komunikat o pomyślnie wykonanym zapytaniu lub tabela z dodaną kolumną
ok. 2 min
Polecenie z arkusza
Zapytanie 4: dodające do tabeli Klienci kolumnę o nazwie adres i typie napisowym, maksymalnie 50-znakowym
To zapytanie zmienia strukturę tabeli, nie dane:
ALTER TABLE klienci - modyfikacja istniejącej tabeli,
ADD adres VARCHAR(50) - nowa kolumna adres; typ VARCHAR(50) to napis o zmiennej długości, najwyżej 50 znaków.
phpMyAdmin odpowiada komunikatem „MySQL zwrócił pusty wynik (zero wierszy)”, a na karcie Struktura tabeli klienci kolumna adres stoi na końcu, z wartościami NULL. Zrzut: kw4.png (R.1.6). Plik kwerendy.txt ma komplet czterech zapytań.
Typowe błędy
Klucz uznaje typ TEXT za błąd - nie ma limitu 50 znaków. Zapytanie wykonane drugi raz kończy się błędem #1060 „Zdublowana nazwa kolumny” - kolumna już istnieje.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT imie, nazwisko, punktyFROM klienciORDER BY punkty DESCLIMIT 3;-- Zapytanie 2SELECT nazwa, COUNT(*)FROM typyJOIN klienci ON typy.id = klienci.Typy_idGROUP BY nazwa;-- Zapytanie 3SELECT zdjecie, imie, opiniaFROM klienciJOIN opinie ON klienci.id = opinie.Klienci_idWHERE Typy_id IN (2, 3);-- Zapytanie 4ALTER TABLE klienci ADD adres VARCHAR(50);
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-22 · po tym etapie masz 13 z 36 kryteriów (pkt)
Krok 8: Zdjęcie ewa.jpg: szerokość 150 px z zachowaniem proporcji
Kryteria:
R.2.1 Obraz w pliku ewa .jpg przeskalowano z zachowaniem proporcji do szerokości 150 px, odpowiadająca temu wysokość wynosi 200 px (± 2 px)
ok. 2 min
Polecenie z arkusza
Cechy grafiki ewa.jpg: Przeskalowana z zachowaniem proporcji do szerokości 150 px
Cztery zdjęcia z archiwum mają już 150 × 200 px, a ewa.jpg - 317 × 423 px. W GIMP-ie: Obraz → Skaluj obraz, łańcuch zamknięty (zachowanie proporcji), szerokość 150 px - wysokość wylicza się sama: 423 × 150 / 317 ≈ 200 px. Plik → Wyeksportuj jako pod tą samą nazwą ewa.jpg (R.2.1).
Teraz wszystkie pięć zdjęć ma ten sam rozmiar, więc bloki opinii będą równe.
Typowe błędy
Przy otwartym łańcuchu wysokość zostaje 423 px i zdjęcie jest ściśnięte w poziomie. Plik → Zapisz zapisuje format .xcf - do JPEG służy Wyeksportuj jako.
Podgląd strony po tym kroku
Krok 9: Plik opinie.php
Kryteria:
R.2.2 Witrynę internetową zapisano w pliku o nazwie opinie.php
ok. 1 min
Polecenie z arkusza
Cechy witryny: Składa się ze strony o nazwie opinie.php
W edytorze zaznaczającym składnię tworzysz plik opinie.php w folderze zdającego (R.2.2) - na razie szkielet HTML: <html>, w nim <head> i <body>. Rozszerzenie .php, bo dojdą skrypty. Dopóki w pliku nie ma kodu PHP, podgląd pokazuje go jak zwykłą stronę.
opinie.phpPHPnowy plik
<html><head></head><body></body></html>
Podgląd strony po tym kroku (opinie.php)
Krok 10: Deklaracja HTML5
ok. 1 min
Polecenie z arkusza
Zapisana w języku HTML5
<!DOCTYPE html> w pierwszej linii pliku. Bez niej przeglądarka przechodzi w tryb zgodności ze starymi stronami i inaczej liczy wysokości bloków.
R.2.3 Zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> oraz zadeklarowano dla witryny język polski (np. lang = 'pl')
ok. 1 min
Polecenie z arkusza
Zadeklarowany język witryny: polski
Atrybut lang="pl" w znaczniku <html> - przeglądarka i czytnik ekranu wiedzą, w jakim języku jest tekst. Deklaracja HTML5, kodowanie i język są gotowe (R.2.3).
R.3.3 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl3.css , formatowanie 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 styl3.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl3.css"> w <head>. Plik stylów powstanie po HTML-u; całe formatowanie strony ma pochodzić z niego (R.3.3).
Typowe błędy
Klucz odbiera R.3.3 także wtedy, gdy choć jeden selektor nie trafia w swój blok (np. kropka zamiast #).
Krok 15: Bloki: baner, główny i cztery bloki stopki
Kryteria:
R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, główny i cztery bloki stopki. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: baner, główny i cztery bloki stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2
Sześć bloków w kolejności z obrazu 2: baner <header>, blok główny <main> i cztery bloki stopki <footer> (R.2.5). Znacznik <footer> może wystąpić na stronie wiele razy, a wszystkie cztery bloki mają ten sam styl - CSS obejmie je jednym selektorem footer, bez klas i identyfikatorów. Na razie bloki stoją jeden pod drugim; cztery bloki stopki obok siebie ustawi CSS.
Krok 20: Drugi blok stopki: nagłówek i lista numerowana
ok. 1 min
Polecenie z arkusza
Zawartość drugiego bloku stopki: Nagłówek trzeciego stopnia o treści: „Nasi top klienci” Lista numerowana (uporządkowana), a w niej efekt działania skryptu 2
<h3> i pusta lista <ol> (ordered list - numerowana). Elementy <li> wypisze skrypt 2, więc w HTML-u lista zostaje pusta - podgląd pokazuje na razie sam nagłówek.
Kroki 23-29 · po tym etapie masz 18 z 36 kryteriów (pkt)
Krok 23: Plik styl3.css: krój dla wszystkich selektorów
Kryteria:
R.4.1 Ustawiono domyślną wartość dla wszystkich selektorów stylu CSS (*): krój czcionki Tahoma, sans-serif (czcionka Tahoma jako pierwsza)
ok. 1 min
Polecenie z arkusza
Styl CSS zdefiniowany w całości w zewnętrznym pliku o nazwie styl3.css. Domyślna wartość dla wszystkich selektorów stylu CSS: krój czcionki Tahoma, w przypadku braku sans-serif
Plik styl3.css obok opinie.php. Selektor * (gwiazdka) obejmuje każdy element strony. Tahoma, sans-serif - najpierw Tahoma, a gdy jej nie ma w systemie, dowolny krój bezszeryfowy (R.4.1).
Krok 25: Blok główny: tło Seashell, wysokość i przewijanie
ok. 2 min
Polecenie z arkusza
Dla bloku głównego: kolor tła Seashell, wysokość 500 px, paski przewijania dodawane są, gdy zawartość bloku jest większa od jego rozmiaru
Wysokość 500 px jest stała, a pięć bloków opinii zajmie znacznie więcej. overflow: auto dodaje pasek przewijania tylko wtedy, gdy zawartość się nie mieści - dokładnie to opisuje arkusz. overflow: scroll pokazywałby paski zawsze, także pusty poziomy.
Krok 26: Bloki stopki: tło, kolor, szerokość i wysokość
Kryteria: ,
R.4.2 Ustawiono kolor tła Tomato dla banera i wszystkich bloków stopki, Seashell dla bloku głównego
R.4.4 Ustawiono wysokość bloku głównego 500px i wszystkich bloków stopki 160px oraz szerokość wszystkich bloków stopki 25% (width lub grid-template-columns lub flex). Dla bloku głównego ustawiono paski przewijania overflow:auto;
ok. 2 min
Polecenie z arkusza
Wspólne dla wszystkich bloków stopki: kolor tła Tomato, biały kolor czcionki, szerokość 25%, wysokość 160 px
Selektor znacznika footer obejmuje wszystkie cztery bloki naraz. Kolory tła banera, bloku głównego i stopki są gotowe (R.4.2), tak samo wysokości, szerokość bloków stopki i przewijanie bloku głównego (R.4.4). Bloki stopki mają już po 25% szerokości, ale stoją jeden pod drugim.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym, nie należy uwzględniać bloków z opiniami (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float albo display flex albo grid)
ok. 2 min
Polecenie z arkusza
Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2
float: left w regule footer: pierwszy blok staje przy lewej krawędzi, każdy następny zaraz obok poprzedniego - 4 × 25% = 100% szerokości strony. Za stopką nie ma już żadnego bloku, więc clear nie jest potrzebne. Klucz R.3.1 przyjmuje float, flex albo grid; bloków opinii przy tym kryterium nie ocenia.
Typowe błędy
Marginesy albo ramki dodane blokom stopki powiększają je ponad 25% - czwarty blok nie zmieści się w wierszu i spadnie pod spód.
Dla selektorów nagłówka pierwszego i drugiego stopnia: wyrównanie tekstu do środka
Dwa selektory po przecinku dostają ten sam styl. Selektory znaczników h1 i h2 - arkusz zastrzega, że style nagłówków, obrazu i cytatu mają być zapisane wyłącznie selektorami znaczników.
R.4.3 Ustawiono biały kolor czcionki dla banera, wszystkich bloków stopki i odnośnika
ok. 1 min
Polecenie z arkusza
Dla odnośnika: biały kolor czcionki
Odnośnik nie dziedziczy koloru z bloku stopki - przeglądarka ma dla niego własny niebieski, dlatego potrzebna jest osobna reguła a. Biały kolor banera, bloków stopki i odnośnika jest gotowy (R.4.3).
Kroki 30-36 · po tym etapie masz 30 z 36 kryteriów (pkt)
Krok 30: Połączenie z bazą hurtownia
Kryteria:
R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy hurtownia
ok. 3 min
Polecenie z arkusza
Skrypty łączą się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie hurtownia
Dwa skrypty arkusza pracują na jednej bazie, więc połączenie wystarczy otworzyć raz - przed pierwszym z nich. Skrypt 1 stoi w bloku głównym pod nagłówkiem <h2>, dlatego blok PHP z połączeniem zaczyna się właśnie tam.
mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy hurtownia: jedno wywołanie łączy z serwerem i wybiera bazę (R.5.1). Połączenie trafia do zmiennej $connection, z której skorzysta też skrypt 2 w stopce - zmienne PHP żyją przez cały plik.
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.
Krok 31: Skrypt 1: zapytanie 3, blok opinii i zdjęcie
Kryteria: , ,
R.5.3 Przynajmniej jedno zapytanie zostało wysłane do bazy: skrypt 1 - zapytanie 3 lub skrypt 2 - zapytanie 1
R.5.5 Skrypt 1 dla każdego zwróconego wiersza wyświetla obraz, którego nazwa pliku jest pobrana z bazy
R.2.8 W bloku głównym umieszczono przynajmniej jeden obraz z tekstem alternatywnym "klient" (w skrypcie lub HTML)
ok. 4 min
Polecenie z arkusza
Działanie skryptu 1: Wysyła do bazy zapytanie 3. Każdy zwrócony zapytaniem wiersz wypisuje w osobnym bloku opinii, według wzoru: Obraz, którego nazwa pliku została pobrana z bazy danych, z tekstem alternatywnym „klient”
mysqli_query($connection, '…') - zapytanie 3 z kwerendy.txt, w jednej linii (R.5.3),
while ($row = mysqli_fetch_row($result)) - pętla bierze kolejne wiersze wyniku jako tablicę numerowaną od zera: $row[0] to nazwa pliku zdjęcia, $row[1] - imię, $row[2] - opinia (kolejność kolumn z SELECT). Gdy wierszy zabraknie, funkcja zwraca false i pętla się kończy,
każdy wiersz to osobny blok <div class='opinion'> - klasa, bo bloków jest kilka i wszystkie mają ten sam styl (klucz przy R.4.8: identyfikator jest błędem),
w bloku <img src='$row[0]' alt='klient'> - nazwa pliku z bazy w atrybucie src (R.5.5) i tekst alternatywny z arkusza (R.2.8). Napis w echo jest w cudzysłowie, więc PHP podstawia $row[0], a wartości atrybutów są w apostrofach, żeby nie zamykać cudzysłowu.
Podgląd: pięć zdjęć jedno pod drugim - bloki nie mają jeszcze stylu.
Typowe błędy
Zdjęcia muszą leżeć w tym samym folderze co opinie.php - w bazie są same nazwy plików, bez ścieżek. Zdjęcie w podfolderze wymaga zmiany na src='img/$row[0]'.
R.2.9 W bloku głównym umieszczono przynajmniej jeden cytat, zastosowano znacznik <blockquote> lub <q> lub <cite> (w skrypcie lub HTML)
R.5.4 Skrypt 1 dla każdego zwróconego wiersza tworzy blok, w którym znajdują się obraz i tekst
ok. 2 min
Polecenie z arkusza
Cytat (element HTML) zawierający opinię, której treść została pobrana z bazy
<blockquote> to znacznik dłuższego cytatu - tu słowa klienta (R.2.9). Treść opinii z $row[2]. Każdy blok ma teraz obraz i tekst (R.5.4).
Klucz dopuszcza też <q> albo <cite>, ale <q> służy do krótkich cytatów w środku zdania (przeglądarka dokłada cudzysłowy), a <cite> - do tytułu dzieła. Styl cytatu ustawisz później selektorem blockquote.
Krok 33: Skrypt 1: imię klienta w nagłówku czwartego stopnia
Kryteria: ,
R.5.6 Skrypt 1 dla każdego zwróconego wiersza wyświetla opinię oraz imię pobrane z bazy
R.2.6 W banerze zapisano nagłówek h1: "Hurtownia spożywcza", w bloku głównym zapisano nagłówek h2: "Opinie naszych klientów" oraz przynajmniej jeden h4 (w skrypcie lub HTML), w blokach stopki przynajmniej jeden nagłówek h3 "Współpracują z nami" lub "Nasi top klienci", lub "Skontaktuj się", lub "Autor:" oraz paragraf "telefon 111222333"
ok. 2 min
Polecenie z arkusza
Nagłówek czwartego stopnia, a w nim pobrane z bazy imię klienta
<h4> z imieniem z $row[1], pod cytatem. Skrypt 1 wypisuje dla każdego wiersza opinię i imię (R.5.6). Strona ma komplet nagłówków: <h1>, <h2>, <h3> w stopce i <h4> w blokach opinii, a do tego paragraf z telefonem (R.2.6).
Podgląd: pięć opinii - Anna, Ewa, Jan, John i Judy, w kolejności z zapytania 3.
R.5.8 Skrypt 2 wyświetla zwrócone wiersze jako elementy listy
R.2.7 W drugim bloku stopki umieszczono listę numerowaną, zastosowano znaczniki <ol>, <li> (w skrypcie lub HTML)
ok. 3 min
Polecenie z arkusza
Działanie skryptu 2: Wysyła do bazy zapytanie 1 i wypisuje zwrócone wiersze jako elementy listy
Blok PHP wewnątrz<ol> w drugim bloku stopki - skrypt wypisuje same elementy <li>, a lista dookoła jest w HTML-u:
mysqli_query z zapytaniem 1 - trzech klientów z największą liczbą punktów. Wynik nadpisuje zmienną $result ze skryptu 1, który jest już skończony,
ta sama pętla while co w skrypcie 1,
echo "<li>$row[0] $row[1]</li>"; - na razie imię i nazwisko (R.5.8, R.2.7).
Podgląd: lista „1. Jan Nowak, 2. Judy Beck, 3. Ewa Nowakowska” - numery dokłada sama lista <ol>.
opinie.phpPHPzmienione: 6 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Opinie klientów</title> <linkrel="stylesheet"href="styl3.css"></head><body> <header> <h1>Hurtownia spożywcza</h1> </header> <main> <h2>Opinie naszych klientów</h2><?php$connection = mysqli_connect('localhost', 'root', '', 'hurtownia');$result = mysqli_query($connection, 'SELECT zdjecie, imie, opinia FROM klienci JOIN opinie ON klienci.id = opinie.Klienci_id WHERE Typy_id IN (2, 3);');while ($row = mysqli_fetch_row($result)) {echo"<div class='opinion'>";echo"<img src='$row[0]' alt='klient'>";echo"<blockquote>$row[2]</blockquote>";echo"<h4>$row[1]</h4>";echo"</div>"; }?> </main> <footer> <h3>Współpracują z nami</h3> <ahref="http://sklep.pl/">Sklep 1</a> </footer> <footer> <h3>Nasi top klienci</h3> <ol><?php$result = mysqli_query($connection, 'SELECT imie, nazwisko, punkty FROM klienci ORDER BY punkty DESC LIMIT 3;');while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> </footer> <footer> <h3>Skontaktuj się</h3> <p>telefon: 111222333</p> </footer> <footer> <h3>Autor: Bartosz Bryniarski</h3> </footer></body></html>
Podgląd strony po tym kroku (opinie.php)
Krok 35: Skrypt 2: punkty według wzoru
Kryteria:
R.5.7 Skrypt 2 wyświetla zwrócone wiersze według wzoru: „<imie> <nazwisko>, <punkty> pkt.”, gdzie pola <> są pobrane z bazy
ok. 1 min
Polecenie z arkusza
według wzoru: „<imie><nazwisko>, <punkty> pkt.”, gdzie pola <> są pobrane z bazy
Po nazwisku przecinek, spacja, liczba punktów z $row[2] i „pkt.” z kropką - znak po znaku jak we wzorze (R.5.7). Podgląd: „Jan Nowak, 3305 pkt.”, jak na obrazie 2.
opinie.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Opinie klientów</title> <linkrel="stylesheet"href="styl3.css"></head><body> <header> <h1>Hurtownia spożywcza</h1> </header> <main> <h2>Opinie naszych klientów</h2><?php$connection = mysqli_connect('localhost', 'root', '', 'hurtownia');$result = mysqli_query($connection, 'SELECT zdjecie, imie, opinia FROM klienci JOIN opinie ON klienci.id = opinie.Klienci_id WHERE Typy_id IN (2, 3);');while ($row = mysqli_fetch_row($result)) {echo"<div class='opinion'>";echo"<img src='$row[0]' alt='klient'>";echo"<blockquote>$row[2]</blockquote>";echo"<h4>$row[1]</h4>";echo"</div>"; }?> </main> <footer> <h3>Współpracują z nami</h3> <ahref="http://sklep.pl/">Sklep 1</a> </footer> <footer> <h3>Nasi top klienci</h3> <ol><?php$result = mysqli_query($connection, 'SELECT imie, nazwisko, punkty FROM klienci ORDER BY punkty DESC LIMIT 3;');while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1], $row[2] pkt.</li>"; }?> </ol> </footer> <footer> <h3>Skontaktuj się</h3> <p>telefon: 111222333</p> </footer> <footer> <h3>Autor: Bartosz Bryniarski</h3> </footer></body></html>
Podgląd strony po tym kroku (opinie.php)
Krok 36: Zamknięcie połączenia z bazą
Kryteria:
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)
ok. 1 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych zamykane jest połączenie z serwerem
mysqli_close($connection) po pętli skryptu 2 - to ostatnia operacja na bazie w całym pliku: skrypt 1 jest wcześniej, w bloku głównym (R.5.2). Strona ma już całą treść; zostały style bloków opinii.
Typowe błędy
mysqli_close na końcu skryptu 1 zamknie połączenie, zanim skrypt 2 z niego skorzysta - PHP zgłosi błąd „mysqli object is already closed” i lista w stopce zostanie pusta.
opinie.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Opinie klientów</title> <linkrel="stylesheet"href="styl3.css"></head><body> <header> <h1>Hurtownia spożywcza</h1> </header> <main> <h2>Opinie naszych klientów</h2><?php$connection = mysqli_connect('localhost', 'root', '', 'hurtownia');$result = mysqli_query($connection, 'SELECT zdjecie, imie, opinia FROM klienci JOIN opinie ON klienci.id = opinie.Klienci_id WHERE Typy_id IN (2, 3);');while ($row = mysqli_fetch_row($result)) {echo"<div class='opinion'>";echo"<img src='$row[0]' alt='klient'>";echo"<blockquote>$row[2]</blockquote>";echo"<h4>$row[1]</h4>";echo"</div>"; }?> </main> <footer> <h3>Współpracują z nami</h3> <ahref="http://sklep.pl/">Sklep 1</a> </footer> <footer> <h3>Nasi top klienci</h3> <ol><?php$result = mysqli_query($connection, 'SELECT imie, nazwisko, punkty FROM klienci ORDER BY punkty DESC LIMIT 3;');while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1], $row[2] pkt.</li>"; } mysqli_close($connection);?> </ol> </footer> <footer> <h3>Skontaktuj się</h3> <p>telefon: 111222333</p> </footer> <footer> <h3>Autor: Bartosz Bryniarski</h3> </footer></body></html>
Kroki 37-41 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 37: Bloki opinii: tło, kolor, wymiary i wyśrodkowanie
Kryteria:
R.4.8 Ustawiono styl dla bloków opinii (np. klasą, id jest błędem): biały kolor tła, kolor czcionki DimGray, szerokość 60%, wysokość 220px, marginesy zewnętrzne (margin) ustawione są parami na 40px i auto
ok. 2 min
Polecenie z arkusza
Dla bloków opinii generowanych skryptem: biały kolor tła, kolor czcionki DimGray, szerokość 60%, wysokość 220 px, marginesy zewnętrzne pionowe 40 px, poziome automatycznie wyliczane przez przeglądarkę
Selektor klasy.opinion (z kropką) - tej, którą skrypt 1 dał każdemu blokowi. Skrót margin: 40px auto: pierwsza wartość to góra i dół, druga - lewa i prawa strona. auto z lewej i prawej przy szerokości 60% stawia blok na środku bloku głównego (R.4.8).
Styl jest dopisany po skryptach, żeby w podglądzie było widać jego efekt - na egzaminie kolejność pisania nie ma znaczenia.
Typowe błędy
margin: auto 40px odwraca kierunki - bloki przykleją się do siebie i staną 40 px od lewej krawędzi.
Krok 40: Cytat: marginesy wewnętrzne, rozmiar i pochylenie
ok. 2 min
Polecenie z arkusza
Dla selektora cytatu: marginesy wewnętrzne 10 px, czcionka o rozmiarze 150%, pochylona
Selektor znacznika blockquote. font-size: 150% - półtora raza większa czcionka niż w bloku, font-style: italic - kursywa. Przeglądarka sama dodaje cytatowi marginesy zewnętrzne (40 px z lewej i z prawej), ale tekst i tak zaczyna się zaraz za zdjęciem - linie tekstu omijają pływający obraz.
Krok 41: Nagłówek h4: do prawej, margines, rozmiar i pochylenie
Kryteria: , ,
R.4.5 Ustawiono cechy czcionki dla selektora cytatu i h4: pochylenie i rozmiar czcionki 150%
R.4.6 Ustawiono wyrównanie tekstu do środka dla selektora h1 i h2 oraz do prawej strony dla nagłówka h4
R.4.7 Ustawiono marginesy zewnętrzne (margin) 10px dla selektora img oraz prawy (margin- right) 40px dla nagłówka h4 oraz marginesy wewnętrzne (padding) 10px dla banera i cytatu
ok. 2 min
Polecenie z arkusza
Dla selektora nagłówka czwartego stopnia: wyrównanie tekstu do prawej strony, margines zewnętrzny prawy 40 px, czcionka o rozmiarze 150%, pochylona
Selektor znacznika h4. Imię klienta stoi przy prawej krawędzi, odsunięte od niej o 40 px - jak podpis pod opinią.
Gotowe są cechy czcionki cytatu i h4 (R.4.5), wyrównanie h1, h2 i h4 (R.4.6) oraz marginesy obrazu, h4, banera i cytatu (R.4.7). Podgląd odpowiada obrazowi 2: białe bloki z cieniem, zdjęcie z zaokrąglonymi rogami, kursywą opinia i imię, a blok główny przewija się w pionie.
Typowe błędy
Arkusz zastrzega selektory znaczników: .opinion h4 albo klasa przy nagłówku nie dają punktów R.4.5 - R.4.7 (uwaga w kluczu przy R.4).
Kroki 42-43 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 42: Zabezpieczenie: htmlspecialchars przy wypisywaniu danych z bazy
ok. 4 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz wypisuje w osobnym bloku opinii
W prawdziwej hurtowni opinie piszą klienci - przez formularz, który arkusz zapowiada jako „późniejszą rozbudowę witryny”. Skrypt 1 wypisuje je każdemu odwiedzającemu tak, jak są w bazie. Sprawdzone na wersji z poprzednich kroków, po wpisaniu do bazy dwóch wartości:
opinia <script>document.title = "Strona przejęta";</script>Świetna obsługa. - przeglądarka wykonała skrypt i zmieniła tytuł karty na „Strona przejęta”,
nazwa zdjęcia x' onerror='z=7 - mieści się w polu zdjecie (20 znaków), a po wklejeniu w src='$row[0]' apostrof zamyka atrybut i dokłada nowy, onerror. Obrazu x nie ma, więc przeglądarka wykonała kod z onerror (ustawił zmienną z).
Tu kod tylko zmieniał tytuł i zmienną - równie dobrze mógłby podmienić stronę albo wysłać komuś ciasteczka zalogowanego użytkownika. To atak XSS (cross-site scripting), zapisany w bazie, więc trafia w każdego odwiedzającego.
Lekarstwo: htmlspecialchars() na każdej wartości z bazy w chwili wypisywania. Funkcja zamienia <, >, &, cudzysłów i - od PHP 8.1 - także apostrof na encje (<, ' …), więc znaczniki stają się zwykłym tekstem, a apostrof nie zamknie atrybutu. Napisy łączy operator .. Zabezpieczone są oba skrypty, a liczba punktów przechodzi przez (int) - liczba całkowita nie zawiera znaczników. Stare linie zostają w komentarzu.
Podgląd: te same dane po poprawce - skrypt w opinii widać jako tekst, a zamiast pierwszego zdjęcia przeglądarka pokazuje tekst alternatywny „klient”.
Typowe błędy
W PHP starszym niż 8.1 htmlspecialchars bez drugiego argumentu nie zamienia apostrofu - wtedy trzeba pisać htmlspecialchars($row[0], ENT_QUOTES). Zamiana przy zapisie do bazy zamiast przy wypisywaniu psuje dane i nie chroni tekstów wpisanych inną drogą, np. importem.
Krok 43: Zabezpieczenie: błąd połączenia bez danych serwera
ok. 4 min
Polecenie z arkusza
Skrypty łączą się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie hurtownia
Sprawdzone na wersji z poprzedniego kroku: gdy bazy hurtownia nie ma (usunięta, niezaimportowana, zła nazwa), mysqli_connect w PHP 8.1 i nowszym rzuca wyjątek mysqli_sql_exception. Nikt go nie łapie, więc strona urywa się pod nagłówkiem „Opinie naszych klientów”, a w jej miejscu stoi komunikat „Fatal error: Uncaught mysqli_sql_exception: Unknown database 'hurtownia'” z pełną ścieżką pliku na serwerze, numerem linii i fragmentem kodu. Stopka znika. Takie komunikaty podpowiadają włamywaczowi, jak zbudowany jest serwis.
Poprawka:
try / catch (mysqli_sql_exception $e) wokół połączenia - wyjątek zostaje złapany,
error_log($e->getMessage()) zapisuje szczegóły do dziennika błędów serwera (dla administratora), a odwiedzający widzi zwykłe zdanie „Opinie są chwilowo niedostępne.”,
$connection = false i warunek if ($connection) w obu skryptach - zapytania i mysqli_close wykonują się tylko przy działającym połączeniu.
Podgląd: strona przy usuniętej bazie - komunikat w bloku głównym, pusta lista w stopce, a reszta strony na swoim miejscu. Przy działającej bazie strona wygląda jak przed poprawką.
Typowe błędy
Wyłączenie wyświetlania błędów (display_errors = Off w php.ini) ukrywa komunikat, ale strona i tak urywa się w połowie - dopiero try / catch pozwala dokończyć stronę.
Krok 44 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 44: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
UWAGA: po zakończeniu pracy utwórz w folderze z numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….
W folderze z numerem zdającego muszą być: anna.jpg, ewa.jpg (przeskalowany), import.jpg, janek.jpg, john.jpg, judy.jpg, kw1.png - kw4.png, kwerendy.txt, opinie.php, przeglądarka.txt i styl3.css (baza.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.