Przejdź do głównej treści
INF.03-03-25.06-SGCzerwiec 2025 · 29 kroków · ok. 79 min · 36 kryteriów z klucza

Rozwiązanie krok po kroku: Portal biblioteki szkolnej (Nowoczesny kod (grid, PDO))

To drugi sposób rozwiązania tego samego arkusza: portal biblioteki szkolnej z bazą biblioteka, okładkami, stroną biblioteka.php i tabelą pięciu losowych książek. Obie wersje spełniają wszystkie 36 kryteriów klucza - różni je sposób pisania kodu.

Czym ta wersja różni się od podstawowej:

  • artykuły na siatce CSS pisanej „od małego ekranu”: domyślnie jedna kolumna 98%, a od 800 px trzy kolumny po 30% w grid-template-columns - bez float i clear,
  • kolory w zmiennych CSS, a kolor każdego artykułu przez article:nth-of-type(n) - HTML nie potrzebuje identyfikatorów,
  • tabela z <thead> i <tbody>, nagłówki kolumn z scope="col", podświetlenie tylko wierszy z danymi,
  • PHP na PDO: dane połączenia w config.php, całe pobieranie danych na górze pliku w try/catch - gdy baza nie odpowiada, strona i tak się wyświetla, a w tabeli pojawia się krótki komunikat,
  • e() (czyli htmlspecialchars) przy każdym wypisaniu danych z bazy i szablon z foreach/endforeach.

