Przejdź do głównej treści
INF.03-01-22.06-SGCzerwiec 2022 · 32 kroki · ok. 65 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Portal dla wędkarzy (Nowoczesny kod (grid, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza wedkowanie z czterema zapytaniami, zdjęcie przeskalowane do 400 px i strona wedkuj.php z listą ryb rzecznych i tabelą ryb drapieżnych - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • siatka CSS zamiast float: bloki stoją w znaczniku <main> z kolumnami 55% i 45%, a blok prawy zajmuje dwa wiersze siatki. Klucz wprost dopuszcza szerokości w grid-template-columns, więc bloki mogą stać w kodzie w naturalnej kolejności - lewe, potem prawy,
  • zmienne CSS dla kolorów z arkusza, tabela z częściami <thead> i <tbody>, odnośnik do kwerend w akapicie zamiast po <br>,
  • PHP na PDO: oba zapytania strona wykonuje na górze pliku wedkuj.php, przed HTML-em, w bloku try, a w HTML-u zostają tylko pętle i wypisywanie przez funkcję e() (htmlspecialchars),
  • komunikat przy awarii bazy zamiast ostrzeżeń PHP, zapytanie 3 z aliasami tabel.

Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza i zdjęcie pochodzą z prawdziwego archiwum pliki1, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP na bazie z arkusza.

Jak liczą się punkty. Klucz ma 35 pozycji (R.1.1 - R.5.6), każda za 1 punkt; pozycja R.2.10 jest w opublikowanym kluczu pusta (bez treści kryterium). Próg zdania to 75%, czyli 27 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych wedkowanie

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie wedkowanie.

    Rozpakuj pliki1.zip z pulpitu (hasło WedkoWaniE&) do folderu zdającego: baza.sql i ryba1.jpg. W phpMyAdmin Nowa → wedkowanie (bez „ę”) albo zapytaniem:

    CREATE DATABASE wedkowanie CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    

    Arkusz nie podaje porównywania, więc wybór należy do Ciebie. Tabele z baza.sql mają zestaw znaków (latin1) zapisany we własnej definicji, więc ustawienie bazy ich nie zmienia.

    Typowe błędy

    Skrypt łączy się z bazą po nazwie - wędkowanie z polską literą to inna baza i R.5.1 przepada.

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

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Do bazy wedkowanie zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum.

    Import → baza.sql → Wykonaj. Zadanie korzysta z trzech tabel z obrazu 1: ryby (styl_zycia: 1 - drapieżnik, 2 - ryba spokojnego żeru), okres_ochronny (wymiar_ochronny w cm) i lowisko (rodzaj: 1 morze, 2 jezioro, 3 rzeka, 4 zalew, 5 staw). Obie mniejsze tabele wskazują rybę kluczem obcym Ryby_id. Plik zawiera też tabele samochody i typy - w zadaniu ich nie używasz.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

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

    Print Screen, cały ekran z paskiem zadań, zapis jako import.png - w PNG, a zrzuty zapytań będą w JPEG.

    Typowe błędy

    Wykadrowany zrzut albo import.jpg zamiast import.png - R.1.1 przepada.

  4. Krok 4: Zapytanie 1: ryby drapieżne

    Kryteria: ,

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

    R.1.3 Utworzono zapytanie 1 wybierające jedynie pola id, nazwa i wystepowanie z tabeli Ryby dla ryb drapieżnych. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa, wystepowanie FROM ryby WHERE styl_zycia=1; oraz wynik działania udokumentowano zrzutem, na którym jest widocznych dokładnie 5 wierszy dla id = 1, 3, 4, 5, 6, widoczne jedynie kolumny id, nazwa, wystepowanie

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pola id, nazwa i wystepowanie z tabeli Ryby dla ryb drapieżnych.

    „Drapieżne” to w bazie styl_zycia = 1 (opis w treści zadania). Każda klauzula w osobnej linii - łatwiej przeczytać i poprawić. Wynik: 5 ryb o identyfikatorach 1, 3, 4, 5, 6 - jak w kluczu. Zrzut kw1.jpg, zapytanie do kwerendy.txt. To zapytanie wyśle Skrypt 2.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, nazwa, wystepowanie
    FROM ryby
    WHERE styl_zycia = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: wymiar ochronny poniżej 30 cm

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola Ryby_id oraz wymiar_ochronny z tabeli Okres_ochronny dla ryb, których wymiar ochronny jest mniejszy niż 30 cm. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT Ryby_id, wymiar_ochronny FROM okres_ochronny WHERE wymiar_ochronny < 30; oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie 4 wiersze: 4 15; 6 0; 7 0; 8 25

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola Ryby_id oraz wymiar_ochronny z tabeli Okres_ochronny dla ryb, których wymiar ochronny jest mniejszy niż 30 cm.

    „Mniejszy niż” to < (mniejszy lub równy byłby <=). Wynik: 4 wiersze - 4/15, 6/0, 7/0, 8/25 - jak w kluczu. Zrzut kw2.jpg.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT id, nazwa, wystepowanie
    FROM ryby
    WHERE styl_zycia = 1;
    
    -- Zapytanie 2
    SELECT Ryby_id, wymiar_ochronny
    FROM okres_ochronny
    WHERE wymiar_ochronny < 30;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: ryby rzeczne z łowiskiem

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pole nazwa z tabeli Ryby oraz odpowiadające tej nazwie pola akwen i wojewodztwo z tabeli Lowisko dla łowisk, które są rzekami. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, akwen, wojewodztwo FROM ryby JOIN lowisko ON ryby.id = lowisko.Ryby_id WHERE rodzaj = 3; (możliwe również INNER JOIN lub porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie 2 rekordy z danymi: Szczupak Warta-Obrzycko Wielkopolskie; Leszcz Przemsza k.Okradzinowa Slaskie

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pole nazwa z tabeli Ryby oraz odpowiadające tej nazwie pola akwen i wojewodztwo z tabeli Lowisko dla łowisk, które są rzekami. Zapytanie wykorzystuje relację.

    • aliasy tabel r i l - krótki przedrostek mówi, z której tabeli pochodzi każde pole, także w warunku,
    • JOIN ... ON l.Ryby_id = r.id - relacja z obrazu 1: łowisko wskazuje swoją rybę,
    • WHERE l.rodzaj = 3 - tylko rzeki.

    Wynik: 2 wiersze - Szczupak (Warta-Obrzycko, Wielkopolskie) i Leszcz (Przemsza k. Okradzinowa, Slaskie). Zrzut kw3.jpg. To zapytanie wyśle Skrypt 1.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT id, nazwa, wystepowanie
    FROM ryby
    WHERE styl_zycia = 1;
    
    -- Zapytanie 2
    SELECT Ryby_id, wymiar_ochronny
    FROM okres_ochronny
    WHERE wymiar_ochronny < 30;
    
    -- Zapytanie 3
    SELECT r.nazwa, l.akwen, l.wojewodztwo
    FROM ryby AS r
    JOIN lowisko AS l ON l.Ryby_id = r.id
    WHERE l.rodzaj = 3;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: kolumna dobowy_limit 0-255

    Kryteria:

    R.1.6 Utworzono zapytanie 4 dodające do tabeli Ryby kolumnę dobowy_limit typu numerycznego, o rozmiarze pozwalającym na wpisanie jedynie liczb naturalnych z przedziału <0, 255> (tinyint unsigned). W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE ryby ADD dobowy_limit TINYINT UNSIGNED; (jedynie typ TINYINT jest poprawny, błędem jest zapis UNSIGNED przed typem) oraz wynik działania udokumentowano zrzutem, na którym jest widoczna wykonana kwerenda i komunikat lub struktura tabeli z nazwą nowego pola

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: dodające do tabeli Ryby kolumnę dobowy_limit typu numerycznego, o rozmiarze pozwalającym na wpisanie jedynie liczb z przedziału <0, 255>.

    Typ dobierasz do zakresu: TINYINT zajmuje 1 bajt, czyli 256 wartości; bez znaku (UNSIGNED) to dokładnie 0-255. Klucz przyjmuje tylko ten typ i tę kolejność słów (sprawdzone na bazie z archiwum: phpMyAdmin pokazuje tinyint(3) UNSIGNED). Zapytanie wykonaj raz - drugie zgłosi, że kolumna już istnieje. Zrzut kw4.jpg: kwerenda z komunikatem albo struktura tabeli z nowym polem.

    Typowe błędy

    UNSIGNED TINYINT (odwrotna kolejność) to błąd składni; INT pozwala na dużo większe liczby, a TINYINT bez UNSIGNED na zakres -128..127 - klucz nie uzna żadnego z nich.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT id, nazwa, wystepowanie
    FROM ryby
    WHERE styl_zycia = 1;
    
    -- Zapytanie 2
    SELECT Ryby_id, wymiar_ochronny
    FROM okres_ochronny
    WHERE wymiar_ochronny < 30;
    
    -- Zapytanie 3
    SELECT r.nazwa, l.akwen, l.wojewodztwo
    FROM ryby AS r
    JOIN lowisko AS l ON l.Ryby_id = r.id
    WHERE l.rodzaj = 3;
    
    -- Zapytanie 4
    ALTER TABLE ryby
    ADD COLUMN dobowy_limit TINYINT UNSIGNED;
    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 35 kryteriów (pkt)

    Krok 8: ryba1.jpg: szerokość 400 px

    Kryteria:

    R.2.1 Grafikę w pliku o nazwie ryba1.jpg przeskalowano z zachowaniem proporcji do szerokości 400 px, odpowiadająca temu wysokość wynosi 320 px (± 2 px)

    ok. 2 min
    Polecenie z arkusza

    Przygotowanie grafiki: Plik ryba1.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 400 px.

    Grafika jest taka sama jak w wersji podstawowej. Zdjęcie ma 600 × 480 px. W GIMP-ie Obraz → Skaluj obraz, łańcuch proporcji zamknięty, szerokość 400 - wysokość wyjdzie 320 px (klucz R.2.1: 320 ± 2). Eksport pod tą samą nazwą.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik wedkuj.php: HTML5, język, kodowanie

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku wedkuj.php oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> oraz zadeklarowano dla witryny język polski

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze strony o nazwie wedkuj.php zapisanej w języku HTML5. Zadeklarowany język dla witryny: polski. Jawnie zastosowany właściwy standard kodowania polskich znaków.

    <!DOCTYPE html>, <html lang="pl"> i <meta charset="UTF-8"> jako pierwszy element <head> - razem R.2.2. Plik ma rozszerzenie .php, bo dojdzie do niego kod PHP; na egzaminie leży w htdocs XAMPP-a i otwierasz go przez http://localhost/....

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

    Kryteria:

    R.2.3 Nadano tytuł strony: Wędkowanie

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Wędkowanie”.

    <title> z polską literą - stąd potrzebne kodowanie UTF-8 (R.2.3) - i viewport, żeby telefon nie pomniejszał strony do szerokości ekranu komputera.

    wedkuj.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>Wędkowanie</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  11. Krok 11: Podpięcie arkusza stylów

    Kryteria:

    R.3.3 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl_1.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_1.css prawidłowo połączony z kodem strony.

    Nazwa z podkreśleniem i cyfrą: styl_1.css. Całe formatowanie pochodzi z tego pliku - bez atrybutów style w HTML-u (R.3.3).

    Typowe błędy

    styl.css zamiast styl_1.css odcina wszystkie style (R.3.3 i cały rezultat R.4); to samo przy jednym selektorze, który nie trafia w blok (np. kropka zamiast #).

    wedkuj.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>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  12. Krok 12: Bloki: baner, dwa lewe, prawy w main, stopka

    Kryteria:

    R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: banera, dwa bloki lewe, prawy i stopkę. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze blok banera, poniżej po lewej stronie dwa bloki lewe, obok jeden blok prawy, na dole blok stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2.

    Baner to <header>, stopka <footer>. Trzy bloki stoją we wspólnym <main> - to główna treść strony i zarazem pojemnik siatki:

    • pierwszy lewy <section id="rivers"> - ryby rzeczne,
    • drugi lewy <section id="predators"> - ryby drapieżne,
    • prawy <aside id="photo"> - zdjęcie i odnośnik, czyli treść dodatkowa obok głównej.

    Bloki stoją w kodzie w kolejności czytania: najpierw lewe, potem prawy. W wersji z float blok prawy musiał stać przed lewymi, żeby zaczynał się od góry - siatka ustawi go na swoim miejscu niezależnie od kolejności w kodzie (R.2.4).

    wedkuj.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
        </header>
        <main>
            <section id="rivers">
            </section>
            <section id="predators">
            </section>
            <aside id="photo">
            </aside>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  13. Krok 13: Baner

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia o treści „Portal dla wędkarzy”.

    <h1> w <header>.

    wedkuj.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>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
            </section>
            <section id="predators">
            </section>
            <aside id="photo">
            </aside>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  14. Krok 14: Pierwszy blok lewy: nagłówek i lista

    ok. 1 min
    Polecenie z arkusza

    Zawartość pierwszego bloku lewego: Nagłówek trzeciego stopnia o treści: „Ryby zamieszkujące rzeki”. Lista numerowana (uporządkowana) wypełniona przez skrypt 1.

    <h3> i pusta <ol> - elementy listy wypisze Skrypt 1.

    wedkuj.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
            </section>
            <aside id="photo">
            </aside>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  15. Krok 15: Drugi blok lewy: tabela z wierszem nagłówkowym

    Kryteria:

    R.2.8 Pierwszy wiersz tabeli zawiera komórki nagłówkowe o treści, kolejno: L.p., Gatunek, Występowanie, zastosowano znacznik <th>

    ok. 2 min
    Polecenie z arkusza

    Zawartość drugiego bloku lewego: Nagłówek trzeciego stopnia o treści: „Ryby drapieżne naszych wód”. Tabela o trzech kolumnach wypełniona danymi. Pierwszy wiersz zawiera komórki nagłówkowe o treści, kolejno: „L.p.”, „Gatunek”, „Występowanie”.

    • <thead> z pierwszym wierszem: trzy komórki nagłówkowe <th> (R.2.8). scope="col" mówi czytnikowi ekranu, że nagłówek opisuje kolumnę - przy każdej komórce danych odczyta jej nazwę,
    • <tbody> - pusta część na wiersze z danymi, które wypisze Skrypt 2.

    Podział na <thead> i <tbody> nie zmienia wyglądu, a oddziela w kodzie nagłówek od danych.

    wedkuj.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
            </aside>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  16. Krok 16: Blok prawy: obraz i odnośnik do kwerend

    Kryteria: ,

    R.2.9 W bloku prawym umieszczono obraz ryba1.jpg wraz z tekstem alternatywnym "Sum"

    R.3.2 Po wybraniu odnośnika "Pobierz kwerendy" otwiera się lub pobiera plik kwerendy.txt

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku prawego: Obraz ryba1.jpg z tekstem alternatywnym o treści: „Sum”. W kolejnej linii odnośnik do pliku kwerendy.txt z treścią: „Pobierz kwerendy”.

    Obraz z tekstem alternatywnym z arkusza (R.2.9). „W kolejnej linii” daje tu akapit wokół odnośnika - blok zawsze zaczyna nową linię, więc <br> nie jest potrzebny. Odnośnik może prowadzić do dowolnego pliku: href="kwerendy.txt" - przeglądarka otworzy plik tekstowy albo go pobierze (R.3.2).

    Typowe błędy

    kwerendy.txt musi leżeć w tym samym folderze co strona - inaczej odnośnik prowadzi donikąd (R.3.2).

    wedkuj.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>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  17. Krok 17: Stopka

    Kryteria:

    R.2.5 W banerze zapisano nagłówek h1: "Portal dla wędkarzy" oraz w blokach lewych przynajmniej jeden nagłówek h3: "Ryby zamieszkujące rzeki" lub "Ryby drapieżne naszych wód" oraz w stopce paragraf o treści: "Stronę wykonał:" z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: akapit (paragraf) o treści: „Stronę wykonał: ”, oraz zawierający numer, którym został podpisany arkusz.

    Akapit w <footer>. Ten krok domyka R.2.5: <h1> w banerze, <h3> w blokach lewych i akapit w stopce. Na egzaminie wpisujesz numer, którym podpisany jest arkusz (PESEL) - tu stoi autor rozwiązania.

    wedkuj.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>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  18. Etap 3: Styl CSS

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

    Krok 18: Plik styl_1.css: zmienne i krój czcionki

    Kryteria:

    R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (dla *): krój czcionki Helvetica (w przypadku wymienionych kilku czcionek Helvetica jest pierwsza)

    ok. 2 min
    Polecenie z arkusza

    Styl CSS zdefiniowany w całości w zewnętrznym pliku o nazwie styl_1.css. Domyślne formatowanie wszystkich selektorów: krój czcionki Helvetica.

    Trzy kolory z arkusza w zmiennych - #4FB3BF pojawi się w trzech regułach (blok prawy, obramowania tabeli, podświetlenie wiersza), więc zmiana odcienia to jedna linia. Selektor * z Helvetiką na pierwszym miejscu (tak wymaga R.4.1) i krojami zapasowymi: Helvetiki zwykle nie ma w Windows, więc przeglądarka weźmie Arial, a w ostateczności dowolny krój bezszeryfowy.

    styl_1.css CSS nowy plik
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  19. Krok 19: Baner i stopka

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloku banera i stopki: kolor tła #00838F, biały kolor czcionki, marginesy wewnętrzne 5 px, rozmiar czcionki 130%, wyrównanie tekstu do środka.

    Jedna reguła dla dwóch selektorów, kolor ze zmiennej var(--teal) (R.4.3).

    styl_1.css CSS zmienione: 9 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  20. Krok 20: Bloki lewe: tło i wysokości

    ok. 2 min
    Polecenie z arkusza

    Dla obu bloków lewych: kolor tła #EFEFEF, szerokość 55%. Dodatkowo dla pierwszego bloku lewego wysokość 150 px oraz dla drugiego – 300 px.

    Wspólna reguła z tłem i dwie osobne z wysokościami: razem 150 + 300 = 450 px - tyle, ile blok prawy. Szerokości 55% tu nie ma: w siatce procent przy bloku liczyłby się od jego kolumny (55% z 55% strony), więc trafi do definicji kolumn siatki - klucz R.4.5 wprost to dopuszcza.

    styl_1.css CSS zmienione: 13 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  21. Krok 21: Blok prawy

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła #00838F dla banera i stopki, #EFEFEF dla obu bloków lewych oraz #4FB3BF dla bloku prawego

    R.4.4 Ustawiono wysokość pierwszego bloku lewego 150px, drugiego lewego 300px oraz prawego 450px

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

    ok. 1 min
    Polecenie z arkusza

    Dla bloku prawego: kolor tła #4FB3BF, szerokość 45%, wysokość 450 px, wyrównanie tekstu do środka.

    Tło, wysokość i wyśrodkowanie; szerokość 45% - jak przy blokach lewych - w kolumnach siatki. Ta reguła domyka kolory tła (R.4.2), wysokości (R.4.4) i wyśrodkowanie banera, stopki i bloku prawego (R.4.6).

    styl_1.css CSS zmienione: 6 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  22. Krok 22: Obraz: cień i marginesy

    Kryteria:

    R.4.8 Ustawiono cień dla obrazu o wartości box-shadow: 10px 10px 7px DimGray; (lub DimGrey)

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: cień o przesunięciu 10 px w obu osiach, rozmyciu 7 px i kolorze DimGray, marginesy zewnętrzne 20 px.

    box-shadow: przesunięcie w poziomie, w pionie, rozmycie, kolor (R.4.8). Selektor znacznika img - uwaga w arkuszu wyklucza klasy i identyfikatory.

    Typowe błędy

    Reguła #photo img albo klasa obrazu nie spełnia R.4.7 i R.4.8 - klucz wymaga samego selektora img.

    styl_1.css CSS zmienione: 5 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    
    img {
        box-shadow: 10px 10px 7px DimGray;
        margin: 20px;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  23. Krok 23: Tabela: obramowania, wyśrodkowanie, marginesy komórek

    Kryteria: ,

    R.4.7 Ustawiono marginesy wewnętrzne (padding) dla banera i stopki 5px, dla selektorów td i th 4px oraz marginesy zewnętrzne (margin) 20px dla selektora img i auto dla tabeli

    R.4.9 Ustawiono dla tabeli i komórki tabeli obramowanie o cechach 1px solid #4FB3BF, obramowanie połączone border-collapse: collapse; lub border-spacing: 0px; (styl dla th nie jest wymagany)

    ok. 2 min
    Polecenie z arkusza

    Dla selektora tabeli, komórek tabeli, komórek nagłówkowych: obramowanie linią ciągłą o szerokości 1 px i kolorze #4FB3BF, obramowanie tabeli i komórek połączone. Dodatkowo dla selektora tabeli: marginesy zewnętrzne wyliczane automatycznie przez przeglądarkę, szerokość 80%. Dodatkowo dla selektora komórek tabeli i nagłówkowych: marginesy wewnętrzne 4 px.

    Trzy reguły w kolejności arkusza, każda z selektorami znaczników. border-collapse: collapse łączy ramki tabeli i komórek w jedną linię (R.4.9); margin: auto przy szerokości 80% stawia tabelę na środku bloku. Ten krok domyka marginesy (R.4.7: 5 px banera i stopki, 4 px komórek, 20 px obrazu, auto tabeli).

    styl_1.css CSS zmienione: 17 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    
    img {
        box-shadow: 10px 10px 7px DimGray;
        margin: 20px;
    }
    
    table,
    td,
    th {
        border: 1px solid var(--aqua);
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 80%;
    }
    
    td,
    th {
        padding: 4px;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  24. Krok 24: Wiersz pod kursorem

    Kryteria:

    R.4.10 Gdy kursor myszy znajdzie się na wierszu tabeli, kolor tła wiersza zmienia się na #4FB3BF (dla tr:hover)

    ok. 1 min
    Polecenie z arkusza

    Gdy kursor myszy znajdzie się na wierszu tabeli, kolor tła wiersza zmienia się na #4FB3BF.

    Pseudoklasa :hover przy tr - cały wiersz zmienia tło (R.4.10). Wiersze z danymi wypisze Skrypt 2.

    styl_1.css CSS zmienione: 4 linie
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    
    img {
        box-shadow: 10px 10px 7px DimGray;
        margin: 20px;
    }
    
    table,
    td,
    th {
        border: 1px solid var(--aqua);
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 80%;
    }
    
    td,
    th {
        padding: 4px;
    }
    
    tr:hover {
        background-color: var(--aqua);
    }
    Podgląd strony po tym kroku (wedkuj.php)
  25. Krok 25: Układ bloków: siatka z kolumnami 55% i 45%

    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 flex albo grid)

    R.4.5 Ustawiono szerokość obu bloków lewych 55%, bloku prawego 45% (width lub grid- template-columns lub flex) oraz selektora table 80%

    ok. 3 min
    Polecenie z arkusza

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

    • display: grid na <main> i grid-template-columns: 55% 45% - dwie kolumny o szerokościach z arkusza (R.4.5 razem z 80% tabeli),
    • grid-template-areas rysuje układ z obrazu 2 słowami: w lewej kolumnie rivers nad predators, w prawej dwa razy photo - blok prawy zajmuje oba wiersze, czyli 150 + 300 = 450 px,
    • grid-area przypisuje każdy blok do jego obszaru.

    Baner i stopka są poza siatką, więc stoją nad nią i pod nią same z siebie - bez float nie ma clear (R.3.1). Wiersze siatki dopasowują się do wysokości bloków, więc wysokości 150, 300 i 450 px z arkusza działają wprost.

    Typowe błędy

    width: 55% przy bloku w siatce liczy się od kolumny: blok miałby 55% z 55% strony, czyli 30% - szerokości podaje się w grid-template-columns.

    styl_1.css CSS zmienione: 20 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    
    img {
        box-shadow: 10px 10px 7px DimGray;
        margin: 20px;
    }
    
    table,
    td,
    th {
        border: 1px solid var(--aqua);
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 80%;
    }
    
    td,
    th {
        padding: 4px;
    }
    
    tr:hover {
        background-color: var(--aqua);
    }
    
    main {
        display: grid;
        grid-template-columns: 55% 45%;
        grid-template-areas:
            "rivers    photo"
            "predators photo";
    }
    
    #rivers {
        grid-area: rivers;
    }
    
    #predators {
        grid-area: predators;
    }
    
    #photo {
        grid-area: photo;
    }
    Podgląd strony po tym kroku (wedkuj.php)
  26. Etap 4: Skrypty PHP

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

    Krok 26: Połączenie z bazą na górze pliku i zamknięcie

    Kryteria: ,

    R.5.1 Skrypt zawiera działające połączenie z serwerem bazy danych i wybór bazy wedkowanie

    R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)

    ok. 4 min
    Polecenie z arkusza

    Wymagania dotyczące skryptów: Napisane w języku PHP. Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie wedkowanie. Na końcu jest zamykane połączenie z serwerem.

    Oba skrypty pobiorą dane przed HTML-em, w jednym bloku PHP na samej górze wedkuj.php - kod rozmawiający z bazą jest w jednym miejscu, a połączenie zamyka się, zanim przeglądarka dostanie pierwszy znacznik.

    • new PDO(...) - serwer localhost, baza wedkowanie, kodowanie utf8mb4, użytkownik root bez hasła (R.5.1). ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, zamiast zwracać false, którego łatwo nie zauważyć; FETCH_ASSOC - wiersze z nazwami kolumn,
    • $pdo = null - PDO nie ma funkcji „zamknij”: połączenie zamyka się, gdy znika ostatnie odwołanie do obiektu. Stoi na końcu bloku, więc pozostanie ostatnią operacją na bazie (R.5.2),
    • try / catch (PDOException ...) - gdy baza nie działa, uczeń zobaczy zwykłe zdanie, a nie komunikat PHP ze szczegółami serwera.

    PDO zamiast mysqli z tabeli 1 - klucz przyjmuje obie biblioteki (uwaga przy R.5). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    wedkuj.php PHP zmienione: 12 linii
    <?php
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    } catch (PDOException $exception) {
        $databaseError = 'Nie udało się pobrać danych z bazy. Spróbuj odświeżyć stronę za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  27. Krok 27: Skrypt 1: zapytanie 3

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

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

    Zapytanie bez danych od użytkownika, więc wystarczy query. fetchAll() zwraca od razu wszystkie wiersze jako listę tablic z nazwami kolumn: ["nazwa" => "Szczupak", "akwen" => "Warta-Obrzycko", ...]. W catch lista dostaje wartość pustą, żeby HTML niżej nie trafił na niezdefiniowaną zmienną (R.5.3). Na stronie jeszcze nic nie widać.

    wedkuj.php PHP zmienione: 6 linii
    <?php
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: zapytanie 3 - ryby rzeczne z łowiskiem
        $riverFish = $pdo->query(
            'SELECT r.nazwa, l.akwen, l.wojewodztwo FROM ryby AS r JOIN lowisko AS l ON l.Ryby_id = r.id WHERE l.rodzaj = 3'
        )->fetchAll();
    
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    } catch (PDOException $exception) {
        $riverFish = [];
        $databaseError = 'Nie udało się pobrać danych z bazy. Spróbuj odświeżyć stronę za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  28. Krok 28: Skrypt 1: zdanie o każdej rybie jako element listy

    Kryteria: , ,

    R.5.4 Skrypt 1 wyświetla każdy zwrócony zapytaniem wiersz według wzoru: "<nazwa_gatunku> pływa w rzece <nazwa_akwenu>, <województwo>”, gdzie nawiasy <> oznaczają wartości pobrane z bazy danych

    R.5.5 Skrypt 1 wyświetla każdy zwrócony zapytaniem wiersz jako element listy

    R.2.6 W pierwszym bloku lewym umieszczono listę numerowaną z dwoma elementami, zastosowano znaczniki <ol>, <li> (wygenerowaną skryptem lub w HTML)

    ok. 3 min
    Polecenie z arkusza

    Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym elemencie listy, według wzoru: ”<nazwa_gatunku> pływa w rzece <nazwa_akwenu>, <wojewodztwo>”, gdzie nawiasy <> oznaczają wartości pobrane z bazy danych.

    • foreach z dwukropkiem i endforeach - w HTML-u czytelniejsze niż klamry rozrzucone między znacznikami; jeden <li> na każdy wiersz wyniku,
    • kolumny po nazwach: $fish['nazwa'], $fish['akwen'], $fish['wojewodztwo'] - zmiana kolejności w SELECT niczego nie psuje,
    • <?= ... ?> to skrót od <?php echo ... ?>, a funkcja e() (na górze pliku) przepuszcza każdy tekst z bazy przez htmlspecialchars - znak < w nazwie łowiska nie rozbije strony ani nie wstrzyknie do niej kodu.

    W pierwszym bloku: „Szczupak pływa w rzece Warta-Obrzycko, Wielkopolskie” i „Leszcz pływa w rzece Przemsza k. Okradzinowa, Slaskie” - jak na obrazie 2 (R.5.4, R.5.5, R.2.6).

    wedkuj.php PHP zmienione: 8 linii
    <?php
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES);
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: zapytanie 3 - ryby rzeczne z łowiskiem
        $riverFish = $pdo->query(
            'SELECT r.nazwa, l.akwen, l.wojewodztwo FROM ryby AS r JOIN lowisko AS l ON l.Ryby_id = r.id WHERE l.rodzaj = 3'
        )->fetchAll();
    
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    } catch (PDOException $exception) {
        $riverFish = [];
        $databaseError = 'Nie udało się pobrać danych z bazy. Spróbuj odświeżyć stronę za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
    <?php foreach ($riverFish as $fish): ?>
                    <li><?= e($fish['nazwa']) ?> pływa w rzece <?= e($fish['akwen']) ?>, <?= e($fish['wojewodztwo']) ?></li>
    <?php endforeach; ?>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  29. Krok 29: Skrypt 2: wiersze tabeli ryb drapieżnych

    Kryteria: ,

    R.5.6 Skrypt 2 wyświetla każdy zwrócony zapytaniem wiersz jako osobny wiersz tabeli zgodnie z Obrazem 2 w arkuszu egzaminacyjnym

    R.2.7 W drugim bloku lewym umieszczono tabelę o trzech kolumnach, zastosowano znaczniki <table>, <tr>, <td> (wygenerowaną skryptem lub w HTML)

    ok. 3 min
    Polecenie z arkusza

    Skrypt 2: wysyła do bazy danych zapytanie 1. Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym wierszu tabeli.

    Zapytanie 1 w tym samym bloku na górze pliku, przed zamknięciem połączenia, a w <tbody> pętla: każdy wiersz wyniku to <tr> z trzema komórkami. W kolumnie „L.p.” stoi identyfikator ryby, jak na obrazie 2 (1, 3, 4, 5, 6). Najedź na wiersz - podświetla się (R.5.6, R.2.7).

    wedkuj.php PHP zmienione: 11 linii
    <?php
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES);
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: zapytanie 3 - ryby rzeczne z łowiskiem
        $riverFish = $pdo->query(
            'SELECT r.nazwa, l.akwen, l.wojewodztwo FROM ryby AS r JOIN lowisko AS l ON l.Ryby_id = r.id WHERE l.rodzaj = 3'
        )->fetchAll();
    
        // Skrypt 2: zapytanie 1 - ryby drapieżne
        $predators = $pdo->query('SELECT id, nazwa, wystepowanie FROM ryby WHERE styl_zycia = 1')->fetchAll();
    
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    } catch (PDOException $exception) {
        $riverFish = [];
        $predators = [];
        $databaseError = 'Nie udało się pobrać danych z bazy. Spróbuj odświeżyć stronę za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
    <?php foreach ($riverFish as $fish): ?>
                    <li><?= e($fish['nazwa']) ?> pływa w rzece <?= e($fish['akwen']) ?>, <?= e($fish['wojewodztwo']) ?></li>
    <?php endforeach; ?>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
    <?php foreach ($predators as $fish): ?>
                        <tr>
                            <td><?= e($fish['id']) ?></td>
                            <td><?= e($fish['nazwa']) ?></td>
                            <td><?= e($fish['wystepowanie']) ?></td>
                        </tr>
    <?php endforeach; ?>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  30. Krok 30: Awaria bazy: komunikat zamiast ostrzeżeń

    ok. 3 min

    Dodatek spoza arkusza - klucz go nie ocenia. Gdy baza nie odpowiada (wyłączony MySQL, złe hasło), blok catch ustawia $databaseError, a nad blokami pojawia się zdanie z role="alert" - czytnik ekranu przeczyta je od razu. Lista i tabela zostają puste, bo zmienne mają w catch wartości puste, a baner, zdjęcie i stopka działają dalej.

    W CSS komunikat dostaje grid-column: 1 / -1 - zajmuje całą szerokość siatki, od pierwszej do ostatniej linii kolumn, zamiast wcisnąć się w obszar jednego bloku.

    Sprawdzone na prawdziwym PHP ze złym hasłem do bazy: jedno zdanie, bez ostrzeżeń i bez szczegółów serwera.

    styl_1.css CSS zmienione: 7 linii
    :root {
        --teal: #00838F;
        --light: #EFEFEF;
        --aqua: #4FB3BF;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header,
    footer {
        background-color: var(--teal);
        color: white;
        padding: 5px;
        font-size: 130%;
        text-align: center;
    }
    
    #rivers,
    #predators {
        background-color: var(--light);
    }
    
    #rivers {
        height: 150px;
    }
    
    #predators {
        height: 300px;
    }
    
    #photo {
        background-color: var(--aqua);
        height: 450px;
        text-align: center;
    }
    
    img {
        box-shadow: 10px 10px 7px DimGray;
        margin: 20px;
    }
    
    table,
    td,
    th {
        border: 1px solid var(--aqua);
        border-collapse: collapse;
    }
    
    table {
        margin: auto;
        width: 80%;
    }
    
    td,
    th {
        padding: 4px;
    }
    
    tr:hover {
        background-color: var(--aqua);
    }
    
    main {
        display: grid;
        grid-template-columns: 55% 45%;
        grid-template-areas:
            "rivers    photo"
            "predators photo";
    }
    
    #rivers {
        grid-area: rivers;
    }
    
    #predators {
        grid-area: predators;
    }
    
    #photo {
        grid-area: photo;
    }
    
    #db-error {
        grid-column: 1 / -1;
        margin: 0;
        padding: 5px;
        background-color: var(--light);
    }
    wedkuj.php PHP zmienione: 3 linie
    <?php
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES);
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=wedkowanie;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    
        // Skrypt 1: zapytanie 3 - ryby rzeczne z łowiskiem
        $riverFish = $pdo->query(
            'SELECT r.nazwa, l.akwen, l.wojewodztwo FROM ryby AS r JOIN lowisko AS l ON l.Ryby_id = r.id WHERE l.rodzaj = 3'
        )->fetchAll();
    
        // Skrypt 2: zapytanie 1 - ryby drapieżne
        $predators = $pdo->query('SELECT id, nazwa, wystepowanie FROM ryby WHERE styl_zycia = 1')->fetchAll();
    
        $pdo = null;    // zamknięcie połączenia - ostatnia operacja na bazie
    } catch (PDOException $exception) {
        $riverFish = [];
        $predators = [];
        $databaseError = 'Nie udało się pobrać danych z bazy. Spróbuj odświeżyć stronę za chwilę.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wędkowanie</title>
        <link rel="stylesheet" href="styl_1.css">
    </head>
    <body>
        <header>
            <h1>Portal dla wędkarzy</h1>
        </header>
        <main>
    <?php if (isset($databaseError)): ?>
            <p role="alert" id="db-error"><?= e($databaseError) ?></p>
    <?php endif; ?>
            <section id="rivers">
                <h3>Ryby zamieszkujące rzeki</h3>
                <ol>
    <?php foreach ($riverFish as $fish): ?>
                    <li><?= e($fish['nazwa']) ?> pływa w rzece <?= e($fish['akwen']) ?>, <?= e($fish['wojewodztwo']) ?></li>
    <?php endforeach; ?>
                </ol>
            </section>
            <section id="predators">
                <h3>Ryby drapieżne naszych wód</h3>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">L.p.</th>
                            <th scope="col">Gatunek</th>
                            <th scope="col">Występowanie</th>
                        </tr>
                    </thead>
                    <tbody>
    <?php foreach ($predators as $fish): ?>
                        <tr>
                            <td><?= e($fish['id']) ?></td>
                            <td><?= e($fish['nazwa']) ?></td>
                            <td><?= e($fish['wystepowanie']) ?></td>
                        </tr>
    <?php endforeach; ?>
                    </tbody>
                </table>
            </section>
            <aside id="photo">
                <img src="ryba1.jpg" alt="Sum">
                <p><a href="kwerendy.txt">Pobierz kwerendy</a></p>
            </aside>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (wedkuj.php)
  31. Etap 5: Porównanie z wersją podstawową

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

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

    ok. 3 min

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

    wersja podstawowawersja nowoczesna
    układfloat: right bloku prawego, float: left lewych, clear stopki<main> z siatką 55% 45% i obszarami
    kolejność w kodzieblok prawy przed lewymi (wymóg float)kolejność czytania: lewe, potem prawy
    szerokościwidth przy blokachgrid-template-columns
    kolorywpisane w każdą regułęzmienne CSS
    tabelawiersze wprost w <table><thead>, <tbody>, scope
    odnośnikpo <br>w akapicie
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami
    gdzie są zapytaniaskrypty w środku HTML-ujeden blok na górze pliku
    odczyt wierszamysqli_fetch_row, $row[1]fetchAll, $fish['akwen']
    wypisywaniedane z bazy wproste() - htmlspecialchars
    awaria bazyostrzeżenia PHPkomunikat

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 arkusza i łatwiej ją napisać bez dokumentacji pod ręką. Nowoczesna oszczędza clear i pilnowania kolejności bloków w kodzie, a siatkę klucz wprost dopuszcza. Obie biblioteki klucz przyjmuje.

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

  32. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Umieść go w folderze z numerem, którym został podpisany arkusz. Nagraj płytę z rezultatami pracy. W folderze z numerem, którym został podpisany arkusz, powinny znajdować się pliki: import.png, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, przeglądarka.txt, ryba1.jpg, styl_1.css, wedkuj.php, ewentualnie inne przygotowane pliki.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona przez http://localhost/.... Sprawdź listę plików (kwerendy.txt musi leżeć obok strony - prowadzi do niego odnośnik), 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 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.