Przejdź do głównej treści
INF.03-11-25.06-SGCzerwiec 2025 · 50 kroków · ok. 87 min · 37 kryteriów z klucza

Rozwiązanie krok po kroku: Portal sprzedaży opon (Wersja podstawowa)

Rozwiązanie buduje portal sprzedaży opon: baza opony z trzema tabelami i czterema operacjami (ORDER BY z LIMIT, warunek na klucz, losowy rekord przez ORDER BY RAND() LIMIT 1 ze złączeniem, UPDATE obniżający ceny o 25%), zdjęcie opony z przezroczystym tłem przeskalowane do 250 px, strona opony.php bez formularza, za to odświeżana co 10 sekund przez header('refresh'), style w styl.css z kropkowanym obramowaniem i opływaniem oraz trzy skrypty PHP: dziesięć najtańszych opon w blokach z ikoną sezonu, „opona dnia” i losowe zamówienie z wyliczoną wartością.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się poleceniem z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Kod PHP jest najpierw pisany funkcjami z tabeli 1 arkusza (proceduralne mysqli), a na końcu zostaje przerobiony na wersję z prawdziwych projektów: wiersze czytane po nazwach kolumn, escapowanie danych, mapa ikon zamiast drabinki if i formatowanie kwot. W tym arkuszu nie ma formularza, więc nie ma też wstrzyknięć SQL do zablokowania - i nie ma JavaScriptu.

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 i PHP na PDO z logiką oddzieloną od HTML-u od pierwszej linii - obie wersje są zgodne z kluczem.

