Przejdź do głównej treści
E.14-01-22.01-SGStyczeń 2022 · 33 kroki · ok. 69 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Grzybobranie - baza grzybów (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza grzybobranie z czterema zapytaniami i strona grzyby.php z listą grzybów jadalnych, grzybami do zup i galerią zdjęć - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • flexbox zamiast float: bloki tytułowy i miniatury stoją we wspólnym <header>, lewy i prawy - we wspólnym <main>, oba pojemniki z display: flex. Szerokości 80%, 20%, 25% i 75% zostają na blokach, bo tam klucz je ocenia, a stopka nie potrzebuje clear,
  • zmienne CSS dla kolorów z arkusza - zielony i beżowy powtarzają się w kilku regułach,
  • PHP na PDO na samej górze grzyby.php: trzy zapytania pobierają dane do tablic, połączenie zamyka się, zanim przeglądarka dostanie pierwszą linię HTML-a, a w blokach zostają tylko pętle wypisujące,
  • każdy tekst z bazy przez e() (htmlspecialchars) - także w atrybutach alt i title, gdzie w wersji podstawowej dało się wstrzyknąć kod JavaScript.

To arkusz E.14 z sesji styczeń 2022 - kwalifikacji formuły 2012, którą zastąpiła INF.03. Archiwum pliki1.zip z tej sesji nie zostało opublikowane; zdjęcia i tabele pochodzą z oryginalnego archiwum CKE z sesji styczeń 2019 (pliki5.zip, to samo hasło @grzYbY, plik dane2.sql - załącznik na stronie arkusza). Zapytania są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.0.7 - użyte konstrukcje działają w obu wersjach).

