Przejdź do głównej treści
INF.03-05-23.01-SGStyczeń 2023 · 40 kroków · ok. 70 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Internetowy kalendarz sierpniowy (Wersja podstawowa)

Kalendarz sierpniowy to baza kalendarz z jedną tabelą zadania (dzień, wpis, nazwa miesiąca, rok), cztery zapytania - warunek na tekście, warunek na dacie, liczenie z grupowaniem (COUNT + GROUP BY) i UPDATE - oraz jedna strona organizer.php. Strona ma dwa skrypty: Skrypt 1 rysuje kalendarz - dla każdego dnia sierpnia osobny blok z datą i wpisem - a skrypt obsługujący formularz zapisuje wpisany tekst do dnia 9 sierpnia, czyli wykonuje zapytanie 4 z wartością z formularza. W stylach jest :hover na bloku kalendarza i dwie reguły, które klucz każe pisać selektorem znacznika (h5 i form), a nie klasą.

Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty są najpierw napisane najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row), a na końcu przerobione na wersję odporną na błędy, które naprawdę wychodzą przy testach.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: trzy bloki banera w siatce CSS wewnątrz jednego znacznika <header>, bloki kalendarza ułożone flexboksem, zapis przez PDO zapytaniem przygotowanym z przekierowaniem po zapisie (wzorzec PRG) i bezpieczne wypisywanie wpisów - obie wersje są zgodne z kluczem.

