Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-05-22.01-SGStyczeń 2022 · 38 kroków · ok. 83 min · 39 kryteriów z klucza
Rozwiązanie krok po kroku: Logowanie do portalu osiedlowego (Nowoczesny kod (flex, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza portal z czterema zapytaniami, zdjęcie przycięte do 400 × 200 px oraz strona uzytkownicy.php z licznikiem użytkowników, formularzem logowania i wizytówką - i tak samo spełnia każde kryterium klucza. Inna jest droga:
semantyczne znaczniki i flex zamiast float: oba banery stoją w <header>, blok lewy i prawy w <main>, a każdy z tych dwóch rzędów to kontener display: flex - stopka nie potrzebuje clear,
zmienne CSS dla trzech kolorów z arkusza, etykiety <label for> i wiersze formularza w blokach zamiast <br>,
PHP na PDO na górze pliku, przed HTML-em - w banerze i w wizytówce zostaje samo wypisanie przygotowanych danych,
zapytania przygotowane z loginem z formularza, porównanie skrótów hasła funkcją hash_equals, każdy tekst z bazy przepuszczony przez htmlspecialchars,
login zostaje w polu po wysłaniu formularza, a błąd bazy danych kończy się zwykłym komunikatem zamiast „Fatal error”.
To arkusz EE.09 ze stycznia 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i zdjęcia pochodzą z oryginalnego archiwum CKE pliki5 (załącznik na stronie arkusza), zapytania i zrzuty są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.0.7 - użyte konstrukcje działają w obu wersjach). Kroki bazy danych i grafiki są takie same jak w wersji podstawowej.
Jak liczą się punkty. Klucz ma 39 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.
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 39 kryteriów (pkt)
Krok 1: Folder zdającego i archiwum pliki5
ok. 2 min
Polecenie z arkusza
Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu.
Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum pliki5.zip rozpakowujesz do tego folderu, podając hasło *Mieszk4ncY* (z gwiazdkami na początku i na końcu, wielkość liter ma znaczenie). W środku są: baza.sql, zdjęcia o1.jpg - o8.jpg i ikona serca icon-on.png.
Arkusz podkreśla, że rozpakowane pliki muszą leżeć w tym samym folderze co pliki strony - skrypt wstawia zdjęcia po samej nazwie pliku zapisanej w bazie (o6.jpg), więc przeglądarka szuka ich obok uzytkownicy.php.
Typowe błędy
Zdjęcia w podfolderze (np. pliki5/o6.jpg) - nazwa z bazy nie zawiera folderu, więc wizytówka pokaże pusty prostokąt zamiast zdjęcia.
Krok 2: XAMPP i pusta baza portal
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 portal
W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa portal, Utwórz. Porównywania napisów arkusz nie narzuca - plik baza.sql i tak tworzy tabele z własnym kodowaniem.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie portal - po niej skrypt PHP wybiera bazę (R.5.1), a klucz sprawdza import do bazy o tej nazwie (R.1.1).
Krok 3: Import pliku baza.sql i zrzut egzamin.jpg
Kryteria:
R.1.1 Wykonano import tabel do bazy portal , czynność udokumentowano plikiem o nazwie egzamin w formacie JPEG
ok. 3 min
Polecenie z arkusza
Do bazy portal zaimportuj plik baza.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze opisanym numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie JPEG i nazwij egzamin. 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
Zaznacz bazę portal, karta Import, Wybierz plik → baza.sql, Wykonaj. Plik sam tworzy obie tabele (dane i uzytkownicy), wstawia po 11 wierszy i ustawia klucze główne. Po imporcie phpMyAdmin pokazuje zielony komunikat o sukcesie, a w lewym panelu pod bazą pojawiają się obie tabele - to są „elementy wskazujące na poprawnie wykonany import”.
Zrzut całego ekranu z paskiem zadań zapisujesz jako egzamin.jpg (Print Screen, wklejenie do edytora grafiki, eksport do JPEG).
Typowe błędy
W tym arkuszu formaty są odwrotne niż zwykle: zrzut importu to JPEG (egzamin.jpg), a zrzuty zapytań - PNG (kw1.png - kw4.png). Zły format to strata punktu.
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: hasło użytkownika Justyna
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 jedynie pole haslo z tabeli uzytkownicy dla użytkownika o loginie Justyna. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT haslo FROM uzytkownicy WHERE login = 'Justyna'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne jest jedynie jedno hasło wynikające z zapytania
ok. 3 min
Polecenie z arkusza
Zapisz i wykonaj zapytania SQL działające na bazie danych portal. Zapytania zapisz w pliku kwerendy.txt. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie PNG o nazwach kw1, kw2, kw3, kw4. Zapytanie 1: wybierające jedynie pole haslo z tabeli uzytkownicy dla użytkownika o loginie Justyna
Zaznacz bazę portal i otwórz kartę SQL:
SELECT haslo - tylko jedna kolumna („jedynie pole haslo”),
FROM uzytkownicy,
WHERE login = 'Justyna' - warunek z loginem w apostrofach, bo to napis.
Wynik to jeden wiersz: a056c8d05ae9ac6ca180bc991b93b7ffe37563e0 - 40 znaków szesnastkowych, czyli skrót SHA-1. Hasła Justyny („qqq” z tabeli 1 arkusza) w bazie nie ma, jest tylko jego skrót. Zapytanie kopiujesz do nowego pliku kwerendy.txt w folderze zdającego, a zrzut całego ekranu - do kw1.png.
To zapytanie wykona później skrypt 2 - z loginem z formularza w miejscu „Justyna”.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT haslo FROM uzytkownicy WHERE login = 'Justyna';
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: liczba wierszy w tabeli dane
Kryteria:
R.1.4 Utworzono zapytanie 2 liczące liczbę wierszy w tabeli dane. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT COUNT(*) FROM dane; możliwa dowolna nazwa pola zamiast * oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest efekt poprawnie wykonanego zapytania - wartość 11
ok. 2 min
Polecenie z arkusza
Zapytanie 2: liczące liczbę wierszy w tabeli dane
SELECT COUNT(*) FROM dane - funkcja COUNT(*) liczy wiersze tabeli (gwiazdka: wszystkie, bez względu na zawartość kolumn). Wynik: 11. Zrzut: kw2.png.
Wynik przyda się skryptowi 1: każdy wiersz tabeli dane to jeden użytkownik portalu, więc baner pokaże „Liczba użytkowników portalu: 11”.
Typowe błędy
SELECT * FROM dane pokaże 11 wierszy, ale niczego nie policzy - klucz wymaga wyniku w postaci wartości 11.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT haslo FROM uzytkownicy WHERE login = 'Justyna';-- Zapytanie 2SELECT COUNT(*) FROM dane;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: dane Justyny z dwóch tabel
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające jedynie pole login z tabeli uzytkownicy i odpowiadające mu pola rok_urodz, przyjaciol, hobby, zdjecie z tabeli dane dla użytkownika o loginie Justyna. Tabele połączone są relacją 1..1, za pomocą kluczy głównych. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT login, rok_urodz, przyjaciol, hobby, zdjecie FROM dane JOIN uzytkownicy ON dane.id = uzytkownicy.id WHERE login = 'Justyna'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest rekord: Justyna, 1995, 10, moda, o6.jpg
ok. 4 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pole login z tabeli uzytkownicy i odpowiadające mu pola rok_urodz, przyjaciol, hobby, zdjecie z tabeli dane dla użytkownika o loginie Justyna. Tabele połączone są relacją 1..1, za pomocą kluczy głównych
Relacja 1..1 przez klucze główne znaczy, że wiersz o id 1 w tabeli uzytkownicy opisuje tę samą osobę co wiersz o id 1 w tabeli dane:
SELECT login, rok_urodz, przyjaciol, hobby, zdjecie - pięć kolumn z arkusza, w tej kolejności,
FROM dane JOIN uzytkownicy - złączenie dwóch tabel,
ON dane.id = uzytkownicy.id - warunek złączenia: równe klucze główne. Nazwa tabeli przed kropką jest konieczna, bo kolumna id jest w obu,
WHERE login = 'Justyna'.
Wynik: Justyna, 1995, 10, moda, o6.jpg - dokładnie rekord z klucza. Zrzut: kw3.png. Kolejność kolumn ma znaczenie dla skryptu 2: mysqli_fetch_row zwróci je pod numerami 0-4.
Typowe błędy
Bez warunku ON (samo FROM dane, uzytkownicy WHERE login = ...) baza połączy Justynę z każdym z 11 wierszy tabeli dane - 11 rekordów zamiast jednego.
kwerendy.txtTekstzmienione: 5 linii
-- Zapytanie 1SELECT haslo FROM uzytkownicy WHERE login = 'Justyna';-- Zapytanie 2SELECT COUNT(*) FROM dane;-- Zapytanie 3SELECT login, rok_urodz, przyjaciol, hobby, zdjecieFROM dane JOIN uzytkownicy ON dane.id = uzytkownicy.idWHERE login = 'Justyna';
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowa kolumna stanowisko
Kryteria:
R.1.6 Utworzono zapytanie 4 dodające do tabeli dane kolumnę stanowisko dowolnego typu napisowego. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE dane ADD stanowisko TEXT; możliwe ADD COLUMN oraz dowolny typ napisowy oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest efekt poprawnie wykonanego zapytania
ok. 2 min
Polecenie z arkusza
Zapytanie 4: dodające do tabeli dane kolumnę stanowisko dowolnego typu tekstowego
ALTER TABLE dane - zmiana struktury istniejącej tabeli,
ADD stanowisko TEXT - nowa kolumna typu TEXT (klucz przyjmuje dowolny typ napisowy, np. VARCHAR(50); słowo COLUMN po ADD jest opcjonalne).
phpMyAdmin odpowiada „MySQL zwrócił pusty wynik” - ALTER TABLE niczego nie wybiera. Zrzut: kw4.png; można też pokazać kartę Struktura z nową kolumną. Nowa kolumna jest pusta (NULL) we wszystkich wierszach i nie przeszkadza skryptom - żadne zapytanie nie używa SELECT *. Plik kwerendy.txt ma komplet czterech zapytań.
Typowe błędy
Zapytanie 4 wykonuj raz - drugie wykonanie zgłosi błąd #1060 („Zduplikowana nazwa kolumny”). Na zrzucie ma być efekt udanego wykonania.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT haslo FROM uzytkownicy WHERE login = 'Justyna';-- Zapytanie 2SELECT COUNT(*) FROM dane;-- Zapytanie 3SELECT login, rok_urodz, przyjaciol, hobby, zdjecieFROM dane JOIN uzytkownicy ON dane.id = uzytkownicy.idWHERE login = 'Justyna';-- Zapytanie 4ALTER TABLE dane ADD stanowisko TEXT;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-20 · po tym etapie masz 17 z 39 kryteriów (pkt)
Krok 8: Grafika: przycięcie o1.jpg do 400 × 200 px
Kryteria:
R.2.1 Wysokość obrazu o1.jpg wynosi dokładnie 200 px, a szerokość 400 px
ok. 3 min
Polecenie z arkusza
Plik o1.jpg, wypakowany z archiwum, należy przyciąć tak, aby jego wysokość wynosiła dokładnie 200 px, szerokość pozostaje niezmieniona – 400 px, obraz należy zapisać w pliku o tej samej nazwie. Pozostałe obrazy zostały przygotowane i nie należy ich zmieniać.
Oryginał ma 400 × 266 px, a wszystkie pozostałe zdjęcia - 400 × 200. Przycięcie to wycięcie fragmentu obrazu, a nie skalowanie: w GIMP-ie Obraz → Rozmiar płótna (szerokość 400, wysokość 200, przesunięcie 0) i Obraz → Przytnij do zawartości, albo narzędzie Kadrowanie z wpisanym rozmiarem 400 × 200. W tym rozwiązaniu odcięty jest dolny pas z błotem - głowy zawodników zostają w kadrze.
Zapis pod tą samą nazwą: Plik → Nadpisz o1.jpg. To zdjęcie zobaczy w wizytówce Krzysiek (w tabeli dane ma o1.jpg) - po przycięciu pasuje do bloku wizytówki tak samo jak pozostałe.
Typowe błędy
Skaluj obraz do 400 × 200 przy rozpiętym łańcuchu spłaszczy zdjęcie - wymiary się zgodzą, ale to nie jest przycięcie. Zmiana o2.jpg - o8.jpg jest wbrew arkuszowi.
Podgląd strony po tym kroku
Krok 9: Plik dane.html
ok. 1 min
Polecenie z arkusza
Składa się ze stron: uzytkownicy.php, dane.html. W pliku o nazwie dane.html jest wpisany jedynie napis „strona w trakcie budowy”. Pozostałe wymagania dotyczą jedynie pliku uzytkownicy.php
Plik dane.html z jednym zdaniem: strona w trakcie budowy. Arkusz mówi „jedynie napis”, więc bez szkieletu HTML. Do tego pliku poprowadzi przycisk „Więcej informacji” z wizytówki.
dane.htmlHTMLnowy plik
strona w trakcie budowy
Podgląd strony po tym kroku (dane.html)
Krok 10: Plik uzytkownicy.php i kodowanie znaków
Kryteria: ,
R.2.2 Witrynę internetową zapisano w pliku o nazwie uzytkownicy.php
R.2.3 Zastosowano właściwy standard kodowania polskich znaków dla witryny
ok. 2 min
Polecenie z arkusza
Witrynę zapisano w pliku uzytkownicy.php. Zastosowany właściwy standard kodowania polskich znaków
Plik uzytkownicy.php w folderze zdającego, obok zdjęć. <!DOCTYPE html> to HTML5, lang="pl" - język treści, a <meta charset="UTF-8"> jako pierwszy element <head> mówi przeglądarce, jak czytać polskie litery. Sam plik zapisujesz w UTF-8 (w Notepad++ menu Kodowanie).
R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl5.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy źle przypisano 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">. Całe formatowanie trafi do tego pliku - żadnych atrybutów style w HTML-u.
Krok 13: Bloki: nagłówek z dwoma banerami, część główna, stopka
Kryteria:
R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: dwa bloki banera, blok lewy i prawy, stopka. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: obok siebie dwa bloki banera, poniżej obok siebie blok lewy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji
Strona ma trzy poziome pasy i każdy dostaje znacznik, który mówi, czym jest:
<header> - nagłówek strony, w nim dwa bloki banera: <section id="banner-left"> i <section id="banner-right">,
<main> - główna treść, w niej blok lewy i prawy, też jako <section>,
<footer> - stopka.
Arkusz wymaga znaczników sekcji dla bloków - pięć bloków z arkusza to cztery <section> i <footer> (R.2.5). <header> i <main> to dodatkowe kontenery: każdy obejmuje jeden rząd bloków, więc w CSS wystarczy ustawić flex na kontenerze.
R.2.6 W lewym bloku banera zapisano nagłówek h2: "Nasze osiedle", w bloku lewym h3 "Logowanie", w bloku prawym h3 "Wizytówka"
ok. 1 min
Polecenie z arkusza
Zawartość banera lewego: nagłówek drugiego stopnia o treści „Nasze osiedle”. Zawartość bloku lewego: Nagłówek trzeciego stopnia o treści „Logowanie”. Zawartość bloku prawego: Nagłówek trzeciego stopnia o treści „Wizytówka”
Trzy zdania arkusza, trzy nagłówki: <h2> w banerze lewym oraz <h3> w bloku lewym i prawym. Baner prawy na razie pusty - liczbę użytkowników wypisze w nim PHP.
R.3.3 Formularz wysyła dane do tej samej strony metodą post (poprawne również bez atrybutu action)
ok. 1 min
Polecenie z arkusza
Formularz wysyłający dane do tego samego pliku metodą post z elementami:
<form method="post"> bez atrybutu action wysyła dane pod ten sam adres, czyli do uzytkownicy.php (R.3.3). Metoda POST - hasło nie trafi do paska adresu ani do historii przeglądarki.
Napis to <label for="login"> połączony z polem o id="login": kliknięcie w napis ustawia kursor w polu, a czytnik ekranu odczyta nazwę pola. Etykieta i pole stoją w jednym bloku <div class="field"> - „poniżej” zrobi CSS, bez <br>.
name="login" - klucz w $_POST,
maxlength="50" - tyle znaków mieści kolumna login w bazie (varchar(50)),
autocomplete="username" - menedżer haseł przeglądarki rozpozna pole loginu.
Poniżej napis hasło, poniżej pole edycyjne pozwalające na niejawne wpisanie hasła
Ten sam układ co login. Niejawne wpisanie to type="password", a autocomplete="current-password" podpowiada przeglądarce, że to hasło do istniejącego konta.
R.2.7 W bloku lewym umieszczono formularz z dwoma polami edycyjnymi i przyciskiem
R.3.4 Pole edycyjne do wpisywania hasła jest typu password oraz przycisk wysyła dane z formularza (input z typem submit lub button)
ok. 1 min
Polecenie z arkusza
Poniżej przycisk o treści „Zaloguj” wysyłający dane z formularza
<button type="submit"> - przycisk z treścią między znacznikami, jawnie określonym typem wysyłającym formularz. Klucz przyjmuje input type="submit" albo button (R.3.4). Formularz ma dwa pola i przycisk (R.2.7).
Typowe błędy
Przycisk w formularzu bez type też wysyła dane, ale jawne type="submit" nie zostawia wątpliwości przy czytaniu kodu.
R.2.9 W stopce umieszczono napis „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz.
ok. 1 min
Polecenie z arkusza
Zawartość stopki: napis o treści „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz.
Na egzaminie po dwukropku wpisujesz swój numer PESEL. W tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora: Bartosz Bryniarski.
Kroki 21-26 · po tym etapie masz 28 z 39 kryteriów (pkt)
Krok 21: Plik styl5.css: kolory jako zmienne i krój Tahoma
Kryteria:
R.4.1 Ustawiono domyślny krój czcionki dla całej strony na Tahoma (dla selektora * lub body lub html lub kontenera całej strony)
ok. 2 min
Polecenie z arkusza
Cechy formatowania CSS: Są zawarte wyłącznie w zewnętrznym arkuszu stylów. Domyślne dla całej strony: krój czcionki Tahoma
Trzy kolory z arkusza powtarzają się w kilku regułach, więc dostają nazwy w :root: --dark (#003d33), --main (#26a69a) i --hover (#004c40). W regułach będzie var(--dark) - zmiana koloru w jednym miejscu zmienia go wszędzie.
* z font-family: Tahoma obejmuje też pola formularza i przyciski (R.4.1). body bez marginesu - pasy dochodzą do krawędzi okna.
Krok 22: Banery obok siebie: tło, kolor tekstu, wysokość, szerokość
ok. 3 min
Polecenie z arkusza
Wspólne dla obu banerów: kolor tła #003d33, biały kolor czcionki, wyrównanie tekstu do środka, wysokość 50 px. Dodatkowo dla banera lewego: szerokość 70%. Dodatkowo dla banera prawego: szerokość 30%
display: flex na <header> i <main> - dzieci kontenera stają obok siebie w jednym rzędzie. Banery w nagłówku, blok lewy i prawy w części głównej; stopka jest poza oboma kontenerami, więc stoi pod nimi bez clear,
wspólne cechy obu banerów w jednej regule, szerokości 70% i 30% osobno - razem 100% rzędu.
Szerokości są na samych blokach, bo tak opisuje je klucz („ustawiono szerokość banera lewego… 70%”).
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)
R.4.2 Ustawiono kolor tła #003d33 dla obu bloków banera i stopki, #26a69a dla bloku lewego i prawego
R.4.3 Ustawiono biały kolor czcionki dla obu bloków banera i stopki
R.4.4 Ustawiono wysokość bloków: 50px dla obu bloków banera, 550px dla bloku lewego i prawego
R.4.5 Ustawiono szerokość banera lewego i bloku prawego 70% oraz banera prawego i bloku lewego 30%
ok. 3 min
Polecenie z arkusza
Dla bloku lewego: kolor tła #26a69a, wysokość 550 px, szerokość 30%. Dla bloku prawego: kolor tła #26a69a, wysokość 550 px, szerokość 70%. Dla bloku stopki: kolor tła #003d33, biały kolor czcionki
Wspólne tło i wysokość bloków w jednej regule, szerokości osobno. W stopce paragraf bez marginesów - pasek ma wysokość jednej linii tekstu, jak na obrazie 2.
Komplet cech bloków: tła (R.4.2), biały tekst banerów i stopki (R.4.3), wysokości (R.4.4) i szerokości (R.4.5). Układ jest zgodny z obrazem 2 (R.3.1) - klucz przyjmuje flex obok float i grid.
Typowe błędy
flex domyślnie zwęża dzieci, które się nie mieszczą (flex-shrink). Przy szerokościach sumujących się do 100% i bez marginesów nic się nie zwęża - ale padding na bloku bez box-sizing: border-box już by to zrobił.
Etykieta i pole są elementami liniowymi i stanęłyby obok siebie. display: block daje każdemu własną linię - pole jest poniżej napisu, jak na obrazie 2, bez znaczników <br> w HTML-u.
R.4.6 Ustawiono wyrównanie tekstu do środka dla obu bloków banera i bloku wizytówki
R.4.7 Ustawiono marginesy zewnętrzne (margin) dla bloku wizytówki 30px
R.4.8 Ustawiono pozostałe cechy bloku wizytówki: szerokość 400px, obramowanie linią ciągłą 1 px koloru #003d33
ok. 2 min
Polecenie z arkusza
Dla bloku wizytówki: szerokość 400 px, marginesy zewnętrzne 30 px, wyrównanie tekstu do środka, obramowanie linią ciągłą 1 px koloru #003d33
Wszystkie cechy z arkusza w jednej regule #card (R.4.6, R.4.7, R.4.8). Zdjęcie osoby (bezpośredni potomek wizytówki, #card > img - serce w nagłówku <h1> zostaje w linii z liczbą) dostaje display: block: obraz liniowy zostawia pod sobą kilka pikseli odstępu na „ogonki” liter, a blokowy przylega do tego, co pod nim.
Krok 26: Przycisk w wizytówce i jego tło po najechaniu
Kryteria: ,
R.4.9 Ustawiono styl dla przycisku w bloku wizytówki (dowolną metodą, tak aby tylko ten przycisk był formatowany stylem) kolor tła #003d33, biały kolor czcionki, szerokość 100%, wysokość 30 px, bez obramowania
R.4.10 Gdy kursor myszy znajdzie się na przycisku w bloku wizytówki jego tło zamienia się na #004c40, np. za pomocą pseudoklasy hover
ok. 2 min
Polecenie z arkusza
Dla przycisku w wizytówce: kolor tła #003d33, biały kolor czcionki, szerokość 100%, wysokość 30 px, bez obramowania. Po najechaniu na przycisk w wizytówce jego tło zamienia się na #004c40
Selektor #card button trafia tylko w przycisk wewnątrz wizytówki - „Zaloguj” jest w bloku lewym i zostaje bez stylu (R.4.9). cursor: pointer pokazuje rączkę jak nad odnośnikiem (klucz tego nie ocenia), a :hover zmienia tło na var(--hover) (R.4.10).
Typowe błędy
Samo button sformatowałoby też przycisk „Zaloguj” - od tego arkusza w tej wersji jest on znacznikiem <button>, więc selektor musi wskazać wizytówkę.
Kroki 27-36 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 27: PHP na górze pliku i połączenie z bazą portal
Kryteria:
R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy portal
ok. 4 min
Polecenie z arkusza
Skrypt łączy się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie portal
Kod PHP stoi na samej górze uzytkownicy.php, przed <!DOCTYPE html>: najpierw przygotowuje wszystkie dane, a HTML niżej tylko je wypisuje. Arkusz mówi o dwóch skryptach - oba są w tym jednym bloku, opisane komentarzami.
e() - krótka funkcja z htmlspecialchars: każdy tekst z bazy i z formularza wypisywany na stronie zamienia <, >, & i cudzysłowy na encje,
new PDO(...) - serwer localhost, baza portal i kodowanie w jednym napisie, potem użytkownik root i puste hasło (R.5.1). ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek,
try / catch - gdy baza nie działa, w wizytówce pojawi się zwykłe zdanie, a nie komunikat PHP z danymi serwera.
PDO zamiast funkcji mysqli z tabeli 2 - klucz przyjmuje obie biblioteki (uwaga przy R.5). Połączenie z nazwą bazy stoi w pliku strony, bo tam klucz je sprawdza, gdyby strona się nie uruchomiła. Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
Krok 28: Skrypt 1: liczba użytkowników w nagłówku h5
Kryteria: ,
R.5.3 Skrypt 1 wysyła do bazy zapytanie 2 lub skrypt 2 wysyła zapytanie 1 i 3 zmodyfikowane tak, że w klauzuli warunku sprawdzony jest login przesłany z formularza
R.5.4 Skrypt 1 wyświetla liczbę użytkowników znajdujących się w bazie (rozwiązanie ma charakter uniwersalny) według wzoru: „Liczba użytkowników portalu: <zwrocona_wartosc>”
ok. 3 min
Polecenie z arkusza
Działanie skryptu 1: Wysyła do bazy danych zapytanie 2. Wartość zwróconą zapytaniem wypisuje w nagłówku piątego stopnia, według wzoru: „Liczba użytkowników portalu: <zwrocona_wartosc>”
$pdo->query('SELECT COUNT(*) FROM dane;') - zapytanie 2 bez żadnych danych z zewnątrz, więc wystarczy zwykłe query (R.5.3),
fetchColumn() - pierwsza kolumna pierwszego wiersza, czyli sama liczba; (int) zamienia napis z bazy na liczbę całkowitą,
w banerze prawym: jeśli liczba jest, wypisz <h5> według wzoru z arkusza. <?= … ?> to skrót od <?php echo … ?>.
Podgląd: „Liczba użytkowników portalu: 11”. Liczba pochodzi z bazy, więc rozwiązanie jest uniwersalne (R.5.4).
Krok 29: Skrypt 2: dane z formularza i login w polu
ok. 3 min
Polecenie z arkusza
Działanie skryptu 2: Skrypt wykonuje akcje tylko wtedy, jeśli dane wysłane z formularza są niepuste
$_SERVER['REQUEST_METHOD'] === 'POST' - skrypt 2 pracuje tylko po wysłaniu formularza,
$_POST['login'] ?? '' - operator ?? daje pusty napis, gdy pola w ogóle nie ma w żądaniu (bez ostrzeżenia PHP),
trim obcina spacje z brzegów loginu - „ Heniek ” to ten sam użytkownik. Hasła się nie obcina: spacja może być jego częścią,
pole loginu dostaje value="<?= e($login) ?>" - po wysłaniu formularza wpisany login zostaje w polu, a e() pilnuje, żeby cudzysłów w loginie nie zamknął atrybutu.
Podgląd: formularz wysłany z danymi z obrazu 2 (Heniek, hasło iii z tabeli 1 arkusza) - login stoi w polu, wizytówka jeszcze pusta.
Krok 30: Skrypt 2: zapytanie 1 przygotowane i „login nie istnieje”
Kryteria:
R.5.5 Skrypt 2 wyświetla komunikat "login nie istnieje", jeżeli podany formularzem login nie istnieje w bazie
ok. 3 min
Polecenie z arkusza
Skrypt wysyła do bazy zmodyfikowane zapytanie 1, tak, że w klauzuli warunku jest sprawdzony login przesłany przez formularz. Jeżeli login nie istnieje w bazie, wyświetlony jest komunikat „login nie istnieje”
$login !== '' && $password !== '' - oba pola niepuste. Porównanie z pustym napisem, a nie empty(): empty('0') jest prawdziwe, więc hasło „0” byłoby uznane za puste,
zapytanie 1 jako zapytanie przygotowane: w miejscu loginu stoi nazwany parametr :login, a wartość przychodzi osobno w execute. Login z apostrofem albo próba wstrzyknięcia SQL zostają zwykłym tekstem,
fetchColumn() zwraca skrót hasła albo false, gdy żaden wiersz nie pasuje - wtedy komunikat „login nie istnieje” (R.5.5),
w wizytówce: jeśli jest komunikat, wypisz go w paragrafie.
R.5.6 Skrypt 2 wyświetla komunikat "hasło nieprawidłowe", jeżeli dla loginu nie zgadza się hasło podane formularzem z hasłem w bazie - zastosowano funkcję sha1 do porównania szyfrowanego hasła
ok. 2 min
Polecenie z arkusza
Jeżeli login istnieje jest sprawdzana zgodność przesłanego formularzem hasła z hasłem przechowywanym w bazie. Należy zastosować funkcję szyfrującą dane algorytmem SHA-1. Jeżeli hasła nie zgadzają się, wyświetlony jest komunikat „hasło nieprawidłowe”
W bazie jest skrót SHA-1, więc sha1($password) liczy skrót hasła z formularza (R.5.6). Do porównania dwóch skrótów służy hash_equals: zwykłe != kończy porównanie na pierwszym różnym znaku, więc czas odpowiedzi zdradza, ile początkowych znaków się zgadza. hash_equals porównuje zawsze cały napis w tym samym czasie.
Podgląd: Heniek z hasłem abc - „hasło nieprawidłowe”.
Krok 32: Skrypt 2: zapytanie 3 i zdjęcie z tekstem „osoba”
ok. 3 min
Polecenie z arkusza
Jeżeli hasła się zgadzają to skrypt wysyła do bazy zmodyfikowane zapytanie 3 tak, że w klauzuli warunku podany jest login przesłany formularzem. Następnie wyświetla dane w bloku wizytówki: Obraz na podstawie nazwy pliku z tekstem alternatywnym „osoba”
zapytanie 3 też przygotowane, z tym samym parametrem :login,
fetch(PDO::FETCH_ASSOC) - wiersz jako tablica z nazwami kolumn: $profile['zdjecie'] zamiast $row[4]. Kod mówi, co wypisuje, i nie psuje się po zmianie kolejności kolumn w zapytaniu,
$profile = null na początku pliku - wizytówka pokazuje dane tylko wtedy, gdy skrypt je ustawił,
w wizytówce gałąź elseif: zdjęcie z src z bazy (przez e()) i alt="osoba".
Podgląd: Heniek z hasłem iii - jego zdjęcie o3.jpg.
R.5.8 Skrypt 2 oblicza wiek na podstawie roku urodzenia z bazy i aktualnej daty. Np. $wiek = date('Y') - $wiersz[1]; (dopuszcza się jawne użycie roku 2022)
ok. 2 min
Polecenie z arkusza
Poniżej w nagłówku czwartego stopnia login oraz w nawiasie wiek danej osoby obliczony na podstawie roku urodzenia (pole rok_urodz)
Wiek liczy skrypt na górze, zanim zacznie się HTML: date('Y') (bieżący rok) minus rok urodzenia z bazy, oba zamienione na liczby całkowite (R.5.8). Wynik trafia do tej samej tablicy pod kluczem wiek. W wizytówce <h4> z loginem i wiekiem w nawiasie.
Podgląd: Heniek (36). Na obrazie 2 jest „Heniek (29)”, ale Heniek ma w bazie rok 1990 - w 2022 roku miał 32 lata, więc ilustracja nie zgadza się z danymi z archiwum.
Krok 34: Skrypt 2: hobby i serce z liczbą przyjaciół
Kryteria: ,
R.2.8 W bloku prawym umieszczono dwa obrazy. Pierwszy ma tekst alternatywny o treści „osoba”, drugi wyświetla obraz serca (za pomocą skryptu lub w HTML)
R.5.9 W skrypcie 1 komunikat jest zapisany w nagłówku h5 oraz w skrypcie 2 login zapisany jest w nagłówku h4, hobby w paragrafie, liczba przyjaciół w nagłówku h1
ok. 2 min
Polecenie z arkusza
Poniżej w paragrafie hobby, poprzedzone napisem „hobby: ”. Poniżej w nagłówku pierwszego stopnia obraz serca wypakowany z archiwum (icon-on.png) oraz liczbę przyjaciół pobraną z bazy (pole przyjaciol)
Paragraf z napisem „hobby: ” i nagłówek <h1> z obrazem serca (tekst alternatywny „serce”) i liczbą przyjaciół. W bloku prawym są dwa obrazy (R.2.8), a napisy mają znaczniki z arkusza: <h5>, <h4>, <p> i <h1> (R.5.9).
R.3.2 Na stronie umieszczono odnośnik zawierający przycisk o treści „Więcej informacji”, którego kliknięcie powoduje przejście do strony dane.html
R.5.7 Skrypt 2, tylko jeżeli login i hasło się zgadzają wyświetla dane odpowiadające loginowi w bloku wizytówka: obraz, login, hobby, liczba przyjaciół
ok. 2 min
Polecenie z arkusza
Poniżej przycisk o treści „Więcej informacji” prowadzący do pliku dane.html.
Klucz opisuje ten element dokładnie: odnośnik zawierający przycisk (R.3.2) - więc <a href="dane.html"> z <button> w środku, jak w wersji podstawowej. Przycisk ma type="button", żeby nigdy nie wysyłał formularza; przejście do dane.html robi odnośnik.
Specyfikacja HTML nie pozwala wkładać przycisku do odnośnika (dwa elementy interaktywne jeden w drugim). Poza egzaminem wystarczy sam odnośnik ostylowany jak przycisk: <a class="button" href="dane.html"> - tu jednak kryterium wymaga przycisku w odnośniku, więc zostaje forma z klucza.
Wizytówka jest kompletna (R.5.7) i pokazuje się tylko po poprawnym logowaniu.
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)
ok. 2 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem
PDO nie ma funkcji close - połączenie zamyka się, gdy znika ostatnie odwołanie do obiektu. Dlatego $statement = null i $pdo = null w bloku finally, który wykonuje się zawsze po try - po udanym logowaniu, po błędzie i po wyjątku. Zamknięcie jest więc ostatnią operacją na bazie w każdej gałęzi (R.5.2), a cały HTML niżej korzysta już tylko ze zmiennych.
Krok 37 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 37: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 3 min
Obie wersje dają komplet 39 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
bloki
cztery <section> i <footer>
to samo w <header> i <main>
układ
float: left sekcji, clear stopki
display: flex na <header> i <main>
kolory
wpisane w każdej regule
zmienne --dark, --main, --hover
formularz
napis, pole, <br>
label for, wiersze w <div>, maxlength, autocomplete
biblioteka
mysqli (tabela 2 arkusza)
PDO z wyjątkami
gdzie jest skrypt
dwa bloki w banerze i w wizytówce
jeden blok na górze pliku, w HTML-u tylko wypisanie
login w zapytaniach
wklejony w treść zapytania
parametr :login
porównanie hasła
sha1($password) != $row[0]
hash_equals
dane w wizytówce
$row[4], wprost
$profile['zdjecie'] przez e()
po wysłaniu
puste pola
login zostaje w polu
awaria bazy
„Fatal error” z danymi serwera
zdanie w wizytówce, reszta strony działa
Obie wersje zostawiają rzeczy wymagane przez arkusz, których prawdziwy serwis by nie zrobił: SHA-1 zamiast password_hash (szybki skrót bez soli), dwa różne komunikaty zdradzające, które loginy istnieją, i przycisk wewnątrz odnośnika. Po udanym logowaniu prawdziwa strona zapamiętałaby też użytkownika w sesji (session_start, $_SESSION) - tu wizytówka znika po odświeżeniu, bo arkusz każe tylko wyświetlić dane.
Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 2 i łatwiej ją napisać bez dokumentacji. Nowoczesna nie wywraca się na apostrofie w loginie, nie przepuszcza wstrzyknięcia SQL i nie gubi loginu po błędzie - a klucz przyjmuje obie.
Krok 38 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 38: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowano poprawność działania witryny. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. W folderze z numerem zdającego: dane.html, egzamin.jpg, kw1.png - kw4.png, kwerendy.txt, o1.jpg - o8.jpg, icon-on.png, przeglądarka.txt, styl5.css i uzytkownicy.php. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.