Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-02-21.01-SGStyczeń 2021 · 34 kroki · ok. 75 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Liga piłkarska i skład reprezentacji (Nowoczesny kod (flex, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza egzamin z czterema zapytaniami, przeskalowana grafika z piłką i strona liga.php z listą zawodników wybranej pozycji i blokami drużyn Ligi Mistrzów - i tak samo spełnia każde kryterium klucza. Inna jest droga:
flex zamiast float: bloki lewy i prawy stoją w pojemniku z display: flex, a blok liga sam układa bloki drużyn w rzędzie i zawija je do nowej linii - bez clear,
zmienne CSS dla kolorów z arkusza, klasa dla bloku z drużyną, opis listy rozwijalnej dla czytników ekranu,
PHP na PDO na górze pliku liga.php, przed HTML-em: najpierw pobranie danych, potem HTML tylko je wypisuje (szablon foreach / endforeach),
zapytanie przygotowane dla numeru pozycji z formularza, sprawdzenie, że to liczba 1-4, i htmlspecialchars przy każdym wypisaniu danych,
wybrana pozycja zostaje zaznaczona na liście po wysłaniu formularza.
To arkusz EE.09 ze stycznia 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i grafiki pochodzą z oryginalnego archiwum CKE z2.zip (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.
Jak liczą się punkty. Klucz ma 38 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 29 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz nie narzuca biblioteki PHP do obsługi bazy.
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 38 kryteriów (pkt)
Krok 1: Folder zdającego i archiwum z2.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 z2.zip zabezpieczone hasłem: $piLkaRze% 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. Po skończonej pracy wyniki zapisz również w tym folderze.
Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum z2.zip rozpakowane z hasłem $piLkaRze% (wielkie L i R). W środku: egzamin.sql, obraz1.jpg i zad2.png. Do tego folderu trafiają wszystkie rezultaty pracy.
Krok 2: XAMPP i pusta baza egzamin
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
Start przy Apache i MySQL, potem http://localhost/phpmyadmin, Nowa, nazwa egzamin, porównywanie np. utf8mb4_polish_ci, Utwórz.
Krok 3: Import pliku egzamin.sql i zrzut import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych egzamin , czynność udokumentowano plikiem o nazwie import w formacie PNG
ok. 3 min
Polecenie z arkusza
Do bazy egzamin zaimportuj plik egzamin.sql z rozpakowanego archiwum. 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
Baza egzamin zaznaczona, karta Import, plik egzamin.sql, Wykonaj. Plik tworzy osiem tabel - cztery z obrazu 1 i cztery niepotrzebne w zadaniu (typy, uslugi, wyniki, zdjecia). Zrzut całego ekranu z komunikatem o sukcesie i listą tabel: import.png.
Typowe błędy
Zrzut importu w PNG, zrzuty zapytań w JPG - zły format to strata punktu.
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: napastnicy
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 pola imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisano id pozycji równe 4 . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 4; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 2 rekordy: Arkadiusz Milik, Adam Buksa
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 imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisane jest id pozycji równe 4
Każda klauzula w osobnej linii - zapytanie czyta się jak zdanie: co (SELECT imie, nazwisko - „jedynie” wyklucza *), skąd (FROM zawodnik), które wiersze (WHERE pozycja_id = 4, „id pozycji” to klucz obcy do tabeli pozycja). Wynik: Arkadiusz Milik i Adam Buksa. Zapytanie trafia do kwerendy.txt, zrzut do kw1.jpg. W skrypcie 1 w miejscu 4 stanie parametr z listy.
R.1.4 Utworzono zapytanie 2 wybierające jedynie pola zespol, punkty, grupa z tabeli liga sortowane malejąco według punktów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie sześć rekordów: dla zespołów EVG, ARS, FCB, CHL, JUV, RM, jedynie kolumny zespol, punkty, grupa
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pola zespol, punkty, grupa z tabeli liga sortowane malejąco według punktów
ORDER BY punkty DESC - od największej liczby punktów. Wynik: sześć drużyn od EVG (34) do RM (5), zrzut kw2.jpg. To zapytanie wykona skrypt 2.
kwerendy.txtTekstzmienione: 5 linii
-- Zapytanie 1SELECT imie, nazwiskoFROM zawodnikWHERE pozycja_id = 4;-- Zapytanie 2SELECT zespol, punkty, grupaFROM ligaORDER BY punkty DESC;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: zawodnicy 3 i 5 z nazwą pozycji
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające jedynie pola id, nazwisko z tabeli zawodnik, oraz nazwę z tabeli pozycja dla zawodników, których id jest równe 3 lub 5. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zawodnik.id, nazwisko, pozycja.nazwa FROM zawodnik JOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.id=3 OR zawodnik.id=5; lub SELECT zawodnik.id, nazwisko, pozycja.nazwa FROM zawodnik, pozycja WHERE zawodnik.pozycja_id = pozycja.id AND (zawodnik.id=3 OR zawodnik.id=5); (nawias wymagany) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dwa rekordy, jedynie pola id, nazwisko, nazwa, dla id = 3 oraz id = 5
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pola id, nazwisko z tabeli zawodnik oraz nazwę z tabeli pozycja dla zawodników, których id jest równe 3 lub 5
Złączenie z aliasami tabel: zawodnik AS z i pozycja AS p - krótsze nazwy, a z.id jednoznacznie wskazuje kolumnę id zawodnika (jest w obu tabelach). JOIN … ON p.id = z.pozycja_id dołącza do zawodnika jego pozycję, a IN (3, 5) to krótszy zapis warunku z.id = 3 OR z.id = 5 - nie wymaga nawiasów przy łączeniu z innymi warunkami. Wynik: 3 Bednarek obronca, 5 Grosicki pomocnik - zrzut kw3.jpg.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT imie, nazwiskoFROM zawodnikWHERE pozycja_id = 4;-- Zapytanie 2SELECT zespol, punkty, grupaFROM ligaORDER BY punkty DESC;-- Zapytanie 3SELECT z.id, z.nazwisko, p.nazwaFROM zawodnik AS zJOIN pozycja AS p ON p.id = z.pozycja_idWHERE z.id IN (3, 5);
R.1.6 Utworzono zapytanie 4 usuwające za pomocą jednej kwerendy SQL wszystkie dane z tabeli rozgrywka (sama tabela nie jest usuwana). W pliku z kwerendami lub na zrzucie istnieje zapis np.: TRUNCATE rozgrywka; lub DELETE FROM rozgrywka; oraz wynik działania zapytania udokumentowano zrzutem z widocznym poprawnym zapytaniem lub pustą tabelą rozgrywka
ok. 2 min
Polecenie z arkusza
Zapytanie 4: usuwające jedną kwerendą SQL wszystkie dane z tabeli rozgrywka (sama tabela nie jest usuwana)
TRUNCATE TABLE rozgrywka; usuwa wszystkie wiersze, tabela zostaje pusta (klucz przyjmuje też DELETE FROM rozgrywka;). DROP TABLE usunąłby tabelę - arkusz tego zabrania. Zrzut kw4.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT imie, nazwiskoFROM zawodnikWHERE pozycja_id = 4;-- Zapytanie 2SELECT zespol, punkty, grupaFROM ligaORDER BY punkty DESC;-- Zapytanie 3SELECT z.id, z.nazwisko, p.nazwaFROM zawodnik AS zJOIN pozycja AS p ON p.id = z.pozycja_idWHERE z.id IN (3, 5);-- Zapytanie 4TRUNCATE TABLE rozgrywka;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-18 · po tym etapie masz 17 z 38 kryteriów (pkt)
Krok 8: Grafika zad2.png: szerokość 50 px z przezroczystością
Kryteria:
R.2.1 Plik zad2.png przeskalowano z zachowaniem proporcji do szerokości 50 px, odpowiadająca temu wysokość wynosi 71 px (± 5 px); przezroczystość została zachowana
ok. 2 min
Polecenie z arkusza
Plik zad2.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 50 px. Należy zachować przezroczystość obrazu
GIMP: Obraz → Skaluj obraz, łańcuch zamknięty, szerokość 50 px - wysokość wychodzi 71 px (589 × 50 / 414). Eksport jako PNG, który zachowuje kanał alfa - tło zostaje przezroczyste.
Podgląd strony po tym kroku
Krok 9: Plik liga.php: szkielet HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie liga.php
Plik liga.php od razu z kompletnym nagłówkiem dokumentu: <!DOCTYPE html> (HTML5), lang="pl" (język treści) i znacznik viewport - na telefonie strona nie będzie pomniejszana do rozmiaru ekranu komputera. Kolejne trzy linie <head> to osobne wymagania arkusza, opisane w następnych krokach.
R.3.4 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl2.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 styl2.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl2.css"> - nazwa z cyfrą 2; całe formatowanie strony pochodzi z tego pliku (R.3.4).
Podział strony na bloki: baner, blok lewy i prawy, blok główny, blok liga zawierający zmienną liczbę bloków z informacją o drużynach. Bloki informacyjne generowane są skryptem, ich liczba zależy od liczby rekordów. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Pięć bloków z arkusza to znaczniki <section> z identyfikatorami banner, left, right, main, league. Bloki lewy i prawy stoją dodatkowo w <div class="columns"> - pojemniku bez znaczenia treściowego (dlatego div, nie section), który w CSS dostanie display: flex i ustawi oba bloki obok siebie. Bloki z drużynami wygeneruje skrypt wewnątrz #league.
Zawartość bloku banera: Nagłówek trzeciego stopnia o treści „Reprezentacja polski w piłce nożnej”. Obraz obraz1.jpg z tekstem alternatywnym o treści: „reprezentacja”
<h3> i <img> z tekstem alternatywnym. Atrybuty width i height z prawdziwym rozmiarem zdjęcia (930 × 272) pozwalają przeglądarce zarezerwować miejsce, zanim plik się wczyta - treść poniżej nie „podskakuje”.
liga.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>piłka nożna</title> <linkrel="stylesheet"href="styl2.css"></head><body> <sectionid="banner"> <h3>Reprezentacja polski w piłce nożnej</h3> <imgsrc="obraz1.jpg"alt="reprezentacja"width="930"height="272"> </section> <divclass="columns"> <sectionid="left"> </section> <sectionid="right"> </section> </div> <sectionid="main"> </section> <sectionid="league"> </section></body></html>
Podgląd strony po tym kroku (liga.php)
Krok 15: Formularz z listą rozwijalną i przyciskiem „Zobacz”
Kryteria: , , ,
R.2.7 W bloku lewym umieszczono formularz, zastosowano znacznik <form> oraz jego zamknięcie
R.2.8 W formularzu umieszczono listę rozwijalną z czterema elementami oraz przycisk "Zobacz"
R.3.2 Przycisk wysyła dane z formularza
R.3.3 Formularz wysyła dane metodą POST do tego samego pliku (poprawne również bez atrybutu action)
ok. 3 min
Polecenie z arkusza
Zawartość bloku lewego: Formularz wysyłający dane metodą POST do tej samej strony, zawierający: Listę rozwijalną z wpisami: Bramkarze, Obrońcy, Pomocnicy, Napastnicy. Przycisk wysyłający zawartość formularza z opisem „Zobacz”
<form method="post"> bez action - dane wracają do liga.php (R.2.7, R.3.3),
<select> z czterema <option>: tekst widzi użytkownik, a value z numerem 1-4 (jak id w tabeli pozycja) trafia do PHP,
aria-label - arkusz nie przewiduje widocznego opisu listy, więc opis „Pozycja zawodników” dostaje tylko czytnik ekranu; wygląd zostaje jak na obrazie 2,
<button type="submit"> - przycisk z napisem jako treścią znacznika; działa tak samo jak <input type="submit"> (R.2.8, R.3.2).
R.2.6 W bloku banera umieszczono obraz obraz1.jpg oraz w bloku lewym umieszczono obraz zad2.png. Przynajmniej jeden z obrazów ma tekst alternatywny: "reprezentacja" (dla obraz1.jpg ) lub "piłka" (dla zad2.png ) gdy obraz nie istnieje powinien wyświetlić się tekst alternatywny
ok. 1 min
Polecenie z arkusza
Obraz zad2.png z tekstem alternatywnym o treści: „piłka”. Paragraf (akapit) o treści: „Autor: ”, dalej wstawiony numer PESEL zdającego
Przeskalowany zad2.png z tekstem alternatywnym i wymiarami (oba obrazy z alt: R.2.6) oraz akapit z autorem - na egzaminie numer PESEL, tutaj Bartosz Bryniarski.
R.2.5 W bloku banera zapisano nagłówek h3: "Reprezentacja polski w piłce nożnej", w bloku głównym nagłówek h3: "Liga mistrzów" oraz zapisano paragraf z numerem PESEL
ok. 1 min
Polecenie z arkusza
Zawartość bloku głównego: nagłówek trzeciego stopnia o treści: „Liga mistrzów”. Zawartość bloku liga: Efekt działania skryptu 2
Drugi <h3>. Oba nagłówki i paragraf z autorem: R.2.5. Blok liga zostaje pusty do kroku ze skryptem 2.
Kroki 19-25 · po tym etapie masz 28 z 38 kryteriów (pkt)
Krok 19: Zmienne z kolorami i styl body
Kryteria:
R.4.1 Ustawiono krój czcionki Verdana dla selektora body lub kontenera całej strony
ok. 2 min
Polecenie z arkusza
Dla znacznika body: krój czcionki Verdana, kolor tła SeaGreen
Na początku styl2.css trzy zmienne CSS w :root (cały dokument): kolor strony, kolor szarych bloków i biel. Nazwa zmiennej zaczyna się od dwóch myślników, a odczytuje się ją funkcją var(). Zmiana koloru w jednym miejscu zmienia go na całej stronie - biel występuje w czterech regułach.
body dostaje krój Verdana i tło var(--page), czyli SeaGreen (R.4.1).
R.4.7 Ustawiono dla pojedynczego bloku z informacją o drużynach marginesy zewnętrzne (margin) 5px, biały kolor czcionki, szerokość 170px, wyrównanie tekstu do środka
R.4.8 Ustawiono obramowanie o szerokości 1px linią ciągłą, białą oraz nadano zaokrąglenie rogów ramki 15px (border-radius) dla pojedynczego bloku z informacją o drużynach
ok. 2 min
Polecenie z arkusza
Dla pojedynczego bloku z informacją o drużynach: biały kolor czcionki, wyrównanie tekstu do środka, szerokość 170 px, marginesy zewnętrzne 5 px, obramowanie: 1 px, linia ciągła, kolor biały, zaokrąglenie rogów obramowania 15 px
Skrypt 2 nada każdemu blokowi z drużyną klasę team - selektor .team mówi wprost, czego dotyczy, i nie zależy od tego, gdzie blok stoi. Wszystkie cechy z arkusza w jednej regule: biały tekst, wyśrodkowanie, 170 px szerokości, 5 px marginesu (R.4.7), ramka 1px solid w kolorze var(--light) i zaokrąglenie 15 px (R.4.8).
Krok 22: Biały blok z czarnym tekstem po najechaniu kursorem
Kryteria:
R.4.9 W momencie najechania kursorem na pojedynczy blok z informacją o drużynach kolor jego tła zmienia się na biały, a czcionki na czarny (np. ustawiony kolor dla pseudoklasy hover lub inne rozwiązania)
ok. 1 min
Polecenie z arkusza
W momencie najechania kursorem na pojedynczy blok z informacją o drużynach, kolor tła zmienia się na biały a kolor czcionki na czarny
.team:hover - tło białe, tekst czarny tylko wtedy, gdy kursor jest nad blokiem (R.4.9).
R.4.2 Ustawiono kolor tła SeaGreen dla selektora body lub kontenera całej strony oraz WhiteSmoke dla bloku lewego i prawego
R.4.3 Ustawiono biały kolor czcionki dla banera i bloku głównego
R.4.4 Ustawiono wysokość banera na 330px, bloku lewego i prawego: 150px
R.4.5 Ustawiono szerokość bloku lewego na 30% i prawego na 70%
ok. 2 min
Polecenie z arkusza
Dla bloku głównego: biały kolor czcionki. Dla bloku lewego: kolor tła WhiteSmoke, szerokość 30%, wyrównanie tekstu do środka, wysokość 150 px. Dla bloku prawego: kolor tła WhiteSmoke, szerokość 70%, wysokość 150 px
Blok główny tylko z białym tekstem (biel banera i bloku głównego: R.4.3). Bloki lewy i prawy z tłem var(--panel) (WhiteSmoke, R.4.2) i wysokością 150 px (R.4.4). Szerokości 30% i 70% zostają na blokach - tak je sprawdza klucz (R.4.5).
Krok 24: Nagłówki h3: wyśrodkowanie, odstęp liter, wielkie litery
Kryteria: ,
R.4.6 Ustawiono wyrównanie tekstu do środka dla banera, bloku lewego i selektora h3
R.4.10 Ustawiono styl selektora h3: odległość między literami 6px (letter-spacing) oraz kapitaliki (np. text-transform: capitalize; lub font-variant: small-caps;)
ok. 2 min
Polecenie z arkusza
Dla znacznika nagłówka trzeciego stopnia: wyrównanie tekstu do środka, odległość między literami 6 px, tekst napisany kapitalikami (capitalize)
text-align: center (razem z banerem i blokiem lewym: R.4.6), letter-spacing: 6px i text-transform: capitalize - wielka pierwsza litera każdego słowa, jak na obrazie 2 (R.4.10).
⚠️ Uwaga o nazewnictwie: „kapitaliki” to w typografii font-variant: small-caps, ale arkusz w nawiasie i obraz 2 wskazują capitalize. Klucz przyjmuje obie właściwości.
R.3.1 Widok układu bloków po uruchomieniu strony w przeglądarce jest w pełni zgodny z obrazem 2 w arkuszu egzaminacyjnym (nie należy brać pod uwagę bloków zawierających informacje o drużynach)
ok. 3 min
Polecenie z arkusza
Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Dwie reguły zamiast float i clear:
.columns { display: flex; } - blok lewy (30%) i prawy (70%) obok siebie, oba o wysokości 150 px. Pojemnik otacza oba bloki, więc blok główny sam staje pod nimi - bez clear,
#league { display: flex; flex-wrap: wrap; } - blok liga układa swoje dzieci (bloki z drużynami) w rzędzie, a gdy się nie mieszczą, zawija je do nowej linii.
Podgląd: kolumny stoją obok siebie, nagłówek „Liga Mistrzów” pod nimi; bloki drużyn dojdą ze skryptem 2 (R.3.1).
Typowe błędy
display: flex na samym #left ustawia w rzędzie jego zawartość (formularz, grafikę, akapit), nie same bloki - flex działa na dzieci elementu, któremu się go nada.
Kroki 26-32 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 26: Skrypt na górze pliku i połączenie przez PDO
Kryteria: ,
R.5.1 Skrypt napisano w języku PHP oraz zawiera on co najmniej jedną instrukcję poprawną składniowo
R.5.2 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy egzamin
ok. 4 min
Polecenie z arkusza
Skrypt połączenia z bazą. Napisany w języku PHP, w pliku liga.php. Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie egzamin
Kod PHP stoi na samej górze liga.php, przed <!DOCTYPE html>: najpierw pobiera dane z bazy do zmiennych, a HTML niżej tylko je wypisuje. Logika i wygląd strony są rozdzielone, a połączenie z bazą jest jedno dla obu skryptów.
e() - krótka funkcja z htmlspecialchars: każdy tekst wypisywany na stronie zamienia <, >, & i cudzysłowy na encje, więc nic z bazy ani z formularza nie zamieni się w kod strony,
$teams = [] - pusta lista na start: gdy baza nie odpowie, strona i tak się zbuduje,
new PDO(...) - serwer localhost, baza egzamin i kodowanie w jednym napisie, potem użytkownik root i puste hasło (R.5.1, R.5.2). ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek, FETCH_ASSOC - wiersze jako tablice z nazwami kolumn,
try / catch - gdy baza nie działa, zamiast komunikatu PHP z danymi serwera będzie zwykłe zdanie.
Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
Krok 27: Skrypt 1: odbiór i sprawdzenie pozycji z listy
Kryteria:
R.5.4 W skrypcie działającym na danych przesłanych z formularza zastosowano tablicę $_POST, zapis musi być poprawny składniowo i logicznie
ok. 3 min
Polecenie z arkusza
Działanie skryptu 1, który odbiera dane przesłane z formularza: Odbiera dane z pola listy wyboru. Jeśli nic nie jest wybrane nie jest wykonywana żadna akcja
$_POST['position'] ?? '' - wartość wybranego wpisu listy, a gdy formularza nie wysłano - pusty napis zamiast ostrzeżenia (R.5.4),
filter_var(…, FILTER_VALIDATE_INT, …) zwraca liczbę tylko wtedy, gdy tekst jest liczbą całkowitą z zakresu 1-4; brak wyboru, abc czy 9 dają false. Lista rozwijalna podsuwa cztery wartości tylko w przeglądarce - dane da się wysłać z pominięciem formularza.
Podgląd: wysłany wpis „Pomocnicy” (wartość 3) - lista jeszcze pusta.
Krok 28: Skrypt 1: zapytanie przygotowane i lista zawodników
Kryteria: ,
R.5.5 Skrypt 1 wysyła do bazy danych zmodyfikowane zapytanie 1 tak, że w warunku id pozycji jest zgodne z wyborem w liście rozwijalnej lub Skrypt 2 wysyła do bazy zapytanie 2
R.5.6 Skrypt 1 wyświetla zwrócone zapytaniem imiona i nazwiska, które zostały przesłane przez formularz
ok. 4 min
Polecenie z arkusza
W innym przypadku skrypt wysyła do bazy danych zmodyfikowane zapytanie 1 tak, że w warunku id pozycji jest zgodne z wyborem w liście. Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy numerowanej
if ($position !== false) - zapytanie tylko dla poprawnego numeru pozycji; bez wyboru nic się nie dzieje,
$pdo->prepare(…) z parametrem :position w miejscu 4 z zapytania 1, potem execute z wartością - baza dostaje treść zapytania i liczbę osobno, więc tekst z formularza nigdy nie stanie się kodem SQL (R.5.5),
w liście szablon foreach ($players as $player): … endforeach; - zapis z dwukropkiem, wygodny między znacznikami HTML; każdy zawodnik jako <li> z paragrafem <p>, każda wartość przez e().
Podgląd: Pomocnicy - Grzegorz Krychowiak i Kamil Grosicki, jak na obrazie 2 (R.5.6).
Krok 29: Wybrana pozycja zostaje zaznaczona na liście
ok. 2 min
Polecenie z arkusza
Listę rozwijalną z wpisami: Bramkarze, Obrońcy, Pomocnicy, Napastnicy
Po wysłaniu formularza strona wczytuje się od nowa i lista wraca do pierwszego wpisu - na obrazie 2 stoi „Bramkarze”, choć lista pokazuje pomocników. Klucz tego nie ocenia, ale to mylące: każdy <option> dostaje atrybut selected, gdy jego numer równa się sprawdzonej pozycji ($position === 3). Porównanie === z liczbą działa, bo filter_var zwraca liczbę całkowitą, a nie tekst.
Podgląd: po wysłaniu „Pomocnicy” lista pokazuje „Pomocnicy” obok wyniku.
Krok 30: Skrypt 2: zapytanie 2 i blok sekcji dla każdej drużyny
Kryteria: , ,
R.5.7 Skrypt 2 definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane zapytaniem dotyczące jednego rekordu
R.5.9 Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem
R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, blok lewy i prawy, blok główny, blok liga zawierający przynajmniej jeden blok z informacją o drużynach (w skrypcie lub HTML). Zastosowano znaczniki sekcji
ok. 4 min
Polecenie z arkusza
Działanie skryptu 2: Wysyła do bazy danych zapytanie 2. Definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane zapytaniem dotyczące jednego rekordu: W nagłówku drugiego stopnia nazwę zespołu pobraną z bazy danych. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem
$pdo->query("…")->fetchAll() wysyła zapytanie 2 i pobiera wszystkie wiersze do tablicy $teams - zapytanie nie ma danych od użytkownika, więc nie musi być przygotowane. W bloku liga szablon foreach ($teams as $team): powtarza <section class="team"> z nagłówkiem <h2> dla każdej drużyny - bloków jest tyle, ile wierszy zwróciła baza (R.5.7, R.5.9). Blok liga ma bloki z informacją o drużynach (R.2.4).
Podgląd: sześć bloków od EVG do RM, od razu w ramkach i w rzędzie.
liga.phpPHPzmienione: 7 linii
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$teams = [];$players = [];$position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);$error = null;try {$pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);if ($position !== false) {$statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');$statement->execute(['position' => $position]);$players = $statement->fetchAll(); }$teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();} catch (PDOException $exception) {$error = 'Nie udało się połączyć z bazą danych.';}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>piłka nożna</title> <linkrel="stylesheet"href="styl2.css"></head><body> <sectionid="banner"> <h3>Reprezentacja polski w piłce nożnej</h3> <imgsrc="obraz1.jpg"alt="reprezentacja"width="930"height="272"> </section> <divclass="columns"> <sectionid="left"> <formmethod="post"> <selectname="position"aria-label="Pozycja zawodników"> <optionvalue="1"<?= $position === 1 ? ' selected' : ''?>>Bramkarze</option> <optionvalue="2"<?= $position === 2 ? ' selected' : ''?>>Obrońcy</option> <optionvalue="3"<?= $position === 3 ? ' selected' : ''?>>Pomocnicy</option> <optionvalue="4"<?= $position === 4 ? ' selected' : ''?>>Napastnicy</option> </select> <buttontype="submit">Zobacz</button> </form> <imgsrc="zad2.png"alt="piłka"width="50"height="71"> <p>Autor: Bartosz Bryniarski</p> </section> <sectionid="right"> <ol><?phpforeach ($playersas$player): ?> <li><p><?= e($player['imie']) ?><?= e($player['nazwisko']) ?></p></li><?phpendforeach; ?> </ol> </section> </div> <sectionid="main"> <h3>Liga mistrzów</h3> </section> <sectionid="league"><?phpforeach ($teamsas$team): ?> <sectionclass="team"> <h2><?= e($team['zespol']) ?></h2> </section><?phpendforeach; ?> </section></body></html>
Podgląd strony po tym kroku (liga.php)
Krok 31: Skrypt 2: punkty w h1 i grupa w paragrafie
Kryteria:
R.5.8 Skrypt 2 wyświetla dane wg wzoru: nazwa zespołu pobrana skryptem w h2, punkty pobrane skryptem w h1, w paragrafie tekst: „grupa: <grupa>”, gdzie <grupa> oznacza daną pobraną skryptem z bazy danych
ok. 2 min
Polecenie z arkusza
W nagłówku pierwszego stopnia punkty pobrane skryptem. W paragrafie tekst: „grupa: <grupa>”, gdzie <grupa> oznacza daną pobraną skryptem
Dwie linie szablonu: <h1> z punktami i paragraf „grupa: ” z literą grupy. Kolumny odczytuje się po nazwach ($team['punkty']), a nie po numerach - kolejność kolumn w zapytaniu przestaje mieć znaczenie (R.5.8).
Krok 32: Zamknięcie połączenia i komunikat o błędzie bazy
Kryteria:
R.5.3 Po wykonaniu operacji na bazie zastosowano funkcję zamknięcia bazy
ok. 3 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem
Blok finally wykonuje się zawsze - po udanych zapytaniach i po błędzie. $statement = null i $pdo = null zamykają połączenie: PDO nie ma osobnej funkcji close, połączenie znika, gdy żadna zmienna go nie trzyma (R.5.3). Połączenie trwa tylko tyle, ile zapytania - HTML wypisuje się już bez niego.
W bloku liga doszedł warunek wypisujący w paragrafie komunikat $error, gdy baza nie odpowiedziała. Sprawdzone przy niedostępnej bazie: strona się wyświetla, a zamiast drużyn stoi „Nie udało się połączyć z bazą danych.” Podgląd: stan z obrazu 2.
liga.phpPHPzmienione: 6 linii
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$teams = [];$players = [];$position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);$error = null;try {$pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);if ($position !== false) {$statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');$statement->execute(['position' => $position]);$players = $statement->fetchAll(); }$teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();} catch (PDOException $exception) {$error = 'Nie udało się połączyć z bazą danych.';} finally {$statement = null;$pdo = null; // zamknięcie połączenia - po ostatniej operacji na bazie}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>piłka nożna</title> <linkrel="stylesheet"href="styl2.css"></head><body> <sectionid="banner"> <h3>Reprezentacja polski w piłce nożnej</h3> <imgsrc="obraz1.jpg"alt="reprezentacja"width="930"height="272"> </section> <divclass="columns"> <sectionid="left"> <formmethod="post"> <selectname="position"aria-label="Pozycja zawodników"> <optionvalue="1"<?= $position === 1 ? ' selected' : ''?>>Bramkarze</option> <optionvalue="2"<?= $position === 2 ? ' selected' : ''?>>Obrońcy</option> <optionvalue="3"<?= $position === 3 ? ' selected' : ''?>>Pomocnicy</option> <optionvalue="4"<?= $position === 4 ? ' selected' : ''?>>Napastnicy</option> </select> <buttontype="submit">Zobacz</button> </form> <imgsrc="zad2.png"alt="piłka"width="50"height="71"> <p>Autor: Bartosz Bryniarski</p> </section> <sectionid="right"> <ol><?phpforeach ($playersas$player): ?> <li><p><?= e($player['imie']) ?><?= e($player['nazwisko']) ?></p></li><?phpendforeach; ?> </ol> </section> </div> <sectionid="main"> <h3>Liga mistrzów</h3> </section> <sectionid="league"><?phpif ($error !== null): ?> <p><?= e($error) ?></p><?phpendif; ?><?phpforeach ($teamsas$team): ?> <sectionclass="team"> <h2><?= e($team['zespol']) ?></h2> <h1><?= e($team['punkty']) ?></h1> <p>grupa: <?= e($team['grupa']) ?></p> </section><?phpendforeach; ?> </section></body></html>
Krok 33 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 33: Co różni tę wersję od podstawowej
ok. 2 min
Polecenie z arkusza
Napisany w języku PHP, w pliku liga.php
Obie wersje dają tę samą stronę i te same punkty. Różnice:
układ: float + clear kontra display: flex - flex nie wymaga pamiętania o clear, a blok liga ma prawdziwą wysokość (otacza bloki drużyn),
PHP: mysqli w dwóch blokach w środku HTML-u kontra PDO na górze pliku i szablon foreach / endforeach - kod bazy w jednym miejscu, HTML prawie bez PHP,
bezpieczeństwo: w wersji podstawowej wartość z listy trafia do zapytania wprost (wstrzyknięcie 0 OR 1=1 pokazuje wszystkich zawodników, UNION - dane z innej tabeli), tutaj jest sprawdzana (filter_var, zakres 1-4) i przekazywana parametrem zapytania przygotowanego; każdy tekst przechodzi przez htmlspecialchars,
wygoda: wybrana pozycja zostaje zaznaczona, lista ma opis dla czytnika ekranu, przycisk to <button>.
PRG (przekierowanie po wysłaniu formularza) nie jest tu potrzebne: formularz niczego nie zapisuje w bazie, tylko wyszukuje - ponowne wysłanie po odświeżeniu strony niczego nie psuje.
liga.phpPHPzmienione: 0 linii
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$teams = [];$players = [];$position = filter_var($_POST['position'] ?? '', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);$error = null;try {$pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);if ($position !== false) {$statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');$statement->execute(['position' => $position]);$players = $statement->fetchAll(); }$teams = $pdo->query('SELECT zespol, punkty, grupa FROM liga ORDER BY punkty DESC;')->fetchAll();} catch (PDOException $exception) {$error = 'Nie udało się połączyć z bazą danych.';} finally {$statement = null;$pdo = null; // zamknięcie połączenia - po ostatniej operacji na bazie}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>piłka nożna</title> <linkrel="stylesheet"href="styl2.css"></head><body> <sectionid="banner"> <h3>Reprezentacja polski w piłce nożnej</h3> <imgsrc="obraz1.jpg"alt="reprezentacja"width="930"height="272"> </section> <divclass="columns"> <sectionid="left"> <formmethod="post"> <selectname="position"aria-label="Pozycja zawodników"> <optionvalue="1"<?= $position === 1 ? ' selected' : ''?>>Bramkarze</option> <optionvalue="2"<?= $position === 2 ? ' selected' : ''?>>Obrońcy</option> <optionvalue="3"<?= $position === 3 ? ' selected' : ''?>>Pomocnicy</option> <optionvalue="4"<?= $position === 4 ? ' selected' : ''?>>Napastnicy</option> </select> <buttontype="submit">Zobacz</button> </form> <imgsrc="zad2.png"alt="piłka"width="50"height="71"> <p>Autor: Bartosz Bryniarski</p> </section> <sectionid="right"> <ol><?phpforeach ($playersas$player): ?> <li><p><?= e($player['imie']) ?><?= e($player['nazwisko']) ?></p></li><?phpendforeach; ?> </ol> </section> </div> <sectionid="main"> <h3>Liga mistrzów</h3> </section> <sectionid="league"><?phpif ($error !== null): ?> <p><?= e($error) ?></p><?phpendif; ?><?phpforeach ($teamsas$team): ?> <sectionclass="team"> <h2><?= e($team['zespol']) ?></h2> <h1><?= e($team['punkty']) ?></h1> <p>grupa: <?= e($team['grupa']) ?></p> </section><?phpendforeach; ?> </section></body></html>
Krok 34 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 34: 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 nazwa przeglądarki, w której sprawdzasz stronę. W folderze z numerem PESEL: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, liga.php, obraz1.jpg, przeglądarka.txt, styl2.css, zad2.png. Płytę nagrywasz, sprawdzasz jej odczyt i opisujesz numerem PESEL.
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.