Przejdź do głównej treści
INF.03-01-23.06-SGCzerwiec 2023 · 38 kroków · ok. 67 min · 38 kryteriów z klucza

Rozwiązanie krok po kroku: Portal sklepu dla uczniów (Wersja podstawowa)

Rozwiązanie buduje stronę sklepu dla uczniów: baza sklep z dostawcami i towarami w relacji i cztery zapytania (warunek na polu 0/1, cena jednego towaru, COUNT z GROUP BY po złączeniu tabel i ALTER TABLE dodające pole), grafika przeskalowana z zachowaniem przezroczystości, strona index.php z banerem, trzema panelami i stopką oraz style w styl.css z numeracją listy literami i zaokrąglonym obramowaniem obrazu. Dwa skrypty PHP: lista towarów w promocji oraz formularz POST z listą rozwijalną, po którego wysłaniu skrypt pobiera cenę wybranego towaru i liczy cenę o 30% niższą.

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ą. Kod PHP jest najpierw pisany funkcjami z tabeli 1 arkusza (proceduralne mysqli), a na końcu wartość z formularza zostaje zabezpieczona zapytaniem przygotowanym, a ceny - sformatowane.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: panele ustawione flexem w znaczniku <main>, kolory w zmiennych CSS, dane pobierane przez PDO na górze pliku, a nazwa towaru sprawdzana z listą i przekazywana zapytaniem przygotowanym - obie wersje są zgodne z kluczem.

