Przejdź do głównej treści
INF.03-02-26.01-SGStyczeń 2026 · 44 kroki · ok. 80 min · 40 kryteriów z klucza

Rozwiązanie krok po kroku: Portal Zdrowy bazarek (Wersja podstawowa)

Rozwiązanie buduje portal „Zdrowy bazarek”: baza bazar (towary z ceną i nazwą pliku zdjęcia, sklepy i tabela zamowienie, która łączy towar ze sklepem i liczbą kilogramów) i cztery zapytania - LIMIT, prosty SELECT, warunek na identyfikator i INSERT z kluczem nadawanym automatycznie - potem dwie grafiki (przezroczyste tło jabłka i przeskalowany szyld), strona index.php z paskiem owoców, blokiem bocznym i formularzem oraz trzy skrypty PHP: zdjęcia owoców wypisane z bazy, lista rozwijana towarów i zamówienie, które liczy wartość (cena × kilogramy) i zapisuje się w bazie.

Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty są najpierw pisane najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row, isset), a na końcu zostają przerobione na wersję z prawdziwych projektów: walidacja liczby kilogramów, zapytania przygotowane, kwota w złotych z dwoma miejscami po przecinku i formularz, który pamięta wybrany towar.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: układ na siatce CSS, kolory w zmiennych i PHP na PDO z zapytaniami przygotowanymi od pierwszej linii - obie wersje są zgodne z kluczem.

