Przejdź do głównej treści
EE.09-04-23.01-SGStyczeń 2023 · 24 kroki · ok. 67 min · 39 kryteriów z klucza

Rozwiązanie krok po kroku: Wizytówki pracowników z formularzem (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Baza, zapytania, zrzuty i przeskalowane zdjęcie są takie same jak w wersji podstawowej, strona index.php wygląda tak samo i spełnia każde kryterium klucza. Inna jest droga:

  • PHP na PDO na górze pliku, przed HTML-em: wszystkie zapytania i zamknięcie połączenia w jednym miejscu, a w HTML-u zostaje szablon wstawiający gotowe dane (<?= ... ?>),
  • numer z formularza sprawdzony na serwerze (filter_input z przedziałem 1 - 9) i zapytanie przygotowane - wpisanie w pole kodu SQL niczego nie wyciąga z bazy,
  • htmlspecialchars przy każdym wypisaniu danych z bazy (funkcja e()),
  • wybrany numer zostaje w polu po wysłaniu formularza, a pole ma opis dla czytników ekranu (aria-label),
  • stopka to jeden <footer> z trzema sekcjami na flexboksie, kolory w zmiennych CSS.

To arkusz EE.09 ze stycznia 2023 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i grafiki pochodzą z oryginalnego archiwum CKE zad4 (załącznik na stronie arkusza), zapytania i zrzuty są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.1.2 - użyte konstrukcje działają w obu wersjach).

