Przejdź do głównej treści
EE.09-03-20.06-SGCzerwiec 2020 · 37 kroków · ok. 73 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Kalendarz z wpisami na lipiec (Wersja podstawowa)

Kalendarz na lipiec 2020: baza egzamin5 z tabelą zadania (import pliku baza5.sql), cztery zapytania - miesiąc i rok dla jednej daty, zadania z lipca, nazwy miesięcy bez powtórzeń zaczynające się na „l” (DISTINCT, LIKE) oraz zmiana wpisu jednego dnia (UPDATE). Do tego logo przeskalowane z zachowaniem proporcji do wysokości 150 px, strona kalendarz.php z dwoma blokami banera, blokami dni lipca generowanymi przez skrypt i formularzem w stopce, style w styl5.css oraz skrypt PHP, który wyświetla miesiąc i rok, dni lipca i zapisuje wpis z formularza do bazy.

To arkusz EE.09 z czerwca 2020 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Z tego samego archiwum egzamin5.zip korzysta arkusz EE.09-01 z tej sesji (organizer na sierpień) - baza jest ta sama, ale polecenia i klucz inne. 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ą. Skrypt jest najpierw napisany najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzony na prawdziwym wstrzyknięciu SQL i zabezpieczony.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: semantyczne znaczniki, układ bez float, PDO z zapytaniem przygotowanym na górze pliku i przekierowanie po zapisie - obie wersje są zgodne z kluczem.