Baza i zdjęcia pochodzą z prawdziwego archiwum pliki3-1 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu. Podgląd strony od kroków z PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 na bazie z arkusza; od Skryptu 3 pokazuje zamówienie z ilustracji 5 (pietruszka, 30 kg).

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

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych bazar

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie bazar, z zestawem polskich znaków (np. utf8_polish_ci)

    Rozpakuj pliki3-1.7z z pulpitu (hasło baz@rEk100% - małpa zamiast „a”, wielkie E i znak procentu na końcu) i załóż folder z numerem zdającego. W phpMyAdmin: Nowa, nazwa bazar (nie „bazarek” - tak nazywa się strona, a nie baza), porównywanie utf8_polish_ci.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie bazar - skrypty łączą się z bazą po nazwie, więc literówka zabiera też punkty za skrypty (R.5.1).

  2. Krok 2: Import tabel z pliku baza-nowa.sql

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabele z pliku baza-nowa.sql do utworzonej bazy

    Zaznacz bazę bazar, potem Import → baza-nowa.sql → Wykonaj. Powstają trzy tabele z ilustracji 1: towar (nazwa, rodzaj, cena, nazwa pliku ze zdjęciem), sklep i zamowienie, która kluczami obcymi wskazuje towar i sklep i zapisuje liczbę kilogramów.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych bazar - plik import.png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel

    Print Screen, wklejasz do edytora grafiki i zapisujesz jako import.png. W tym arkuszu wszystkie zrzuty - import i zapytania - idą do PNG.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: dziesięć pierwszych towarów

    Kryteria: ,

    R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające 10 pierwszych rekordów z tabeli towar , jedynie pola nazwa i plik. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT nazwa, plik FROM towar LIMIT 10; oraz na zrzucie widocznych jest dokładnie 10 wierszy z nazwami: gruszka, jabłko, banan, ananas, mango, winogrona, jagody, maliny, pomarańcza, cytryna

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające 10 pierwszych rekordów z tabeli towar, jedynie pola nazwa i plik

    • SELECT nazwa, plik - dwa pola,
    • FROM towar,
    • LIMIT 10 - zwraca tylko dziesięć pierwszych wierszy.

    Wynik: gruszka, jabłko, banan, ananas, mango, winogrona, jagody, maliny, pomarańcza, cytryna - każdy z nazwą pliku zdjęcia, jak w kluczu. Z tego zapytania Skrypt 1 zrobi pasek zdjęć. Zapytania zapisujesz w kwerendy.txt, zrzut jako kw1.png.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa, plik FROM towar LIMIT 10;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: identyfikatory i nazwy towarów

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie id i nazwę towarów. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT id, nazwa FROM towar; oraz na zrzucie widoczne są wyniki działania zapytania (nie wszystkie rekordy będą widoczne, 39 lub 40 rekordów)

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie identyfikator i nazwę towarów

    Dwa pola bez warunku: 39 wierszy (klucz: 39 lub 40). Na zrzucie nie zmieszczą się wszystkie - to w porządku, klucz o tym wie. Skrypt 2 zrobi z tego listę rozwijaną: identyfikator pójdzie do value, nazwa będzie widoczną treścią. Zrzut: kw2.png.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, plik FROM towar LIMIT 10;
    
    -- Zapytanie 2
    SELECT id, nazwa FROM towar;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: towar o identyfikatorze 1

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające jedynie rodzaj, nazwę i cenę towaru dla id = 1. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT rodzaj, nazwa, cena FROM towar WHERE id = 1; oraz na zrzucie widoczny jest dokładnie jeden rekord: owoc gruszka 5.00

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie rodzaj, nazwę i cenę towaru o identyfikatorze 1

    Trzy pola i warunek na klucz główny - zawsze najwyżej jeden wiersz: owoc gruszka 5.00. Zrzut: kw3.png. W Skrypcie 3 w miejscu 1 stanie identyfikator wybrany w formularzu, a cena posłuży do policzenia wartości zamówienia.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, plik FROM towar LIMIT 10;
    
    -- Zapytanie 2
    SELECT id, nazwa FROM towar;
    
    -- Zapytanie 3
    SELECT rodzaj, nazwa, cena FROM towar WHERE id = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: zamówienie 20 kg pomarańczy

    Kryteria:

    R.1.6 Wykonane zapytanie 4 wstawiające do tabeli zamowienie rekord o wartościach: towar o id 9, sklep o id 2, liczba kilogramów 20, klucz główny nadawany automatycznie. W pliku z kwerendami lub na zrzucie istnieje zapis np. INSERT INTO zamowienie(id_towar, id_sklep, liczba_kg) VALUES (9, 2, 20); (klucz główny pominięty lub NULL) oraz na zrzucie jest widoczny komunikat o poprawnie wykonanym zapytaniu lub tabela z dodanym rekordem

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: wstawiające do tabeli zamowienie rekord o wartościach: towar o identyfikatorze 9, sklep o identyfikatorze 2, liczba kilogramów 20, klucz główny nadawany automatycznie

    Wymień w nawiasie tylko trzy kolumny, które wypełniasz - id pomiń i baza nada je sama (AUTO_INCREMENT). Nowe zamówienie dostało identyfikator 49: 20 kg pomarańczy (towar 9) dla sklepu „dino” (sklep 2). Zrzut z komunikatem albo z tabelą po wstawieniu: kw4.png.

    Typowe błędy

    Wpisanie klucza ręcznie (VALUES (49, 9, 2, 20)) przeczy wymaganiu „klucz główny nadawany automatycznie” - klucz pomijasz albo podajesz NULL.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa, plik FROM towar LIMIT 10;
    
    -- Zapytanie 2
    SELECT id, nazwa FROM towar;
    
    -- Zapytanie 3
    SELECT rodzaj, nazwa, cena FROM towar WHERE id = 1;
    
    -- Zapytanie 4
    INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES (9, 2, 20);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika jabłka z przezroczystym tłem

    Kryteria:

    R.2.1 Grafika jablko.png lub jabłko.png ma przezroczyste tło

    ok. 4 min
    Polecenie z arkusza

    Dla grafiki jablko.png należy nadać tło przezroczyste i zapisać pod tą samą nazwą

    Tło jabłka to jednolity kremowy kolor. W GIMP-ie: Warstwa → Przezroczystość → Dodaj kanał alfa, potem różdżka (zaznaczanie ciągłych obszarów) kliknięta w tło i Delete. Różdżka zaznacza tylko piksele połączone z miejscem kliknięcia, więc jabłko i liść zostają; delikatny cień pod owocem ma inny kolor, więc też zostaje. Eksport do PNG pod tą samą nazwą. Po lewej oryginał, po prawej wynik na szachownicy, która oznacza przezroczystość - przezroczystych jest 14907 z 22 500 pikseli.

    Uwaga na nazwę: arkusz pisze jablko.png, ale w archiwum i w bazie (pole plik) jest jabłko.png z „ł”. Na egzaminie zapisujesz plik pod nazwą z archiwum - wtedy Skrypt 1 go znajdzie; klucz uznaje obie nazwy (R.2.1).

    Typowe błędy

    JPEG nie ma przezroczystości - eksport do .jpg zamieni przezroczyste tło na białe.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Grafika market.png: szerokość 300 px

    Kryteria:

    R.2.2 Grafika market.png przeskalowana z zachowaniem proporcji do szerokości dokładnie 300 px, odpowiadająca temu wysokość to 378 px ( ± 5 px)

    ok. 3 min
    Polecenie z arkusza

    Grafikę market.png należy przeskalować z zachowaniem proporcji do szerokości 300 px

    Oryginał ma 508 × 640 px. W GIMP-ie Obraz → Skaluj obraz, szerokość 300 px przy zamkniętym łańcuchu proporcji - wysokość wychodzi sama: 378 px (klucz: 378 ±5). Eksport pod tą samą nazwą, w PNG - szyld ma przezroczyste tło i ma je zachować.

    Typowe błędy

    Wpisanie samej szerokości przy otwartym łańcuchu zostawia wysokość 640 px - szyld jest zniekształcony i niezgodny z kluczem.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Plik index.php w HTML5

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie index.php. Zapisana w języku HTML5

    Deklaracja <!DOCTYPE html> i szkielet strony. Rozszerzenie .php, bo dojdą skrypty; na egzaminie plik leży w htdocs XAMPP-a i otwierasz go przez http://localhost/....

    index.php PHP nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  11. Krok 11: Język strony

    Kryteria:

    R.2.3 W pliku index.php znajduje się deklaracja HTML5 <!DOCTYPE HTML> i deklaracja języka zawartości witryny: polski np. <html lang="pl">

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny

    Atrybut lang="pl" w znaczniku <html> - razem z deklaracją HTML5 to jedno kryterium klucza.

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

    ok. 1 min
    Polecenie z arkusza

    Jawnie zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwszy element <head> - bez niego „wagę” i „Zamów” mogą wyświetlić się krzakami.

    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)
  13. Krok 13: Tytuł strony

    Kryteria:

    R.2.4 W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony "Zdrowy bazarek"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „Zdrowy bazarek”

    <title> w <head> - widać go na karcie przeglądarki. Z kodowaniem to drugie kryterium nagłówka strony.

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

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza

    ok. 1 min
    Polecenie z arkusza

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

    Nazwa pliku: styl.css (nie style.css). Całe formatowanie ma pochodzić z tego pliku - żadnych atrybutów style w HTML-u.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Bloki: nagłówek, nawigacja, główny, stopka

    Kryteria:

    R.2.5 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header, nav, main->aside+section, footer (dopuszcza się zastosowanie bloków pomocniczych)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3

    Klucz wymaga wprost header, nav, main z aside i section w środku oraz footer (R.2.5). Blok boczny i sekcję postawisz obok siebie w CSS - w HTML-u wystarczy, że oba są wewnątrz <main>.

    index.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
            </aside>
            <section>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Nagłówek strony

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: nagłówek pierwszego stopnia o treści „Zdrowy bazarek”

    Pierwszego stopnia, czyli <h1>. Blok nawigacyjny zostaje na razie pusty - zdjęcia owoców wypisze Skrypt 1.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
            </aside>
            <section>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Blok boczny: szyld

    Kryteria:

    R.2.7 W bloku bocznym umieszczony obraz z pliku market.png , z tekstem alternatywnym "bazarek"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku bocznego: obraz market.png z tekstem alternatywnym „bazarek”

    <img> z przeskalowanym plikiem i alt="bazarek".

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  18. Krok 18: Sekcja: akapit z poleceniem

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku sekcji: Paragraf o treści: „Wybierz owoc lub warzywo i podaj jego wagę:”

    Zwykły akapit <p> na początku sekcji.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Formularz wysyłany metodą POST

    Kryteria: ,

    R.2.8 W bloku sekcji umieszczony formularz

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

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyłający dane do tego samego pliku metodą bezpieczną

    method="post" - „metoda bezpieczna” w rozumieniu arkusza: dane jadą w treści żądania, a nie w adresie, więc nie zostają w historii przeglądarki ani w zakładkach. (W specyfikacji HTTP „bezpieczna” znaczy co innego - metodę, która niczego nie zmienia na serwerze, czyli GET - ale klucz R.3.3 rozstrzyga: POST.) Atrybut action pomijasz - formularz bez niego wysyła dane do bieżącego pliku (klucz: „poprawne również bez atrybutu action”).

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  20. Krok 20: Lista rozwijana towarów

    ok. 1 min
    Polecenie z arkusza

    Lista rozwijana wypełniona skryptem 2

    <select> z nazwą product - pod tą nazwą wybrany identyfikator trafi do $_POST. Opcji na razie nie ma, wypisze je Skrypt 2.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Krok 21: Pole liczby kilogramów

    Kryteria:

    R.3.5 Pole edycyjne jest typu number

    ok. 2 min
    Polecenie z arkusza

    Pole edycyjne przeznaczone do wpisywania jedynie liczb całkowitych

    type="number" - przeglądarka przyjmie tylko liczbę. Domyślny krok pola liczbowego to 1 (step="1"), więc przy próbie wysłania 2,5 przeglądarka zgłosi błąd - pole przyjmuje tylko liczby całkowite, jak chce arkusz. name="weight" to klucz w $_POST.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Przycisk „Zamów”

    Kryteria:

    R.3.4 Przycisk realizuje funkcję wysłania danych z formularza (input lub button z typem submit lub button bez typu)

    ok. 1 min
    Polecenie z arkusza

    Przycisk „Zamów” wysyłający dane z formularza do skryptu 3

    <button type="submit"> wysyła formularz; Skrypt 3 odczyta dane po przeładowaniu tej samej strony.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  23. Krok 23: Stopka

    Kryteria:

    R.2.6 W bloku nagłówkowym umieszczony <h1>: "Zdrowy bazarek", w bloku sekcji <p>, w stopce <p> z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: paragraf o treści: „Stronę opracował: ”, dalej wstawiony numer zdającego

    Akapit w <footer>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Z tym krokiem są już elementy z kryterium R.2.6: <h1>, akapit w sekcji i akapit w stopce.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  24. Etap 3: Styl CSS

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

    Krok 24: Plik styl.css: krój Georgia

    Kryteria:

    R.4.1 domyślne formatowanie wszystkich selektorów (*): krój czcionki Georgia, serif (dozwolona tylko taka kolejność)

    ok. 1 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: krój czcionki Georgia, w przypadku braku serif

    Selektor uniwersalny *. Kolejność krojów ma znaczenie: najpierw Georgia, na końcu rodzina zapasowa serif - klucz dopuszcza tylko taką.

    styl.css CSS nowy plik
    * {
        font-family: Georgia, serif;
    }
    Podgląd strony po tym kroku (index.php)
  25. Krok 25: Nagłówek i stopka

    Kryteria: , ,

    R.4.3 kolor czcionki: blok nagłówkowy i stopka - biały

    R.4.6 marginesy wewnętrzne (padding) : blok nagłówkowy i stopka - 2px

    R.4.7 wyrównanie tekstu do środka: blok nagłówkowy i stopka

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloku nagłówkowego i stopki: kolor tła ForestGreen, biały kolor czcionki, marginesy wewnętrzne 2 px, wyrównanie tekstu do środka

    Jedna reguła dla dwóch selektorów po przecinku. Marginesy wewnętrzne to padding.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    Podgląd strony po tym kroku (index.php)
  26. Krok 26: Blok nawigacyjny: ukryty nadmiar

    Kryteria:

    R.4.8 przepełnienie bloku: blok nawigacyjny - hidden

    ok. 2 min
    Polecenie z arkusza

    Dla bloku nawigacyjnego: kolor tła DarkKhaki, wysokość 150 px, w przypadku przepełnienia bloku pozostała jego zawartość jest ukryta (na ilustracji 2 jest 8 owoców – reszta nie zmieściła się w bloku i została ukryta)

    Zdjęcia mają po 150 px wysokości, czyli tyle, ile blok - mieści się dokładnie jeden rząd. Owoce, które nie zmieszczą się w szerokości okna, przechodzą do drugiego rzędu, a overflow: hidden go ucina: na wąskim ekranie widać mniej owoców, na szerokim więcej (podpis ilustracji 2). auto dodałoby pasek przewijania, a tego arkusz nie chce.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    nav {
        background-color: DarkKhaki;
        height: 150px;
        overflow: hidden;
    }
    Podgląd strony po tym kroku (index.php)
  27. Krok 27: Blok boczny i sekcja

    Kryteria: , ,

    R.4.2 kolor tła: blok nagłówkowy i stopka - ForestGreen, blok nawigacyjny - DarkKhaki, bloki boczny i sekcji - Khaki

    R.4.4 wysokość: blok nawigacyjny - 150px, bloki boczny i sekcji - 400px

    R.4.5 szerokość: bloki boczny i sekcji - 50% (width lub grid-template-columns lub flex)

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloku bocznego i sekcji: kolor tła Khaki, szerokość 50%, wysokość 400 px

    Jedna reguła dla obu bloków. Ta reguła zamyka kryteria kolorów tła (nagłówek, stopka, nawigacja, boczny, sekcja), wysokości i szerokości.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    nav {
        background-color: DarkKhaki;
        height: 150px;
        overflow: hidden;
    }
    aside, section {
        background-color: Khaki;
        width: 50%;
        height: 400px;
    }
    Podgląd strony po tym kroku (index.php)
  28. Krok 28: Układ bloków zgodny z ilustracją 3

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3

    Arkusz nie mówi, jak postawić blok boczny obok sekcji - wybierasz display: flex na <main>. Dzieci kontenera flex stają w rzędzie, a dwa razy 50% daje całą szerokość. Przy float trzeba by jeszcze dodać clear: both stopce; flex nie wypuszcza dzieci poza kontener, więc stopka sama zostaje pod spodem (R.3.1).

    Typowe błędy

    Bloki, które na siebie zachodzą (sprawdzane w inspektorze), zabierają punkt za układ, nawet gdy strona „na oko” wygląda dobrze.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    nav {
        background-color: DarkKhaki;
        height: 150px;
        overflow: hidden;
    }
    aside, section {
        background-color: Khaki;
        width: 50%;
        height: 400px;
    }
    main {
        display: flex;
    }
    Podgląd strony po tym kroku (index.php)
  29. Krok 29: Obraz w bloku bocznym

    Kryteria:

    R.4.9 styl jedynie dla obrazu w bloku bocznym: marginesy wewnętrzne - 2px, zewnętrzne - 10px, obramowanie 2px dotted ForestGreen, zaokrąglenie rogów 40px (dowolną metodą: id, klasa, potomek)

    ok. 2 min
    Polecenie z arkusza

    Jedynie dla obrazu w bloku bocznym: marginesy wewnętrzne 2 px, zewnętrzne 10 px, obramowanie linią kropkową o szerokości 2 px i kolorze ForestGreen, zaokrąglenie rogów 40 px

    „Jedynie dla obrazu w bloku bocznym” - samo img objęłoby też zdjęcia owoców. Selektor potomka aside img trafia tylko w obrazy wewnątrz <aside> (klucz dopuszcza też identyfikator albo klasę). dotted to linia z kropek.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    nav {
        background-color: DarkKhaki;
        height: 150px;
        overflow: hidden;
    }
    aside, section {
        background-color: Khaki;
        width: 50%;
        height: 400px;
    }
    main {
        display: flex;
    }
    aside img {
        padding: 2px;
        margin: 10px;
        border: 2px dotted ForestGreen;
        border-radius: 40px;
    }
    Podgląd strony po tym kroku (index.php)
  30. Krok 30: Akapity: większa kursywa

    Kryteria:

    R.4.10 styl selektora p: rozmiar czcionki 120%, kursywa

    ok. 1 min
    Polecenie z arkusza

    Dla selektora paragrafu: rozmiar czcionki 120%, kursywa

    Selektor znacznika p - zgodnie z uwagą arkusza. Działa na akapit w sekcji, stopkę i akapit z wynikiem zamówienia, który dopisze Skrypt 3.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Georgia, serif;
    }
    header, footer {
        background-color: ForestGreen;
        color: white;
        padding: 2px;
        text-align: center;
    }
    nav {
        background-color: DarkKhaki;
        height: 150px;
        overflow: hidden;
    }
    aside, section {
        background-color: Khaki;
        width: 50%;
        height: 400px;
    }
    main {
        display: flex;
    }
    aside img {
        padding: 2px;
        margin: 10px;
        border: 2px dotted ForestGreen;
        border-radius: 40px;
    }
    p {
        font-size: 120%;
        font-style: italic;
    }
    Podgląd strony po tym kroku (index.php)
  31. Etap 4: Skrypty PHP

    Kroki 31-41 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 31: Połączenie z bazą i zamknięcie na końcu

    Kryteria:

    R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy bazar oraz ostatnią operacją na bazie jest jej zamknięcie

    ok. 2 min
    Polecenie z arkusza

    Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie bazar. Po wykonaniu wszystkich operacji połączenie z bazą jest zamykane

    Pierwszy skrypt na stronie stoi w bloku nawigacyjnym, więc tam otwierasz połączenie: mysqli_connect z czterema argumentami łączy się z serwerem i od razu wybiera bazę. Uchwyt w zmiennej $connection posłuży wszystkim trzem skryptom. Ostatni blok PHP, pod formularzem, na razie tylko zamyka połączenie - Skrypt 3 dopiszesz nad tą linią (R.5.1). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    index.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  32. Krok 32: Skrypt 1: zapytanie 1

    Kryteria:

    R.5.2 Skrypt zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub zapytanie 2

    ok. 1 min
    Polecenie z arkusza

    Skrypt 1: wysyła do bazy danych zapytanie 1

    Treść zapytania w zmiennej, mysqli_query wysyła ją do bazy, a w $result zostaje wynik do odczytania wiersz po wierszu.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  33. Krok 33: Skrypt 1: zdjęcie każdego owocu

    Kryteria:

    R.5.4 Skrypt 1 wyświetla obrazy dla każdego wiersza pobranego z bazy, źródłem jest pole plik, tekstem alternatywnym jest nazwa (obrazy mogą być ukryte za sprawą właściwości CSS overflow, zamiast obrazu z jabłkiem może się wyświetlać tekst alternatywny)

    ok. 3 min
    Polecenie z arkusza

    Skrypt 1: dla każdego wiersza pobranego z bazy wyświetla obraz o pobranej z bazy nazwie pliku i tekście alternatywnym odpowiadającym nazwie owocu

    mysqli_fetch_row oddaje kolejny wiersz jako tablicę w kolejności pól z SELECT: $row[0] - nazwa, $row[1] - plik. Plik idzie do src, nazwa do alt. Cudzysłowy atrybutów wewnątrz napisu PHP poprzedzasz ukośnikiem \". W podglądzie pasek owoców; na szerokim ekranie zmieści się więcej niż 8 z ilustracji 2, na wąskim mniej - nadmiar ucina overflow: hidden.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  34. Krok 34: Skrypt 2: zapytanie 2

    ok. 1 min
    Polecenie z arkusza

    Skrypt 2: wysyła do bazy danych zapytanie 2

    Skrypt 2 piszesz wewnątrz <select> - to, co wypisze, stanie się opcjami listy. Zmiennych $query i $result używasz ponownie: pasek owoców jest już wypisany.

    index.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  35. Krok 35: Skrypt 2: opcje z identyfikatorem w value

    Kryteria: ,

    R.5.5 Skrypt 2 wypełnia listę rozwijaną z danymi pobranymi z bazy, atrybut value to id, wyświetlana wartość opcji to nazwa towaru

    R.2.9 Na stronie umieszczona lista rozwijana (w HTML lub skrypcie), zastosowane znaczniki < select> i <option> , pole edycyjne i przycisk "Zamów"

    ok. 2 min
    Polecenie z arkusza

    Skrypt 2: dla każdego wiersza pobranego z bazy generuje opcję listy rozwijanej, gdzie w atrybucie value znajduje się zwrócone pole id, a w treści opcji znajduje się nazwa towaru

    Widać nazwę, a formularz wyśle value, czyli identyfikator - zapytanie 3 szuka towaru po id. Rozwiń listę w podglądzie: 39 towarów, pierwsza gruszka, jak na ilustracji 4. Z opcjami lista spełnia kryterium R.2.9 (<select> i <option>, pole edycyjne i przycisk „Zamów”).

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  36. Krok 36: Skrypt 3: tylko po wysłaniu formularza

    ok. 2 min
    Polecenie z arkusza

    Skrypt 3, wykonywany tylko wtedy, gdy wysłano dane z formularza

    Przy zwykłym wejściu na stronę tablica $_POST jest pusta, po kliknięciu „Zamów” ma klucze product i weight. Warunek isset na jednym polu wystarczy. Zamknięcie połączenia stoi pod blokiem if, poza nim - wykona się zawsze, także bez wysłania formularza, i nadal jako ostatnia operacja na bazie.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  37. Krok 37: Skrypt 3: wartości z formularza

    Kryteria:

    R.5.6 Skrypt 3 stosuje tablicę $_POST dla danych wysłanych z formularza

    ok. 2 min
    Polecenie z arkusza

    Pobiera wartości z formularza: id towaru i liczbę kilogramów

    Obie wartości czekają w tablicy $_POST pod nazwami nadanymi polom (product, weight). Przepisz je do zmiennych o czytelnych nazwach. Podgląd pokazuje stronę po wybraniu pietruszki i wpisaniu 30 kg, jak na ilustracji 5 - na razie nic się nie zmienia, skrypt jeszcze niczego nie wypisuje.

    Typowe błędy

    Puste pole wagi kończy się w PHP 8 błędem krytycznym „Unsupported operand types: string * string” przy mnożeniu ceny przez wagę - strona urywa się w połowie (sprawdzone w PHP 8.2). Klucz tego nie sprawdza - zabezpieczenie jest w etapie „Dobre praktyki”.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  38. Krok 38: Skrypt 3: zapytanie 3 dla wybranego towaru

    Kryteria:

    R.5.3 Skrypt zawiera instrukcję wysyłającą do bazy danych zmodyfikowane zapytanie 3: sprawdzane jest id przesłane formularzem lub zmodyfikowane zapytanie 4: wstawiany jest rekord z id towaru i liczbą kg przesłaną zapytaniem

    ok. 2 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 3, tak że wybierany jest rekord o id wskazanym w formularzu

    Zapytanie 3, w którym zamiast 1 stoi $productId. Warunek na klucz główny zwraca jeden wiersz, więc wystarczy jedno mysqli_fetch_row bez pętli: w $row masz rodzaj, nazwę i cenę.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  39. Krok 39: Skrypt 3: wartość zamówienia

    Kryteria:

    R.5.7 Skrypt 3 oblicza wartość iloczynu ceny zwróconej zapytaniem oraz liczby kilogramów wysłanej z formularza

    ok. 2 min
    Polecenie z arkusza

    Oblicza wartość na podstawie zwróconej zapytaniem ceny oraz liczby kilogramów wysłanej z formularza

    Wartość to cena razy kilogramy. Cena przychodzi z bazy jako tekst „14.70”, a liczba kilogramów z formularza jako tekst „30” - operator * w PHP zamienia oba na liczby: 14,70 × 30 = 441.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                        $value = $row[2] * $weight;
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  40. Krok 40: Skrypt 3: akapit z wartością

    Kryteria:

    R.5.8 Skrypt 3 wyświetla w paragrafie tekst: „<rodzaj> <nazwa> wartość: <wartość> zł”, gdzie w znakach <> umieszczono zwrócone zapytaniem pola i wyliczoną wartość

    ok. 2 min
    Polecenie z arkusza

    Wypisuje w dodatkowym paragrafie pod formularzem tekst: „<rodzaj> <nazwa> wartość: <wartość> zł”, gdzie w znakach <> umieszczono zwrócone zapytaniem pola i wyliczoną wartość

    Blok PHP stoi pod formularzem, więc akapit pojawi się pod nim. Podgląd: „warzywo pietruszka wartość: 441 zł” - dokładnie jak na ilustracji 5. PHP wypisuje liczbę bez zbędnych zer, więc 441,0 staje się „441”.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                        $value = $row[2] * $weight;
                        echo "<p>$row[0] $row[1] wartość: $value zł</p>";
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  41. Krok 41: Skrypt 3: zapis zamówienia

    Kryteria: ,

    R.5.9 Skrypt 3 wstawia do tabeli zamowienie rekord z danymi pobranymi z formularza (należy sprawdzić w phpMyAdmin)

    R.5.10 W skryptach zastosowana przynajmniej jedna zmienna oraz nazwy wszystkich zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 3 min
    Polecenie z arkusza

    Wstawia do bazy rekord za pomocą zmodyfikowanego zapytania 4, w ten sposób, że w miejscu id towaru i liczby kilogramów są wpisywane odpowiednie wartości wysłane z formularza (id sklepu pozostaje bez zmian lub jest pomijane)

    Zapytanie 4 z $productId i $weight w miejscu 9 i 20; sklep 2 zostaje. Sprawdzone, tak jak każe klucz, w bazie: po zamówieniu pietruszki w tabeli zamowienie przybył rekord 50 (towar 12, sklep 2, 30 kg). Wszystkie zmienne mają nazwy mówiące, co przechowują ($connection, $query, $result, $row, $productId, $weight, $value) - to kryterium R.5.10.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                        $value = $row[2] * $weight;
                        echo "<p>$row[0] $row[1] wartość: $value zł</p>";
                        $query = "INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES ($productId, 2, $weight);";
                        mysqli_query($connection, $query);
                    }
                    mysqli_close($connection);
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  42. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 42-43 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 42: Zamówienie: walidacja wagi i zapytania przygotowane

    ok. 4 min
    Polecenie z arkusza

    Skrypt 3: pobiera wartości z formularza, wysyła zmodyfikowane zapytanie 3, oblicza wartość, wypisuje ją w paragrafie i wstawia rekord zmodyfikowanym zapytaniem 4

    Wersja z egzaminu sprawdzona dwoma „złośliwymi” wysłaniami. Puste pole wagi kończy stronę błędem PHP „Unsupported operand types: string * string” - w PHP 8 mnożenie ceny przez pusty tekst jest błędem, a nie zerem. Waga -5 przechodzi bez słowa: strona pisze „wartość: -73.5 zł”, a w tabeli zamowienie ląduje zamówienie na minus 5 kg (pole type="number" przyjmuje liczby ujemne). Poprawki: rzutowanie (int) i warunek > 0 dla obu wartości (inaczej komunikat zamiast zamówienia), zapytania przygotowane (mysqli_prepare + mysqli_stmt_bind_param), sprawdzenie, czy towar istnieje (identyfikator spoza bazy, np. 999 wysłany z pominięciem formularza, daje komunikat „Nie ma takiego towaru.” zamiast błędu klucza obcego), i kwota przez number_format - dwa miejsca po przecinku i polski przecinek: „441,00 zł”. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 22 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            while ($row = mysqli_fetch_row($result)) {
                                echo "<option value=\"$row[0]\">$row[1]</option>";
                            }
                        ?>
                    </select>
                    <input type="number" name="weight">
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    $productId = (int) ($_POST["product"] ?? 0);
                    $weight = (int) ($_POST["weight"] ?? 0);
                    if ($productId > 0 && $weight > 0) {
                        $statement = mysqli_prepare($connection, "SELECT rodzaj, nazwa, cena FROM towar WHERE id = ?");
                        mysqli_stmt_bind_param($statement, "i", $productId);
                        mysqli_stmt_execute($statement);
                        $product = mysqli_fetch_row(mysqli_stmt_get_result($statement));
                        if ($product) {
                            $value = $product[2] * $weight;
                            echo "<p>" . htmlspecialchars($product[0] . " " . $product[1]) . " wartość: " . number_format($value, 2, ",", " ") . " zł</p>";
                            $statement = mysqli_prepare($connection, "INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES (?, 2, ?)");
                            mysqli_stmt_bind_param($statement, "ii", $productId, $weight);
                            mysqli_stmt_execute($statement);
                        } else {
                            echo "<p>Nie ma takiego towaru.</p>";
                        }
                    } elseif (isset($_POST["product"])) {
                        echo "<p>Podaj liczbę kilogramów większą od zera.</p>";
                    }
                    mysqli_close($connection);
                    /* Wersja z egzaminu:
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                        $value = $row[2] * $weight;
                        echo "<p>$row[0] $row[1] wartość: $value zł</p>";
                        $query = "INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES ($productId, 2, $weight);";
                        mysqli_query($connection, $query);
                    }
                    */
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  43. Krok 43: Formularz pamięta wybrany towar, waga od 1 kg

    ok. 3 min
    Polecenie z arkusza

    Lista rozwijana wypełniona skryptem 2. Pole edycyjne przeznaczone do wpisywania jedynie liczb całkowitych

    Na ilustracji 5 po zamówieniu na liście nadal stoi „pietruszka”, a wersja z egzaminu po przeładowaniu wraca do gruszki. Skrypt 2 dopisuje teraz selected do opcji, której identyfikator przyszedł z formularza - w podglądzie po zamówieniu wybrana jest pietruszka. W polu wagi atrybuty min="1" i required zatrzymują puste i ujemne wartości już w przeglądarce; kontrola w PHP z poprzedniego kroku zostaje, bo przeglądarkę da się ominąć. Nazwy towarów wypisujesz przez htmlspecialchars. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Zdrowy bazarek</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Zdrowy bazarek</h1>
        </header>
        <nav>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "bazar");
                $query = "SELECT nazwa, plik FROM towar LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[1]\" alt=\"$row[0]\">";
                }
            ?>
        </nav>
        <main>
            <aside>
                <img src="market.png" alt="bazarek">
            </aside>
            <section>
                <p>Wybierz owoc lub warzywo i podaj jego wagę:</p>
                <form method="post">
                    <select name="product">
                        <?php
                            $query = "SELECT id, nazwa FROM towar;";
                            $result = mysqli_query($connection, $query);
                            $selected = (int) ($_POST["product"] ?? 0);
                            while ($row = mysqli_fetch_row($result)) {
                                $mark = ($row[0] == $selected) ? " selected" : "";
                                echo "<option value=\"$row[0]\"$mark>" . htmlspecialchars($row[1]) . "</option>";
                            }
                            // while ($row = mysqli_fetch_row($result)) { echo "<option value=\"$row[0]\">$row[1]</option>"; }
                        ?>
                    </select>
                    <input type="number" name="weight" min="1" required>
                    <button type="submit">Zamów</button>
                </form>
                <?php
                    $productId = (int) ($_POST["product"] ?? 0);
                    $weight = (int) ($_POST["weight"] ?? 0);
                    if ($productId > 0 && $weight > 0) {
                        $statement = mysqli_prepare($connection, "SELECT rodzaj, nazwa, cena FROM towar WHERE id = ?");
                        mysqli_stmt_bind_param($statement, "i", $productId);
                        mysqli_stmt_execute($statement);
                        $product = mysqli_fetch_row(mysqli_stmt_get_result($statement));
                        if ($product) {
                            $value = $product[2] * $weight;
                            echo "<p>" . htmlspecialchars($product[0] . " " . $product[1]) . " wartość: " . number_format($value, 2, ",", " ") . " zł</p>";
                            $statement = mysqli_prepare($connection, "INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES (?, 2, ?)");
                            mysqli_stmt_bind_param($statement, "ii", $productId, $weight);
                            mysqli_stmt_execute($statement);
                        } else {
                            echo "<p>Nie ma takiego towaru.</p>";
                        }
                    } elseif (isset($_POST["product"])) {
                        echo "<p>Podaj liczbę kilogramów większą od zera.</p>";
                    }
                    mysqli_close($connection);
                    /* Wersja z egzaminu:
                    if (isset($_POST["product"])) {
                        $productId = $_POST["product"];
                        $weight = $_POST["weight"];
                        $query = "SELECT rodzaj, nazwa, cena FROM towar WHERE id = $productId;";
                        $result = mysqli_query($connection, $query);
                        $row = mysqli_fetch_row($result);
                        $value = $row[2] * $weight;
                        echo "<p>$row[0] $row[1] wartość: $value zł</p>";
                        $query = "INSERT INTO zamowienie (id_towar, id_sklep, liczba_kg) VALUES ($productId, 2, $weight);";
                        mysqli_query($connection, $query);
                    }
                    */
                ?>
            </section>
        </main>
        <footer>
            <p>Stronę opracował: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  44. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę.

    W folderze z numerem zdającego: import.png, index.php, jabłko.png, kw1.png - kw4.png, kwerendy.txt, market.png, przeglądarka.txt, styl.css oraz pozostałe zdjęcia owoców z archiwum (Skrypt 1 ich używa). Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.