Przejdź do głównej treści
EE.09-04-21.01-SGStyczeń 2021 · 26 kroków · ok. 60 min · 40 kryteriów z klucza

Rozwiązanie krok po kroku: Kalkulator BMI z zapisem wyników (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza egzamin z czterema zapytaniami, przeskalowana ilustracja z przezroczystością i strona waga.php z formularzem, który liczy BMI i zapisuje pomiar, oraz tabelą przedziałów - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • znaczniki <header>, <main> i <footer>: baner i logo to sekcje w nagłówku strony, bloki lewy i prawy stoją w kontenerze, a w rzędy ustawia je display: flex zamiast float i clear,
  • zmienne CSS dla kolorów z arkusza, etykiety <label> przy polach formularza,
  • PHP na PDO na górze pliku, przed HTML-em: odczyt danych z formularza z walidacją liczb, obliczenie, zapis i odczyt z bazy w jednym miejscu, a w HTML-u zostaje tylko wypisanie,
  • przedział BMI odczytany z tabeli bmi zapytaniem przygotowanym zamiast granic wpisanych w kod,
  • funkcja e() (htmlspecialchars) przy każdej wypisywanej wartości, try/catch/finally z zamknięciem połączenia w każdym przypadku.

To arkusz EE.09 ze stycznia 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i grafika pochodzą z oryginalnego archiwum CKE z4.zip (załącznik na stronie arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2, także po wysłaniu formularza danymi z obrazu 2 (waga 70, wzrost 170).

Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem; klucz przyjmuje zarówno mysqli, jak i PDO.

  1. Etap 1: Baza danych

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

    Krok 1: Folder zdającego i archiwum z4.zip

    ok. 2 min
    Polecenie z arkusza

    Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie z4.zip zabezpieczone hasłem: #Wylicz3ni4BMI^ Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Umieść w tym folderze rozpakowane pliki.

    Folder na pulpicie nazwany numerem PESEL - w tym rozwiązaniu Bartosz Bryniarski. Archiwum z4.zip rozpakuj do niego, hasło #Wylicz3ni4BMI^. W środku: egzamin.sql, rys1.png i wzor.png.

  2. Krok 2: XAMPP, baza egzamin i import egzamin.sql

    ok. 2 min
    Polecenie z arkusza

    Do wykonania zadania należy użyć tabel: bmi oraz wynik przedstawionych na obrazie 1. Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie egzamin. Do bazy egzamin zaimportuj plik egzamin.sql z rozpakowanego archiwum

    W XAMPP Control Panel Start przy Apache i MySQL, w phpMyAdmin (http://localhost/phpmyadmin) Nowa → nazwa egzamin → Utwórz, potem karta Import, plik egzamin.sql, Wykonaj. Plik zakłada sześć tabel, ale zadanie korzysta tylko z dwóch z obrazu 1: bmi (cztery przedziały wskaźnika) i wynik (zapisane pomiary; pole bmi_id wskazuje przedział z tabeli bmi).

  3. Krok 3: Zrzut import.png

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    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

    Karta Struktura bazy egzamin pokazuje listę tabel z liczbą rekordów - to „elementy wskazujące na poprawnie wykonany import”. Zrzut całego ekranu z paskiem zadań zapisujesz jako import.png.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: nowy pomiar w tabeli wynik

    Kryteria: ,

    R.1.2 Zapisano plik tekstowy o nazwie kwerendy zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Utworzono zapytanie 1 wstawiające do tabeli wynik rekord o danych: klucz główny nadawany automatycznie, bmi_id = 1, data_pomiaru = 2020-05-20, wynik = 15. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO wynik(bmi_id, data_pomiaru, wynik) VALUES (1, "2020-05- 20", 15); (możliwe bez pierwszego nawiasu lub przez listę przypisań) oraz wynik działania zapytania udokumentowano zrzutem na którym widoczne jest poprawne zapytanie lub dodany rekord w tabeli

    ok. 2 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie egzamin. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem 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: wstawiające do tabeli wynik rekord o danych: klucz główny nadawany automatycznie, bmi_id = 1, data_pomiaru = 2020-05-20, wynik = 15

    INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (1, '2020-05-20', 15) - lista pól bez id (nada go AUTO_INCREMENT), data w apostrofach. Odpowiedź „1 wiersz wstawiony” - zrzut kw1.jpg. Wykonaj je raz.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (1, '2020-05-20', 15);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: przedziały BMI

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola id, informacja i wart_min z tabeli bmi . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, informacja, wart_min FROM bmi; oraz wynik działania zapytania udokumentowano zrzutem, na którym są widoczne dokładnie cztery rekordy o id= 1, 2, 3, 4, jedynie pola id, informacja, wart_min

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola id, informacja i wart_min z tabeli bmi

    Trzy pola w kolejności kolumn tabeli na stronie. Wynik: 4 przedziały z ich początkami (0, 19, 26, 31). Zrzut kw2.jpg - to samo zapytanie wyśle skrypt 2, a do zrzutu prowadzi odsyłacz w stopce.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (1, '2020-05-20', 15);
    
    -- Zapytanie 2
    SELECT id, informacja, wart_min FROM bmi;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: relacja wynik - bmi

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pola wynik z tabeli wynik oraz informacja z tabeli bmi . Wykorzystano relację. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT wynik, bmi.informacja FROM wynik JOIN bmi ON wynik.bmi_id = bmi.id; możliwe INNER JOIN lub bez JOIN (porównanie kluczy w warunku) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest co najmniej jeden wiersz jedynie z danymi: 20, waga prawidlowa. większa liczba wierszy wynika z wykonania kwerendy 1 lub wstawienia rekordów przez stronę ale nie z powodu nieprawidłowego przypisania kluczy w zapytaniu

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola wynik z tabeli wynik oraz informacja z tabeli bmi; zapytanie wykorzystuje relację

    • SELECT wynik, informacja - wynik pomiaru z tabeli wynik i opis przedziału z tabeli bmi,
    • FROM wynik JOIN bmi ON wynik.bmi_id = bmi.id - relacja z obrazu 1.

    Wynik po zapytaniu 1: dwa wiersze - 20, waga prawidlowa (rekord z importu) oraz 15, niedowaga. Zrzut: kw3.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (1, '2020-05-20', 15);
    
    -- Zapytanie 2
    SELECT id, informacja, wart_min FROM bmi;
    
    -- Zapytanie 3
    SELECT wynik, informacja FROM wynik JOIN bmi ON wynik.bmi_id = bmi.id;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: granice niedowagi

    Kryteria:

    R.1.6 Utworzono zapytanie 4 wybierające jedynie pola wart_min i wart_max z tabeli bmi dla niedowagi. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT wart_min, wart_max FROM bmi WHERE informacja="niedowaga"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest dokładnie jeden wiersz jedynie z danymi 0, 18

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: wybierające jedynie pola wart_min i wart_max z tabeli bmi dla niedowagi (pole informacja)

    SELECT wart_min, wart_max FROM bmi z warunkiem WHERE informacja = 'niedowaga'. Wynik: jeden wiersz 0, 18. Zrzut: kw4.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (1, '2020-05-20', 15);
    
    -- Zapytanie 2
    SELECT id, informacja, wart_min FROM bmi;
    
    -- Zapytanie 3
    SELECT wynik, informacja FROM wynik JOIN bmi ON wynik.bmi_id = bmi.id;
    
    -- Zapytanie 4
    SELECT wart_min, wart_max FROM bmi WHERE informacja = 'niedowaga';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika: wysokość 300 px z przezroczystością

    Kryteria:

    R.2.1 Plik rys1.png przeskalowano z zachowaniem proporcji do wysokości 300 px, odpowiadająca temu szerokość wynosi 364 px (± 5 px); przezroczystość została zachowana

    ok. 2 min
    Polecenie z arkusza

    Plik rys1.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 300 px. Należy zachować przezroczystość obrazu

    Oryginał ma 400 × 330 px i przezroczyste tło. W GIMP-ie Obraz → Skaluj obraz z zamkniętym łańcuchem proporcji, wysokość 300 px - szerokość: 400 × 300 / 330 = 363,6, czyli 364 px (klucz: 364 ±5). Zapis jako PNG - ten format przechowuje przezroczystość.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik waga.php: nagłówek dokumentu

    Kryteria: , ,

    R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie waga oraz zastosowano właściwy standard kodowania polskich znaków

    R.2.3 Nadano tytuł strony: "Twój wskaźnik BMI”

    R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl4.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze strony o nazwie waga.php. Zastosowany właściwy standard kodowania polskich znaków. Tytuł strony widoczny na karcie przeglądarki: „Twój wskaźnik BMI”. Arkusz stylów w pliku o nazwie styl4.css prawidłowo połączony z kodem strony

    Cała część <head> w jednym kroku:

    • <!DOCTYPE html> - HTML5, lang="pl" - język treści,
    • <meta charset="UTF-8"> jako pierwszy element <head> (R.2.2 - razem z nazwą pliku waga.php),
    • <title>Twój wskaźnik BMI</title> (R.2.3),
    • <meta name="viewport"> - telefon pokazuje stronę w swojej szerokości (arkusz tego nie wymaga),
    • <link rel="stylesheet" href="styl4.css"> (R.3.5 - punkt przyznawany razem z poprawnymi selektorami).
    waga.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  10. Krok 10: Bloki: nagłówek z banerem i logo, kolumny, część główna, stopka

    Kryteria:

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, logo, blok lewy i prawy, główny oraz stopka. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: obok siebie baner i logo, poniżej blok lewy i prawy, następnie główny oraz stopka. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2

    <header> z sekcjami banner i logo, kontener <div class="columns"> z sekcjami left i right, <main> - blok główny (jeden na stronie, więc bez identyfikatora) i <footer> - stopka. Znaczniki HTML5 mówią, czym jest każda część strony; <header> i kontener kolumn dostaną w CSS display: flex.

    waga.php PHP zmienione: 16 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
            </section>
            <section id="logo">
            </section>
        </header>
        <div class="columns">
            <section id="left">
            </section>
            <section id="right">
            </section>
        </div>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  11. Krok 11: Baner, logo i ilustracja

    Kryteria:

    R.2.6 W bloku logo umieszczono obraz wzor.png oraz w bloku lewym umieszczono obraz rys1.png. Przynajmniej jeden z obrazów ma tekst alternatywny: "liczymy BMI" (dla wzor.png ) lub "zrzuć kalorie!" (dla rys1.png ), gdy obraz nie istnieje powinien wyświetlić się tekst alternatywny

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku banera: nagłówek drugiego stopnia o treści „Oblicz wskaźnik BMI”. Zawartość bloku logo: obraz wzor.png z tekstem alternatywnym „liczymy BMI”. Zawartość bloku lewego: obraz rys1.png z tekstem alternatywnym o treści: „zrzuć kalorie!”

    Nagłówek <h2> (poziom narzucony przez arkusz), obraz wzoru i ilustracja 364 × 300 px, oba z tekstem alternatywnym (R.2.6).

    waga.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
            </section>
        </div>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  12. Krok 12: Blok prawy: nagłówek i formularz

    Kryteria: , , , ,

    R.2.5 W bloku banera zapisano nagłówek h2: "Oblicz wskaźnik BMI", w bloku prawym nagłówek h1: "Podaj dane"

    R.2.7 W bloku prawym umieszczono formularz, zastosowano znacznik <form> oraz jego zamknięcie

    R.2.8 W formularzu umieszczono dwa pola edycyjne oraz przycisk "Licz BMI i zapisz wynik"

    R.3.2 Przycisk wysyła dane z formularza oraz przynajmniej jedno pole do wprowadzania danych jest typu liczbowego

    R.3.3 Formularz wysyła dane metodą POST do tego samego pliku (poprawne również bez atrybutu action)

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek pierwszego stopnia o treści: „Podaj dane”. Formularz wysyłający dane metodą POST do tej samej strony, zawierający: Napis „Waga:”, następnie pole edycyjne typu numerycznego. Napis „Wzrost [cm]:”, następnie pole edycyjne typu numerycznego. Przycisk wysyłający zawartość formularza z opisem „Licz BMI i zapisz wynik”

    • <h1> - razem z <h2> banera nagłówki są gotowe (R.2.5),
    • <form method="post"> bez action wysyła dane do bieżącego adresu, czyli do tej samej strony (R.2.7, R.3.3),
    • napisy w <label for="…">: kliknięcie napisu ustawia kursor w polu, a czytnik ekranu odczyta go razem z polem,
    • dwa pola type="number" z nazwami waga, wzrost oraz <button type="submit"> z opisem z arkusza (R.2.8, R.3.2).
    waga.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
            </section>
        </div>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  13. Krok 13: Blok główny i stopka

    Kryteria: ,

    R.2.10 Pierwszy wiersz tabeli jest wierszem nagłówkowym, zastosowano znacznik <th> (opcjonalnie <thead> i <td>) oraz jego zamknięcie

    R.3.4 Kliknięcie odsyłacza otwiera dowolny plik ze zrzutem ekranu

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku głównego: Tabela z trzema kolumnami. Komórki nagłówkowe w pierwszym wierszu tabeli: „lp.”, „Interpretacja”, „zaczyna się od…”. Zawartość stopki: Tekst: „Autor: ”, dalej wstawiony numer PESEL zdającego. Odsyłacz do pliku kw2.jpg o treści „Wynik działania kwerendy 2”

    Tabela z wierszem nagłówkowym w <thead> (klucz wprost dopuszcza <thead>, R.2.10) i pustym <tbody>, w którym skrypt wypisze przedziały. W stopce po „Autor: ” na egzaminie stoi numer PESEL, tu Bartosz Bryniarski, i odsyłacz do zrzutu kw2.jpg (R.3.4).

    waga.php PHP zmienione: 13 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
            </section>
        </div>
        <main>
            <table>
                <thead>
                    <tr>
                        <th>lp.</th>
                        <th>Interpretacja</th>
                        <th>zaczyna się od...</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
            <a href="kw2.jpg">Wynik działania kwerendy 2</a>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  14. Etap 3: Styl CSS

    Kroki 14-20 · po tym etapie masz 30 z 40 kryteriów (pkt)

    Krok 14: Zmienne kolorów i selektor body

    Kryteria:

    R.4.1 Ustawiono krój czcionki Helvetica dla znacznika body lub kontenera całej strony

    ok. 2 min
    Polecenie z arkusza

    Cechy formatowania CSS: Dla znacznika body: krój czcionki Helvetica, kolor tła #FFE4B5

    Reguła :root z zmiennymi CSS - kolory z arkusza dostają nazwy, a reguły odwołują się do nich przez var(--indigo). Reguła body: Helvetica, a na komputerze bez niej (np. z Windows) Arial albo inny krój bezszeryfowy (R.4.1), i beżowe tło.

    styl4.css CSS nowy plik
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    Podgląd strony po tym kroku (waga.php)
  15. Krok 15: Układ: dwa rzędy na flex

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: obok siebie baner i logo, poniżej blok lewy i prawy, następnie główny oraz stopka. Podział zrealizowany za pomocą znaczników sekcji, zgodnie z obrazem 2

    display: flex na <header> i kontenerze .columns ustawia ich sekcje w rzędzie. <main> i <footer> stoją pod nimi zwykłymi blokami na całą szerokość - bez float i clear. Klucz ocenia układ w przeglądarce (R.3.1), a szerokości 75/25 i 45/55 stoją na samych blokach, jak oczekuje R.4.5.

    styl4.css CSS zmienione: 5 linii
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    Podgląd strony po tym kroku (waga.php)
  16. Krok 16: Baner i logo

    Kryteria:

    R.4.10 Ustawiono rozmiar czcionki 150% dla banera

    ok. 1 min
    Polecenie z arkusza

    Dla banera: tło koloru #4B0082, biały kolor czcionki, wyrównanie tekstu do środka, szerokość 75%, wysokość 100 px, rozmiar czcionki 150%. Dla bloku logo: szerokość 25%, wysokość 100 px

    Oba bloki 100 px wysokości, szerokości 75 + 25 = 100%, rozmiar czcionki banera 150% (R.4.10).

    styl4.css CSS zmienione: 14 linii
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    
    #banner {
        background-color: var(--indigo);
        color: white;
        text-align: center;
        width: 75%;
        height: 100px;
        font-size: 150%;
    }
    
    #logo {
        width: 25%;
        height: 100px;
    }
    Podgląd strony po tym kroku (waga.php)
  17. Krok 17: Bloki lewy i prawy

    Kryteria:

    R.4.4 Ustawiono wysokość bloku logo i banera na 100px, bloku lewego i prawego: 300px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku lewego: szerokość 45%, wysokość 300 px. Dla bloku prawego: szerokość 55%, wysokość 300 px, wyrównanie tekstu do środka

    Rząd 45 + 55%, oba bloki po 300 px wysokości (R.4.4).

    styl4.css CSS zmienione: 11 linii
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    
    #banner {
        background-color: var(--indigo);
        color: white;
        text-align: center;
        width: 75%;
        height: 100px;
        font-size: 150%;
    }
    
    #logo {
        width: 25%;
        height: 100px;
    }
    
    #left {
        width: 45%;
        height: 300px;
    }
    
    #right {
        width: 55%;
        height: 300px;
        text-align: center;
    }
    Podgląd strony po tym kroku (waga.php)
  18. Krok 18: Blok główny i stopka

    Kryteria:

    R.4.2 Ustawiono kolor tła #FFE4B5 dla znacznika body lub kontenera całej strony, oraz kolor tła #4B0082 dla bloków banera, głównego i stopki

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: tło koloru #4B0082, marginesy wewnętrzne 60 px. Dla stopki: tło koloru #4B0082, biały kolor czcionki, marginesy wewnętrzne 40 px

    Selektory znaczników main i footer - fioletowe tło z tej samej zmiennej co baner (R.4.2 razem z tłem strony).

    styl4.css CSS zmienione: 11 linii
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    
    #banner {
        background-color: var(--indigo);
        color: white;
        text-align: center;
        width: 75%;
        height: 100px;
        font-size: 150%;
    }
    
    #logo {
        width: 25%;
        height: 100px;
    }
    
    #left {
        width: 45%;
        height: 300px;
    }
    
    #right {
        width: 55%;
        height: 300px;
        text-align: center;
    }
    
    main {
        background-color: var(--indigo);
        padding: 60px;
    }
    
    footer {
        background-color: var(--indigo);
        color: white;
        padding: 40px;
    }
    Podgląd strony po tym kroku (waga.php)
  19. Krok 19: Formularz

    Kryteria:

    R.4.7 Ustawiono marginesy wewnętrzne (padding) 60px dla bloku głównego oraz 40px dla stopki oraz marginesy zewnętrzne (margin) 40px dla znacznika form

    ok. 1 min
    Polecenie z arkusza

    Dla znacznika formularza: marginesy zewnętrzne 40 px

    Margines zewnętrzny formularza; razem z marginesami wewnętrznymi bloku głównego i stopki - R.4.7.

    styl4.css CSS zmienione: 4 linie
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    
    #banner {
        background-color: var(--indigo);
        color: white;
        text-align: center;
        width: 75%;
        height: 100px;
        font-size: 150%;
    }
    
    #logo {
        width: 25%;
        height: 100px;
    }
    
    #left {
        width: 45%;
        height: 300px;
    }
    
    #right {
        width: 55%;
        height: 300px;
        text-align: center;
    }
    
    main {
        background-color: var(--indigo);
        padding: 60px;
    }
    
    footer {
        background-color: var(--indigo);
        color: white;
        padding: 40px;
    }
    
    form {
        margin: 40px;
    }
    Podgląd strony po tym kroku (waga.php)
  20. Krok 20: Tabela i wiersz pod kursorem

    Kryteria: , , , ,

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

    R.4.5 Ustawiono szerokość bloku logo na 25%, banera na 75%, bloku lewego na 45%, prawego na 55%, znacznika tabeli 90%

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera, bloku prawego i znacznika tabeli

    R.4.8 Ustawiono obramowanie o szerokości 1px linią kreskowaną, żółtą (dowolny odcień) dla znacznika tabeli

    R.4.9 W momencie najechania kursorem na pojedynczy wiersz tabeli kolor tła wiersza zmienia się na #9370DB a czcionki na żółty (dowolny odcień) (np. za pomocą pseudoklasy hover)

    ok. 2 min
    Polecenie z arkusza

    Dla znacznika tabeli: biały kolor czcionki, wyrównanie tekstu do środka, szerokość 90%, obramowanie 1 px, kreskowane, żółte. W momencie najechania kursorem na pojedynczy wiersz tabeli, kolor tła wiersza zmienia się na #9370DB a czcionki na żółty

    Biały tekst (R.4.3 razem z banerem i stopką), wyrównanie do środka (R.4.6 razem z banerem i blokiem prawym), szerokość 90% (R.4.5), kreskowane żółte obramowanie (R.4.8) i pseudoklasa tr:hover (R.4.9).

    styl4.css CSS zmienione: 12 linii
    :root {
        --indigo: #4B0082;
        --moccasin: #FFE4B5;
        --purple: #9370DB;
    }
    
    body {
        font-family: Helvetica, Arial, sans-serif;
        background-color: var(--moccasin);
    }
    
    header,
    .columns {
        display: flex;
    }
    
    #banner {
        background-color: var(--indigo);
        color: white;
        text-align: center;
        width: 75%;
        height: 100px;
        font-size: 150%;
    }
    
    #logo {
        width: 25%;
        height: 100px;
    }
    
    #left {
        width: 45%;
        height: 300px;
    }
    
    #right {
        width: 55%;
        height: 300px;
        text-align: center;
    }
    
    main {
        background-color: var(--indigo);
        padding: 60px;
    }
    
    footer {
        background-color: var(--indigo);
        color: white;
        padding: 40px;
    }
    
    form {
        margin: 40px;
    }
    
    table {
        color: white;
        text-align: center;
        width: 90%;
        border: 1px dashed yellow;
    }
    
    tr:hover {
        background-color: var(--purple);
        color: yellow;
    }
    Podgląd strony po tym kroku (waga.php)
  21. Etap 4: Skrypt PHP

    Kroki 21-23 · po tym etapie masz 38 z 40 kryteriów (pkt)

    Krok 21: Dane z formularza, obliczenie i wypisanie wyniku

    Kryteria: , , ,

    R.5.1 Skrypt napisano w języku PHP i zawiera on co najmniej jedną instrukcję poprawną składniowo

    R.5.4 W skrypcie działającym na danych przesłanych przez formularz zastosowano tablicę $_POST, zapis musi być poprawny składniowo i logicznie

    R.5.6 Skrypt 1 liczy wskaźnik BMI na podstawie danych z formularza, wzór np. $waga / ($wzrost * $wzrost) * 10000;

    R.5.7 Skrypt 1 wyświetla dane i obliczenia według wzoru: „Twoja waga: <podana_waga>; Twój wzrost: <podany_wzrost> BMI wynosi: <obliczona_wartość>”

    ok. 4 min
    Polecenie z arkusza

    Napisany w języku PHP, w pliku waga.php. Działanie skryptu 1, który odbiera dane przesłane z formularza: Skrypt odbiera dane z dwóch pól edycyjnych. Jeśli przynajmniej jedno pole edycyjne jest puste, nie jest wykonywana żadna akcja. Jeżeli wpisano dane, skrypt liczy wskaźnik BMI zgodnie ze wzorem znajdującym się na obrazie wzor.png (otrzymaną wartość należy pomnożyć przez 10000, gdyż wzrost podany jest w centymetrach). Dane i obliczenia są wyświetlone według wzoru: „Twoja waga: <podana_waga>; Twój wzrost: <podany_wzrost> BMI wynosi: <obliczona_wartość>”, łamanie linii przed „BMI”

    Logika PHP stoi na górze pliku, przed <!DOCTYPE html> - najpierw dane, potem HTML, który je wypisuje (R.5.1).

    • e() zamienia wartość na tekst i przepuszcza go przez htmlspecialchars, więc znaki <, >, & i cudzysłowy pokażą się jako tekst,
    • $_POST['waga'] ?? null - wartość pola albo null, gdy formularza nie wysłano (R.5.4),
    • filter_var(..., FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]) zwraca liczbę albo false - dla pustego pola, tekstu, zera i liczby mniejszej od 1. Warunek !== false dla obu pól daje zachowanie z arkusza: puste pole - brak akcji, a przy okazji żaden tekst ani zero nie trafi do dzielenia,
    • wzór z wzor.png z mnożeniem przez 10 000, bo wzrost jest w centymetrach (R.5.6),
    • w bloku prawym, pod formularzem, if (...): / endif; wypisuje paragraf z danymi i wynikiem, z <br> przed „BMI” (R.5.7).

    Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2 - tu po wysłaniu 70 i 170: „BMI wynosi: 24.221453287197”, jak na obrazie 2. Sprawdzone też: pierwsze wejście, puste pole, tekst zamiast liczby i wzrost 0 - strona nie wypisuje wyniku i nie zgłasza błędu.

    waga.php PHP zmienione: 16 linii
    <?php
    function e($value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $weight = filter_var($_POST['waga'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $height = filter_var($_POST['wzrost'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $bmi = null;
    if ($weight !== false && $height !== false) {
        $bmi = $weight / ($height * $height) * 10000;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
    <?php if ($bmi !== null): ?>
                <p>Twoja waga: <?= e($weight) ?>; Twój wzrost: <?= e($height) ?><br>BMI wynosi: <?= e($bmi) ?></p>
    <?php endif; ?>
            </section>
        </div>
        <main>
            <table>
                <thead>
                    <tr>
                        <th>lp.</th>
                        <th>Interpretacja</th>
                        <th>zaczyna się od...</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
            <a href="kw2.jpg">Wynik działania kwerendy 2</a>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  22. Krok 22: PDO i przedział BMI z tabeli bmi

    Kryteria: , ,

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

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

    R.5.8 Skrypt 1 wyznacza przedział BMI, zgodnie z tabelą bmi w bazie danych i przypisuje wartość 1 dla niedowagi, 2 dla wagi prawidłowej, 3 dla nadwagi i 4 dla otyłości

    ok. 4 min
    Polecenie z arkusza

    Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie egzamin. Następnie skrypt wyznacza przedział BMI, zgodnie z wartościami, jakie są umieszczone w tabeli i przypisuje wartość 1 dla niedowagi, 2 dla wagi prawidłowej, 3 dla nadwagi i 4 dla otyłości. Po wykonaniu operacji na bazie skrypt zamyka połączenie z serwerem

    • new PDO(...) - localhost, baza egzamin w adresie DSN, root, puste hasło (R.5.2), PDO::ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, a catch zapisuje neutralny komunikat,
    • zamiast przepisywać granice do kodu, skrypt pyta o nie tabelę bmi: SELECT id FROM bmi WHERE wart_min <= ? ORDER BY wart_min DESC LIMIT 1 - spośród przedziałów, które zaczynają się nie wyżej niż obliczone BMI, bierze ten o największym początku. Identyfikatory w tabeli to dokładnie numery z arkusza: 1 niedowaga, 2 waga prawidłowa, 3 nadwaga, 4 otyłość (R.5.8). Porównanie z samym początkiem przedziału zamyka dziury między granicami całkowitymi (BMI 18,6 trafia do niedowagi),
    • BMI trafia do zapytania jako parametr ? zapytania przygotowanego (prepare + execute) - dane nie są doklejane do treści SQL,
    • finally wykonuje się po sukcesie i po błędzie: $pdo = null zamyka połączenie (R.5.3).
    waga.php PHP zmienione: 20 linii
    <?php
    function e($value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $weight = filter_var($_POST['waga'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $height = filter_var($_POST['wzrost'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $bmi = null;
    if ($weight !== false && $height !== false) {
        $bmi = $weight / ($height * $height) * 10000;
    }
    
    $ranges = [];
    $error = null;
    $saveError = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
    
        if ($bmi !== null) {
            $find = $pdo->prepare('SELECT id FROM bmi WHERE wart_min <= ? ORDER BY wart_min DESC LIMIT 1;');
            $find->execute([$bmi]);
            $rangeId = (int) $find->fetchColumn();
        }
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
    <?php if ($bmi !== null): ?>
                <p>Twoja waga: <?= e($weight) ?>; Twój wzrost: <?= e($height) ?><br>BMI wynosi: <?= e($bmi) ?></p>
    <?php endif; ?>
            </section>
        </div>
        <main>
            <table>
                <thead>
                    <tr>
                        <th>lp.</th>
                        <th>Interpretacja</th>
                        <th>zaczyna się od...</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
            <a href="kw2.jpg">Wynik działania kwerendy 2</a>
        </footer>
    </body>
    </html>

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

  23. Krok 23: Zapis pomiaru: zapytanie 1 przygotowane

    Kryteria:

    R.5.5 Skrypt 1 wysyła do bazy danych zapytanie 1 zmodyfikowane tak, że dane wstawiane do tabeli są wyliczone z danych formularza lub zwrócone funkcją PHP np. date('Y-m-d') lub Skrypt 2 wysyła do bazy zapytanie 2

    ok. 3 min
    Polecenie z arkusza

    Skrypt wysyła do bazy danych zmodyfikowane zapytanie 1 wstawiające dane do bazy: bmi_id – wyznaczony przedział np. 3, jeśli obliczone BMI to nadwaga; data_pomiaru – aktualna data wyznaczona funkcją PHP, w formacie Y-m-d; wynik – obliczony wskaźnik BMI

    Zapytanie 1 z trzema parametrami ?, a w execute ich wartości w tej samej kolejności: przedział, date('Y-m-d') (dzisiejsza data w formacie bazy) i obliczone BMI (R.5.5). Nie trzeba pilnować apostrofów wokół daty - zajmuje się tym PDO.

    Zapis ma własny try/catch: gdy się nie powiedzie, pod wynikiem pojawi się „Nie udało się zapisać wyniku”, a BMI i tak jest wyświetlone. Sprawdzone w bazie po wysłaniu 70 i 170: rekord z bmi_id = 2, dzisiejszą datą (2026-11-10) i wynikiem 24 - kolumna wynik jest całkowita, więc baza zapisuje wartość bez części ułamkowej. Dla 54, 74, 80 i 95 kg przy 170 cm zapisały się przedziały 1, 2, 3 i 4.

    Typowe błędy

    Formularz wysyłany ponownie (F5 po wysłaniu) dopisuje kolejny rekord. Typowa odpowiedź na to - przekierowanie po zapisie (wzorzec PRG) - wymagałaby przechowania wyniku do wyświetlenia (np. w sesji), a arkusz każe pokazać wynik w odpowiedzi na wysłanie formularza.

    waga.php PHP zmienione: 10 linii
    <?php
    function e($value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $weight = filter_var($_POST['waga'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $height = filter_var($_POST['wzrost'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $bmi = null;
    if ($weight !== false && $height !== false) {
        $bmi = $weight / ($height * $height) * 10000;
    }
    
    $ranges = [];
    $error = null;
    $saveError = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
    
        if ($bmi !== null) {
            $find = $pdo->prepare('SELECT id FROM bmi WHERE wart_min <= ? ORDER BY wart_min DESC LIMIT 1;');
            $find->execute([$bmi]);
            $rangeId = (int) $find->fetchColumn();
    
            try {
                $insert = $pdo->prepare('INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (?, ?, ?);');
                $insert->execute([$rangeId, date('Y-m-d'), $bmi]);
            } catch (PDOException $exception) {
                $saveError = 'Nie udało się zapisać wyniku';
            }
        }
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
    <?php if ($bmi !== null): ?>
                <p>Twoja waga: <?= e($weight) ?>; Twój wzrost: <?= e($height) ?><br>BMI wynosi: <?= e($bmi) ?></p>
    <?php endif; ?>
    <?php if ($saveError !== null): ?>
                <p><?= e($saveError) ?></p>
    <?php endif; ?>
            </section>
        </div>
        <main>
            <table>
                <thead>
                    <tr>
                        <th>lp.</th>
                        <th>Interpretacja</th>
                        <th>zaczyna się od...</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
            <a href="kw2.jpg">Wynik działania kwerendy 2</a>
        </footer>
    </body>
    </html>

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

  24. Etap 5: Skrypt PHP: tabela przedziałów

    Krok 24 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 24: Zapytanie 2 i wiersze tabeli

    Kryteria: ,

    R.2.9 W bloku głównym umieszczono tabelę o trzech kolumnach i przynajmniej jednym wierszu, użyto znaczniki <table>, <tr>, <td> i ich zamknięcia, generowane skryptem lub HTML

    R.5.9 Skrypt 2 wyświetla otrzymane dane w komórkach tabeli zgodnie z obrazem 2 arkusza egzaminacyjnego

    ok. 3 min
    Polecenie z arkusza

    Działanie skryptu 2: Wysyła do bazy danych zapytanie 2. Dane otrzymane z bazy są umieszczane w kolejnych wierszach tabeli, w odpowiednich komórkach, tak jak na Obrazie 2

    $pdo->query(...)->fetchAll(PDO::FETCH_ASSOC) - zapytanie 2 i cztery przedziały w tablicy $ranges, z polami dostępnymi po nazwach. W <tbody> pętla w składni alternatywnej foreach (...): / endforeach;, między nimi zwykły HTML wiersza, a w komórkach skrócone <?= ... ?> z e(). Trzy komórki w kolejności nagłówków (R.2.9, R.5.9); przy awarii bazy - jeden wiersz z komunikatem. Podgląd: cała strona po wysłaniu 70 i 170, jak na obrazie 2.

    waga.php PHP zmienione: 13 linii
    <?php
    function e($value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $weight = filter_var($_POST['waga'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $height = filter_var($_POST['wzrost'] ?? null, FILTER_VALIDATE_FLOAT, ['options' => ['min_range' => 1]]);
    $bmi = null;
    if ($weight !== false && $height !== false) {
        $bmi = $weight / ($height * $height) * 10000;
    }
    
    $ranges = [];
    $error = null;
    $saveError = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=egzamin;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ]);
        $ranges = $pdo->query('SELECT id, informacja, wart_min FROM bmi;')->fetchAll(PDO::FETCH_ASSOC);
    
        if ($bmi !== null) {
            $find = $pdo->prepare('SELECT id FROM bmi WHERE wart_min <= ? ORDER BY wart_min DESC LIMIT 1;');
            $find->execute([$bmi]);
            $rangeId = (int) $find->fetchColumn();
    
            try {
                $insert = $pdo->prepare('INSERT INTO wynik (bmi_id, data_pomiaru, wynik) VALUES (?, ?, ?);');
                $insert->execute([$rangeId, date('Y-m-d'), $bmi]);
            } catch (PDOException $exception) {
                $saveError = 'Nie udało się zapisać wyniku';
            }
        }
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Twój wskaźnik BMI</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <section id="banner">
                <h2>Oblicz wskaźnik BMI</h2>
            </section>
            <section id="logo">
                <img src="wzor.png" alt="liczymy BMI">
            </section>
        </header>
        <div class="columns">
            <section id="left">
                <img src="rys1.png" alt="zrzuć kalorie!">
            </section>
            <section id="right">
                <h1>Podaj dane</h1>
                <form method="post">
                    <label for="weight">Waga:</label>
                    <input type="number" id="weight" name="waga"><br>
                    <label for="height">Wzrost [cm]:</label>
                    <input type="number" id="height" name="wzrost"><br>
                    <button type="submit">Licz BMI i zapisz wynik</button>
                </form>
    <?php if ($bmi !== null): ?>
                <p>Twoja waga: <?= e($weight) ?>; Twój wzrost: <?= e($height) ?><br>BMI wynosi: <?= e($bmi) ?></p>
    <?php endif; ?>
    <?php if ($saveError !== null): ?>
                <p><?= e($saveError) ?></p>
    <?php endif; ?>
            </section>
        </div>
        <main>
            <table>
                <thead>
                    <tr>
                        <th>lp.</th>
                        <th>Interpretacja</th>
                        <th>zaczyna się od...</th>
                    </tr>
                </thead>
                <tbody>
    <?php foreach ($ranges as $range): ?>
                    <tr>
                        <td><?= e($range['id']) ?></td>
                        <td><?= e($range['informacja']) ?></td>
                        <td><?= e($range['wart_min']) ?></td>
                    </tr>
    <?php endforeach; ?>
    <?php if ($error !== null): ?>
                    <tr>
                        <td colspan="3"><?= e($error) ?></td>
                    </tr>
    <?php endif; ?>
                </tbody>
            </table>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
            <a href="kw2.jpg">Wynik działania kwerendy 2</a>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (waga.php)
  25. Etap 6: Porównanie z wersją podstawową

    Krok 25 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 25: Co jest inaczej i którą wersję wybrać na egzaminie

    ok. 3 min

    Obie wersje dają komplet 40 punktów. Różnice:

    wersja podstawowawersja nowoczesna
    blokisześć <section> jedna pod drugą<header>, kontener kolumn, <main> i <footer>
    układfloat: left i clear: bothdisplay: flex na <header> i .columns
    kolorywpisane w każdej regulezmienne --indigo, --moccasin, --purple
    formularznapisy przed polami, <input type="submit"><label for> i <button>
    bibliotekamysqli (tabela 1 arkusza), dwa połączeniaPDO z wyjątkami, jedno połączenie
    dane z formularzaempty (w Dobrych praktykach is_numeric)filter_var z FILTER_VALIDATE_FLOAT
    przedział BMIdrabinka if z granicami w kodziezapytanie do tabeli bmi
    zapisINSERT z wklejonymi zmiennymizapytanie przygotowane z ?
    wypisywaniewprost (zabezpieczone w Dobrych praktykach)zawsze przez e()
    błąd bazy„Fatal error” ze ścieżką plikucatch i komunikat, wynik BMI dalej widoczny

    Sprawdzone na prawdziwym PHP: opis przedziału ze znacznikiem <s> ta wersja pokazuje dosłownie, a bez bazy egzamin strona liczy BMI, informuje, że wyniku nie zapisano, i wyświetla tabelę z komunikatem „Baza danych jest chwilowo niedostępna”.

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 arkusza i łatwiej ją napisać bez dokumentacji; nowoczesna oddziela logikę od wyglądu i nie wywraca się na złych danych ani przy awarii bazy - klucz przyjmuje obie.

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

  26. Etap 7: Oddanie pracy

    Krok 26 · po tym etapie masz 40 z 40 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny, zapisz go w folderze z numerem PESEL, jako przeglądarka.txt. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. W folderze zdającego: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, przeglądarka.txt, przeskalowany rys1.png, styl4.css, waga.php i wzor.png. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem PESEL.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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