Baza i logo pochodzą z prawdziwego archiwum zad5.zip (załącznik do arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd strony od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.1.2 - zachowanie użytych funkcji jest w obu wersjach takie samo); od kroków Skryptu 1 podgląd pokazuje stronę po wysłaniu formularza z wpisem „zakupy”, jak na obrazie 2.

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

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych kalendarz

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie kalendarz

    Najpierw archiwum zad5.zip z pulpitu (hasło kaL(end)arz% - z nawiasami w środku i procentem na końcu) i folder z numerem zdającego, do którego trafiają baza5.sql, logo1.png i logo2.png. W phpMyAdmin: Nowa, nazwa kalendarz - plik SQL nazywa się inaczej niż baza.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie kalendarz (nie baza5 ani egzamin z komentarza w pliku) - skrypt łączy się z bazą po nazwie (R.5.1).

  2. Krok 2: Import tabeli z pliku baza5.sql

    ok. 2 min
    Polecenie z arkusza

    Do bazy kalendarz zaimportuj tabele z pliku baza5.sql z rozpakowanego archiwum

    Przy zaznaczonej bazie kalendarz: Import → baza5.sql → Wykonaj. Powstaje tabela zadania z obrazu 1: 63 dni - cały lipiec i cały sierpień 2020 roku oraz jeden dzień listopada. Pole miesiac zawiera nazwę miesiąca bez polskich liter (sierpien), a pole wpis dla dni bez zadań ma pusty tekst; tylko listopadowy wiersz ma w nim NULL.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych kalendarz 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 pod nazwą import. Nie kadruj zrzutu. Zrzut powinien obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel

    Print Screen, wklejenie do edytora grafiki i zapis jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG.

    Typowe błędy

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

  4. Krok 4: Zapytanie 1: zadania z sierpnia

    Kryteria: ,

    R.1.2 Zapisano plik 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 dataZadania i wpis dla zadań z sierpnia. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien'; (poprawne też: dataZadania LIKE '____-08-__' lub użycie %) oraz wynik działania udokumentowano zrzutem, na którym widoczny jest w komunikacie zapis o liczbie rekordów "(31 ogółem...)", rekordy są jedynie z sierpnia, jedynie pola dataZadania i wpis. Na zrzucie nie muszą być widoczne wszystkie zwrócone zapytaniem wiersze

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pola dataZadania i wpis dla zadań, z miesiąca sierpnia

    • SELECT dataZadania, wpis - dwa pola, nazwa dataZadania z wielką literą w środku,
    • FROM zadania,
    • WHERE miesiac = 'sierpien' - tekst w bazie jest bez polskich liter, więc 'sierpień' nie znalazłoby nic.

    Wynik: 31 wierszy (komunikat „31 ogółem”), od 2020-08-01 Remont do 2020-08-31. Klucz uznaje też warunek na dacie, np. dataZadania LIKE '____-08-__' - daje te same 31 dni (sprawdzone). Z tego zapytania powstanie Skrypt 1. Zapytania trafiają do kwerendy.txt, zrzut wyniku do kw1.jpg.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: miesiąc i rok dla 7 sierpnia 2020

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola miesiac i rok dla zadania z dnia 7 sierpnia 2020 r. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-08- 07'; oraz wynik działania udokumentowano zrzutem, na którym widoczne jest: sierpien, 2020

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola miesiac i rok dla zadania z dnia 7 sierpnia 2020 r.

    • SELECT miesiac, rok,
    • FROM zadania,
    • WHERE dataZadania = '2020-08-07' - data w zapytaniu SQL ma postać rok-miesiąc-dzień w apostrofach.

    Wynik: jeden wiersz sierpien, 2020 - jak w kluczu. Zrzut: kw2.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';
    
    -- Zapytanie 2
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-08-07';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: wizyty u weterynarza w każdym miesiącu

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie nazwę miesiąca oraz w kolumnie wpis zliczające dla każdego miesiąca wpisy rozpoczynające się od słowa „Weterynarz”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT miesiac, COUNT(*) FROM zadania WHERE wpis LIKE 'Weterynarz%' GROUP BY miesiac; (zamiast * może być dowolne pole) oraz wynik działania udokumentowano zrzutem, na którym widoczne jest jedynie: lipiec, 2; sierpien, 2

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie nazwę miesiąca oraz liczące dla każdego miesiąca ile jest wpisów rozpoczynających się od słowa „Weterynarz” w kolumnie wpis

    • SELECT miesiac, COUNT(*) - nazwa miesiąca i liczba wierszy,
    • FROM zadania,
    • WHERE wpis LIKE 'Weterynarz%' - % zastępuje dowolny ciąg znaków, więc pasują wpisy „Weterynarz - Brutus” i „Weterynarz - Dika”; znak tylko na końcu wzorca oznacza „rozpoczyna się od”,
    • GROUP BY miesiac - COUNT liczy osobno dla każdego miesiąca.

    Wynik: lipiec 2 i sierpien 2 - jak w kluczu. Listopad nie pojawia się wcale, bo żaden jego wpis nie pasuje do warunku. Zrzut: kw3.jpg.

    Typowe błędy

    Bez GROUP BY zapytanie zwraca jeden wiersz z liczbą 4 (na MariaDB z jakąś jedną nazwą miesiąca) - klucz wymaga wyniku dla każdego miesiąca osobno.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';
    
    -- Zapytanie 2
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-08-07';
    
    -- Zapytanie 3
    SELECT miesiac, COUNT(*) FROM zadania WHERE wpis LIKE 'Weterynarz%' GROUP BY miesiac;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowy wpis na 9 sierpnia 2020

    Kryteria:

    R.1.6 Utworzono zapytanie 4 aktualizujące pole wpis dla zadania z datą 2020-08-09, nowy wpis to „Wycieczka: Zalew Mietkowski”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE zadania SET wpis='Wycieczka: Zalew Mietkowski' WHERE dataZadania="2020-08-09"; oraz wynik działania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnej aktualizacji lub tabela ze zaktualizowanym wpisem

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: aktualizujące pole wpis dla zadania z datą 9 sierpnia 2020, nowy wpis to „Wycieczka: Zalew Mietkowski”

    • UPDATE zadania - zmiana danych w istniejących wierszach,
    • SET wpis = 'Wycieczka: Zalew Mietkowski' - nowa wartość pola,
    • WHERE dataZadania = '2020-08-09' - tylko ten jeden dzień; bez warunku zmieniłyby się wszystkie 63 wpisy.

    phpMyAdmin pokazuje komunikat o jednym zmodyfikowanym rekordzie; zrzut kw4.jpg ma ten komunikat i rekord po zmianie. To zapytanie wróci w skrypcie formularza - z tekstem z pola edycyjnego zamiast stałego wpisu.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';
    
    -- Zapytanie 2
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-08-07';
    
    -- Zapytanie 3
    SELECT miesiac, COUNT(*) FROM zadania WHERE wpis LIKE 'Weterynarz%' GROUP BY miesiac;
    
    -- Zapytanie 4
    UPDATE zadania SET wpis = 'Wycieczka: Zalew Mietkowski' WHERE dataZadania = '2020-08-09';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Logo 120 × 120 px

    Kryteria:

    R.2.1 Plik logo2.png przeskalowano do wymiarów 120 px na 120 px (± 2 px)

    ok. 2 min
    Polecenie z arkusza

    Plik logo2.png, wypakowany z archiwum, należy przeskalować dokładnie do wymiarów 120 px na 120 px

    W GIMP-ie: Obraz → Skaluj obraz, szerokość 120 px - przy zablokowanym łańcuchu proporcji wysokość sama zmieni się na 120, bo obraz jest kwadratem 300 × 300. Potem Plik → Nadpisz logo2.png (albo Wyeksportuj jako logo2.png); format PNG zachowuje przezroczyste tło wokół koła. logo1.png z archiwum nie jest w zadaniu używany.

    Typowe błędy

    Zmiana samego atrybutu width w HTML-u nie zmienia pliku - klucz sprawdza wymiary pliku logo2.png (120 × 120 px, ±2 px).

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

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie organizer.php

    Deklaracja <!DOCTYPE html> i szkielet strony. Rozszerzenie .php, bo strona będzie miała skrypty; na egzaminie folder z numerem zdającego leży w htdocs XAMPP-a i strona otwiera się przez http://localhost/..., inaczej PHP się nie wykona.

    organizer.php PHP nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  10. Krok 10: Kodowanie polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwszy element <head>.

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  11. Krok 11: Język strony

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku organizer.php oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> i zadeklarowano język witryny: polski np. <html lang="pl">

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany język witryny: polski

    Atrybut lang="pl" w znaczniku <html>. Razem z nazwą pliku, deklaracją HTML5 i kodowaniem to jedno kryterium klucza (R.2.2).

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  12. Krok 12: Tytuł strony

    Kryteria:

    R.2.3 Nadano tytuł stronie: "Sierpniowy kalendarz"

    ok. 1 min
    Polecenie z arkusza

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

    <title> w <head>.

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

    Kryteria:

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

    Nazwa pliku: styl5.css - z cyfrą 5. Całe formatowanie ma pochodzić z tego pliku, bez atrybutów style.

    Typowe błędy

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

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  14. Krok 14: Bloki: trzy bloki banera, blok główny i stopka

    Kryteria:

    R.2.4 Układ strony zdefiniowano dzieląc ją na: 3 bloki banera, blok główny i stopkę. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: trzy bloki banera, poniżej blok główny, w którym znajdują się generowane skryptem bloki kalendarza, 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

    Trzy bloki banera to trzy znaczniki <header> - wszystkie z klasą banner (wspólne kolory i wysokość) i każdy z własnym identyfikatorem (banner1 - banner3, różne szerokości). Blok główny to <main>, stopka - <footer>. Bloki kalendarza nie są pisane w HTML-u: wygeneruje je Skrypt 1 wewnątrz <main>.

    organizer.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
        </header>
        <header class="banner" id="banner2">
        </header>
        <header class="banner" id="banner3">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  15. Krok 15: Pierwszy blok banera: nagłówek

    ok. 1 min
    Polecenie z arkusza

    Zawartość pierwszego bloku banera: nagłówek pierwszego stopnia o treści „Organizer: SIERPIEŃ”

    <h1> z napisem dokładnie jak w arkuszu - słowo „SIERPIEŃ” wielkimi literami, z polską literą Ń.

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
        </header>
        <header class="banner" id="banner3">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  16. Krok 16: Drugi blok banera: formularz POST do tej samej strony

    Kryteria: ,

    R.2.6 W drugim bloku banera umieszczono formularz, zastosowano znacznik <form>

    R.3.3 Zdefiniowano dla formularza metodę POST

    ok. 2 min
    Polecenie z arkusza

    Zawartość drugiego bloku banera: formularz wysyłający dane metodą bezpieczną do tej samej strony, zawierający pole edycyjne i przycisk

    <form> z atrybutem action="organizer.php" - dane wracają do tej samej strony - i method="post". Dane idą w treści żądania, a nie w adresie strony, więc wpisanego tekstu nie widać na pasku adresu ani w historii.

    ⚠️ Rozbieżność arkusz-klucz: arkusz każe wysyłać dane „metodą bezpieczną”, a w specyfikacji HTTP (RFC 9110) metody bezpieczne (safe) to GET i HEAD - te, które nie zmieniają danych na serwerze. Klucz CKE (R.3.3) wymaga POST - na egzaminie punkt daje wersja z klucza.

    Typowe błędy

    Formularz bez method wysyła dane metodą GET (domyślną) - klucz nie uzna R.3.3, a skrypt czytający $_POST niczego nie dostanie.

    organizer.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
            </form>
        </header>
        <header class="banner" id="banner3">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  17. Krok 17: Formularz: pole edycyjne z podpisem

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne podpisane: „Zapisz wydarzenie: ”

    <input type="text"> z podpisem w <label>. Atrybut name="event" to nazwa, pod którą tekst trafi do skryptu ($_POST["event"]), a for w etykiecie wskazuje id pola - kliknięcie podpisu ustawia kursor w polu.

    Typowe błędy

    Pole bez atrybutu name nie jest wysyłane wcale - skrypt formularza nie ma czego zapisać (R.5.6, R.5.7).

    organizer.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
            </form>
        </header>
        <header class="banner" id="banner3">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  18. Krok 18: Formularz: przycisk OK

    Kryteria: ,

    R.2.7 Na stronie umieszczono pole do wprowadzania danych oraz przycisk "OK"

    R.3.2 Przycisk ma funkcję wysyłania danych (input lub button z typem submit lub button bez typu)

    ok. 1 min
    Polecenie z arkusza

    Przycisk o treści „OK” wysyłający zawartość formularza

    <button type="submit"> - przycisk wysyłający formularz (klucz uznaje też <input type="submit" value="OK"> albo <button> bez typu, bo w formularzu domyślnie wysyła).

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
        </header>
        <header class="banner" id="banner3">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  19. Krok 19: Trzeci blok banera: logo

    Kryteria:

    R.2.8 W trzecim bloku banera umieszczono obraz logo2.png wraz z tekstem alternatywnym "sierpień"

    ok. 1 min
    Polecenie z arkusza

    Zawartość trzeciego bloku banera: logo2.png z tekstem alternatywnym o treści: „sierpień”

    <img> z przeskalowanym plikiem i atrybutem alt. Obraz ma już 120 × 120 px, więc w HTML-u nie trzeba podawać wymiarów.

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  20. Krok 20: Blok główny: miejsce na Skrypt 1

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: efekt działania skryptu 1

    Bloki kalendarza powstaną w <main> - blok PHP dojdzie w etapie skryptów. Ten krok nie zmienia pliku.

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

  21. Krok 21: Stopka

    Kryteria:

    R.2.5 W banerze pierwszym zapisano nagłówek h1: "Organizer: SIERPIEŃ" oraz w stopce zapisano paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: Paragraf (akapit) o treści: „Stronę wykonał: ”, dalej wstawiony numer zdającego

    Akapit <p> w <footer>. Na egzaminie w miejscu imienia i nazwiska wpisuje się numer zdającego, czyli PESEL; w tym rozwiązaniu stoi tam „Bartosz Bryniarski”. Strona ma już nagłówek <h1> w pierwszym bloku banera i akapit w stopce (R.2.5).

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  22. Etap 3: Styl CSS

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

    Krok 22: Krój czcionki dla wszystkich elementów

    Kryteria:

    R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (*): krój czcionki Tahoma

    ok. 1 min
    Polecenie z arkusza

    Ustawione domyślne wartości dla wszystkich selektorów stylu CSS: krój czcionki Tahoma

    Selektor uniwersalny * - krój dostają wszystkie elementy, także pole formularza i przycisk.

    styl5.css CSS nowy plik
    * {
        font-family: Tahoma;
    }
    Podgląd strony po tym kroku (organizer.php)
  23. Krok 23: Wszystkie bloki banera

    Kryteria:

    R.4.5 Ustawiono wysokość 120px dla trzech bloków banera

    ok. 1 min
    Polecenie z arkusza

    Dla wszystkich bloków banera: kolor tła #7DA453, biały kolor czcionki, wysokość 120 px

    Jedna reguła dla klasy .banner - trzy bloki mają ją w HTML-u, więc wspólne właściwości nie są powtarzane trzy razy. Wysokość 120 px to tyle, ile ma logo.

    styl5.css CSS zmienione: 5 linii
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    Podgląd strony po tym kroku (organizer.php)
  24. Krok 24: Szerokości bloków banera

    Kryteria:

    R.4.4 Ustawiono szerokość bloków banera: 40% pierwszy i drugi oraz 20% trzeci (width lub grid- template-columns lub flex) poprawne również rozwiązanie bez szerokości dla trzeciego bloku jeśli bloki wstawiono w kontener nadrzędny

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo pierwszy i drugi blok banera ma szerokość 40%, trzeci 20%

    Szerokości są różne, więc idą do reguł z identyfikatorami. 40% + 40% + 20% = 100% - trzy bloki zajmą razem całą szerokość strony.

    styl5.css CSS zmienione: 6 linii
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    Podgląd strony po tym kroku (organizer.php)
  25. Krok 25: Blok kalendarza

    Kryteria:

    R.4.8 Ustawiono dla bloku kalendarza: kolor tła #AED581, szerokość 200px, wysokość 100px, marginesy zewnętrzne (margin) 7px, obramowanie 1px solid #7DA453 (np. za pomocą klasy. Użycie id jest błędem)

    ok. 2 min
    Polecenie z arkusza

    Dla bloku kalendarza: kolor tła #AED581, szerokość 200 px, wysokość 100 px, marginesy zewnętrzne 7 px, obramowanie o szerokości 1 px, linią ciągłą o kolorze #7DA453

    Bloków kalendarza będzie 31, więc formatuje je klasa .day - skrypt nada ją każdemu blokowi. Klucz przy R.4.8 pisze wprost, że użycie identyfikatora jest błędem: id ma być na stronie jeden, a bloków jest wiele. margin: 7px to odstęp z każdej strony bloku, border: 1px solid #7DA453 - obramowanie w kolorze banera.

    styl5.css CSS zmienione: 7 linii
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    Podgląd strony po tym kroku (organizer.php)
  26. Krok 26: Blok kalendarza pod kursorem

    Kryteria:

    R.4.9 Gdy kursor znajdzie się na bloku kalendarza, kolor tła bloku zmienia się na #7DA453, czcionki na biały

    ok. 1 min
    Polecenie z arkusza

    Gdy kursor znajdzie się na bloku kalendarza, kolor tła bloku zmienia się na #7DA453, czcionki na biały

    Pseudoklasa :hover - na obrazie 2 kursor stoi na bloku z 9 sierpnia i ten blok ma kolory banera.

    styl5.css CSS zmienione: 4 linie
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    .day:hover {
        background-color: #7DA453;
        color: white;
    }
    Podgląd strony po tym kroku (organizer.php)
  27. Krok 27: Stopka

    Kryteria: ,

    R.4.2 Ustawiono kolor tła #7DA453 dla trzech bloków banera i stopki

    R.4.3 Ustawiono biały kolor czcionki dla trzech bloków banera i stopki

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła #7DA453, biały kolor czcionki, marginesy wewnętrzne 5 px

    Selektor znacznika footer. Kolor tła i czcionki mają już trzy bloki banera i stopka - komplet do R.4.2 i R.4.3.

    styl5.css CSS zmienione: 5 linii
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    .day:hover {
        background-color: #7DA453;
        color: white;
    }
    footer {
        background-color: #7DA453;
        color: white;
        padding: 5px;
    }
    Podgląd strony po tym kroku (organizer.php)
  28. Krok 28: Nagłówek piątego stopnia

    Kryteria:

    R.4.7 Ustawiono wyrównanie tekstu do środka dla selektora h5

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka piątego stopnia: wyrównanie tekstu do środka

    Selektor znacznika h5 - w nagłówkach piątego stopnia skrypt wypisze daty. Uwaga pod listą stylów każe tu użyć selektora znacznika, a nie klasy, i klucz (R.4.7) uznaje tylko taki zapis.

    styl5.css CSS zmienione: 3 linie
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    .day:hover {
        background-color: #7DA453;
        color: white;
    }
    footer {
        background-color: #7DA453;
        color: white;
        padding: 5px;
    }
    h5 {
        text-align: center;
    }
    Podgląd strony po tym kroku (organizer.php)
  29. Krok 29: Formularz: margines wewnętrzny górny

    Kryteria:

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 5px dla stopki oraz wewnętrzny górny (padding-top) 50px dla selektora form

    ok. 1 min
    Polecenie z arkusza

    Dla selektora formularza: margines wewnętrzny górny: 50 px

    Selektor znacznika form, właściwość padding-top - formularz zsuwa się mniej więcej na środek wysokości banera, jak na obrazie 2. Margines wewnętrzny stopki jest już ustawiony (R.4.6).

    Typowe błędy

    margin-top zamiast padding-top albo reguła dla klasy formularza zamiast znacznika form - klucz (R.4.6) uznaje tylko margines wewnętrzny dla selektora form.

    styl5.css CSS zmienione: 3 linie
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    .day:hover {
        background-color: #7DA453;
        color: white;
    }
    footer {
        background-color: #7DA453;
        color: white;
        padding: 5px;
    }
    h5 {
        text-align: center;
    }
    form {
        padding-top: 50px;
    }
    Podgląd strony po tym kroku (organizer.php)
  30. Krok 30: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (Uwaga! Blok główny nie musi zawierać bloków kalendarza; prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: trzy bloki banera, poniżej blok główny, w którym znajdują się generowane skryptem bloki kalendarza, 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

    float: left dostają bloki banera (stają obok siebie: 40% + 40% + 20%) i bloki kalendarza (układają się w rzędy po tyle, ile zmieści szerokość okna - blok z marginesami zajmuje 216 px, więc sześć w rzędzie, jak na obrazie 2, mieści się od szerokości strony około 1310 px (6 × 216 px plus marginesy body; sprawdzone w Chrome), a w węższym oknie jest ich pięć). Banery wypełniają cały rząd, więc pierwszy blok kalendarza zaczyna się pod nimi. Stopka z clear: both staje pod wszystkimi pływającymi blokami. Klucz przy R.3.1 zaznacza, że blok główny nie musi mieć bloków kalendarza - ocenia się układ.

    styl5.css CSS zmienione: 6 linii
    * {
        font-family: Tahoma;
    }
    .banner {
        background-color: #7DA453;
        color: white;
        height: 120px;
    }
    #banner1, #banner2 {
        width: 40%;
    }
    #banner3 {
        width: 20%;
    }
    .day {
        background-color: #AED581;
        width: 200px;
        height: 100px;
        margin: 7px;
        border: 1px solid #7DA453;
    }
    .day:hover {
        background-color: #7DA453;
        color: white;
    }
    footer {
        background-color: #7DA453;
        color: white;
        padding: 5px;
    }
    h5 {
        text-align: center;
    }
    form {
        padding-top: 50px;
    }
    .banner, .day {
        float: left;
    }
    footer {
        clear: both;
    }
    Podgląd strony po tym kroku (organizer.php)
  31. Etap 4: Skrypty PHP

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

    Krok 31: Połączenie z bazą i zamknięcie połączenia

    Kryteria: ,

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

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

    ok. 2 min
    Polecenie z arkusza

    Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie kalendarz

    Na stronie są dwa bloki PHP: skrypt obsługujący formularz w drugim bloku banera, zaraz pod formularzem, i Skrypt 1 w bloku głównym. Kolejność ma znaczenie: skrypt formularza wykonuje się pierwszy, więc zapisuje nowy wpis do bazy, zanim Skrypt 1 odczyta kalendarz - zmiana jest widoczna od razu po wysłaniu, jak na obrazie 2. Dlatego to on otwiera połączenie (mysqli_connect z czterema argumentami: serwer, użytkownik, puste hasło, baza; uchwyt w zmiennej $connection), a Skrypt 1 zamyka je na końcu - kolejne instrukcje będą dopisywane nad mysqli_close, więc zamknięcie zostanie ostatnią operacją na bazie (R.5.2). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    organizer.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  32. Krok 32: Formularz: tekst z pola edycyjnego

    Kryteria:

    R.5.6 W skrypcie obsługującym formularz zastosowano tablicę $_POST, zapis jest poprawny składniowo i logicznie

    ok. 2 min
    Polecenie z arkusza

    Skrypt pobiera dane z pola edycyjnego

    Tekst z pola jest w tablicy $_POST pod nazwą z atrybutu name, czyli $_POST["event"]. Przy pierwszym otwarciu strony formularz nie był jeszcze wysłany i tego elementu tablicy nie ma - dlatego odczyt stoi w warunku isset. Bez niego PHP 8 wypisałby ostrzeżenie „Undefined array key”, a zapytanie z kolejnego kroku wykonywałoby się przy każdym wejściu na stronę.

    organizer.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"])) {
                    $event = $_POST["event"];
                }
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  33. Krok 33: Formularz: zmodyfikowane zapytanie 4

    Kryteria:

    R.5.7 Skrypt obsługujący formularz uaktualnia dane w bazie danych. Dane pobrane z formularza są wpisane do rekordu o dacie 2020-08-09. Należy sprawdzić w phpMyAdmin czy po wciśnięciu przycisku baza została uaktualniona, nie jest wymagane uaktualnienie na stronie

    ok. 3 min
    Polecenie z arkusza

    Następnie za pomocą zmodyfikowanego zapytania 4 uaktualnia dane w bazie danych tak, że dane w polu wpis zostały pobrane z formularza. Aby uprościć zadanie skrypt wprowadza wpis zawsze do rekordu o dacie 2020-08-09.

    Zapytanie 4 z jedną zmianą: zamiast stałego tekstu „Wycieczka: Zalew Mietkowski” jest zmienna $event - PHP wstawia jej wartość do napisu w cudzysłowach, a apostrofy wokół niej są apostrofami SQL-a. Warunek zostaje ten sam: zawsze dzień 2020-08-09. mysqli_query wysyła zapytanie; UPDATE nie zwraca wierszy, więc wynik nie jest potrzebny. Sprawdzone na bazie: po wysłaniu formularza z tekstem „zakupy” rekord z 9 sierpnia ma wpis zakupy - to sprawdza egzaminator w phpMyAdmin (R.5.7).

    organizer.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"])) {
                    $event = $_POST["event"];
                    $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                    mysqli_query($connection, $query);
                }
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  34. Krok 34: Skrypt 1: zapytanie 1

    Kryteria:

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 1 lub skrypt obsługujący formularz wysyła zmodyfikowane zapytanie 4

    ok. 1 min
    Polecenie z arkusza

    Wysyła do bazy danych zapytanie 1

    Zapytanie 1 bez zmian, w zmiennej $query. Nazwy $query i $result powtarzają się po skrypcie formularza - tamto zapytanie zostało już wykonane, więc można ich użyć ponownie. mysqli_query wysyła zapytanie, a w $result zostaje 31 wierszy do odczytania.

    organizer.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"])) {
                    $event = $_POST["event"];
                    $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                    mysqli_query($connection, $query);
                }
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                $query = "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';";
                $result = mysqli_query($connection, $query);
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  35. Krok 35: Skrypt 1: blok kalendarza z datą dla każdego wiersza

    Kryteria:

    R.5.4 Skrypt 1 wyświetla w bloku głównym bloki zdefiniowane za pomocą znaczników sekcji. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    ok. 3 min
    Polecenie z arkusza

    Za pomocą znacznika sekcji definiuje blok, a w nim wyświetla dane przesłane skryptem dotyczące jednego wiersza. Blok jest zgodny z Obrazem 3 oraz jest w nim wyświetlone: data zadania w nagłówku piątego stopnia

    Pętla while z mysqli_fetch_row przechodzi po wierszach wyniku; $row[0] to dataZadania, pierwsze pole zapytania. Dla każdego wiersza skrypt otwiera znacznik <section class="day"> (klasa z reguły stylu bloku kalendarza; cudzysłowy atrybutu wewnątrz napisu PHP poprzedza ukośnik \"), wypisuje datę w <h5> i zamyka blok. Podgląd: 31 zielonych bloków z datami - tyle, ile wierszy zwraca zapytanie (R.5.4).

    organizer.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"])) {
                    $event = $_POST["event"];
                    $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                    mysqli_query($connection, $query);
                }
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                $query = "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<section class=\"day\">";
                    echo "<h5>$row[0]</h5>";
                    echo "</section>";
                }
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  36. Krok 36: Skrypt 1: wpis w akapicie

    Kryteria:

    R.5.5 Skrypt 1 wyświetla datę zadania w nagłówku h5 oraz pole wpis w paragrafie

    ok. 2 min
    Polecenie z arkusza

    Pole wpis w paragrafie (akapicie)

    Drugie pole zapytania, $row[1] (wpis), w akapicie <p> pod datą - blok wygląda jak na obrazie 3. Dni bez zadań mają w bazie pusty tekst, więc ich akapit jest pusty. Podgląd to strona po wysłaniu formularza z wpisem „zakupy”: skrypt formularza zapisał go do 9 sierpnia, zanim Skrypt 1 odczytał bazę, więc blok 2020-08-09 pokazuje „zakupy” zamiast „Wycieczka: Zalew Mietkowski” z zapytania 4 - jak na obrazie 2.

    organizer.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"])) {
                    $event = $_POST["event"];
                    $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                    mysqli_query($connection, $query);
                }
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                $query = "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<section class=\"day\">";
                    echo "<h5>$row[0]</h5>";
                    echo "<p>$row[1]</p>";
                    echo "</section>";
                }
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  37. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 37-39 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 37: Formularz: apostrof i puste pole

    ok. 4 min
    Polecenie z arkusza

    Następnie za pomocą zmodyfikowanego zapytania 4 uaktualnia dane w bazie danych tak, że dane w polu wpis zostały pobrane z formularza. Aby uprościć zadanie skrypt wprowadza wpis zawsze do rekordu o dacie 2020-08-09.

    Wersja egzaminacyjna sprawdzona dwoma wpisami, które zdarzają się naprawdę:

    • Urodziny Ani's - apostrof z tekstu zamyka napis w zapytaniu SQL; MariaDB zgłasza błąd składni, a PHP 8 zamienia go w wyjątek mysqli_sql_exception i strona urywa się w połowie banera (sprawdzone - kalendarza nie ma wcale). Ten sam mechanizm pozwala wpisać w pole fragment SQL i zmienić zapytanie,
    • puste pole - kliknięcie OK bez tekstu kasuje wpis z 9 sierpnia (sprawdzone).

    Poprawka: zapytanie przygotowane (mysqli_prepare ze znakiem ? w miejscu wartości, mysqli_stmt_bind_param z typem "s" - tekst, mysqli_stmt_execute) - wartość idzie do bazy osobno i żaden znak jej nie rozbije, oraz warunek z trim: same spacje też nie zmieniają wpisu. Podgląd: kalendarz po wysłaniu wpisu z apostrofem. Stare linie zostały w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    organizer.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"]) && trim($_POST["event"]) != "") {
                    $event = trim($_POST["event"]);
                    $stmt = mysqli_prepare($connection, "UPDATE zadania SET wpis = ? WHERE dataZadania = '2020-08-09';");
                    mysqli_stmt_bind_param($stmt, "s", $event);
                    mysqli_stmt_execute($stmt);
                }
                // $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                // mysqli_query($connection, $query);
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                $query = "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<section class=\"day\">";
                    echo "<h5>$row[0]</h5>";
                    echo "<p>$row[1]</p>";
                    echo "</section>";
                }
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  38. Krok 38: Skrypt 1: wpis wypisany jako tekst

    ok. 3 min
    Polecenie z arkusza

    Pole wpis w paragrafie (akapicie)

    Wpis pochodzi od użytkownika, a Skrypt 1 wkleja go do strony bez zmian. Test na wersji egzaminacyjnej: wpis <b>zakupy</b> pokazuje się pogrubiony - przeglądarka wykonała znaczniki z formularza, a tak samo wykonałaby <script>. htmlspecialchars zamienia < i > na encje, więc wpis pokazuje się dosłownie, razem ze znakami. Przy okazji mysqli_fetch_assoc zamiast numerów kolumn - $day["dataZadania"] czyta się łatwiej niż $row[0] - a ?? "" zastępuje wartość NULL pustym tekstem, bo od PHP 8.1 htmlspecialchars(null) daje ostrzeżenie o przestarzałym wywołaniu. Podgląd: wpis ze znacznikami po poprawce. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    organizer.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Sierpniowy kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <header class="banner" id="banner1">
            <h1>Organizer: SIERPIEŃ</h1>
        </header>
        <header class="banner" id="banner2">
            <form action="organizer.php" method="post">
                <label for="event">Zapisz wydarzenie: </label>
                <input type="text" id="event" name="event">
                <button type="submit">OK</button>
            </form>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "kalendarz");
                if (isset($_POST["event"]) && trim($_POST["event"]) != "") {
                    $event = trim($_POST["event"]);
                    $stmt = mysqli_prepare($connection, "UPDATE zadania SET wpis = ? WHERE dataZadania = '2020-08-09';");
                    mysqli_stmt_bind_param($stmt, "s", $event);
                    mysqli_stmt_execute($stmt);
                }
                // $query = "UPDATE zadania SET wpis = '$event' WHERE dataZadania = '2020-08-09';";
                // mysqli_query($connection, $query);
            ?>
        </header>
        <header class="banner" id="banner3">
            <img src="logo2.png" alt="sierpień">
        </header>
        <main>
            <?php
                $query = "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'sierpien';";
                $result = mysqli_query($connection, $query);
                while ($day = mysqli_fetch_assoc($result)) {
                    $note = htmlspecialchars($day["wpis"] ?? "");
                    echo "<section class=\"day\">";
                    echo "<h5>" . $day["dataZadania"] . "</h5>";
                    echo "<p>$note</p>";
                    echo "</section>";
                }
                // while ($row = mysqli_fetch_row($result)) { ... "<h5>$row[0]</h5>" ... "<p>$row[1]</p>" ... }
                mysqli_close($connection);
            ?>
        </main>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (organizer.php)
  39. Krok 39: Polskie litery we wpisach z formularza

    ok. 3 min
    Polecenie z arkusza

    Następnie za pomocą zmodyfikowanego zapytania 4 uaktualnia dane w bazie danych tak, że dane w polu wpis zostały pobrane z formularza. Aby uprościć zadanie skrypt wprowadza wpis zawsze do rekordu o dacie 2020-08-09.

    Wpis „Śniadanie u babci w Łodzi” zapisuje się w bazie jako „?niadanie u babci w ?odzi” - sprawdzone na MariaDB z XAMPP-a. Przyczyna nie leży w PHP: tabela zadania z pliku baza5.sql jest utworzona z kodowaniem latin1 (DEFAULT CHARSET=latin1), a w nim nie ma liter „ś”, „ł”, „ą” - baza zastępuje je znakiem zapytania bez żadnego komunikatu („ó” akurat jest w latin1, więc przechodzi). Dane z arkusza nie mają polskich liter (stąd sierpien), dlatego zadanie tego nie pokazuje.

    Poprawka to jedno zapytanie na strukturze tabeli, w pliku kodowanie.sql: ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 zmienia kodowanie tabeli i przepisuje istniejące dane (wpisy z arkusza zostają bez zmian - sprawdzone). Po nim ten sam wpis zapisuje się poprawnie. Na egzaminie tego nie rób - zrzuty i zapytania mają dotyczyć tabeli z importu, a klucz tego nie sprawdza.

    kodowanie.sql SQL nowy plik
    -- Zmiana kodowania tabeli zadania (poza zadaniem egzaminacyjnym)
    ALTER TABLE zadania CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    Podgląd strony po tym kroku (organizer.php)
  40. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

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

    W przeglądarka.txt wystarczy nazwa przeglądarki, w której była sprawdzana strona.

    W folderze z numerem zdającego: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, logo2.png (już 120 × 120 px), organizer.php, przeglądarka.txt i styl5.css. Po nagraniu płyty trzeba sprawdzić jej odczyt i opisać ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.