Jak liczą się punkty. Klucz ma 34 kryteria (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 26 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.

  1. Etap 1: Baza danych

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

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

    ok. 2 min
    Polecenie z arkusza

    Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie pliki1.zip zabezpieczone hasłem: @grzYbY Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj numeru, którym został podpisany arkusz. Rozpakowane pliki umieść w tym folderze. Po skończonej pracy wyniki zapisz w tym folderze.

    Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum rozpakowane 7-Zipem z hasłem @grzYbY. Archiwum z sesji 2022 nie zostało opublikowane - tym samym hasłem otwiera się pliki5.zip z sesji styczeń 2019 (załącznik na stronie arkusza): osiem zdjęć grzybów i plik SQL z tabelami (tam dane2.sql).

  2. Krok 2: XAMPP i pusta baza grzybobranie

    ok. 2 min
    Polecenie z arkusza

    Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz nową bazę danych o nazwie grzybobranie

    Start przy Apache i MySQL, potem http://localhost/phpmyadmin, Nowa, nazwa grzybobranie, porównywanie utf8mb4_polish_ci - pełny zestaw znaków Unicode i polska kolejność sortowania.

  3. Krok 3: Import tabel i zrzut import.png

    Kryteria:

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

    ok. 3 min
    Polecenie z arkusza

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

    Baza grzybobranie, karta Import, plik SQL z archiwum, Wykonaj. Zadanie korzysta z trzech tabel z obrazu 1: grzyby, rodzina (1 pieczarkowate … 5 boczniakowate) i potrawy (1 sos … 4 zupa, 5 niejadalne); rodzina_id i potrawy_id to klucze obce. Zrzut całego ekranu z komunikatem o sukcesie i listą tabel: import.png.

    Typowe błędy

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

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: grzyby jadalne

    Kryteria: ,

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

    R.1.3 Utworzono zapytanie 1 wybierające jedynie pola id, nazwa oraz potoczna z tabeli grzyby jedynie dla grzybów jadalnych. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa, potoczna FROM grzyby WHERE jadalny = 1; oraz wynik działania udokumentowano zrzutem, na którym widocznych jest dokładnie 7 rekordów o id: 1, 2, 3, 4, 6, 7, 8; jedynie pola id, nazwa, potoczna

    ok. 3 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie danych. Zapytania zapisz w pliku kwerendy.txt. Wykonaj zrzuty ekranu przedstawiające wyniki działania zapytań. Zrzuty zapisz w formacie PNG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań Zapytanie 1: wybierające jedynie pola id, nazwa oraz potoczna z tabeli grzyby jedynie dla grzybów jadalnych

    Każda klauzula w osobnej linii - przy dłuższych zapytaniach łatwiej wtedy znaleźć błąd. Grzyb jadalny ma w polu jadalny wartość 1. Wynik: 7 wierszy o id 1, 2, 3, 4, 6, 7, 8 (bez szatana). Zapytanie trafia do kwerendy.txt, zrzut - do kw1.png.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, nazwa, potoczna
    FROM grzyby
    WHERE jadalny = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: grzyby do zup z nazwą rodziny

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pole potoczna z tabeli grzyby oraz odpowiadające mu pole nazwa z tabeli rodzina jedynie dla grzybów, do których przypisana jest potrawa zupa. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT potoczna, rodzina.nazwa FROM grzyby JOIN rodzina ON rodzina_id = rodzina.id WHERE potrawy_id = 4; (lub INNER JOIN lub porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym widoczne są dokładnie 2 rekordy z danymi: prawdziwek, borowikowate, podgrzybek, borowikowate

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pole potoczna z tabeli grzyby oraz odpowiadające mu pole nazwa z tabeli rodzina jedynie dla grzybów, do których przypisana jest potrawa zupa

    JOIN … ON grzyby.rodzina_id = rodzina.id - relacja: klucz obcy grzyba równa się kluczowi głównemu rodziny. Kolumnę nazwa mają obie tabele, więc trzeba wskazać rodzina.nazwa. Zupa ma w tabeli potrawy numer 4. Wynik: 2 wiersze, prawdziwek, borowikowate i podgrzybek, borowikowate. Zrzut: kw2.png.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT id, nazwa, potoczna
    FROM grzyby
    WHERE jadalny = 1;
    
    -- Zapytanie 2
    SELECT potoczna, rodzina.nazwa
    FROM grzyby
    JOIN rodzina ON grzyby.rodzina_id = rodzina.id
    WHERE potrawy_id = 4;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: pliki zdjęć i nazwy grzybów

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pola nazwa_pliku oraz nazwa z tabeli grzyby . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa_pliku, nazwa FROM grzyby; oraz wynik działania udokumentowano zrzutem, na którym widoczne jest 8 rekordów, jedynie pola nazwa_pliku i nazwa

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola nazwa_pliku oraz nazwa z tabeli grzyby

    Dwie kolumny, bez warunku - 8 wierszy, od pieczarka.jpg, pieczarka dwuzarodnikowa do trufla.jpg, trufla letnia. Zrzut: kw3.png.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT id, nazwa, potoczna
    FROM grzyby
    WHERE jadalny = 1;
    
    -- Zapytanie 2
    SELECT potoczna, rodzina.nazwa
    FROM grzyby
    JOIN rodzina ON grzyby.rodzina_id = rodzina.id
    WHERE potrawy_id = 4;
    
    -- Zapytanie 3
    SELECT nazwa_pliku, nazwa
    FROM grzyby;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: kolumna opis w tabeli rodzina

    Kryteria:

    R.1.6 Utworzono zapytanie 4 dodające do tabeli rodzina pole opis typu napisowego. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE rodzina ADD opis TEXT; (lub ADD COLUMN, dowolne typy napisowe) oraz wynik działania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnie dodanej kolumnie lub struktura tabeli z dodaną kolumną

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: dodające do tabeli rodzina pole opis typu napisowego

    ALTER TABLE zmienia strukturę tabeli, ADD opis TEXT dodaje kolumnę typu tekstowego (klucz przyjmuje też ADD COLUMN i inne typy napisowe). Na zrzucie kw4.png komunikat albo karta Struktura tabeli rodzina z nową kolumną.

    Typowe błędy

    Drugie wykonanie tego samego ALTER TABLE kończy się błędem #1060 „Duplicate column name”.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT id, nazwa, potoczna
    FROM grzyby
    WHERE jadalny = 1;
    
    -- Zapytanie 2
    SELECT potoczna, rodzina.nazwa
    FROM grzyby
    JOIN rodzina ON grzyby.rodzina_id = rodzina.id
    WHERE potrawy_id = 4;
    
    -- Zapytanie 3
    SELECT nazwa_pliku, nazwa
    FROM grzyby;
    
    -- Zapytanie 4
    ALTER TABLE rodzina
    ADD opis TEXT;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Kopia zdjęcia: podgrzybek-miniatura.jpg

    ok. 1 min
    Polecenie z arkusza

    Obraz podgrzybek.jpg należy skopiować na nowy i nazwać podgrzybek-miniatura.jpg (powinny być dwa pliki: podgrzybek.jpg i podgrzybek-miniatura.jpg).

    Kopia pliku (Ctrl+C, Ctrl+V) i zmiana nazwy na podgrzybek-miniatura.jpg. Oryginał zostaje - do niego poprowadzi odnośnik z miniatury.

  9. Krok 9: Miniatura: wysokość 80 px z zachowaniem proporcji

    Kryteria:

    R.2.7 Obraz podgrzybek-miniatura.jpg przeskalowano z zachowaniem proporcji do wysokości 80 px, odpowiadająca temu szerokość wynosi 107 px (± 5 px)

    ok. 2 min
    Polecenie z arkusza

    Obraz podgrzybek-miniatura.jpg należy przeskalować z zachowaniem proporcji do wysokości 80 px

    W GIMP-ie Obraz → Skaluj obraz na kopii, łańcuch proporcji zamknięty, wysokość 80 px - szerokość wychodzi 267 × 80 / 200 ≈ 107 px (klucz: 107 ±5). Plik → Nadpisz podgrzybek-miniatura.jpg.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Plik grzyby.php i kodowanie polskich znaków

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie grzyby.php Zastosowany właściwy standard kodowania polskich znaków

    Szkielet HTML5 w pliku grzyby.php: lang="pl" i <meta charset="UTF-8"> jako pierwszy element <head>, plik zapisany w UTF-8 (R.2.1). Rozszerzenie .php, bo na górze pliku stanie skrypt.

    grzyby.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  11. Krok 11: Tytuł strony

    Kryteria:

    R.2.2 Nadano tytuł strony: "Grzybobranie”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Grzybobranie”

    <title>Grzybobranie</title> (R.2.2). Obok znacznik viewport - telefon pokaże stronę w swojej szerokości. Klucz go nie ocenia; w nowej stronie dopisuje się go z nawyku.

    grzyby.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  12. Krok 12: Podpięcie arkusza stylów styl.css

    Kryteria:

    R.3.3 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 źle przypisano 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"> (R.3.3). Całe formatowanie pochodzi z tego pliku - w znacznikach nie ma atrybutów style.

    Typowe błędy

    Klucz odbiera R.3.3 także wtedy, gdy choć jeden selektor nie trafia w blok (np. kropka zamiast # przy identyfikatorze).

    grzyby.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  13. Krok 13: Bloki: tytułowy i miniatury w header, lewy i prawy w main, stopka

    Kryteria:

    R.2.3 Wygląd strony zdefiniowano dzieląc ją na bloki: tytułowy, miniatury, lewy, prawy, stopka. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze: tytułowy i miniatury, poniżej: lewy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby układ bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2

    Każdy blok z arkusza to znacznik sekcji (R.2.3): sekcje title, thumbnail, left i right oraz <footer>. Bloki jednego rzędu stoją we wspólnym pojemniku - <header> dla górnego rzędu (nagłówek strony) i <main> dla treści głównej (czytnik ekranu pozwala do niej przeskoczyć). CSS zamieni każdy pojemnik w jeden rząd bloków.

    Typowe błędy

    Bloki z samych <div> nie spełniają R.2.3 - klucz wymaga znaczników sekcji.

    grzyby.php PHP zmienione: 14 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
            </section>
            <section id="thumbnail">
            </section>
        </header>
        <main>
            <section id="left">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  14. Krok 14: Blok tytułowy: nagłówek pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku tytułowego: nagłówek pierwszego stopnia o treści „Czas na grzyby!”

    <h1> - jedyny nagłówek pierwszego stopnia na stronie.

    grzyby.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
            </section>
        </header>
        <main>
            <section id="left">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  15. Krok 15: Blok miniatury: miniatura będąca odnośnikiem

    Kryteria: ,

    R.2.6 W bloku miniatury umieszczono obraz podgrzybek-miniatura.jpg , z tekstem alternatywnym "Grzybobranie"

    R.3.2 Miniatura jest odnośnikiem, którego kliknięcie pobiera / otwiera plik podgrzybek.jpg

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku miniatury: obraz podgrzybek-miniatura.jpg z tekstem alternatywnym „Grzybobranie”, jest on odnośnikiem, który prowadzi do obrazu podgrzybek.jpg

    Obraz z src i alt (R.2.6) wewnątrz <a href="podgrzybek.jpg"> - kliknięcie miniatury otwiera pełne zdjęcie (R.3.2). Bez width i height w znaczniku: wymiary ma już sam plik miniatury.

    grzyby.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  16. Krok 16: Blok lewy: dwa nagłówki i lista punktowana

    Kryteria:

    R.2.5 W bloku lewym umieszczono listę punktowaną, zastosowano znaczniki <ul>, <li> oraz ich zamknięcia

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek trzeciego stopnia o treści „Grzyby jadalne” efekt działania skryptu 1 Nagłówek trzeciego stopnia o treści „Polecamy do zup” lista punktowana (nieuporządkowana), a w niej efekt działania skryptu 2

    Dwa <h3> i lista punktowana <ul> (R.2.5) - jej elementy <li> wypisze skrypt 2. Między nagłówkami miejsce na akapity skryptu 1.

    grzyby.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
                <h3>Polecamy do zup</h3>
                <ul>
                </ul>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  17. Krok 17: Stopka: akapit z autorem

    Kryteria:

    R.2.4 W bloku tytułowym zapisano h1: "Czas na grzyby!" oraz w bloku lewym zapisano dwa h3: "Grzyby jadalne" i "Polecamy do zup" oraz w stopce zapisano akapit z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: akapit (paragraf) o treści „Autor: ”, dalej wstawiony numer zdającego

    Na egzaminie po dwukropku wpisujesz swój numer PESEL; w tym rozwiązaniu stoi tam imię i nazwisko autora, Bartosz Bryniarski. Komplet nagłówków i akapit w stopce dają R.2.4.

    grzyby.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
                <h3>Polecamy do zup</h3>
                <ul>
                </ul>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  18. Etap 3: Styl CSS

    Kroki 18-26 · po tym etapie masz 26 z 34 kryteriów (pkt)

    Krok 18: Plik styl.css: kolory jako zmienne i krój Helvetica

    Kryteria:

    R.4.1 Ustawiono domyślny krój czcionki dla całej strony na Helvetica (dla * lub html, lub body, lub kontenera całej strony)

    ok. 2 min
    Polecenie z arkusza

    Domyślne dla całej strony: krój czcionki Helvetica

    Na początku pliku zmienne CSS w :root: zielony z arkusza powtarza się w trzech blokach i w ramkach zdjęć, beżowy - w dwóch blokach. Reguły dalej używają var(--green), więc zmiana odcienia to jedna linia.

    Krój Helvetica na selektorze * (R.4.1). Windows nie ma tego kroju - przeglądarka podstawi zastępczy bezszeryfowy, jak na obrazie 2.

    styl.css CSS nowy plik
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    Podgląd strony po tym kroku (grzyby.php)
  19. Krok 19: Blok tytułowy: tło, kolor tekstu, wymiary, wyśrodkowanie

    ok. 1 min
    Polecenie z arkusza

    Dla bloku tytułowego: kolor tła ForestGreen, biały kolor czcionki, wysokość 100 px, szerokość 80%, wyrównanie tekstu do środka

    Pięć właściwości z arkusza na #title; kolor tła ze zmiennej --green, w której stoi ForestGreen.

    styl.css CSS zmienione: 8 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    Podgląd strony po tym kroku (grzyby.php)
  20. Krok 20: Blok miniatury: tło i wymiary

    ok. 1 min
    Polecenie z arkusza

    Dla bloku miniatury: kolor tła ForestGreen, wysokość 100 px, szerokość 20%

    80% + 20% = 100% górnego rzędu.

    styl.css CSS zmienione: 6 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    Podgląd strony po tym kroku (grzyby.php)
  21. Krok 21: Blok lewy: tło i wymiary

    ok. 1 min
    Polecenie z arkusza

    Dla bloku lewego: kolor tła Tan, wysokość 700 px, szerokość 25%

    Kolor ze zmiennej --tan.

    styl.css CSS zmienione: 6 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    Podgląd strony po tym kroku (grzyby.php)
  22. Krok 22: Blok prawy: tło i wymiary

    Kryteria: ,

    R.4.4 Ustawiono wysokość 100px dla bloku tytułowego i bloku miniatury oraz 700px dla bloków lewego i prawego

    R.4.5 Ustawiono szerokość 20% dla bloku miniatury, 80% dla bloku tytułowego, 25% dla bloku lewego i 75% dla bloku prawego

    ok. 1 min
    Polecenie z arkusza

    Dla bloku prawego: kolor tła Tan, wysokość 700 px, szerokość 75%

    25% + 75% = 100% drugiego rzędu. Wysokości (R.4.4) i szerokości (R.4.5) czterech bloków są ustawione - na samych blokach, bo tam klucz je ocenia.

    styl.css CSS zmienione: 6 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    
    #right {
        background-color: var(--tan);
        height: 700px;
        width: 75%;
    }
    Podgląd strony po tym kroku (grzyby.php)
  23. Krok 23: Stopka: tło, kolor tekstu, wyśrodkowanie

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła ForestGreen dla bloków tytułowego, miniatury i stopki oraz Tan dla bloków lewego i prawego

    R.4.3 Ustawiono biały kolor czcionki dla bloku tytułowego i stopki

    R.4.6 Ustawiono wyrównanie tekstu do środka dla bloku tytułowego i stopki

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła ForestGreen, biały kolor czcionki, wyrównanie tekstu do środka

    Kolory tła (R.4.2), biały tekst bloku tytułowego i stopki (R.4.3) oraz ich wyśrodkowanie (R.4.6) są gotowe.

    styl.css CSS zmienione: 6 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    
    #right {
        background-color: var(--tan);
        height: 700px;
        width: 75%;
    }
    
    footer {
        background-color: var(--green);
        color: white;
        text-align: center;
    }
    Podgląd strony po tym kroku (grzyby.php)
  24. Krok 24: Obrazy: marginesy, obramowanie i zaokrąglenie rogów

    Kryteria: , ,

    R.4.7 Ustawiono marginesy zewnętrzne (margin) 4px oraz wewnętrzne (padding) 5px dla selektora obrazu

    R.4.8 Ustawiono obramowanie 1px linią ciągłą o kolorze ForestGreen dla obrazów

    R.4.9 Ustawiono zaokrąglenie rogów 20px dla obrazów

    ok. 2 min
    Polecenie z arkusza

    Dla selektora obrazu: marginesy zewnętrzne 4 px, marginesy wewnętrzne 5 px, obramowanie 1 px linią ciągłą o kolorze ForestGreen, zaokrąglenie rogów 20 px

    Selektor znacznika img obejmuje miniaturę i wszystkie zdjęcia skryptu 3: margin: 4px i padding: 5px (R.4.7), ramka 1 px w kolorze ze zmiennej (R.4.8), border-radius: 20px (R.4.9). Miniatura z odstępami i ramką ma 80 + 2 × (4 + 5 + 1) = 100 px - dokładnie wysokość bloku miniatury.

    styl.css CSS zmienione: 7 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    
    #right {
        background-color: var(--tan);
        height: 700px;
        width: 75%;
    }
    
    footer {
        background-color: var(--green);
        color: white;
        text-align: center;
    }
    
    img {
        margin: 4px;
        padding: 5px;
        border: 1px solid var(--green);
        border-radius: 20px;
    }
    Podgląd strony po tym kroku (grzyby.php)
  25. Krok 25: Obraz pod kursorem: obramowanie Maroon

    Kryteria:

    R.4.10 W momencie, gdy kursor znajdzie się na obrazie, jego kolor obramowania zmienia się na Maroon

    ok. 1 min
    Polecenie z arkusza

    W momencie, gdy kursor znajdzie się na obrazie, jego kolor obramowania zmienia się na Maroon

    Pseudoklasa :hover zmienia tylko border-color - grubość i styl ramki zostają z reguły img (R.4.10).

    styl.css CSS zmienione: 4 linie
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    
    #right {
        background-color: var(--tan);
        height: 700px;
        width: 75%;
    }
    
    footer {
        background-color: var(--green);
        color: white;
        text-align: center;
    }
    
    img {
        margin: 4px;
        padding: 5px;
        border: 1px solid var(--green);
        border-radius: 20px;
    }
    
    img:hover {
        border-color: Maroon;
    }
    Podgląd strony po tym kroku (grzyby.php)
  26. Krok 26: Układ bloków: flexbox w header i main

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze: tytułowy i miniatury, poniżej: lewy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby układ bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2

    display: flex na <header> i <main> ustawia bloki każdego pojemnika w jednym rzędzie, w kolejności z HTML-a, z szerokościami z ich własnych reguł. Pojemniki stoją jeden pod drugim, a stopka pod nimi - bez float i bez clear (R.3.1). W wersji podstawowej o tym, który blok trafi do drugiego rzędu, decydowała suma procentów; tutaj rzędy wynikają wprost z HTML-a.

    Druga reguła zeruje margines akapitu w stopce. Akapit ma domyślnie 16 px marginesu u góry i u dołu, a ten margines „wychodzi” poza stopkę - między blokami a zieloną stopką zostałby biały pasek. W wersji podstawowej ukrywało go clear: both. Arkusz tej reguły nie wymaga; dzięki niej stopka przylega do bloków jak na obrazie 2.

    Typowe błędy

    Bloki o sumie szerokości 100% nie mogą mieć marginesów ani obramowań - we flexboxie zwęziłyby się wtedy, zamiast trzymać 25% i 75%.

    styl.css CSS zmienione: 9 linii
    :root {
        --green: ForestGreen;
        --tan: Tan;
    }
    
    * {
        font-family: Helvetica;
    }
    
    #title {
        background-color: var(--green);
        color: white;
        height: 100px;
        width: 80%;
        text-align: center;
    }
    
    #thumbnail {
        background-color: var(--green);
        height: 100px;
        width: 20%;
    }
    
    #left {
        background-color: var(--tan);
        height: 700px;
        width: 25%;
    }
    
    #right {
        background-color: var(--tan);
        height: 700px;
        width: 75%;
    }
    
    footer {
        background-color: var(--green);
        color: white;
        text-align: center;
    }
    
    img {
        margin: 4px;
        padding: 5px;
        border: 1px solid var(--green);
        border-radius: 20px;
    }
    
    img:hover {
        border-color: Maroon;
    }
    
    header,
    main {
        display: flex;
    }
    
    footer p {
        margin: 0;
    }
    Podgląd strony po tym kroku (grzyby.php)
  27. Etap 4: Skrypty PHP

    Kroki 27-31 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 27: Skrypt na górze pliku i połączenie z bazą

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP i zawiera przynajmniej jedną zgodną ze składnią instrukcję

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

    ok. 4 min
    Polecenie z arkusza

    Napisane w języku PHP Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie grzybobranie

    Skrypt stoi na samej górze grzyby.php, przed <!DOCTYPE html>: najpierw pobiera dane z bazy, a HTML niżej je tylko wypisuje (R.5.1). Pod nagłówkiem „Grzyby jadalne” pojawia się na razie jedno: komunikat, gdy połączenie się nie uda.

    • e() - krótka funkcja z htmlspecialchars: każdy tekst z bazy wypisany na stronie ma znaki <, >, & i oba rodzaje cudzysłowów zamienione na encje, więc nie stanie się kodem strony,
    • new PDO(...) - serwer localhost, baza grzybobranie i kodowanie w jednym napisie, potem użytkownik root i puste hasło (R.5.2),
    • ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek; FETCH_ASSOC - wiersze przychodzą jako tablice z nazwami kolumn ($mushroom['nazwa'] zamiast $row[1]),
    • try / catch - gdy baza nie działa, odwiedzający dostaje zwykłe zdanie, a nie komunikat PHP z nazwą użytkownika bazy i ścieżką pliku na serwerze.

    Połączenie z nazwą bazy stoi w pliku strony, bo tam klucz je sprawdza, jeśli strona się nie uruchomi (uwaga przy R.5). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    grzyby.php PHP zmienione: 20 linii
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $error = null;
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=grzybobranie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $error = 'Baza grzybów jest chwilowo niedostępna, spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
    <?php if ($error !== null): ?>
                <p><?= e($error) ?></p>
    <?php endif; ?>
                <h3>Polecamy do zup</h3>
                <ul>
                </ul>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  28. Krok 28: Skrypt 1: zapytanie 1 i grzyby jadalne w akapitach

    Kryteria: ,

    R.5.4 Skrypt 1 wysyła do bazy danych zapytanie 1 lub skrypt 2 wysyła zapytanie 2 lub skrypt 3 wysyła zapytanie 3

    R.5.5 Skrypt 1 wyświetla wszystkie pobrane z bazy danych wiersze w osobnych akapitach w formacie: <id>. <nazwa> (<potoczna>), gdzie pola zapisane w <> są pobrane z bazy danych

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 1: Wysyła do bazy zapytanie 1 Kolejne wiersze są wyświetlane w osobnych akapitach w formacie: <id>. <nazwa> (<potoczna>), gdzie pola zapisane w <> są pobrane z bazy danych

    Na górze pliku trzy puste tablice, $edible, $soups i $photos - wypełnią je zapytania. Ustawione przed try, istnieją także wtedy, gdy połączenie się nie uda, więc pętle w HTML-u nic nie wypiszą zamiast zgłosić ostrzeżenie.

    • $pdo->query(...) wysyła zapytanie 1 bez zmian (R.5.4) - nie ma w nim danych od użytkownika, więc zapytanie przygotowane nie jest potrzebne,
    • fetchAll() od razu zwraca wszystkie wiersze jako tablicę, bez pętli while.

    Pod nagłówkiem pętla foreach w składni alternatywnej (foreach (...): … endforeach;), czytelniejszej przy przeplataniu PHP z HTML-em: numer, kropka, nazwa i nazwa potoczna w nawiasie, każdy grzyb w osobnym akapicie (R.5.5). id to liczba z bazy; teksty idą przez e(). Zapis <?= … ?> to skrót od <?php echo … ?>.

    Podgląd: siedem akapitów, od 1. pieczarka dwuzarodnikowa (pieczarka) do 8. trufla letnia (trufla).

    grzyby.php PHP zmienione: 8 linii
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $error = null;
    $edible = [];
    $soups = [];
    $photos = [];
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=grzybobranie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $edible = $pdo->query('SELECT id, nazwa, potoczna FROM grzyby WHERE jadalny = 1;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Baza grzybów jest chwilowo niedostępna, spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
    <?php if ($error !== null): ?>
                <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($edible as $mushroom): ?>
                <p><?= $mushroom['id'] ?>. <?= e($mushroom['nazwa']) ?> (<?= e($mushroom['potoczna']) ?>)</p>
    <?php endforeach; ?>
                <h3>Polecamy do zup</h3>
                <ul>
                </ul>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  29. Krok 29: Skrypt 2: zapytanie 2 i elementy listy

    Kryteria:

    R.5.6 Skrypt 2 wyświetla każdy wiersz jako element listy, w formacie: <potoczna>, rodzina: <nazwa rodziny>, gdzie pola zapisane w <> są pobrane z bazy danych

    ok. 3 min
    Polecenie z arkusza

    Działanie skryptu 2: Wysyła do bazy zapytanie 2 wyświetla każdy wiersz jako elementy listy, w formacie: <potoczna>, rodzina: <nazwa rodziny>, gdzie pola zapisane w <> są pobrane z bazy danych

    Drugie zapytanie na górze pliku, wynik w $soups. Zapytanie jest długie, więc napis stoi w osobnej linii wywołania - łatwiej go porównać z kwerendy.txt.

    Pętla stoi wewnątrz <ul>: każdy wiersz to element <li> z tekstem „, rodzina: ” między polami (R.5.6). Kolumna rodzina.nazwa wraca w tablicy pod kluczem nazwa - PDO bierze nazwę kolumny bez nazwy tabeli. Podgląd: prawdziwek, rodzina: borowikowate i podgrzybek, rodzina: borowikowate.

    grzyby.php PHP zmienione: 6 linii
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $error = null;
    $edible = [];
    $soups = [];
    $photos = [];
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=grzybobranie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $edible = $pdo->query('SELECT id, nazwa, potoczna FROM grzyby WHERE jadalny = 1;')->fetchAll();
        $soups = $pdo->query(
            'SELECT potoczna, rodzina.nazwa FROM grzyby JOIN rodzina ON grzyby.rodzina_id = rodzina.id WHERE potrawy_id = 4;'
        )->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Baza grzybów jest chwilowo niedostępna, spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
    <?php if ($error !== null): ?>
                <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($edible as $mushroom): ?>
                <p><?= $mushroom['id'] ?>. <?= e($mushroom['nazwa']) ?> (<?= e($mushroom['potoczna']) ?>)</p>
    <?php endforeach; ?>
                <h3>Polecamy do zup</h3>
                <ul>
    <?php foreach ($soups as $mushroom): ?>
                    <li><?= e($mushroom['potoczna']) ?>, rodzina: <?= e($mushroom['nazwa']) ?></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  30. Krok 30: Skrypt 3: zapytanie 3 i galeria zdjęć z dymkiem

    Kryteria: ,

    R.5.7 Skrypt 3 wyświetla obrazy, dla których nazwa pliku jest pobrana z bazy. Liczba obrazów jest równa liczbie zwróconych zapytaniem wierszy

    R.5.8 W skrypcie 3 zwrócona zapytaniem nazwa jest zapisana jako atrybut title obrazu

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 3: Wysyła do bazy zapytanie 3 Dla każdego wiersza wartości zwrócone zapytaniem: nazwa pliku i nazwa wykorzystane są do wyświetlenia obrazu, w ten sposób, że nazwa pliku jest źródłem obrazu, a nazwa jest tytułem obrazu wyświetlanym jako dymek, gdy kursor myszy znajdzie się na elemencie (patrz obraz 2).

    Trzecie zapytanie na górze, wynik w $photos. W bloku prawym pętla wypisuje jeden znacznik <img> na wiersz - tyle zdjęć, ile wierszy (R.5.7): nazwa pliku w src, nazwa grzyba w title - dymek po zatrzymaniu kursora (R.5.8) - i w alt dla czytników ekranu.

    Znacznik jest zwykłym HTML-em, a PHP wstawia tylko wartości - nie trzeba ukośników przed cudzysłowami jak w echo "…\"…". e() w atrybutach jest tu najważniejsze: w wersji podstawowej nazwa z cudzysłowem zamykała atrybut title i dopisywała do zdjęcia kod JavaScript. Podgląd: osiem zdjęć, dymek drugiego to „czubajka kania”.

    grzyby.php PHP zmienione: 4 linie
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $error = null;
    $edible = [];
    $soups = [];
    $photos = [];
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=grzybobranie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $edible = $pdo->query('SELECT id, nazwa, potoczna FROM grzyby WHERE jadalny = 1;')->fetchAll();
        $soups = $pdo->query(
            'SELECT potoczna, rodzina.nazwa FROM grzyby JOIN rodzina ON grzyby.rodzina_id = rodzina.id WHERE potrawy_id = 4;'
        )->fetchAll();
        $photos = $pdo->query('SELECT nazwa_pliku, nazwa FROM grzyby;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Baza grzybów jest chwilowo niedostępna, spróbuj ponownie za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
    <?php if ($error !== null): ?>
                <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($edible as $mushroom): ?>
                <p><?= $mushroom['id'] ?>. <?= e($mushroom['nazwa']) ?> (<?= e($mushroom['potoczna']) ?>)</p>
    <?php endforeach; ?>
                <h3>Polecamy do zup</h3>
                <ul>
    <?php foreach ($soups as $mushroom): ?>
                    <li><?= e($mushroom['potoczna']) ?>, rodzina: <?= e($mushroom['nazwa']) ?></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
    <?php foreach ($photos as $photo): ?>
                <img src="<?= e($photo['nazwa_pliku']) ?>" alt="<?= e($photo['nazwa']) ?>" title="<?= e($photo['nazwa']) ?>">
    <?php endforeach; ?>
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (grzyby.php)
  31. Krok 31: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

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

    PDO nie ma funkcji close - połączenie zamyka się, gdy znika ostatnie odwołanie do obiektu, dlatego $pdo = null (R.5.3). Stoi w bloku finally, który wykonuje się zawsze po try - po udanych zapytaniach i po wyjątku. Wszystkie trzy zapytania pobrały już dane do tablic, więc połączenie zamyka się, zanim przeglądarka dostanie choć linię HTML-a. W wersji podstawowej mysqli_close musiało stać za skryptem 3; tutaj miejsce zamknięcia nie zależy od układu strony.

    grzyby.php PHP zmienione: 2 linie
    <?php
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $error = null;
    $edible = [];
    $soups = [];
    $photos = [];
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=grzybobranie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $edible = $pdo->query('SELECT id, nazwa, potoczna FROM grzyby WHERE jadalny = 1;')->fetchAll();
        $soups = $pdo->query(
            'SELECT potoczna, rodzina.nazwa FROM grzyby JOIN rodzina ON grzyby.rodzina_id = rodzina.id WHERE potrawy_id = 4;'
        )->fetchAll();
        $photos = $pdo->query('SELECT nazwa_pliku, nazwa FROM grzyby;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Baza grzybów jest chwilowo niedostępna, spróbuj ponownie za chwilę.';
    } finally {
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Grzybobranie</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <section id="title">
                <h1>Czas na grzyby!</h1>
            </section>
            <section id="thumbnail">
                <a href="podgrzybek.jpg"><img src="podgrzybek-miniatura.jpg" alt="Grzybobranie"></a>
            </section>
        </header>
        <main>
            <section id="left">
                <h3>Grzyby jadalne</h3>
    <?php if ($error !== null): ?>
                <p><?= e($error) ?></p>
    <?php endif; ?>
    <?php foreach ($edible as $mushroom): ?>
                <p><?= $mushroom['id'] ?>. <?= e($mushroom['nazwa']) ?> (<?= e($mushroom['potoczna']) ?>)</p>
    <?php endforeach; ?>
                <h3>Polecamy do zup</h3>
                <ul>
    <?php foreach ($soups as $mushroom): ?>
                    <li><?= e($mushroom['potoczna']) ?>, rodzina: <?= e($mushroom['nazwa']) ?></li>
    <?php endforeach; ?>
                </ul>
            </section>
            <section id="right">
    <?php foreach ($photos as $photo): ?>
                <img src="<?= e($photo['nazwa_pliku']) ?>" alt="<?= e($photo['nazwa']) ?>" title="<?= e($photo['nazwa']) ?>">
    <?php endforeach; ?>
            </section>
        </main>
        <footer>
            <p>Autor: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  32. Etap 5: Porównanie z wersją podstawową

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

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

    ok. 3 min

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

    wersja podstawowawersja nowoczesna
    układfloat: left sekcji, clear: both stopkidwa rzędy: <header> i <main> z display: flex
    kolorywpisane w każdej regulezmienne --green i --tan w :root
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami i try / catch
    gdzie są skryptytrzy bloki PHP w treści stronywszystkie zapytania na górze pliku, w blokach tylko pętle
    wiersze wynikuwhile + mysqli_fetch_row, $row[0]fetchAll + foreach, $mushroom['nazwa']
    zdjęcie w skrypcie 3echo z ukośnikami przed cudzysłowamizwykły znacznik HTML z wstawionymi wartościami
    tekst z bazywklejony wprost (zabezpieczony dopiero w etapie dobrych praktyk)zawsze przez e(), także w alt i title
    zamknięcie bazymysqli_close po skrypcie 3$pdo = null w finally
    baza niedostępna„Fatal error” z nazwą użytkownika bazy i ścieżką plikujedno zdanie, reszta strony się wyświetla

    Sprawdzone na tych samych próbach co wersja podstawowa: nazwa grzyba z cudzysłowem i kodem JavaScript wyświetla się dosłownie w dymku i w akapicie, a złe hasło do bazy daje tylko komunikat pod nagłówkiem „Grzyby jadalne”.

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 i łatwiej ją napisać bez dokumentacji. Nowoczesna jest bezpieczna od pierwszej linii - a klucz przyjmuje obie.

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

  33. Etap 6: Oddanie pracy

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

    Krok 33: Zawartość folderu i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    UWAGA: katalog z rezultatami pracy oraz płytę należy opisać numerem, którym został podpisany arkusz, czyli numerem PESEL lub w przypadku jego braku numerem paszportu.

    W folderze z numerem zdającego: import.png, kw1.png - kw4.png, kwerendy.txt, grzyby.php, styl.css, wszystkie zdjęcia z archiwum oraz podgrzybek.jpg i podgrzybek-miniatura.jpg. Strona sprawdzana przez http://localhost/…. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

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

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.

Potwierdzenie

Informacja