Baza i grafika pochodzą z prawdziwego archiwum materialy1 (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 i z widocznym zapytaniem. Od kroku z formularzem podgląd pokazuje stronę po wysłaniu formularza z wybraną gumką do mazania - jak na obrazie 2.

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

    Krok 1: Baza danych sklep

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Utwórz nową bazę danych o nazwie sklep.

    Rozpakuj materialy1.7z z pulpitu (hasło Z@dani3x) do folderu z numerem zdającego: sklep.sql i promocja.png. W phpMyAdmin: Nowa, nazwa sklep. Arkusz nie podaje porównywania - wybierasz np. utf8mb4_polish_ci.

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

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Do bazy zaimportuj tabele z pliku sklep.sql, z wcześniej rozpakowanego archiwum.

    Przy zaznaczonej bazie sklep: Import → sklep.sql → Wykonaj. Dwie tabele z obrazu 1: dostawcy (3 dostawców) i towary (10 towarów). Pole promocja to 0 (bez promocji) albo 1 (w promocji), a idDostawcy wskazuje id w tabeli dostawcy - na tych polach opiera się relacja.

  3. Krok 3: Zrzut ekranu baza.jpg

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie JPEG i nazwij baza. 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, zapis jako baza.jpg - w tym arkuszu zrzut importu nazywa się baza, a zrzuty zapytań kwerenda1 - kwerenda4, wszystkie w JPEG.

    Typowe błędy

    Nazwa import.jpg (jak w wielu innych arkuszach) zamiast baza.jpg to strata punktu R.1.1.

  4. Krok 4: Zapytanie 1: towary objęte promocją

    Kryteria: ,

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

    R.1.3 Zapisano zapytanie 1 wybierające jedynie pole nazwa z tabeli towary dla towarów objętych promocją. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM towary WHERE promocja = 1; oraz wynik działania zapytania udokumentowano zrzutem ekranu, na którym widoczne są jedynie nazwy towarów: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt.

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pole nazwa z tabeli towary dla towarów objętych promocją.

    „Objęte promocją” to w bazie promocja = 1. Wynik: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt. - jak w kluczu. Zapytanie do kwerendy.txt, zrzut kwerenda1.jpg - arkusz wymaga, by na zrzucie było widać także treść zapytania (phpMyAdmin pokazuje ją nad wynikiem).

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa FROM towary WHERE promocja = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: cena markerów

    Kryteria:

    R.1.4 Zapisano zapytanie 2 wybierające jedynie pole cena z tabeli towary dla towaru Markery 4 szt. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczna jest jedynie cena 22.4

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pole cena z tabeli towary dla towaru Markery 4 szt.

    Warunek porównuje cały napis, razem ze spacjami i kropką: nazwa = 'Markery 4 szt.'. Wynik: 22.4 - jak w kluczu. Zrzut: kwerenda2.jpg. To zapytanie wyśle skrypt 2, podstawiając nazwę wybraną w formularzu.

    Typowe błędy

    nazwa = "Markery 4 szt" bez kropki na końcu nie znajdzie towaru - wynik będzie pusty.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM towary WHERE promocja = 1;
    
    -- Zapytanie 2
    SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: liczba towarów każdego dostawcy

    Kryteria:

    R.1.5 Zapisano zapytanie 3 wybierające jedynie pola id i nazwa z tabeli dostawcy oraz zliczające liczbę towarów dostarczanych przez każdego z dostawców. Nazwa kolumny (alias) zliczającej liczba_towarow. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa; (lub INNER JOIN, lub wersja bez JOIN z porównaniem kluczy po WHERE, w funkcji COUNT możliwa również *) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 3 rekordy, jedynie pola id, nazwa z tabeli dostawcy oraz odpowiadająca im liczba_towarow: Art. szkolne - 4, Papiernictwo - 4, Wszystko dla ucznia - 2

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola id oraz nazwa dla wszystkich rekordów z tabeli dostawcy oraz zliczające liczbę towarów dostarczanych przez każdego z dostawców. Nazwa kolumny (alias) dla zliczenia towarów: liczba_towarow. W zapytaniu 3 należy posłużyć się relacją.

    • FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id - relacja: każdy towar dostaje swojego dostawcę.
    • GROUP BY dostawcy.nazwa - jedna grupa na dostawcę, a w niej COUNT(towary.id) zlicza jego towary; alias liczba_towarow (bez spacji i polskich liter, więc bez cudzysłowu).
    • Obie tabele mają kolumny id i nazwa, więc każdą poprzedzasz nazwą tabeli.

    Wynik: 3 wiersze - Art. szkolne 4, Papiernictwo 4, Wszystko dla ucznia 2, jak w kluczu. Zrzut: kwerenda3.jpg.

    Typowe błędy

    SELECT id, nazwa ... bez nazw tabel to błąd „column is ambiguous” - obie tabele mają te kolumny.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM towary WHERE promocja = 1;
    
    -- Zapytanie 2
    SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';
    
    -- Zapytanie 3
    SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowe pole informacje

    Kryteria:

    R.1.6 Zapisano zapytanie 4 modyfikujące strukturę tabeli dostawcy poprzez dodanie pola typu napisowego o nazwie informacje. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE dostawcy ADD COLUMN informacje TEXT; (możliwe również bez słowa COLUMN, dowolny typ tekstowy) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnie wykonanym zapytaniu lub zmieniona struktura tabeli

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: modyfikujące strukturę tabeli dostawcy, poprzez dodanie pola typu tekstowego o nazwie informacje.

    Strukturę tabeli zmienia ALTER TABLE: ADD COLUMN informacje TEXT dodaje pole tekstowe (TEXT albo np. VARCHAR(100)). Zrzut kwerenda4.jpg pokazuje komunikat o wykonaniu albo, jak obok, strukturę tabeli z nowym polem. kwerendy.txt ma komplet.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM towary WHERE promocja = 1;
    
    -- Zapytanie 2
    SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';
    
    -- Zapytanie 3
    SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa;
    
    -- Zapytanie 4
    ALTER TABLE dostawcy ADD COLUMN informacje TEXT;
    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 19 z 38 kryteriów (pkt)

    Krok 8: promocja.png: 180 px szerokości z przezroczystością

    Kryteria:

    R.2.1 Obraz z pliku promocja.png przeskalowano do szerokości 180 px, odpowiadająca temu wysokość wynosi 162 px (± 5 px) oraz obraz ma tło przezroczyste

    ok. 2 min
    Polecenie z arkusza

    Przygotowanie grafiki: Plik promocja.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 180 px. Plik powinien być zapisany z zachowaniem przezroczystości pod tą samą nazwą.

    Obraz ma 378 × 340 px i przezroczyste tło. W GIMP-ie: Obraz → Skaluj obraz, łańcuch proporcji zamknięty, szerokość 180 - wysokość wyjdzie 162 px (340 × 180 / 378; klucz R.2.1: 162 ± 5). Eksportuj jako promocja.png - format PNG zachowuje kanał przezroczystości, więc tło dalej jest przezroczyste (na stronie prześwituje kolor panelu).

    Typowe błędy

    Eksport do JPEG (albo spłaszczenie obrazu) zamienia przezroczyste tło na białe - klucz R.2.1 wymaga przezroczystości.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy standard kodowania polskich znaków

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze strony o nazwie index.php. Zapisany w języku HTML5.

    Utwórz index.php: <!DOCTYPE html> i szkielet <html>, <head>, <body>.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Ustawiony język zawartości strony na polski.

    lang="pl" w <html>.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy 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"> - przycisk SPRAWDŹ i nagłówek „Sprawdź cenę” mają polskie litery.

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

    Kryteria:

    R.2.3 Nadano stronie tytuł "Sklep dla uczniów”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki „Sklep dla uczniów”.

    <title> w <head> (R.2.3).

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

    Kryteria:

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

    ok. 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">.

    Typowe błędy

    Klucz R.3.5 odbiera punkt także za źle przypisany selektor bloku (np. kropka zamiast #).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  14. Krok 14: Bloki: baner, trzy panele, stopka

    Kryteria:

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, panele lewy, środkowy, prawy, oraz stopkę. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

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

    Baner to <header>, stopka <footer>, a trzy panele - trzy <section> z identyfikatorami left, middle, right (po angielsku). Panele lewy i prawy mają wspólny wygląd, środkowy - własny, więc CSS musi je rozróżniać (R.2.4).

    index.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Baner: nagłówek pierwszego stopnia

    Kryteria:

    R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia o treści „Dzisiejsze promocje naszego sklepu”.

    <h1> w <header>.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Panel lewy: nagłówek i lista numerowana

    Kryteria: ,

    R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail

    R.2.6 W bloku lewym umieszczono jedną listę numerowaną (w kodzie HTML lub skrypcie), użyto znaczników <ol>, <li>

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek drugiego stopnia o treści „Taniej o 30%”. Lista numerowana (uporządkowana) zgodna z obrazem 2, elementy listy generowane są skryptem 1.

    <h2> i pusta <ol> - elementy wypisze skrypt 1. Na obrazie 2 lista jest numerowana literami (a, b, c) - to zrobi CSS.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Panel środkowy: formularz z listą rozwijalną

    Kryteria: , , , ,

    R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail

    R.2.7 W bloku środkowym umieszczono listę rozwijaną, zawierającą nazwy: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt. użyto znaczników <select>, <option>

    R.2.8 W bloku środkowym umieszczono przycisk SPRAWDŹ

    R.3.2 Dane z formularza przesyłane są za pomocą metody POST do tego samego pliku (poprawne również bez atrybutu action)

    R.3.3 Przycisk w formularzu realizuje wysyłanie danych do skryptu (input lub button z typem submit lub button bez typu)

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku środkowego: Nagłówek drugiego stopnia o treści „Sprawdź cenę”. Formularz wysyłający dane do tego samego pliku metodą bezpieczną oraz składający się z: Listy rozwijalnej zawierającej nazwy towarów: „Gumka do mazania”, „Cienkopis”, „Pisaki 60 szt.”, „Markery 4 szt.”. Przycisku SPRAWDŹ, którego wybranie powoduje wysłanie danych do skryptu 2.

    • Metoda bezpieczna w rozumieniu arkusza to method="post": dane idą w treści żądania, a nie w adresie strony. W specyfikacji HTTP „bezpieczne” są co prawda metody, które niczego nie zmieniają na serwerze (GET i HEAD), ale arkusz używa tego słowa w innym sensie, a klucz wymaga POST. Bez atrybutu action formularz wysyła dane do tego samego pliku (R.3.2).
    • Lista rozwijalna to <select> z nazwą product (pod tą nazwą PHP odczyta wybór) i cztery <option>. Opcja bez atrybutu value wysyła swój tekst - a skrypt potrzebuje właśnie nazwy towaru (R.2.7).
    • <button type="submit">SPRAWDŹ</button> wysyła formularz (R.2.8, R.3.3).
    Typowe błędy

    method="get" też wysyła dane, ale nie jest metodą „bezpieczną” z arkusza - klucz R.3.2 wymaga POST.

    index.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  18. Krok 18: Blok na wynik skryptu 2

    ok. 1 min
    Polecenie z arkusza

    Blok zawierający efekt działania skryptu 2.

    Pusty <div id="result"> pod formularzem - wypisze w nim ceny skrypt 2. Identyfikator pozwoli nadać mu obramowanie i margines.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
            </div>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Panel prawy: kontakt z odsyłaczem pocztowym i obraz

    Kryteria: , ,

    R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail

    R.2.9 W bloku prawym umieszczono obraz promocja.png z tekstem alternatywnym "promocja"

    R.3.4 Napis [email protected] jest odsyłaczem pocztowym, w definicji zastosowano "mailto:"

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek drugiego stopnia o treści: „Kontakt”. Paragraf (akapit) o treści „e-mail: [email protected]”, gdzie napis „[email protected]” jest odsyłaczem pocztowym łączącym z tym adresem. Obraz promocja.png z tekstem alternatywnym „promocja”.

    Odsyłacz pocztowy to zwykły <a>, ale adres zaczyna się od mailto: - kliknięcie otwiera program pocztowy z wpisanym odbiorcą (R.3.4). Odnośnikiem jest sam adres, słowo „e-mail:” zostaje zwykłym tekstem. Pod spodem przeskalowany obraz (R.2.9).

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  20. Krok 20: Stopka: nagłówek czwartego stopnia

    Kryteria:

    R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: nagłówek czwartego stopnia o treści „Autor strony: ”, dalej wstawiony numer zdającego.

    <h4> w <footer> - w tym arkuszu stopka ma nagłówek, nie akapit. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Etap 3: Styl CSS

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

    Krok 21: Plik styl.css: krój i wyśrodkowanie

    Kryteria:

    R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (*) krój czcionki Garamond i wyrównanie tekstu do środka

    ok. 1 min
    Polecenie z arkusza

    Domyślne formatowanie wszystkich selektorów: krój czcionki Garamond, wyrównanie tekstu do środka.

    Utwórz styl.css; selektor * obejmuje wszystkie elementy (R.4.1).

    styl.css CSS nowy plik
    * {
        font-family: Garamond;
        text-align: center;
    }
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Baner i stopka

    Kryteria: , , ,

    R.4.2 Ustawiono kolor tła dla banera i stopki na #8C7B75, panelu lewego i prawego na #BCAAA4, panelu środkowego na #EFDCD5

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

    R.4.4 Ustawiono wysokość banera i stopki na 70px oraz trzech paneli na 400px

    R.4.6 Ustawiono rozmiar czcionki dla banera i stopki na 150%

    ok. 1 min
    Polecenie z arkusza

    Dla banera i stopki: kolor tła #8C7B75, biały kolor czcionki, wysokość 70 px, rozmiar czcionki 150%.

    Jedna reguła dla dwóch selektorów. Kolor w zapisie szesnastkowym wpisujesz dokładnie jak w arkuszu.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    Podgląd strony po tym kroku (index.php)
  23. Krok 23: Panele lewy i prawy

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła dla banera i stopki na #8C7B75, panelu lewego i prawego na #BCAAA4, panelu środkowego na #EFDCD5

    R.4.4 Ustawiono wysokość banera i stopki na 70px oraz trzech paneli na 400px

    R.4.5 Ustawiono szerokość panelu lewego i prawego na 35%, panelu środkowego na 30%

    ok. 1 min
    Polecenie z arkusza

    Dla panelu lewego i prawego: kolor tła #BCAAA4, wysokość 400 px, szerokość 35%.

    Selektory identyfikatorów zaczynają się od #.

    Typowe błędy

    .left (kropka) zamiast #left nie trafia w element - klucz R.3.5 wprost wymienia ten błąd.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    Podgląd strony po tym kroku (index.php)
  24. Krok 24: Panel środkowy

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła dla banera i stopki na #8C7B75, panelu lewego i prawego na #BCAAA4, panelu środkowego na #EFDCD5

    R.4.4 Ustawiono wysokość banera i stopki na 70px oraz trzech paneli na 400px

    R.4.5 Ustawiono szerokość panelu lewego i prawego na 35%, panelu środkowego na 30%

    ok. 1 min
    Polecenie z arkusza

    Dla panelu środkowego: kolor tła #EFDCD5, wysokość 400 px, szerokość 30%.

    Jaśniejsze tło i 30% szerokości - razem z panelami bocznymi 35% + 30% + 35% = 100%.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    #middle {
        background-color: #EFDCD5;
        height: 400px;
        width: 30%;
    }
    Podgląd strony po tym kroku (index.php)
  25. Krok 25: Lista: numeracja literami, elementy do lewej

    Kryteria:

    R.4.7 Ustawiono styl selektora ol: małe litery (np. list-style-type: lower-alpha;) oraz styl selektora li: wyrównanie tekstu do lewej strony

    ok. 1 min
    Polecenie z arkusza

    Dla selektora listy numerowanej: numeracja małymi literami. Dla selektora elementu listy: wyrównanie tekstu do lewej strony.

    list-style-type: lower-alpha numeruje elementy literami a, b, c… (upper-alpha - wielkimi, lower-roman - rzymskimi). li { text-align: left } nadpisuje domyślne wyśrodkowanie z * tylko dla elementów listy. Arkusz wymaga selektorów znaczników ol i li (R.4.7).

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    #middle {
        background-color: #EFDCD5;
        height: 400px;
        width: 30%;
    }
    ol {
        list-style-type: lower-alpha;
    }
    li {
        text-align: left;
    }
    Podgląd strony po tym kroku (index.php)
  26. Krok 26: Obraz: ramka kreskowa i zaokrąglenie

    Kryteria: , ,

    R.4.8 Ustawiono obramowanie dla selektora img na 1px dashed #8C7B75 oraz obramowanie dla bloku z wynikiem działania skryptu 2: 1px solid #8C7B75

    R.4.9 Ustawiono dla obrazu marginesy wewnętrzne (padding) na 5px oraz dla bloku z wynikami skryptu 2 jedynie margines zewnętrzny górny (np. margin-top) na 100px

    R.4.10 Ustawiono dla obrazu zaokrąglenie obramowania 10% (np. border-radius: 10%;)

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: obramowanie o szerokości 1 px linią kreskową koloru #8C7B75, marginesy wewnętrzne 5 px, zaokrąglenie obramowania 10%.

    Linia kreskowa to dashed. padding odsuwa ramkę od obrazu, a border-radius: 10% zaokrągla jej rogi - jak na obrazie 2.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    #middle {
        background-color: #EFDCD5;
        height: 400px;
        width: 30%;
    }
    ol {
        list-style-type: lower-alpha;
    }
    li {
        text-align: left;
    }
    img {
        border: 1px dashed #8C7B75;
        padding: 5px;
        border-radius: 10%;
    }
    Podgląd strony po tym kroku (index.php)
  27. Krok 27: Blok wyniku skryptu 2

    Kryteria: ,

    R.4.8 Ustawiono obramowanie dla selektora img na 1px dashed #8C7B75 oraz obramowanie dla bloku z wynikiem działania skryptu 2: 1px solid #8C7B75

    R.4.9 Ustawiono dla obrazu marginesy wewnętrzne (padding) na 5px oraz dla bloku z wynikami skryptu 2 jedynie margines zewnętrzny górny (np. margin-top) na 100px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku z wynikiem działania skryptu 2: margines zewnętrzny górny 100 px, obramowanie o szerokości 1 px linią ciągłą koloru #8C7B75.

    margin-top: 100px odsuwa blok od formularza, linia ciągła to solid. Pusty blok jest na razie tylko poziomą kreską - wypełni go skrypt 2.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
        text-align: center;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    #middle {
        background-color: #EFDCD5;
        height: 400px;
        width: 30%;
    }
    ol {
        list-style-type: lower-alpha;
    }
    li {
        text-align: left;
    }
    img {
        border: 1px dashed #8C7B75;
        padding: 5px;
        border-radius: 10%;
    }
    #result {
        margin-top: 100px;
        border: 1px solid #8C7B75;
    }
    Podgląd strony po tym kroku (index.php)
  28. Krok 28: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display z wartością flex lub grid albo position)

    ok. 2 min
    Polecenie z arkusza

    Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z obrazem 2.

    section { float: left; } stawia trzy panele obok siebie (35% + 30% + 35% = 100% - bez marginesów, inaczej ostatni spadłby niżej), a footer { clear: both; } sprowadza stopkę pod nie (R.3.1).

    Typowe błędy

    Dodanie panelom marginesu albo ramki przekracza 100% szerokości - prawy panel spada pod lewy.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
        text-align: center;
    }
    footer {
        clear: both;
    }
    header, footer {
        background-color: #8C7B75;
        color: white;
        height: 70px;
        font-size: 150%;
    }
    section {
        float: left;
    }
    #left, #right {
        background-color: #BCAAA4;
        height: 400px;
        width: 35%;
    }
    #middle {
        background-color: #EFDCD5;
        height: 400px;
        width: 30%;
    }
    ol {
        list-style-type: lower-alpha;
    }
    li {
        text-align: left;
    }
    img {
        border: 1px dashed #8C7B75;
        padding: 5px;
        border-radius: 10%;
    }
    #result {
        margin-top: 100px;
        border: 1px solid #8C7B75;
    }
    Podgląd strony po tym kroku (index.php)
  29. Etap 4: Skrypty PHP

    Kroki 29-35 · po tym etapie masz 38 z 38 kryteriów (pkt)

    Krok 29: Połączenie z bazą danych

    Kryteria:

    R.5.1 Zastosowano funkcję realizującą połączenie z serwerem bazy danych na localhost, użytkownik root, bez hasła, baza danych sklep

    ok. 2 min
    Polecenie z arkusza

    Wymagania dotyczące skryptu: Napisany w języku PHP, umieszczony w pliku index.php. Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie sklep.

    Połączenie otwierasz raz, zaraz po <body>, w zmiennej $connection. mysqli_connect: serwer, użytkownik, hasło (puste), nazwa bazy (R.5.1). Od tego kroku podgląd to wynik działania strony po stronie serwera.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  30. Krok 30: Skrypt 1: towary w promocji jako lista

    Kryteria: , ,

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

    R.5.4 Skrypt 1 wyświetla nazwy towarów zwrócone zapytaniem (Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt.)

    R.5.5 Wyświetlane przez skrypt 1 nazwy towarów są elementami listy numerowanej

    ok. 3 min
    Polecenie z arkusza

    Skrypt 1: Wysyła do bazy danych zapytanie 1. Nazwy towarów zwrócone zapytaniem wypisywane są jako elementy listy numerowanej.

    Skrypt stoi wewnątrz <ol>. mysqli_query wysyła zapytanie 1, pętla while z mysqli_fetch_row wypisuje każdą nazwę w <li>. W podglądzie: cztery towary, numerowane literami a-d, jak na obrazie 2 (R.5.3, R.5.4, R.5.5).

    index.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  31. Krok 31: Skrypt 2: odczyt wyboru z formularza

    ok. 2 min
    Polecenie z arkusza

    Skrypt 2: Pobiera z formularza nazwę towaru wybranego w liście rozwijalnej.

    Skrypt 2 stoi w bloku wyniku. Dane wysłane metodą POST są w tablicy $_POST, pod nazwą pola z formularza: $_POST['product']. Przy pierwszym wejściu na stronę formularz nie był jeszcze wysłany i tej wartości nie ma - dlatego całość obejmujesz warunkiem isset (funkcja PHP spoza tabeli 1 arkusza - ta wymienia tylko funkcje mysqli): kod wykona się dopiero po kliknięciu SPRAWDŹ.

    Typowe błędy

    Bez isset pierwsze otwarcie strony pokazuje ostrzeżenie PHP „Undefined array key product”.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $product = $_POST['product'];
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>

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

  32. Krok 32: Skrypt 2: zapytanie z wybraną nazwą

    Kryteria:

    R.5.6 Skrypt 2 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 zmodyfikowane tak, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijanej

    ok. 3 min
    Polecenie z arkusza

    Wysyła do bazy danych zapytanie 2, zmodyfikowane w ten sposób, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijalnej.

    Zapytanie 2, ale zamiast stałej nazwy - zmienna: WHERE nazwa = '$product'. Zapytanie bierzesz w cudzysłów, bo w cudzysłowie PHP podstawia wartości zmiennych; apostrofy wokół nazwy zostają wewnątrz, bo nazwa to tekst w SQL. Zapytanie zwraca jeden wiersz, więc wystarczy jedno mysqli_fetch_row. Od tego kroku podgląd pokazuje stronę po wysłaniu formularza z wybraną gumką do mazania (R.5.6).

    ⚠️ Wklejanie tekstu z formularza do SQL jest niebezpieczne - poprawisz to w etapie „Dobre praktyki”.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $product = $_POST['product'];
        $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        $row = mysqli_fetch_row($prices);
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>

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

  33. Krok 33: Skrypt 2: cena niższa o 30%

    Kryteria:

    R.5.7 Skrypt 2 oblicza na podstawie zwróconej zapytaniem wartości cenę promocyjną obniżoną o 30% (np. *0.7). Zaokrąglenie nie jest błędem.

    ok. 1 min
    Polecenie z arkusza

    Na podstawie ceny zwróconej zapytaniem oblicza cenę promocyjną jako wartość niższą o 30%.

    Cena niższa o 30% to 70% ceny: $row[0] * 0.7. W PHP liczba zmiennoprzecinkowa ma kropkę dziesiętną. Dla gumki za 3.2 wychodzi 2.24 (R.5.7).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $product = $_POST['product'];
        $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        $row = mysqli_fetch_row($prices);
        $promoPrice = $row[0] * 0.7;
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>

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

  34. Krok 34: Skrypt 2: dwa wiersze z cenami

    Kryteria:

    R.5.8 Skrypt 2 wyświetla dane w bloku pod formularzem, w dwóch wierszach, zgodnie z formatem cena regularna: <cena_pobrana_z_bazy> cena w promocji 30%: <obliczona_cena>

    ok. 2 min
    Polecenie z arkusza

    Pod formularzem wypisuje dane w bloku, zgodnie z obrazem 2, w formacie: cena regularna: <cena_pobrana_z_bazy> cena w promocji 30%: <obliczona_cena>.

    Dwie linie echo, a między nimi <br> - dwa wiersze w jednym bloku, jak na obrazie 2: „cena regularna: 3.2” i „cena w promocji 30%: 2.24” (R.5.8).

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $product = $_POST['product'];
        $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        $row = mysqli_fetch_row($prices);
        $promoPrice = $row[0] * 0.7;
        echo "cena regularna: $row[0]<br>";
        echo "cena w promocji 30%: $promoPrice";
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  35. Krok 35: Zamknięcie połączenia

    Kryteria:

    R.5.2 Ostatnią operacją na bazie jest zamknięcie połączenia z serwerem bazy danych

    ok. 1 min
    Polecenie z arkusza

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

    mysqli_close($connection) po stopce - ostatnia operacja na bazie (R.5.2). Strona spełnia wszystkie kryteria arkusza.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $product = $_POST['product'];
        $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        $row = mysqli_fetch_row($prices);
        $promoPrice = $row[0] * 0.7;
        echo "cena regularna: $row[0]<br>";
        echo "cena w promocji 30%: $promoPrice";
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  36. Etap 5: Dobre praktyki (poza kluczem)

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

    Krok 36: Skrypt 2: zapytanie przygotowane zamiast wklejania $_POST

    ok. 4 min
    Polecenie z arkusza

    Wysyła do bazy danych zapytanie 2, zmodyfikowane w ten sposób, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijalnej.

    Lista rozwijalna nie chroni przed niczym - wysłane dane da się podmienić w narzędziach przeglądarki i wpisać np. ' OR 1=1 --. Wklejone do SQL zmienia sens zapytania (SQL injection). Zapytanie przygotowane rozdziela kod i dane: mysqli_prepare z ? w miejscu nazwy, mysqli_stmt_bind_param z typem 's' (string) - wartość nigdy nie stanie się częścią SQL. Gdy towaru nie ma ($row puste), skrypt nic nie wypisuje zamiast ostrzeżeń. Stare linie zostają w komentarzu. Podgląd bez zmian.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $statement = mysqli_prepare($connection, 'SELECT cena FROM towary WHERE nazwa = ?');
        mysqli_stmt_bind_param($statement, 's', $_POST['product']);
        mysqli_stmt_execute($statement);
        $row = mysqli_fetch_row(mysqli_stmt_get_result($statement));
        // $product = $_POST['product'];
        // $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        // $row = mysqli_fetch_row($prices);
        if ($row) {
            $promoPrice = $row[0] * 0.7;
            echo "cena regularna: $row[0]<br>";
            echo "cena w promocji 30%: $promoPrice";
        }
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  37. Krok 37: Skrypt 2: ceny w formacie złotówkowym

    ok. 2 min
    Polecenie z arkusza

    Na podstawie ceny zwróconej zapytaniem oblicza cenę promocyjną jako wartość niższą o 30%.

    Mnożenie liczb zmiennoprzecinkowych daje czasem wyniki w rodzaju 15.679999999 i zawsze wypisuje kropkę. number_format($cena, 2, ',', ' ') formatuje liczbę po polsku: dwa miejsca po przecinku, przecinek dziesiętny i spacja między tysiącami - „2,24 zł”, „38,50 zł”. Policz dalej na liczbach, sformatuj dopiero przy wypisywaniu.

    Na egzaminie wystarczy wersja wcześniejsza - format z obrazu 2 to „2.24”, a klucz nie wymaga zaokrąglania.

    index.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sklep dla uczniów</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'sklep');
    ?>
        <header>
            <h1>Dzisiejsze promocje naszego sklepu</h1>
        </header>
        <section id="left">
            <h2>Taniej o 30%</h2>
            <ol>
    <?php
    $products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');
    while ($row = mysqli_fetch_row($products)) {
        echo "<li>$row[0]</li>";
    }
    ?>
            </ol>
        </section>
        <section id="middle">
            <h2>Sprawdź cenę</h2>
            <form method="post">
                <select name="product">
                    <option>Gumka do mazania</option>
                    <option>Cienkopis</option>
                    <option>Pisaki 60 szt.</option>
                    <option>Markery 4 szt.</option>
                </select>
                <button type="submit">SPRAWDŹ</button>
            </form>
            <div id="result">
    <?php
    if (isset($_POST['product'])) {
        $statement = mysqli_prepare($connection, 'SELECT cena FROM towary WHERE nazwa = ?');
        mysqli_stmt_bind_param($statement, 's', $_POST['product']);
        mysqli_stmt_execute($statement);
        $row = mysqli_fetch_row(mysqli_stmt_get_result($statement));
        // $product = $_POST['product'];
        // $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");
        // $row = mysqli_fetch_row($prices);
        if ($row) {
            $promoPrice = $row[0] * 0.7;
            $regular = number_format($row[0], 2, ',', ' ');
            $promo = number_format($promoPrice, 2, ',', ' ');
            echo "cena regularna: $regular zł<br>";
            echo "cena w promocji 30%: $promo zł";
        }
    }
    ?>
            </div>
        </section>
        <section id="right">
            <h2>Kontakt</h2>
            <p>e-mail: <a href="mailto:[email protected]">[email protected]</a></p>
            <img src="promocja.png" alt="promocja">
        </section>
        <footer>
            <h4>Autor strony: Bartosz Bryniarski</h4>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  38. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz w folderze z numerem zdającego 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 folderze z numerem zdającego powinny się znajdować następujące pliki: baza.jpg, index.php, kwerenda1.jpg, kwerenda2.jpg kwerenda3.jpg kwerenda4.jpg, kwerendy.txt, promocja.png, przeglądarka.txt, styl.css oraz ewentualnie inne przygotowane pliki.

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

    Sprawdź listę plików z arkusza (sklep.sql z archiwum nie jest na niej wymieniony, ale może zostać), 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 37.

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.