Baza i grafiki pochodzą z prawdziwego archiwum pliki8 (załącznik do pobrania na stronie arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu.

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

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych opony

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych opony , czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

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

    W przeglądarce otwierasz http://localhost/phpmyadmin, klikasz Nowa w lewym panelu, wpisujesz nazwę opony i z listy metod porównywania wybierasz utf8_polish_ci. Uwaga na nazwy: baza to opony, plik do importu opona.sql, a tabela z oponami w środku też nazywa się opony - trzy podobne słowa, które łatwo pomylić.

    Typowe błędy

    Nazwa bazy musi być dokładnie opony - skrypty PHP łączą się z bazą po nazwie, więc literówka odetnie punkty także za skrypty (R.5.2).

  2. Krok 2: Import tabel z pliku opona.sql

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych opony , czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabele z pliku opona.sql do utworzonej bazy.

    Wejdź do bazy opony (musi być zaznaczona w lewym panelu), karta Import, Wybierz plik → opona.sql z rozpakowanego archiwum, Wykonaj.

    Po imporcie są trzy tabele z ilustracji 1: klient (id, imie, nazwisko - 9 klientów), opony (nr_kat, producent, model, sezon, cena - 27 opon; sezon to letnia, zimowa albo uniwersalna) i zamowienie (id_zam, id, nr_kat, ilosc - 325 zamówień). Tabela zamowienie ma dwa klucze obce: id wskazuje klienta, nr_kat oponę - to po nr_kat złączysz ją z oponami w zapytaniu 3.

    Typowe błędy

    Import bez wcześniejszego wejścia do bazy opony tworzy tabele w innej bazie (np. test) - skrypty nie znajdą wtedy tabeli opony.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych opony , czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

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

    Klawisz Print Screen (cały ekran, nie Alt+PrtScr, który łapie tylko aktywne okno), wklejasz do edytora grafiki i zapisujesz jako import.png w folderze z numerem zdającego. W tym arkuszu wszystkie zrzuty (import i cztery kwerendy) są w PNG. Na zrzucie ma być widać komunikat phpMyAdmin o pomyślnym imporcie albo trzy tabele w bazie.

    Typowe błędy

    Wykadrowany zrzut (samo okno przeglądarki, bez paska zadań) nie jest oceniany - klucz mówi to wprost.

  4. Krok 4: Zapytanie 1: dziesięć najtańszych opon

    Kryteria: ,

    R.1.2 Zapisany plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1 wybierające pierwsze 10 rekordów z najtańszymi oponami (wszystkie pola). W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nr_kat, producent, model, sezon, cena FROM opony ORDER BY cena LIMIT 10; (lub SELECT * FROM opony ORDER BY cena LIMIT 10;) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 10 rekordów z wszystkimi polami

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające pierwsze 10 rekordów z najtańszymi oponami (wszystkie pola).

    Zakładka SQL w phpMyAdmin (przy zaznaczonej bazie opony). Klauzula po klauzuli:

    • SELECT * - „wszystkie pola”, więc tym razem gwiazdka jest właściwa (klucz dopuszcza też wypisanie pięciu kolumn).
    • FROM opony - tabela opon.
    • ORDER BY cena - od najtańszej (domyślne ASC).
    • LIMIT 10 - tylko pierwsze dziesięć wierszy posortowanego wyniku. Kolejność klauzul jest stała: LIMIT zawsze na końcu, po ORDER BY.

    Wynik: 10 opon, od uLFA AL135 za 101,50 zł. Zapytanie kopiujesz do pliku kwerendy.txt i robisz zrzut: kw1.png. To samo zapytanie wyśle skrypt 1 do bloku bocznego. Zrzuty zapytań 1-3 robisz przed zapytaniem 4, które zmieni ceny - klucz to przewiduje i cen nie ocenia.

    Typowe błędy

    LIMIT 10 bez ORDER BY cena daje dziesięć pierwszych opon z tabeli, nie dziesięć najtańszych. ORDER BY cena DESC dałoby najdroższe.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT * FROM opony ORDER BY cena LIMIT 10;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: opona o numerze katalogowym 9

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie producenta, model, sezon i cenę opony o numerze katalogowym 9. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczny jest dokładnie jeden rekord z danymi: uLFA, AL135 zimowa; oraz widoczna jest cena

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie producenta, model, sezon i cenę opony o numerze katalogowym 9.

    SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9 - cztery kolumny w kolejności z arkusza (bez nr_kat, bo „jedynie”) i warunek na klucz główny, więc wynik to jeden wiersz: uLFA, AL135, zimowa, 101,50 - dokładnie jak w kluczu. Zrzut: kw2.png. Skrypt 2 wyśle to zapytanie do sekcji „Opona dnia”.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT * FROM opony ORDER BY cena LIMIT 10;
    
    -- Zapytanie 2
    SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: jedno losowe zamówienie z modelem i ceną

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające jedynie identyfikator zamówienia i ilość oraz odpowiadające im model i cenę opony. Wybierany jest tylko jeden losowy rekord. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony USING (nr_kat) ORDER BY RAND() LIMIT 1; (lub porównanie kluczy po ON lub WHERE) oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczny jest dokładnie jeden rekord z 4 polami

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie identyfikator zamówienia i ilość oraz odpowiadające im model i cenę opony. Wybierany jest tylko jeden losowy rekord. Należy zastosować relację.

    Identyfikator i ilość są w zamowienie, model i cena w opony - „zastosować relację” znaczy złączyć tabele po nr_kat.

    • SELECT id_zam, ilosc, model, cena - cztery kolumny z dwóch tabel.
    • FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat - do każdego zamówienia dokładasz jego oponę; kolumna nazywa się tak samo w obu tabelach, więc poprzedzasz ją nazwą tabeli (klucz CKE pokazuje skrót USING (nr_kat)).
    • ORDER BY RAND() LIMIT 1 - przepis z ramki w arkuszu: RAND() nadaje każdemu wierszowi losową liczbę, sortowanie po niej tasuje wiersze, a LIMIT 1 bierze pierwszy. Każde wykonanie zwraca inne zamówienie.

    Wynik: jeden wiersz z czterema polami - na zrzucie kw3.png zamówienie 7: 4 sztuki modelu AL100 po 290,50 zł (ten sam rekord jest na ilustracji 2). Skrypt 3 wyśle to zapytanie do sekcji „Najnowsze zamówienie”.

    Typowe błędy

    LIMIT 1 bez ORDER BY RAND() zawsze zwraca to samo zamówienie - klucz wymaga losowania.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT * FROM opony ORDER BY cena LIMIT 10;
    
    -- Zapytanie 2
    SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;
    
    -- Zapytanie 3
    SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: obniżka cen opon letnich o 25%

    Kryteria:

    R.1.6 Wykonane zapytanie 4 aktualizujące cenę opon letnich obniżając ją o 25%. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE opony SET cena = cena - cena * 0.25 WHERE sezon = "letnia"; (opcjonalnie cena = 0.75 * cena) oraz wynik działania zapytania udokumentowany zrzutem, na którym jest komunikat o pomyślnym wykonaniu zapytania lub widoczna tabela ze zmienionymi wartościami

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 4: aktualizujące cenę opon letnich obniżając ją o 25%.

    To nie SELECT, tylko UPDATE - zapytanie zmienia dane:

    • UPDATE opony - którą tabelę,
    • SET cena = cena * 0.75 - nowa wartość liczona ze starej: cena po obniżce o 25% to 75% ceny, czyli cena * 0.75 (klucz przyjmuje też cena - cena * 0.25),
    • WHERE sezon = "letnia" - tylko opony letnie. Bez WHERE przecena objęłaby wszystkie 27 opon i nie da się tego cofnąć.

    phpMyAdmin odpowiada komunikatem „Zmodyfikowanych rekordów: 17” - to jest zrzut kw4.png (klucz przyjmuje też zrzut tabeli ze zmienionymi cenami). Plik kwerendy.txt ma komplet czterech zapytań. Od tej chwili strona pokaże niższe ceny opon letnich - ilustracja 2 w arkuszu pokazuje stan sprzed przeceny.

    Typowe błędy

    SET cena = 0.25 * cena obniża cenę o 75%, nie o 25%. Wykonanie zapytania dwa razy przecenia opony dwukrotnie - UPDATE nie jest idempotentny.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT * FROM opony ORDER BY cena LIMIT 10;
    
    -- Zapytanie 2
    SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;
    
    -- Zapytanie 3
    SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;
    
    -- Zapytanie 4
    UPDATE opony SET cena = cena * 0.75 WHERE sezon = "letnia";
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-20 · po tym etapie masz 15 z 37 kryteriów (pkt)

    Krok 8: Grafika opona.png: przezroczyste tło

    Kryteria:

    R.2.1 Grafika opona.png ma przezroczyste tło i widoczna jest opona

    ok. 4 min
    Polecenie z arkusza

    Cechy grafiki opona.png: wykonana na podstawie grafiki opona.jpg i zapisana w formacie PNG. Tło przezroczyste.

    Otwórz opona.jpg (385 × 542 px, opona na białym tle) w GIMP-ie. JPEG nie przechowuje przezroczystości, więc najpierw Warstwa → Przezroczystość → Dodaj kanał alfa. Potem narzędzie Zaznaczenie rozmyte (różdżka) z progiem ok. 20: klik w białe tło zaznacza cały obszar wokół opony, Edycja → Wyczyść (Delete) zamienia go w szachownicę przezroczystości. Białe odblaski wewnątrz felgi nie łączą się z tłem, więc różdżka ich nie zaznaczy. Zapis przez Eksportuj jako z rozszerzeniem .png - tylko PNG zachowa kanał alfa (klucz R.2.1: przezroczyste tło i widoczna opona).

    Typowe błędy

    Eksport do JPEG zamiast PNG spłaszcza przezroczystość na białe tło - kryterium R.2.1 pada, choć w GIMP-ie wszystko wyglądało dobrze.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Grafika opona.png: wysokość 250 px

    Kryteria:

    R.2.2 Grafika przeskalowana do wysokości 250 px, odpowiadająca temu szerokość wynosi 178 px (± 5 px)

    ok. 2 min
    Polecenie z arkusza

    Przeskalowana z zachowaniem proporcji do wysokości 250 px.

    Obraz → Skaluj obraz, wysokość 250 px z zamkniętym łańcuchem proporcji - szerokość wychodzi sama: 178 px (klucz: 178 ±5). Przeskaluj po usunięciu tła, na pełnej rozdzielczości różdżka pracuje dokładniej. Ponowny eksport do opona.png. Na stronie opona wyląduje w sekcji 1, gdzie ma 300 px wysokości - 250 px plus marginesy wewnętrzne obrazu zmieszczą się dokładnie.

    Typowe błędy

    Skalowanie do szerokości 250 px zamiast wysokości daje obraz 250 × 352 px - za wysoki na sekcję i niezgodny z kluczem.

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

  10. Krok 10: Plik opony.php w HTML5

    Kryteria:

    R.2.3 W pliku opony.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 2 min
    Polecenie z arkusza

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

    W edytorze zaznaczającym składnię tworzysz plik opony.php w folderze zdającego, obok grafik. Rozszerzenie .php, bo dojdą skrypty PHP - na razie to czysty HTML.

    Pierwsza linia <!DOCTYPE html> mówi przeglądarce, że dokument jest w HTML5. Dalej szkielet każdej strony: <html>, a w nim <head> (informacje o stronie) i <body> (to, co widać w oknie).

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

    Kryteria:

    R.2.3 W pliku opony.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    Atrybut lang="pl" w znaczniku <html>. Czytnik ekranu czyta wtedy tekst polską wymową, a przeglądarka dobiera słownik. Na stronie nic się nie zmienia - to informacja dla programów.

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

    Kryteria:

    R.2.3 W pliku opony.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwsza rzecz w <head>. „Jawnie” znaczy: wpisane w kodzie, nie zdane na domysł przeglądarki. Bez tej linii „Wartość zamówienia” i „zł” mogłyby wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8.

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

    Kryteria:

    R.2.4 Stronie nadany tytuł "OPONY”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „OPONY”.

    <title> w <head> - napis na karcie przeglądarki, nie nagłówek na stronie. Klucz R.2.4 sprawdza tekst „OPONY”.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.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.

    <link rel="stylesheet" href="styl.css"> w <head>. W tym arkuszu nazwa to styl.css - sprawdź ją w treści zadania, bo w innych arkuszach bywa style.css albo styles.css. Plik napiszesz po HTML.

    Typowe błędy

    Zła nazwa pliku w href to brak stylów i cały rezultat R.4 przepada, bo „formatowanie CSS pochodzi jedynie z tego arkusza”.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  15. Krok 15: Bloki semantyczne

    Kryteria:

    R.2.5 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: main->aside+section+section, footer

    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. Zawartość bloku głównego: blok boczny, sekcja 1 i sekcja 2.

    Z ilustracji 3: blok główny, a w nim blok boczny po lewej i dwie sekcje jedna pod drugą po prawej; na dole stopka. Nie ma bloku nagłówkowego - arkusz go nie wymienia i klucz R.2.5 też nie: main → aside + section + section, footer (nazwy w tabeli 2 arkusza).

    Sekcje dostają identyfikatory offer (opona dnia) i order (najnowsze zamówienie), bo arkusz nadaje im różne tła - w CSS trzeba je rozróżnić. Nazwy identyfikatorów i zmiennych piszesz w tym rozwiązaniu po angielsku (arkusz dopuszcza polski lub angielski); nazwy narzucone przez arkusz (opony.php, styl.css, klasa opona, kolumny bazy) zostają.

    Typowe błędy

    Dodanie <header> „dla porządku” nie zaszkodzi, ale <aside> poza <main> nie spełnia R.2.5.

    opony.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
            </aside>
            <section id="offer">
            </section>
            <section id="order">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  16. Krok 16: Blok boczny: odnośnik „więcej ofert”

    Kryteria:

    R.3.3 Utworzony odnośnik o treści „więcej ofert” jego kliknięcie otwiera stronę https://opona.pl/

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku bocznego: efekt działania skryptu 1. Paragraf z odnośnikiem o treści „więcej ofert” prowadzący do strony https://opona.pl/.

    Paragraf <p> z odnośnikiem <a href="https://opona.pl/"> - adres zewnętrzny w całości, z https://. Skrypt 1 (dziesięć bloków z oponami) dopiszesz nad paragrafem, bo arkusz wymienia go pierwszy. Klucz R.3.3 sprawdza, czy kliknięcie otwiera stronę; w podglądzie kliknięcia są zablokowane.

    Typowe błędy

    href="opona.pl" bez https:// to ścieżka względna - przeglądarka szuka pliku opona.pl w folderze strony.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
            </section>
            <section id="order">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  17. Krok 17: Sekcja 1: grafika opony

    Kryteria:

    R.2.7 W pierwszej sekcji umieszczona grafika opona z tekstem alternatywnym "Opona"

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji 1: grafika opona.png z tekstem alternatywnym o treści: „Opona”.

    <img> ze src wskazującym przygotowany plik PNG i tekstem alternatywnym z arkusza (klucz R.2.7). Przezroczyste tło widać dopiero, gdy sekcja dostanie kolor w CSS - wtedy przez tło opony prześwituje fiolet, nie biały prostokąt.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
            </section>
            <section id="order">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  18. Krok 18: Sekcja 1: nagłówek „Opona dnia”

    Kryteria:

    R.2.6 Umieszczone w pierwszej sekcji <h2>: „Opona dnia”, w drugiej sekcji <h2>: „Najnowsze zamówienie", oraz paragraf z numerem zdającego w bloku stopki

    ok. 1 min
    Polecenie z arkusza

    Nagłówek drugiego stopnia o treści: „Opona dnia”. Efekt działania skryptu 2.

    <h2> pod obrazem. Skrypt 2 dopisze pod nim trzy kolejne <h2> z danymi opony numer 9. Na ilustracji 2 nagłówki stoją po prawej od opony - to zrobi opływanie float z CSS, nie HTML.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  19. Krok 19: Sekcja 2: nagłówek „Najnowsze zamówienie”

    Kryteria:

    R.2.6 Umieszczone w pierwszej sekcji <h2>: „Opona dnia”, w drugiej sekcji <h2>: „Najnowsze zamówienie", oraz paragraf z numerem zdającego w bloku stopki

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji 2: nagłówek drugiego stopnia o treści: „Najnowsze zamówienie”. Efekt działania skryptu 3.

    <h2> w drugiej sekcji; skrypt 3 dopisze pod nim dwa <h2> z losowym zamówieniem. Klucz R.2.6 sprawdza oba nagłówki sekcji razem z paragrafem stopki.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  20. Krok 20: Stopka z numerem zdającego

    Kryteria:

    R.2.6 Umieszczone w pierwszej sekcji <h2>: „Opona dnia”, w drugiej sekcji <h2>: „Najnowsze zamówienie", oraz paragraf z numerem zdającego w bloku stopki

    ok. 1 min
    Polecenie z arkusza

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

    Paragraf <p> w <footer>. W tym rozwiązaniu po dwukropku stoi nazwisko autora - na egzaminie wpisujesz swój numer zdającego (PESEL), bo tego sprawdza klucz R.2.6. Struktura HTML jest kompletna - dalej style.

    opony.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  21. Etap 3: Styl CSS

    Kroki 21-30 · po tym etapie masz 26 z 37 kryteriów (pkt)

    Krok 21: Plik styl.css: krój czcionki

    Kryteria:

    R.4.1 Ustawiony domyślnie dla wszystkich selektorów (*): krój czcionki "Trebuchet MS", sans- serif (tylko taka kolejność)

    ok. 1 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: krój czcionki Trebuchet MS, w przypadku braku sans-serif.

    Utwórz plik styl.css obok opony.php. Selektor uniwersalny * obejmuje każdy element. font-family to lista: nazwa z dwóch słów w cudzysłowie ("Trebuchet MS"), potem rodzina zapasowa sans-serif - klucz R.4.1 mówi: tylko taka kolejność.

    styl.css CSS nowy plik
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    Podgląd strony po tym kroku (opony.php)
  22. Krok 22: Blok boczny: tło, wymiary, paski przewijania

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku bocznego #C5CAE9, pierwszej sekcji #9FA8DA, drugiej sekcji i selektora h3 #7986CB, stopki #283593

    R.4.4 Ustawiona wysokość bloku bocznego 600px obu sekcji 300px oraz szerokość bloku bocznego 40%, obu sekcji 60% (width lub grid-template-columns lub flex)

    R.4.7 Ustawiona dla bloku bocznego cecha overflow: auto;

    ok. 1 min
    Polecenie z arkusza

    Dla bloku bocznego: kolor tła #C5CAE9, szerokość 40%, wysokość 600 px, paski przewijania tylko w przypadku przepełnienia bloku.

    Selektor znacznika aside. Wysokość 600 px to dokładnie dwie sekcje po 300 px - blok boczny ma sięgać od góry pierwszej do dołu drugiej. „Paski tylko przy przepełnieniu” to overflow: auto (klucz R.4.7): dziesięć bloków z oponami będzie znacznie wyższe niż 600 px, więc pojawi się pionowy pasek jak na ilustracji 2.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    Podgląd strony po tym kroku (opony.php)
  23. Krok 23: Obie sekcje: wymiary

    Kryteria:

    R.4.4 Ustawiona wysokość bloku bocznego 600px obu sekcji 300px oraz szerokość bloku bocznego 40%, obu sekcji 60% (width lub grid-template-columns lub flex)

    ok. 1 min
    Polecenie z arkusza

    Dla obu sekcji: szerokość 60%, wysokość 300 px.

    Selektor section obejmuje obie sekcje naraz. 40% bloku bocznego plus 60% sekcji daje 100% szerokości.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        width: 60%;
        height: 300px;
    }
    Podgląd strony po tym kroku (opony.php)
  24. Krok 24: Sekcje: osobne kolory tła

    Kryteria:

    R.4.2 Ustawiony kolor tła dla bloku bocznego #C5CAE9, pierwszej sekcji #9FA8DA, drugiej sekcji i selektora h3 #7986CB, stopki #283593

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo kolor tła sekcji 1: #9FA8DA, sekcji 2: #7986CB.

    Dwie reguły po identyfikatorach - dokładają tło do wspólnych wymiarów z poprzedniego kroku, nie kasują ich. Teraz widać, po co była przezroczystość opony: przez jej tło prześwituje fiolet sekcji.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    Podgląd strony po tym kroku (opony.php)
  25. Krok 25: Stopka: tło, kolor, margines wewnętrzny

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku bocznego #C5CAE9, pierwszej sekcji #9FA8DA, drugiej sekcji i selektora h3 #7986CB, stopki #283593

    R.4.3 Ustawiony biały kolor czcionki dla stopki i nagłówka trzeciego stopnia

    R.4.6 Ustawione marginesy wewnętrzne (padding) dla stopki oraz selektora img 20px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku stopki: kolor tła #283593, biały kolor czcionki, marginesy wewnętrzne 20 px.

    Selektor footer: granatowe tło, biały tekst, padding: 20px z każdej strony (klucz R.4.6).

    styl.css CSS zmienione: 5 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    Podgląd strony po tym kroku (opony.php)
  26. Krok 26: 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 zastosowane 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. 3 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.

    Trzy dopiski robią układ z ilustracji 3, wszystkie z float: left:

    • aside pływa w lewo i zajmuje 40% szerokości,
    • section - pierwsza sekcja staje obok bloku bocznego (40% + 60% = 100%), a druga nie ma już miejsca w tym wierszu, więc schodzi pod pierwszą - ale tylko na wysokość pierwszej sekcji (300 px), bo blok boczny po lewej ma 600 px i nadal zajmuje swoje 40%. Dwie sekcje układają się więc jedna pod drugą, na prawo od bloku bocznego,
    • footer dostaje clear: both, żeby wrócił pod wszystkie pływające bloki.

    Klucz R.3.1 przyjmuje też flex i grid - przy dwóch sekcjach w kolumnie float wymaga najmniej kodu.

    Typowe błędy

    Bez clear: both stopka wjeżdża pod pływające bloki. display: flex na main ustawiłoby trzy bloki w jednym wierszu - sekcje obok siebie zamiast jedna pod drugą.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        float: left;
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        float: left;
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        clear: both;
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    Podgląd strony po tym kroku (opony.php)
  27. Krok 27: Klasa opona: tło, marginesy, obramowanie, zaokrąglenie

    Kryteria:

    R.4.10 Zdefiniowana klasa dla opony oraz jej styl: kolor tła #9FA8DA, margin: 40px; border: 2px dotted #283593; zaokrąglenie rogów 30px

    ok. 2 min
    Polecenie z arkusza

    Dla klasy CSS opona, przypisanej do bloków generowanych w skrypcie 1: kolor tła #9FA8DA, marginesy zewnętrzne 40 px, obramowanie linią kropkowaną o szerokości 2 px i kolorze #283593, zaokrąglenie rogów 30 px.

    Nazwę klasy narzuca arkusz: .opona (kropka = klasa). Obramowanie zapisujesz skrótem border: 2px dotted #283593 - szerokość, styl, kolor; „linia kropkowana” to dotted (dashed byłaby kreskowana). Klucz R.4.10 podaje dokładnie ten zapis. Bloków jeszcze nie ma - wygeneruje je skrypt 1; wtedy każdy dostanie to tło, margines 40 px z każdej strony i zaokrąglone rogi.

    Typowe błędy

    dashed to linia kreskowana, dotted kropkowana - arkusz mówi „kropkowana”. border-style bez szerokości i koloru nie spełni całego kryterium.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        float: left;
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        float: left;
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        clear: both;
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    .opona {
        background-color: #9FA8DA;
        margin: 40px;
        border: 2px dotted #283593;
        border-radius: 30px;
    }
    Podgląd strony po tym kroku (opony.php)
  28. Krok 28: Obraz: opływanie i margines wewnętrzny

    Kryteria: ,

    R.4.6 Ustawione marginesy wewnętrzne (padding) dla stopki oraz selektora img 20px

    R.4.8 Ustawione dla obrazu opływanie tekstem po prawej stronie float: left;

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: opływanie tekstem po prawej stronie (obraz jest po lewej stronie), marginesy wewnętrzne 20 px.

    Selektor znacznika img - zgodnie z uwagą arkusza bez klas. „Opływanie tekstem po prawej, obraz po lewej” to float: left (klucz R.4.8 podaje go wprost): obraz odsuwa się do lewej krawędzi, a nagłówki stają po jego prawej stronie. Reguła obejmie wszystkie obrazy: oponę w sekcji 1 i ikony sezonów w blokach skryptu 1 - na ilustracji 2 ikony też są po lewej z odstępem. Margines wewnętrzny 20 px to padding.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        float: left;
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        float: left;
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        clear: both;
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    .opona {
        background-color: #9FA8DA;
        margin: 40px;
        border: 2px dotted #283593;
        border-radius: 30px;
    }
    img {
        float: left;
        padding: 20px;
    }
    Podgląd strony po tym kroku (opony.php)
  29. Krok 29: Nagłówki drugiego stopnia: wyśrodkowanie i marginesy

    Kryteria:

    R.4.5 Ustawione dla selektora h2 wyrównanie tekstu do środka oraz margines zewnętrzny (margin) 0 i margines wewnętrzny (padding) 15px

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka drugiego stopnia: wyrównanie tekstu do środka, marginesy zewnętrzne 0 px, marginesy wewnętrzne 15 px.

    Selektor h2. margin: 0 zdejmuje domyślne odstępy nagłówka, a padding: 15px daje odstęp wewnątrz - dzięki temu cztery <h2> w sekcji 1 (jeden z HTML, trzy ze skryptu 2) zmieszczą się w 300 px obok opony. Klucz R.4.5 sprawdza wszystkie trzy właściwości.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        float: left;
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        float: left;
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        clear: both;
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    .opona {
        background-color: #9FA8DA;
        margin: 40px;
        border: 2px dotted #283593;
        border-radius: 30px;
    }
    img {
        float: left;
        padding: 20px;
    }
    h2 {
        text-align: center;
        margin: 0;
        padding: 15px;
    }
    Podgląd strony po tym kroku (opony.php)
  30. Krok 30: Nagłówki trzeciego stopnia: tło, kolor, rozmiar

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła dla bloku bocznego #C5CAE9, pierwszej sekcji #9FA8DA, drugiej sekcji i selektora h3 #7986CB, stopki #283593

    R.4.3 Ustawiony biały kolor czcionki dla stopki i nagłówka trzeciego stopnia

    R.4.9 Ustawiony dla nagłówka trzeciego stopnia rozmiar czcionki 140%

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka trzeciego stopnia: kolor tła #7986CB, biały kolor czcionki, rozmiar czcionki 140%.

    Selektor h3. Na stronie nie ma jeszcze żadnego <h3> - wypisze je skrypt 1 (cena w każdym bloku). Reguła czeka: klucz R.4 dopuszcza ocenę po kodzie CSS tylko, gdy elementu nie ma w HTML, ale w tym rozwiązaniu elementy będą - z PHP. Rozmiar 140% liczy się względem czcionki rodzica. Arkusz stylów jest kompletny.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: "Trebuchet MS", sans-serif;
    }
    aside {
        float: left;
        background-color: #C5CAE9;
        width: 40%;
        height: 600px;
        overflow: auto;
    }
    section {
        float: left;
        width: 60%;
        height: 300px;
    }
    #offer {
        background-color: #9FA8DA;
    }
    #order {
        background-color: #7986CB;
    }
    footer {
        clear: both;
        background-color: #283593;
        color: white;
        padding: 20px;
    }
    .opona {
        background-color: #9FA8DA;
        margin: 40px;
        border: 2px dotted #283593;
        border-radius: 30px;
    }
    img {
        float: left;
        padding: 20px;
    }
    h2 {
        text-align: center;
        margin: 0;
        padding: 15px;
    }
    h3 {
        background-color: #7986CB;
        color: white;
        font-size: 140%;
    }
    Podgląd strony po tym kroku (opony.php)
  31. Etap 4: Skrypty PHP

    Kroki 31-46 · po tym etapie masz 37 z 37 kryteriów (pkt)

    Krok 31: Odświeżanie strony co 10 sekund

    Kryteria:

    R.5.1 Strona jest odświeżana co 10 sekund

    ok. 2 min
    Polecenie z arkusza

    Napisane w języku PHP. Strona jest odświeżana co 10 sekund.

    Kod PHP piszesz między <?php a ?> - serwer wykonuje go, zanim strona trafi do przeglądarki. Odświeżanie robi funkcja z ramki w arkuszu: header('refresh: 10') wysyła przeglądarce nagłówek HTTP „odśwież tę stronę za 10 sekund”; bez url=, bo odświeżasz ten sam adres. Ramka ostrzega: nagłówek musi pójść przed jakimkolwiek wypisaniem - dlatego ten blok PHP stoi na samym początku pliku, nawet przed <!DOCTYPE html>. Spacja czy pusta linia przed <?php też jest „wypisaniem” i zepsułaby nagłówek. Po co odświeżanie: skrypt 3 losuje zamówienie, więc co 10 sekund sekcja 2 pokaże inne (podpis ilustracji 2 o tym mówi).

    Od tego kroku podgląd to wynik działania strony po stronie serwera (PHP nie wykonuje się w przeglądarce) - na razie wygląda jak wcześniej, a odświeżania w podglądzie nie widać.

    Typowe błędy

    header() po <!DOCTYPE html> daje ostrzeżenie „headers already sent” i strona się nie odświeża. Znacznik <meta http-equiv="refresh"> też działa, ale arkusz podpowiada header() w sekcji o PHP.

    opony.php PHP zmienione: 3 linie
    <?php
    header('refresh: 10');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  32. Krok 32: Połączenie z bazą danych

    Kryteria: ,

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

    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. 2 min
    Polecenie z arkusza

    Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie opony.

    W tym samym bloku, zaraz po nagłówku, otwierasz połączenie raz i trzymasz je w zmiennej $connection (znacząca, angielska nazwa - R.5.10), z której skorzystają trzy skrypty. mysqli_connect z tabeli 1 arkusza przyjmuje kolejno: serwer, użytkownika, hasło (puste) i nazwę bazy.

    Typowe błędy

    Kolejność argumentów ma znaczenie: mysqli_connect('localhost', 'root', 'opony') podaje „opony” jako HASŁO. Nazwa bazy jest czwarta. Plik sprawdzaj przez http://localhost/…, nie otwierając go z dysku.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  33. Krok 33: Skrypt 1: zapytanie 1 do bazy

    Kryteria:

    R.5.3 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub skrypt 2 - zapytanie 2 lub skrypt 3 - zapytanie 3

    ok. 2 min
    Polecenie z arkusza

    Skrypt 1: wysyła do bazy danych zapytanie 1.

    Skrypt 1 piszesz w bloku bocznym, nad paragrafem z odnośnikiem - tam mają trafić bloki z oponami. mysqli_query($connection, ...) wysyła zapytanie i zwraca wynik, który zapisujesz w $tyres (klucz R.5.3). Treść to dokładnie zapytanie 1 z kwerendy.txt: dziesięć najtańszych opon, wszystkie pola. Kolejność kolumn w SELECT * jest taka jak w tabeli: nr_kat, producent, model, sezon, cena - od niej zależą indeksy w kolejnych krokach.

    opony.php PHP zmienione: 3 linie
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  34. Krok 34: Skrypt 1: blok z klasą opona dla każdego rekordu

    Kryteria: ,

    R.2.8 W bloku bocznym utworzony przynajmniej jeden blok z klasą CSS opona oraz nagłówek <h3>, <h4> (w HTML lub skrypcie)

    R.5.4 Skrypt 1 tworzy tyle bloków, ile wybiera zapytanie

    ok. 2 min
    Polecenie z arkusza

    Dla każdego zwróconego zapytaniem rekordu wyświetla blok z przypisaną klasą CSS opona, w którym znajdują się: obraz sezonu, nagłówek czwartego stopnia i nagłówek trzeciego stopnia.

    „Dla każdego rekordu” to pętla: mysqli_fetch_row($tyres) (tabela 1) oddaje kolejny wiersz jako tablicę od zera, a gdy wierszy zabraknie - false, co kończy while. Każdy obieg otwiera <div class='opona'> i go zamyka - klasa z CSS, więc blok od razu dostaje fioletowe tło, kropkowaną ramkę i zaokrąglenie. Podgląd: dziesięć pustych bloków, tyle, ile zwraca zapytanie (klucz R.5.4). Zawartość dokładasz w trzech następnych krokach.

    opony.php PHP zmienione: 4 linie
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  35. Krok 35: Skrypt 1: ikona sezonu

    Kryteria:

    R.5.6 Skrypt 1 wyświetla obraz lato.png, gdy opona jest letnia, zima.png , gdy jest zimowa, uniwer.png gdy jest uniwersalna

    ok. 3 min
    Polecenie z arkusza

    W przypadku opony letniej obraz lato.png, w przypadku zimowej obraz zima.png, w przypadku uniwersalnej obraz uniwer.png.

    Trzy przypadki to drabinka if / elseif / else na kolumnie sezon ($row[3] - czwarta kolumna tabeli). Porównaj z dokładnymi wartościami z bazy: letnia, zimowa; wszystko inne (czyli uniwersalna) trafia do else. Każda gałąź wypisuje <img> z odpowiednim plikiem z archiwum; alt z nazwą sezonu dopisujesz dla porządku, arkusz go nie wymaga. Dzięki regule img z CSS ikona pływa po lewej z marginesem 20 px, jak na ilustracji 2.

    Typowe błędy

    Porównanie $row[3] == 'letnie' (inna forma słowa) nigdy nie będzie prawdziwe - wartość musi być dokładnie taka jak w kolumnie sezon.

    opony.php PHP zmienione: 7 linii
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  36. Krok 36: Skrypt 1: nagłówek czwartego stopnia z producentem i modelem

    Kryteria: ,

    R.2.8 W bloku bocznym utworzony przynajmniej jeden blok z klasą CSS opona oraz nagłówek <h3>, <h4> (w HTML lub skrypcie)

    R.5.5 Skrypt 1 wyświetla przynajmniej dla jednego rekordu teksty „Opona: <producent> <model>” oraz „Cena: <cena>”

    ok. 1 min
    Polecenie z arkusza

    Nagłówek czwartego stopnia o treści „Opona: <producent> <model>”.

    <h4> z tekstem „Opona: ” i dwiema kolumnami: $row[1] producent, $row[2] model, rozdzielone spacją (klucz R.5.5 sprawdza ten format). Nagłówek staje po prawej od pływającej ikony.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  37. Krok 37: Skrypt 1: nagłówek trzeciego stopnia z ceną

    Kryteria:

    R.5.5 Skrypt 1 wyświetla przynajmniej dla jednego rekordu teksty „Opona: <producent> <model>” oraz „Cena: <cena>”

    ok. 1 min
    Polecenie z arkusza

    Nagłówek trzeciego stopnia o treści „Cena: <cena>”.

    <h3> z ceną z piątej kolumny ($row[4]). Teraz zaczyna działać czekająca reguła h3 z CSS: ciemniejszy pasek, biały tekst, większa czcionka - blok wygląda jak na ilustracji 2. Skrypt 1 jest kompletny; blok boczny dostał pasek przewijania.

    Typowe błędy

    $row[3] to sezon, $row[4] to cena - przy SELECT * indeksy liczy się od zera po kolumnach tabeli.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  38. Krok 38: Skrypt 2: zapytanie 2 i jeden wiersz

    Kryteria:

    R.5.3 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub skrypt 2 - zapytanie 2 lub skrypt 3 - zapytanie 3

    ok. 2 min
    Polecenie z arkusza

    Skrypt 2: wysyła do bazy zapytanie 2.

    Skrypt 2 piszesz w sekcji 1, pod nagłówkiem „Opona dnia”. Zapytanie 2 z kwerendy.txt zwraca dokładnie jeden wiersz, więc nie potrzeba pętli - pojedyncze mysqli_fetch_row wkłada go do $row. Kolejność kolumn jak w SELECT: producent, model, sezon, cena.

    opony.php PHP zmienione: 4 linie
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  39. Krok 39: Skrypt 2: nagłówek z producentem i modelem

    Kryteria:

    R.5.7 Skrypt 2 wyświetla zwrócony rekord w postaci: „<producent> model <model>”, „Sezon: <sezon>”, „Tylko <cena> zł!”

    ok. 1 min
    Polecenie z arkusza

    Wyświetla w nagłówku drugiego stopnia treść „<producent> model <model>”.

    <h2> z producentem ($row[0]), słowem „model” i modelem ($row[1]). Reguła h2 z CSS wyśrodkowuje go w miejscu obok pływającej opony. Podgląd: „uLFA model AL135”.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  40. Krok 40: Skrypt 2: nagłówek z sezonem

    Kryteria:

    R.5.7 Skrypt 2 wyświetla zwrócony rekord w postaci: „<producent> model <model>”, „Sezon: <sezon>”, „Tylko <cena> zł!”

    ok. 1 min
    Polecenie z arkusza

    W kolejnym nagłówku drugiego stopnia treść „Sezon: <sezon>”.

    Drugi <h2> z trzecią kolumną. Podgląd: „Sezon: zimowa”.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  41. Krok 41: Skrypt 2: nagłówek z ceną

    Kryteria:

    R.5.7 Skrypt 2 wyświetla zwrócony rekord w postaci: „<producent> model <model>”, „Sezon: <sezon>”, „Tylko <cena> zł!”

    ok. 1 min
    Polecenie z arkusza

    W kolejnym nagłówku drugiego stopnia treść „Tylko <cena> zł!”.

    Trzeci <h2>: „Tylko ”, cena z czwartej kolumny, „ zł!”. Kolumna decimal(10,2) oddaje cenę z dwoma miejscami po kropce: „Tylko 101.50 zł!”, jak na ilustracji 2. Skrypt 2 jest kompletny; cztery nagłówki mieszczą się obok opony dzięki margin: 0 z CSS.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  42. Krok 42: Skrypt 3: zapytanie 3 i losowy wiersz

    Kryteria:

    R.5.3 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub skrypt 2 - zapytanie 2 lub skrypt 3 - zapytanie 3

    ok. 2 min
    Polecenie z arkusza

    Skrypt 3: wysyła do bazy zapytanie 3.

    Skrypt 3 piszesz w sekcji 2, pod nagłówkiem. Zapytanie 3 z kwerendy.txt zwraca jeden losowy wiersz (ORDER BY RAND() LIMIT 1), więc znów bez pętli - mysqli_fetch_row do $row. Kolejność kolumn: id_zam, ilosc, model, cena. Przy każdym odświeżeniu strony (co 10 sekund) baza wylosuje inne zamówienie - podgląd pokazuje to z ilustracji 2 (zamówienie 7).

    opony.php PHP zmienione: 4 linie
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_row($order);
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  43. Krok 43: Skrypt 3: nagłówek z identyfikatorem, ilością i modelem

    Kryteria:

    R.5.9 Skrypt 3 wyświetla teksty „<id_zam> <ilosc> sztuki modelu <model>” lub „Wartość zamówienia <wartość> zł”, z wyliczoną wartością

    ok. 1 min
    Polecenie z arkusza

    Wyświetla w nagłówku drugiego stopnia treść „<id_zam> <ilosc> sztuki modelu <model>”.

    <h2> składany z trzech kolumn i słów z arkusza: identyfikator ($row[0]), ilość ($row[1]), „sztuki modelu”, model ($row[2]). Podgląd: „7 4 sztuki modelu AL100” - dokładnie jak na ilustracji 2 (format jest z arkusza, nawet jeśli brzmi nienaturalnie).

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_row($order);
    echo "<h2>$row[0] $row[1] sztuki modelu $row[2]</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  44. Krok 44: Skrypt 3: wartość zamówienia

    Kryteria:

    R.5.8 Skrypt 3 wylicza wartość zamówienia jako iloczyn ceny i ilości opon

    ok. 1 min
    Polecenie z arkusza

    Wartość oznacza wyliczoną wartość na podstawie zwróconych z bazy ilości i ceny.

    Wartość to iloczyn ilości i ceny: $row[1] * $row[3] do zmiennej $value (klucz R.5.8 sprawdza mnożenie). PHP sam zamienia napis „290.50” z bazy na liczbę przy mnożeniu. Dla zamówienia z ilustracji: 4 × 290,50 = 1162.

    Typowe błędy

    $row[1] * $row[2] mnoży ilość przez model (napis) - PHP 8 zgłosi błąd typu. Cena jest czwartą kolumną zapytania 3.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_row($order);
    echo "<h2>$row[0] $row[1] sztuki modelu $row[2]</h2>";
    $value = $row[1] * $row[3];
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  45. Krok 45: Skrypt 3: nagłówek z wartością zamówienia

    Kryteria:

    R.5.9 Skrypt 3 wyświetla teksty „<id_zam> <ilosc> sztuki modelu <model>” lub „Wartość zamówienia <wartość> zł”, z wyliczoną wartością

    ok. 1 min
    Polecenie z arkusza

    W kolejnym nagłówku drugiego stopnia treść „Wartość zamówienia <wartość> zł”.

    Drugi <h2> z wyliczoną wartością. Podgląd: „Wartość zamówienia 1162 zł”, jak na ilustracji 2 - PHP wypisuje liczbę bez zbędnych zer po przecinku. Skrypt 3 jest kompletny.

    opony.php PHP zmienione: 1 linia
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_row($order);
    echo "<h2>$row[0] $row[1] sztuki modelu $row[2]</h2>";
    $value = $row[1] * $row[3];
    echo "<h2>Wartość zamówienia $value zł</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  46. Krok 46: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Na końcu zamykane jest połączenie z bazą.

    mysqli_close($connection) na końcu pliku, po wszystkich trzech skryptach. Klucz R.5.2 sprawdza, że zamknięcie jest ostatnią operacją na bazie. Strona spełnia wszystkie kryteria arkusza - dalej trzy kroki „jak w prawdziwym projekcie”.

    Typowe błędy

    mysqli_close po skrypcie 1 sprawia, że skrypty 2 i 3 idą po zamkniętym połączeniu - sekcje zostają puste.

    opony.php PHP zmienione: 3 linie
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_row($tyres)) {
        echo "<div class='opona'>";
        if ($row[3] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row[3] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: $row[1] $row[2]</h4>";
        echo "<h3>Cena: $row[4]</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_row($offer);
    echo "<h2>$row[0] model $row[1]</h2>";
    echo "<h2>Sezon: $row[2]</h2>";
    echo "<h2>Tylko $row[3] zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_row($order);
    echo "<h2>$row[0] $row[1] sztuki modelu $row[2]</h2>";
    $value = $row[1] * $row[3];
    echo "<h2>Wartość zamówienia $value zł</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  47. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 47-49 · po tym etapie masz 37 z 37 kryteriów (pkt)

    Krok 47: Refaktor: wiersze po nazwach kolumn

    Kryteria: , ,

    R.5.5 Skrypt 1 wyświetla przynajmniej dla jednego rekordu teksty „Opona: <producent> <model>” oraz „Cena: <cena>”

    R.5.7 Skrypt 2 wyświetla zwrócony rekord w postaci: „<producent> model <model>”, „Sezon: <sezon>”, „Tylko <cena> zł!”

    R.5.9 Skrypt 3 wyświetla teksty „<id_zam> <ilosc> sztuki modelu <model>” lub „Wartość zamówienia <wartość> zł”, z wyliczoną wartością

    ok. 4 min
    Polecenie z arkusza

    Skrypt 1: wysyła do bazy danych zapytanie 1.

    Wszystkie trzy skrypty czytają wiersze po numerach: $row[4] to cena, $row[3] sezon - kto czyta ten kod za miesiąc, musi zaglądać do zapytania, a przy SELECT * wystarczy dodać kolumnę do tabeli, żeby numery się przesunęły. mysqli_fetch_assoc oddaje wiersz jako tablicę po nazwach kolumn: $row['cena'], $row['sezon']. W napisie z cudzysłowem taki element trzeba objąć klamrami: {$row['model']}. Kod czyta się jak zdanie, a zmiana kolejności kolumn w zapytaniu niczego nie psuje. Podgląd bez zmian.

    Typowe błędy

    Klucz tablicy musi być dokładnie nazwą kolumny z wyniku zapytania, z wielkością liter włącznie: $row['Cena'] zamiast $row['cena'] daje ostrzeżenie „Undefined array key” i pustą wartość (sprawdzone w PHP 8.2).

    opony.php PHP zmienione: 12 linii
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_assoc($tyres)) {
        echo "<div class='opona'>";
        if ($row['sezon'] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row['sezon'] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        echo "<h4>Opona: {$row['producent']} {$row['model']}</h4>";
        echo "<h3>Cena: {$row['cena']}</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_assoc($offer);
    echo "<h2>{$row['producent']} model {$row['model']}</h2>";
    echo "<h2>Sezon: {$row['sezon']}</h2>";
    echo "<h2>Tylko {$row['cena']} zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_assoc($order);
    echo "<h2>{$row['id_zam']} {$row['ilosc']} sztuki modelu {$row['model']}</h2>";
    $value = $row['ilosc'] * $row['cena'];
    echo "<h2>Wartość zamówienia $value zł</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  48. Krok 48: Refaktor: escapowanie danych z bazy

    Kryteria: , ,

    R.5.5 Skrypt 1 wyświetla przynajmniej dla jednego rekordu teksty „Opona: <producent> <model>” oraz „Cena: <cena>”

    R.5.7 Skrypt 2 wyświetla zwrócony rekord w postaci: „<producent> model <model>”, „Sezon: <sezon>”, „Tylko <cena> zł!”

    R.5.9 Skrypt 3 wyświetla teksty „<id_zam> <ilosc> sztuki modelu <model>” lub „Wartość zamówienia <wartość> zł”, z wyliczoną wartością

    ok. 3 min
    Polecenie z arkusza

    Nagłówek czwartego stopnia o treści „Opona: <producent> <model>”.

    Ta strona nie ma formularza, ale nazwy producentów, modeli i sezonów ktoś kiedyś wpisał do bazy - a napis <script>…</script> w nazwie modelu wykonałby się u każdego, kto otworzy stronę (XSS). htmlspecialchars() zamienia <, >, ", & na encje, więc tekst wyświetla się dosłownie i nie staje się kodem. Napisy przechodzą przez funkcję do zmiennych o angielskich nazwach, a echo używa już tylko ich. Liczby (id_zam, ilosc, cena) zostają - nie niosą znaczników. Podgląd bez zmian.

    Typowe błędy

    Escapowanie przy zapisie do bazy (zamiast przy wypisywaniu) zniekształca dane - encje &lt; trafiłyby do tabeli. Escapujesz na wyjściu.

    opony.php PHP zmienione: 10 linii
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    while ($row = mysqli_fetch_assoc($tyres)) {
        echo "<div class='opona'>";
        if ($row['sezon'] == 'letnia') {
            echo "<img src='lato.png' alt='letnia'>";
        } elseif ($row['sezon'] == 'zimowa') {
            echo "<img src='zima.png' alt='zimowa'>";
        } else {
            echo "<img src='uniwer.png' alt='uniwersalna'>";
        }
        $producer = htmlspecialchars($row['producent']);
        $model = htmlspecialchars($row['model']);
        echo "<h4>Opona: $producer $model</h4>";
        echo "<h3>Cena: {$row['cena']}</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_assoc($offer);
    $producer = htmlspecialchars($row['producent']);
    $model = htmlspecialchars($row['model']);
    echo "<h2>$producer model $model</h2>";
    $season = htmlspecialchars($row['sezon']);
    echo "<h2>Sezon: $season</h2>";
    echo "<h2>Tylko {$row['cena']} zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_assoc($order);
    $model = htmlspecialchars($row['model']);
    echo "<h2>{$row['id_zam']} {$row['ilosc']} sztuki modelu $model</h2>";
    $value = $row['ilosc'] * $row['cena'];
    echo "<h2>Wartość zamówienia $value zł</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  49. Krok 49: Refaktor: mapa ikon i formatowanie kwot

    Kryteria:

    R.5.6 Skrypt 1 wyświetla obraz lato.png, gdy opona jest letnia, zima.png , gdy jest zimowa, uniwer.png gdy jest uniwersalna

    ok. 3 min
    Polecenie z arkusza

    W przypadku opony letniej obraz lato.png, w przypadku zimowej obraz zima.png, w przypadku uniwersalnej obraz uniwer.png.

    Dwie poprawki na czytelność i wygląd:

    • mapa zamiast drabinki if: tablica $icons wiąże sezon z plikiem, a $icons[$row['sezon']] ?? 'uniwer.png' bierze ikonę jednym wyrażeniem (operator ?? daje wartość domyślną, gdy klucza nie ma). Czwarty sezon to jeden wpis w tablicy, nie kolejny elseif. Stara drabinka zostaje w komentarzu,
    • number_format($cena, 2, ',', ' ') zapisuje kwoty po polsku: „1 162,00 zł” zamiast „1162 zł”, „101,50” zamiast „101.50”.

    Na egzaminie wystarczy wersja z kroków wcześniejszych - klucz tego nie sprawdza. To już kod gotowy do prawdziwego użycia.

    Typowe błędy

    number_format zwraca napis - formatuj dopiero wynik mnożenia, nie cenę przed rachunkiem.

    opony.php PHP zmienione: 10 linii
    <?php
    header('refresh: 10');
    $connection = mysqli_connect('localhost', 'root', '', 'opony');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>OPONY</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <main>
            <aside>
    <?php
    $tyres = mysqli_query($connection, 'SELECT * FROM opony ORDER BY cena LIMIT 10;');
    $icons = ['letnia' => 'lato.png', 'zimowa' => 'zima.png', 'uniwersalna' => 'uniwer.png'];
    while ($row = mysqli_fetch_assoc($tyres)) {
        echo "<div class='opona'>";
        // if ($row['sezon'] == 'letnia') { ... } elseif (...) { ... } else { ... }
        $icon = $icons[$row['sezon']] ?? 'uniwer.png';
        echo "<img src='$icon' alt='{$row['sezon']}'>";
        $producer = htmlspecialchars($row['producent']);
        $model = htmlspecialchars($row['model']);
        echo "<h4>Opona: $producer $model</h4>";
        $price = number_format($row['cena'], 2, ',', ' ');
        echo "<h3>Cena: $price</h3>";
        echo '</div>';
    }
    ?>
                <p><a href="https://opona.pl/">więcej ofert</a></p>
            </aside>
            <section id="offer">
                <img src="opona.png" alt="Opona">
                <h2>Opona dnia</h2>
    <?php
    $offer = mysqli_query($connection, 'SELECT producent, model, sezon, cena FROM opony WHERE nr_kat = 9;');
    $row = mysqli_fetch_assoc($offer);
    $producer = htmlspecialchars($row['producent']);
    $model = htmlspecialchars($row['model']);
    echo "<h2>$producer model $model</h2>";
    $season = htmlspecialchars($row['sezon']);
    echo "<h2>Sezon: $season</h2>";
    $price = number_format($row['cena'], 2, ',', ' ');
    echo "<h2>Tylko $price zł!</h2>";
    ?>
            </section>
            <section id="order">
                <h2>Najnowsze zamówienie</h2>
    <?php
    $order = mysqli_query($connection, 'SELECT id_zam, ilosc, model, cena FROM zamowienie JOIN opony ON zamowienie.nr_kat = opony.nr_kat ORDER BY RAND() LIMIT 1;');
    $row = mysqli_fetch_assoc($order);
    $model = htmlspecialchars($row['model']);
    echo "<h2>{$row['id_zam']} {$row['ilosc']} sztuki modelu $model</h2>";
    $value = $row['ilosc'] * $row['cena'];
    $formatted = number_format($value, 2, ',', ' ');
    echo "<h2>Wartość zamówienia $formatted zł</h2>";
    ?>
            </section>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>
    Podgląd strony po tym kroku (opony.php)
  50. Etap 6: Oddanie pracy

    Krok 50 · po tym etapie masz 37 z 37 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

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

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

    W folderze z numerem zdającego muszą być: import.png, kw1.png … kw4.png, kwerendy.txt, lato.png, opona.png, opony.php, przeglądarka.txt, styl.css, uniwer.png, zima.png. Nagraj płytę, sprawdź jej odczyt i opisz numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.