Przejdź do głównej treści
E.14-01-24.06-SGCzerwiec 2024 · 42 kroki · ok. 78 min · 36 kryteriów z klucza

Rozwiązanie krok po kroku: Atlas zwierząt z wyborem gromady (Wersja podstawowa)

Atlas zwierząt: baza baza zaimportowana z pliku baza2.sql, cztery zapytania (ryby z tabeli Zwierzeta, złączenie z tabelą Gromady, liczba ssaków i nowe konto użytkownika CREATE USER), strona index.php z banerem, formularzem wyboru gromady i trzema blokami głównymi, style w styl3.css oraz dwa skrypty PHP: pierwszy wypisuje zwierzęta gromady wybranej w polu numerycznym, drugi - wszystkie zwierzęta z nazwą gromady.

To arkusz E.14 z sesji czerwiec 2024 - kwalifikacji formuły 2012, którą zastąpiła INF.03. To samo zadanie wróciło w styczniu 2021 oraz w czerwcu 2023 i 2025 (każde wydanie ma w serwisie własny arkusz i własne rozwiązanie, bo różnią się brzmieniem arkusza albo klucza). 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 napisany najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzony na prawdziwym wstrzyknięciu SQL i zabezpieczony.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: semantyczne bloki z flex, zmienne CSS, etykieta <label> i PDO z zapytaniem przygotowanym - obie wersje są zgodne z kluczem.

Baza i zdjęcie pochodzą z oryginalnego archiwum CKE z sesji styczeń 2019, w której zadanie pojawiło się po raz pierwszy (załącznik do pobrania na stronie arkusza): otwiera się hasłem z arkusza i zawiera oba pliki, o których arkusz mówi. Arkusz nazywa archiwum materialy-03.7z (format 7-Zip), zawartość jest ta sama. Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2.

