INF.03-05-26.01-SGStyczeń 2026 · 54 kroki · ok. 92 min · 39 kryteriów z klucza
Rozwiązanie krok po kroku: Portal zgłoszeń wypadków (Wersja podstawowa)
Rozwiązanie buduje portal zgłoszeń wypadków: baza zgloszenia (personel, pojazdy i rejestr zgłoszeń, który łączy osobę z pojazdem i datą) i cztery zapytania - warunek na tekst, COUNT z GROUP BY, podzapytanie NOT IN szukające osób bez żadnego zgłoszenia i INSERT z CURDATE() - potem strona index.php z dwiema sekcjami obok siebie i trzy skrypty PHP: tabela policjantów albo ratowników wybranych polem opcji, lista osób bez zgłoszeń i formularz, który dopisuje zgłoszenie do rejestru.
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 pisane najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row, isset), a na końcu zostają przerobione na wersję z prawdziwych projektów: kolejność skryptów, dzięki której lista od razu widzi nowe zgłoszenie, biała lista opcji, zapytanie przygotowane i htmlspecialchars.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: układ na siatce CSS, kolory w zmiennych i PHP na PDO z białą listą, zapytaniami przygotowanymi i przekierowaniem po zapisie od pierwszej linii - obie wersje są zgodne z kluczem.
Baza pochodzi z prawdziwego archiwum pliki7 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu. Podgląd strony od kroków z PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 na bazie z arkusza; od kroku z polem opcji pokazuje stan z ilustracji 2, czyli po wybraniu „Ratownik” i kliknięciu „Pokaż”.
Jak liczą się punkty. Klucz ma 39 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów - 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 39 kryteriów (pkt)
Krok 1: Baza danych zgloszenia
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie zgloszenia, z zestawem polskich znaków (np. utf8_polish_ci)
Rozpakuj pliki7.7z z pulpitu (hasło @LarMowe^ - z małpą na początku i daszkiem na końcu) i załóż folder z numerem zdającego. W phpMyAdmin: Nowa, nazwa zgloszenia (bez „ł”, tak jak w arkuszu), porównywanie utf8_polish_ci. Porównywanie wybrane przy bazie dziedziczą tabele zakładane później bez własnego ustawienia; tabele z zgloszenia.sql mają je zapisane w definicji (COLLATE=utf8_polish_ci), więc porównują tekst po polsku i bez względu na wielkość liter - status = 'Policjant' znajdzie te same wiersze co 'policjant'.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie zgloszenia - skrypty łączą się z bazą po nazwie, więc literówka zabiera też punkty za skrypty (R.5.1).
Krok 2: Import tabel z pliku zgloszenia.sql
ok. 2 min
Polecenie z arkusza
Z rozpakowanego archiwum zaimportuj tabele z pliku zgloszenia.sql do utworzonej bazy
Zaznacz bazę zgloszenia, potem Import → zgloszenia.sql → Wykonaj. Powstają trzy tabele z ilustracji 1: personel (18 osób, pole status z wartością „policjant” albo „ratownik”), pojazdy (30 pojazdów, typ „K” - karetka, „R” - radiowóz) i rejestr (29 zgłoszeń), który kluczami obcymi wskazuje osobę i pojazd.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonany import tabel do bazy danych zgloszenia - plik import.png
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą 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
Print Screen, wklejasz do edytora grafiki i zapisujesz jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG - odwrotnie niż w wielu innych arkuszach.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: policjanci
Kryteria: ,
R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonane zapytanie 1 wybierające jedynie identyfikatory, imiona i nazwiska tych osób spośród personelu, dla których status to policjant. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, imie, nazwisko FROM personel WHERE status = "policjant"; oraz na zrzucie widocznych jest dokładnie 11 rekordów z id: 1, 2, 5, 6, 7, 8, 10, 11, 14, 16, 18
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie identyfikatory, imiona i nazwiska tych osób spośród personelu, których status to policjant
SELECT id, imie, nazwisko - trzy pola, bez statusu,
FROM personel - jedna tabela,
WHERE status = 'policjant' - tekst w apostrofach, dokładnie tak, jak jest zapisany w bazie.
Wynik: 11 wierszy o identyfikatorach 1, 2, 5, 6, 7, 8, 10, 11, 14, 16, 18 - zgodnie z kluczem. Zapytania zapisujesz w kwerendy.txt, zrzut wyniku jako kw1.jpg. Z tego zapytania zrobisz Skrypt 1, w którym słowo „policjant” zastąpi opcja z formularza.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT id, imie, nazwisko FROM personel WHERE status = 'policjant';
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: liczba karetek i radiowozów
Kryteria:
R.1.4 Wykonane zapytanie 2 wybierające jedynie typ i zliczające liczbę pojazdów zgrupowanych według typu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT typ, COUNT(*) FROM pojazdy GROUP BY typ; oraz na zrzucie widoczne są dane: K 6; R 24
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie typ i zliczające liczbę pojazdów zgrupowanych według typu (zapytanie wybiera liczbę karetek i radiowozów)
SELECT typ, COUNT(*) - typ i liczba wierszy w grupie,
FROM pojazdy,
GROUP BY typ - wiersze z tym samym typem zlewają się w jeden, a COUNT(*) liczy, ile ich było.
Wynik: dwa wiersze - K 6 i R 24 (klucz: K 6; R 24). Zrzut: kw2.jpg.
Typowe błędy
SELECT COUNT(*) FROM pojazdy bez grupowania zwraca jedną liczbę 30 - nie widać, ile jest karetek, a ile radiowozów.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, imie, nazwisko FROM personel WHERE status = 'policjant';-- Zapytanie 2SELECT typ, COUNT(*) FROM pojazdy GROUP BY typ;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: osoby bez żadnego zgłoszenia
Kryteria:
R.1.5 Wykonane zapytanie 3 wybierające jedynie te identyfikatory i nazwiska osób spośród personelu, których id nie pojawia się w rejestrze. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr); lub SELECT personel.id, nazwisko FROM personel LEFT JOIN rejestr ON personel.id = id_personel GROUP BY personel.id HAVING COUNT(data) = 0; (lub inne rozwiązania dające uniwersalny wynik) oraz na zrzucie widoczne są dokładnie 3 rekordy: 2 Nowak, 3 Nosowska, 4 Mizera. (Baza musi być przywrócona do stanu początkowego)
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie te identyfikatory i nazwiska osób spośród personelu, których id nie pojawia się w rejestrze
SELECT id, nazwisko FROM personel - dwa pola z personelu,
WHERE id NOT IN - zostają tylko te osoby, których identyfikatora nie ma na liście zwróconej przez nawias za tym słowem,
(SELECT id_personel FROM rejestr) - podzapytanie: wszystkie identyfikatory osób, które mają jakiekolwiek zgłoszenie.
Wynik: trzy wiersze - 2 Nowak, 3 Nosowska, 4 Mizera, jak w kluczu. Klucz uznaje też wersję z LEFT JOIN ... HAVING COUNT(data) = 0 - sprawdzone, daje te same trzy osoby. Zrzut: kw3.jpg.
Typowe błędy
Zapytanie 3 wykonujesz PRZED zapytaniem 4 albo na bazie przywróconej do stanu początkowego (uwaga w kluczu) - inaczej wynik zależy od tego, co już dopisano do rejestru.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, imie, nazwisko FROM personel WHERE status = 'policjant';-- Zapytanie 2SELECT typ, COUNT(*) FROM pojazdy GROUP BY typ;-- Zapytanie 3SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowe zgłoszenie z dzisiejszą datą
Kryteria:
R.1.6 Wykonane zapytanie 4 wstawiające rekord do tabeli rejestr : identyfikator personelu: 1, identyfikator pojazdu: 14, automatycznie wpisywana aktualna data, klucz generowany automatycznie. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO rejestr(data, id_personel, id_pojazd) VALUES (CURDATE(), 1, 14); ( możliwe też CURRENT_DATE() i NOW()) oraz na zrzucie jest komunikat o poprawnie wykonanym zapytaniu lub widoczny wstawiony wiersz
ok. 2 min
Polecenie z arkusza
Zapytanie 4: wstawiające rekord do tabeli rejestr: identyfikator personelu: 1, identyfikator pojazdu: 14, automatycznie wpisywana aktualna data, klucz generowany automatycznie
INSERT INTO rejestr (data, id_personel, id_pojazd) - wymieniasz tylko trzy kolumny; id pomijasz, więc baza nada je sama (AUTO_INCREMENT),
VALUES (CURDATE(), 1, 14) - CURDATE() wstawia dzisiejszą datę w chwili wykonania zapytania (klucz uznaje też CURRENT_DATE() i NOW()).
Nowe zgłoszenie dostało identyfikator 30 i datę 2026-10-04 - dzień, w którym wykonano zapytanie. Zrzut z komunikatem albo z wstawionym wierszem: kw4.jpg.
Typowe błędy
Data wpisana ręcznie ('2026-01-12') nie jest „automatycznie wpisywaną aktualną datą” - jutro to zapytanie wstawiłoby wczorajszy dzień.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, imie, nazwisko FROM personel WHERE status = 'policjant';-- Zapytanie 2SELECT typ, COUNT(*) FROM pojazdy GROUP BY typ;-- Zapytanie 3SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);-- Zapytanie 4INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), 1, 14);
Podgląd strony po tym kroku
Etap 2: Strona HTML
Kroki 8-28 · po tym etapie masz 17 z 39 kryteriów (pkt)
Krok 8: Plik index.php w HTML5
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie index.php. Zapisana w języku HTML5
Deklaracja <!DOCTYPE html> i szkielet strony. Rozszerzenie .php, bo dojdą skrypty; na egzaminie plik leży w htdocs XAMPP-a i otwierasz go przez http://localhost/....
Krok 13: Bloki: nagłówek, główny z dwiema sekcjami, stopka
Kryteria:
R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header, main->section+section, footer (dopuszcza się zastosowanie bloków pomocniczych)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3
Klucz wymaga wprost header, main z dwiema section w środku i footer (R.2.3). Sekcje mają inny kolor tła, więc dostają identyfikatory left i right - po nich rozróżnisz je w CSS. Obok siebie postawisz je w arkuszu stylów.
R.2.5 Na stronie umieszczony przynajmniej jeden formularz, zastosowany znacznik <form>
R.3.3 Przynajmniej jeden formularz wysyła dane metodą POST do tego samego pliku (poprawne również bez atrybutu action)
ok. 1 min
Polecenie z arkusza
Formularz wysyłający dane do tego samego pliku metodą bezpieczną
method="post" - „metoda bezpieczna” w rozumieniu arkusza: dane jadą w treści żądania, a nie w adresie, więc nie zostają w historii przeglądarki ani w zakładkach. (W specyfikacji HTTP „bezpieczna” znaczy co innego - metodę, która niczego nie zmienia na serwerze, czyli GET - ale klucz R.3.3 rozstrzyga: POST.) Atrybut action pomijasz - formularz bez niego wysyła dane do bieżącego pliku (klucz: „poprawne również bez atrybutu action”).
Krok 17: Pole opcji „Policjant”, domyślnie zaznaczone
ok. 2 min
Polecenie z arkusza
Pole opcji z treścią „Policjant”, domyślnie zaznaczone
<input type="radio"> z atrybutem checked - zaznaczone od pierwszego wejścia na stronę. Treść „Policjant” to etykieta <label> połączona z polem przez for/id, więc kliknięcie napisu też zaznacza pole. value="policjant" to wartość, która pojedzie do skryptu - małymi literami, dokładnie tak, jak status jest zapisany w bazie.
W jednym momencie można zaznaczyć tylko jedno pole opcji
To zapewnia już kod z dwóch poprzednich kroków: oba pola mają ten sam name="option". Przeglądarka traktuje pola opcji o tej samej nazwie jak jedną grupę - zaznaczenie „Ratownik” odznacza „Policjant”. Z różnymi nazwami dałoby się zaznaczyć oba naraz.
Typowe błędy
Różne wartości name w polach opcji - obie kropki da się zaznaczyć jednocześnie, a skrypt nie wie, którą wybrać (R.3.5).
R.2.9 Pierwszy wiersz tabeli zawiera komórki nagłówkowe „Id”, „Imię”, „Nazwisko”, zastosowane znaczniki <tr> i <th>
ok. 2 min
Polecenie z arkusza
Tabela z trzema kolumnami, w której pierwszy wiersz zawiera komórki nagłówkowe: „Id”, „Imię”, „Nazwisko”. Pozostałe wiersze wypełnione są przez skrypt 1
Pierwszy wiersz <tr> z trzema komórkami nagłówkowymi <th> - przeglądarka pogrubia je i wyśrodkowuje. Wiersze z danymi (<td>) dopisze Skrypt 1, dlatego po nagłówku zostawiasz miejsce przed </table>.
Lista numerowana (uporządkowana) wypełniona przez skrypt 2
Lista uporządkowana to <ol> (nieuporządkowana byłaby <ul>). Elementy <li> wypisze Skrypt 2. Numerów 1., 2., 3. na ilustracji 2 nie widać - ukryjesz je w CSS, bo przed nazwiskiem i tak stoi identyfikator osoby.
Formularz wysyłający dane do tego samego pliku metodą bezpieczną
Tak samo jak w lewej sekcji: method="post", bez action. To osobny formularz - wysyła tylko swoje pola, więc pole opcji z lewej sekcji nie pojedzie razem z identyfikatorem osoby.
R.3.5 Pierwsze pole opcji jest domyślnie zaznaczone (checked) , w jednym momencie można wybrać tylko jedno pole opcji, pole edycyjne jest typu number
ok. 1 min
Polecenie z arkusza
Pole edycyjne przeznaczone do wpisywania liczb
type="number" - przeglądarka przyjmie tylko liczbę i pokaże strzałki do zmiany wartości. id="person" łączy pole z etykietą, a name="person" to klucz, pod którym wartość trafi do $_POST. Z tym krokiem są spełnione wszystkie warunki R.3.5: pierwsze pole opcji zaznaczone, jedna grupa opcji i pole liczbowe.
R.2.4 W bloku nagłówkowym znajduje się <h1>: „Zgłoszenia wydarzeń”, w sekcji lewej <h2>: „Personel", w sekcji prawej <h2>: „Nowe zgłoszenie” oraz <p> z numerem zdającego w stopce
ok. 1 min
Polecenie z arkusza
Zawartość stopki: paragraf o treści „Stronę wykonał: ”, dalej wstawiony numer zdającego
Akapit w <footer>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Z tym krokiem są już wszystkie nagłówki i akapit z kryterium R.2.4: <h1>, dwa <h2> i <p> w stopce.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3
Arkusz nie mówi, jak postawić sekcje obok siebie - wybierasz display: flex na <main>. Dzieci kontenera flex stają w rzędzie, a dwa razy 50% daje całą szerokość. Przy float: left trzeba by jeszcze dodać clear: both stopce, inaczej wjechałaby pod sekcje; flex nie wypuszcza dzieci poza kontener, więc stopka sama zostaje pod spodem (R.3.1).
Typowe błędy
Bloki, które na siebie zachodzą (sprawdzane w inspektorze), zabierają punkt za układ, nawet gdy strona „na oko” wygląda dobrze.
R.4.5 wyrównanie tekstu do środka: selektory h1, h2, h3
ok. 1 min
Polecenie z arkusza
Wspólne dla selektorów nagłówka pierwszego, drugiego i trzeciego stopnia: wyrównanie tekstu do środka
Selektory znaczników h1, h2, h3 - zgodnie z uwagą arkusza, która każe stylować nagłówki i tabelę wyłącznie selektorem znacznika (bez klas i identyfikatorów). Nagłówek <h3> wypisze dopiero Skrypt 1, ale reguła czeka na niego.
Wspólne dla selektora tabeli i selektora komórki tabeli: obramowanie linią ciągłą o szerokości 1 px i kolorze Maroon
Skrót border: 1px solid Maroon - grubość, styl (linia ciągła) i kolor w jednej właściwości. Komórka tabeli to td; komórek danych jeszcze nie ma, obramowanie zobaczysz po Skrypcie 1.
Krok 36: Tabela: szerokość, jedno obramowanie, wyśrodkowanie
Kryteria: ,
R.4.4 wysokość: blok sekcji lewej i prawej - 500px, szerokość: blok sekcji lewej i prawej - 50% (width lub grid-template-columns lub flex) , selektor table - 85%
R.4.8 obramowanie: tabeli i selektora td - border: 1px solid Maroon; oraz dla tabeli krawędzie połączone: border-collapse: collapse;
ok. 2 min
Polecenie z arkusza
Dodatkowo dla selektora tabeli: szerokość 85%, krawędzie połączone w jedno obramowanie, marginesy zewnętrzne automatycznie wyliczone przez przeglądarkę
border-collapse: collapse skleja obramowanie tabeli i komórek w jedną linię (bez niej każda komórka ma osobną ramkę z odstępem). margin: auto każe przeglądarce rozdzielić wolne miejsce po równo na lewo i prawo - tabela o szerokości 85% staje na środku sekcji, jak na ilustracji 2.
R.4.2 kolor tła: blok nagłówkowy, stopka i oba przyciski - Maroon, blok sekcji lewej - LightSalmon, blok sekcji prawej - DarkSalmon
R.4.3 kolor czcionki: blok nagłówkowy, stopka, oba przyciski - biały
R.4.6 marginesy wewnętrzne (padding) : blok nagłówkowy, stopka, oba przyciski - 10px marginesy zewnętrzne (margin) : tabela - auto, jedynie margin-left dla obu przycisków - 20px
R.4.9 styl obu przycisków: bez obramowania np. border: none; oraz border-radius: 20px;
ok. 2 min
Polecenie z arkusza
Dla obu przycisków: kolor tła Maroon, biały kolor czcionki, jedynie margines zewnętrzny lewy 20 px, marginesy wewnętrzne 10 px, bez obramowania, zaokrąglenie rogów 20 px
Selektor button łapie oba przyciski naraz. „Jedynie margines zewnętrzny lewy” to margin-left: 20px - nie margin: 20px, który odsunąłby przycisk ze wszystkich stron. border: none zdejmuje domyślną szarą ramkę przycisku. Ta reguła zamyka kryteria kolorów tła i czcionki (nagłówek, stopka, przyciski) oraz marginesów.
Kroki 40-49 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 40: Połączenie z bazą i zamknięcie na końcu
Kryteria:
R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy zgloszenia oraz ostatnią operacją na bazie jest jej zamknięcie
ok. 2 min
Polecenie z arkusza
Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie zgloszenia. Na końcu zamykane jest połączenie z serwerem
Pierwszy skrypt na stronie stoi w lewej sekcji, między formularzem a tabelą, więc tam otwierasz połączenie: mysqli_connect z czterema argumentami łączy się z serwerem i od razu wybiera bazę. Uchwyt w zmiennej $connection posłuży wszystkim trzem skryptom. Ostatni blok PHP, pod drugim formularzem, na razie tylko zamyka połączenie - Skrypt 3 dopiszesz nad tą linią. Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
R.5.2 Przynajmniej jeden skrypt zawiera instrukcję wysyłającą do bazy danych zapytanie
ok. 2 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 1
Zapytanie 1 w zmiennej, na razie bez zmian - ze słowem „policjant”. mysqli_query wysyła je do bazy, a w $result zostaje wynik do odczytania wiersz po wierszu. Apostrofy wokół tekstu w SQL siedzą wewnątrz napisu PHP w cudzysłowach, więc nie trzeba ich niczym poprzedzać.
Krok 42: Skrypt 1: opcja z formularza albo „policjant”
Kryteria: ,
R.5.3 Skrypt 1 zawiera instrukcję wysyłającą do bazy zmodyfikowane zapytanie 1 w ten sposób, że wybierane są rekordy z opcją wysłaną z formularza (policjant lub ratownik) lub w stanie początkowym z opcją policjant
R.5.8 Przynajmniej jeden skrypt zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 1, zmodyfikowane w ten sposób, że wybierane są rekordy z opcją wysłaną z formularza (policjant lub ratownik) lub w stanie początkowym z opcją policjant
Wybrane pole opcji czeka w tablicy $_POST pod nazwą grupy, czyli option. Przy pierwszym wejściu na stronę formularza nikt nie wysłał - isset to sprawdza i wtedy przyjmujesz „policjant” (stan początkowy z arkusza). W zapytaniu zamiast słowa stoi zmienna $option; PHP wstawi jej wartość do napisu w cudzysłowach, a apostrofy wokół zostają, bo w SQL to nadal tekst. Podgląd pokazuje stronę po wybraniu „Ratownik” i kliknięciu „Pokaż” - tabela jeszcze pusta, wiersze wypisze następny krok.
R.5.4 Skrypt 1 wyświetla <h3> o treści „Wybrano opcję: <opcja>”, gdzie <> oznacza wybraną w formularzu opcję
ok. 1 min
Polecenie z arkusza
Wypisuje nagłówek trzeciego stopnia o treści „Wybrano opcję: <opcja>”, gdzie <opcja> oznacza wybraną w formularzu opcję. Element ten należy wypisać przed tabelą.
Blok PHP stoi między formularzem a tabelą, więc wszystko, co wypisze echo, pojawi się nad tabelą. W napisie jest wartość pola opcji - stąd „ratownik” małą literą, dokładnie jak na ilustracji 2. Wyśrodkowanie dał już styl h3.
Krok 44: Skrypt 1: wiersze tabeli z identyfikatorem
ok. 2 min
Polecenie z arkusza
Wszystkie zwrócone zapytaniem wiersze wyświetla jako kolejne wiersze tabeli zgodnie z ilustracją 2
Wiersze danych muszą trafić do środka tabeli, dlatego druga część Skryptu 1 stoi pod wierszem nagłówkowym, przed </table>. Korzysta z $result z pierwszej części - zmienne PHP żyją przez całą stronę. mysqli_fetch_row oddaje kolejny wiersz jako tablicę ($row[0] - id), a po ostatnim zwraca null i pętla while się kończy. Na razie jedna komórka, żeby zobaczyć, że pętla działa: siedmiu ratowników, od 3 do 17.
R.5.5 Skrypt 1 wypełnia tabelę zwróconymi zapytaniem wierszami, odpowiednie pola w kolumnach, wyświetlone są wszystkie zwrócone wiersze
R.2.8 W sekcji lewej umieszczona tabela o 3 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>
ok. 2 min
Polecenie z arkusza
Wszystkie zwrócone zapytaniem wiersze wyświetla jako kolejne wiersze tabeli zgodnie z ilustracją 2
Kolejne komórki w kolejności pól z SELECT: imię, nazwisko. Podgląd wygląda jak lewa sekcja z ilustracji 2: Joanna Nosowska, Karolina Mizera, Leon Zawodowiec i dalej, razem 7 wierszy. Po wybraniu „Policjant” (albo przy pierwszym wejściu) tabela ma 11 wierszy - tyle, ile zapytanie 1.
Skrypt 2 piszesz wewnątrz<ol> - to, co wypisze, stanie się elementami listy. Zmiennych $query i $result używasz ponownie: tabela Skryptu 1 jest już wypisana.
index.phpPHPzmienione: 4 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 47: Skrypt 2: elementy listy
Kryteria: ,
R.5.6 Skrypt 2 wyświetla wszystkie zwrócone zapytaniem 3 wiersze jako elementy <li> (id i nazwisko)
R.2.7 W sekcji prawej umieszczona jedna lista numerowana z elementami, zastosowane znaczniki <ol>, <li> (w skrypcie lub HTML)
ok. 2 min
Polecenie z arkusza
Wszystkie zwrócone zapytaniem wiersze wyświetla jako elementy listy zgodnie z ilustracją 2
Każdy wiersz to jeden <li> z identyfikatorem i nazwiskiem rozdzielonymi spacją. Podgląd: 2 Nowak, 3 Nosowska, 4 Mizera - jak na ilustracji 2. Te identyfikatory użytkownik wpisze w pole pod listą.
index.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 48: Skrypt 3: tylko po wysłaniu drugiego formularza
ok. 2 min
Polecenie z arkusza
Jeżeli wysłano dane z formularza to skrypt wysyła do bazy danych zmodyfikowane zapytanie 4 tak, że w miejscu id personelu jest podana wartość wysłana z formularza
Na stronie są dwa formularze, ale każdy wysyła tylko swoje pola: po „Pokaż” w $_POST jest option, po „Dodaj zgłoszenie” - person. Warunek isset($_POST["person"]) reaguje więc wyłącznie na drugi formularz. Zamknięcie połączenia stoi pod blokiem if, poza nim - wykona się zawsze, także bez wysłania formularza, i nadal jako ostatnia operacja na bazie.
Typowe błędy
Puste pole identyfikatora daje zapytanie VALUES (CURDATE(), , 14) - błąd składni SQL, wyjątek „Uncaught mysqli_sql_exception” i strona urwana w połowie (sprawdzone w PHP 8.2). Klucz tego nie sprawdza - zabezpieczenie jest w etapie „Dobre praktyki”.
index.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?phpif (isset($_POST["person"])) { } mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Krok 49: Skrypt 3: nowe zgłoszenie z identyfikatorem z formularza
Kryteria: ,
R.5.7 Skrypt 3 wysyła do bazy zmodyfikowane zapytanie 4 tak, że we wstawianym rekordzie id_personelu ma wartość przesłaną z formularza (sprawdzić w phpMyAdmin )
R.5.9 W skryptach zastosowana przynajmniej jedna zmienna oraz nazwy wszystkich zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania
ok. 3 min
Polecenie z arkusza
Jeżeli wysłano dane z formularza to skrypt wysyła do bazy danych zmodyfikowane zapytanie 4 tak, że w miejscu id personelu jest podana wartość wysłana z formularza
Zapytanie 4, w którym zamiast 1 stoi zmienna $person z formularza; pojazd 14 i CURDATE() zostają. Strona niczego nie wypisuje - efekt sprawdzasz w phpMyAdmin, jak każe klucz. Sprawdzone: po wpisaniu 2 i kliknięciu „Dodaj zgłoszenie” w tabeli rejestr przybył rekord 31 (data dzisiejsza, osoba 2, pojazd 14). Wszystkie zmienne mają nazwy mówiące, co przechowują ($connection, $option, $query, $result, $row, $person) - to kryterium R.5.9.
index.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?phpif (isset($_POST["person"])) {$person = $_POST["person"];$query = "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), $person, 14);"; mysqli_query($connection, $query); } mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Kroki 50-53 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 50: Skrypt 3 nad listą: lista od razu bez dodanej osoby
ok. 3 min
Polecenie z arkusza
Jeżeli wysłano dane z formularza to skrypt wysyła do bazy danych zmodyfikowane zapytanie 4 tak, że w miejscu id personelu jest podana wartość wysłana z formularza
Wersja z egzaminu ma pułapkę, którą widać dopiero po uruchomieniu: po dodaniu zgłoszenia dla osoby 2 lista nadal pokazuje „2 Nowak”. PHP wykonuje skrypty od góry do dołu, a Skrypt 2 czyta bazę przed Skryptem 3, który dopisuje zgłoszenie - Nowak znika dopiero przy następnym wejściu na stronę. Przenieś zapis nad listę (zamknięcie połączenia zostaje na samym dole) i podgląd po wysłaniu „2” pokazuje już tylko Nosowską i Mizerę. Na egzaminie wystarczy wersja wcześniejsza - klucz sprawdza zapis w phpMyAdmin.
index.phpPHPzmienione: 8 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2><?phpif (isset($_POST["person"])) {$person = $_POST["person"];$query = "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), $person, 14);"; mysqli_query($connection, $query); }?> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php// Skrypt 3 przeniesiony nad listę (Skrypt 2), żeby lista od razu widziała nowe zgłoszenie mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 51: Zapis zgłoszenia: zapytanie przygotowane i obsługa błędu
ok. 4 min
Polecenie z arkusza
Jeżeli wysłano dane z formularza to skrypt wysyła do bazy danych zmodyfikowane zapytanie 4 tak, że w miejscu id personelu jest podana wartość wysłana z formularza
Wersja z egzaminu sprawdzona dwoma „złośliwymi” wysłaniami: puste pole daje zapytanie VALUES (CURDATE(), , 14) i stronę urwaną błędem „Uncaught mysqli_sql_exception”, a identyfikator 99 kończy się tym samym błędem z powodu klucza obcego („a foreign key constraint fails” - takiej osoby nie ma w personelu). Poprawki: !empty zamiast isset (puste pole nie uruchamia zapisu), rzutowanie (int), zapytanie przygotowane (mysqli_prepare, znak ?, mysqli_stmt_bind_param z typem "i") i try/catch, który zamienia błąd bazy na komunikat. Podgląd pokazuje stan po wysłaniu identyfikatora 99. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
index.phpPHPzmienione: 13 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");if (isset($_POST["option"])) {$option = $_POST["option"]; } else {$option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2><?phpif (!empty($_POST["person"])) {$person = (int) $_POST["person"];$statement = mysqli_prepare($connection, "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), ?, 14)"); mysqli_stmt_bind_param($statement, "i", $person);try { mysqli_stmt_execute($statement);echo"<p>Zgłoszenie dodane.</p>"; } catch (mysqli_sql_exception $error) {echo"<p>Nie ma osoby o identyfikatorze $person.</p>"; } }/* Wersja z egzaminu: if (isset($_POST["person"])) { $person = $_POST["person"]; $query = "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), $person, 14);"; mysqli_query($connection, $query); } */?> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php// Skrypt 3 przeniesiony nad listę (Skrypt 2), żeby lista od razu widziała nowe zgłoszenie mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 52: Opcja z formularza tylko z listy dozwolonych
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 1, zmodyfikowane w ten sposób, że wybierane są rekordy z opcją wysłaną z formularza (policjant lub ratownik) lub w stanie początkowym z opcją policjant
Formularz pozwala wybrać tylko dwie wartości, ale żądanie POST można wysłać z pominięciem formularza. Sprawdzone na tej bazie: wartość ' OR '1'='1 zamienia warunek w status = '' OR '1'='1' i tabela pokazuje 18 osób - cały personel. Ponieważ dozwolone są dokładnie dwie opcje, najprostsza ochrona to biała lista: in_array sprawdza, czy wartość jest jedną z nich, a w przeciwnym razie wracasz do „policjant”. Operator ?? zastępuje cztery linie z isset. Stara wersja zostaje w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
index.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"checked> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");$option = $_POST["option"] ?? "policjant";if (!in_array($option, ["policjant", "ratownik"])) {$option = "policjant"; }// if (isset($_POST["option"])) { $option = $_POST["option"]; } else { $option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($row = mysqli_fetch_row($result)) {echo"<tr>";echo"<td>$row[0]</td>";echo"<td>$row[1]</td>";echo"<td>$row[2]</td>";echo"</tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2><?phpif (!empty($_POST["person"])) {$person = (int) $_POST["person"];$statement = mysqli_prepare($connection, "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), ?, 14)"); mysqli_stmt_bind_param($statement, "i", $person);try { mysqli_stmt_execute($statement);echo"<p>Zgłoszenie dodane.</p>"; } catch (mysqli_sql_exception $error) {echo"<p>Nie ma osoby o identyfikatorze $person.</p>"; } }/* Wersja z egzaminu: if (isset($_POST["person"])) { $person = $_POST["person"]; $query = "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), $person, 14);"; mysqli_query($connection, $query); } */?> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php// Skrypt 3 przeniesiony nad listę (Skrypt 2), żeby lista od razu widziała nowe zgłoszenie mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 53: Zaznaczona opcja zostaje po wysłaniu, pola po nazwach
ok. 3 min
Polecenie z arkusza
Pole opcji z treścią „Policjant”, domyślnie zaznaczone
Na ilustracji 2 tabela pokazuje ratowników, a zaznaczony jest „Policjant” - po przeładowaniu strony atrybut checked wraca na pierwsze pole i użytkownik nie widzi, co wybrał. Dopisz w polach opcji krótki PHP: checked dostaje pole, którego wartość przyszła z formularza (a przy pierwszym wejściu - „Policjant”, jak wymaga arkusz). W tabeli mysqli_fetch_assoc oddaje wiersz z kluczami takimi jak nazwy kolumn ($employee["nazwisko"] mówi więcej niż $row[2]; osobna nazwa $employee, bo $person to już identyfikator z drugiego formularza), a htmlspecialchars chroni stronę przed znakami < i > w danych z bazy. Na egzaminie wystarczy wersja wcześniejsza - zaznaczenie jak na ilustracji jest zgodne z arkuszem.
index.phpPHPzmienione: 7 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>ZGŁOSZENIA</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Zgłoszenia wydarzeń</h1> </header> <main> <sectionid="left"> <h2>Personel</h2> <formmethod="post"> <inputtype="radio"id="police"name="option"value="policjant"<?phpif (($_POST["option"] ?? "policjant") != "ratownik") echo"checked"; ?>> <labelfor="police">Policjant</label> <inputtype="radio"id="rescuer"name="option"value="ratownik"<?phpif (($_POST["option"] ?? "") == "ratownik") echo"checked"; ?>> <labelfor="rescuer">Ratownik</label> <buttontype="submit">Pokaż</button> </form><?php$connection = mysqli_connect("localhost", "root", "", "zgloszenia");$option = $_POST["option"] ?? "policjant";if (!in_array($option, ["policjant", "ratownik"])) {$option = "policjant"; }// if (isset($_POST["option"])) { $option = $_POST["option"]; } else { $option = "policjant"; }$query = "SELECT id, imie, nazwisko FROM personel WHERE status = '$option';";$result = mysqli_query($connection, $query);echo"<h3>Wybrano opcję: $option</h3>";?> <table> <tr> <th>Id</th> <th>Imię</th> <th>Nazwisko</th> </tr><?phpwhile ($employee = mysqli_fetch_assoc($result)) {echo"<tr>";echo"<td>" . $employee["id"] . "</td>";echo"<td>" . htmlspecialchars($employee["imie"]) . "</td>";echo"<td>" . htmlspecialchars($employee["nazwisko"]) . "</td>";echo"</tr>"; }// while ($row = mysqli_fetch_row($result)) { echo "<tr><td>$row[0]</td><td>$row[1]</td><td>$row[2]</td></tr>"; }?> </table> </section> <sectionid="right"> <h2>Nowe zgłoszenie</h2><?phpif (!empty($_POST["person"])) {$person = (int) $_POST["person"];$statement = mysqli_prepare($connection, "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), ?, 14)"); mysqli_stmt_bind_param($statement, "i", $person);try { mysqli_stmt_execute($statement);echo"<p>Zgłoszenie dodane.</p>"; } catch (mysqli_sql_exception $error) {echo"<p>Nie ma osoby o identyfikatorze $person.</p>"; } }/* Wersja z egzaminu: if (isset($_POST["person"])) { $person = $_POST["person"]; $query = "INSERT INTO rejestr (data, id_personel, id_pojazd) VALUES (CURDATE(), $person, 14);"; mysqli_query($connection, $query); } */?> <ol><?php$query = "SELECT id, nazwisko FROM personel WHERE id NOT IN (SELECT id_personel FROM rejestr);";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]$row[1]</li>"; }?> </ol> <formmethod="post"> <labelfor="person">Wybierz id osoby z listy: </label> <inputtype="number"id="person"name="person"> <buttontype="submit">Dodaj zgłoszenie</button> </form><?php// Skrypt 3 przeniesiony nad listę (Skrypt 2), żeby lista od razu widziała nowe zgłoszenie mysqli_close($connection);?> </section> </main> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Etap 6: Oddanie pracy
Krok 54 · po tym etapie masz 39 z 39 kryteriów (pkt)
Krok 54: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę.
W folderze z numerem zdającego: import.png, index.php, kw1.jpg - kw4.jpg, kwerendy.txt, przeglądarka.txt, styl.css. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.