Jak liczą się punkty. Klucz ma 39 kryteriów (R.1.1 - R.5.7), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów. Klucz przyjmuje zarówno mysqli, jak i PDO, a układ na float, flex albo grid.

  1. Etap 1: Baza danych

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

    Krok 1: Folder zdającego i archiwum zad4

    ok. 2 min
    Polecenie z arkusza

    Archiwum należy rozpakować. Na pulpicie konta Egzamin należy utworzyć folder. Jako nazwy folderu należy użyć numeru zdającego, którym został podpisany arkusz. Rozpakowane pliki należy umieścić w tym folderze. Zaleca się, aby rozpakowane pliki znajdowały się w tym samym folderze, co pliki strony. Po skończonej pracy wszystkie wyniki należy zapisać w tym folderze.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum zad4.zip rozpakowujesz do tego folderu, podając hasło #WizyTowniK$ (wielkość liter i oba znaki specjalne mają znaczenie). W środku: baza.sql, obraz.jpg (zdjęcie zespołu do stopki) i zdjęcia pracowników 1.jpg - 9.jpg - nazwa pliku to numer pracownika w bazie, z tego skorzysta skrypt.

    Strona jest w PHP, więc działa tylko przez serwer. Folder możesz skopiować do C:\xampp\htdocs albo pracować w nim i na koniec skopiować pliki z htdocs z powrotem - wyniki muszą trafić do folderu na pulpicie.

  2. Krok 2: Pusta baza firma

    ok. 2 min
    Polecenie z arkusza

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

    W XAMPP Control Panel Start przy Apache i MySQL, potem http://localhost/phpmyadmin. Nowa, nazwa firma, porównywanie np. utf8mb4_polish_ci (arkusz go nie narzuca), Utwórz.

  3. Krok 3: Import pliku baza.sql i zrzut import.jpg

    Kryteria:

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

    ok. 3 min
    Polecenie z arkusza

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

    Zaznacz bazę firma, karta Import, Wybierz plik → baza.sql, Wykonaj. Plik tworzy dwie tabele z obrazu 1: pracownicy (9 osób) i stanowiska (4 stanowiska). Na zrzucie widać komunikat o sukcesie i obie tabele w lewym panelu; tu dodatkowo otwarta jest tabela pracownicy. Zrzut całego ekranu z paskiem zadań zapisz jako import.jpg (JPEG - zrzuty zapytań będą w PNG).

    Pola czyRODO i czyBadania przechowują 1 albo 0 (tak/nie) - przydadzą się w zapytaniach 2 i 3.

    Typowe błędy

    Zrzut w PNG albo nazwany inaczej niż import nie spełnia R.1.1. Wykadrowany zrzut nie jest oceniany.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: dane pracownika o id 1

    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 id, imie, nazwisko, adres, miasto z tabeli pracownicy dla wiersza o id równym 1. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest jedynie rekord z danymi: 1, Jan, Nowak, ul. Grottgera 5, Bytom

    ok. 3 min
    Polecenie z arkusza

    Wykonaj zapytania SQL działające na bazie firma. Zapytania zapisz w pliku kwerendy.txt. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie PNG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające jedynie pola id, imie, nazwisko, adres, miasto z tabeli pracownicy dla wiersza o id równym 1

    Karta SQL bazy firma:

    • SELECT id, imie, nazwisko, adres, miasto - pięć pól z arkusza, w tej kolejności; skrypt będzie odczytywał je po numerach,
    • FROM pracownicy,
    • WHERE id = 1 - jeden wiersz.

    Wynik: 1, Jan, Nowak, ul. Grottgera 5, Bytom. Zapytanie kopiujesz do kwerendy.txt (R.1.2), zrzut: kw1.png. To samo zapytanie, ze zmienionym numerem, wyśle skrypt 1.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: kto nie podpisał dokumentu RODO

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola imie, nazwisko z tabeli pracownicy dla pracowników, którzy nie podpisali dokumentu RODO. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = false; (lub 0) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie rekordy: Katarzyna, Kowalska; Krzysztof, Rostecki; Robert, Marcinkowski

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola imie, nazwisko z tabeli pracownicy dla pracowników, którzy nie podpisali dokumentu RODO

    „Nie podpisał” to czyRODO = 0 (klucz przyjmuje też = false). Wynik: Katarzyna Kowalska, Krzysztof Rostecki, Robert Marcinkowski - te trzy osoby wypisze skrypt 2 w stopce. Zrzut: kw2.png.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: bez badań, urodzeni w latach 1970 - 1979

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pola id, nazwisko z tabeli pracownicy dla pracowników bez aktualnych badań pracowniczych, którzy urodzili się w latach 1970 ÷ 1979. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwisko FROM pracownicy WHERE dataUr LIKE "197%" AND czyBadania = false; (lub 0); (możliwe też przez porównanie daty początkowej i końcowej) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest jedynie jeden rekord z danymi: 8, Maj

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola id, nazwisko z tabeli pracownicy dla pracowników bez aktualnych badań pracowniczych, którzy urodzili się w latach 1970 ÷ 1979

    Dwa warunki naraz, więc AND:

    • czyBadania = 0 - brak aktualnych badań,
    • dataUr BETWEEN '1970-01-01' AND '1979-12-31' - data urodzenia w przedziale; BETWEEN obejmuje oba końce, więc 1 stycznia 1970 i 31 grudnia 1979 też się liczą. Daty zapisujesz jako tekst w formacie RRRR-MM-DD.

    Klucz podaje też krótszy zapis dataUr LIKE '197%' - porównuje datę zamienioną na tekst z wzorcem „zaczyna się od 197”. Daje ten sam wynik, ale BETWEEN porównuje daty jako daty i może skorzystać z indeksu. Wynik: jeden pracownik - 8, Maj (Ewa Maj, ur. 28.02.1979). Zrzut: kw3.png.

    Typowe błędy

    BETWEEN 1970 AND 1979 bez cudzysłowów i miesięcy porównuje datę z liczbami i nie zwraca nikogo. Rok można też wyciągnąć funkcją: YEAR(dataUr) BETWEEN 1970 AND 1979.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;
    
    -- Zapytanie 3
    SELECT id, nazwisko FROM pracownicy WHERE czyBadania = 0 AND dataUr BETWEEN '1970-01-01' AND '1979-12-31';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowa kolumna umiejetnosci

    Kryteria:

    R.1.6 Utworzono zapytanie 4 wstawiające kolumnę umiejetnosci typu tekstowego do tabeli pracownicy . W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE pracownicy ADD umiejetnosci TEXT; (lub ADD COLUMN; dowolny typ tekstowy) oraz wynik działania zapytania udokumentowano zrzutem wskazującym na poprawne dodanie kolumny

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: wstawiające kolumnę umiejetnosci typu tekstowego do tabeli pracownicy

    Nowa kolumna to zmiana struktury: ALTER TABLE pracownicy ADD COLUMN umiejetnosci TEXT (słowo COLUMN można pominąć). TEXT to typ tekstowy bez podawania długości - pasuje do listy umiejętności, która bywa długa; klucz przyjmuje dowolny typ tekstowy, np. VARCHAR(255). Nazwa bez polskich liter. Na zrzucie kw4.png (karta Struktura) nowa kolumna jest dziesiąta, na końcu tabeli. kwerendy.txt ma komplet.

    Typowe błędy

    INSERT wstawia wiersze, a nie kolumny - „wstawiające kolumnę” w arkuszu to ALTER TABLE ... ADD.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;
    
    -- Zapytanie 3
    SELECT id, nazwisko FROM pracownicy WHERE czyBadania = 0 AND dataUr BETWEEN '1970-01-01' AND '1979-12-31';
    
    -- Zapytanie 4
    ALTER TABLE pracownicy ADD COLUMN umiejetnosci TEXT;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika: wysokość 200 px z zachowaniem proporcji

    Kryteria:

    R.2.1 Plik obraz .jpg przeskalowano z zachowaniem proporcji do wysokości 200 px odpowiadająca temu szerokość wynosi 300 px (± 5 px)

    ok. 2 min
    Polecenie z arkusza

    Plik obraz.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji do wysokości 200 px

    Oryginał ma 640 × 426 px. W GIMP-ie Obraz → Skaluj obraz, łańcuch między szerokością a wysokością zamknięty (to jest „zachowanie proporcji”), wysokość 200 - szerokość wyliczy się sama: 640 × 200 / 426 ≈ 300 px (klucz dopuszcza 300 ± 5 px). Plik → Nadpisz obraz.jpg.

    Zdjęć pracowników 1.jpg - 9.jpg nie zmieniasz - ich rozmiar w wizytówce ustawi CSS.

    Typowe błędy

    Wpisanie 200 przy otwartym łańcuchu zostawi szerokość 640 px - zdjęcie będzie spłaszczone, a R.2.1 niespełnione.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Szkielet index.php: HTML5, kodowanie, język, tytuł, styl

    Kryteria: , , ,

    R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie index

    R.2.3 Zastosowano deklarację języka HTML5, jawnie zapisany standard kodowania polskich znaków oraz zadeklarowano język witryny (np. <html lang = 'pl'>)

    R.2.4 Nadano tytuł stronie: "Wizytówki"

    R.3.6 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl4.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. 3 min
    Polecenie z arkusza

    Składa się ze strony o nazwie index.php. Zapisana w języku HTML5. Jawnie zastosowany właściwy standard kodowania polskich znaków. Zadeklarowany język zawartości witryny: polski. Tytuł strony widoczny na karcie przeglądarki: „Wizytówki”. Arkusz stylów w pliku o nazwie styl4.css prawidłowo połączony z kodem strony

    Plik index.php (R.2.2) z nagłówkiem, który w każdej stronie wygląda tak samo: <!DOCTYPE html>, <html lang="pl">, <meta charset="UTF-8"> (R.2.3), <title>Wizytówki</title> (R.2.4) i <link> do styl4.css (R.3.6). Doszedł <meta name="viewport"> - telefon pokaże stronę w szerokości ekranu; klucz go nie ocenia.

    index.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  10. Krok 10: Bloki: baner, wizytówka i stopka z trzema sekcjami

    Kryteria:

    R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, wizytówki, trzy bloki stopki. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na: blok banera, blok wizytówki, obok siebie trzy bloki stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2

    • <header> - baner,
    • <main> - wizytówka jest główną treścią strony, więc to ona dostaje <main>; selektor main nie wymaga identyfikatora,
    • jeden <footer> - stopka strony - z trzema blokami <section> (footer-left, footer-middle, footer-right). Wspólny rodzic przyda się w CSS: to on ustawi bloki w rzędzie.

    Wszystkie to znaczniki sekcji HTML5 (R.2.5).

    index.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
        </header>
        <main>
        </main>
        <footer>
            <section id="footer-left">
            </section>
            <section id="footer-middle">
            </section>
            <section id="footer-right">
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  11. Krok 11: Baner: nagłówek i formularz

    Kryteria: , , ,

    R.2.9 W bloku banera umieszczono formularz z polem edycyjnym i przyciskiem

    R.3.3 Zdefiniowano wysyłanie danych z formularza do tego samego pliku metodą POST (poprawne również bez atrybutu action)

    R.3.4 Zdefiniowano typ numeryczny dla pola edycyjnego oraz wartości: minimalną 1, maksymalną 9 oraz początkową 1

    R.3.5 Przycisk wysyła dane z formularza (input lub button z typem submit, lub button bez typu)

    ok. 3 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia o treści „Wizytówki pracowników”, formularz wysyłający dane metodą bezpieczną do tego samego pliku, zawierający: pole edycyjne o wartości początkowej 1, przyjmujące tylko wartości liczbowe z przedziału od 1 do 9, przycisk o treści „WYŚWIETL”, którego wciśnięcie powoduje wysłanie danych do skryptu PHP

    • <h1> z tytułem banera,
    • <form method="post"> bez action - dane wracają do index.php (R.3.3). „Metoda bezpieczna” z arkusza to w kluczu POST; w słowniku protokołu HTTP bezpieczna (safe) nazywa się metoda tylko odczytująca dane, czyli GET - do wyboru wizytówki naturalniejsza, ale klucz wymaga POST,
    • <input type="number" name="id" min="1" max="9" value="1"> (R.3.4) i <button type="submit"> (R.3.5) - baner ma formularz z polem i przyciskiem (R.2.9),
    • aria-label - pole nie ma widocznej etykiety (obraz 2), więc opis dostaje dla czytnika ekranu, który bez niego przeczytałby tylko „pole liczbowe, 1”.

    Wartość 1 zastąpi później PHP numerem z formularza - na start i tak będzie to 1.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="1" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
        </main>
        <footer>
            <section id="footer-left">
            </section>
            <section id="footer-middle">
            </section>
            <section id="footer-right">
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  12. Krok 12: Zawartość trzech bloków stopki

    Kryteria: , ,

    R.2.8 W lewym bloku stopki umieszczono obraz o nazwie obraz.jpg z tekstem alternatywnym "pracownicy firmy" lub w bloku wizytówki umieszczono obraz z tekstem alternatywnym "pracownik" (w skrypcie lub HTML)

    R.2.10 W stopce umieszczono paragraf "Autorem wizytownika jest: "

    R.3.2 Na stronie umieszczono odnośnik, którego kliknięcie inicjuje otwarcie strony http://agencjareklamowa543.pl/ (opcjonalnie https://agencjareklamowa543.pl/) w nowej karcie przeglądarki

    ok. 3 min
    Polecenie z arkusza

    Zawartość lewego bloku stopki: obraz o nazwie obraz.jpg z tekstem alternatywnym „pracownicy firmy”. Zawartość środkowego bloku stopki: paragraf o treści „Autorem wizytownika jest: ”, dalej wstawiony numer zdającego, którym został podpisany arkusz. Odnośnik do strony http://agencjareklamowa543.pl/ otwierający się w osobnej karcie przeglądarki i podpisany „Zobacz nasze realizacje”. Zawartość prawego bloku stopki: paragraf (akapit) o treści „Osoby proszone o podpisanie dokumentu RODO:”, lista numerowana (uporządkowana) o elementach wypełnionych skryptem 2

    • lewy: zdjęcie z tekstem alternatywnym (R.2.8) i wymiarami width="300" height="200" - przeglądarka rezerwuje miejsce, zanim plik się pobierze,
    • środkowy: akapit z autorem (na egzaminie numer PESEL, tu Bartosz Bryniarski, R.2.10) i odnośnik z target="_blank" (R.3.2) oraz rel="noopener noreferrer" - obca strona w nowej karcie nie dostaje dostępu do karty z wizytownikiem (window.opener) i nie poznaje jej adresu,
    • prawy: akapit i pusta lista numerowana <ol> - elementy dopisze PHP.
    index.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="1" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                </ol>
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  13. Etap 3: Styl CSS

    Kroki 13-17 · po tym etapie masz 30 z 39 kryteriów (pkt)

    Krok 13: Zmienne kolorów, strona i nagłówek pierwszego stopnia

    Kryteria:

    R.4.1 Ustawiono dla selektora strony (body lub html, lub kontenera strony) krój czcionki Arial, kolor tła AntiqueWhite oraz dla selektora h1 grubość czcionki na 300

    ok. 2 min
    Polecenie z arkusza

    Styl CSS powinien być zdefiniowany jedynie w zewnętrznym pliku CSS. Dla selektora strony: krój czcionki Arial, kolor tła AntiqueWhite. Dla selektora nagłówka pierwszego stopnia: grubość czcionki 300

    W :root dwie zmienne CSS: brąz banera, stopki, pola i przycisku (w arkuszu pięć razy) oraz ciemny brąz tekstu wizytówki. body - Arial i tło AntiqueWhite, a h1 - grubość 300 (selektor znacznika, jak każe uwaga arkusza; R.4.1).

    styl4.css CSS nowy plik
    :root {
        --brown: #7B5E57;
        --dark-brown: #5D4037;
    }
    
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    
    h1 {
        font-weight: 300;
    }
    Podgląd strony po tym kroku (index.php)
  14. Krok 14: Baner i blok wizytówki

    Kryteria: ,

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera i bloku wizytówki

    R.4.8 Ustawiono dla bloku wizytówki cień o cechach: przesunięcie poziome i pionowe 0, rozmycie 20px kolor szary (dowolny odcień) np. box-shadow: 0 0 20px grey; (lub 0 0 20px 0 grey, lub gray, lub inny dowolny szary)

    ok. 3 min
    Polecenie z arkusza

    Dla bloku banera: kolor tła #7B5E57, biały kolor czcionki, wyrównanie tekstu do środka. Dla bloku wizytówki: kolor czcionki #5D4037, maksymalna szerokość 300 px, wyrównanie tekstu do środka, marginesy zewnętrzne dolny i górny 70px, boczne ustalane automatycznie przez przeglądarkę, margines wewnętrzny dolny 60 px, cień bloku bez przesunięcia pionowego i poziomego, rozmycie 20 px i kolor szary

    header dostaje tło ze zmiennej, biały tekst i środkowanie; main - wizytówka: max-width: 300px, margin: 70px auto (70 px góra i dół, boki po równo - blok na środku), padding-bottom: 60px i cień 0 0 20px gray rozlany równo wokół bloku (R.4.8). Banner i wizytówka mają tekst wyśrodkowany (R.4.6).

    styl4.css CSS zmienione: 15 linii
    :root {
        --brown: #7B5E57;
        --dark-brown: #5D4037;
    }
    
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    
    h1 {
        font-weight: 300;
    }
    
    header {
        background-color: var(--brown);
        color: white;
        text-align: center;
    }
    
    main {
        color: var(--dark-brown);
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Stopka: trzy bloki w rzędzie

    Kryteria: , , , ,

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)

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

    R.4.3 Ustawiono biały kolor czcionki dla bloku banera, trzech bloków stopki oraz #5D4037 dla bloku wizytówki

    R.4.4 Ustawiono wysokość 200px dla trzech bloków stopki

    R.4.5 Ustawiono szerokość dla bloków lewego i prawego stopki 33%,dla bloku środkowego stopki 34% oraz maksymalną szerokość (max-width) 300px dla bloku wizytówki

    ok. 3 min
    Polecenie z arkusza

    Dla bloków lewego i prawego stopki: kolor tła #7B5E57, biały kolor czcionki, wysokość 200 px, szerokość 33%. Dla bloku środkowego stopki: kolor tła #7B5E57, biały kolor czcionki, wysokość 200 px, szerokość 34%

    • footer { display: flex; } - dzieci stopki, czyli trzy sekcje, stają w rzędzie (R.3.1). Nie ma pływania, więc nie trzeba niczego „czyścić”, a bloki zawsze mają wspólną górną krawędź,
    • cechy wspólne trzech bloków w jednej regule: tło, biały tekst, wysokość 200 px (R.4.2, R.4.3, R.4.4),
    • szerokości osobno: 33% dla bocznych i 34% dla środkowego - zostają na blokach, tak jak zapisuje je klucz (R.4.5; z max-width wizytówki).

    Suma to 100%, więc flex nie musi niczego ściskać.

    styl4.css CSS zmienione: 21 linii
    :root {
        --brown: #7B5E57;
        --dark-brown: #5D4037;
    }
    
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    
    h1 {
        font-weight: 300;
    }
    
    header {
        background-color: var(--brown);
        color: white;
        text-align: center;
    }
    
    main {
        color: var(--dark-brown);
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    
    footer {
        display: flex;
    }
    
    #footer-left,
    #footer-middle,
    #footer-right {
        background-color: var(--brown);
        color: white;
        height: 200px;
    }
    
    #footer-left,
    #footer-right {
        width: 33%;
    }
    
    #footer-middle {
        width: 34%;
    }
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Zdjęcie w wizytówce

    Kryteria:

    R.4.9 Ustawiono styl wyłącznie dla obrazu w bloku wizytówki szerokość 100%, margines wewnętrzny dolny (padding-bottom) 20 px

    ok. 1 min
    Polecenie z arkusza

    Dla obrazu znajdującego się w wizytówce (obraz w stopce nie jest formatowany tym stylem): szerokość 100%, margines wewnętrzny dolny 20 px

    Selektor potomka main img - wyłącznie zdjęcie w wizytówce, zdjęcie zespołu w stopce zostaje w swoim rozmiarze (R.4.9).

    styl4.css CSS zmienione: 5 linii
    :root {
        --brown: #7B5E57;
        --dark-brown: #5D4037;
    }
    
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    
    h1 {
        font-weight: 300;
    }
    
    header {
        background-color: var(--brown);
        color: white;
        text-align: center;
    }
    
    main {
        color: var(--dark-brown);
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    
    footer {
        display: flex;
    }
    
    #footer-left,
    #footer-middle,
    #footer-right {
        background-color: var(--brown);
        color: white;
        height: 200px;
    }
    
    #footer-left,
    #footer-right {
        width: 33%;
    }
    
    #footer-middle {
        width: 34%;
    }
    
    main img {
        width: 100%;
        padding-bottom: 20px;
    }
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Pole, przycisk i efekt najechania

    Kryteria: ,

    R.4.7 Ustawiono marginesy zewnętrzne (margin) dolny i górny: 70px, boczne: auto dla bloku wizytówki; 5px dla selektora pola edycyjnego i przycisku oraz marginesy wewnętrzne (padding) 10px dla selektora pola edycyjnego i przycisku, margines wewnętrzny dolny (padding-bottom) 60px dla bloku wizytówki

    R.4.10 Ustawiono dla pola edycyjnego i przycisku obramowanie 1px solid white; tło #7B5E57 i biały kolor czcionki oraz jedynie dla przycisku pseudoklasę hover z wartościami: tło białe, kolor czcionki #7B5E57

    ok. 2 min
    Polecenie z arkusza

    Dla selektora pola edycyjnego i przycisku: kolor tła #7B5E57, biały kolor czcionki, marginesy wewnętrzne 10 px, zewnętrzne 5 px, obramowanie 1 px, linią ciągłą białą. Gdy kursor myszy znajdzie się w obrębie przycisku, tło przycisku zmienia się na białe, a kolor czcionki na #7B5E57

    input, button - selektory znaczników z uwagi arkusza, marginesy 10 px i 5 px (R.4.7 razem z marginesami wizytówki), biała ramka. button:hover odwraca kolory tylko przycisku (R.4.10) - ta sama zmienna --brown raz jest tłem, raz kolorem tekstu.

    styl4.css CSS zmienione: 14 linii
    :root {
        --brown: #7B5E57;
        --dark-brown: #5D4037;
    }
    
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    
    h1 {
        font-weight: 300;
    }
    
    header {
        background-color: var(--brown);
        color: white;
        text-align: center;
    }
    
    main {
        color: var(--dark-brown);
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    
    footer {
        display: flex;
    }
    
    #footer-left,
    #footer-middle,
    #footer-right {
        background-color: var(--brown);
        color: white;
        height: 200px;
    }
    
    #footer-left,
    #footer-right {
        width: 33%;
    }
    
    #footer-middle {
        width: 34%;
    }
    
    main img {
        width: 100%;
        padding-bottom: 20px;
    }
    
    input,
    button {
        background-color: var(--brown);
        color: white;
        padding: 10px;
        margin: 5px;
        border: 1px solid white;
    }
    
    button:hover {
        background-color: white;
        color: var(--brown);
    }
    Podgląd strony po tym kroku (index.php)
  18. Etap 4: Skrypt PHP

    Kroki 18-22 · po tym etapie masz 39 z 39 kryteriów (pkt)

    Krok 18: Na górze pliku: połączenie PDO z bazą firma

    Kryteria: ,

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

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

    ok. 4 min
    Polecenie z arkusza

    Napisany w języku PHP. Skrypt łączy się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie firma. Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem

    Cały PHP stoi na początku pliku, przed <!DOCTYPE html>: najpierw zebranie danych, potem HTML, który je tylko wstawia. Gdy coś pójdzie źle, wiadomo to, zanim przeglądarka dostanie choć kawałek strony.

    • declare(strict_types=1); - PHP nie zamienia po cichu typów przy wywołaniach funkcji,
    • new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', ...) - serwer, baza firma i kodowanie w jednym napisie, użytkownik root, puste hasło (R.5.1),
    • ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, który łapie catch i zamienia na komunikat; FETCH_ASSOC - wiersze jako tablice z nazwami kolumn ($employee['imie'] zamiast $row[1]),
    • finally { $pdo = null; } - wykona się zawsze, po udanych zapytaniach i po błędzie; usunięcie obiektu PDO zamyka połączenie, a zapytania dojdą w środku try, więc zamknięcie zawsze będzie ostatnią operacją na bazie (R.5.2).

    Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2 - na razie strona wygląda jak wcześniej.

    index.php PHP zmienione: 14 linii
    <?php
    declare(strict_types=1);
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="1" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                </ol>
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Zapytanie przygotowane o pracownika nr 1

    ok. 3 min
    Polecenie z arkusza

    Działanie skryptu 1: wysyła do bazy zapytanie 1 zmodyfikowane w ten sposób, że dane wybrane kwerendą po uruchomieniu strony WWW dotyczą pracownika o id równym 1, po zatwierdzeniu formularza, pracownika o id wpisanym do pola edycyjnego

    Trzy zmienne na start - numer $id = 1, pusta wizytówka $employee i brak błędu $error - oraz zapytanie 1 jako zapytanie przygotowane:

    • prepare(...) z parametrem :id w miejscu numeru - baza dostaje treść zapytania osobno od danych,
    • execute(['id' => $id]) podstawia wartość,
    • fetch() zwraca wiersz albo false, gdy pracownika nie ma; ?: null zamienia false na null.

    Na razie numer to zawsze 1 - formularz dojdzie, gdy wizytówka będzie już wypisana.

    index.php PHP zmienione: 7 linii
    <?php
    declare(strict_types=1);
    
    $id = 1;
    $employee = null;
    $error = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $statement = $pdo->prepare('SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = :id;');
        $statement->execute(['id' => $id]);
        $employee = $statement->fetch() ?: null;
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="1" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                </ol>
            </section>
        </footer>
    </body>
    </html>

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

  20. Krok 20: Wizytówka jako szablon z danymi

    Kryteria: , ,

    R.2.6 W bloku banera zapisano nagłówek h1: "Wizytówki pracowników", w bloku wizytówki zapisano nagłówki h2 i h4 (w skrypcie lub HTML)

    R.5.4 Skrypt 1 wypisuje w bloku wizytówki imię, nazwisko, adres i miasto

    R.5.5 W skrypcie 1 ustalono nazwę pliku na podstawie wartości id pracownika zwróconej zapytaniem np. $wiersz[0] = (string) $wiersz[0] . ".jpg"; oraz wyświetlono obraz o takiej nazwie pliku

    ok. 4 min
    Polecenie z arkusza

    dane otrzymane z bazy są wyświetlane według schematu: obraz z tekstem alternatywnym „pracownik” i nazwą pliku <id>.jpg, gdzie <id> to pole id wybrane z bazy, nagłówek drugiego stopnia z imieniem i nazwiskiem wybranymi z bazy, nagłówek czwartego stopnia o treści „Adres:”, paragraf z adresem i miastem wybranymi z bazy danych rozdzielone przecinkiem

    Na górze pliku doszła funkcja e() - skrót htmlspecialchars z kodowaniem UTF-8. Każde wypisanie danych z bazy przechodzi przez nią: znak < w nazwisku czy adresie pokaże się jako tekst, a nie stanie się znacznikiem (ochrona przed XSS).

    W <main> szablon zamiast echo z całym HTML-em w napisach:

    • <?php if ($employee): ?> ... <?php else: ?> ... <?php endif; ?> - składnia z dwukropkiem czytelna między znacznikami,
    • <?= ... ?> to skrót od <?php echo ... ?>,
    • nazwa zdjęcia z pola id: $employee['id'] . '.jpg' (R.5.5), <h2> z imieniem i nazwiskiem, <h4>Adres:</h4> i akapit z adresem i miastem po przecinku (R.5.4, R.2.6),
    • gałąź else wypisze komunikat, gdy pracownika nie ma albo baza nie odpowiada.

    Podgląd: wizytówka Jana Nowaka, jak na obrazie 2.

    index.php PHP zmienione: 13 linii
    <?php
    declare(strict_types=1);
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $id = 1;
    $employee = null;
    $error = '';
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $statement = $pdo->prepare('SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = :id;');
        $statement->execute(['id' => $id]);
        $employee = $statement->fetch() ?: null;
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="1" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
            <?php if ($employee): ?>
                <img src="<?= e($employee['id'] . '.jpg') ?>" alt="pracownik">
                <h2><?= e($employee['imie'] . ' ' . $employee['nazwisko']) ?></h2>
                <h4>Adres:</h4>
                <p><?= e($employee['adres'] . ', ' . $employee['miasto']) ?></p>
            <?php else: ?>
                <p><?= e($error ?: 'Nie ma pracownika o tym numerze.') ?></p>
            <?php endif; ?>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                </ol>
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Krok 21: Numer z formularza: sprawdzony i zostawiony w polu

    Kryteria:

    R.5.3 Skrypt 2 wysyła do bazy zapytanie 2 lub skrypt 1 wysyła do bazy zmodyfikowane zapytanie 1 w ten sposób, że dane wybrane kwerendą po uruchomieniu strony WWW dotyczą pracownika o id równym 1, natomiast po zatwierdzeniu formularza, pracownika o id wpisanym do pola edycyjnego formularza

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 1: wysyła do bazy zapytanie 1 zmodyfikowane w ten sposób, że dane wybrane kwerendą po uruchomieniu strony WWW dotyczą pracownika o id równym 1, po zatwierdzeniu formularza, pracownika o id wpisanym do pola edycyjnego

    Po kliknięciu „WYŚWIETL” numer przychodzi w $_POST['id']:

    • filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ...) przepuszcza tylko liczbę całkowitą z przedziału 1 - 9 (opcje min_range i max_range) i od razu zwraca ją jako liczbę; tekst, ułamek albo 12 dają false,
    • przy false skrypt ustawia komunikat i nie pyta bazy - zapytanie wykonuje się tylko przy poprawnym numerze (if ($error === '')),
    • w polu value="<?= $id ?>" - po wysłaniu formularza pole pokazuje wybrany numer, a nie znów 1. Przy pierwszym wejściu $id to 1, więc wartość początkowa się zgadza.

    Atrybuty min i max w HTML-u sprawdza tylko przeglądarka, a formularz można wysłać z jej pominięciem - dlatego sprawdzenie na serwerze. Sprawdzone: wysłanie w polu id tekstu 0 UNION SELECT ... GROUP_CONCAT(dataUr) ... (w wersji podstawowej bez zabezpieczeń wyciągało daty urodzenia wszystkich pracowników) daje tu tylko komunikat o złym numerze.

    Podgląd: formularz wysłany z numerem 8 - wizytówka Ewy Maj, a w polu 8 (R.5.3).

    index.php PHP zmienione: 13 linii
    <?php
    declare(strict_types=1);
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $id = 1;
    $employee = null;
    $error = '';
    if (isset($_POST['id'])) {
        $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 9]]);
        if ($id === false) {
            $error = 'Numer pracownika musi być liczbą od 1 do 9.';
            $id = 1;
        }
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        if ($error === '') {
            $statement = $pdo->prepare('SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = :id;');
            $statement->execute(['id' => $id]);
            $employee = $statement->fetch() ?: null;
        }
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="<?= $id ?>" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
            <?php if ($employee): ?>
                <img src="<?= e($employee['id'] . '.jpg') ?>" alt="pracownik">
                <h2><?= e($employee['imie'] . ' ' . $employee['nazwisko']) ?></h2>
                <h4>Adres:</h4>
                <p><?= e($employee['adres'] . ', ' . $employee['miasto']) ?></p>
            <?php else: ?>
                <p><?= e($error ?: 'Nie ma pracownika o tym numerze.') ?></p>
            <?php endif; ?>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                </ol>
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Lista osób bez dokumentu RODO

    Kryteria: , ,

    R.2.7 W bloku stopki umieszczono listę numerowaną, zastosowano znaczniki <ol>, <li> (w skrypcie lub HTML)

    R.5.6 W skrypcie 2 zastosowano pętlę działającą na wszystkich wierszach wybranych zapytaniem

    R.5.7 Skrypt 2 wypisuje imiona i nazwiska wybrane zapytaniem jako osobne elementy listy

    ok. 3 min
    Polecenie z arkusza

    Skrypt 2 wysyła do bazy zapytanie 2 i wypisuje imiona i nazwiska wybrane zapytaniem jako osobne elementy listy

    • na górze pliku, w tym samym try przed finally: zapytanie 2 przez query (nie ma w nim danych od użytkownika, więc nie musi być przygotowane) i fetchAll() - wszystkie wiersze naraz w tablicy $rodo,
    • w <ol> pętla foreach po tablicy (R.5.6) i każda osoba jako <li> (R.5.7, R.2.7), przepuszczona przez e().

    Zamknięcie połączenia w finally jest nadal ostatnią operacją na bazie. Podgląd: trzy ponumerowane osoby w prawym bloku stopki, jak na obrazie 2.

    index.php PHP zmienione: 5 linii
    <?php
    declare(strict_types=1);
    
    function e(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }
    
    $id = 1;
    $employee = null;
    $rodo = [];
    $error = '';
    if (isset($_POST['id'])) {
        $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 9]]);
        if ($id === false) {
            $error = 'Numer pracownika musi być liczbą od 1 do 9.';
            $id = 1;
        }
    }
    
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=firma;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        if ($error === '') {
            $statement = $pdo->prepare('SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = :id;');
            $statement->execute(['id' => $id]);
            $employee = $statement->fetch() ?: null;
        }
        $rodo = $pdo->query('SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Baza danych jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
                <input type="number" name="id" min="1" max="9" value="<?= $id ?>" aria-label="Numer pracownika od 1 do 9">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <main>
            <?php if ($employee): ?>
                <img src="<?= e($employee['id'] . '.jpg') ?>" alt="pracownik">
                <h2><?= e($employee['imie'] . ' ' . $employee['nazwisko']) ?></h2>
                <h4>Adres:</h4>
                <p><?= e($employee['adres'] . ', ' . $employee['miasto']) ?></p>
            <?php else: ?>
                <p><?= e($error ?: 'Nie ma pracownika o tym numerze.') ?></p>
            <?php endif; ?>
        </main>
        <footer>
            <section id="footer-left">
                <img src="obraz.jpg" alt="pracownicy firmy" width="300" height="200">
            </section>
            <section id="footer-middle">
                <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
                <a href="http://agencjareklamowa543.pl/" target="_blank" rel="noopener noreferrer">Zobacz nasze realizacje</a>
            </section>
            <section id="footer-right">
                <p>Osoby proszone o podpisanie dokumentu RODO:</p>
                <ol>
                    <?php foreach ($rodo as $person): ?>
                        <li><?= e($person['imie'] . ' ' . $person['nazwisko']) ?></li>
                    <?php endforeach; ?>
                </ol>
            </section>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  23. Etap 5: Porównanie z wersją podstawową

    Krok 23 · po tym etapie masz 39 z 39 kryteriów (pkt)

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

    ok. 3 min

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

    wersja podstawowawersja nowoczesna
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami
    gdzie jest PHPdwa bloki w HTML-u (wizytówka, lista)całość na górze pliku, w HTML-u szablon <?= ?>
    numer z formularza$_POST['id'] wklejony w zapytaniefilter_input 1 - 9 i zapytanie przygotowane
    zły numerostrzeżenia PHP albo „Fatal error”komunikat w wizytówce
    dane z bazyecho bez zmiane() - htmlspecialchars
    wiersz wyniku$row[1]$employee['imie']
    zamknięcie bazymysqli_close po skrypcie 2$pdo = null w finally
    pole po wysłaniuwraca do 1pokazuje wybrany numer
    stopkatrzy <footer> z float: leftjeden <footer> z flexem i trzema <section>
    kolorywpisane w każdej regulezmienne --brown, --dark-brown

    Wersja podstawowa z dodanymi krokami „Dobre praktyki” dochodzi do tego samego poziomu bezpieczeństwa, nowoczesna ma go od pierwszego zapytania. W prawdziwej aplikacji dane logowania do bazy trzyma się w osobnym pliku poza katalogiem strony, a konto bazy nie jest kontem root bez hasła - na egzaminie oba te ustawienia narzuca arkusz.

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 i łatwiej ją napisać bez dokumentacji. Nowoczesna nie wywraca się na złym numerze i nie wypuszcza danych osobowych przez pole formularza - a klucz przyjmuje obie.

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

  24. Etap 6: Oddanie pracy

    Krok 24 · po tym etapie masz 39 z 39 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

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

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. W folderze z numerem zdającego: zdjęcia 1.jpg - 9.jpg, import.jpg, index.php, kw1.png - kw4.png, kwerendy.txt, obraz.jpg, przeglądarka.txt i styl4.css. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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