INF.03-07-25.01-SGStyczeń 2025 · 32 kroki · ok. 64 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Wyszukiwarka polskich miast (Wersja podstawowa)
Rozwiązanie buduje wyszukiwarkę polskich miast: baza wykaz z województwami i miastami oraz cztery zapytania - funkcja tekstowa LOWER, zliczanieCOUNT, złączenie ze wzorcem LIKE i sortowaniem oraz grupowanie z aliasem, potem baner wycięty z mapy Polski i favicon z literą M, strona index.php z formularzem i blokiem wyników oraz style w style.css. Skrypt PHP odbiera z formularza początek nazwy miasta, wypisuje go jako filtr i pokazuje tabelę pasujących miast z województwami.
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ą. Skrypt jest najpierw pisany najprościej (mysqli_query, mysqli_fetch_row), a na końcu zostaje przerobiony na wersję z prawdziwych projektów: zapytanie przygotowane, które nie pozwala wstrzyknąć kodu SQL przez pole formularza, 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 z nazwanymi obszarami i PHP na PDO z zapytaniem przygotowanym od pierwszej linii - obie wersje są zgodne z kluczem.
Baza i mapa pochodzą z prawdziwego archiwum pliki11 (załącznik do arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd strony to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2; po dodaniu skryptu pokazuje stan po wysłaniu formularza z „Po” - jak na ilustracji 5.
Jak liczą się punkty. Klucz ma 38 kryteriów (R.1.1 - R.5.8), 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: Baza danych wykaz
Kryteria:
R.1.1 Wykonany import tabeli do bazy danych wykaz, co jest udokumentowane w pliku import.png
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie wykaz, z zestawem polskich znaków (np. utf8_unicode_ci).
Rozpakuj pliki11.7z z pulpitu (hasło @PolSki3Miast@) do folderu z numerem zdającego: wykaz.sql i mapa_polski.jpg. W phpMyAdmin: Nowa, nazwa wykaz, porównywanie np. utf8_unicode_ci.
Krok 2: Import tabel z pliku wykaz.sql
Kryteria:
R.1.1 Wykonany import tabeli do bazy danych wykaz, co jest udokumentowane w pliku import.png
ok. 2 min
Polecenie z arkusza
Do utworzonej bazy zaimportuj tabele z pliku wykaz.sql z rozpakowanego archiwum.
Import → wykaz.sql. Dwie tabele z ilustracji 1: wojewodztwa (16) i miasta (z polem id_wojewodztwa). Ciekawostka, która wróci przy sortowaniu: plik tworzy tabele z CHARSET=utf8, ale bez porównywania, więc dostają domyślne utf8_general_ci - niezależnie od tego, co wybrano dla bazy.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonany import tabeli do bazy danych wykaz, co jest udokumentowane w pliku 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 i zapis jako import.png.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: województwa małymi literami
Kryteria: ,
R.1.2 Zapisany plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonane zapytanie 1 wybierające jedynie nazwy województw, zapisane małymi literami. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT LOWER(nazwa) FROM wojewodztwa; (poprawne też LCASE ) oraz wynik działania udokumentowany zrzutem, na którym widocznych jest dokładnie 16 rekordów z nazwami województw zapisanymi małymi literami
ok. 1 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie nazwy województw, wszystkie litery w nazwach województw są zamienione na małe.
Nazwy są w bazie wielkimi literami („DOLNOŚLĄSKIE”). Funkcja LOWER() (albo LCASE()) zamienia wszystkie litery na małe - także polskie. Wynik: 16 wierszy, „dolnośląskie”, „kujawsko-pomorskie”… Zapytanie do kwerendy.txt, zrzut kw1.png.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT LOWER(nazwa) FROM wojewodztwa;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: liczba miast województwa 1
Kryteria:
R.1.4 Wykonane zapytanie 2 obliczające liczbę miast, dla których id_wojewodztwa = 1. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT COUNT(nazwa) FROM miasta WHERE id_wojewodztwa = 1; (COUNT poprawne też z * lub innym polem ) oraz wynik działania udokumentowany zrzutem, na którym widoczna jest jedynie wartość 91
ok. 1 min
Polecenie z arkusza
Zapytanie 2: obliczające liczbę miast dla których id_wojewodztwa jest równe jeden.
COUNT(nazwa) liczy wiersze spełniające warunek. Wynik: 91. Zrzut: kw2.png.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT LOWER(nazwa) FROM wojewodztwa;-- Zapytanie 2SELECT COUNT(nazwa) FROM miasta WHERE id_wojewodztwa = 1;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: miasta na „Lu” z województwami
Kryteria:
R.1.5 Wykonane zapytanie 3 wybierające jedynie nazwy miast zaczynające się od „Lu” i odpowiadające im nazwy województw, posortowane alfabetycznie po nazwie miasta. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE "Lu%" ORDER BY miasta.nazwa; (opcjonalnie ASC, możliwe też INNER JOIN lub porównanie kluczy po WHERE ) oraz wynik działania udokumentowany zrzutem, na którym widocznych jest dokładnie 15 wierszy z nazwami miast i województw, nazwy miast rozpoczynają się od "Lu"
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie nazwy miast zaczynające się od cząstki „Lu” i odpowiadające im nazwy województw, posortowane alfabetycznie po nazwie miasta. Należy posłużyć się relacją.
obie tabele mają kolumnę nazwa, więc wszędzie piszesz ją z nazwą tabeli: miasta.nazwa, wojewodztwa.nazwa,
JOIN ... ON wojewodztwa.id = id_wojewodztwa - relacja,
WHERE miasta.nazwa LIKE "Lu%" - nazwa zaczyna się od „Lu”,
ORDER BY miasta.nazwa - alfabetycznie.
Wynik: 15 wierszy, od Lubaczowa. Zrzut: kw3.png. To zapytanie - z cząstką z formularza zamiast „Lu” - wyśle skrypt.
Typowe błędy
Samo nazwa bez nazwy tabeli kończy się błędem „Column 'nazwa' in field list is ambiguous”.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT LOWER(nazwa) FROM wojewodztwa;-- Zapytanie 2SELECT COUNT(nazwa) FROM miasta WHERE id_wojewodztwa = 1;-- Zapytanie 3SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE "Lu%" ORDER BY miasta.nazwa;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: liczba miast w każdym województwie
Kryteria:
R.1.6 Wykonane zapytanie 4 wybierające jedynie nazwy województw i odpowiadającą im liczbę miast, które się w nich znajdują. Kolumna z liczbą miast jest nazwana (alias) „Liczba miast”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT wojewodztwa.nazwa, COUNT(miasta.nazwa) AS "Liczba miast" FROM wojewodztwa JOIN miasta ON wojewodztwa.id = miasta.id_wojewodztwa GROUP BY wojewodztwa.nazwa; (AS opcjonalnie, możliwe również INNER JOIN, poprawne też porównanie kluczy po WHERE ) oraz wynik działania udokumentowany zrzutem, na którym jest dokładnie 16 wierszy z nazwą województw i odpowiadającą im liczbą miast, np. 91 dla Dolnośląskiego 52 dla Kujawsko-Pomorskiego. Kolumna z liczbą nazwana (alias) jest "Liczba miast"
ok. 3 min
Polecenie z arkusza
Zapytanie 4: wybierające jedynie nazwy województw i odpowiadającą im liczbę miast, które się w nich znajdują. Kolumna z liczbą miast powinna mieć nadany (alias) „Liczba miast”. Należy posłużyć się relacją.
Złączenie, GROUP BY wojewodztwa.nazwa i COUNT(miasta.nazwa) w każdej grupie; alias ze spacją w cudzysłowie. Wynik: 16 wierszy, np. dolnośląskie 91, kujawsko-pomorskie 52 - jak w kluczu. Zrzut: kw4.png.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT LOWER(nazwa) FROM wojewodztwa;-- Zapytanie 2SELECT COUNT(nazwa) FROM miasta WHERE id_wojewodztwa = 1;-- Zapytanie 3SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE "Lu%" ORDER BY miasta.nazwa;-- Zapytanie 4SELECT wojewodztwa.nazwa, COUNT(miasta.nazwa) AS "Liczba miast" FROM wojewodztwa JOIN miasta ON wojewodztwa.id = miasta.id_wojewodztwa GROUP BY wojewodztwa.nazwa;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-19 · po tym etapie masz 18 z 38 kryteriów (pkt)
Krok 8: Baner: górna część mapy
Kryteria:
R.2.1 Na grafice baner.jpg widać górną część mapy z Morzem Bałtyckim. Obraz ma dokładnie: szerokość 1406 px, wysokość 270 px
ok. 3 min
Polecenie z arkusza
Przygotowanie pliku z banerem strony: Plik mapa_polski.jpg należy wykadrować tak, że widoczna jest jedynie górna część mapy o wysokości 270 px. Nazwa pliku wynikowego baner.jpg.
Mapa ma 1406 × 1262 px. W GIMP-ie Obraz → Rozmiar płótna: szerokość bez zmian, wysokość 270, przesunięcie 0 (górna krawędź) i Obraz → Przytnij do płótna - albo zaznaczenie prostokątne 1406 × 270 od punktu 0, 0 i Przytnij do zaznaczenia. Zostaje pas z Morzem Bałtyckim. Eksportuj jakobaner.jpg: dokładnie 1406 × 270 px (R.2.1).
Typowe błędy
Skalowanie zamiast kadrowania (np. do wysokości 270) zmniejsza całą mapę - klucz wymaga szerokości 1406 px i widoku samej górnej części.
Podgląd strony po tym kroku
Krok 9: Favicon fav.png: czerwone M
Kryteria: ,
R.2.2 Obraz fav.png ma wymiary dokładnie 192 px na 192 px oraz tło przezroczyste
R.2.3 Na obrazie faviconu widoczna jest litera M zapisana czcionką szeryfową w kolorze czerwonym. Litera M wypełnia min. 90% obrazu, przynajmniej w jednej z osi
ok. 3 min
Polecenie z arkusza
Przygotowanie faviconu: wysokość i szerokość 192 px. Tło przezroczyste. Obraz wypełnia litera M koloru czerwonego zapisana dowolną czcionką szeryfową. Litera M wypełnia cały obraz, przynajmniej w jednej z osi (pionowej lub poziomej). Nazwa fav.png.
Plik → Nowy192 × 192, wypełnienie: przezroczystość. Narzędzie Tekst: litera M, czcionka szeryfowa (z „kreseczkami” na końcach, np. Times New Roman Bold), kolor czerwony ff0000. Rozmiar dobierasz tak, żeby litera sięgała prawie od krawędzi do krawędzi - tu 183 z 192 px w poziomie; klucz wymaga co najmniej 90% (R.2.2, R.2.3). Eksportuj jakofav.png.
Podgląd strony po tym kroku
Krok 10: Plik index.php w HTML5
Kryteria:
R.2.4 Witryna internetowa zapisana w pliku index.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl">. Strona zawiera sekcje head i body
ok. 1 min
Polecenie z arkusza
Cechy witryny: Składa się ze strony o nazwie index.php. Zapisana w języku HTML5.
Jedna strona, index.php - z formularzem i skryptem w tym samym pliku. Bez PHP podgląd pokazuje ją wprost.
R.2.4 Witryna internetowa zapisana w pliku index.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl">. Strona zawiera sekcje head i body
R.2.4 Witryna internetowa zapisana w pliku index.php oraz zapisany jawnie standard kodowania polskich znaków, deklaracja HTML5 <!DOCTYPE HTML>, zadeklarowany język witryny: polski np. <html lang="pl">. Strona zawiera sekcje head i body
ok. 1 min
Polecenie z arkusza
Jawnie zastosowany właściwy standard kodowania polskich znaków.
R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie style.css formatowanie CSS pochodzi jedynie z tego arkusza. Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie style.css prawidłowo połączony z kodem strony.
R.2.6 Zdefiniowany układ strony, dzielący ją na bloki: nagłówkowy, dwa lewe i prawy przy pomocy semantycznych znaczników sekcji języka HTML5, zgodnie z ich znaczeniem, w tym do części nagłówkowej - header. Dopuszcza się dodatkowe użycie bloków div lub section
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: kontener zawartości, a w nim blok nagłówkowy, poniżej dwa bloki lewe jeden pod drugim i obok blok prawy. Podział zrealizowany za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 4.
Kontener <div id="container">, w nim <header> i trzy <section>: search (lewy górny), results (prawy), info (lewy dolny) (R.2.6). Rozmieszczenie zrobi CSS.
R.2.7 Umieszczone w bloku lewym górnym <h4>: "Podaj początek nazwy miasta", w bloku prawym <h1>: "Wyniki wyszukiwania miast z uwzględnieniem filtra:" oraz w lewym dolnym paragraf: "Egzamin INF.03" oraz drugi paragraf z numerem zdającego
R.2.10 W bloku lewym górnym umieszczony formularz składający się z pola edycyjnego i przycisku Szukaj
R.3.3 Formularz wysyła dane metodą POST do tego samego pliku (poprawne również bez atrybutu action)
R.3.4 Przycisk realizuje funkcję wysłania danych z formularza (input lub button z typem submit lub button bez typu)
ok. 3 min
Polecenie z arkusza
Zawartość bloku lewego-górnego: Nagłówek czwartego stopnia o treści „Podaj początek nazwy miasta”. Formularz wysyłający dane do tego samego pliku metodą bezpieczną, o polach: Pole edycyjne. Przycisk „Szukaj” wysyłający dane formularza do skryptu.
<form method="post"> bez action wysyła dane do tego samego pliku (R.3.3). „Metoda bezpieczna” w rozumieniu arkusza to POST (tak ocenia klucz R.3.3): dane idą w treści żądania, a nie w adresie strony. W specyfikacji HTTP „bezpieczne” są co prawda metody, które niczego nie zmieniają na serwerze (GET i HEAD), ale punkt daje method="post". Pole tekstowe ma name="city" - pod tą nazwą skrypt znajdzie je w $_POST; przycisk type="submit" wysyła formularz (R.3.4).
R.2.7 Umieszczone w bloku lewym górnym <h4>: "Podaj początek nazwy miasta", w bloku prawym <h1>: "Wyniki wyszukiwania miast z uwzględnieniem filtra:" oraz w lewym dolnym paragraf: "Egzamin INF.03" oraz drugi paragraf z numerem zdającego
ok. 1 min
Polecenie z arkusza
Zawartość bloku prawego: Nagłówek pierwszego stopnia o treści „Wyniki wyszukiwania miast z uwzględnieniem filtra:”.
<h1>; pod nim stanie skrypt.
index.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wyszukiwarka miast</title> <linkrel="icon"href="fav.png"> <linkrel="stylesheet"href="style.css"></head><body> <divid="container"> <header> <imgsrc="baner.jpg"alt="Polska"> </header> <sectionid="search"> <h4>Podaj początek nazwy miasta</h4> <formmethod="post"> <inputtype="text"name="city"> <buttontype="submit">Szukaj</button> </form> </section> <sectionid="results"> <h1>Wyniki wyszukiwania miast z uwzględnieniem filtra:</h1> </section> <sectionid="info"> </section> </div></body></html>
Podgląd strony po tym kroku (index.php)
Krok 19: Blok lewy dolny: dwa akapity
Kryteria:
R.2.7 Umieszczone w bloku lewym górnym <h4>: "Podaj początek nazwy miasta", w bloku prawym <h1>: "Wyniki wyszukiwania miast z uwzględnieniem filtra:" oraz w lewym dolnym paragraf: "Egzamin INF.03" oraz drugi paragraf z numerem zdającego
ok. 1 min
Polecenie z arkusza
Zawartość bloku lewego-dolnego: Paragraf (akapit) zawierający napis „Egzamin INF.03”. Paragraf z napisem „Autor: ”, dalej wstawiony numer zdającego.
Dwa <p>. Na egzaminie po „Autor:” wpisujesz swój numer zdającego (PESEL).
index.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wyszukiwarka miast</title> <linkrel="icon"href="fav.png"> <linkrel="stylesheet"href="style.css"></head><body> <divid="container"> <header> <imgsrc="baner.jpg"alt="Polska"> </header> <sectionid="search"> <h4>Podaj początek nazwy miasta</h4> <formmethod="post"> <inputtype="text"name="city"> <buttontype="submit">Szukaj</button> </form> </section> <sectionid="results"> <h1>Wyniki wyszukiwania miast z uwzględnieniem filtra:</h1> </section> <sectionid="info"> <p>Egzamin INF.03</p> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Podgląd strony po tym kroku (index.php)
Etap 3: Styl CSS
Kroki 20-26 · po tym etapie masz 29 z 38 kryteriów (pkt)
Krok 20: Plik style.css: krój czcionki
Kryteria:
R.4.1 Ustawiony domyślnie dla wszystkich selektorów (*): krój czcionki Helvetica
ok. 1 min
Polecenie z arkusza
Domyślne dla wszystkich selektorów: krój czcionki Helvetica.
Selektor * (R.4.1).
style.cssCSSnowy plik
* {font-family: Helvetica;}
Podgląd strony po tym kroku (index.php)
Krok 21: Tło i wyśrodkowanie
Kryteria: ,
R.4.2 Ustawiony kolor tła LightSalmon dla ciała strony oraz DarkSalmon dla bloków lewego- dolnego i prawego
R.4.5 Ustawione wyrównanie tekstu do środka dla ciała strony
ok. 1 min
Polecenie z arkusza
Dla ciała strony: kolor tła LightSalmon, wyrównanie tekstu do środka.
R.4.2 Ustawiony kolor tła LightSalmon dla ciała strony oraz DarkSalmon dla bloków lewego- dolnego i prawego
R.4.3 Ustawiona wysokość 400px bloku lewego-górnego, 100px lewego-dolnego i 500px prawego
R.4.4 Ustawiona szerokość obu bloków lewych 30%, prawego 70% (width lub grid-template- columns lub flex) oraz dla selektora img szerokość 100% i selektora table 70%
R.4.7 Ustawione paski przewijania (overflow) na auto dla bloku prawego
ok. 2 min
Polecenie z arkusza
Dla bloku lewego-górnego: szerokość 30%, wysokość 400 px. Dla bloku lewego-dolnego: kolor tła DarkSalmon, szerokość 30%, wysokość 100 px. Dla bloku prawego: kolor tła DarkSalmon, szerokość 70%, wysokość 500 px, paski przewijania widoczne tylko w przypadku, gdy zawartość nie mieści się.
Wysokości się sumują: 400 + 100 = 500 px po lewej, tyle co blok prawy. overflow: auto - pasek tylko przy długiej liście miast (R.4.2, R.4.3, R.4.4, R.4.7).
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 4 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float albo display flex albo grid albo position)
ok. 2 min
Polecenie z arkusza
Poniżej dwa bloki lewe jeden pod drugim i obok blok prawy. Podział zrealizowany tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z ilustracją 4.
Bloki lewe dostają float: left, a blok prawy float: right:
search (30%) staje w lewym górnym rogu, a results (70%) przy prawej krawędzi obok niego - razem 100% szerokości kontenera,
info spływa w dół, aż zmieści się przy lewej krawędzi: zaraz pod blokiem search (400 px), obok wciąż trwającego bloku results (500 px).
Prawy blok musi pływać w prawo: gdyby wszystkie trzy miały float: left, przeglądarka postawiłaby info dopiero pod blokiem results - blok pływający w lewo nie może stanąć wyżej niż dół wcześniejszego bloku pływającego w lewo, który ma obok siebie. Wysokości się zgadzają (400 + 100 = 500 px), więc oba lewe bloki kończą się równo z prawym. Pod blokami nie ma już innej treści, więc clear nie jest potrzebne (R.3.1).
Typowe błędy
Siatka grid-template-columns: 30% 70% na kontenerze razem z width: 30% i width: 70% na blokach daje bloki trzy razy węższe: procent szerokości elementu siatki liczy się od jego kolumny, nie od strony (30% z 30% to 9%). Przy siatce szerokości zostają tylko w grid-template-columns.
R.4.4 Ustawiona szerokość obu bloków lewych 30%, prawego 70% (width lub grid-template- columns lub flex) oraz dla selektora img szerokość 100% i selektora table 70%
Krok 25: Akapit filtra: klasa i kolor pod kursorem
Kryteria: ,
R.4.9 Ustawiony styl jedynie dla paragrafu filtra: czcionka pochylona o rozmiarze 200%, marginesy wewnętrzne 10px
R.4.10 Gdy kursor myszy znajdzie się na paragrafie z frazą, jego kolor czcionki zmienia się na GhostWhite
ok. 2 min
Polecenie z arkusza
Jedynie dla paragrafu ze skryptu wyświetlającego tekst filtra: czcionka pochylona o rozmiarze 200%, marginesy wewnętrzne 10 px. Gdy kursor myszy znajdzie się na paragrafie filtra jego kolor czcionki zmienia się na GhostWhite.
„Jedynie dla tego paragrafu” - na stronie są też inne akapity (w bloku lewym dolnym), więc styl dostaje klasafilter, którą skrypt nada akapitowi z filtrem (R.4.9, R.4.10).
Typowe błędy
Selektor p zmieniłby też „Egzamin INF.03” i „Autor:” - klucz mówi „jedynie dla paragrafu filtra”.
R.4.4 Ustawiona szerokość obu bloków lewych 30%, prawego 70% (width lub grid-template- columns lub flex) oraz dla selektora img szerokość 100% i selektora table 70%
R.4.6 Ustawione marginesy zewnętrzne (margin) na auto dla tabeli
R.4.8 Ustawione obramowanie dla tabeli i selektora td: 1px dotted Maroon
ok. 2 min
Polecenie z arkusza
Dla selektora tabeli i selektora komórek tabeli (bez nagłówkowych): obramowanie linią kropkowaną o grubości 1 px i kolorze Maroon. Dodatkowo dla selektora tabeli: szerokość 70%, marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę.
Linia kropkowana to dotted. „Bez nagłówkowych” - selektor td, nie th. margin: auto przy szerokości 70% wyśrodkowuje tabelę (R.4.4, R.4.6, R.4.8). Tabelę wygeneruje skrypt.
Kroki 27-30 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 27: Połączenie z bazą wykaz i zamknięcie
Kryteria: , ,
R.5.1 Skrypt jest napisany w języku PHP i zawiera przynajmniej jedną zgodną z treścią zadania instrukcję
R.5.2 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy wykaz
R.5.3 Ostatnią operacją na bazie jest jej zamknięcie
ok. 2 min
Polecenie z arkusza
Łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie wykaz. Na końcu zamykane jest połączenie z serwerem.
Skrypt w bloku prawym, pod nagłówkiem. Od razu połączenie na początku i mysqli_close na końcu - wszystko inne wstawisz pomiędzy (R.5.1, R.5.2, R.5.3). Podgląd od tego kroku to wynik prawdziwego uruchomienia w PHP.
R.5.4 W skrypcie zapisana instrukcja warunkowa sprawdzająca czy formularz wysyła dane. Wszystkie operacje obsługujące formularz i zapytanie są wykonywane tylko wtedy, gdy warunek jest spełniony
R.5.6 Skrypt wyświetla w paragrafie frazę pobraną z formularza
ok. 3 min
Polecenie z arkusza
Skrypt sprawdza czy z formularza zostały wysłane dane i jeżeli tak to wyświetla w paragrafie wyszukiwany filtr, który został przesłany z formularza.
isset($_POST["city"]) - przy pierwszym wejściu na stronę formularza nie wysłano i pola nie ma; wszystko, co dotyczy wyszukiwania, dzieje się w środku if (R.5.4). Wpisaną cząstkę wypisujesz w akapicie z klasą filter - styl z CSS już czeka. Podgląd pokazuje stan po wysłaniu „Po” (R.5.6).
R.5.5 Skrypt zawiera instrukcję wysyłającą do bazy danych zmodyfikowane zapytanie 3 w ten sposób, że wybierane są miasta rozpoczynające się od frazy przesłanej przez formularz
ok. 2 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 3, w ten sposób że wybierane są miasta rozpoczynające się od cząstki przesłanej przez formularz.
W zapytaniu 3 zamiast Lu stoi zmienna: LIKE '$filter%' - po wstawieniu „Po” baza dostaje LIKE 'Po%' (R.5.5).
index.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wyszukiwarka miast</title> <linkrel="icon"href="fav.png"> <linkrel="stylesheet"href="style.css"></head><body> <divid="container"> <header> <imgsrc="baner.jpg"alt="Polska"> </header> <sectionid="search"> <h4>Podaj początek nazwy miasta</h4> <formmethod="post"> <inputtype="text"name="city"> <buttontype="submit">Szukaj</button> </form> </section> <sectionid="results"> <h1>Wyniki wyszukiwania miast z uwzględnieniem filtra:</h1><?php$connection = mysqli_connect("localhost", "root", "", "wykaz");if (isset($_POST["city"])) {$filter = $_POST["city"];echo"<p class=\"filter\">$filter</p>";$query = "SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE '$filter%' ORDER BY miasta.nazwa;";$result = mysqli_query($connection, $query); } mysqli_close($connection);?> </section> <sectionid="info"> <p>Egzamin INF.03</p> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
R.2.8 W bloku prawym umieszczona tabela o dwóch kolumnach i pierwszym wierszu zawierającym komórki nagłówkowe. Zastosowane znaczniki <table>, <tr>, <th>, <td> (w skrypcie lub HTML)
R.5.7 Skrypt wyświetla zwrócone miasta i województwa w osobnych wierszach tabeli
R.5.8 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania
ok. 3 min
Polecenie z arkusza
Tworzy tabelę z wierszem składającym się z komórek nagłówkowych: „Miasto” , „Województwo”. Wyświetla zwrócone miasta i województwa w osobnych wierszach tabeli – patrz ilustracja 5.
Otwarcie tabeli i wiersz nagłówkowy wypisujesz przed pętlą (raz), wiersze z danymi w pętli, zamknięcie </table>po niej. Podgląd: 14 miast na „Po” - jak na ilustracji 5, łącznie z kolejnością „Poznań”, a dopiero potem „Połaniec”: tabele mają porównywanie utf8_general_ci, w którym „ł” stoi za „z” (R.2.8, R.5.7, R.5.8).
index.phpPHPzmienione: 6 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wyszukiwarka miast</title> <linkrel="icon"href="fav.png"> <linkrel="stylesheet"href="style.css"></head><body> <divid="container"> <header> <imgsrc="baner.jpg"alt="Polska"> </header> <sectionid="search"> <h4>Podaj początek nazwy miasta</h4> <formmethod="post"> <inputtype="text"name="city"> <buttontype="submit">Szukaj</button> </form> </section> <sectionid="results"> <h1>Wyniki wyszukiwania miast z uwzględnieniem filtra:</h1><?php$connection = mysqli_connect("localhost", "root", "", "wykaz");if (isset($_POST["city"])) {$filter = $_POST["city"];echo"<p class=\"filter\">$filter</p>";$query = "SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE '$filter%' ORDER BY miasta.nazwa;";$result = mysqli_query($connection, $query);echo"<table>";echo"<tr><th>Miasto</th><th>Województwo</th></tr>";while ($row = mysqli_fetch_row($result)) {echo"<tr><td>$row[0]</td><td>$row[1]</td></tr>"; }echo"</table>"; } mysqli_close($connection);?> </section> <sectionid="info"> <p>Egzamin INF.03</p> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Podgląd strony po tym kroku (index.php)
Etap 5: Dobre praktyki (poza kluczem)
Krok 31 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 31: Zapytanie przygotowane i htmlspecialchars
ok. 5 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 3, w ten sposób że wybierane są miasta rozpoczynające się od cząstki przesłanej przez formularz.
W wersji z egzaminu tekst z pola trafia wprost do treści zapytania. Wpisanie x' OR 1=1 OR 'a'=' zamyka apostrof i dokleja warunek zawsze prawdziwy 1=1 - strona wypisuje wtedy wszystkie miasta z bazy (919 wierszy - sprawdzone w PHP 8.2 na bazie z arkusza). To SQL injection. Poprawki:
zapytanie przygotowane: LIKE ? i mysqli_stmt_bind_param - wartość idzie do bazy osobno i nie zmieni zapytania,
addcslashes($filter, "%_\\") - znaki % i _ wpisane przez użytkownika mają być zwykłymi znakami, nie wzorcem, a % doklejasz sam,
trim usuwa przypadkowe spacje, htmlspecialchars zabezpiecza wypisywany filtr i dane z bazy.
Podgląd po tej zmianie pokazuje znów wynik dla „Po”. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
index.phpPHPzmienione: 8 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wyszukiwarka miast</title> <linkrel="icon"href="fav.png"> <linkrel="stylesheet"href="style.css"></head><body> <divid="container"> <header> <imgsrc="baner.jpg"alt="Polska"> </header> <sectionid="search"> <h4>Podaj początek nazwy miasta</h4> <formmethod="post"> <inputtype="text"name="city"> <buttontype="submit">Szukaj</button> </form> </section> <sectionid="results"> <h1>Wyniki wyszukiwania miast z uwzględnieniem filtra:</h1><?php$connection = mysqli_connect("localhost", "root", "", "wykaz");if (isset($_POST["city"])) {$filter = trim($_POST["city"]);echo"<p class=\"filter\">" . htmlspecialchars($filter) . "</p>";$statement = mysqli_prepare($connection, "SELECT miasta.nazwa, wojewodztwa.nazwa FROM miasta JOIN wojewodztwa ON wojewodztwa.id = id_wojewodztwa WHERE miasta.nazwa LIKE ? ORDER BY miasta.nazwa");$pattern = addcslashes($filter, "%_\\") . "%"; mysqli_stmt_bind_param($statement, "s", $pattern); mysqli_stmt_execute($statement);$result = mysqli_stmt_get_result($statement);echo"<table>";echo"<tr><th>Miasto</th><th>Województwo</th></tr>";while ($row = mysqli_fetch_row($result)) {echo"<tr><td>" . htmlspecialchars($row[0]) . "</td><td>" . htmlspecialchars($row[1]) . "</td></tr>"; }echo"</table>"; } mysqli_close($connection);?> </section> <sectionid="info"> <p>Egzamin INF.03</p> <p>Autor: Bartosz Bryniarski</p> </section> </div></body></html>
Krok 32 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 32: 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. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wpisujesz nazwę przeglądarki.
W folderze: index.php, style.css, kwerendy.txt, import.png, kw1.png - kw4.png, baner.jpg, fav.png i przeglądarka.txt. 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.