Baza i grafiki pochodzą z oryginalnego archiwum CKE egzamin5.zip (załącznik do pobrania na stronie arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2.

Jak liczą się punkty. Klucz ma 34 kryteria (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 26 punktów - 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: Folder zdającego i archiwum egzamin5.zip

    ok. 2 min
    Polecenie z arkusza

    Na pulpicie znajdziesz archiwum ZIP o nazwie egzamin5.zip zabezpieczone hasłem: kaL(end)arz% Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Umieść w tym folderze rozpakowane pliki.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum egzamin5.zip rozpakowujesz (np. 7-Zipem), podając hasło kaL(end)arz% - wielkość liter, nawiasy i znak procentu mają znaczenie. W środku są trzy pliki: baza5.sql (tabela do importu), logo1.png i logo2.png. W tym zadaniu potrzebne jest tylko logo1.png - logo2.png należy do bliźniaczego arkusza z organizerem.

    Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, plik strony i plik stylów.

    Typowe błędy

    Pliki zapisane poza folderem zdającego (np. tylko w htdocs) nie trafią na płytę - a ocenia się wyłącznie to, co jest na płycie.

  2. Krok 2: XAMPP i pusta baza egzamin5

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie egzamin5

    W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa egzamin5, Utwórz.

  3. Krok 3: Import pliku baza5.sql i zrzut import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych egzamin5 , czynność udokumentowano plikiem o nazwie import w formacie PNG. Zrzut zawiera cały obszar ekranu monitora z widocznym paskiem zadań

    ok. 3 min
    Polecenie z arkusza

    Do bazy egzamin5 zaimportuj tabele z pliku baza5.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG pod nazwą import w folderze opisanym numerem PESEL. 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

    Zaznacz bazę egzamin5, karta Import, Wybierz plik → baza5.sql, Wykonaj. Plik zawiera polecenie CREATE TABLE zadania i dane, więc tabela powstaje razem z importem. Po imporcie kliknij tabelę zadania (karta Przeglądaj): 63 wiersze - każdy dzień lipca i sierpnia 2020 oraz jeden dzień listopada. Zrzut całego ekranu z paskiem zadań: import.png.

    Nazwy miesięcy w kolumnie miesiac są zapisane bez polskich liter (lipiec, sierpien, listopad) - zapytania muszą porównywać z tym, co jest w tabeli.

    Typowe błędy

    Zrzut importu w PNG (import.png), zrzuty kwerend w JPG - zły format albo wykadrowany zrzut nie jest oceniany.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: miesiąc i rok dla 1 lipca

    Kryteria: ,

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

    R.1.3 Utworzono zapytanie 1 wybierające jedynie pola miesiac i rok z tabeli zadania dla zadania z datą 2020-07-01. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07- 01'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest dokładnie jeden rekord z danymi: lipiec 2020

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pola miesiac i rok z tabeli zadania dla zadania z datą 2020-07-01

    Karta SQL bazy egzamin5. Zapytanie po kolei:

    • SELECT miesiac, rok - dwie kolumny z arkusza,
    • FROM zadania,
    • WHERE dataZadania = '2020-07-01' - datę w SQL zapisuje się jak napis, w formacie RRRR-MM-DD.

    Wynik: dokładnie jeden wiersz: lipiec, 2020. Zapytanie zapisujesz w pliku kwerendy.txt, a cały ekran - jako kw1.jpg. Tego zapytania użyje skrypt 1 w banerze.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: zadania z lipca

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola dataZadania i wpis z tabeli zadania dla zadań, których miesiąc to lipiec. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie pola dataZadania i wpis. Rekordy mają daty jedynie z lipca przy czym jest widoczna albo poprawna kwerenda albo dokładnie 31 rekordów (daty od 1-31 lipca)

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola dataZadania i wpis z tabeli zadania dla zadań, których miesiąc to lipiec

    • SELECT dataZadania, wpis - dwie kolumny, w tej kolejności (skrypt wyświetli je w bloku dnia),
    • FROM zadania,
    • WHERE miesiac = 'lipiec' - napis w apostrofach.

    Wynik: 31 wierszy, od 2020-07-01 (Projekt z programowania) do 2020-07-31 (Warszawa) - klucz wymaga dokładnie tylu. Zrzut: kw2.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';
    
    -- Zapytanie 2
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: miesiące bez powtórzeń zaczynające się na „l”

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pole miesiac i wyświetlające je bez powtórzeń, z tabeli zadania dla miesięcy zaczynających się na literę „l”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT DISTINCT miesiac FROM zadania WHERE miesiac LIKE "l%"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dwa rekordy, jedynie dane: lipiec i listopad

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pole miesiąc i wyświetlające je bez powtórzeń, z tabeli zadania dla miesięcy zaczynających się na literę „l” (l jak lew, lizak)

    • SELECT DISTINCT miesiac - DISTINCT usuwa powtórzenia: „lipiec” stoi w 31 wierszach, a w wyniku pojawi się raz. Kolumna nazywa się miesiac (bez „ą”), choć arkusz pisze „miesiąc”,
    • FROM zadania,
    • WHERE miesiac LIKE 'l%' - litera l na początku, a po niej %, czyli dowolny ciąg znaków.

    Wynik: dwa wiersze - lipiec i listopad, dokładnie jak w kluczu. Zrzut: kw3.jpg.

    Typowe błędy

    LIKE '%l' szuka miesięcy kończących się na „l”, a bez DISTINCT wynik ma 32 wiersze (31 razy lipiec i listopad).

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';
    
    -- Zapytanie 2
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';
    
    -- Zapytanie 3
    SELECT DISTINCT miesiac FROM zadania WHERE miesiac LIKE 'l%';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowy wpis dla 13 lipca

    Kryteria:

    R.1.6 Utworzono zapytanie 4 zmieniające pole wpis w tabeli zadania dla zadania z datą 2020- 07-13, nowy wpis to „Wycieczka: jezioro”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE zadania SET wpis='Wycieczka: jezioro' WHERE dataZadania='2020-07-13'; oraz wynik działania zapytania udokumentowano zrzutem wskazującym na poprawne wykonanie zapytania

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: zmieniające pole wpis w tabeli zadania dla zadania z datą 2020-07-13, nowy wpis to „Wycieczka: jezioro”

    • UPDATE zadania - zmiana istniejących wierszy,
    • SET wpis = 'Wycieczka: jezioro' - nowa wartość kolumny,
    • WHERE dataZadania = '2020-07-13' - tylko ten jeden dzień.

    phpMyAdmin odpowiada „1 wiersz zmieniony” - zrzut kw4.jpg. Plik kwerendy.txt ma komplet czterech zapytań. Z tego zapytania skrypt zrobi zapis wpisu z formularza.

    Typowe błędy

    UPDATE bez WHERE zmienia wszystkie 63 wiersze - phpMyAdmin wykona je bez pytania.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';
    
    -- Zapytanie 2
    SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';
    
    -- Zapytanie 3
    SELECT DISTINCT miesiac FROM zadania WHERE miesiac LIKE 'l%';
    
    -- Zapytanie 4
    UPDATE zadania SET wpis = 'Wycieczka: jezioro' WHERE dataZadania = '2020-07-13';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika: logo1.png o wysokości 150 px

    Kryteria:

    R.2.1 Plik logo1.png przeskalowano z zachowaniem proporcji do wysokości 150 px, odpowiadająca temu szerokość wynosi 188 px (± 2 px)

    ok. 2 min
    Polecenie z arkusza

    Plik logo1.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 150 px

    Oryginał ma 350 × 280 px. Przy zachowaniu proporcji szerokość zmienia się w tym samym stosunku co wysokość: 350 × 150 / 280 = 187,5, czyli 188 px - tyle przyjmuje klucz (188 ± 2 px). W GIMP-ie Obraz → Skaluj obraz, z zamkniętym łańcuchem przy wymiarach wpisujesz tylko wysokość 150, a szerokość przelicza się sama. Potem Plik → Nadpisz logo1.png (R.2.1).

    Typowe błędy

    Rozpięty łańcuch i ręcznie wpisane 150 × 150 px zniekształcają logo - klucz sprawdza szerokość 188 px.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik kalendarz.php

    ok. 1 min
    Polecenie z arkusza

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

    Plik kalendarz.php w folderze zdającego, obok logo1.png. Rozszerzenie .php, bo dojdzie skrypt - na razie szkielet HTML5: <!DOCTYPE html> i lang="pl".

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie kalendarz oraz zastosowano właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwszy element <head>, a plik zapisany w UTF-8. Klucz ocenia nazwę pliku i kodowanie razem (R.2.2).

    kalendarz.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 (kalendarz.php)
  11. Krok 11: Tytuł strony

    Kryteria:

    R.2.3 Nadano tytuł strony: "Mój kalendarz”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Mój kalendarz”

    <title>Mój kalendarz</title> w <head> - napis na karcie przeglądarki (R.2.3).

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

    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 zamaist #)

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie styl5.css prawidłowo połączony z kodem strony

    <link rel="stylesheet" href="styl5.css"> w <head>. Plik stylów powstanie po HTML-u (R.3.4).

    Typowe błędy

    Klucz uznaje R.3.4 tylko wtedy, gdy całe formatowanie pochodzi z tego pliku i każdy selektor trafia w swój blok (kropka zamiast # odbiera punkt).

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

    Kryteria:

    R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: dwa bloki banera, poniżej blok główny, na dole blok stopki. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: dwa bloki banera, poniżej blok główny, w którym znajdują się bloki wyświetlające dane kolejnych dni, na dole blok stopki.

    Cztery bloki w kolejności z obrazu 2: dwa bloki banera i blok główny jako <section> z identyfikatorami banner-logo, banner-title i main (nazwy po angielsku - arkusz ich nie narzuca), na dole <footer>. Bloki dni wygeneruje skrypt wewnątrz bloku głównego. Obok siebie bloki banera ustawi CSS (R.2.4).

    kalendarz.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
        </section>
        <section id="banner-title">
        </section>
        <section id="main">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  14. Krok 14: Pierwszy blok banera: logo z tekstem alternatywnym

    Kryteria:

    R.2.6 W pierwszym bloku banera umieszczono obraz logo1.png wraz z tekstem alternatywnym "Mój kalendarz"

    ok. 1 min
    Polecenie z arkusza

    Zawartość pierwszego bloku banera: logo1.png z tekstem alternatywnym o treści: „Mój kalendarz”

    <img> z src (przeskalowany plik z folderu zdającego) i alt - tekst dla czytnika ekranu i na wypadek braku obrazu (R.2.6). Wysokość obrazu 150 px równa się wysokości bloku banera.

    kalendarz.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
        </section>
        <section id="main">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  15. Krok 15: Drugi blok banera: nagłówek „KALENDARZ”

    ok. 1 min
    Polecenie z arkusza

    Zawartość drugiego bloku banera: Nagłówek pierwszego stopnia o treści: „KALENDARZ”

    <h1> - pierwszego stopnia. Pod nim stanie efekt skryptu 1: nagłówek trzeciego stopnia z miesiącem i rokiem.

    kalendarz.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  16. Krok 16: Stopka: formularz metodą POST

    Kryteria: ,

    R.2.7 W bloku stopki umieszczono formularz, zastosowano znacznik <form> i jego zamknięcie

    R.3.3 Zdefiniowano dla formularza metodę POST

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: Formularz wysyłający dane metodą POST do tej samej strony

    <form method="post"> bez atrybutu action wysyła dane do adresu, z którego został wczytany - czyli do kalendarz.php. Znacznik ma zamknięcie </form> (R.2.7), a metoda POST przesyła wpis w treści żądania; w PHP odczytasz go z tablicy $_POST (R.3.3).

    kalendarz.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  17. Krok 17: Pole edycyjne „dodaj wpis: ”

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne podpisane: „dodaj wpis: ”

    Podpis wprost w formularzu, za nim <input type="text"> z name="wpis" - pod tym kluczem tekst trafi do PHP: $_POST['wpis'].

    kalendarz.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  18. Krok 18: Przycisk „DODAJ”

    Kryteria: ,

    R.2.8 W formularzu umieszczono pole do wprowadzania danych oraz przycisk "DODAJ"

    R.3.2 Zastosowano przycisk do wysyłania danych z formularza

    ok. 1 min
    Polecenie z arkusza

    Przycisk wysyłający zawartość formularza z opisem „DODAJ”

    <input type="submit" value="DODAJ"> - przycisk typu submit wysyła formularz (R.2.8, R.3.2).

    Typowe błędy

    <input type="button"> wygląda tak samo, ale niczego nie wysyła - brak punktu R.3.2.

    kalendarz.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  19. Krok 19: Stopka: paragraf z autorem strony

    ok. 1 min
    Polecenie z arkusza

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

    Na egzaminie po dwukropku wpisujesz swój numer PESEL; w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski. To ma być paragraf <p> - pod formularzem, jak na obrazie 2.

    kalendarz.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  20. Etap 3: Styl CSS

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

    Krok 20: Plik styl5.css: krój Arial dla całej strony

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

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

    Nowy plik styl5.css. Selektor uniwersalny * obejmuje każdy element, także pole tekstowe i przycisk, które kroju po body nie dziedziczą (R.4.1).

    styl5.css CSS nowy plik
    * {
        font-family: Arial;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  21. Krok 21: Pierwszy blok banera

    ok. 1 min
    Polecenie z arkusza

    Dla pierwszego bloku banera: kolor tła #483D8B, wysokość 150 px, szerokość 30%

    Selektor identyfikatora #banner-logo. #483D8B to granatowo-fioletowy kolor z arkusza (DarkSlateBlue).

    styl5.css CSS zmienione: 5 linii
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  22. Krok 22: Drugi blok banera

    Kryteria: ,

    R.4.4 Ustawiono wysokość dla wszystkich bloków banera na 150px

    R.4.5 Ustawiono szerokość pierwszego bloku banera na 30%, drugiego bloku banera na 70%

    ok. 1 min
    Polecenie z arkusza

    Dla drugiego bloku banera: kolor tła #483D8B, biały kolor czcionki, wysokość 150 px, szerokość 70%

    30% + 70% = 100%, więc oba bloki zmieszczą się w jednym rzędzie - bez obramowań i padding, które by je poszerzyły. Wysokość obu bloków banera (R.4.4) i ich szerokości (R.4.5) są ustawione.

    styl5.css CSS zmienione: 6 linii
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    #banner-title {
        background-color: #483D8B;
        color: white;
        height: 150px;
        width: 70%;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  23. Krok 23: Blok jednego dnia

    Kryteria:

    R.4.8 Ustawiono dla bloku z danymi z kalendarza: kolor tła #AFEEEE, wysokość 100px, szerokość 150px, marginesy zewnętrzne (margin) 3px, obramowanie o szerokości 1px linią ciągłą

    ok. 2 min
    Polecenie z arkusza

    Dla bloku wyświetlającego dane jednego dnia: kolor tła #AFEEEE, szerokość 150 px, wysokość 100 px, marginesy zewnętrzne 3 px, obramowanie o szerokości 1 px, linią ciągłą

    Bloków dni będzie 31, więc selektor klasy .day. border: 1px solid - szerokość i styl linii; arkusz nie podaje koloru, więc obramowanie bierze kolor tekstu (czarny) (R.4.8). Bloki pojawią się dopiero ze skryptem - klucz pozwala sprawdzić to kryterium w pliku CSS.

    styl5.css CSS zmienione: 7 linii
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    #banner-title {
        background-color: #483D8B;
        color: white;
        height: 150px;
        width: 70%;
    }
    .day {
        background-color: #AFEEEE;
        width: 150px;
        height: 100px;
        margin: 3px;
        border: 1px solid;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  24. Krok 24: Stopka

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła #483D8B dla obu bloków banera i stopki

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

    R.4.7 Ustawiono marginesy wewnętrzne (padding) na 10px dla stopki

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła #483D8B, biały kolor czcionki, marginesy wewnętrzne 10 px

    Ten sam kolor co w banerze: tło obu bloków banera i stopki (R.4.2), biały tekst w drugim bloku banera i stopce (R.4.3), padding: 10px - margines wewnętrzny stopki (R.4.7).

    styl5.css CSS zmienione: 5 linii
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    #banner-title {
        background-color: #483D8B;
        color: white;
        height: 150px;
        width: 70%;
    }
    .day {
        background-color: #AFEEEE;
        width: 150px;
        height: 100px;
        margin: 3px;
        border: 1px solid;
    }
    footer {
        background-color: #483D8B;
        color: white;
        padding: 10px;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  25. Krok 25: Nagłówek piątego stopnia do środka

    Kryteria:

    R.4.6 Ustawiono wyrównanie tekstu do środka dla znacznika h5

    ok. 1 min
    Polecenie z arkusza

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

    Selektor znacznika h5 - w nim skrypt wypisze datę każdego dnia, wyśrodkowaną jak na obrazie 3 (R.4.6).

    styl5.css CSS zmienione: 3 linie
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    #banner-title {
        background-color: #483D8B;
        color: white;
        height: 150px;
        width: 70%;
    }
    .day {
        background-color: #AFEEEE;
        width: 150px;
        height: 100px;
        margin: 3px;
        border: 1px solid;
    }
    footer {
        background-color: #483D8B;
        color: white;
        padding: 10px;
    }
    h5 {
        text-align: center;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  26. Krok 26: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest w pełni zgodny z Obrazem 2 w arkuszu egzaminacyjnym (uwaga! Blok główny nie musi zawierać bloków kalendarza)

    ok. 3 min
    Polecenie z arkusza

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

    • oba bloki banera dostają float: left i stają obok siebie (30% + 70%),
    • blok główny z clear: both zaczyna się pod nimi,
    • bloki dni też pływają w lewo: każdy zajmuje 150 + 2 + 6 = 158 px, więc przeglądarka układa ich w rzędzie tyle, ile się zmieści - na ekranie szerokości ok. 1150 px siedem, jak tydzień w kalendarzu na obrazie 2,
    • stopka z clear: both staje pod ostatnim rzędem dni.

    Klucz przy R.3.1 zaznacza, że blok główny nie musi zawierać bloków dni, żeby układ był uznany.

    Typowe błędy

    Bez clear przy stopce jej tło wsunie się pod pływające bloki dni.

    styl5.css CSS zmienione: 6 linii
    * {
        font-family: Arial;
    }
    #banner-logo {
        background-color: #483D8B;
        height: 150px;
        width: 30%;
    }
    #banner-title {
        background-color: #483D8B;
        color: white;
        height: 150px;
        width: 70%;
    }
    .day {
        background-color: #AFEEEE;
        width: 150px;
        height: 100px;
        margin: 3px;
        border: 1px solid;
    }
    footer {
        background-color: #483D8B;
        color: white;
        padding: 10px;
    }
    h5 {
        text-align: center;
    }
    #banner-logo, #banner-title, .day {
        float: left;
    }
    #main, footer {
        clear: both;
    }
    Podgląd strony po tym kroku (kalendarz.php)
  27. Etap 4: Skrypt PHP

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

    Krok 27: Połączenie z bazą egzamin5

    Kryteria:

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

    ok. 3 min
    Polecenie z arkusza

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

    Na samej górze kalendarz.php, przed <!DOCTYPE html>, piszesz pierwszy blok PHP. Funkcja mysqli_connect z tabeli 1 arkusza przyjmuje kolejno serwer localhost, użytkownika root, puste hasło '' i nazwę bazy egzamin5 - czwarty argument od razu wybiera bazę (R.5.1). Połączenie trafia do zmiennej $connection.

    Dlaczego na górze: z połączenia korzystają dwa skrypty w różnych miejscach strony, a formularz stoi w stopce, czyli po bloku głównym. Gdyby zapis wpisu był przy formularzu, blok 13 lipca pokazywałby jeszcze stary wpis. W tym bloku stanie więc też obsługa formularza. Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2; stronę sprawdzasz przez http://localhost/….

    kalendarz.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  28. Krok 28: Skrypt 1: miesiąc i rok w nagłówku trzeciego stopnia

    Kryteria: , ,

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

    R.5.4 Skrypt 1 wyświetla tekst: „miesiąc: <nazwa_miesiąca>, rok: <rok>”, gdzie pola w nawiasach <> oznaczają dane pobrane skryptem

    R.2.5 W drugim bloku banera zapisano nagłówek h1: "KALENDARZ" i nagłówek h3 (w skrypcie lub HTML) oraz zapisano przynajmniej jeden paragraf (znacznik <p>)

    ok. 3 min
    Polecenie z arkusza

    Działanie skryptu 1: Wysyła do bazy danych zapytanie 1. Wyświetla w nagłówku trzeciego stopnia tekst: „miesiąc: <nazwa_miesiąca>, rok: <rok>”, gdzie pola w nawiasach <…> oznaczają dane pobrane skryptem

    Blok PHP w drugim bloku banera, pod nagłówkiem „KALENDARZ”:

    • mysqli_query($connection, "SELECT ...") - zapytanie 1 z kwerendy.txt (R.5.3); wynik trafia do $result,
    • zapytanie zwraca jeden wiersz, więc wystarczy jedno wywołanie mysqli_fetch_row - tablica numerowana od zera: $row[0] to miesiac, $row[1] - rok,
    • echo nagłówka <h3> ze stałym tekstem i dwiema wartościami. Napis jest w cudzysłowie "…", więc PHP podstawia wartości zmiennych.

    Na stronie: „miesiąc: lipiec, rok: 2020” (R.5.4). Drugi blok banera ma teraz <h1> i <h3>, a w stopce jest paragraf (R.2.5).

    kalendarz.php PHP zmienione: 5 linii
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  29. Krok 29: Skrypt 2: zapytanie 2 i blok dla każdego wiersza

    Kryteria:

    R.5.5 Skrypt 2 definiuje w bloku głównym blok (za pomocą znaczników sekcji), a w nim wyświetla dane przesłane skryptem. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 2: Wysyła do bazy danych zapytanie 2. Definiuje blok (za pomocą znacznika sekcji), a w nim wyświetla dane przesłane skryptem, dotyczące jednego wiersza. Liczba wygenerowanych bloków odpowiada liczbie wierszy zwróconych zapytaniem

    Blok PHP w <section id="main">:

    • zapytanie 2 przez to samo połączenie,
    • while ($row = mysqli_fetch_row($result)) - mysqli_fetch_row zwraca kolejny wiersz, a gdy wierszy zabraknie - false, i pętla się kończy,
    • w każdym obrocie echo wypisuje znacznik sekcji z klasą day - tą samą, którą ma reguła w CSS.

    Zapytanie zwraca 31 wierszy, więc na stronie jest 31 bloków (R.5.5). Bloki są jeszcze puste, ale już widać kafelki ułożone po siedem w rzędzie.

    kalendarz.php PHP zmienione: 7 linii
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo '</section>';
            }
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  30. Krok 30: Skrypt 2: data w h5, wpis w paragrafie

    Kryteria:

    R.5.6 Data zadania jest zapisana w nagłówku h5 oraz pole wpis jest zapisane w paragrafie

    ok. 2 min
    Polecenie z arkusza

    Blok jest zgodny z Obrazem 3 oraz jest w nim wyświetlone: Data zadania w nagłówku piątego stopnia. Pole wpis w paragrafie (akapicie)

    Wiersz z zapytania 2 ma dwie kolumny: $row[0] to dataZadania, $row[1] - wpis. Data w <h5> (wyśrodkowana regułą z CSS), wpis w <p> - jak w pierwszym bloku na obrazie 3: „2020-07-01” i „Projekt z programowania” (R.5.6). Dni bez wpisu mają w bazie pusty napis, więc pokazują samą datę. Blok 13 lipca ma już „Wycieczka: jezioro” z zapytania 4.

    kalendarz.php PHP zmienione: 2 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo "<h5>$row[0]</h5>";
                echo "<p>$row[1]</p>";
                echo '</section>';
            }
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  31. Krok 31: Odczyt wpisu z formularza

    Kryteria:

    R.5.7 W skrypcie działającym na danych przesłanych przez formularz zastosowano tabelę $_POST, zapis musi być poprawny składniowo i logicznie

    ok. 2 min
    Polecenie z arkusza

    Działanie skryptu, który odbiera dane przesłane z formularza. Skrypt pobiera dane z pola edycyjnego

    W bloku na górze pliku, pod połączeniem:

    • isset($_POST['wpis']) - prawdziwe dopiero po kliknięciu „DODAJ”; przy zwykłym wejściu na stronę ta część się nie wykonuje,
    • $wpis = $_POST['wpis']; - tekst z pola o nazwie wpis do zmiennej. Kluczem w tablicy $_POST jest atrybut name pola (R.5.7).

    Podgląd: formularz wysłany ze słowem „Kajaki” - skrypt je odczytał, ale jeszcze nigdzie nie zapisał.

    kalendarz.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    if (isset($_POST['wpis'])) {
        $wpis = $_POST['wpis'];
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo "<h5>$row[0]</h5>";
                echo "<p>$row[1]</p>";
                echo '</section>';
            }
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  32. Krok 32: Zapis wpisu: zmodyfikowane zapytanie 4

    Kryteria:

    R.5.8 Skrypt obsługujący formularz uaktualnia dane w bazie danych. Wpis pobrany z formularza jest wpisany do rekordu o dacie 2020-07-13. Należy sprawdzić w bazie danych czy po wciśnięciu przycisku baza została uaktualniona, nie jest wymagane uaktualnienie na stronie

    ok. 3 min
    Polecenie z arkusza

    Następnie uaktualnia dane w bazie danych. Aby uprościć zadanie skrypt wprowadza wpis zawsze do rekordu o dacie 2020-07-13. Do uaktualnienia danych wykorzystaj zapytanie 4 modyfikując w nim wartość pola wpis

    Zapytanie 4 z kwerendy.txt, w którym w miejsce stałego tekstu „Wycieczka: jezioro” stoi '$wpis'. Data zostaje: arkusz każe zawsze zapisywać do 13 lipca. Całe zapytanie jest w cudzysłowie, więc PHP podstawia wartość zmiennej, a apostrofy wewnątrz to ograniczniki napisu w SQL.

    Sprawdzenie, jak każe klucz (R.5.8): po wpisaniu „Kajaki” i kliknięciu „DODAJ” w tabeli zadania wiersz z datą 2020-07-13 ma wpis Kajaki. Zapis stoi na górze pliku, przed skryptem 2, więc nowy wpis widać od razu w bloku 13 lipca.

    Typowe błędy

    Wpis z literami „ś” czy „ż” (np. „Śniardwy”) kończy się błędem „Incorrect string value”: tabela z archiwum ma kodowanie latin1, które tych liter nie zna, a MariaDB z XAMPP działa w trybie ścisłym. To cecha bazy z archiwum - klucz sprawdza import pliku bez zmian, więc tabeli nie przerabiaj, a zapis sprawdź słowem bez polskich liter.

    kalendarz.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    if (isset($_POST['wpis'])) {
        $wpis = $_POST['wpis'];
        mysqli_query($connection, "UPDATE zadania SET wpis = '$wpis' WHERE dataZadania = '2020-07-13';");
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo "<h5>$row[0]</h5>";
                echo "<p>$row[1]</p>";
                echo '</section>';
            }
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  33. Krok 33: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

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

    mysqli_close($connection) na końcu skryptu 2, po pętli - to ostatnie zapytanie na stronie (formularz w stopce nie korzysta już z bazy, jego zapis wykonał się na górze pliku), więc zamknięcie jest ostatnią operacją na bazie (R.5.2). Strona spełnia wszystkie kryteria arkusza. Dalej trzy kroki o zabezpieczeniach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close w banerze, zaraz po skrypcie 1, sprawia, że skrypt 2 dostaje zamknięte połączenie i PHP kończy się błędem.

    kalendarz.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    if (isset($_POST['wpis'])) {
        $wpis = $_POST['wpis'];
        mysqli_query($connection, "UPDATE zadania SET wpis = '$wpis' WHERE dataZadania = '2020-07-13';");
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            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);
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  34. Etap 5: Dobre praktyki (poza kluczem)

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

    Krok 34: Zabezpieczenie: zapytanie przygotowane dla UPDATE

    ok. 4 min
    Polecenie z arkusza

    Do uaktualnienia danych wykorzystaj zapytanie 4 modyfikując w nim wartość pola wpis

    Tekst z formularza trafia do zapytania wprost - to SQL injection. Sprawdzone na wersji z poprzednich kroków:

    • wpis Hakowanie' -- zamienia zapytanie w UPDATE zadania SET wpis = 'Hakowanie' -- ' WHERE .... Dwa myślniki ze spacją zaczynają w SQL komentarz, więc warunek WHERE znika i baza zmienia wszystkie 63 wiersze tabeli - cały kalendarz dostał wpis „Hakowanie”,
    • zwykły wpis z apostrofem, np. Kino 'Helios', rozbija składnię zapytania - PHP 8.1 i nowsze zgłaszają wyjątek mysqli_sql_exception, a zamiast strony widać „Fatal error”.

    Lekarstwo to zapytanie przygotowane: mysqli_prepare z jednym znakiem ? w miejscu wpisu, mysqli_stmt_bind_param z typem 's' (napis) i mysqli_stmt_execute. Baza dostaje treść zapytania i dane osobno, więc dane nigdy nie staną się kodem SQL. Podgląd: ten sam „wpis-atak” zapisał się jako zwykły tekst - tylko w bloku 13 lipca. Stara linia zostaje w komentarzu.

    kalendarz.php PHP zmienione: 4 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    if (isset($_POST['wpis'])) {
        $wpis = $_POST['wpis'];
        // mysqli_query($connection, "UPDATE zadania SET wpis = '$wpis' WHERE dataZadania = '2020-07-13';");
        $statement = mysqli_prepare($connection, "UPDATE zadania SET wpis = ? WHERE dataZadania = '2020-07-13';");
        mysqli_stmt_bind_param($statement, 's', $wpis);
        mysqli_stmt_execute($statement);
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            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);
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  35. Krok 35: Zabezpieczenie: htmlspecialchars przy wyświetlaniu wpisu

    ok. 3 min
    Polecenie z arkusza

    Pole wpis w paragrafie (akapicie)

    Zapytanie przygotowane chroni bazę, ale wpis wraca potem na stronę - i każdy, kto otworzy kalendarz, zobaczy go jako kod HTML. Sprawdzone: wpis <b style="color:red">PILNE</b> wyświetlał się w bloku 13 lipca jako czerwone, pogrubione słowo. Tak samo przeszedłby znacznik <script> - kod JavaScript uruchamiałby się u każdego odwiedzającego (stored XSS).

    Funkcja htmlspecialchars zamienia <, >, & i cudzysłowy na encje (np. < na &lt;), więc przeglądarka pokazuje znaki dosłownie. Stosuje się ją przy wypisywaniu danych od użytkownika - tutaj kolumna wpis. Podgląd: wpis widać dosłownie, ze znacznikami.

    kalendarz.php PHP zmienione: 2 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    if (isset($_POST['wpis'])) {
        $wpis = $_POST['wpis'];
        // mysqli_query($connection, "UPDATE zadania SET wpis = '$wpis' WHERE dataZadania = '2020-07-13';");
        $statement = mysqli_prepare($connection, "UPDATE zadania SET wpis = ? WHERE dataZadania = '2020-07-13';");
        mysqli_stmt_bind_param($statement, 's', $wpis);
        mysqli_stmt_execute($statement);
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo "<h5>$row[0]</h5>";
                // echo "<p>$row[1]</p>";
                echo '<p>' . htmlspecialchars($row[1]) . '</p>';
                echo '</section>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  36. Krok 36: Zabezpieczenie: pusty formularz nie kasuje wpisu

    ok. 3 min
    Polecenie z arkusza

    Skrypt pobiera dane z pola edycyjnego

    isset jest prawdziwe także wtedy, gdy pole jest puste - po kliknięciu „DODAJ” klucz wpis zawsze jest w $_POST. Sprawdzone: kliknięcie przycisku bez wpisania tekstu skasowało „Wycieczka: jezioro” z 13 lipca.

    Warunek dostaje drugi człon: trim($_POST['wpis']) !== '' - trim zdejmuje spacje z brzegów, więc wpis z samych spacji też się nie liczy. Do bazy idzie wersja przycięta. Podgląd: formularz wysłany z trzema spacjami - wpis 13 lipca został.

    kalendarz.php PHP zmienione: 4 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'egzamin5');
    // if (isset($_POST['wpis'])) {
    //     $wpis = $_POST['wpis'];
    if (isset($_POST['wpis']) && trim($_POST['wpis']) !== '') {
        $wpis = trim($_POST['wpis']);
        // mysqli_query($connection, "UPDATE zadania SET wpis = '$wpis' WHERE dataZadania = '2020-07-13';");
        $statement = mysqli_prepare($connection, "UPDATE zadania SET wpis = ? WHERE dataZadania = '2020-07-13';");
        mysqli_stmt_bind_param($statement, 's', $wpis);
        mysqli_stmt_execute($statement);
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Mój kalendarz</title>
        <link rel="stylesheet" href="styl5.css">
    </head>
    <body>
        <section id="banner-logo">
            <img src="logo1.png" alt="Mój kalendarz">
        </section>
        <section id="banner-title">
            <h1>KALENDARZ</h1>
            <?php
            $result = mysqli_query($connection, "SELECT miesiac, rok FROM zadania WHERE dataZadania = '2020-07-01';");
            $row = mysqli_fetch_row($result);
            echo "<h3>miesiąc: $row[0], rok: $row[1]</h3>";
            ?>
        </section>
        <section id="main">
            <?php
            $result = mysqli_query($connection, "SELECT dataZadania, wpis FROM zadania WHERE miesiac = 'lipiec';");
            while ($row = mysqli_fetch_row($result)) {
                echo '<section class="day">';
                echo "<h5>$row[0]</h5>";
                // echo "<p>$row[1]</p>";
                echo '<p>' . htmlspecialchars($row[1]) . '</p>';
                echo '</section>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <form method="post">
                dodaj wpis: <input type="text" name="wpis">
                <input type="submit" value="DODAJ">
            </form>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (kalendarz.php)
  37. Etap 6: Oddanie pracy

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

    Krok 37: 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 weryfikowałeś poprawność działania witryny. Nazwij plik przeglądarka.txt i zapisz go w folderze z numerem PESEL. Nagraj płytę z rezultatami pracy.

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

    W folderze z numerem zdającego muszą być: import.png, kalendarz.php, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, logo1.png, przeglądarka.txt i styl5.css. Nagraj płytę, sprawdź jej odczyt, opisz ją numerem PESEL i zostaw w pudełku na stanowisku razem z arkuszem.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

Podgląd

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

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

Potwierdzenie

Informacja