INF.03-08-25.06-SGCzerwiec 2025 · 64 kroki · ok. 119 min
Rozwiązanie krok po kroku: Portal hobbystyczny o smokach
Budujemy portal hobbystyczny o smokach: baza smoki z czterema kwerendami, grafika przeskalowana do 300 px wysokości, strona smoki.php ze stylami w styl.css, przełączanie sekcji w JavaScript i dwa skrypty PHP (lista krajów i tabela smoków wybranego kraju).
Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się cytatem wymagania, a kod obok pokazuje dokładnie te linie, które je spełniają. Kolejność jest taka, jak warto pracować na egzaminie: najpierw baza i zrzuty (pewne punkty), potem struktura strony, style, JavaScript, na końcu PHP.
Grafiki, opisy i baza danych pochodzą z prawdziwego archiwum pliki7 (załącznik do pobrania na stronie 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.
Etapy pracy (64 kroki to siedem krótkich etapów):
Baza danych - kroki 1-7 (kryteria R.1, 6 punktów)
Grafika i strona HTML - kroki 8-30 (R.2 i R.3, 15 punktów)
Styl CSS - kroki 31-42 (R.4, 10 punktów)
JavaScript - kroki 43-49 (R.5.6 - R.5.10)
Skrypty PHP - kroki 50-59 (R.5.1 - R.5.5)
Nasłuchiwacze zamiast onclick - kroki 60-63 (wariant, poza kluczem)
Oddanie pracy - krok 64
Jak liczą się punkty. Klucz ma 41 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 31 punktów - można stracić 10 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.
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.
Arkusz: Utwórz bazę danych o nazwie smoki, z zestawem polskich znaków (np. utf8_polish_ci).
W przeglądarce otwieramy http://localhost/phpmyadmin, klikamy Nowa w lewym panelu, wpisujemy nazwę smoki i z listy metod porównywania wybieramy utf8_polish_ci. Bez polskiego porównywania polskie litery mogłyby sortować się poza alfabetem (np. „ł” za „z”), a dane z importu mogłyby stracić ogonki.
Typowe błędy
Nazwa bazy musi być dokładnie smoki - skrypty PHP łączą się z bazą po nazwie, więc Smoki albo smok odetnie punkty także za skrypty.
Krok 2: Import tabel z pliku bazasmoki.sql
Kryteria: R.1.1ok. 2 min
Arkusz: Z rozpakowanego archiwum zaimportuj tabele z pliku bazasmoki.sql do utworzonej bazy.
Wchodzimy do bazy smoki (musi być zaznaczona w lewym panelu), karta Import, Wybierz plik → bazasmoki.sql z rozpakowanego archiwum, Wykonaj.
Po imporcie w bazie są trzy tabele z ilustracji 1: smok (id, nazwa, dlugosc, szerokosc, pochodzenie - 44 wiersze), parada (id, rok, liczba_widzow, atrakcje - 48 wierszy) i łącząca je udzial z kluczami obcymi id_smok i id_parada (127 wierszy). To relacja wiele do wielu - jeden smok bierze udział w wielu paradach, a w jednej paradzie idzie wiele smoków. Ta wiedza przyda się przy zapytaniu 3.
Typowe błędy
Import bez wcześniejszego wejścia do bazy smoki tworzy tabele w innej bazie (np. test) - zapytania w PHP nie znajdą wtedy tabeli smok.
Krok 3: Zrzut ekranu import.jpg
Kryteria: R.1.1ok. 2 min
Arkusz: Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie JPEG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.
Klawisz Print Screen (cały ekran, nie Alt+PrtScr, który łapie tylko aktywne okno), wklejamy do edytora grafiki i zapisujemy jako import.jpg w folderze z numerem zdającego. Na zrzucie ma być widać komunikat phpMyAdmin o pomyślnym imporcie albo listę trzech tabel w bazie smoki - to dowód, że import się udał.
Typowe błędy
Wykadrowany zrzut (samo okno przeglądarki, bez paska zadań) nie jest oceniany - klucz mówi to wprost. Zrzut importu ma być w JPEG, zrzuty kwerend w PNG.
Krok 4: Zapytanie 1: smoki z Polski
Kryteria: R.1.2, R.1.3ok. 4 min
Arkusz: Zapytanie 1: wybierające jedynie nazwę, długość i szerokość smoka, dla smoków z Polski.
Zakładka SQL w phpMyAdmin (przy zaznaczonej bazie smoki). Zapytanie czytamy klauzula po klauzuli:
SELECT nazwa, dlugosc, szerokosc - które kolumny ma zwrócić wynik. Słowo „jedynie” w arkuszu oznacza, że wymieniamy dokładnie te trzy; SELECT * nie spełnia warunku, bo zwraca też id i pochodzenie. Nazwy kolumn bierzemy z ilustracji 1 (bez polskich znaków, tak jak w tabeli).
FROM smok - z której tabeli.
WHERE pochodzenie = "Polska" - które wiersze: tylko te, w których kraj to Polska. Napis porównujemy w cudzysłowie.
Wynik: dokładnie 23 rekordy o trzech kolumnach. Zapytanie od razu kopiujemy do pliku kwerendy.txt (zwykły edytor tekstu, np. Notatnik) i robimy zrzut całego ekranu z wynikiem: kw1.png.
Typowe błędy
WHERE pochodzenie = Polska bez cudzysłowu to błąd składni - napis w SQL zawsze w cudzysłowie albo apostrofach.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska";
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: kraje pochodzenia bez powtórzeń
Kryteria: R.1.4ok. 3 min
Arkusz: Zapytanie 2: wybierające niepowtarzające się kraje pochodzenia smoków, posortowane rosnąco według kraju pochodzenia.
Klauzula po klauzuli:
SELECT DISTINCT pochodzenie - jedna kolumna, a DISTINCT usuwa powtórzenia: bez niego dostalibyśmy „Polska” 23 razy, po jednym na każdego polskiego smoka.
FROM smok - kraj pochodzenia jest w tabeli smoków.
ORDER BY pochodzenie - sortowanie po tej kolumnie. Rosnąco (A→Z) jest domyślne, więc ASC można pominąć; malejąco byłoby DESC.
Wynik to pięć wierszy: Bułgaria, Chiny, Francja, Japonia, Polska. Zrzut: kw2.png.
To samo zapytanie wyśle później skrypt 1, żeby wypełnić listę rozwijaną - warto je zapamiętać.
Typowe błędy
Klucz dopuszcza też GROUP BY pochodzenie zamiast DISTINCT (wtedy ORDER BY jest według klucza opcjonalne). DISTINCT jest jednak prostszy i dokładnie oddaje słowo „niepowtarzające się” z arkusza.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska";-- Zapytanie 2SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: średnia długość smoków w paradach po 2005 roku
Kryteria: R.1.5ok. 6 min
Arkusz: Zapytanie 3: wybierające jedynie rok z tabeli parada i obliczającą odpowiadającą mu średnią wartość długości z tabeli smok, nazwa kolumny (alias) „Średnia długość” tylko dla lat po 2005 roku. Należy posłużyć się relacją i zgrupować rekordy względem roku.
Najtrudniejsze zapytanie arkusza. Rok jest w tabeli parada, długość w smok, a żadna z nich nie ma klucza do drugiej - łączy je tabela udzial (ilustracja 1). Klauzula po klauzuli:
SELECT rok, AVG(dlugosc) AS "Średnia długość" - rok i średnia z długości. AVG to funkcja grupująca: liczy jedną wartość z wielu wierszy. AS nadaje kolumnie wyniku nazwę (alias); alias ze spacją i polskimi znakami musi być w cudzysłowie.
FROM parada - zaczynamy od tabeli z rokiem.
JOIN udzial ON parada.id = udzial.id_parada - do każdej parady dokładamy jej wpisy z tabeli łączącej; ON mówi, po których kolumnach wiersze do siebie pasują (klucz główny parady = klucz obcy w udzial).
JOIN smok ON udzial.id_smok = smok.id - i do każdego wpisu dokładamy smoka, żeby mieć jego długość. Po dwóch złączeniach każdy wiersz to para „parada + smok, który w niej szedł”.
WHERE rok > 2005 - odrzucamy parady z 2005 i wcześniejsze przed liczeniem średniej. „Po 2005 roku” to >, nie >=.
GROUP BY rok - wiersze o tym samym roku zlewają się w jeden, a AVG liczy średnią osobno dla każdej grupy. Bez grupowania wyszłaby jedna liczba dla wszystkich lat.
JOIN bez warunku ON daje iloczyn kartezjański i złą średnią. HAVING rok > 2005 też zadziała, ale warunek na zwykłej kolumnie to miejsce dla WHERE - HAVING jest dla warunków na wyniku funkcji grupujących (np. HAVING AVG(dlugosc) > 5).
kwerendy.txtTekstzmienione: 8 linii
-- Zapytanie 1SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska";-- Zapytanie 2SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;-- Zapytanie 3SELECT rok, AVG(dlugosc) AS "Średnia długość"FROM paradaJOIN udzial ON parada.id = udzial.id_paradaJOIN smok ON udzial.id_smok = smok.idWHERE rok > 2005GROUP BY rok;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowa kolumna w tabeli parada
Kryteria: R.1.6ok. 3 min
Arkusz: Zapytanie 4: zmieniające strukturę tabeli parada, przez wstawienie nowej kolumny lokalizacja typu napisowego o maksymalnej długości 100 znaków.
Zmiana struktury tabeli to ALTER TABLE (nie UPDATE, który zmienia dane). Typ napisowy o maksymalnej długości to VARCHAR(100). Zrzut kw4.png ma pokazać komunikat o pomyślnym wykonaniu albo kartę Struktura z nową kolumną.
Plik kwerendy.txt zawiera teraz wszystkie cztery zapytania - sprawdź, że jest zapisany w folderze z numerem zdającego.
Typowe błędy
CHAR(100) to napis o stałej długości 100 znaków - arkusz mówi o długości maksymalnej, czyli VARCHAR.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = "Polska";-- Zapytanie 2SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;-- Zapytanie 3SELECT rok, AVG(dlugosc) AS "Średnia długość"FROM paradaJOIN udzial ON parada.id = udzial.id_paradaJOIN smok ON udzial.id_smok = smok.idWHERE rok > 2005GROUP BY rok;-- Zapytanie 4ALTER TABLE parada ADD COLUMN lokalizacja VARCHAR(100);
Podgląd strony po tym kroku
Krok 8: Przeskalowanie grafiki smok1.jpg
Kryteria: R.2.1ok. 3 min
Arkusz: Cechy grafiki smok1.jpg: przeskalowana z zachowaniem proporcji do wysokości 300 px.
Plik smok1.jpg z archiwum to zdjęcie z aparatu: 3872 × 2592 px, 2,6 MB - za duże na stronę. W edytorze grafiki rastrowej (np. GIMP: Obraz → Skaluj obraz) wpisujemy wysokość 300 px przy zamkniętym łańcuchu proporcji. Szerokość przeliczy się sama na 448 px (3872 · 300 / 2592 = 448,1) - i dokładnie to sprawdza egzaminator (448 ±5 px). Zapisujemy jako smok1.jpg w folderze zdającego. Pozostałe dwa zdjęcia mają już 448 × 300 px - arkusz nie każe ich ruszać.
Typowe błędy
Rozłączony łańcuch proporcji = obraz rozciągnięty do 300 px wysokości przy starej szerokości. Wysokość się zgadza, punktu nie ma.
Podgląd strony po tym kroku
Krok 9: Plik smoki.php w HTML5
Kryteria: R.2.2ok. 2 min
Arkusz: Składa się ze strony o nazwie smoki.php. Zapisana w języku HTML5.
W edytorze zaznaczającym składnię tworzymy plik smoki.php w folderze zdającego. Rozszerzenie .php, bo na końcu dojdą skrypty PHP - na razie to czysty HTML i przeglądarka pokaże go tak samo jak .html.
Pierwsza linia <!DOCTYPE html> mówi przeglądarce, że dokument jest w HTML5. Dalej szkielet każdej strony: <html>, a w nim <head> (informacje o stronie) i <body> (to, co widać w oknie).
Typowe błędy
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0..."> to deklaracja XHTML, nie HTML5 - klucz sprawdza krótką postać HTML5.
Arkusz: Zadeklarowany polski język zawartości witryny.
Atrybut lang="pl" w znaczniku <html>. Czytnik ekranu czyta wtedy tekst polską wymową, a przeglądarka dobiera słownik i dzielenie wyrazów. Na stronie nic się nie zmienia - to informacja dla programów, nie dla oka.
Arkusz: Jawnie zastosowany właściwy standard kodowania polskich znaków.
<meta charset="UTF-8"> jako pierwsza rzecz w <head>. „Jawnie” znaczy: wpisane w kodzie, a nie zdane na domysł przeglądarki. Bez tej linii „Długość” może wyświetlić się jako „DÅ‚ugość”. Plik trzeba też zapisać w UTF-8 - większość edytorów robi to domyślnie.
Arkusz: 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.css jeszcze nie istnieje - napiszemy go po HTML - ale połączenie może już być: gdy plik się pojawi w tym samym folderze, style zadziałają bez zmian w HTML.
Typowe błędy
<link> to znacznik pusty - w HTML5 bez </link> i bez ukośnika />. Bez rel="stylesheet" przeglądarka nie potraktuje pliku jako stylów.
Arkusz: 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.
Z ilustracji 3: na górze blok nagłówkowy, pod nim obok siebie blok nawigacyjny i blok główny, na dole stopka. Semantyczne odpowiedniki z tabeli 4 arkusza to <header>, <nav>, <main> i <footer> - nie<div> z klasami. Na razie są puste. To, że nawigacja i część główna staną obok siebie, zrobi dopiero CSS.
Typowe błędy
Cztery zwykłe <div> z identyfikatorami w rodzaju naglowek, nawigacja wyglądają na stronie identycznie, ale kryterium R.2.3 wymaga znaczników semantycznych - to jest sprawdzane w kodzie źródłowym.
Arkusz: Zawartość bloku nagłówkowego: nagłówek drugiego stopnia o treści „Poznaj smoki!”.
Drugiego stopnia to <h2> - nie <h1>, choć na pierwszym nagłówku strony wydaje się naturalniejszy. Egzaminator sprawdza dokładnie ten znacznik, który wskazał arkusz. Wykrzyknik należy do treści.
Arkusz: Zawartość bloku nawigacyjnego to trzy bloki: blok 1 z treścią „Baza”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
W <nav> dajemy <div> z tekstem „Baza”. Dostaje id="block1" - po tym identyfikatorze złapie go JavaScript i osobny styl (tylko blok 1 ma inne tło) - oraz klasę block, wspólną dla trzech bloków, żeby nie powtarzać stylów trzy razy.
Nazwy identyfikatorów, klas, zmiennych i funkcji piszemy w tym rozwiązaniu po angielsku - arkusz dopuszcza polski lub angielski, ale wymaga konsekwencji i znaczących nazw. Wyjątkiem są nazwy narzucone przez arkusz (smoki.php, styl.css, kolumny bazy).
Wywołanie funkcji po kliknięciu dopiszemy, gdy będzie gotowy skrypt. Teraz budujemy samą strukturę.
Arkusz: Blok 2 z treścią „Opisy”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
Tak samo jak blok 1: id="block2" i klasa block. Identyfikatory numerujemy konsekwentnie (block1, block2, block3), bo skrypt będzie je składał z liczby.
Arkusz: Zawartość bloku głównego to trzy sekcje (w jednym momencie jest widoczna tylko jedna sekcja). Sekcja 1: nagłówek trzeciego stopnia o treści „Baza Smoków”.
W <main> dajemy <section id="section1"> z nagłówkiem <h3> (trzeciego stopnia). Identyfikator jest potrzebny, bo JavaScript będzie przełączał widoczność sekcji. „Widoczna tylko jedna” zrobią CSS (ukrycie sekcji 2 i 3 na starcie) i JS (przełączanie) - HTML zawiera wszystkie trzy.
Arkusz: Formularz wysyłający dane do tego samego pliku metodą bezpieczną, z elementami: lista rozwijana, przycisk.
„Metoda bezpieczna” to POST - dane nie pojawiają się w adresie strony, jak przy GET. „Do tego samego pliku” to brak atrybutu action (przeglądarka wysyła wtedy formularz na adres bieżącej strony) albo action="smoki.php" - klucz przyjmuje oba warianty.
Typowe błędy
method="get" (albo brak method, bo GET jest domyślny) wyśle kraj w adresie - to nie jest metoda bezpieczna i skrypt czytający $_POST nic nie dostanie.
Arkusz: Lista rozwijana wypełniona przez skrypt 1.
<select> z atrybutem name="country" - pod tą nazwą wybrana wartość trafi do PHP jako $_POST['country']. Opcje <option> wstawi skrypt 1 na podstawie zapytania 2, więc lista na razie jest pusta i w podglądzie wygląda na wąską.
Typowe błędy
Bez atrybutu name przeglądarka w ogóle nie wyśle wartości listy - formularz dojdzie pusty i skrypt 2 nie będzie miał po czym filtrować.
Arkusz: Przycisk „Szukaj”, wysyłający dane z formularza do skryptu 2.
<button type="submit"> wewnątrz formularza wysyła go po kliknięciu. Typ submit jest dla <button> w formularzu domyślny, ale wpisany wprost nie zostawia wątpliwości. Klucz przyjmuje też <input type="submit" value="Szukaj">.
Arkusz: Tabela o trzech kolumnach. Pierwszy wiersz jest wierszem z komórkami nagłówkowymi: „Nazwa”, „Długość”, „Szerokość”. Kolejne wiersze są wypełnione przez skrypt 2.
<table> z jednym wierszem <tr>, w którym są komórki nagłówkowe<th> - nie <td>. To osobne kryterium (R.2.9) i częsta strata punktu. Kolejne wiersze <tr> z komórkami <td> dopisze skrypt 2, więc w HTML jest tylko nagłówek.
Arkusz: Lista definicji wypełniona danymi, które należy skopiować z pliku opis.txt. Nazwa smoka jest terminem, a pozostałe dane - opisem definicji, zgodnie z ilustracją 5.
Lista definicji to <dl>, termin <dt>, opis <dd> - trzy pary, jedna pod drugą. Klucz sprawdza terminy w tej kolejności: Smok czerwony, Smok zielony, Smok niebieski. Opisy kopiujemy z opis.txt (Ctrl+C / Ctrl+V), nie przepisujemy - literówki w kopiowanym tekście to zbędne ryzyko.
Typowe błędy
Lista wypunktowana <ul> z pogrubioną nazwą wygląda podobnie, ale kryterium R.2.7 wymaga znaczników <dl>, <dt>, <dd>.
smoki.phpPHPzmienione: 8 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 26: Sekcja 3 z nagłówkiem
Kryteria: R.2.4, R.2.5ok. 1 min
Arkusz: Sekcja 3: nagłówek trzeciego stopnia o treści „Galeria”.
<section id="section3"> z <h3>. W bloku głównym są teraz trzy sekcje - komplet z kryterium R.2.4.
smoki.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 27: Obraz smok1.jpg
Kryteria: R.2.6ok. 1 min
Arkusz: Obraz smok1.jpg z tekstem alternatywnym „Smok czerwony”.
<img src="smok1.jpg" alt="Smok czerwony"> - to plik przeskalowany wcześniej do 300 px wysokości, leżący w tym samym folderze co smoki.php. Tekst alternatywny przepisujemy dokładnie: czyta go czytnik ekranu i pokazuje przeglądarka, gdy obraz się nie wczyta.
Typowe błędy
src="C:\Users\...\smok1.jpg" działa tylko na komputerze autora - na płycie egzaminatora obraz się nie wczyta. Ścieżka ma być względna.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 28: Obraz smok2.jpg
Kryteria: R.2.6ok. 1 min
Arkusz: Obraz smok2.jpg z tekstem alternatywnym „Smok wielki”.
Drugi obraz, ten sam wzorzec: src z nazwą pliku z archiwum, alt dokładnie z treści zadania.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 29: Obraz smok3.jpg
Kryteria: R.2.6ok. 1 min
Arkusz: Obraz smok3.jpg z tekstem alternatywnym „Skrzydlaty łaciaty”.
Trzeci obraz. W alt są polskie znaki - działają dzięki <meta charset="UTF-8"> z początku pliku.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 30: Stopka z numerem zdającego
Kryteria: R.2.5ok. 1 min
Arkusz: Zawartość stopki: paragraf o treści „Stronę opracował: ”, dalej wstawiony numer zdającego.
Paragraf <p> w <footer>. W tym rozwiązaniu po dwukropku stoi nazwisko autora - na egzaminie wpisujesz w to miejsce swój numer zdającego (PESEL), bo tego sprawdza klucz. Struktura HTML strony jest kompletna - dalej style.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 31: Plik styl.css: domyślne wyrównanie i krój
Kryteria: R.4.1ok. 2 min
Arkusz: Domyślnie dla wszystkich selektorów: wyrównanie tekstu do środka, krój czcionki Georgia.
Tworzymy plik styl.css obok smoki.php. „Dla wszystkich selektorów” to selektor uniwersalny * - reguła obejmuje każdy element strony. text-align: center wyśrodkowuje tekst, font-family: Georgia ustawia krój. W podglądzie od razu widać wyśrodkowanie i szeryfową czcionkę - to znak, że <link> z HTML zadziałał.
Typowe błędy
body { ... } też dziedziczy na całą stronę, ale klucz R.4.1 wymienia selektor * wprost.
styl.cssCSSnowy plik
* {text-align: center;font-family: Georgia;}
Podgląd strony po tym kroku (smoki.php)
Krok 32: Nagłówek i stopka: tło, kolor tekstu, margines wewnętrzny
Kryteria: R.4.2, R.4.3, R.4.6ok. 2 min
Arkusz: Wspólne dla bloku nagłówkowego i stopki: kolor tła Tomato, kolor czcionki MistyRose, marginesy wewnętrzne 10 px.
Wspólne cechy dwóch elementów piszemy raz - selektory rozdzielone przecinkiem header, footer. Kolory nazwane (Tomato, MistyRose) przepisujemy z arkusza. Margines wewnętrzny to padding; zewnętrzny byłby margin - arkusz rozróżnia te dwa słowa i klucz też.
Typowe błędy
margin: 10px zamiast padding: 10px - odstęp będzie na zewnątrz pomarańczowego pola, a nie w nim. Kryterium R.4.6 mówi o marginesach wewnętrznych.
Selektor nav (znacznik semantyczny z HTML). Szerokość w procentach liczy się względem rodzica, czyli <body> - nawigacja zajmie jedną piątą szerokości okna. Blok główny dostanie pozostałe 80%, a obok siebie ustawimy je za chwilę.
Arkusz: Dla bloku 1, bloku 2, bloku 3: kolor tła #FFAEA5, wysokość 170 px, rozmiar czcionki 200%.
Trzy bloki mają w HTML wspólną klasę block, więc jedna reguła .block (kropka = selektor klasy) załatwia wszystkie. Trzy razy 170px daje 510px - dokładnie tyle, ile za chwilę dostanie blok główny, dzięki czemu kolumny będą równej wysokości jak na ilustracji 2. font-size: 200% to dwa razy większy tekst niż odziedziczony.
Typowe błędy
#block1, #block2, #block3 { ... } też jest poprawne, ale przy klasie mniej pisania i mniej miejsc na literówkę. Kolor szesnastkowy zaczyna się od #.
Selektor identyfikatora #block1 (krzyżyk = id). Ta reguła stoi po regule .block i jest bardziej szczegółowa (id wygrywa z klasą), więc nadpisuje tło tylko dla bloku 1. Na starcie „Baza” jest jasna, jak aktywna zakładka - to stan początkowy, do którego JavaScript będzie wracał.
Arkusz: Dla bloku głównego: kolor tła MistyRose, szerokość 80%, wysokość 510 px, paski przewijania widoczne tylko w przypadku przepełnienia zawartością.
Selektor main. „Paski przewijania tylko przy przepełnieniu” to overflow: auto - scroll pokazywałby je zawsze, hidden obcinałby treść bez możliwości przewinięcia. Wysokość 510px równa się sumie trzech bloków nawigacji.
Typowe błędy
overflow: scroll daje paski zawsze, także przy pustej sekcji - klucz R.4.5 wymaga auto.
Krok 37: Układ bloków: nawigacja obok bloku głównego
Kryteria: R.3.1ok. 3 min
Arkusz: 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.
Domyślnie każdy blok zajmuje całą szerokość i staje pod poprzednim. float: left dla nav i main ustawia je obok siebie (20% + 80% = 100%, więc mieszczą się w jednej linii). Stopka dostaje clear: both, żeby wróciła pod obie kolumny, a nie wcisnęła się obok nich. To jedno z dopuszczalnych rozwiązań - klucz przyjmuje też display: flex albo grid.
Reguły float dopisujemy do istniejących selektorów nav i main, a footer dostaje własną regułę (wspólna z header zostaje bez zmian).
Typowe błędy
Bez clear: both stopka może wjechać pod pływające kolumny albo obok nich - układ przestaje zgadzać się z ilustracją 3 i R.3.1 przepada.
Arkusz: Jedynie dla sekcji 2 i sekcji 3: sekcje są usunięte z DOM (patrz tabela 3).
Tabela 3 arkusza: display: none - element jest całkowicie usunięty z układu strony (nie zajmuje miejsca, w odróżnieniu od visibility: hidden). Po tym kroku widać tylko sekcję 1, jak na ilustracji 2. Pozostałe sekcje pokaże JavaScript, zmieniając display na block.
Arkusz: Dla selektora tabeli: marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość 60%, obramowanie linią kreskowaną o szerokości 1 px i kolorze Indigo.
Arkusz mówi wprost: selektor znacznikatable, nie klasa ani id (uwaga pod listą cech CSS). margin: auto przy ustalonej szerokości wyśrodkowuje tabelę w bloku głównym. Skrót border: 1px dashed Indigo łączy grubość, styl (kreskowana) i kolor.
Typowe błędy
Styl tabeli przez klasę (.tabela) nie spełnia wymagania, nawet gdy wygląda identycznie - arkusz uzasadnia to „projektem późniejszej rozbudowy witryny”.
Krok 40: Lista rozwijana i przycisk: margines zewnętrzny
Kryteria: R.4.6ok. 1 min
Arkusz: Dla listy rozwijanej i przycisku: marginesy zewnętrzne 20 px.
Selektory select, button z margin: 20px - odstęp na zewnątrz elementów, więc lista i przycisk odsuwają się od siebie i od nagłówka. Tu arkusz mówi o marginesach zewnętrznych, więc margin, nie padding.
Krok 41: Termin listy definicji: pogrubienie i kursywa
Kryteria: R.4.7ok. 1 min
Arkusz: Dla selektora terminu w liście definicji (dt): czcionka pogrubiona i pochylona.
Znowu selektor znacznika - dt. Pogrubienie to font-weight: bold, pochylenie font-style: italic. Efekt widać po kliknięciu „Opisy”, gdy zadziała skrypt; na razie sekcja 2 jest ukryta.
Arkusz: W momencie gdy kursor znajdzie się na terminie w liście definicji jego rozmiar czcionki zmienia się na 180%.
Pseudoklasa :hover opisuje stan „kursor nad elementem”. dt:hover { font-size: 180% } powiększa nazwę smoka, gdy na nią najedziesz - dokładnie to pokazuje ilustracja 5 („Smok zielony” większy od pozostałych). Arkusz stylów jest kompletny.
Krok 43: Plik script.js i funkcja wywoływana kliknięciem
Kryteria: R.3.5, R.5.6, R.5.10ok. 3 min
Arkusz: Skrypt jest napisany w języku JavaScript. Składa się z jednej lub trzech funkcji wywoływanych po kliknięciu na jednym z bloków w bloku nawigacyjnym.
Tworzymy plik script.js i podpinamy go w smoki.php na końcu <body> przez <script src="script.js"></script> - na końcu, żeby wszystkie bloki i sekcje już istniały, gdy skrypt zacznie działać.
Piszemy jedną funkcję showSection(number) - angielska nazwa mówi, co robi (wymaganie o znaczącym nazewnictwie w języku polskim lub angielskim), a parametr number powie jej, który blok kliknięto. Blok 1 dostaje onclick="showSection(1)" - to spełnia wymaganie z sekcji HTML „gdy zostanie kliknięty, jest wywoływana funkcja”. Ciało funkcji wypełnimy w kolejnych krokach.
Typowe błędy
Skrypt podpięty w <head> wykona się, zanim powstaną elementy block1…section3 - getElementById zwróci null i kliknięcie skończy się błędem w konsoli.
script.jsJavaScriptnowy plik
function showSection(number) {}
smoki.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 44: Kliknięcie: wszystkie bloki dostają tło #FFAEA5
Kryteria: R.5.6ok. 3 min
Arkusz: Gdy zostanie kliknięty Blok 1: kolor tła bloku 1 zmienia się na MistyRose, pozostałe na #FFAEA5.
Zaczynamy od „pozostałych”: najprościej jest najpierw ustawić ciemniejsze tło wszystkim trzem blokom, a dopiero potem rozjaśnić kliknięty. Wtedy nie trzeba pamiętać, który blok był aktywny wcześniej.
Co robi ta pętla, linia po linii:
for (let i = 1; i <= 3; i++) - zmienna i przyjmuje kolejno 1, 2, 3.
'block' + i skleja napis z liczbą: block1, block2, block3 - dokładnie identyfikatory z HTML.
document.getElementById(...) (tabela 2 arkusza) znajduje element o tym identyfikatorze.
.style.backgroundColor = '#FFAEA5' zmienia jego styl. Nazwa CSS background-color w JavaScript traci myślnik i dostaje wielką literę: backgroundColor.
Kliknięcie „Baza” w podglądzie przyciemni na razie także blok 1 - poprawimy to w następnej linii.
Typowe błędy
style.background-color to błąd składni JavaScript (minus jest odejmowaniem). Nazwy z myślnikiem piszemy w notacji wielbłądziej: backgroundColor.
script.jsJavaScriptzmienione: 3 linie
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5'; }}
Arkusz: Kolor tła bloku 1 zmienia się na MistyRose.
Jedna linia po pętli: 'block' + number to identyfikator klikniętego bloku (dla showSection(1) - block1), a jemu ustawiamy MistyRose. Kolejność ma znaczenie - gdyby ta linia stała przed pętlą, pętla zaraz by ją nadpisała i wszystkie bloki byłyby ciemne.
W podglądzie kliknij „Baza” - blok zostaje jasny, tak jak na starcie. Kolory działają; teraz sekcje.
script.jsJavaScriptzmienione: 1 linia
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';}
Podgląd strony po tym kroku (smoki.php)
Krok 46: Kliknięcie: wszystkie sekcje ukryte
Kryteria: R.5.6ok. 2 min
Arkusz: Sposób wyświetlania Sekcji 1 zmienia się na blokowy, pozostałe są usunięte.
Ten sam schemat co przy kolorach, więc dopisujemy drugą linię do tej samej pętli: 'section' + i daje section1…section3, a style.display = 'none' usuwa sekcję z układu strony (wartość „usunięte” z tabeli 3 arkusza). Po tej linii kliknięcie chowa wszystkie trzy sekcje - blok główny robi się pusty. Pokażemy właściwą w następnym kroku.
script.jsJavaScriptzmienione: 1 linia
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5';document.getElementById('section' + i).style.display = 'none'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';}
Arkusz: Sposób wyświetlania Sekcji 1 zmienia się na blokowy.
Po pętli, obok linii z MistyRose, dopisujemy 'section' + number z style.display = 'block' - sekcja o numerze klikniętego bloku wraca jako element blokowy. Numeracja section1…section3 odpowiada block1…block3, więc jeden parametr number wystarcza na wszystko.
Podgląd działa - kliknij w nim „Baza”: nic się nie zmienia, bo to stan początkowy. Pozostałe bloki podłączymy w dwóch następnych krokach.
script.jsJavaScriptzmienione: 1 linia
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5';document.getElementById('section' + i).style.display = 'none'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';document.getElementById('section' + number).style.display = 'block';}
Podgląd strony po tym kroku (smoki.php)
Krok 48: Blok 2 wywołuje funkcję
Kryteria: R.5.7, R.5.8ok. 1 min
Arkusz: Gdy zostanie kliknięty Blok 2: kolor tła bloku 2 zmienia się na MistyRose, pozostałe na #FFAEA5. Sposób wyświetlania Sekcji 2 zmienia się na blokowy, pozostałe są usunięte.
Funkcja jest już gotowa na każdy numer - wystarczy w HTML dopisać blokowi 2 onclick="showSection(2)". Kliknij „Opisy” w podglądzie: blok 2 jaśnieje, blok 1 ciemnieje, w bloku głównym pojawia się lista definicji ze stylami dt (ilustracja 5).
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 49: Blok 3 wywołuje funkcję
Kryteria: R.3.5, R.5.7, R.5.8, R.5.9ok. 1 min
Arkusz: Gdy zostanie kliknięty Blok 3: kolor tła bloku 3 zmienia się na MistyRose, pozostałe na #FFAEA5. Sposób wyświetlania Sekcji 3 zmienia się na blokowy, pozostałe są usunięte.
onclick="showSection(3)" dla bloku 3. Sprawdź w podglądzie pełną sekwencję z klucza (R.5.9): kliknij „Galeria”, potem „Opisy”, a na koniec „Baza” - strona ma wrócić do stanu początkowego: jasny blok 1 i widoczna sekcja 1. Nasza funkcja to gwarantuje, bo za każdym razem najpierw „zeruje” wszystkie bloki i sekcje.
Typowe błędy
Trzy osobne funkcje, z których każda tylko pokazuje swoją sekcję i nie chowa pozostałych, po serii kliknięć zostawią widoczne wszystkie sekcje naraz - R.5.8 i R.5.9 przepadają.
smoki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 50: Połączenie z bazą danych
Kryteria: R.5.1, R.5.10ok. 3 min
Arkusz: Skrypty 1 i 2 są napisane w języku PHP. Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie smoki.
Kod PHP piszemy między <?php a ?> - serwer wykonuje go, zanim strona trafi do przeglądarki. Połączenie otwieramy raz, na samym początku pliku, i trzymamy w zmiennej $connection (znacząca, angielska nazwa - jak w całym rozwiązaniu), z której skorzystają oba skrypty. mysqli_connect z tabeli 1 arkusza przyjmuje kolejno: serwer, użytkownika, hasło (puste) i nazwę bazy.
Od tego kroku podgląd to wynik działania strony po stronie serwera (PHP nie wykonuje się w przeglądarce) - na razie wygląda tak samo jak wcześniej, bo skrypt niczego jeszcze nie wypisuje.
Typowe błędy
Kolejność argumentów ma znaczenie: mysqli_connect('localhost', 'root', 'smoki') podaje „smoki” jako HASŁO. Nazwa bazy jest czwarta. Plik sprawdzaj przez http://localhost/…, nie otwierając go z dysku - inaczej PHP się nie wykona.
smoki.phpPHPzmienione: 3 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 51: Skrypt 1: zapytanie 2 do bazy
Kryteria: R.5.2ok. 2 min
Arkusz: Skrypt 1: wysyła do bazy danych zapytanie 2.
Skrypt 1 piszemy wewnątrz<select>, bo tam mają trafić opcje. mysqli_query($connection, ...) wysyła zapytanie i zwraca wynik, który zapisujemy w zmiennej $countries. Treść zapytania to dokładnie zapytanie 2 z pliku kwerendy.txt - kraje bez powtórzeń, posortowane.
smoki.phpPHPzmienione: 3 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Arkusz: Wszystkie zwrócone zapytaniem wiersze są zapisywane jako opcje listy rozwijanej, zgodnie z ilustracją 4.
„Wszystkie wiersze” to pętla. mysqli_fetch_row($countries) (tabela 1 arkusza) oddaje kolejny wiersz wyniku jako tablicę numerowaną od zera, a gdy wierszy zabraknie - false. Zapis while ($row = mysqli_fetch_row($countries)) robi dwie rzeczy naraz: przypisuje wiersz do $row i sprawdza, czy coś przyszło. Pętla wykona się więc dokładnie tyle razy, ile jest krajów - pięć - i sama się zakończy.
Ciało pętli jest jeszcze puste, więc w podglądzie lista nadal nie ma opcji.
Typowe błędy
Pojedyncze = w warunku while jest tu celowe (przypisanie); == porównałoby zmienną z wynikiem i pętla nie zadziałałaby poprawnie.
smoki.phpPHPzmienione: 2 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Arkusz: Wszystkie zwrócone zapytaniem wiersze są zapisywane jako opcje listy rozwijanej, zgodnie z ilustracją 4.
W ciele pętli echo wypisuje gotowy znacznik HTML <option> do strony. Zapytanie 2 ma jedną kolumnę, więc kraj siedzi w $row[0]. Napis jest w cudzysłowie, bo tylko wtedy PHP podstawia wartość zmiennej. Pięć obiegów pętli = pięć opcji: w podglądzie lista rozwijana ma już Bułgarię, Chiny, Francję, Japonię i Polskę - jak na ilustracji 4.
Typowe błędy
echo '<option>$row[0]</option>' w apostrofach wypisze dosłownie „$row[0]” pięć razy - PHP nie podstawia zmiennych w apostrofach.
smoki.phpPHPzmienione: 1 linia
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 54: Skrypt 2: tylko po wysłaniu formularza
Kryteria: R.5.3ok. 2 min
Arkusz: Skrypt 2, wykonywany tylko, gdy formularz wysłał dane.
Skrypt 2 piszemy w <table>, pod wierszem nagłówkowym. Warunek isset($_POST['country']) (funkcja z tabeli 1) jest prawdziwy tylko wtedy, gdy formularz został wysłany metodą POST i zawierał pole country - przy pierwszym wejściu na stronę tablica $_POST jest pusta i cały blok if jest pomijany. Dlatego tabela na starcie ma tylko nagłówek.
Typowe błędy
Skrypt czyta z $_POST, bo formularz ma method="post". Przy $_GET warunek nigdy nie będzie prawdziwy - nazwa tablicy musi odpowiadać metodzie formularza.
smoki.phpPHPzmienione: 4 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Arkusz: Wysyła do bazy danych zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza.
Wewnątrz if bierzemy wartość wysłaną z listy rozwijanej: $_POST['country'] - klucz country to dokładnie atrybut name z <select>. Zapisujemy ją do zmiennej $country o znaczącej nazwie. Podgląd bez zmian: skrypt na razie tylko czyta.
smoki.phpPHPzmienione: 1 linia
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Krok 56: Skrypt 2: zapytanie 1 z krajem z formularza
Kryteria: R.5.2ok. 3 min
Arkusz: Wysyła do bazy danych zmodyfikowane zapytanie 1, tak że w warunku umieszczony jest kraj pochodzenia wysłany z formularza.
Bierzemy zapytanie 1 z kwerendy.txt i w warunku WHERE pochodzenie = ... zamiast „Polska” wstawiamy $country. Cały napis zapytania jest w cudzysłowie (PHP podstawi zmienną), a wartość w SQL musi być w cudzysłowie albo apostrofach - stąd '$country' w apostrofach, żeby nie kolidowały z zewnętrznym cudzysłowem. Wynik zapytania trafia do $dragons.
Typowe błędy
Wstawianie wartości z formularza prosto do zapytania wystarcza na egzaminie, ale w prawdziwej aplikacji to podatność SQL injection - tam używa się zapytań przygotowanych (mysqli_prepare).
smoki.phpPHPzmienione: 1 linia
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];$dragons = mysqli_query($connection, "SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = '$country';");}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Arkusz: Każdy zwrócony zapytaniem wiersz jest zapisywany jako kolejny wiersz tabeli, zgodnie z ilustracją 4.
Ta sama konstrukcja co w skrypcie 1: while ($row = mysqli_fetch_row($dragons)) pobiera kolejne smoki wybranego kraju, aż wynik się skończy. Tym razem każdy wiersz ma trzy pola - w kolejności z zapytania: $row[0] nazwa, $row[1] długość, $row[2] szerokość.
smoki.phpPHPzmienione: 2 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];$dragons = mysqli_query($connection, "SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = '$country';");while ($row = mysqli_fetch_row($dragons)) { }}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Arkusz: Każdy zwrócony zapytaniem wiersz jest zapisywany jako kolejny wiersz tabeli, zgodnie z ilustracją 4.
echo w pętli dokłada do tabeli jeden <tr> z trzema <td> - nazwa, długość i szerokość trafiają pod nagłówki „Nazwa”, „Długość”, „Szerokość”. Ponieważ kod stoi wewnątrz <table>, wypisane wiersze lądują dokładnie pod wierszem nagłówkowym.
Podgląd pokazuje stan po wybraniu Francji i kliknięciu „Szukaj” (ilustracja 4): dziesięć smoków. Lista rozwijana po wysłaniu wraca do pierwszej opcji - arkusz nie wymaga zapamiętania wyboru.
Typowe błędy
Komórki w innej kolejności niż nagłówki (np. długość pod „Nazwa”) to strata R.5.5 - klucz sprawdza, że komórki są „wypełnione zgodnie z nagłówkami”.
smoki.phpPHPzmienione: 1 linia
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];$dragons = mysqli_query($connection, "SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = '$country';");while ($row = mysqli_fetch_row($dragons)) {echo"<tr><td>$row[0]</td><td>$row[1]</td><td>$row[2]</td></tr>"; }}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 59: Zamknięcie połączenia z bazą
Kryteria: R.5.1ok. 1 min
Arkusz: Na końcu działania skrypt zamyka połączenie z serwerem.
mysqli_close($connection) na końcu pliku, gdy oba skrypty już skorzystały z połączenia. Klucz sprawdza, że zamknięcie jest ostatnią operacją na bazie - dlatego nie zamykamy po skrypcie 1, bo skrypt 2 potrzebowałby połączenia ponownie. Strona smoki.php jest gotowa.
Typowe błędy
mysqli_close tuż za listą rozwijaną (po skrypcie 1) sprawia, że zapytanie skryptu 2 idzie po zamkniętym połączeniu - tabela zostaje pusta i przepadają R.5.1 oraz R.5.5.
smoki.phpPHPzmienione: 3 linie
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav> <divid="block1"class="block"onclick="showSection(1)">Baza</div> <divid="block2"class="block"onclick="showSection(2)">Opisy</div> <divid="block3"class="block"onclick="showSection(3)">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];$dragons = mysqli_query($connection, "SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = '$country';");while ($row = mysqli_fetch_row($dragons)) {echo"<tr><td>$row[0]</td><td>$row[1]</td><td>$row[2]</td></tr>"; }}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script><?phpmysqli_close($connection);?></body></html>
Arkusz: Składa się z jednej lub trzech funkcji wywoływanych po kliknięciu na jednym z bloków w bloku nawigacyjnym.
Rozwiązanie z onclick jest poprawne i na egzaminie wystarcza. Drugi, częściej spotykany w praktyce sposób to nasłuchiwacze zdarzeń rejestrowane w JavaScript - HTML opisuje wtedy tylko strukturę, a całe zachowanie siedzi w skrypcie. Pokazujemy go jako wariant, nie zmianę.
Stare linie bloków zostają w komentarzu HTML <!-- … --> (przeglądarka je pomija), a pod nimi te same bloki bez atrybutu onclick. Po tym kroku kliknięcia przestają działać - podłączymy je z powrotem w skrypcie.
Typowe błędy
Komentarz HTML nie może zawierać -- w środku ani być zagnieżdżony - jeden <!-- i jeden --> na całą grupę linii.
smoki.phpPHPzmienione: 5 linii
<?php$connection = mysqli_connect('localhost', 'root', '', 'smoki');?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Smoki</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Poznaj smoki!</h2> </header> <nav><!-- wersja z atrybutem onclick: <div id="block1" class="block" onclick="showSection(1)">Baza</div> <div id="block2" class="block" onclick="showSection(2)">Opisy</div> <div id="block3" class="block" onclick="showSection(3)">Galeria</div> --> <divid="block1"class="block">Baza</div> <divid="block2"class="block">Opisy</div> <divid="block3"class="block">Galeria</div> </nav> <main> <sectionid="section1"> <h3>Baza Smoków</h3> <formmethod="post"> <selectname="country"><?php$countries = mysqli_query($connection, 'SELECT DISTINCT pochodzenie FROM smok ORDER BY pochodzenie;');while ($row = mysqli_fetch_row($countries)) {echo"<option>$row[0]</option>";}?> </select> <buttontype="submit">Szukaj</button> </form> <table> <tr><th>Nazwa</th><th>Długość</th><th>Szerokość</th></tr><?phpif (isset($_POST['country'])) {$country = $_POST['country'];$dragons = mysqli_query($connection, "SELECT nazwa, dlugosc, szerokosc FROM smok WHERE pochodzenie = '$country';");while ($row = mysqli_fetch_row($dragons)) {echo"<tr><td>$row[0]</td><td>$row[1]</td><td>$row[2]</td></tr>"; }}?> </table> </section> <sectionid="section2"> <h3>Opisy smoków</h3> <dl> <dt>Smok czerwony</dt> <dd>Pochodzi z Chin. Ma 1000 lat. Żywi się mniejszymi zwierzętami. Posiada łuski cenne na rynkach wschodnich do wyrabiania lekarstw. Jest dziki i groźny.</dd> <dt>Smok zielony</dt> <dd>Pochodzi z Bułgarii. Ma 10000 lat. Żywi się mniejszymi zwierzętami, ale tylko w kolorze zielonym. Jest kosmaty. Z sierści zgubionej przez niego, tka się najdroższe materiały.</dd> <dt>Smok niebieski</dt> <dd>Pochodzi z Francji. Ma 100 lat. Żywi się owocami morza. Jest natchnieniem dla najlepszych malarzy. Często im pozuje. Smok ten jest przyjacielem ludzi i czasami im pomaga. Jest jednak próżny i nie lubi się przepracowywać.</dd> </dl> </section> <sectionid="section3"> <h3>Galeria</h3> <imgsrc="smok1.jpg"alt="Smok czerwony"> <imgsrc="smok2.jpg"alt="Smok wielki"> <imgsrc="smok3.jpg"alt="Skrzydlaty łaciaty"> </section> </main> <footer> <p>Stronę opracował: Bartosz Bryniarski</p> </footer> <scriptsrc="script.js"></script><?phpmysqli_close($connection);?></body></html>
Podgląd strony po tym kroku (smoki.php)
Krok 61: Nasłuchiwacz kliknięcia dla bloku 1
Kryteria: R.3.5, R.5.6ok. 3 min
Arkusz: Blok 1 z treścią „Baza”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
addEventListener('click', ...) mówi przeglądarce: „gdy ten element zostanie kliknięty, uruchom podaną funkcję”. Pierwszy argument to nazwa zdarzenia (click, bez „on”), drugi - funkcja do wykonania. Podajemy funkcję anonimowąfunction () { showSection(1); }, bo showSection potrzebuje argumentu, a nasłuchiwacz wywołuje funkcję bez argumentów.
Kod stoi pozashowSection, na końcu pliku - wykona się raz, przy wczytaniu skryptu, a skrypt jest podpięty na końcu <body>, więc block1 już istnieje. W podglądzie działa znów tylko „Baza”.
Typowe błędy
addEventListener('click', showSection(1))wywołuje funkcję od razu przy rejestracji i jako nasłuchiwacz przekazuje jej wynik (undefined) - kliknięcie nic nie zrobi. Przekazujemy funkcję, nie jej wywołanie.
script.jsJavaScriptzmienione: 4 linie
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5';document.getElementById('section' + i).style.display = 'none'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';document.getElementById('section' + number).style.display = 'block';}document.getElementById('block1').addEventListener('click', function () { showSection(1);});
Podgląd strony po tym kroku (smoki.php)
Krok 62: Nasłuchiwacze dla bloków 2 i 3
Kryteria: R.3.5, R.5.7, R.5.8, R.5.9ok. 2 min
Arkusz: Blok 2 z treścią „Opisy”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript. Blok 3 z treścią „Galeria”, gdy zostanie kliknięty jest wywoływana funkcja JavaScript.
Dwa kolejne nasłuchiwacze, różnią się tylko identyfikatorem i numerem przekazywanym do showSection. Wszystkie trzy bloki znów reagują na kliknięcie - sprawdź w podglądzie sekwencję z klucza: „Galeria”, „Opisy”, „Baza”.
Trzy prawie identyczne fragmenty to sygnał, że da się to zapisać krócej - następny krok.
script.jsJavaScriptzmienione: 6 linii
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5';document.getElementById('section' + i).style.display = 'none'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';document.getElementById('section' + number).style.display = 'block';}document.getElementById('block1').addEventListener('click', function () { showSection(1);});document.getElementById('block2').addEventListener('click', function () { showSection(2);});document.getElementById('block3').addEventListener('click', function () { showSection(3);});
Podgląd strony po tym kroku (smoki.php)
Krok 63: Nasłuchiwacze w pętli
Kryteria: R.3.5, R.5.10ok. 3 min
Arkusz: Należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim.
Trzy nasłuchiwacze zostają w komentarzu (// na początku każdej linii - JavaScript je pomija), a zastępuje je pętla for po numerach 1-3: identyfikator składamy jak w showSection ('block' + i), a funkcja anonimowa przekazuje i dalej.
Ważny szczegół: let i tworzy osobną zmienną i dla każdego obiegu pętli, więc każdy nasłuchiwacz pamięta swój numer. Ze starszym var i wszystkie trzy funkcje widziałyby tę samą zmienną o końcowej wartości 4 i żaden blok nie działałby poprawnie.
Podgląd działa jak przy onclick - a HTML jest czystszy. Oba warianty spełniają klucz; wybierz ten, który pewniej napiszesz bez błędu.
Typowe błędy
var i zamiast let i w tej pętli to klasyczny błąd domknięć - każde kliknięcie wywoła showSection(4), czyli getElementById zwróci null i skrypt się wysypie.
script.jsJavaScriptzmienione: 16 linii
function showSection(number) {for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).style.backgroundColor = '#FFAEA5';document.getElementById('section' + i).style.display = 'none'; }document.getElementById('block' + number).style.backgroundColor = 'MistyRose';document.getElementById('section' + number).style.display = 'block';}// wersja z trzema osobnymi nasłuchiwaczami:// document.getElementById('block1').addEventListener('click', function () {// showSection(1);// });// document.getElementById('block2').addEventListener('click', function () {// showSection(2);// });// document.getElementById('block3').addEventListener('click', function () {// showSection(3);// });for (let i = 1; i <= 3; i++) {document.getElementById('block' + i).addEventListener('click', function () { showSection(i); });}
Podgląd strony po tym kroku (smoki.php)
Krok 64: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Arkusz: 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 wpisujemy nazwę przeglądarki, w której sprawdzaliśmy stronę przez http://localhost/…. Na egzaminie nazwa pliku dokładnie jak w arkuszu, z „ą” - w tym rozwiązaniu plik nazywa się przegladarka.txt tylko dlatego, że podgląd nie przyjmuje polskich znaków w nazwach plików. W folderze z numerem zdającego muszą być: import.jpg, kw1.png, kw2.png, kw3.png, kw4.png, kwerendy.txt, przeglądarka.txt, smok1.jpg, smok2.jpg, smok3.jpg, smoki.php, styl.css i script.js.
Nagrywamy płytę, sprawdzamy jej odczyt na stanowisku i opisujemy numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.