Kroki nadal idą zdanie po zdaniu za treścią arkusza. Podgląd strony PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 na bazie z arkusza (po zapytaniu 3) - z jedną różnicą: zamiast losowania podgląd pokazuje pięć książek z ilustracji 2, żeby wyglądał jak w arkuszu. Okładki, baza i teksty.txt pochodzą z prawdziwego archiwum pliki12.

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

  1. Etap 1: Baza danych

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

    Krok 1: Baza biblioteka, import i zrzut import.png

    Kryteria:

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

    ok. 4 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie biblioteka, z zestawem polskich znaków (np. utf8_unicode_ci). Z rozpakowanego archiwum zaimportuj tabelę z pliku baza.sql do utworzonej bazy. Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą import. Nie kadruj zrzutu.

    1. Baza: Nowa w phpMyAdmin albo zapytanie CREATE DATABASE biblioteka CHARACTER SET utf8 COLLATE utf8_unicode_ci;.
    2. Import: zaznacz bazę biblioteka, Import → baza.sql → Wykonaj. Powstają ksiazki (5381 wierszy, cały katalog) i uczniowie (15 wierszy) z kluczem obcym id_ksiazki; uczeń bez książki ma tam NULL.
    3. Zrzut całego ekranu z paskiem zadań jako import.png. W tym arkuszu wszystkie zrzuty są w PNG.
    Typowe błędy

    Import bez zaznaczonej bazy biblioteka ląduje w innej bazie - skrypt nie znajdzie potem tabeli ksiazki.

  2. Krok 2: Zapytanie 1: wypożyczenia po 2 marca 2020

    Kryteria: ,

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

    R.1.3 Wykonane zapytanie 1 wybierające jedynie nazwisko, imię, klasę i datę wypożyczenia uczniów, dla których data wypożyczenia jest późniejsza niż 2020-03-02. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwisko, imie, klasa, data_wypozyczenia FROM uczniowie WHERE data_wypozyczenia > '2020-03-02'; (data zapisana 02-03-2020 jest błędem) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 5 rekordów zawierających jedynie pola nazwisko, imie, klasa, data_wypozyczenia (nazwiska: pierwsze Woźniak, ostatnie Kawtan)

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie nazwisko, imię, klasę i datę wypożyczenia dla uczniów dla których data wypożyczenia jest późniejsza niż 2020-03-02.

    WHERE data_wypozyczenia > '2020-03-02' - „późniejsza niż” to ostre >, a data w apostrofach w formacie RRRR-MM-DD, tak jak przechowuje ją baza (klucz: zapis 02-03-2020 to błąd). Wynik: 5 wierszy, od Woźniak do Kawtan. Zapytania zapisuj w kwerendy.txt z komentarzem -- nad każdym; zrzut: kw1.png.

    Typowe błędy

    >= '2020-03-02' dokłada dwa wypożyczenia z 2 marca - 7 wierszy zamiast 5.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwisko, imie, klasa, data_wypozyczenia
    FROM uczniowie
    WHERE data_wypozyczenia > '2020-03-02';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 2
  3. Krok 3: Zapytanie 2: kto co wypożyczył

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie nazwisko, imię, datę wypożyczenia oraz odpowiadające im autora i kod książki wypożyczonej przez ucznia. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwisko, imie, data_wypozyczenia, autor, kod FROM uczniowie INNER JOIN ksiazki ON uczniowie.id_ksiazki = ksiazki.id; (możliwe samo JOIN, również z przyrównaniem kluczy po WHERE) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 7 rekordów dla kodów 2711, 271C, 2719, 277D, 2735, 2739, 2727

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie nazwisko, imię i datę wypożyczenia oraz odpowiadające im pola autor i kod książki wypożyczonej przez ucznia. Należy posłużyć się relacją.

    • FROM uczniowie AS u JOIN ksiazki AS k - aliasy tabel u i k,
    • ON k.id = u.id_ksiazki - uczeń łączy się z książką, której id ma w kluczu obcym,
    • w SELECT każda kolumna z aliasem - od razu widać, z której tabeli pochodzi.

    JOIN (czyli INNER JOIN) pomija uczniów z NULL w id_ksiazki - mają nie wypożyczać niczego, więc nie ma ich w wyniku. Wynik: 7 wierszy, kody 2711, 271C, 2719, 277D, 2735, 2739, 2727. Zrzut: kw2.png.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT nazwisko, imie, klasa, data_wypozyczenia
    FROM uczniowie
    WHERE data_wypozyczenia > '2020-03-02';
    
    -- Zapytanie 2
    SELECT u.nazwisko, u.imie, u.data_wypozyczenia, k.autor, k.kod
    FROM uczniowie AS u
    JOIN ksiazki AS k ON k.id = u.id_ksiazki;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 3: usunięcie książek z autorem „0”

    Kryteria:

    R.1.5 Wykonane zapytanie 3 usuwające wszystkie rekordy tabeli ksiazki, w których autorowi została przypisana wartość ‘0’ . W pliku z kwerendami lub na zrzucie istnieje zapis np.: DELETE FROM ksiazki WHERE autor = '0'; oraz wynik działania zapytania udokumentowany zrzutem, na którym widoczny jest komunikat o poprawnym usunięciu 621 rekordów lub widoczna tabela z usuniętymi rekordami

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: usuwające wszystkie rekordy tabeli ksiazki, w których autorowi została przypisana wartość '0'.

    DELETE FROM ksiazki WHERE autor = '0' - zero jako napis w apostrofach, bo kolumna autor jest tekstowa. Bezpieczny nawyk przed każdym DELETE: najpierw ten sam warunek w SELECT COUNT(*) FROM ksiazki WHERE autor = '0' - wynik 621 mówi, ile wierszy zniknie. Potem DELETE i zrzut komunikatu o usunięciu 621 rekordów: kw3.png.

    Typowe błędy

    DELETE FROM ksiazki bez WHERE kasuje cały katalog - phpMyAdmin pyta o potwierdzenie, ale cofnąć się tego nie da.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT nazwisko, imie, klasa, data_wypozyczenia
    FROM uczniowie
    WHERE data_wypozyczenia > '2020-03-02';
    
    -- Zapytanie 2
    SELECT u.nazwisko, u.imie, u.data_wypozyczenia, k.autor, k.kod
    FROM uczniowie AS u
    JOIN ksiazki AS k ON k.id = u.id_ksiazki;
    
    -- Zapytanie 3
    DELETE FROM ksiazki
    WHERE autor = '0';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 4: pięć losowych książek

    Kryteria:

    R.1.6 Wykonane zapytanie 4 wybierające losowo dokładnie pięć rekordów z całej tabeli ksiazki zawierających jedynie pola autor, tytul i kod. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT autor, tytul, kod FROM ksiazki ORDER BY RAND() LIMIT 5; oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 5 rekordów zawierających jedynie pola autor, tytul i kod

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 4: wybierające losowo dokładnie pięć rekordów z całej tabeli ksiazki zawierających jedynie pola autor, tytul i kod.

    ORDER BY RAND() tasuje wiersze (każdy dostaje losową liczbę i sortowanie idzie po niej), a LIMIT 5 bierze pięć pierwszych. Każde uruchomienie daje inny wynik. Zrzut: kw4.png. To zapytanie wyśle skrypt PHP.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT nazwisko, imie, klasa, data_wypozyczenia
    FROM uczniowie
    WHERE data_wypozyczenia > '2020-03-02';
    
    -- Zapytanie 2
    SELECT u.nazwisko, u.imie, u.data_wypozyczenia, k.autor, k.kod
    FROM uczniowie AS u
    JOIN ksiazki AS k ON k.id = u.id_ksiazki;
    
    -- Zapytanie 3
    DELETE FROM ksiazki
    WHERE autor = '0';
    
    -- Zapytanie 4
    SELECT autor, tytul, kod
    FROM ksiazki
    ORDER BY RAND()
    LIMIT 5;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Etap 2: Grafika i strona HTML

    Kroki 6-14 · po tym etapie masz 16 z 36 kryteriów (pkt)

    Krok 6: Okładki: pas książek na górze i dole, zapis w JPEG

    Kryteria:

    R.2.1 Motywy książek z grafiki ksiazki.png umieszczone na dole i górze przynajmniej jednej grafiki JPEG z ksiazka1 , ksiazka2 , ksiazka3 . Motyw w całości mieści się w wymiarach książki

    ok. 5 min
    Polecenie z arkusza

    Grafiki ksiazka1, ksiazka2, ksiazka3 zapisane w formacie JPEG. Grafiki ksiazka1.jpg, ksiazka2.jpg, ksiazka3.jpg przekształcone poprzez wklejenie na pierwszy plan książek z pliku ksiazki.png na dole i górze obrazu, powinny one w całości zmieścić się w wymiarach obrazu, patrz ilustracja 2.

    W GIMP-ie dla każdej okładki 350 × 480 px: Plik → Otwórz jako warstwy → ksiazki.png (1799 × 314 px), Warstwa → Skaluj warstwę do ok. 330 px szerokości z zachowaniem proporcji, przesunięcie na górę, Warstwa → Duplikuj i przesunięcie kopii na dół, eksport jako ksiazkaN.jpg. Pas musi w całości zmieścić się w obrazie.

    Grafika nie ma „nowoczesnej” wersji - to ta sama praca co w wersji podstawowej.

    Typowe błędy

    Pas wklejony w pełnej szerokości wystaje poza okładkę - klucz wymaga, żeby mieścił się w całości.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Okładki: autor i tytuł czcionką szeryfową

    Kryteria:

    R.2.2 Na przynajmniej jednej grafice umieszczony autor i tytuł. Zastosowana czcionka szeryfowa, tytuły zostały pogrubione

    ok. 5 min
    Polecenie z arkusza

    W grafice ksiazka1.jpg w niebieskim polu umieszczony tekst „HANS CHRISTIAN ANDERSEN Ropucha”. W grafice ksiazka2.jpg w zielonym polu umieszczony tekst „MARIA KONOPNICKA Przygoda z lalką”. W grafice ksiazka3.jpg w fioletowym polu umieszczony tekst „IGNACY KRASICKI Przyjaciel”. Tekst zapisany jest czcionką szeryfową, tytuł jest dodatkowo pogrubiony.

    Narzędzie Tekst, krój szeryfowy (np. Times New Roman, Georgia), autor wielkimi literami, tytuł w osobnej linii pogrubiony (Bold). Po wpisaniu - ponowny eksport do .jpg.

    Typowe błędy

    Domyślny krój GIMP-a (Sans) jest bezszeryfowy; cały tekst pogrubiony też jest błędem - pogrubiony ma być tylko tytuł.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Krok 8: Plik biblioteka.php: HTML5, język i kodowanie

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie biblioteka.php. Zapisana w języku HTML5. Zadeklarowany polski język zawartości witryny. Jawnie zastosowany właściwy standard kodowania polskich znaków.

    <!DOCTYPE html>, <html lang="pl"> i <meta charset="UTF-8"> jako pierwszy element <head> - przeglądarka zna kodowanie, zanim przeczyta cokolwiek z polskimi znakami.

    biblioteka.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  9. Krok 9: Tytuł, viewport i arkusz stylów

    Kryteria: ,

    R.2.4 Nadany tytuł stronie "BIBLIOTEKA SZKOLNA”

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

    ok. 2 min
    Polecenie z arkusza

    Tytuł strony „BIBLIOTEKA SZKOLNA” widoczny na karcie przeglądarki. Arkusz stylów w pliku o nazwie styles.css prawidłowo połączony z kodem strony.

    <title> (R.2.4) i <link rel="stylesheet" href="styles.css"> (R.3.2) - w tym arkuszu plik nazywa się styles.css. Meta viewport jest potrzebna, żeby zapytanie @media o 800 px działało na telefonie tak samo jak w zwężonym oknie komputera.

    Typowe błędy

    href="styl.css" z przyzwyczajenia - strona traci wszystkie style, a z nimi cały rezultat R.4.

    biblioteka.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>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  10. Krok 10: Bloki semantyczne

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

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

    Układ z klucza R.2.5: <header>, <section>, <main> z trzema <article> w środku, <footer>. Artykuły nie mają identyfikatorów - każdy dostanie inny kolor, ale CSS rozpozna je po pozycji (:nth-of-type), więc HTML zostaje czystą strukturą.

    Typowe błędy

    Artykuły poza <main> nie spełniają R.2.5 - klucz wymaga ich wewnątrz bloku głównego.

    biblioteka.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>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
        </header>
        <section>
        </section>
        <main>
            <article>
            </article>
            <article>
            </article>
            <article>
            </article>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  11. Krok 11: Nagłówek strony i nagłówek sekcji

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: nagłówek drugiego stopnia o treści: „STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN”. Zawartość sekcji: nagłówek trzeciego stopnia o treści: „Nasze dzisiejsze propozycje:”.

    <h2> w nagłówku i <h3> w sekcji, treści skopiowane z teksty.txt.

    biblioteka.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>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
        </section>
        <main>
            <article>
            </article>
            <article>
            </article>
            <article>
            </article>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  12. Krok 12: Tabela z częścią nagłówkową i treścią

    Kryteria:

    R.2.10 Pierwszy wiersz tabeli zawiera komórki nagłówkowe, zastosowane znaczniki <tr>, <th>

    ok. 3 min
    Polecenie z arkusza

    Tabela o trzech kolumnach, w której pierwszy wiersz zawiera komórki nagłówkowe o treści: Autor, Tytuł, Katalog. Tabela jest wypełniona przez skrypt.

    Tabela jest podzielona na dwie części: <thead> z wierszem komórek nagłówkowych <th> (R.2.10) i pusty <tbody>, do którego skrypt wpisze książki. Podział mówi przeglądarce i czytnikowi ekranu, który wiersz jest nagłówkiem, a przy wydruku długiej tabeli nagłówek powtarza się na każdej stronie. scope="col" przy <th> zaznacza, że komórka opisuje kolumnę - czytnik ekranu przeczyta „Autor: Stanisław Wyspiański”.

    Pierwszy wiersz tabeli nadal zawiera komórki nagłówkowe - <thead> niczego tu nie zmienia w ocenie.

    biblioteka.php PHP zmienione: 11 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
            </article>
            <article>
            </article>
            <article>
            </article>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  13. Krok 13: Trzy artykuły: okładka i streszczenie

    Kryteria: ,

    R.2.6 Zapisane w bloku nagłówkowym <h2>: "STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN", w bloku sekcji <h3>: "Nasze dzisiejsze propozycje:" oraz paragraf w przynajmniej jednym bloku artykułu

    R.2.7 W przynajmniej jednym bloku artykułu umieszczony obraz ksiazka1 lub ksiazka2 , lub ksiazka3. Obraz ma tekst alternatywny "okładka książki"

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku głównego: trzy bloki artykułu. W każdym bloku artykułu znajdują się: grafika, kolejno ksiazka1.jpg, ksiazka2.jpg, ksiazka3.jpg z tekstami alternatywnymi o treści „okładka książki”. Paragraf zawierający odpowiedni tekst streszczenia - patrz ilustracja 2 oraz plik teksty.txt.

    W każdym artykule obraz z tekstem alternatywnym z arkusza i paragraf ze streszczeniem skopiowanym z teksty.txt.

    Obrazy mają atrybuty width="350" height="480" - rzeczywiste wymiary pliku. Przeglądarka zna wtedy proporcje okładki, zanim ją pobierze, i rezerwuje na nią miejsce: tekst pod spodem nie „skacze”, gdy obraz się wczyta. Wyświetlany rozmiar i tak ustawi CSS (szerokość 70%).

    Typowe błędy

    src="ksiazka1.png" wskazuje plik z archiwum, a nie przerobioną okładkę JPEG.

    biblioteka.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  14. Krok 14: Stopka z numerem zdającego

    Kryteria:

    R.2.8 W bloku stopki wstawiony został numer zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: napis „Stronę wykonał: ”, dalej wstawiony numer zdającego.

    Tu stoi nazwisko autora rozwiązania - na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL).

    biblioteka.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>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  15. Etap 3: Styl CSS

    Kroki 15-22 · po tym etapie masz 29 z 36 kryteriów (pkt)

    Krok 15: Zmienne z kolorami, krój i wyrównanie

    Kryteria:

    R.4.1 Ustawione domyślne formatowanie wszystkich selektorów (*): krój czcionki Roboto, w przypadku jego braku Arial, sans-serif, wyrównanie tekstu do środka

    ok. 2 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: krój czcionki: Roboto, w przypadku jego braku Arial, sans-serif, wyrównanie tekstu do środka.

    Na początku styles.css zmienne z kolorami arkusza w :root; SteelBlue występuje cztery razy (nagłówek, stopka, ramka tabeli, podświetlony wiersz), więc ustawiony raz w --color-bar. Potem * z listą krojów: przeglądarka bierze pierwszy dostępny - Roboto, Arial, a w ostateczności dowolny bezszeryfowy (R.4.1).

    styles.css CSS nowy plik
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  16. Krok 16: Ciało strony, nagłówek i stopka

    Kryteria: ,

    R.4.2 Ustawiony kolor tła LightCyan dla selektora body

    R.4.4 Ustawiony dla bloku nagłówkowego i stopki biały kolor czcionki

    ok. 2 min
    Polecenie z arkusza

    Dla selektora ciała strony: kolor tła LightCyan. Dla bloku nagłówkowego i stopki: kolor tła SteelBlue, biały kolor czcionki, marginesy wewnętrzne 10 px.

    body selektorem znacznika - arkusz zastrzega to na stronie 5 (R.4.2). Nagłówek i stopka w jednej regule: tło ze zmiennej, biały tekst (R.4.4), padding: 10px.

    styles.css CSS zmienione: 11 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  17. Krok 17: Artykuły: margines wewnętrzny górny i zewnętrzne

    ok. 1 min
    Polecenie z arkusza

    Dla wszystkich bloków artykułu: margines wewnętrzny górny 40 px, marginesy zewnętrzne 1% oraz ułożenie.

    padding-top: 40px i margin: 1% - dokładnie z arkusza (R.4.8 ocenia margines 1% artykułów). W siatce procent marginesu liczy się od szerokości komórki, a nie całego bloku głównego, więc odstęp jest mniejszy niż przy float; większy oddech między kolumnami da column-gap w następnym kroku.

    styles.css CSS zmienione: 5 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    
    article {
        padding-top: 40px;
        margin: 1%;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  18. Krok 18: Szerokie ekrany: trzy kolumny po 30%

    Kryteria: ,

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

    R.3.4 Po zwiększeniu szerokości okna przeglądarki jedynie dla 800 px i powyżej bloki w bloku głównym są ustawione obok siebie

    ok. 4 min
    Polecenie z arkusza

    Gdy szerokość ekranu wynosi 800 px i więcej, trzy bloki są wyświetlane obok siebie, ich szerokość wynosi 30%.

    Blok główny staje się siatką. Reguła bez warunku to wąski ekran - jedna kolumna 98% (o tym w następnym kroku), a justify-content: center ustawia kolumny siatki na środku bloku głównego, więc wolne miejsce rozkłada się po równo z obu stron. Zapytanie @media (width >= 800px) - zapis zakresowy z poziomu 4 zapytań medialnych, dosłownie „800 px i więcej” - zmienia siatkę na trzy kolumny: repeat(3, 30%) to skrót od 30% 30% 30%. column-gap: 2% odsuwa kolumny od siebie zamiast dokładania marginesów.

    Klucz R.4.5 dopuszcza szerokości zapisane w grid-template-columns, a R.3.4 sprawdza granicę: przy dokładnie 800 px artykuły mają stać obok siebie - >= to zapewnia. Stopka nie potrzebuje clear, bo nic nie pływa.

    Typowe błędy

    (width > 800px) przenosi dokładnie 800 px do układu pod sobą - R.3.4 mówi „800 px i powyżej obok siebie”.

    styles.css CSS zmienione: 13 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    
    article {
        padding-top: 40px;
        margin: 1%;
    }
    
    main {
        display: grid;
        grid-template-columns: 98%;
        justify-content: center;
    }
    
    @media (width >= 800px) {
        main {
            grid-template-columns: repeat(3, 30%);
            column-gap: 2%;
        }
    }
    Podgląd strony po tym kroku (biblioteka.php)
  19. Krok 19: Wąskie ekrany: artykuły jeden pod drugim

    Kryteria: ,

    R.3.3 Po zmniejszeniu szerokości okna przeglądarki jedynie poniżej 800 px bloki w bloku głównym są ustawione jeden pod drugim

    R.4.5 Zdefiniowane reguły @media dla trzech bloków artykułu: dla reguły szerokości ekranu 800px i więcej - szerokość bloku 30% w przeciwnym przypadku szerokość bloku 98% (width lub grid-template-columns lub flex)

    ok. 2 min
    Polecenie z arkusza

    Gdy szerokość ekranu jest mniejsza niż 800 px szerokość każdego z trzech bloków wynosi 98% (są wyświetlane jeden pod drugim) zgodnie z ilustracją 4.

    Ten krok nie dopisuje kodu: wąski ekran obsługuje reguła bazowa z poprzedniego kroku, grid-template-columns: 98% - jedna kolumna, więc artykuły stoją jeden pod drugim (R.3.3). To podejście „od małego ekranu” (mobile first): najpierw układ najprostszy, a zapytanie @media tylko go rozszerza. Nie ma dwóch zapytań z granicami 799px / 800px, między którymi przy powiększeniu strony mogłaby zostać szczelina.

    Zwęź okno poniżej 800 px - artykuły ustawią się jak na ilustracji 4. Razem z poprzednim krokiem to komplet R.4.5: 30% od 800 px, 98% poniżej.

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

  20. Krok 20: Kolory artykułów

    Kryteria:

    R.4.3 Ustawiony kolor tła bloku nagłówkowego i stopki SteelBlue, pierwszy blok artykułu DodgerBlue, drugi - LimeGreen, trzeci - DarkOrchid

    ok. 2 min
    Polecenie z arkusza

    Dodatkowo dla pierwszego artykułu: kolor tła DodgerBlue. Dodatkowo dla drugiego artykułu: kolor tła LimeGreen. Dodatkowo dla trzeciego artykułu: kolor tła DarkOrchid.

    article:nth-of-type(1) znaczy „pierwszy element article wśród rodzeństwa” - artykuł wybrany po pozycji, bez dopisywania id w HTML. Gdyby kolejność okładek się zmieniła, kolory pójdą za pozycją, a nie za nazwą identyfikatora. Komplet teł z R.4.3: SteelBlue nagłówka i stopki oraz trzy kolory artykułów.

    styles.css CSS zmienione: 12 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    
    article {
        padding-top: 40px;
        margin: 1%;
    }
    
    main {
        display: grid;
        grid-template-columns: 98%;
        justify-content: center;
    }
    
    @media (width >= 800px) {
        main {
            grid-template-columns: repeat(3, 30%);
            column-gap: 2%;
        }
    }
    
    article:nth-of-type(1) {
        background-color: var(--color-book-1);
    }
    
    article:nth-of-type(2) {
        background-color: var(--color-book-2);
    }
    
    article:nth-of-type(3) {
        background-color: var(--color-book-3);
    }
    Podgląd strony po tym kroku (biblioteka.php)
  21. Krok 21: Obraz i paragraf

    Kryteria:

    R.4.7 Ustawione marginesy wewnętrzne (padding) 10px dla bloków nagłówkowego i stopki, 20px dla selektora paragrafu oraz margines górny (padding-top) 40px dla trzech bloków artykułu

    ok. 2 min
    Polecenie z arkusza

    Dla selektora obrazu: szerokość 70%. Dla selektora paragrafu: marginesy wewnętrzne 20 px.

    img i p selektorami znaczników (zastrzeżenie arkusza). Do szerokości 70% dochodzi height: auto - bez tego atrybut height="480" z HTML trzymałby stałą wysokość i okładka by się rozciągnęła. Z auto wysokość wynika z proporcji podanych w atrybutach.

    styles.css CSS zmienione: 9 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    
    article {
        padding-top: 40px;
        margin: 1%;
    }
    
    main {
        display: grid;
        grid-template-columns: 98%;
        justify-content: center;
    }
    
    @media (width >= 800px) {
        main {
            grid-template-columns: repeat(3, 30%);
            column-gap: 2%;
        }
    }
    
    article:nth-of-type(1) {
        background-color: var(--color-book-1);
    }
    
    article:nth-of-type(2) {
        background-color: var(--color-book-2);
    }
    
    article:nth-of-type(3) {
        background-color: var(--color-book-3);
    }
    
    img {
        width: 70%;
        height: auto;
    }
    
    p {
        padding: 20px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  22. Krok 22: Tabela i podświetlenie wiersza

    Kryteria: , , ,

    R.4.6 Ustawiona szerokość dla selektora img oraz selektora table na 70%

    R.4.8 Ustawione marginesy zewnętrzne (margin) 1% dla trzech bloków artykułu, auto dla tabeli

    R.4.9 Ustawione obramowanie tabeli linią ciągłą o kolorze SteelBlue i szerokości 1px

    R.4.10 W momencie gdy kursor myszy znajdzie się na wierszu tabeli, jego kolor tła zmienia się na SteelBlue, a kolor czcionki na biały, np. tr:hover

    ok. 3 min
    Polecenie z arkusza

    Dla selektora tabeli: wyśrodkowanie tabeli, szerokość 70%, obramowanie linią ciągłą o kolorze SteelBlue i szerokości 1 px. W momencie gdy kursor myszy znajdzie się na wierszu tabeli, jego kolor tła zmienia się na SteelBlue, a kolor czcionki na biały.

    margin: auto wyśrodkowuje tabelę o ustalonej szerokości 70% (R.4.6 razem z obrazem, R.4.8 razem z marginesami artykułów), ramka 1 px ciągła (R.4.9).

    Podświetlenie dostaje selektor tbody tr:hover - tylko wiersze z danymi. Wiersz nagłówkowy w <thead> nie reaguje na kursor, bo nie jest czymś, co się wybiera (R.4.10).

    styles.css CSS zmienione: 11 linii
    :root {
        --color-page: LightCyan;
        --color-bar: SteelBlue;
        --color-book-1: DodgerBlue;
        --color-book-2: LimeGreen;
        --color-book-3: DarkOrchid;
    }
    
    * {
        font-family: Roboto, Arial, sans-serif;
        text-align: center;
    }
    
    body {
        background-color: var(--color-page);
    }
    
    header,
    footer {
        background-color: var(--color-bar);
        color: white;
        padding: 10px;
    }
    
    article {
        padding-top: 40px;
        margin: 1%;
    }
    
    main {
        display: grid;
        grid-template-columns: 98%;
        justify-content: center;
    }
    
    @media (width >= 800px) {
        main {
            grid-template-columns: repeat(3, 30%);
            column-gap: 2%;
        }
    }
    
    article:nth-of-type(1) {
        background-color: var(--color-book-1);
    }
    
    article:nth-of-type(2) {
        background-color: var(--color-book-2);
    }
    
    article:nth-of-type(3) {
        background-color: var(--color-book-3);
    }
    
    img {
        width: 70%;
        height: auto;
    }
    
    p {
        padding: 20px;
    }
    
    table {
        margin: auto;
        width: 70%;
        border: 1px solid var(--color-bar);
    }
    
    tbody tr:hover {
        background-color: var(--color-bar);
        color: white;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  23. Etap 4: Skrypt PHP

    Kroki 23-27 · po tym etapie masz 36 z 36 kryteriów (pkt)

    Krok 23: Plik config.php i połączenie PDO

    Kryteria: , ,

    R.5.1 Skrypt napisany w języku PHP i zawiera przynajmniej jedną zgodną z treścią zadania instrukcję

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

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

    ok. 4 min
    Polecenie z arkusza

    Napisany w języku PHP. Łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie biblioteka.

    Dane połączenia są w osobnym pliku config.php, który zwraca tablicę - hasło do bazy jest w jednym miejscu, poza plikiem strony. W dsn od razu charset=utf8mb4, więc polskie tytuły przychodzą poprawnie.

    Na górze biblioteka.php: wczytanie konfiguracji, dwie zmienne z wartościami domyślnymi ($books = [] - na razie brak książek, $databaseError = '' - brak błędu) i new PDO(...) z trybem wyjątków i pobieraniem tablic asocjacyjnych.

    Obsługa błędu jest tu inna niż przerwanie strony: catch nie kończy skryptu, tylko zapisuje krótki komunikat. Biblioteka bez tabeli propozycji nadal ma nagłówek, okładki i streszczenia - lepiej pokazać stronę bez jednej części niż białą stronę. Treść wyjątku (z nazwą serwera i użytkownika) nie trafia do przeglądarki.

    Typowe błędy

    PDO nie ma w tabeli 1 arkusza - nazwy stałych (PDO::ATTR_ERRMODE, PDO::FETCH_ASSOC) trzeba znać na pamięć. Kto nie jest pewny, pisze mysqli_* z tabeli 1, jak w wersji podstawowej.

    biblioteka.php PHP zmienione: 14 linii
    <?php
    $config = require 'config.php';
    $books = [];
    $databaseError = '';
    
    try {
        $pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $databaseError = 'Propozycje są chwilowo niedostępne.';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    config.php PHP nowy plik
    <?php
    // Dane połączenia z bazą - w jednym miejscu, poza plikiem strony
    return [
        'dsn' => 'mysql:host=localhost;dbname=biblioteka;charset=utf8mb4',
        'user' => 'root',
        'password' => '',
    ];
    Podgląd strony po tym kroku (biblioteka.php)
  24. Krok 24: Funkcja e() do bezpiecznego wypisywania

    ok. 2 min
    Polecenie z arkusza

    W każdym wierszu tabeli, w odpowiednich komórkach, wyświetlane są zwrócone zapytaniem kolejne wiersze z bazy.

    Krótka funkcja e() (escape) przepuszcza każdą wartość przez htmlspecialchars z ENT_QUOTES: znaki <, >, & i cudzysłowy zamieniają się na encje, więc tytuł zawsze wyświetla się jako tekst. Tu katalog jest zamknięty, ale tytuły w prawdziwej bibliotece wpisują ludzie - a tytuł z <script> wykonałby się u każdego odwiedzającego (XSS). Jedna funkcja zamiast htmlspecialchars(...) w każdej komórce to mniej pisania i mniejsza szansa, że któraś komórka zostanie pominięta.

    biblioteka.php PHP zmienione: 5 linii
    <?php
    $config = require 'config.php';
    $books = [];
    $databaseError = '';
    
    try {
        $pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $databaseError = 'Propozycje są chwilowo niedostępne.';
    }
    
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  25. Krok 25: Zapytanie 4 do bazy

    Kryteria:

    R.5.4 Skrypt zawiera instrukcję wysyłającą do bazy danych zapytanie 4

    ok. 2 min
    Polecenie z arkusza

    Wysyła do bazy danych zapytanie 4.

    Zapytanie stoi wewnątrz try, zaraz po połączeniu - błąd w zapytaniu (np. literówka w nazwie tabeli) trafi do tego samego catch co nieudane połączenie. query() wystarcza, bo w zapytaniu nie ma danych od użytkownika; fetchAll() od razu odbiera pięć wierszy do tablicy $books.

    W tym arkuszu nie ma formularza, więc nie ma wejścia do sprawdzania (filter_var) ani zapytań przygotowanych - zabezpieczeniem jest tu wyłącznie bezpieczne wypisywanie.

    biblioteka.php PHP zmienione: 1 linia
    <?php
    $config = require 'config.php';
    $books = [];
    $databaseError = '';
    
    try {
        $pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $books = $pdo->query('SELECT autor, tytul, kod FROM ksiazki ORDER BY RAND() LIMIT 5')->fetchAll();
    } catch (PDOException $exception) {
        $databaseError = 'Propozycje są chwilowo niedostępne.';
    }
    
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  26. Krok 26: Zamknięcie połączenia z bazą

    Kryteria:

    R.5.3 Ostatnią operacją na bazie jest jej zamknięcie

    ok. 1 min
    Polecenie z arkusza

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

    $pdo = null; zamyka połączenie PDO - zaraz po jedynym zapytaniu, jeszcze przed HTML. To ostatnia operacja na bazie (R.5.3): niżej w pliku są już tylko pętle po tablicy $books, która zostaje w pamięci.

    biblioteka.php PHP zmienione: 1 linia
    <?php
    $config = require 'config.php';
    $books = [];
    $databaseError = '';
    
    try {
        $pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $books = $pdo->query('SELECT autor, tytul, kod FROM ksiazki ORDER BY RAND() LIMIT 5')->fetchAll();
    } catch (PDOException $exception) {
        $databaseError = 'Propozycje są chwilowo niedostępne.';
    }
    $pdo = null;
    
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  27. Krok 27: Wiersze tabeli z danymi z bazy

    Kryteria: ,

    R.5.5 Skrypt wyświetla w wierszach tabeli dane zwrócone zapytaniem, dane są wpisane do odpowiednich komórek tabeli

    R.2.9 W bloku sekcji umieszczono tabelę o 3 kolumnach (w skrypcie lub HTML) zastosowane znaczniki <table>, <tr>, <td>

    ok. 3 min
    Polecenie z arkusza

    W każdym wierszu tabeli, w odpowiednich komórkach, wyświetlane są zwrócone zapytaniem kolejne wiersze z bazy.

    W <tbody> pętla foreach ($books as $book): ... endforeach; - składnia alternatywna PHP, wygodna między znacznikami HTML. Każda książka to <tr> z trzema <td>; wartości po nazwach kolumn ($book['autor'], $book['tytul'], $book['kod']), więc kolejność kolumn w SELECT nie ma znaczenia. Każda wartość idzie przez e().

    Pod pętlą - wiersz z komunikatem, gdy pobranie się nie udało (colspan="3" łączy trzy komórki w jedną). Podgląd pokazuje pięć książek z ilustracji 2; na serwerze każde odświeżenie losuje inne.

    biblioteka.php PHP zmienione: 12 linii
    <?php
    $config = require 'config.php';
    $books = [];
    $databaseError = '';
    
    try {
        $pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $books = $pdo->query('SELECT autor, tytul, kod FROM ksiazki ORDER BY RAND() LIMIT 5')->fetchAll();
    } catch (PDOException $exception) {
        $databaseError = 'Propozycje są chwilowo niedostępne.';
    }
    $pdo = null;
    
    function e(string|int|float|null $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>BIBLIOTEKA SZKOLNA</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <header>
            <h2>STRONA BIBLIOTEKI SZKOLNEJ WIEDZAMIN</h2>
        </header>
        <section>
            <h3>Nasze dzisiejsze propozycje:</h3>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Autor</th>
                        <th scope="col">Tytuł</th>
                        <th scope="col">Katalog</th>
                    </tr>
                </thead>
                <tbody>
    <?php foreach ($books as $book): ?>
                    <tr>
                        <td><?= e($book['autor']) ?></td>
                        <td><?= e($book['tytul']) ?></td>
                        <td><?= e($book['kod']) ?></td>
                    </tr>
    <?php endforeach; ?>
    <?php if ($databaseError !== ''): ?>
                    <tr>
                        <td colspan="3"><?= e($databaseError) ?></td>
                    </tr>
    <?php endif; ?>
                </tbody>
            </table>
        </section>
        <main>
            <article>
                <img src="ksiazka1.jpg" alt="okładka książki" width="350" height="480">
                <p>Według różnych podań najpaskudniejsza ropucha nosi w głowie piękny, cenny klejnot.</p>
            </article>
            <article>
                <img src="ksiazka2.jpg" alt="okładka książki" width="350" height="480">
                <p>Panna Stefcia i Maryla nie są to zbyt grzeczne damy, nawet nie słuchają mamy...</p>
            </article>
            <article>
                <img src="ksiazka3.jpg" alt="okładka książki" width="350" height="480">
                <p>Ratuj mnie, przyjacielu, w ostatniej potrzebie: Kocham piękną Irenę. Rodzice i ona...</p>
            </article>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  28. Etap 5: Porównanie z wersją podstawową

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

    Krok 28: Co jest inaczej i którą wersję wybrać

    ok. 3 min
    Polecenie z arkusza

    Ocenie będzie podlegać 5 rezultatów: operacje na bazie danych, zawartość witryny internetowej, działanie witryny internetowej, styl CSS witryny internetowej, skrypt połączenia z bazą.

    wersja podstawowata wersja
    artykuły obok siebiefloat: left + clear w stopce, dwa @mediasiatka, jedna reguła bazowa i jedno @media (width >= 800px)
    kolory artykułów#book1, #book2, #book3article:nth-of-type(n), bez id w HTML
    tabelawiersze <tr> wprost w <table><thead> / <tbody>, scope="col"
    bazamysqli_* z tabeli 1, pętla while w tabeliPDO w try/catch, dane pobrane na górze pliku
    błąd bazyostrzeżenia PHP na stroniestrona działa, w tabeli komunikat

    Na egzaminie wersja podstawowa jest szybsza, jeśli funkcji PDO nie zna się na pamięć - mysqli_* są w tabeli 1. CSS z tej wersji można bez ryzyka połączyć z PHP z tamtej: obie części oceniane są osobno (R.3/R.4 i R.5).

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

  29. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

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

    Na płycie: biblioteka.php, config.php, import.png, ksiazka1.jpg - ksiazka3.jpg, kw1.png - kw4.png, kwerendy.txt, przeglądarka.txt, styles.css. Bez config.php strona nie połączy się z bazą. Po nagraniu sprawdź odczyt płyty.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.