Jak liczą się punkty. Klucz ma 36 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 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.

  1. Etap 1: Baza danych

    Kroki 1-7 · po tym etapie masz 6 z 36 kryteriów (pkt)

    Krok 1: Folder zdającego i archiwum z materiałami

    ok. 2 min
    Polecenie z arkusza

    Na pulpicie znajdziesz archiwum 7-zip o nazwie materialy-03.7z zabezpieczone hasłem: G@tuneK Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Rozpakowane pliki umieść w tym folderze. Po skończonej pracy wyniki zapisz w tym folderze.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum materialy-03.7z rozpakowujesz programem 7-Zip do tego folderu, podając hasło G@tuneK (wielkość liter ma znaczenie, @ zamiast litery „a”). W środku są dwa pliki: baza2.sql (tabele do importu) i zwierzeta.jpg (zdjęcie do bloku lewego).

    Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, index.php i styl3.css. Na stronie arkusza w serwisie archiwum jest w wersji materialy3.zip z pierwszego wydania zadania - hasło i pliki są te same.

    Typowe błędy

    Pliki zapisane poza folderem zdającego (np. tylko w htdocs) nie trafią na płytę - a ocenia się wyłącznie to, co jest na płycie.

  2. Krok 2: XAMPP i pusta baza o nazwie baza

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz nową bazę danych o nazwie baza

    W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa baza (tak dosłownie brzmi nazwa bazy w arkuszu), porównywanie np. utf8mb4_polish_ci, Utwórz. Baza jest na razie pusta - tabele przyjdą z importu.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie baza - z nią połączy się skrypt PHP (R.5.2), a import do innej bazy nie daje R.1.1.

  3. Krok 3: Import pliku baza2.sql i zrzut import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych baza , czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 3 min
    Polecenie z arkusza

    Do bazy zaimportuj tabele z pliku baza2.sql z rozpakowanego archiwum Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL, w formacie PNG i nazwij import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel

    Zaznacz bazę baza w lewym panelu, karta Import, Wybierz plik → baza2.sql, Wykonaj. Plik tworzy 12 tabel - poza trzema z obrazu 1 (zwierzeta, gromady, odzywianie) są tam tabele z innych zadań; zostawiasz je, zadanie ich nie dotyczy.

    Struktura z obrazu 1: tabela zwierzeta ma pola id, Gromady_id, Odzywianie_id, gatunek, wystepowanie, czy_zagrozony i obraz. Pola Gromady_id i Odzywianie_id to klucze obce - wskazują wiersz w tabelach gromady (1 ryby, 2 płazy, 3 gady, 4 ptaki, 5 ssaki) i odzywianie. Tabela zwierzeta ma 9 wierszy.

    Po imporcie widać zielony komunikat o sukcesie i listę tabel w lewym panelu - to jest „element wskazujący na poprawny import”. Zrzut całego ekranu z paskiem zadań zapisujesz jako import.png.

    Typowe błędy

    Ten zrzut ma format PNG (zrzuty kwerend - JPG). Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: gatunki i występowanie ryb

    Kryteria: ,

    R.1.2 Zapisano plik kwerendy.txt z zapytaniami SQL

    R.1.3 Utworzono zapytanie 1 wybierające jedynie pola gatunek i wystepowanie z tabeli Zwierzeta jedynie dla ryb. W pliku z kwerendami istnieje zapis np.: SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = 1; lub wynik działania udokumentowano zrzutem, na którym widoczne są dokładnie 2 rekordy dla suma i jesiotra, wyświetlone jedynie kolumny gatunek, wystepowanie

    ok. 4 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie danych. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie JPG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające jedynie pola gatunek i wystepowanie z tabeli Zwierzeta jedynie dla ryb

    Karta SQL bazy baza. Zapytanie klauzula po klauzuli:

    • SELECT gatunek, wystepowanie - „jedynie pola” wyklucza SELECT *; nazwa wystepowanie bez polskiej litery, tak jak w tabeli,
    • FROM zwierzeta,
    • WHERE Gromady_id = 1 - ryby to gromada o identyfikatorze 1 (tabela gromady na obrazie 1). Warunek idzie po kluczu obcym, nie po nazwie.

    Wynik: 2 wiersze - Sum pospolity, Eurazja i Jesiotr zachodni, Europa, dokładnie jak w kluczu. Zapytanie kopiujesz do pliku kwerendy.txt (Notatnik, jedno zapytanie pod drugim), a cały ekran z wynikiem zapisujesz jako kw1.jpg (Print Screen, wklejenie do edytora grafiki, zapis jako JPEG).

    To zapytanie jest wzorem dla skryptu nr 1: w miejsce 1 trafi numer gromady wpisany w formularzu.

    Typowe błędy

    WHERE nazwa = 'ryby' nie zadziała - tabela zwierzeta nie ma kolumny z nazwą gromady, ma tylko jej numer. Zrzuty kwerend zapisuj w JPG, nie w PNG.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: zwierzęta z nazwą gromady (relacja)

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola id i gatunek z tabeli Zwierzeta oraz odpowiadające im pole nazwa z tabeli Gromady. W pliku z kwerendami istnieje zapis np.: SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id; możliwe również INNER JOIN (lub porównanie kluczy po WHERE)lub wynik działania udokumentowano zrzutem, na którym widoczne jest dokładnie 9 rekordów o id= 1 - 9, jedynie pola id, gatunek, nazwa

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola id i gatunek z tabeli Zwierzeta oraz odpowiadające im pole nazwa z tabeli Gromady. Należy posłużyć się relacją.

    • SELECT zwierzeta.id, gatunek, nazwa - kolumna id jest w obu tabelach, więc trzeba wskazać, z której: zwierzeta.id. gatunek i nazwa są jednoznaczne,
    • FROM zwierzeta JOIN gromady - złączenie dwóch tabel,
    • ON zwierzeta.Gromady_id = gromady.id - relacja: klucz obcy zwierzęcia równa się kluczowi głównemu gromady. Dla każdego zwierzęcia baza dobiera jego gromadę.

    Wynik: 9 wierszy o id 1-9, od Sum pospolity, ryby do Dingo australijski, ssaki. Klucz przyjmuje też INNER JOIN i zapis z przecinkiem i warunkiem w WHERE. Zrzut: kw2.jpg. To zapytanie wyśle skrypt nr 2.

    Typowe błędy

    Samo SELECT id, ... przy złączeniu kończy się błędem #1052 „Column id in field list is ambiguous” - kolumna o tej nazwie jest w obu tabelach. Bez warunku ON baza zwróci 45 wierszy (każde zwierzę z każdą gromadą).

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = 1;
    
    -- Zapytanie 2
    SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: liczba ssaków

    Kryteria:

    R.1.5 Utworzono zapytanie 3 zliczające liczbę rekordów w tabeli Zwierzeta jedynie dla ssaków. W pliku z kwerendami istnieje zapis np.: SELECT COUNT(*) FROM zwierzeta WHERE Gromady_id = 5; lub wynik działania udokumentowano zrzutem, na którym widoczny jest wynik działania kwerendy - wartość 4

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: zliczające liczbę rekordów w tabeli Zwierzeta jedynie dla ssaków

    COUNT(*) to funkcja agregująca - zamiast wierszy zwraca ich liczbę. WHERE Gromady_id = 5 ogranicza liczenie do ssaków (gromada 5). Wynik: jedna komórka z wartością 4 (wilk, hiena, sarna, dingo). Zrzut: kw3.jpg.

    Typowe błędy

    SUM(Gromady_id) doda numery gromad (5 + 5 + 5 + 5 = 20), a nie policzy rekordów. Do liczenia wierszy służy COUNT.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = 1;
    
    -- Zapytanie 2
    SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;
    
    -- Zapytanie 3
    SELECT COUNT(*) FROM zwierzeta WHERE Gromady_id = 5;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: użytkownik KatarzynaNowak

    Kryteria:

    R.1.6 Utworzono zapytanie 4 tworzące użytkownika KatarzynaNowak o haśle K4tNow. W pliku z kwerendami istnieje zapis np.: CREATE USER 'KatarzynaNowak'@'localhost' IDENTIFIED BY 'K4tNow'; (lub 'KatarzynaNowak'@'%') lub wynik działania udokumentowano zrzutem, na którym widoczna jest kwerenda i komunikat "MySQL zwrócił pusty wynik...". Nie uznajemy automatycznego utworzenia konta

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: tworzące użytkownika KatarzynaNowak o haśle K4tNow

    • CREATE USER - polecenie tworzące konto serwera bazy danych (nie wiersz w tabeli),
    • 'KatarzynaNowak'@'localhost' - nazwa użytkownika i host, z którego może się łączyć; klucz przyjmuje też '%' (dowolny host),
    • IDENTIFIED BY 'K4tNow' - hasło zapisane jawnie w zapytaniu; serwer sam zapisze je w postaci zaszyfrowanej.

    phpMyAdmin odpowiada „MySQL zwrócił pusty wynik (np. zero rekordów)” - CREATE USER niczego nie wybiera, więc to znak sukcesu. Zrzut z zapytaniem i komunikatem: kw4.jpg. Plik kwerendy.txt ma komplet czterech zapytań.

    Typowe błędy

    Konto założone w zakładce Konta użytkowników (bez zapytania SQL) nie jest uznawane - klucz wymaga kwerendy. Drugie wykonanie tego samego CREATE USER kończy się błędem #1396, bo konto już istnieje.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = 1;
    
    -- Zapytanie 2
    SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;
    
    -- Zapytanie 3
    SELECT COUNT(*) FROM zwierzeta WHERE Gromady_id = 5;
    
    -- Zapytanie 4
    CREATE USER 'KatarzynaNowak'@'localhost' IDENTIFIED BY 'K4tNow';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Strona HTML

    Kroki 8-22 · po tym etapie masz 19 z 36 kryteriów (pkt)

    Krok 8: Plik index.php

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie index.php

    Plik index.php w folderze zdającego, obok zwierzeta.jpg. Rozszerzenie .php, bo dojdą skrypty - na razie to czysty HTML. <!DOCTYPE html> oznacza HTML5, lang="pl" mówi przeglądarce i czytnikom ekranu, że treść jest po polsku. Do sprawdzania strony kopiujesz folder do C:\xampp\htdocs (albo tam pracujesz i na końcu kopiujesz pliki do folderu zdającego) i otwierasz http://localhost/…/index.php.

    index.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  9. Krok 9: Kodowanie polskich znaków

    Kryteria:

    R.2.1 Witrynę internetową zapisano w pliku index.php oraz zastosowano właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwsza rzecz w <head>. Bez tej linii „ATLAS ZWIERZĄT” i „Płazy” mogą wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8 (w Notepad++ menu Kodowanie). Nazwa pliku i kodowanie dają razem R.2.1.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  10. Krok 10: Tytuł strony

    Kryteria:

    R.2.2 Nadano tytuł strony: "Dane o zwierzętach”, jest on widoczny na karcie przeglądarki

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Dane o zwierzętach”

    <title> w <head> - napis na karcie przeglądarki. Tytuł („Dane o zwierzętach”) i nagłówek banera („ATLAS ZWIERZĄT”) to dwa różne teksty.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  11. Krok 11: Podpięcie arkusza stylów styl3.css

    Kryteria:

    R.3.6 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl3.css , formatowanie pochodzi jedynie od CSS

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie styl3.css prawidłowo połączony z kodem strony

    <link rel="stylesheet" href="styl3.css"> w <head>. Nazwa ma w sobie cyfrę: styl3.css. Plik stylów powstanie po HTML-u; od tej chwili całe formatowanie ma pochodzić z niego (R.3.6) - bez atrybutów style w znacznikach.

    Typowe błędy

    Zła nazwa w href to brak stylów. Klucz odbiera R.3.6 także wtedy, gdy choć jeden selektor nie trafia w blok (np. kropka zamiast # przy identyfikatorze).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  12. Krok 12: Bloki: baner, formularz, trzy główne i stopka

    Kryteria:

    R.2.3 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, blok formularza, trzy bloki główne: lewy, środkowy i prawy, blok stopki. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze baner, poniżej blok formularza, poniżej trzy bloki główne: lewy, środkowy i prawy, na dole blok stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2

    Sześć bloków w kolejności z obrazu 2: baner <header>, blok formularza i trzy bloki główne jako <section>, stopka <footer> - to są „znaczniki sekcji” HTML5 (R.2.3). Sekcje różnią się wyglądem, więc dostają identyfikatory: form-block, left, middle i right (nazwy po angielsku - arkusz ich nie narzuca). Na razie bloki są puste i stoją jeden pod drugim; trzy główne ustawi obok siebie CSS.

    Typowe błędy

    Bloki z samych <div> bez znaczników sekcji nie spełniają R.2.3 - klucz wymaga znaczników sekcji (header, section, footer...).

    index.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
        </header>
        <section id="form-block">
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  13. Krok 13: Baner: nagłówek pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia „ATLAS ZWIERZĄT”

    <h1> w <header>, tekst wielkimi literami jak w arkuszu. Klucz R.2.4 sprawdza go razem z dwoma nagłówkami <h2> - punkt przyjdzie po nagłówku bloku prawego.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  14. Krok 14: Blok formularza: nagłówek „Gromady:”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku formularza: Nagłówek drugiego stopnia o treści „Gromady:”

    Drugiego stopnia to <h2>. Dwukropek należy do treści nagłówka.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Lista numerowana gromad

    Kryteria:

    R.2.5 Umieszczono listę numerowaną o elementach: „Ryby”, „Płazy”, „Gady”, „Ptaki”, „Ssaki” oraz zastosowano znaczniki ol, li

    ok. 1 min
    Polecenie z arkusza

    Lista numerowana o elementach: „Ryby”, „Płazy”, „Gady”, „Ptaki”, „Ssaki”

    Lista numerowana to <ol> (ordered list), każdy element w <li> z zamknięciem </li> (R.2.5). Numery 1-5 dopisuje przeglądarka - w tekście ich nie wpisujesz. Kolejność gromad nie jest przypadkowa: numer na liście to ten sam numer, który ma gromada w tabeli gromady, więc uczeń wie, co wpisać w pole formularza.

    Typowe błędy

    <ul> to lista wypunktowana (kropki zamiast numerów) - klucz wymaga znaczników <ol> i <li>.

    index.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Formularz wysyłający dane metodą POST

    Kryteria:

    R.3.2 Dane z formularza przesyłane są za pomocą metody POST

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyłający dane metodą POST do tej samej strony z elementami

    <form method="post"> - bez atrybutu action formularz wysyła dane do tego samego adresu, z którego został wczytany, czyli do index.php („do tej samej strony”). Metoda POST przesyła dane w treści żądania, nie w adresie strony; w PHP odczytasz je z tablicy $_POST (R.3.2).

    Typowe błędy

    Bez method="post" formularz użyje metody GET - wartość trafi do adresu (index.php?gromada=4), a skrypt czytający $_POST niczego nie dostanie.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
            </form>
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Tekst „Wybierz gromadę: ” i pole numeryczne

    ok. 1 min
    Polecenie z arkusza

    Tekst „Wybierz gromadę: ” Pole edycyjne typu numerycznego

    Tekst wprost w formularzu, a za nim <input type="number"> - pole numeryczne: przyjmuje tylko liczby i ma strzałki do zmiany wartości, jak na obrazie 2. Atrybut name="gromada" to klucz, pod którym wartość trafi do PHP: $_POST['gromada'].

    Typowe błędy

    type="text" wygląda podobnie, ale nie jest polem typu number - klucz sprawdza typ pola (R.3.3).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
            </form>
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  18. Krok 18: Przycisk „Wyświetl”

    Kryteria: ,

    R.2.6 Umieszczono formularz z polem do wprowadzania danych oraz przyciskiem opisanym "Wyświetl"

    R.3.3 Pole jest typu number oraz przycisk jest typu submit

    ok. 1 min
    Polecenie z arkusza

    Przycisk wysyłający dane o nazwie „Wyświetl”

    <input type="submit" value="Wyświetl"> - przycisk, który wysyła formularz; napis na nim to wartość value. Formularz ma komplet: pole i przycisk (R.2.6), pole jest typu number, a przycisk typu submit - wysyła dane (R.3.3).

    Typowe błędy

    <input type="button"> wygląda tak samo, ale niczego nie wysyła - skrypt nr 1 nigdy nie dostanie wartości.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Blok lewy: zdjęcie z tekstem alternatywnym

    Kryteria:

    R.2.7 Umieszczono obraz zwierzeta.jpg oraz ma on tekst alternatywny "dzikie zwierzeta"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego – lewego: obraz zwierzeta.jpg z wypakowanego archiwum, z tekstem alternatywnym „dzikie zwierzęta”

    <img> z atrybutami src (nazwa pliku z folderu zdającego) i alt - tekst, który czytnik ekranu przeczyta zamiast zdjęcia i który pokaże się, gdy plik się nie wczyta (R.2.7). Zdjęcie z archiwum ma 400 × 300 px i trafia na stronę bez zmian - arkusz nie każe go przerabiać.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  20. Krok 20: Blok prawy: nagłówek „Wszystkie zwierzęta w bazie”

    Kryteria:

    R.2.4 Na stronie zapisano nagłówek h1: "ATLAS ZWIERZĄT" oraz nagłówek h2: "Gromady:" oraz nagłówek h2: „Wszystkie zwierzęta w bazie”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego – prawego: Nagłówek drugiego stopnia o treści „Wszystkie zwierzęta w bazie”

    Drugi <h2>. Strona ma już nagłówek <h1> w banerze, <h2> w bloku formularza i <h2> w bloku prawym (R.2.4). Pod tym nagłówkiem wypisze swój wynik skrypt nr 2; blok środkowy zostaje na razie pusty - wypełni go skrypt nr 1.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Krok 21: Stopka: odnośnik otwierany w nowej karcie

    Kryteria: ,

    R.3.4 Na stronie znajduje się odnośnik o treści "Poznaj inne strony o zwierzętach", jego kliknięcie inicjuje próbę otwarcia strony "atlas-zwierzat.pl" (poprawne z http://; https:// lub bez protokołu)

    R.3.5 Odnośnik jest otwierany w osobnym oknie / zakładce przeglądarki

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: Odnośnik o treści „Poznaj inne strony o zwierzętach” prowadzący do strony „atlas-zwierzat.pl”, odnośnik otwiera stronę w osobnej karcie

    <a href="https://atlas-zwierzat.pl"> - adres z protokołem https://. Sam atlas-zwierzat.pl przeglądarka potraktuje jak nazwę pliku w folderze strony (klucz przyjmuje obie formy - R.3.4). Atrybut target="_blank" otwiera stronę w nowej karcie (R.3.5).

    Typowe błędy

    target="blank" (bez podkreślenia) też otworzy nową kartę, ale nazwaną „blank” - kolejne kliknięcie trafi do tej samej karty. Wartość z arkusza „w osobnej karcie” to _blank.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Stopka: autor strony

    Kryteria:

    R.2.8 W stopce zapisano tekst "autor Atlasu zwierząt: " oraz wstawiono numer zdającego

    ok. 1 min
    Polecenie z arkusza

    Napis o treści „autor Atlasu zwierząt: ”, dalej wstawiony numer PESEL zdającego

    Napis stoi zaraz za odnośnikiem, w tej samej linii - jak na obrazie 2. Na egzaminie po dwukropku wpisujesz swój numer PESEL. W tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora: Bartosz Bryniarski (R.2.8).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  23. Etap 3: Styl CSS

    Kroki 23-30 · po tym etapie masz 28 z 36 kryteriów (pkt)

    Krok 23: Plik styl3.css: krój Garamond dla całej strony

    Kryteria:

    R.4.1 Ustawiono krój czcionki dla całej strony na Garamond (dla body lub html lub *)

    ok. 1 min
    Polecenie z arkusza

    Cechy formatowania CSS działające na stronie: Domyślne dla całej strony: krój czcionki Garamond

    Nowy plik styl3.css w folderze zdającego - od teraz każda reguła trafia tylko tutaj. Pierwsza reguła: selektor uniwersalny * z font-family: Garamond.

    Dlaczego *, a nie body: pola formularza i przyciski nie dziedziczą kroju po body, a na obrazie 2 napis „Wyświetl” na przycisku jest pisany Garamondem. Starsze wydania klucza przyjmują też body i html, wydanie z czerwca 2023 pisze wprost „(*)” - selektor * jest bezpieczny zawsze (R.4.1).

    styl3.css CSS nowy plik
    * {
        font-family: Garamond;
    }
    Podgląd strony po tym kroku (index.php)
  24. Krok 24: Baner: tło, kolor tekstu, wyśrodkowanie, marginesy wewnętrzne

    ok. 2 min
    Polecenie z arkusza

    Dla bloku banera: kolor tła RosyBrown, biały kolor czcionki, wyrównanie tekstu do środka, marginesy wewnętrzne 10 px

    Selektor znacznika header - na stronie jest jeden baner. RosyBrown i white to nazwy kolorów CSS (wielkość liter bez znaczenia) - wpisuj je dosłownie, przeglądarka zna je bez zamiany na kod szesnastkowy. „Marginesy wewnętrzne” to padding (zewnętrzne to margin).

    styl3.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    Podgląd strony po tym kroku (index.php)
  25. Krok 25: Blok formularza: tło, wyśrodkowanie, marginesy wewnętrzne

    ok. 1 min
    Polecenie z arkusza

    Dla bloku formularza: kolor tła DarkSalmon, wyrównanie tekstu do środka, marginesy wewnętrzne 40 px

    Selektor identyfikatora #form-block - z krzyżykiem, bo w HTML-u jest id="form-block". Wyśrodkowanie dziedziczą nagłówek, numery listy i formularz, dlatego na obrazie 2 cała zawartość bloku stoi pośrodku.

    styl3.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    Podgląd strony po tym kroku (index.php)
  26. Krok 26: Bloki główne lewy i prawy: tło i wymiary

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloku głównego lewego oraz prawego: kolor tła LightSalmon, wysokość 300 px, szerokość 30%

    „Wspólne” - dwa selektory rozdzielone przecinkiem dostają jedną regułę. Wysokość 300 px to dokładnie wysokość zdjęcia z archiwum.

    styl3.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    #left, #right {
        background-color: LightSalmon;
        height: 300px;
        width: 30%;
    }
    Podgląd strony po tym kroku (index.php)
  27. Krok 27: Blok główny środkowy: tło i wymiary

    Kryteria: ,

    R.4.4 Ustawiono wysokość dla trzech bloków głównych 300px

    R.4.5 Ustawiono szerokość bloku głównego prawego i lewego 30% oraz głównego środkowego na 40%

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego – środkowego: kolor tła LightSalmon, wysokość 300 px, szerokość 40%

    Szerokości 30% + 40% + 30% = 100% - trzy bloki zajmą razem całą szerokość strony. Wysokości wszystkich trzech bloków głównych (R.4.4) i ich szerokości (R.4.5) są ustawione.

    Typowe błędy

    Bloki o sumie szerokości 100% nie mogą mieć marginesów, padding ani obramowań - każdy piksel więcej zepchnie blok prawy pod spód.

    styl3.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    #left, #right {
        background-color: LightSalmon;
        height: 300px;
        width: 30%;
    }
    #middle {
        background-color: LightSalmon;
        height: 300px;
        width: 40%;
    }
    Podgląd strony po tym kroku (index.php)
  28. Krok 28: Stopka: tło, kolor tekstu, wyśrodkowanie, marginesy wewnętrzne

    Kryteria: , , ,

    R.4.2 Ustawiono kolor tła RosyBrown dla bloku banera i stopki oraz DarkSalmon dla bloku formularza oraz LightSalmon dla trzech bloków głównych

    R.4.3 Ustawiono biały kolor czcionki dla banera i stopki

    R.4.6 Ustawiono wyrównanie tekstu do środka dla bloku banera, formularza i stopki

    R.4.7 Ustawiono marginesy wewnętrzne (padding) 10px dla banera oraz 40px dla bloku formularza oraz 30px dla stopki

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła RosyBrown, biały kolor czcionki, wyrównanie tekstu do środka, marginesy wewnętrzne 30 px

    Ten sam kolor co w banerze. Komplet: kolory tła wszystkich bloków (R.4.2), biały tekst banera i stopki (R.4.3), wyśrodkowanie banera, formularza i stopki (R.4.6), marginesy wewnętrzne 10, 40 i 30 px (R.4.7).

    Biały kolor nie obejmuje odnośnika - przeglądarka ma dla <a> własny kolor (fioletowy po odwiedzeniu, niebieski przed), dlatego na obrazie 2 odnośnik w stopce jest fioletowy, a napis o autorze biały.

    styl3.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    #left, #right {
        background-color: LightSalmon;
        height: 300px;
        width: 30%;
    }
    #middle {
        background-color: LightSalmon;
        height: 300px;
        width: 40%;
    }
    footer {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 30px;
    }
    Podgląd strony po tym kroku (index.php)
  29. Krok 29: Lista numerowana: obramowanie i rozmiar czcionki

    Kryteria:

    R.4.8 Ustawiono styl listy numerowanej: obramowanie 2px linią ciągłą w kolorze rgb(205, 92, 92) lub #CD5C5C oraz rozmiar czcionki 150%

    ok. 1 min
    Polecenie z arkusza

    Dla listy numerowanej: obramowanie 2 px linią ciągłą w kolorze RGB: 205, 92, 92; rozmiar czcionki 150%

    Selektor znacznika ol. Skrót border łączy grubość (2px), styl (solid - linia ciągła) i kolor - zapis rgb(205, 92, 92) to dokładnie wartości z arkusza (ten sam kolor ma nazwę IndianRed i kod #CD5C5C, klucz przyjmuje rgb i kod). font-size: 150% - półtora raza większe litery niż w bloku (R.4.8).

    styl3.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    #left, #right {
        background-color: LightSalmon;
        height: 300px;
        width: 30%;
    }
    #middle {
        background-color: LightSalmon;
        height: 300px;
        width: 40%;
    }
    footer {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 30px;
    }
    ol {
        border: 2px solid rgb(205, 92, 92);
        font-size: 150%;
    }
    Podgląd strony po tym kroku (index.php)
  30. Krok 30: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Wygląd układu bloków na stronie po uruchomieniu w przeglądarce jest w pełni zgodny z obrazem 2 w arkuszu egzaminacyjnym

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki: na górze baner, poniżej blok formularza, poniżej trzy bloki główne: lewy, środkowy i prawy, na dole blok stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2

    Sekcje dostają float: left - bloki główne (30% + 40% + 30%) stają obok siebie w jednym rzędzie. Blok formularza też jest sekcją, ale ma zajmować całą szerokość, więc reguła #form-block zdejmuje z niego opływanie (float: none) - identyfikator jest silniejszy niż sam znacznik, więc wygrywa niezależnie od kolejności. Stopka z clear: both zaczyna się dopiero pod pływającymi blokami.

    Zdjęcie ma 400 px szerokości, a blok lewy 30% okna: przy oknie szerszym niż ok. 1350 px mieści się w całości (jak na obrazie 2), przy węższym jego prawy brzeg chowa się pod blokiem środkowym. Arkusz nie każe zmieniać rozmiaru zdjęcia - a reguła dla img wykraczałaby poza cechy formatowania z arkusza. Klucz R.3.1 sprawdza układ bloków.

    Typowe błędy

    Bez float: none dla bloku formularza (albo bez osobnego znacznika dla niego) blok formularza też popłynie w lewo i trzy bloki główne ustawią się obok niego. Bez clear: both stopka wsunie się pod pływające bloki.

    styl3.css CSS zmienione: 9 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 10px;
    }
    #form-block {
        background-color: DarkSalmon;
        text-align: center;
        padding: 40px;
    }
    #left, #right {
        background-color: LightSalmon;
        height: 300px;
        width: 30%;
    }
    #middle {
        background-color: LightSalmon;
        height: 300px;
        width: 40%;
    }
    footer {
        background-color: RosyBrown;
        color: white;
        text-align: center;
        padding: 30px;
    }
    ol {
        border: 2px solid rgb(205, 92, 92);
        font-size: 150%;
    }
    section {
        float: left;
    }
    #form-block {
        float: none;
    }
    footer {
        clear: both;
    }
    Podgląd strony po tym kroku (index.php)
  31. Etap 4: Skrypty PHP

    Kroki 31-38 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 31: Blok środkowy: miejsce skryptu i połączenie z bazą

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP

    R.5.2 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy baza

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku głównego – środkowego: efekt wykonania skryptu nr 1 Napisany w języku PHP Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie baza

    „Efekt wykonania skryptu nr 1” ma być w bloku środkowym, więc tam piszesz blok PHP, między <?php a ?>. Serwer wykona go, zanim strona trafi do przeglądarki (R.5.1).

    Pierwsza instrukcja: mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy baza (R.5.2). Połączenie trafia do zmiennej $connection. Wystarczy jedno połączenie na całą stronę - skrypt nr 2 w bloku prawym skorzysta z tej samej zmiennej, bo PHP wykonuje wszystkie bloki jednego pliku po kolei.

    Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2) - na razie wygląda jak wcześniej. Stronę sprawdzasz przez http://localhost/…, a nie otwierając plik z dysku: przeglądarka sama nie wykona PHP.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  32. Krok 32: Skrypt nr 1: wartość z pola edycyjnego

    ok. 2 min
    Polecenie z arkusza

    Działanie skryptu nr 1: Skrypt pobiera dane z pola edycyjnego

    • isset($_POST['gromada']) jest prawdziwe dopiero po kliknięciu „Wyświetl”. Przy pierwszym wejściu na stronę formularz nie był wysłany i skrypt nr 1 nic nie robi - blok środkowy jest pusty,
    • $gromada = $_POST['gromada']; - wartość pola (klucz to atrybut name) trafia do zmiennej o czytelnej nazwie.

    Od tego kroku podgląd pokazuje stronę po wysłaniu formularza z wartością 4, jak na obrazie 2. Na razie nic jeszcze nie widać - wartość jest tylko odczytana.

    Typowe błędy

    Odczyt $_POST['gromada'] bez isset przy pierwszym wejściu na stronę daje ostrzeżenie „Undefined array key” wypisane na stronie.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 31.

  33. Krok 33: Skrypt nr 1: nagłówek z nazwą gromady

    Kryteria:

    R.5.5 Skrypt wypisuje w tekst zależny od podanej wartości w polu. Jeśli podano 1 – „RYBY”, 2 – „PŁAZY”, 3 – „GADY”, 4 – „PTAKI”, 5 – „SSAKI”

    ok. 3 min
    Polecenie z arkusza

    W zależności od wartości pola wypisuje w nagłówku drugiego stopnia: dla wartości 1 – „RYBY”, 2 – „PŁAZY”, 3 – „GADY”, 4 – „PTAKI”, 5 – „SSAKI”

    Pięć wartości, pięć napisów - drabinka if / elseif: pierwszy prawdziwy warunek wypisuje swój nagłówek, reszta jest pomijana. Napis idzie w znaczniku <h2> (R.5.5). Porównanie == porównuje wartość, a nie typ: z formularza przychodzi napis '4', a '4' == 4 jest w PHP prawdziwe.

    Podgląd: wartość 4 - w bloku środkowym nagłówek PTAKI. Dla wartości spoza 1-5 (np. 7) żaden warunek nie jest prawdziwy i nagłówka nie ma - arkusz nie mówi, co wtedy wypisać.

    Typowe błędy

    if ($gromada = 1) z jednym znakiem równości to przypisanie, nie porównanie - warunek zawsze jest prawdziwy i dla każdej wartości wypisze się „RYBY”.

    index.php PHP zmienione: 11 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  34. Krok 34: Skrypt nr 1: zmodyfikowane zapytanie 1

    Kryteria:

    R.5.4 Skrypt nr 1 wysyła do bazy zmodyfikowane zapytanie nr 1, w ten sposób, że w sekcji warunku sprawdzana gromada jest zgodna z wartością w polu formularza. Jeśli w polu wpisana jest wartość 1 – zapytanie dotyczy ryb, wartość 2 – zapytanie dotyczy płazów itd.

    ok. 2 min
    Polecenie z arkusza

    Wysyła do bazy zmodyfikowane zapytanie nr 1, w ten sposób, że w sekcji warunku sprawdzana gromada jest zgodna z wartością pobraną z pola edycyjnego. Jeśli w polu wpisana jest wartość 1 – zapytanie dotyczy ryb, wartość 2 – zapytanie dotyczy płazów itd.

    Zapytanie 1 z kwerendy.txt z jedną zmianą: w miejsce 1 w warunku stoi $gromada. Całe zapytanie jest w cudzysłowie "…", więc PHP podstawia wartość zmiennej - dla 4 baza dostaje WHERE Gromady_id = 4. Numery na liście w bloku formularza są tymi samymi numerami co id w tabeli gromady, dlatego wartość z pola można wstawić do warunku bez żadnej zamiany (R.5.4).

    Wynik mysqli_query trafia do $result - jeszcze nic nie jest wypisane. Zapytanie stoi w tym samym warunku co nagłówek: wysyła się tylko po wysłaniu formularza.

    Typowe błędy

    Zapytanie w apostrofach '… Gromady_id = $gromada;' - PHP nie podstawi zmiennej i baza dostanie dosłownie tekst $gromada, co kończy się błędem składni SQL.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 33.

  35. Krok 35: Skrypt nr 1: gatunek i występowanie w osobnych wierszach

    Kryteria:

    R.5.6 Skrypt nr 1 wypisuje zwrócone zapytaniem pola gatunek i występowanie w osobnych wierszach

    ok. 3 min
    Polecenie z arkusza

    Wartości zwrócone zapytaniem są wypisywane w osobnych wierszach, w formacie „<gatunek>, <występowanie>”

    • mysqli_fetch_row($result) zwraca kolejny wiersz wyniku jako tablicę numerowaną od zera: $row[0] to gatunek, $row[1] - wystepowanie (kolejność kolumn z SELECT). Gdy wierszy zabraknie, zwraca false i pętla while się kończy,
    • echo "$row[0], $row[1]<br>"; - format z arkusza: gatunek, przecinek, spacja, występowanie; <br> przenosi kolejny rekord do nowego wiersza (R.5.6).

    Podgląd: trzy ptaki z bazy - Wrona siwa, Europa, Puszczyk zwyczajny, Eurazja, Sroka zwyczajna, Eurazja, dokładnie jak na obrazie 2.

    Typowe błędy

    Bez <br> wszystkie rekordy skleją się w jedną linię - przeglądarka ignoruje znaki nowej linii z PHP.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  36. Krok 36: Skrypt nr 2: zapytanie 2

    Kryteria:

    R.5.7 Skrypt nr 2 wysyła do bazy zapytanie 2

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku głównego – prawego: Efekt wykonania skryptu nr 2 Działanie skryptu nr 2: Skrypt wysyła do bazy zapytanie numer 2

    Drugi blok PHP stoi w bloku prawym, pod nagłówkiem „Wszystkie zwierzęta w bazie”. Korzysta z połączenia $connection otwartego w bloku środkowym. Zapytanie 2 z kwerendy.txt bez zmian (R.5.7) - tu nie ma żadnej zmiennej, więc wystarczą apostrofy. Skrypt nr 2 działa zawsze, także przed wysłaniem formularza.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  37. Krok 37: Skrypt nr 2: rekordy w formacie „id. gatunek, gromada”

    Kryteria:

    R.5.8 Skrypt nr 2 wypisuje w kolejnych wierszach pola id, gatunek, nazwa zwrócone zapytaniem

    ok. 2 min
    Polecenie z arkusza

    W kolejnych wierszach wypisywane są rekordy w formacie: „<id>. <gatunek>, <nazwa gromady>”

    Ta sama pętla co w skrypcie nr 1, tylko z trzema kolumnami: $row[0] - id, $row[1] - gatunek, $row[2] - nazwa gromady. Po numerze kropka i spacja, po gatunku przecinek i spacja (R.5.8).

    Podgląd: dziewięć zwierząt, od 1. Sum pospolity, ryby do 9. Dingo australijski, ssaki. Nazwy gromad są w bazie zapisane małymi literami i bez polskich znaków (plazy) - strona wypisuje je tak, jak są w tabeli.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            while ($row = mysqli_fetch_row($result)) {
                echo "$row[0]. $row[1], $row[2]<br>";
            }
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  38. Krok 38: Zamknięcie połączenia z bazą

    Kryteria:

    R.5.3 Po wykonaniu operacji na bazie zastosowano funkcję zamknięcia bazy

    ok. 1 min
    Polecenie z arkusza

    Na końcu działania skrypt zamyka połączenie z serwerem bazodanowym

    mysqli_close($connection) na końcu bloku PHP w bloku prawym - po ostatnim zapytaniu na stronie, poza warunkami, więc wykona się zawsze (R.5.3). Strona spełnia wszystkie kryteria arkusza; podgląd pokazuje stan z obrazu 2. Dalej trzy kroki o zabezpieczeniach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close w bloku środkowym (zaraz po skrypcie nr 1) zamknie połączenie, zanim skrypt nr 2 wyśle swoje zapytanie - PHP 8 zgłosi wtedy błąd „mysqli object is already closed”.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            while ($row = mysqli_fetch_row($result)) {
                echo "$row[0]. $row[1], $row[2]<br>";
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>

    Podgląd strony bez zmian - taki jak po kroku 37.

  39. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 39-41 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 39: Zabezpieczenie: zapytanie przygotowane

    ok. 4 min
    Polecenie z arkusza

    Wysyła do bazy zmodyfikowane zapytanie nr 1, w ten sposób, że w sekcji warunku sprawdzana gromada jest zgodna z wartością pobraną z pola edycyjnego.

    Wartość z formularza trafia do zapytania wprost - to SQL injection. Pole type="number" nie chroni: ogranicza tylko to, co da się wpisać w przeglądarce, a żądanie POST można wysłać z dowolną treścią (np. narzędziami deweloperskimi albo programem curl). Sprawdzone na wersji z poprzednich kroków:

    • wartość 0 OR 1=1 zamienia warunek w zawsze prawdziwy - blok środkowy wypisuje wszystkie dziewięć zwierząt,
    • wartość 0 UNION SELECT imie, nazwisko FROM pracownicy dokleja wynik z innej tabeli - w bloku środkowym pojawiają się imiona i nazwiska pracowników (Anna, Kowalska …), czyli dane, których strona nigdy nie miała pokazywać,
    • puste pole rozbija składnię zapytania (WHERE Gromady_id = ;) - PHP 8 zgłasza wyjątek mysqli_sql_exception i zamiast strony widać „Fatal error”.

    Lekarstwo to zapytanie przygotowane: mysqli_prepare ze znakiem ? w miejscu wartości, mysqli_stmt_bind_param z typem 'i' (liczba całkowita), mysqli_stmt_execute i mysqli_stmt_get_result - wynik czyta się dalej tą samą pętlą. Baza dostaje treść zapytania i wartość osobno, więc wartość nigdy nie stanie się kodem SQL. Podgląd: ta sama wartość z UNION - typ 'i' zamienia ją na liczbę 0 i blok środkowy jest pusty. Stara linia zostaje w komentarzu.

    Typowe błędy

    Liczba liter w 'i' musi równać się liczbie znaków ? i liczbie zmiennych - inaczej mysqli_stmt_bind_param zgłosi błąd.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                $gromada = $_POST['gromada'];
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                // $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                $statement = mysqli_prepare($connection, 'SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = ?');
                mysqli_stmt_bind_param($statement, 'i', $gromada);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            while ($row = mysqli_fetch_row($result)) {
                echo "$row[0]. $row[1], $row[2]<br>";
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  40. Krok 40: Zabezpieczenie: sprawdzenie wartości z formularza

    ok. 3 min
    Polecenie z arkusza

    Skrypt pobiera dane z pola edycyjnego

    Dwie poprawki tego, co przychodzi z formularza:

    • (int) zamienia napis na liczbę całkowitą jeszcze przed nagłówkiem i zapytaniem: '4' daje 4, pusty napis i tekst w rodzaju 0 OR 1=1 - liczbę 0 lub inną liczbę, ale nigdy kod SQL. Puste pole przestaje wywracać stronę,
    • wartość spoza zakresu 1-5 dostaje komunikat „Wpisz numer gromady od 1 do 5.” - bez niego po wpisaniu 7 blok środkowy był po prostu pusty i nie było wiadomo dlaczego.

    Podgląd: wartość 7 - komunikat zamiast pustego bloku. Arkusz tego komunikatu nie wymaga; na egzaminie nie przeszkadza w żadnym kryterium.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                // $gromada = $_POST['gromada'];
                $gromada = (int) $_POST['gromada'];
                if ($gromada < 1 || $gromada > 5) {
                    echo '<p>Wpisz numer gromady od 1 do 5.</p>';
                }
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                // $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                $statement = mysqli_prepare($connection, 'SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = ?');
                mysqli_stmt_bind_param($statement, 'i', $gromada);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                while ($row = mysqli_fetch_row($result)) {
                    echo "$row[0], $row[1]<br>";
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            while ($row = mysqli_fetch_row($result)) {
                echo "$row[0]. $row[1], $row[2]<br>";
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  41. Krok 41: Zabezpieczenie: htmlspecialchars na wyjściu

    ok. 2 min
    Polecenie z arkusza

    W kolejnych wierszach wypisywane są rekordy w formacie: „<id>. <gatunek>, <nazwa gromady>”

    Skrypty wypisują tekst z bazy prosto do HTML-a. Gdyby ktoś dopisał do tabeli gatunek w rodzaju <script>…</script> (np. przez inny formularz albo panel), przeglądarka wykonałaby go u każdego odwiedzającego - to atak XSS. Funkcja htmlspecialchars zamienia znaki <, >, & i cudzysłów na encje (&lt; …), więc przeglądarka pokaże je jako tekst.

    Zasada: dane wejściowe sprawdzasz przy odbiorze (poprzedni krok), a dane wypisywane - zabezpieczasz w chwili wypisywania. Liczby (id z bazy) tego nie potrzebują. Podgląd wygląda tak samo jak wcześniej - w danych z archiwum nie ma znaków specjalnych.

    index.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Dane o zwierzętach</title>
        <link rel="stylesheet" href="styl3.css">
    </head>
    <body>
        <header>
            <h1>ATLAS ZWIERZĄT</h1>
        </header>
        <section id="form-block">
            <h2>Gromady:</h2>
            <ol>
                <li>Ryby</li>
                <li>Płazy</li>
                <li>Gady</li>
                <li>Ptaki</li>
                <li>Ssaki</li>
            </ol>
            <form method="post">
                Wybierz gromadę: <input type="number" name="gromada">
                <input type="submit" value="Wyświetl">
            </form>
        </section>
        <section id="left">
            <img src="zwierzeta.jpg" alt="dzikie zwierzęta">
        </section>
        <section id="middle">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'baza');
            if (isset($_POST['gromada'])) {
                // $gromada = $_POST['gromada'];
                $gromada = (int) $_POST['gromada'];
                if ($gromada < 1 || $gromada > 5) {
                    echo '<p>Wpisz numer gromady od 1 do 5.</p>';
                }
                if ($gromada == 1) {
                    echo '<h2>RYBY</h2>';
                } elseif ($gromada == 2) {
                    echo '<h2>PŁAZY</h2>';
                } elseif ($gromada == 3) {
                    echo '<h2>GADY</h2>';
                } elseif ($gromada == 4) {
                    echo '<h2>PTAKI</h2>';
                } elseif ($gromada == 5) {
                    echo '<h2>SSAKI</h2>';
                }
                // $result = mysqli_query($connection, "SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = $gromada;");
                $statement = mysqli_prepare($connection, 'SELECT gatunek, wystepowanie FROM zwierzeta WHERE Gromady_id = ?');
                mysqli_stmt_bind_param($statement, 'i', $gromada);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                while ($row = mysqli_fetch_row($result)) {
                    // echo "$row[0], $row[1]<br>";
                    echo htmlspecialchars($row[0]) . ', ' . htmlspecialchars($row[1]) . '<br>';
                }
            }
            ?>
        </section>
        <section id="right">
            <h2>Wszystkie zwierzęta w bazie</h2>
            <?php
            $result = mysqli_query($connection, 'SELECT zwierzeta.id, gatunek, nazwa FROM zwierzeta JOIN gromady ON zwierzeta.Gromady_id = gromady.id;');
            while ($row = mysqli_fetch_row($result)) {
                // echo "$row[0]. $row[1], $row[2]<br>";
                echo $row[0] . '. ' . htmlspecialchars($row[1]) . ', ' . htmlspecialchars($row[2]) . '<br>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <a href="https://atlas-zwierzat.pl" target="_blank">Poznaj inne strony o zwierzętach</a>
            autor Atlasu zwierząt: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  42. Etap 6: Oddanie pracy

    Krok 42 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 42: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    UWAGA: po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Umieść go w folderze z numerem PESEL.

    W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….

    W folderze z numerem zdającego muszą być: import.png, index.php, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, przeglądarka.txt, styl3.css i zwierzeta.jpg (plik baza2.sql z archiwum może zostać). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

    Podgląd strony bez zmian - taki jak po kroku 41.

Podgląd

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: . 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.

Potwierdzenie

Informacja