Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-01-25.01-SGStyczeń 2025 · 35 kroków · ok. 76 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Rozgrywki futbolowe i reprezentacja Polski (Nowoczesny kod (flex, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza egzamin z czterema zapytaniami, przeskalowana grafika piłkarza i strona futbol.php z blokami meczów i listą zawodników - i tak samo spełnia każde kryterium klucza. Inna jest droga:
flex zamiast float: blok mecze jest kontenerem, który sam układa bloki z rozgrywkami w rzędzie i zawija je do nowej linii, a bloki lewy i prawy stoją w pojemniku z display: flex - bez clear,
zmienne CSS dla kolorów z arkusza, klasa dla bloku z rozgrywką, etykieta <label> połączona z polem liczbowym,
PHP na PDO na górze pliku futbol.php, przed HTML-em: najpierw pobranie danych, potem HTML tylko je wypisuje (szablon foreach / endforeach),
zapytanie przygotowane dla liczby z formularza, sprawdzenie, że to numer pozycji 1-4, i htmlspecialchars przy każdym wypisaniu danych,
wybrana pozycja zostaje w polu po wysłaniu formularza (na obrazie 2 w polu stoi 4 obok wyniku).
To arkusz EE.09 ze stycznia 2025 - kwalifikacji formuły 2017, którą zastąpiła INF.03 (zadanie powtarza arkusz ze stycznia 2021 z dopisanymi wymaganiami HTML5, jawnego kodowania i języka strony). Archiwum dane.7z tej sesji nie jest opublikowane w materiałach CKE/OKE - baza i grafiki pochodzą z identycznego archiwum CKE z1.zip z pierwszego wydania zadania (arkusz EE.09-01-21.01), 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 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 38 kryteriów (pkt)
Krok 1: Folder zdającego i archiwum z materiałami
ok. 2 min
Polecenie z arkusza
Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie dane.7z zabezpieczone hasłem: !Futboi& Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu należy użyć numeru zdającego. Umieść w tym folderze rozpakowane pliki. Po skończonej pracy wyniki zapisz również w tym folderze.
Folder na pulpicie nazwany numerem zdającego (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum dane.7z rozpakowane 7-Zipem z hasłem !Futboi& (przed ostatnim znakiem litera i). W środku: egzamin.sql, obraz1.jpg i zad1.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 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: mecze drużyny EVG
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 Wykonano zapytanie 1 wybierające jedynie pola zespol1, zespol2, wynik, data_rozgrywki z tabeli rozgrywka dla wartości pola zespol1 równego „EVG”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = "EVG"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie 5 rekordów, jedynie pola zespol1, zespol2, wynik, data_rozgrywki; w polu zespol1 widnieje tylko "EVG"
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 zdającego. 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 zespol1, zespol2, wynik, data_rozgrywki z tabeli rozgrywka dla rekordów o wartości pola zespol1 równej „EVG”
Każda klauzula w osobnej linii - tak zapytanie czyta się jak zdanie: co (SELECT z czterema kolumnami - „jedynie” wyklucza *), skąd (FROM rozgrywka), które wiersze (WHERE zespol1 = 'EVG'). Wynik: 5 meczów, te same co w blokach na obrazie 2. Zapytanie trafia do kwerendy.txt, zrzut do kw1.jpg.
R.1.4 Wykonano zapytanie 2 wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, którym przypisano id pozycji równe 3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 3; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dane: Grzegorz Krychowiak i Kamil Grosicki
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pola imie i nazwisko z tabeli zawodnik dla zawodników, dla których przypisane jest id pozycji równe 3
„Id pozycji” to kolumna pozycja_id (klucz obcy do tabeli pozycja). Wynik: Grzegorz Krychowiak i Kamil Grosicki, zrzut kw2.jpg. W skrypcie w miejscu 3 stanie parametr z formularza.
R.1.5 Wykonano zapytanie 3 wybierające jedynie pola id zawodnika, nazwisko, oraz nazwę pozycji z tabel zawodnik i pozycja dla zawodników, których id jest równe 1, 2 lub 3. 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 < 4; (możliwe inne zapisy warunku, INNER JOIN lub bez JOIN - porównanie kluczy w warunku oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie trzy rekordy, jedynie pola id, nazwisko, nazwa, dla id = 1, 2, 3, uwaga: jeżeli zapytanie bez JOIN to alternatywa (OR) obowiązkowo w nawiasie
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pola id, nazwisko z tabeli zawodnik oraz nazwę pozycji z tabeli pozycja dla zawodników, którym przypisane jest id równe 1, 2 lub 3
Złączenie z aliasami tabel: zawodnik AS z i pozycja AS p - krótsze nazwy w całym zapytaniu, 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ę, IN (1, 2, 3) wybiera trzech zawodników. Wynik: 1 Szczesny bramkarz, 2 Pietrzak obronca, 3 Bednarek obronca - zrzut kw3.jpg. Nagłówki kolumn wyniku to id, nazwisko, nazwa: aliasy tabel ich nie zmieniają.
kwerendy.txtTekstzmienione: 6 linii
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywkiFROM rozgrywkaWHERE zespol1 = 'EVG';-- Zapytanie 2SELECT imie, nazwiskoFROM zawodnikWHERE pozycja_id = 3;-- Zapytanie 3SELECT z.id, z.nazwisko, p.nazwaFROM zawodnik AS zJOIN pozycja AS p ON p.id = z.pozycja_idWHERE z.id IN (1, 2, 3);
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: usunięcie tabeli liga
Kryteria:
R.1.6 Wykonano zapytanie 4 usuwające tabelę liga. W pliku z kwerendami lub na zrzucie istnieje zapis np.: DROP TABLE liga; oraz wynik działania zapytania udokumentowano zrzutem wskazującym na poprawne wykonanie zapytania
ok. 2 min
Polecenie z arkusza
Zapytanie 4: usuwające tabelę liga
DROP TABLE liga; usuwa tabelę razem ze strukturą (DELETE i TRUNCATE usuwają tylko wiersze). Potwierdzenie w phpMyAdmin, komunikat „MySQL zwrócił pusty wynik”, zrzut kw4.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywkiFROM rozgrywkaWHERE zespol1 = 'EVG';-- Zapytanie 2SELECT imie, nazwiskoFROM zawodnikWHERE pozycja_id = 3;-- Zapytanie 3SELECT z.id, z.nazwisko, p.nazwaFROM zawodnik AS zJOIN pozycja AS p ON p.id = z.pozycja_idWHERE z.id IN (1, 2, 3);-- Zapytanie 4DROP TABLE liga;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-19 · po tym etapie masz 18 z 38 kryteriów (pkt)
Krok 8: Grafika zad1.png: szerokość 150 px z przezroczystością
Kryteria:
R.2.1 Plik zad1.png przeskalowano z zachowaniem proporcji do szerokości 150 px, odpowiadająca temu wysokość wynosi 165 px (± 5 px); przezroczystość została zachowana
ok. 2 min
Polecenie z arkusza
Plik zad1.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 150 px. Należy zachować przezroczystość obrazu
GIMP: Obraz → Skaluj obraz, łańcuch zamknięty, szerokość 150 px - wysokość wychodzi 165 px (402 × 150 / 366). Eksport jako PNG, który zachowuje kanał alfa - tło zostaje przezroczyste.
Podgląd strony po tym kroku
Krok 9: Plik futbol.php: szkielet HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie futbol.php. Zapisana w języku HTML 5. Ustawiony język zawartości strony na polski
Plik futbol.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 styl.css, formatowanie CSS 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 styl.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl.css"> - całe formatowanie strony pochodzi z tego pliku (R.3.4).
R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, blok mecze, poniżej blok główny, lewy i prawy. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: baner, poniżej blok mecze zawierający zmienną liczbę bloków z informacją o rozgrywkach. Bloki informacyjne generowane są skryptem, a ich liczba zależy od danych w bazie. Poniżej blok główny, poniżej bloki lewy i prawy. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Pięć bloków z arkusza to znaczniki <section> z identyfikatorami banner, matches, main, left, right. Bloki lewy i prawy stoją dodatkowo w <div class="columns"> - to pojemnik bez znaczenia treściowego (dlatego div, nie section), który w CSS dostanie display: flex i ustawi oba bloki obok siebie. Bloki z meczami wygeneruje skrypt wewnątrz #matches. Podział na bloki: R.2.4.
Zawartość bloku banera: Nagłówek drugiego stopnia o treści „Światowe rozgrywki piłkarskie”. Obraz obraz1.jpg z tekstem alternatywnym o treści: „boisko”
<h2> i <img> z tekstem alternatywnym. Atrybuty width i height z prawdziwym rozmiarem zdjęcia (930 × 310) pozwalają przeglądarce zarezerwować miejsce, zanim plik się wczyta - treść poniżej nie „podskakuje”.
R.2.5 W bloku banera zapisano nagłówek h2: "Światowe rozgrywki piłkarskie", w bloku głównym nagłówek h2: "Reprezentacja Polski" oraz zapisano przynajmniej jeden paragraf
ok. 1 min
Polecenie z arkusza
Zawartość bloku lewego: Paragraf (akapit) o treści: „Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):”
Paragraf <p> z arkusza, a jego tekst w <label for="position"> - to opis pola, które za chwilę dostanie id="position". Kliknięcie w tekst ustawia kursor w polu, a czytnik ekranu odczyta opis razem z polem. Oba nagłówki i paragraf: R.2.5.
Krok 17: Formularz z polem liczbowym i przyciskiem „Sprawdź”
Kryteria: , , ,
R.2.7 W bloku lewym umieszczono formularz
R.2.8 Na stronie umieszczono pole edycyjne oraz przycisk "Sprawdź"
R.3.2 Przycisk wysyła dane z formularza oraz pole do wprowadzania danych jest typu liczbowego
R.3.3 Formularz wysyła dane metodą POST do tego samego pliku
ok. 3 min
Polecenie z arkusza
Formularz wysyłający dane metodą POST do tej samej strony, zawierający: Pole edycyjne typu numerycznego. Przycisk wysyłający zawartość formularza z opisem „Sprawdź”
<form method="post"> bez action - dane wracają do futbol.php (R.2.7, R.3.3),
type="number" z min="1" i max="4" - strzałki pola nie wyjdą poza numery pozycji z tabeli pozycja, a przeglądarka podpowie błąd przy innej liczbie. To tylko wygoda: skrypt i tak sprawdzi liczbę sam,
<button type="submit"> - przycisk z napisem jako treścią znacznika (przyjąłby też ikonę albo pogrubienie); działa tak samo jak <input type="submit"> (R.2.8, R.3.2).
Pole nie ma required: arkusz mówi, co ma się stać przy pustym polu (nic), więc puste wysłanie musi być możliwe.
R.2.6 W bloku banera umieszczono obraz obraz1.jpg z tekstem alternatywnym: "boisko" lub w bloku prawym umieszczono obraz z piłkarzem z tekstem alternatywnym: "piłkarz"
ok. 1 min
Polecenie z arkusza
Zawartość bloku prawego: Obraz zad1.png z tekstem alternatywnym o treści: „piłkarz”. Paragraf (akapit) o treści: „Autor: ”, dalej wstawiony numer zdającego
Przeskalowany zad1.png z tekstem alternatywnym (oba obrazy z alt: R.2.6) i akapit z autorem - na egzaminie numer zdającego, tutaj Bartosz Bryniarski.
Kroki 20-26 · po tym etapie masz 29 z 38 kryteriów (pkt)
Krok 20: Zmienne z kolorami i styl body
Kryteria:
R.4.1 Ustawiono krój czcionki Tahoma dla body
ok. 2 min
Polecenie z arkusza
Dla znacznika body: krój czcionki Tahoma, kolor tła Crimson
Na początku styl.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 - WhiteSmoke występuje w trzech blokach, biel w trzech regułach.
body dostaje krój Tahoma i tło var(--page), czyli Crimson (R.4.1).
R.4.7 Dla pojedynczego bloku z informacją o rozgrywkach ustawiono: biały kolor czcionki, szerokość 200px, wyrównanie tekstu do środka, marginesy zewnętrzne (margin) 10px
R.4.8 Dla pojedynczego bloku z informacją o rozgrywkach ustawiono obramowanie o szerokości 1px linią ciągłą, czarną (wartość domyślna nie musi być zapisana) oraz nadano zaokrąglenie rogów ramki 10px (border-radius)
ok. 2 min
Polecenie z arkusza
Dla pojedynczego bloku z informacją o rozgrywkach: biały kolor czcionki, wyrównanie tekstu do środka, szerokość 200 px, marginesy zewnętrzne 10 px, obramowanie: 1 px, linia ciągła, kolor czarny, zaokrąglenie rogów obramowania 10 px
Skrypt 1 nada każdemu blokowi z meczem klasę match - selektor .match 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, 200 px szerokości, 10 px marginesu (R.4.7), ramka 1px solid black i zaokrąglenie 10 px (R.4.8).
R.4.9 W momencie najechania kursorem na pojedynczy blok z informacją o rozgrywkach kolor jego ramki zmienia się na biały (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 rozgrywkach, kolor jego ramki zmienia się na biały
.match:hover zmienia tylko border-color - grubość i styl linii zostają (R.4.9).
R.4.2 Ustawiono kolor tła Crimson dla body, oraz WhiteSmoke dla bloków głównego, lewego i prawego
R.4.4 Ustawiono wysokość banera na 370px, bloku głównego: 50px, lewego i prawego: 230px
R.4.5 Ustawiono szerokość bloku lewego na 70% i prawego na 30%
ok. 2 min
Polecenie z arkusza
Dla bloku głównego: kolor tła WhiteSmoke, wysokość 50 px. Dla bloku lewego: kolor tła WhiteSmoke, szerokość 70%, wysokość 230 px. Dla bloku prawego: kolor tła WhiteSmoke, szerokość 30%, wysokość 230 px, wyrównanie tekstu do prawej strony
Trzy reguły z tłem var(--panel) (WhiteSmoke). Szerokości 70% i 30% zostają na blokach - tak je sprawdza klucz (R.4.5). Wysokości banera i trzech bloków (R.4.4), tła (R.4.2) i wyrównanie do prawej w bloku prawym są ustawione.
Krok 25: Nagłówki h2: wyśrodkowanie, odstęp liter, wielkie litery
Kryteria: ,
R.4.6 Ustawiono wyrównanie tekstu do środka dla banera i nagłówka h2 oraz wyrównanie do prawej strony dla bloku prawego
R.4.10 Ustawiono styl nagłówka h2: odległość między literami (letter-spacing) 7px oraz kapitaliki (text- transform: capitalize;)
ok. 2 min
Polecenie z arkusza
Dla znacznika nagłówka drugiego stopnia: wyrównanie tekstu do środka, odległość między literami 7 px, tekst napisany kapitalikami (capitalize)
text-align: center (R.4.6), letter-spacing: 7px 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 z tej sesji wymienia tylko capitalize.
R.3.1 Układ 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 generowanych skryptem (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float albo display flex albo grid albo position)
ok. 3 min
Polecenie z arkusza
Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Dwie reguły zamiast float i clear:
#matches { display: flex; flex-wrap: wrap; } - blok mecze układa swoje dzieci (bloki z rozgrywkami) w rzędzie, a gdy się nie mieszczą, zawija je do nowej linii. Blok mecze ma przy tym prawdziwą wysokość (otacza bloki), więc blok główny sam staje pod nim - bez clear,
.columns { display: flex; } - blok lewy (70%) i prawy (30%) obok siebie. Oba mają podaną wysokość 230 px, więc stoją równo.
Podgląd: kolumny stoją już obok siebie; bloki meczów dojdą ze skryptem 1 (R.3.1).
Typowe błędy
display: flex na samym #left albo #right ustawia w rzędzie ich zawartość, nie same bloki - flex działa na dzieci elementu, któremu się go nada.
Kroki 27-33 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 27: Skrypt na górze pliku i połączenie przez PDO
Kryteria: ,
R.5.1 Skrypt napisano w języku PHP i zawiera przynajmniej jedną instrukcję zgodną ze składnią
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 futbol.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 futbol.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,
$matches = [] - 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.
PDO zamiast funkcji mysqli z tabeli 1 - klucz przyjmuje obie biblioteki (uwaga przy R.5). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
R.5.5 Skrypt 1 wysyła do bazy danych zapytanie 1 lub Skrypt 2 wysyła do bazy zmodyfikowane zapytanie 2 tak, że w warunku id pozycji jest równe wartości z pola edycyjnego
ok. 2 min
Polecenie z arkusza
Działanie skryptu 1: Wysyła do bazy danych zapytanie 1
$pdo->query("…") wysyła zapytanie 1, a ->fetchAll() od razu pobiera wszystkie wiersze do tablicy $matches - pięć meczów, każdy jako tablica ['zespol1' => 'EVG', 'zespol2' => 'FCB', …] (R.5.5). Zapytanie nie ma żadnych danych od użytkownika, więc nie musi być przygotowane. Na stronie jeszcze nic nie widać.
futbol.phpPHPzmienione: 1 linia
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$matches = [];$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, ]);$matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->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>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"width="930"height="310"> </section> <sectionid="matches"> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <divclass="columns"> <sectionid="left"> <p><labelfor="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p> <formmethod="post"> <inputtype="number"id="position"name="position"min="1"max="4"> <buttontype="submit">Sprawdź</button> </form> <ul> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"width="150"height="165"> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Krok 29: Skrypt 1: blok sekcji z nagłówkiem dla każdego meczu
Kryteria: ,
R.5.6 Skrypt 1 definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane zapytaniem dotyczące jednego rekordu
R.5.8 Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem
ok. 4 min
Polecenie z arkusza
Definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane zwrócone zapytaniem dotyczące jednego wiersza: W nagłówku trzeciego stopnia tekst: „<zespół 1> - <zespół 2>”, gdzie pola w nawiasach <> oznaczają dane pobrane zapytaniem. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem
W bloku mecze szablon: foreach ($matches as $match): … endforeach; - zapis z dwukropkiem, wygodny między znacznikami HTML. Wszystko między nimi powtarza się dla każdego meczu, więc bloków <section class="match"> jest tyle, ile wierszy zwróciła baza (R.5.6, R.5.8). Krótki znacznik <?= … ?> wypisuje wartość; każda przechodzi przez e().
Podgląd: pięć bloków „EVG - FCB”, „EVG - FCB”, „EVG - JUV”, „EVG - RM”, „EVG - FCB”, od razu w ramkach i w rzędzie.
R.5.7 Skrypt 1 wyświetla dane wg wzoru: "<zespół 1> - <zespół 2>" w nagłówku h3, następnie "<wynik>" w nagłówku h4, następnie paragraf "w dniu: <data rozgrywki>", gdzie pole w nawiasach <> oznacza dane pobrane skryptem
ok. 2 min
Polecenie z arkusza
W nagłówku czwartego stopnia wynik pobrany zapytaniem. W paragrafie tekst: „w dniu: <data rozgrywki>”, gdzie pole w nawiasach <> oznacza dane pobrane zapytaniem
Dwie linie szablonu: <h4> z wynikiem i paragraf „w dniu: ” z datą. Kolumny odczytuje się po nazwach ($match['wynik']), a nie po numerach - kolejność kolumn w zapytaniu przestaje mieć znaczenie (R.5.7).
Krok 31: Skrypt 2: odbiór i sprawdzenie liczby z formularza
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 2, który odbiera dane przesłane z formularza: Odbiera dane z pola edycyjnego. Jeśli pole edycyjne jest puste nie jest wykonywana żadna akcja
$_POST['position'] ?? '' - wartość pola z formularza, 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; puste pole, abc czy 9 dają false. Pole type="number" pilnuje tego tylko w przeglądarce - dane da się wysłać z pominięciem formularza,
pole dostało value="<?= e($positionText) ?>" - po wysłaniu wpisana liczba wraca do pola (na obrazie 2 w polu stoi 4 obok wyniku); e() chroni przed tekstem z cudzysłowem.
Podgląd: wysłana liczba 4 - stoi w polu, lista jeszcze pusta.
Krok 32: Skrypt 2: zapytanie przygotowane i lista zawodników
Kryteria:
R.5.9 Skrypt 2 wyświetla przynajmniej jedno imię i nazwisko jeśli wypełniono pole do wprowadzania danych
ok. 4 min
Polecenie z arkusza
Jeżeli wpisano dane skrypt wysyła do bazy danych zmodyfikowane zapytanie 2 tak, że w warunku id pozycji jest równe wartości z pola edycyjnego. Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy punktowanej
if ($position !== false) - zapytanie tylko dla poprawnego numeru pozycji; przy pustym polu nic się nie dzieje,
$pdo->prepare(…) z parametrem :position w miejscu 3 z zapytania 2, potem execute z wartością - baza dostaje treść zapytania i liczbę osobno, więc tekst z formularza nigdy nie stanie się kodem SQL,
w liście szablon foreach ($players as $player): każdy zawodnik jako <li> z paragrafem <p> z imieniem i nazwiskiem.
Podgląd: pozycja 4 - Arkadiusz Milik i Adam Buksa, jak na obrazie 2 (R.5.9).
Krok 33: 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 mecze doszedł warunek wypisujący w paragrafie komunikat $error, gdy baza nie odpowiedziała. Sprawdzone przy wyłączonym serwerze bazy: strona się wyświetla, a zamiast meczów stoi „Nie udało się połączyć z bazą danych.” Podgląd: stan z obrazu 2.
futbol.phpPHPzmienione: 6 linii
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$matches = [];$players = [];$positionText = $_POST['position'] ?? '';$position = filter_var($positionText, 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, ]);$matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->fetchAll();if ($position !== false) {$statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');$statement->execute(['position' => $position]);$players = $statement->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>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"width="930"height="310"> </section> <sectionid="matches"><?phpif ($error !== null): ?> <p><?= e($error) ?></p><?phpendif; ?><?phpforeach ($matchesas$match): ?> <sectionclass="match"> <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3> <h4><?= e($match['wynik']) ?></h4> <p>w dniu: <?= e($match['data_rozgrywki']) ?></p> </section><?phpendforeach; ?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <divclass="columns"> <sectionid="left"> <p><labelfor="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p> <formmethod="post"> <inputtype="number"id="position"name="position"min="1"max="4"value="<?= e($positionText) ?>"> <buttontype="submit">Sprawdź</button> </form> <ul><?phpforeach ($playersas$player): ?> <li><p><?= e($player['imie']) ?><?= e($player['nazwisko']) ?></p></li><?phpendforeach; ?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"width="150"height="165"> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Krok 34 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 34: Co różni tę wersję od podstawowej
ok. 2 min
Polecenie z arkusza
Napisany w języku PHP, w pliku futbol.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 mecze ma prawdziwą wysokość,
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 liczba z formularza trafia do zapytania wprost (wstrzyknięcie 0 OR 1=1 pokazuje wszystkich zawodników), tutaj jest sprawdzana (filter_var, zakres 1-4) i przekazywana parametrem zapytania przygotowanego; każdy tekst przechodzi przez htmlspecialchars,
wygoda: wybrana pozycja zostaje w polu, etykieta jest połączona z polem, 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.
futbol.phpPHPzmienione: 0 linii
<?phpfunctione($text){returnhtmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');}$matches = [];$players = [];$positionText = $_POST['position'] ?? '';$position = filter_var($positionText, 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, ]);$matches = $pdo->query("SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';")->fetchAll();if ($position !== false) {$statement = $pdo->prepare('SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = :position;');$statement->execute(['position' => $position]);$players = $statement->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>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"width="930"height="310"> </section> <sectionid="matches"><?phpif ($error !== null): ?> <p><?= e($error) ?></p><?phpendif; ?><?phpforeach ($matchesas$match): ?> <sectionclass="match"> <h3><?= e($match['zespol1']) ?> - <?= e($match['zespol2']) ?></h3> <h4><?= e($match['wynik']) ?></h4> <p>w dniu: <?= e($match['data_rozgrywki']) ?></p> </section><?phpendforeach; ?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <divclass="columns"> <sectionid="left"> <p><labelfor="position">Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</label></p> <formmethod="post"> <inputtype="number"id="position"name="position"min="1"max="4"value="<?= e($positionText) ?>"> <buttontype="submit">Sprawdź</button> </form> <ul><?phpforeach ($playersas$player): ?> <li><p><?= e($player['imie']) ?><?= e($player['nazwisko']) ?></p></li><?phpendforeach; ?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"width="150"height="165"> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Krok 35 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 35: 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 zdającego, 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 zdającego: import.png, futbol.php, kw1.jpg - kw4.jpg, kwerendy.txt, obraz1.jpg, przeglądarka.txt, styl.css, zad1.png. Płytę nagrywasz, sprawdzasz jej odczyt i opisujesz 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.