Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-01-24.01-SGStyczeń 2024 · 45 kroków · ok. 88 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Rozgrywki futbolowe i reprezentacja Polski (Wersja podstawowa)
Strona o rozgrywkach piłkarskich: baza egzamin zaimportowana z pliku, cztery zapytania (mecze drużyny EVG, pomocnicy, złączenie zawodników z pozycjami i usunięcie tabeli liga), grafika z piłkarzem przeskalowana z zachowaniem przezroczystości, strona futbol.php ze stylami w styl.css oraz dwa skrypty PHP: pierwszy generuje z bazy bloki z wynikami meczów, drugi po wysłaniu formularza wypisuje zawodników grających na wybranej pozycji.
To arkusz EE.09 ze stycznia 2024 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Zadanie powtarza arkusz ze stycznia 2021 z kilkoma dopisanymi wymaganiami (HTML5, jawne kodowanie, język strony). Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty są najpierw napisane najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzone na prawdziwym wstrzyknięciu SQL i zabezpieczone.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: układ na display: flex, zmienne CSS, PDO z zapytaniem przygotowanym na górze pliku i wybrana pozycja zostająca w polu formularza - obie wersje są zgodne z kluczem.
Archiwum dane.7z z tej sesji nie jest opublikowane w materiałach CKE/OKE. Jego zawartość (egzamin.sql, obraz1.jpg, zad1.png) jest identyczna z oryginalnym archiwum CKE z1.zip z pierwszego wydania zadania (arkusz EE.09-01-21.01, załącznik na stronie tamtego arkusza) i z tych plików korzysta rozwiązanie. Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2.
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 - można stracić 9 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-7 · po tym etapie masz 6 z 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.
Na pulpicie tworzysz folder nazwany numerem zdającego (numerem PESEL, a bez niego numerem paszportu) - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum dane.7z (arkusz nazywa je „archiwum ZIP”, ale to format 7z) otwierasz programem 7-Zip i rozpakowujesz do tego folderu, podając hasło !Futboi& - dokładnie tak, przed ostatnim znakiem jest litera i, nie l. W środku są trzy pliki: egzamin.sql (baza do importu), obraz1.jpg (zdjęcie stadionu do banera) i zad1.png (sylwetka piłkarza na przezroczystym tle).
Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, plik strony i stylów.
Typowe błędy
Pliki zapisane poza folderem zdającego (np. tylko w htdocs) nie trafią na płytę - a ocenia się tylko to, co jest na płycie.
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
W XAMPP Control Panel klikasz Start przy Apache i MySQL (nazwy modułów robią się zielone), potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa egzamin, porównywanie np. utf8mb4_polish_ci (arkusz go nie narzuca), Utwórz.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie egzamin - skrypt PHP łączy się z bazą po nazwie (R.5.2).
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
Zaznacz bazę egzamin w lewym panelu, karta Import, Wybierz plik → egzamin.sql z folderu zdającego, Wykonaj. phpMyAdmin odpowiada „Import zakończył się sukcesem” i wypisuje liczbę wykonanych zapytań.
Plik zawiera 8 tabel: oprócz czterech z obrazu 1 (liga, pozycja, rozgrywka, zawodnik) także typy, uslugi, wyniki i zdjecia - nie są potrzebne w zadaniu, ale import ich nie omija. Na zrzucie widać komunikat o sukcesie i listę tabel z liczbą rekordów - to są „elementy wskazujące na poprawnie wykonany import”. Cały ekran z paskiem zadań zapisujesz jako import.png.
Typowe błędy
Zrzut importu ma format PNG, a zrzuty zapytań - JPG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: 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 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. 4 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”
Zaznacz bazę egzamin i otwórz kartę SQL. Zapytanie klauzula po klauzuli:
SELECT zespol1, zespol2, wynik, data_rozgrywki - cztery kolumny wymienione w arkuszu; „jedynie” wyklucza SELECT * (tabela ma jeszcze id),
FROM rozgrywka,
WHERE zespol1 = 'EVG' - tylko mecze, w których EVG jest pierwszym zespołem. Napis w apostrofach (cudzysłów "EVG" z przykładu w kluczu MariaDB też przyjmie).
Wynik: 5 meczów, od EVG FCB 3:1 2019-05-14 do EVG FCB 1:1 2019-05-22 - te same, które na obrazie 2 stoją w blokach pod banerem. Zapytanie kopiujesz do pliku kwerendy.txt, a zrzut całego ekranu zapisujesz jako kw1.jpg (Print Screen, wklejenie do edytora grafiki, eksport do JPEG).
Tego zapytania użyje skrypt 1.
Typowe błędy
WHERE zespol2 = 'EVG' albo OR zespol2 = 'EVG' zmienia wynik - klucz wymaga dokładnie 5 rekordów i tylko „EVG” w kolumnie zespol1.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: zawodnicy z pozycji 3
Kryteria:
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
SELECT imie, nazwisko - dwie kolumny,
FROM zawodnik,
WHERE pozycja_id = 3 - „id pozycji” to w tabeli zawodnik kolumna pozycja_id (klucz obcy do tabeli pozycja, gdzie 3 to pomocnik). Liczba bez apostrofów - kolumna jest liczbowa.
Wynik: Grzegorz Krychowiak i Kamil Grosicki. Zrzut: kw2.jpg. Skrypt 2 użyje tego zapytania, wstawiając w miejsce 3 liczbę wpisaną w formularz.
Typowe błędy
WHERE id = 3 sprawdza identyfikator zawodnika, nie jego pozycję - wynikiem byłby tylko Jan Bednarek.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';-- Zapytanie 2SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 3;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: zawodnicy z nazwą pozycji
Kryteria:
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. 4 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
Dane z dwóch tabel, więc potrzebne jest złączenie:
SELECT zawodnik.id, zawodnik.nazwisko, pozycja.nazwa - kolumna id jest w obu tabelach, więc trzeba podać, z której (inaczej błąd #1052 „niejednoznaczna kolumna”); przy pozostałych nazwa tabeli jest dla czytelności,
FROM zawodnik JOIN pozycja ON zawodnik.pozycja_id = pozycja.id - do każdego zawodnika dołączany jest wiersz pozycji o numerze z jego kolumny pozycja_id,
WHERE zawodnik.id IN (1, 2, 3) - IN to krótszy zapis zawodnik.id = 1 OR zawodnik.id = 2 OR zawodnik.id = 3 (klucz przyjmuje też < 4).
Wynik: 1 Szczesny bramkarz, 2 Pietrzak obronca, 3 Bednarek obronca (dane w bazie są bez polskich liter). Zrzut: kw3.jpg.
Typowe błędy
Bez warunku złączenia (FROM zawodnik, pozycja WHERE zawodnik.id IN (1, 2, 3)) każdy zawodnik połączy się z każdą z 4 pozycji - 12 wierszy zamiast 3. Warunek z OR bez JOIN trzeba ująć w nawias: WHERE zawodnik.pozycja_id = pozycja.id AND (zawodnik.id = 1 OR …).
kwerendy.txtTekstzmienione: 4 linie
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';-- Zapytanie 2SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 3;-- Zapytanie 3SELECT zawodnik.id, zawodnik.nazwisko, pozycja.nazwa FROM zawodnikJOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.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 całą tabelę - strukturę razem z danymi. phpMyAdmin przed wykonaniem pyta „Czy na pewno chcesz wykonać DROP TABLE liga?” - potwierdzasz, a odpowiedź to „MySQL zwrócił pusty wynik”: znak, że polecenie się wykonało. Zrzut: kw4.jpg. Tabela liga znika z listy tabel bazy; strona z niej nie korzysta, więc skryptom to nie przeszkadza.
Plik kwerendy.txt ma komplet czterech zapytań.
Typowe błędy
DELETE FROM liga i TRUNCATE liga usuwają tylko wiersze - tabela zostaje w bazie, a arkusz każe usunąć tabelę.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';-- Zapytanie 2SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = 3;-- Zapytanie 3SELECT zawodnik.id, zawodnik.nazwisko, pozycja.nazwa FROM zawodnikJOIN pozycja ON zawodnik.pozycja_id = pozycja.id WHERE zawodnik.id IN (1, 2, 3);-- Zapytanie 4DROP TABLE liga;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-24 · 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
Oryginał ma 366 × 402 px i przezroczyste tło (kanał alfa). W GIMP-ie: Obraz → Skaluj obraz, łańcuch między szerokością a wysokością zamknięty (to jest „zachowanie proporcji”), szerokość 150 px - wysokość przelicza się sama: 402 × 150 / 366 = 164,8, czyli 165 px (klucz: 165 px ±5).
Zapis: Plik → Nadpisz zad1.png albo Eksportuj jako z rozszerzeniem .png. Format PNG zachowuje kanał alfa - tło zostaje przezroczyste i na stronie pod piłkarzem będzie widać szare tło bloku prawego.
Typowe błędy
Eksport do JPEG (np. zad1.jpg) zamieni przezroczyste tło na białe albo czarne - klucz wymaga zachowania przezroczystości. Zwykłe Zapisz w GIMP-ie zapisuje format .xcf.
Podgląd strony po tym kroku
Krok 9: Plik futbol.php w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie futbol.php. Zapisana w języku HTML 5
Plik futbol.php w folderze zdającego, obok grafik. Rozszerzenie .php, bo dojdą skrypty - na razie to czysty HTML. Pierwsza linia <!DOCTYPE html> to deklaracja HTML5 - krótka, bez adresu definicji typu dokumentu, jaki miały HTML 4 i XHTML.
Atrybut lang="pl" w znaczniku <html> (jest już w szkielecie z poprzedniego kroku). Przeglądarka dobiera po nim np. dzielenie wyrazów i słownik sprawdzania pisowni, a czytnik ekranu - wymowę.
R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie futbol oraz zastosowano jawnie właściwy standard kodowania polskich znaków
ok. 1 min
Polecenie z arkusza
Jawnie zastosowany właściwy standard kodowania polskich znaków
<meta charset="UTF-8"> jako pierwsza rzecz w <head> - to jest „jawne” podanie kodowania: zapisane w kodzie strony, a nie zgadywane przez przeglądarkę. Bez tej linii „Światowe”, „piłkarskie” i „obrońcy” mogą wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8 (w Notepad++ menu Kodowanie). Nazwa pliku i kodowanie dają razem R.2.2.
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"> w <head>. Plik stylów powstanie po HTML-u; całe formatowanie trafi tylko do niego, bez atrybutów style w HTML-u (R.3.4).
Typowe błędy
Klucz nie uznaje R.3.4 także wtedy, gdy choć jeden selektor źle trafia w blok (np. kropka zamiast # przy identyfikatorze).
Krok 14: Bloki: baner, mecze, główny, lewy i prawy
Kryteria:
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ęć znaczników <section> w kolejności z obrazu 2, każdy z identyfikatorem, bo każdy blok ma inne style: banner, matches (blok mecze), main (blok główny), left i right - nazwy po angielsku, arkusz ich nie narzuca. Bloków z wynikami meczów nie piszesz w HTML-u: wygeneruje je skrypt 1, po jednym <section> na mecz, wewnątrz bloku matches.
Na razie bloki są puste i stoją jeden pod drugim - lewy obok prawego ustawi CSS. Podział na bloki daje R.2.4 (klucz z tej sesji nie wymaga bloku z meczem w HTML-u).
Zawartość bloku banera: Nagłówek drugiego stopnia o treści „Światowe rozgrywki piłkarskie”
Drugiego stopnia to <h2> - na tej stronie nie ma żadnego <h1>. Tekst wpisujesz małymi literami jak w arkuszu; wielkie litery na początku słów (obraz 2) doda CSS.
Krok 16: Baner: zdjęcie stadionu z tekstem alternatywnym
ok. 1 min
Polecenie z arkusza
Obraz obraz1.jpg z tekstem alternatywnym o treści: „boisko”
<img> z atrybutami src (nazwa pliku z folderu zdającego) i alt - tekst, który czytnik ekranu przeczyta zamiast zdjęcia i który pokaże się, gdy plik się nie wczyta. Zdjęcie ma 930 × 310 px i zostaje w tym rozmiarze - arkusz go nie zmienia.
Zawartość bloku mecze: Efekt działania skryptu 1. Zawartość bloku głównego: nagłówek drugiego stopnia o treści: „Reprezentacja Polski”
Blok mecze zostaje na razie pusty - wypełni go skrypt 1. W bloku głównym drugi nagłówek <h2>; oba nagłówki strony dostaną te same style przez selektor h2.
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):”
Akapit <p> z instrukcją dla użytkownika - numery pozycji odpowiadają tabeli pozycja z obrazu 1. Strona ma już oba nagłówki <h2> i pierwszy paragraf (R.2.5).
futbol.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> </section> <sectionid="right"> </section></body></html>
Podgląd strony po tym kroku (futbol.php)
Krok 19: Formularz wysyłający dane metodą POST
Kryteria: ,
R.2.7 W bloku lewym umieszczono formularz
R.3.3 Formularz wysyła dane metodą POST do tego samego pliku
ok. 1 min
Polecenie z arkusza
Formularz wysyłający dane metodą POST do tej samej strony, zawierający:
<form method="post"> - bez atrybutu action formularz wysyła dane do tego samego adresu, z którego został wczytany, czyli do futbol.php. Metoda POST przesyła dane w treści żądania, nie w adresie strony; w PHP odczytasz je z tablicy $_POST. Znacznik z zamknięciem stoi w bloku lewym (R.2.7, R.3.3).
Typowe błędy
method="get" dopisze wartość do adresu (futbol.php?position=4) - skrypt czytający $_POST niczego nie dostanie.
type="number" - przeglądarka przyjmie tylko liczbę i dorysuje strzałki zmiany wartości (widać je na obrazie 2). Atrybut name="position" to klucz, pod którym wartość trafi do PHP: $_POST['position'].
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
ok. 1 min
Polecenie z arkusza
Przycisk wysyłający zawartość formularza z opisem „Sprawdź”
<input type="submit" value="Sprawdź"> - przycisk, który wysyła formularz; napis to wartość value. Formularz ma komplet: pole liczbowe i przycisk wysyłający (R.2.8, R.3.2).
Typowe błędy
<input type="button"> wygląda tak samo, ale niczego nie wysyła - brak punktu R.3.2 i skrypt 2 nigdy nie dostanie danych.
R.2.9 W bloku lewym umieszczono jedną listę punktowaną, zastosowano znaczniki <ul>, <li>, (generowana skryptem lub HTML)
ok. 1 min
Polecenie z arkusza
Lista punktowana (nieuporządkowana), a w niej efekt działania skryptu 2
Lista nieuporządkowana to <ul> (unordered list). Na razie pusta - elementy <li> z imionami i nazwiskami wypisze skrypt 2, dlatego jego kod stanie między <ul> a </ul> (R.2.9 przyjmuje listę generowaną skryptem).
R.2.6 W bloku banera umieszczono obraz obraz1.jpg z tekstem alternatywnym: "boisko" lub w bloku prawym umieszczono obraz zad1.png 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”
Przeskalowany zad1.png (150 × 165 px) z tekstem alternatywnym. Oba obrazy strony są na miejscu i oba mają alt (R.2.6).
Kroki 25-34 · po tym etapie masz 29 z 38 kryteriów (pkt)
Krok 25: Plik styl.css: krój i tło strony
Kryteria:
R.4.1 Ustawiono krój czcionki Tahoma dla body
ok. 1 min
Polecenie z arkusza
Dla znacznika body: krój czcionki Tahoma, kolor tła Crimson
Nowy plik styl.css w folderze zdającego - od teraz każda reguła trafia tylko tutaj. Selektor znacznika body: krój Tahoma dziedziczą wszystkie elementy strony, a Crimson to nazwa koloru CSS (karmazynowa czerwień). Pola formularza kroju nie dziedziczą - arkusz tego nie wymaga.
styl.cssCSSnowy plik
body {font-family: Tahoma;background-color: Crimson;}
Podgląd strony po tym kroku (futbol.php)
Krok 26: Baner: biały tekst, wyśrodkowanie, wysokość
Kryteria:
R.4.3 Ustawiono biały kolor czcionki dla banera
ok. 1 min
Polecenie z arkusza
Dla bloku banera: biały kolor czcionki, wyrównanie tekstu do środka, wysokość 370 px
Selektor identyfikatora #banner - z krzyżykiem, bo w HTML-u jest id="banner". text-align: center wyśrodkowuje nagłówek i zdjęcie (obraz jest elementem w linii, więc słucha wyrównania tekstu). 370 px mieści nagłówek i zdjęcie wysokie na 310 px. Biały tekst banera - R.4.3.
styl.cssCSSzmienione: 5 linii
body {font-family: Tahoma;background-color: Crimson;}#banner {color: white;text-align: center;height: 370px;}
Podgląd strony po tym kroku (futbol.php)
Krok 27: Pojedynczy blok z rozgrywką: tekst, szerokość, marginesy
Kryteria:
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
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
Bloki z meczami to znaczniki <section>wewnątrz bloku matches, więc selektor jest potomny: #matches section - spacja znaczy „każdy section w środku #matches”. Pięć głównych bloków strony też jest sekcjami, ale nie leżą w #matches, więc ta reguła ich nie dotyczy (R.4.7).
Bloków jeszcze nie ma na stronie - pojawią się z wynikiem skryptu 1, od razu w tym stylu.
Typowe błędy
Sam selektor section objąłby wszystkie bloki strony - baner, blok główny i lewy też dostałyby szerokość 200 px.
Krok 28: Pojedynczy blok z rozgrywką: obramowanie i zaokrąglenie
Kryteria:
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)
Skrót border: 1px solid black - grubość, styl linii (solid = ciągła) i kolor w jednej właściwości. border-radius: 10px zaokrągla rogi ramki (R.4.8). To osobna reguła dla tego samego selektora - mogłaby też trafić do poprzedniej.
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
Pseudoklasa :hover działa, gdy kursor jest nad elementem. Zmienia się tylko kolor ramki (border-color) - grubość i styl zostają z poprzedniej reguły, więc blok nie „skacze”. Na obrazie 2 tak wygląda drugi blok (R.4.9).
Krok 32: Blok prawy: tło, szerokość, wysokość, wyrównanie do prawej
Kryteria: , ,
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 prawego: kolor tła WhiteSmoke, szerokość 30%, wysokość 230 px, wyrównanie tekstu do prawej strony
70% + 30% = 100% - oba bloki zmieszczą się obok siebie, jeśli nie dostaną marginesów ani ramek. text-align: right dosuwa do prawej krawędzi i akapit z autorem, i grafikę piłkarza (obraz 2). Tła trzech szarych bloków i body (R.4.2), wysokości banera, bloku głównego, lewego i prawego (R.4.4) i szerokości (R.4.5) są ustawione.
Typowe błędy
Bloki o sumie szerokości 100% nie mogą mieć padding, margin ani border - każdy piksel więcej zepchnie blok prawy pod lewy.
Krok 33: 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 - nagłówek na środku bloku (razem z banerem i blokiem prawym: R.4.6),
letter-spacing: 7px - dodatkowe 7 px po każdej literze, stąd „rozstrzelone” nagłówki z obrazu 2,
text-transform: capitalize - pierwsza litera każdego słowa wielka: „Światowe Rozgrywki Piłkarskie”, jak na obrazie 2 (R.4.10).
⚠️ Uwaga o nazewnictwie: arkusz nazywa to „kapitalikami”, ale kapitaliki to co innego - wszystkie litery w kształcie wielkich, małe zmniejszone (font-variant: small-caps). Wartość w nawiasie i obraz 2 rozstrzygają: chodzi o capitalize. Klucz z tej sesji wymienia tylko text-transform: capitalize.
Typowe błędy
text-transform: uppercase zamieni cały napis na wielkie litery - obraz 2 pokazuje wielką tylko pierwszą literę słowa.
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 i clear albo display flex albo grid albo position)
ok. 3 min
Polecenie z arkusza
Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2
Trzy reguły układu:
#matches section { float: left; } - bloki z meczami stają obok siebie w rzędzie (każdy zajmuje 200 + 2 × 1 + 2 × 10 = 222 px; pięć bloków to 1110 px),
#main { clear: both; } - blok główny zaczyna się dopiero pod wszystkimi pływającymi blokami meczów. Bez tego wsunąłby się pod nie, bo blok matches z samymi pływającymi elementami ma wysokość 0,
#left, #right { float: left; } - blok lewy (70%) przy lewej krawędzi, prawy (30%) tuż obok niego.
Klucz R.3.1 ocenia układ pięciu głównych bloków, bez bloków z rozgrywkami{'' if STARA else ' (przyjmuje float i clear, flex, grid albo position)'}. Podgląd: blok lewy i prawy stoją już obok siebie; bloki meczów dojdą ze skryptem 1.
Typowe błędy
Bez clear: both przy bloku głównym jego szare tło wjedzie pod bloki meczów, a nagłówek „Reprezentacja Polski” stanie za nimi.
Kroki 35-41 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 35: Miejsce skryptu 1 i połączenie z bazą egzamin
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. 3 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
Efekt skryptu 1 ma się pojawić w bloku mecze - tam więc piszesz blok PHP, między <?php a ?>. Serwer wykona go, zanim strona trafi do przeglądarki.
Pierwsza instrukcja: mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy egzamin (połączenie i wybór bazy w jednym wywołaniu). Połączenie trafia do zmiennej $connection, z której skorzystają oba skrypty - skrypt 2 stoi niżej w tym samym pliku, więc zmienna jest dla niego dostępna (R.5.1, R.5.2).
Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2) - na razie wygląda jak wcześniej. Stronę sprawdzasz przez http://localhost/…/futbol.php, a nie otwierając plik z dysku: przeglądarka sama nie wykona PHP.
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
mysqli_query($connection, "…") wysyła do bazy zapytanie 1 przepisane z kwerendy.txt i zwraca wynik - zbiór wierszy, który trafia do zmiennej $result. Zapytanie stoi w cudzysłowie "…", a napis 'EVG' w środku - w apostrofach: dwa różne znaki się nie gryzą (R.5.5).
Na stronie jeszcze nic nie widać - wiersze trzeba wypisać.
Krok 37: 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
while ($row = mysqli_fetch_row($result)) - mysqli_fetch_row zwraca kolejny wiersz wyniku jako tablicę numerowaną od zera: $row[0] to zespol1, $row[1] - zespol2, $row[2] - wynik, $row[3] - data_rozgrywki (kolejność kolumn z zapytania). Gdy wierszy zabraknie, funkcja zwraca false i pętla się kończy,
w każdym obrocie pętli echo '<section>' i echo '</section>' - jeden blok na jeden wiersz, więc bloków jest dokładnie tyle, ile meczów zwróciła baza (R.5.6, R.5.8),
echo "<h3>$row[0] - $row[1]</h3>" - w cudzysłowie PHP podstawia wartości zmiennych, także elementów tablicy zapisanych bez apostrofów w nawiasie.
Podgląd: pięć bloków z nagłówkami „EVG - FCB”, „EVG - FCB”, „EVG - JUV”, „EVG - RM”, „EVG - FCB” - od razu w ramkach i obok siebie, bo style były gotowe wcześniej.
Typowe błędy
echo '<h3>$row[0] - $row[1]</h3>' w apostrofach wypisze dosłownie $row[0] - $row[1] - PHP podstawia zmienne tylko w cudzysłowie "…".
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 w pętli, po nagłówku <h3>: <h4> z wynikiem meczu ($row[2]) i paragraf z napisem „w dniu: ” i datą ($row[3]). Podgląd: bloki wyglądają jak na obrazie 2 - od „3:1, w dniu: 2019-05-14” do „1:1, w dniu: 2019-05-22” (R.5.7).
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
Drugi blok PHP stoi wewnątrz listy <ul> - to, co wypisze, stanie się jej elementami.
$_POST['position'] - wartość pola o nazwie position (R.5.4),
empty() jest prawdziwe, gdy klucza w ogóle nie ma (pierwsze wejście na stronę, formularz nie był wysłany) albo gdy pole wysłano puste. Wykrzyknik ! odwraca warunek: kod w klamrach wykona się tylko wtedy, gdy wpisano liczbę - przy pustym polu nie dzieje się nic, jak każe arkusz.
Podgląd: wysłana liczba 4 - lista jest jeszcze pusta, zapytanie dojdzie w następnym kroku.
Typowe błędy
Samo $_POST['position'] bez sprawdzenia przy pierwszym wejściu na stronę daje ostrzeżenie „Undefined array key” - formularz jeszcze nie był wysłany.
Krok 40: Skrypt 2: zapytanie 2 z pozycją z formularza 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
zapytanie 2 z kwerendy.txt, w którym zamiast 3 stoi $position - liczba z formularza. Cudzysłów sprawia, że PHP wstawi jej wartość, a wynik znów trafia do $result,
pętla while z mysqli_fetch_row - $row[0] to imię, $row[1] nazwisko,
każdy zawodnik jako element listy <li>, a w nim paragraf <p> z imieniem i nazwiskiem.
Podgląd: wpisano 4 (napastnicy) - lista pokazuje Arkadiusz Milik i Adam Buksa, jak na obrazie 2 (R.5.9). Pole po wysłaniu jest puste: strona wczytuje się od nowa, a arkusz nie wymaga, żeby liczba w nim została.
futbol.phpPHPzmienione: 4 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"><?php$connection = mysqli_connect('localhost', 'root', '', 'egzamin');$result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");while ($row = mysqli_fetch_row($result)) {echo'<section>';echo"<h3>$row[0] - $row[1]</h3>";echo"<h4>$row[2]</h4>";echo"<p>w dniu: $row[3]</p>";echo'</section>';}?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> <formmethod="post"> <inputtype="number"name="position"> <inputtype="submit"value="Sprawdź"> </form> <ul><?phpif (!empty($_POST['position'])) {$position = $_POST['position'];$result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");while ($row = mysqli_fetch_row($result)) {echo"<li><p>$row[0]$row[1]</p></li>"; }}?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"> <p>Autor: Bartosz Bryniarski</p> </section></body></html>
Podgląd strony po tym kroku (futbol.php)
Krok 41: Zamknięcie połączenia z bazą
Kryteria:
R.5.3 Po wykonaniu operacji na bazie zastosowano funkcję zamknięcia bazy
ok. 1 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem
mysqli_close($connection) na końcu drugiego bloku PHP, poza warunkiem - wykona się zawsze, także gdy pole formularza jest puste. Zamknięcie po skrypcie 1 odcięłoby skrypt 2 od bazy (R.5.3).
Strona spełnia wszystkie kryteria arkusza. Dalej trzy kroki o zabezpieczeniach - klucz ich nie wymaga.
Typowe błędy
mysqli_close w bloku skryptu 1 sprawia, że mysqli_query w skrypcie 2 dostaje zamknięte połączenie - PHP 8 kończy się wtedy błędem „mysqli object is already closed”.
futbol.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"><?php$connection = mysqli_connect('localhost', 'root', '', 'egzamin');$result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");while ($row = mysqli_fetch_row($result)) {echo'<section>';echo"<h3>$row[0] - $row[1]</h3>";echo"<h4>$row[2]</h4>";echo"<p>w dniu: $row[3]</p>";echo'</section>';}?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> <formmethod="post"> <inputtype="number"name="position"> <inputtype="submit"value="Sprawdź"> </form> <ul><?phpif (!empty($_POST['position'])) {$position = $_POST['position'];$result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");while ($row = mysqli_fetch_row($result)) {echo"<li><p>$row[0]$row[1]</p></li>"; }}mysqli_close($connection);?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"> <p>Autor: Bartosz Bryniarski</p> </section></body></html>
Kroki 42-44 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 42: Zabezpieczenie: zapytanie przygotowane w skrypcie 2
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
Pole type="number" pilnuje liczby tylko w przeglądarce. Formularz można wysłać z pominięciem strony (np. programem curl albo narzędziami deweloperskimi), a wtedy w $_POST['position'] stoi dowolny tekst - i trafia wprost do zapytania. To SQL injection, sprawdzone na wersji z poprzednich kroków:
0 OR 1=1 - warunek jest zawsze prawdziwy i lista pokazuje wszystkich 7 zawodników,
0 UNION SELECT nazwa, cena FROM uslugi - do wyniku doklejają się wiersze z zupełnie innej tabeli (dziesięć usług z cenami, np. „Piling enzymatyczny 45”); tak samo dałoby się odczytać np. tabelę z hasłami,
abc - błąd składni SQL, PHP 8.1 i nowsze zgłaszają wyjątek mysqli_sql_exception i zamiast strony widać „Fatal error” z fragmentem zapytania.
Lekarstwo to zapytanie przygotowane: mysqli_prepare ze znakiem ? w miejscu liczby, mysqli_stmt_bind_param z typem 'i' (liczba całkowita), mysqli_stmt_execute i mysqli_stmt_get_result - wynik czyta się dalej tą samą pętlą. Baza dostaje treść zapytania i dane osobno, więc dane nigdy nie staną się kodem SQL. Podgląd: ten sam atak z UNION - lista jest pusta (tekst zamieniony na liczbę daje 0, a pozycji 0 nie ma). Stara linia zostaje w komentarzu.
Typowe błędy
Liczba liter w 'i' musi równać się liczbie znaków ? i liczbie zmiennych - inaczej mysqli_stmt_bind_param zgłosi błąd.
futbol.phpPHPzmienione: 5 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"><?php$connection = mysqli_connect('localhost', 'root', '', 'egzamin');$result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");while ($row = mysqli_fetch_row($result)) {echo'<section>';echo"<h3>$row[0] - $row[1]</h3>";echo"<h4>$row[2]</h4>";echo"<p>w dniu: $row[3]</p>";echo'</section>';}?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> <formmethod="post"> <inputtype="number"name="position"> <inputtype="submit"value="Sprawdź"> </form> <ul><?phpif (!empty($_POST['position'])) {$position = $_POST['position'];// $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");$statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;'); mysqli_stmt_bind_param($statement, 'i', $position); mysqli_stmt_execute($statement);$result = mysqli_stmt_get_result($statement);while ($row = mysqli_fetch_row($result)) {echo"<li><p>$row[0]$row[1]</p></li>"; }}mysqli_close($connection);?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"> <p>Autor: Bartosz Bryniarski</p> </section></body></html>
Podgląd strony po tym kroku (futbol.php)
Krok 43: Zabezpieczenie: sprawdzenie liczby z formularza
ok. 3 min
Polecenie z arkusza
Odbiera dane z pola edycyjnego. Jeśli pole edycyjne jest puste nie jest wykonywana żadna akcja
Zapytanie przygotowane chroni bazę, ale skrypt nadal przyjmuje wszystko: abc, -5, 4.7. Lepiej odrzucić złe dane, zanim w ogóle dojdzie do zapytania:
filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, …) czyta pole z formularza i zwraca liczbę całkowitą tylko wtedy, gdy tekst nią jest i mieści się w zakresie 1-4 (min_range, max_range - tyle pozycji jest w tabeli pozycja),
w każdym innym przypadku zwraca false, a gdy pola w ogóle nie wysłano - null. Oba są fałszywe, więc if ($position) przepuszcza wyłącznie poprawne numery pozycji; pusty formularz dalej nie robi nic.
Podgląd: wysłana liczba 9 - zapytanie się nie wykonuje i lista jest pusta. Dwie stare linie zostają w komentarzu.
futbol.phpPHPzmienione: 4 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"><?php$connection = mysqli_connect('localhost', 'root', '', 'egzamin');$result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");while ($row = mysqli_fetch_row($result)) {echo'<section>';echo"<h3>$row[0] - $row[1]</h3>";echo"<h4>$row[2]</h4>";echo"<p>w dniu: $row[3]</p>";echo'</section>';}?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> <formmethod="post"> <inputtype="number"name="position"> <inputtype="submit"value="Sprawdź"> </form> <ul><?php// if (!empty($_POST['position'])) {// $position = $_POST['position'];$position = filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);if ($position) {// $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");$statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;'); mysqli_stmt_bind_param($statement, 'i', $position); mysqli_stmt_execute($statement);$result = mysqli_stmt_get_result($statement);while ($row = mysqli_fetch_row($result)) {echo"<li><p>$row[0]$row[1]</p></li>"; }}mysqli_close($connection);?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"> <p>Autor: Bartosz Bryniarski</p> </section></body></html>
Krok 44: Zabezpieczenie: htmlspecialchars przy wypisywaniu danych
ok. 3 min
Polecenie z arkusza
Wyświetla zwrócone zapytaniem dane: imiona i nazwiska w paragrafach, jako elementy listy punktowanej
Oba skrypty wklejają w kod strony tekst prosto z bazy. Gdy w tabeli znajdzie się znak <, przeglądarka potraktuje go jak początek znacznika. Sprawdzone: po dopisaniu do tabeli rozgrywka meczu z wynikiem zapisanym jako <i>1:0 wersja z poprzednich kroków zamienia ten tekst w znacznik kursywy, który rozlewa się na resztę strony - a w miejscu <i> mógłby stać skrypt.
htmlspecialchars zamienia <, >, & i cudzysłowy na encje (< itd.), więc przeglądarka pokaże je jako zwykłe znaki. array_map('htmlspecialchars', $row) robi to naraz dla wszystkich pól wiersza - w obu pętlach, tuż przed echo. Zasada: dane z bazy i z formularza zabezpiecza się przy wypisywaniu, nie przy zapisie. Podgląd: strona wygląda tak samo jak na obrazie 2 - na zwykłych danych zmiana jest niewidoczna.
Na egzaminie wystarczy wersja wcześniejsza - klucz nie sprawdza żadnego z trzech zabezpieczeń.
futbol.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Rozgrywki futbolowe</title> <linkrel="stylesheet"href="styl.css"></head><body> <sectionid="banner"> <h2>Światowe rozgrywki piłkarskie</h2> <imgsrc="obraz1.jpg"alt="boisko"> </section> <sectionid="matches"><?php$connection = mysqli_connect('localhost', 'root', '', 'egzamin');$result = mysqli_query($connection, "SELECT zespol1, zespol2, wynik, data_rozgrywki FROM rozgrywka WHERE zespol1 = 'EVG';");while ($row = mysqli_fetch_row($result)) {echo'<section>';// echo "<h3>$row[0] - $row[1]</h3>";$row = array_map('htmlspecialchars', $row);echo"<h3>$row[0] - $row[1]</h3>";echo"<h4>$row[2]</h4>";echo"<p>w dniu: $row[3]</p>";echo'</section>';}?> </section> <sectionid="main"> <h2>Reprezentacja Polski</h2> </section> <sectionid="left"> <p>Podaj pozycję zawodników (1-bramkarze, 2-obrońcy, 3-pomocnicy, 4-napastnicy):</p> <formmethod="post"> <inputtype="number"name="position"> <inputtype="submit"value="Sprawdź"> </form> <ul><?php// if (!empty($_POST['position'])) {// $position = $_POST['position'];$position = filter_input(INPUT_POST, 'position', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]);if ($position) {// $result = mysqli_query($connection, "SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = $position;");$statement = mysqli_prepare($connection, 'SELECT imie, nazwisko FROM zawodnik WHERE pozycja_id = ?;'); mysqli_stmt_bind_param($statement, 'i', $position); mysqli_stmt_execute($statement);$result = mysqli_stmt_get_result($statement);while ($row = mysqli_fetch_row($result)) {$row = array_map('htmlspecialchars', $row);echo"<li><p>$row[0]$row[1]</p></li>"; }}mysqli_close($connection);?> </ul> </section> <sectionid="right"> <imgsrc="zad1.png"alt="piłkarz"> <p>Autor: Bartosz Bryniarski</p> </section></body></html>
Podgląd strony po tym kroku (futbol.php)
Etap 6: Oddanie pracy
Krok 45 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 45: 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 wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….
W folderze z numerem zdającego muszą być: import.png, futbol.php, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, obraz1.jpg, przeglądarka.txt, styl.css i zad1.png (plik egzamin.sql z archiwum może zostać). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.