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

Rozwiązanie krok po kroku: Wizytówki pracowników z formularzem (Wersja podstawowa)

Aplikacja wizytówek pracowniczych: baza firma z tabelami pracownicy i stanowiska, na której cztery zapytania wybierają dane pracownika, osoby bez podpisanego dokumentu RODO i pracownika bez aktualnych badań urodzonego w latach 70., a ostatnie dodaje kolumnę umiejetnosci. Do tego zdjęcie zespołu przeskalowane do wysokości 200 px i strona index.php: baner z formularzem wyboru numeru pracownika, wizytówka ze zdjęciem i adresem wypisana przez skrypt PHP oraz trzy bloki stopki - w prawym lista osób proszonych o podpisanie dokumentu RODO.

To arkusz EE.09 ze stycznia 2023 - kwalifikacji formuły 2017, którą zastąpiła INF.03. 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ą. PHP jest napisany najprościej, funkcjami z tabeli 1 arkusza (mysqli_connect, mysqli_query, mysqli_fetch_row, mysqli_close), a na końcu są trzy kroki o zabezpieczeniach, których klucz nie sprawdza - pokazane na prawdziwym ataku na ten skrypt.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: PDO z zapytaniem przygotowanym na górze pliku, walidacja numeru, stopka na flex i zmienne CSS - obie wersje są zgodne z kluczem.

Baza i grafiki pochodzą z oryginalnego archiwum CKE zad4 (załącznik do pobrania na stronie arkusza, hasło w treści zadania). 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 funkcje 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 (75% z 39 to 29,25, a punktów nie dzieli się na części). Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.

  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-24 · 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: Plik index.php w HTML5

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie index.php. Zapisana w języku HTML5

    Plik index.php (R.2.2) - rozszerzenie .php, bo strona będzie zawierać skrypty, choć na początku to czysty HTML. Pierwsza linia <!DOCTYPE html> to deklaracja HTML5. Plik bez ani linijki PHP podgląd pokazuje wprost; wynik działania PHP pojawi się od etapu skryptów.

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

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwszy element <head>; plik zapisz w UTF-8. Dane z bazy też są w UTF-8 (utf8mb4 w baza.sql), więc polskie litery z tabeli wyświetlą się poprawnie.

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

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany język zawartości witryny: polski

    lang="pl" w znaczniku <html>. Deklaracja HTML5, kodowanie i język razem dają R.2.3.

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

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Wizytówki”

    <title>Wizytówki</title> (R.2.4) - krótszy niż nagłówek banera „Wizytówki pracowników”.

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

    Kryteria:

    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. 1 min
    Polecenie z arkusza

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

    <link rel="stylesheet" href="styl4.css">. Całe formatowanie trafi do tego pliku (R.3.6) - także pseudoklasa :hover przycisku.

    Typowe błędy

    Atrybut style w znaczniku albo blok <style> odbiera R.3.6; tak samo zły selektor bloku (np. .card zamiast #card).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  14. Krok 14: Bloki: baner, wizytówka i trzy bloki stopki

    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

    Pięć bloków ze znaczników sekcji HTML5 (R.2.5):

    • <header> - baner,
    • <section id="card"> - blok wizytówki (identyfikatory po angielsku, arkusz ich nie narzuca),
    • trzy znaczniki <footer> z identyfikatorami footer-left, footer-middle, footer-right - stopka na obrazie 2 to trzy osobne bloki stojące obok siebie. Obok siebie ustawi je dopiero CSS.
    index.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Baner: nagłówek pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia o treści „Wizytówki pracowników”

    <h1> w <header>.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Formularz wysyłający metodą POST do tego samego pliku

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    formularz wysyłający dane metodą bezpieczną do tego samego pliku, zawierający:

    <form method="post"> - bez atrybutu action formularz wysyła dane pod adres bieżącej strony, czyli do index.php (można też wpisać action="index.php"; klucz przyjmuje obie formy, R.3.3).

    Arkusz i klucz przez „metodę bezpieczną” rozumieją POST: wysłany numer nie pojawia się w adresie strony. W terminologii protokołu HTTP słowo „bezpieczna” ma inne znaczenie - metodami bezpiecznymi (ang. safe) nazywa się te, które tylko odczytują dane, i jest nią właśnie GET. Do odczytu wizytówki GET byłby naturalniejszy (adres index.php?id=5 dałoby się zapisać w zakładkach), ale na egzaminie liczy się klucz - wpisz post.

    Typowe błędy

    method="get" - formularz zadziała, ale R.3.3 wymaga POST.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Wizytówki</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h1>Wizytówki pracowników</h1>
            <form method="post">
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Pole numeryczne 1 - 9 z wartością początkową 1

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    pole edycyjne o wartości początkowej 1, przyjmujące tylko wartości liczbowe z przedziału od 1 do 9

    <input> z czterema atrybutami (R.3.4):

    • type="number" - pole liczbowe ze strzałkami; przeglądarka nie przyjmie liter,
    • min="1" i max="9" - przedział; przy próbie wysłania 10 przeglądarka pokaże dymek z błędem i niczego nie wyśle,
    • value="1" - wartość na start.

    Atrybut name="id" nadaje nazwę, pod którą wartość trafi do skryptu PHP ($_POST['id']) - bez name pole w ogóle nie jest wysyłane.

    Typowe błędy

    Ograniczenia min i max sprawdza tylko przeglądarka - w etapie dobrych praktyk widać, co się dzieje, gdy ktoś wyśle formularz z pominięciem przeglądarki.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  18. Krok 18: Przycisk WYŚWIETL

    Kryteria: ,

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

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

    ok. 1 min
    Polecenie z arkusza

    przycisk o treści „WYŚWIETL”, którego wciśnięcie powoduje wysłanie danych do skryptu PHP

    <button type="submit"> wysyła formularz (R.3.5; przycisk bez typu w formularzu też wysyła). Napis wielkimi literami jak w arkuszu. Baner ma komplet: nagłówek i formularz z polem i przyciskiem (R.2.9).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Blok wizytówki czeka na skrypt 1

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku wizytówek: efekt działania skryptu 1

    Zawartość wizytówki (zdjęcie, imię i nazwisko, adres) wypisze skrypt PHP z danych z bazy - w HTML-u blok #card zostaje na razie pusty. Skrypt powstanie po stylach.

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

  20. Krok 20: Lewy blok stopki: zdjęcie zespołu

    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)

    ok. 1 min
    Polecenie z arkusza

    Zawartość lewego bloku stopki: obraz o nazwie obraz.jpg z tekstem alternatywnym „pracownicy firmy”

    <img> z src i alt (R.2.8). To przeskalowane zdjęcie 300 × 200 px - tak wysokie jak blok stopki.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Krok 21: Środkowy blok stopki: autor

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Zawartość środkowego bloku stopki: paragraf o treści „Autorem wizytownika jest: ”, dalej wstawiony numer zdającego, którym został podpisany arkusz

    Na egzaminie po dwukropku wpisujesz numer PESEL; tu stoi imię i nazwisko autora: Bartosz Bryniarski (R.2.10).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Odnośnik otwierany w nowej karcie

    Kryteria:

    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. 1 min
    Polecenie z arkusza

    Odnośnik do strony http://agencjareklamowa543.pl/ otwierający się w osobnej karcie przeglądarki i podpisany „Zobacz nasze realizacje”

    <a> z pełnym adresem i target="_blank" - osobna karta (R.3.2).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  23. Krok 23: Prawy blok stopki: akapit RODO

    ok. 1 min
    Polecenie z arkusza

    Zawartość prawego bloku stopki: paragraf (akapit) o treści „Osoby proszone o podpisanie dokumentu RODO:”

    <p> z tekstem z arkusza.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  24. Krok 24: Lista numerowana na wyniki skryptu 2

    ok. 1 min
    Polecenie z arkusza

    lista numerowana (uporządkowana) o elementach wypełnionych skryptem 2

    Lista numerowana to <ol> (ordered list); <ul> dałby kropki zamiast numerów. Elementy <li> wypisze skrypt 2 - w HTML-u lista zostaje pusta.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  25. Etap 3: Styl CSS

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

    Krok 25: Plik styl4.css: krój i tło strony

    ok. 1 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

    Nowy plik styl4.css. Selektor strony body: krój Arial i tło AntiqueWhite - nazwa koloru CSS, jasny beż z obrazu 2.

    styl4.css CSS nowy plik
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    Podgląd strony po tym kroku (index.php)
  26. Krok 26: Baner

    ok. 1 min
    Polecenie z arkusza

    Dla bloku banera: kolor tła #7B5E57, biały kolor czcionki, wyrównanie tekstu do środka

    Selektor header. text-align: center środkuje nagłówek i formularz - pole i przycisk są elementami liniowymi, więc ustawiają się jak tekst.

    styl4.css CSS zmienione: 5 linii
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    Podgląd strony po tym kroku (index.php)
  27. Krok 27: 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 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

    Selektor #card:

    • max-width: 300px - na szerokim ekranie 300 px, na wąskim (telefon) blok się zwęzi,
    • margin: 70px auto - skrót dwóch wartości: pierwsza to góra i dół (70 px), druga to boki; auto dzieli wolne miejsce po równo, więc wizytówka stoi na środku strony,
    • padding-bottom: 60px - pusty pas pod adresem (obraz 2),
    • box-shadow: 0 0 20px gray - oba przesunięcia 0, więc cień rozlewa się równo dookoła bloku; rozmycie 20 px, kolor szary (R.4.8).

    Banner i wizytówka mają wyrównanie do środka (R.4.6).

    Typowe błędy

    margin: 70px bez auto przyklei wizytówkę do lewej. width: 300px zamiast max-width daje ten sam obraz na komputerze, ale klucz (R.4.5) wymaga maksymalnej szerokości.

    styl4.css CSS zmienione: 8 linii
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        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)
  28. Krok 28: Lewy i prawy blok stopki

    ok. 1 min
    Polecenie z arkusza

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

    Dwa selektory identyfikatorów po przecinku - jedna reguła na dwa bloki o tych samych cechach.

    styl4.css CSS zmienione: 6 linii
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    #footer-left, #footer-right {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 33%;
    }
    Podgląd strony po tym kroku (index.php)
  29. Krok 29: Środkowy blok stopki

    Kryteria: , , ,

    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. 2 min
    Polecenie z arkusza

    Dla bloku środkowego stopki: kolor tła #7B5E57, biały kolor czcionki, wysokość 200 px, szerokość 34%

    Ta sama reguła z szerokością 34% - razem 33 + 34 + 33 = 100%, bloki wypełnią całą szerokość strony. Tło (R.4.2), biały tekst stopki i banera oraz brązowy tekst wizytówki (R.4.3), wysokość 200 px (R.4.4) i szerokości z maksymalną szerokością wizytówki (R.4.5) są ustawione.

    Bloki stoją jeszcze jeden pod drugim - obok siebie ustawi je reguła układu na końcu pliku.

    styl4.css CSS zmienione: 6 linii
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    #footer-left, #footer-right {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 33%;
    }
    #footer-middle {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 34%;
    }
    Podgląd strony po tym kroku (index.php)
  30. Krok 30: 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 #card img - tylko obraz wewnątrz wizytówki; samo img objęłoby też zdjęcie w stopce i rozciągnęło je (R.4.9). Zdjęcie pracownika 400 × 267 px zmieści się w 300 px szerokości bloku.

    Typowe błędy

    Selektor img bez #card - klucz wymaga stylu wyłącznie dla obrazu w wizytówce.

    styl4.css CSS zmienione: 4 linie
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    #footer-left, #footer-right {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 33%;
    }
    #footer-middle {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 34%;
    }
    #card img {
        width: 100%;
        padding-bottom: 20px;
    }
    Podgląd strony po tym kroku (index.php)
  31. Krok 31: Nagłówek pierwszego stopnia: cienki krój

    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. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka pierwszego stopnia: grubość czcionki 300

    Selektor znacznika h1 - arkusz w uwadze zabrania tu klasy i identyfikatora. font-weight: 300 to krój cieńszy od zwykłego (400), a nagłówki domyślnie mają 700 (pogrubienie). Z regułą strony daje to R.4.1.

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

    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

    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łą

    Selektory znaczników input, button - też narzucone w uwadze arkusza. Pole i przycisk mają tło banera i białą ramkę, więc na obrazie 2 widać je jako dwa jasne prostokąty. Marginesy wizytówki, pola i przycisku są ustawione (R.4.7).

    styl4.css CSS zmienione: 7 linii
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    #footer-left, #footer-right {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 33%;
    }
    #footer-middle {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 34%;
    }
    #card img {
        width: 100%;
        padding-bottom: 20px;
    }
    h1 {
        font-weight: 300;
    }
    input, button {
        background-color: #7B5E57;
        color: white;
        padding: 10px;
        margin: 5px;
        border: 1px solid white;
    }
    Podgląd strony po tym kroku (index.php)
  33. Krok 33: Przycisk po najechaniu kursorem

    Kryteria:

    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. 1 min
    Polecenie z arkusza

    Gdy kursor myszy znajdzie się w obrębie przycisku, tło przycisku zmienia się na białe, a kolor czcionki na #7B5E57

    Pseudoklasa :hover tylko dla button - pole liczbowe ma się nie zmieniać (R.4.10). Reguła stoi po regule input, button, a przy tej samej sile selektorów wygrywa reguła zapisana później - tu i tak button:hover jest silniejszy od samego button.

    Typowe błędy

    input:hover, button:hover zmieni też pole - klucz wymaga pseudoklasy jedynie dla przycisku.

    styl4.css CSS zmienione: 4 linie
    body {
        font-family: Arial;
        background-color: AntiqueWhite;
    }
    header {
        background-color: #7B5E57;
        color: white;
        text-align: center;
    }
    #card {
        color: #5D4037;
        max-width: 300px;
        text-align: center;
        margin: 70px auto;
        padding-bottom: 60px;
        box-shadow: 0 0 20px gray;
    }
    #footer-left, #footer-right {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 33%;
    }
    #footer-middle {
        background-color: #7B5E57;
        color: white;
        height: 200px;
        width: 34%;
    }
    #card img {
        width: 100%;
        padding-bottom: 20px;
    }
    h1 {
        font-weight: 300;
    }
    input, button {
        background-color: #7B5E57;
        color: white;
        padding: 10px;
        margin: 5px;
        border: 1px solid white;
    }
    button:hover {
        background-color: white;
        color: #7B5E57;
    }
    Podgląd strony po tym kroku (index.php)
  34. Krok 34: Układ: trzy bloki stopki obok siebie

    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)

    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

    float: left na trzech blokach stopki - ustawiają się w rzędzie od lewej. Szerokości dają razem dokładnie 100%, więc trzeci blok mieści się jeszcze w rzędzie (bloki nie mają marginesów ani obramowań, które by do tego doszły). Baner i wizytówka są zwykłymi blokami nad stopką (R.3.1). Pod stopką nie ma treści, więc clear nie jest potrzebny.

    Typowe błędy

    Dodanie stopce padding albo border przy szerokościach 33/34/33% zepchnie prawy blok do nowego wiersza - wtedy pomaga box-sizing: border-box.

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

    Kroki 35-44 · po tym etapie masz 39 z 39 kryteriów (pkt)

    Krok 35: Skrypt 1 w bloku wizytówki: połączenie z bazą firma

    Kryteria:

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

    ok. 3 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

    „Zawartość bloku wizytówek: efekt działania skryptu 1” - blok PHP (<?php ... ?>) piszesz więc wewnątrz <section id="card">. Serwer wykona go, zanim strona trafi do przeglądarki, a w jego miejsce wstawi to, co skrypt wypisze.

    Pierwsza instrukcja: mysqli_connect z tabeli 1 - serwer localhost, użytkownik root, puste hasło '' i baza firma (R.5.1). Połączenie trafia do zmiennej $connection; skorzysta z niej też skrypt 2 w stopce - zmienne PHP z jednego bloku <?php są widoczne w kolejnych blokach tego samego pliku.

    Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2). Stronę otwierasz przez http://localhost/…/index.php - otwarty z dysku plik PHP nie zostanie wykonany.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  36. Krok 36: Zapytanie 1 i odczyt wiersza

    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

    Najpierw sama pierwsza część zdania - pracownik numer 1:

    • mysqli_query($connection, '...') - zapytanie 1 z kwerendy.txt, wynik w $result,
    • mysqli_fetch_row($result) - pierwszy (i jedyny) wiersz wyniku jako tablica numerowana od zera: $row[0] to id, $row[1] - imie, $row[2] - nazwisko, $row[3] - adres, $row[4] - miasto. Kolejność jest taka jak pól w SELECT.

    Skrypt jeszcze niczego nie wypisuje - podgląd się nie zmienia. Numer z formularza dojdzie po wypisaniu wizytówki.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $result = mysqli_query($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;');
            $row = mysqli_fetch_row($result);
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>

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

  37. Krok 37: Zdjęcie pracownika: nazwa pliku z pola id

    Kryteria:

    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. 3 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

    • $file = $row[0] . '.jpg'; - kropka w PHP skleja napisy: id 1 i .jpg dają 1.jpg (R.5.5),
    • echo wypisuje znacznik <img> z tą nazwą i tekstem alternatywnym „pracownik”. Cudzysłowy atrybutów wewnątrz napisu w cudzysłowach poprzedzasz ukośnikiem \" - inaczej PHP uznałby, że napis się kończy. W napisie w cudzysłowach podwójnych PHP sam wstawia wartość zmiennej $file.

    Podgląd: zdjęcie Jana Nowaka (1.jpg) w wizytówce, rozciągnięte do jej szerokości przez CSS.

    Typowe błędy

    Napis w apostrofach '<img src="$file">' nie podstawia zmiennych - przeglądarka dostanie dosłownie $file i nie znajdzie pliku.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $result = mysqli_query($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;');
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  38. Krok 38: Imię i nazwisko w nagłówku drugiego stopnia

    ok. 2 min
    Polecenie z arkusza

    nagłówek drugiego stopnia z imieniem i nazwiskiem wybranymi z bazy

    echo "<h2>$row[1] $row[2]</h2>"; - imię, spacja, nazwisko. W napisie w cudzysłowach PHP podstawia też elementy tablicy zapisane bez apostrofów wokół indeksu, np. $row[1].

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $result = mysqli_query($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;');
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  39. Krok 39: Nagłówek „Adres:”

    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)

    ok. 1 min
    Polecenie z arkusza

    nagłówek czwartego stopnia o treści „Adres:”

    Stały tekst, więc w apostrofach: echo '<h4>Adres:</h4>';. Wizytówka ma już nagłówki <h2> i <h4> z R.2.6 (klucz przyjmuje je w skrypcie).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $result = mysqli_query($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;');
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  40. Krok 40: Adres i miasto w akapicie

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    paragraf z adresem i miastem wybranymi z bazy danych rozdzielone przecinkiem

    echo "<p>$row[3], $row[4]</p>"; - adres, przecinek ze spacją, miasto. Podgląd jak na obrazie 2: zdjęcie, „Jan Nowak”, „Adres:”, „ul. Grottgera 5, Bytom” (R.5.4).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $result = mysqli_query($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = 1;');
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  41. Krok 41: Numer pracownika z formularza

    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. 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

    Teraz druga część zdania:

    • $id = 1; - wartość domyślna, gdy strona jest otwierana pierwszy raz,
    • isset($_POST['id']) jest prawdziwe dopiero po kliknięciu „WYŚWIETL” - wtedy $id dostaje numer z pola o nazwie id,
    • zapytanie przechodzi do cudzysłowów podwójnych i zamiast 1 ma $id - PHP wstawi tam liczbę przed wysłaniem zapytania do bazy (R.5.3).

    Podgląd: formularz wysłany z numerem 8 - wizytówka Ewy Maj (8.jpg). Pole w banerze znów pokazuje 1, bo value="1" jest wpisane na stałe; arkusz nie wymaga, żeby wybrany numer w nim został (wersja nowoczesna go zostawia).

    Typowe błędy

    Zapytanie w apostrofach ('... WHERE id = $id;') wyśle do bazy dosłownie $id i skończy się błędem składni SQL.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                $id = $_POST['id'];
            }
            $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  42. Krok 42: Skrypt 2 w liście: zapytanie 2

    ok. 2 min
    Polecenie z arkusza

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

    Drugi blok PHP stoi wewnątrz <ol> - wypisane elementy <li> trafią do listy. Korzysta z połączenia $connection otwartego przez skrypt 1 i wysyła zapytanie 2 z kwerendy.txt. Zmienna $result dostaje nowy wynik - poprzedni (wiersz pracownika) już nie jest potrzebny.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                $id = $_POST['id'];
            }
            $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                ?>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  43. Krok 43: Pętla po osobach 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

    • while ($row = mysqli_fetch_row($result)) - w każdym obrocie pętli kolejny wiersz wyniku; gdy wierszy zabraknie, funkcja zwraca null i pętla się kończy. Pętla przechodzi przez wszystkie wiersze wyniku (R.5.6),
    • echo "<li>$row[0] $row[1]</li>"; - imię i nazwisko jako osobny element listy (R.5.7, R.2.7 - znaczniki <ol> i <li>).

    Podgląd: w prawym bloku stopki trzy ponumerowane osoby - Katarzyna Kowalska, Krzysztof Rostecki, Robert Marcinkowski - jak na obrazie 2.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                $id = $_POST['id'];
            }
            $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  44. Krok 44: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem

    mysqli_close($connection) po pętli w skrypcie 2 - to ostatnia operacja na bazie na całej stronie (R.5.2). Zamknięcie w skrypcie 1 odcięłoby połączenie, zanim skrypt 2 zdąży wysłać zapytanie. Strona spełnia wszystkie kryteria arkusza; podgląd jak na obrazie 2. Dalej trzy kroki o zabezpieczeniach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close na końcu skryptu 1 sprawia, że mysqli_query w skrypcie 2 dostaje zamknięte połączenie - PHP 8 kończy się wtedy błędem.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                $id = $_POST['id'];
            }
            $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </footer>
    </body>
    </html>

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

  45. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 45-47 · po tym etapie masz 39 z 39 kryteriów (pkt)

    Krok 45: Zabezpieczenie: numer z formularza sprawdzony w PHP

    ok. 4 min
    Polecenie z arkusza

    pole edycyjne o wartości początkowej 1, przyjmujące tylko wartości liczbowe z przedziału od 1 do 9

    Atrybuty type="number", min i max sprawdza przeglądarka. Formularz można wysłać z jej pominięciem (wystarczy polecenie curl albo narzędzia programisty), a skrypt wkleja tekst z pola wprost w zapytanie - to SQL injection. Sprawdzone na wersji z poprzednich kroków, w polu id wysłano:

    0 UNION SELECT 3, 'Daty urodzenia:', '', GROUP_CONCAT(imie, ' ', nazwisko, ' - ', dataUr SEPARATOR '; '), 'badania' FROM pracownicy

    Pracownika o id 0 nie ma, a UNION dokleja wiersz zbudowany przez atakującego: wizytówka pokazała daty urodzenia wszystkich dziewięciu pracowników - dane osobowe, których strona nigdy nie miała wyświetlać (tak samo da się wyciągnąć informację o badaniach lekarskich). Tekst abc kończy się wyjątkiem mysqli_sql_exception i „Fatal error” zamiast strony, a numer 12 - ostrzeżeniami PHP i pustą wizytówką.

    Pierwsza poprawka to sprawdzenie danych na serwerze:

    • (int) zamienia tekst na liczbę całkowitą - z 0 UNION SELECT… zostaje 0, z abc też 0,
    • numer spoza przedziału 1 - 9 z arkusza zamienia się na domyślne 1.

    Podgląd: ten sam atak po poprawce - wizytówka Jana Nowaka, żadne dane nie wyciekły. Stara linia zostaje w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                // $id = $_POST['id'];
                $id = (int) $_POST['id'];
                if ($id < 1 || $id > 9) {
                    $id = 1;
                }
            }
            $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </footer>
    </body>
    </html>

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

  46. Krok 46: Zabezpieczenie: zapytanie przygotowane

    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

    Sprawdzenie numeru zamknęło dziurę, ale zapytanie nadal powstaje ze sklejania tekstu - wystarczy, że ktoś później usunie linię z (int) albo skopiuje to zapytanie w miejsce, gdzie trafia napis, i atak wraca. Zasada, która działa zawsze: dane nigdy nie wchodzą do treści zapytania.

    • mysqli_prepare - zapytanie ze znakiem ? w miejscu numeru; baza sprawdza jego składnię, zanim zobaczy dane,
    • mysqli_stmt_bind_param($statement, 'i', $id) - podstawienie wartości; 'i' znaczy liczba całkowita (s - napis, d - liczba z przecinkiem),
    • mysqli_stmt_execute wykonuje zapytanie, a mysqli_stmt_get_result oddaje zwykły wynik - dalsza część skryptu z mysqli_fetch_row zostaje bez zmian.

    Zapytanie 2 w skrypcie 2 nie zawiera żadnych danych od użytkownika, więc może zostać zwykłym mysqli_query. Podgląd: pracownik nr 5, Joanna Nowakowska - strona działa jak wcześniej.

    Typowe błędy

    Liczba liter w drugim argumencie mysqli_stmt_bind_param musi równać się liczbie znaków ? i liczbie zmiennych.

    index.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                // $id = $_POST['id'];
                $id = (int) $_POST['id'];
                if ($id < 1 || $id > 9) {
                    $id = 1;
                }
            }
            // $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $statement = mysqli_prepare($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = ?;');
            mysqli_stmt_bind_param($statement, 'i', $id);
            mysqli_stmt_execute($statement);
            $result = mysqli_stmt_get_result($statement);
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            echo "<h2>$row[1] $row[2]</h2>";
            echo '<h4>Adres:</h4>';
            echo "<p>$row[3], $row[4]</p>";
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  47. Krok 47: Zabezpieczenie: htmlspecialchars przy wypisywaniu danych z bazy

    ok. 4 min
    Polecenie z arkusza

    dane otrzymane z bazy są wyświetlane według schematu

    Dane w bazie wpisują ludzie - kadry, inny formularz, a kolumnę umiejetnosci z zapytania 4 mogą wypełniać sami pracownicy. Gdy w polu znajdzie się znacznik, echo wstawia go do strony jako kod. Sprawdzone na kopii bazy, w której adres Roberta Marcinkowskiego (nr 7) zawierał dopisek ze znacznikiem <script>: wersja z poprzednich kroków wykonała ten skrypt u każdego, kto otworzył wizytówkę, i podmieniła całą stronę - to atak XSS (wstrzyknięcie skryptu).

    htmlspecialchars zamienia znaki <, >, & i cudzysłowy na encje (&lt; itd.), więc przeglądarka pokazuje je jako tekst. Używa się jej na wyjściu, przy każdym wypisaniu danych, które nie pochodzą z kodu strony: imię i nazwisko, adres i miasto w skrypcie 1 oraz elementy listy w skrypcie 2. Numer pliku zdjęcia jest liczbą z bazy, a nagłówek „Adres:” stałym tekstem - tych nie trzeba.

    Podgląd: ta sama kopia bazy po poprawce - znacznik widać w wizytówce jako zwykły tekst, strona działa. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <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">
                <button type="submit">WYŚWIETL</button>
            </form>
        </header>
        <section id="card">
            <?php
            $connection = mysqli_connect('localhost', 'root', '', 'firma');
            $id = 1;
            if (isset($_POST['id'])) {
                // $id = $_POST['id'];
                $id = (int) $_POST['id'];
                if ($id < 1 || $id > 9) {
                    $id = 1;
                }
            }
            // $result = mysqli_query($connection, "SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = $id;");
            $statement = mysqli_prepare($connection, 'SELECT id, imie, nazwisko, adres, miasto FROM pracownicy WHERE id = ?;');
            mysqli_stmt_bind_param($statement, 'i', $id);
            mysqli_stmt_execute($statement);
            $result = mysqli_stmt_get_result($statement);
            $row = mysqli_fetch_row($result);
            $file = $row[0] . '.jpg';
            echo "<img src=\"$file\" alt=\"pracownik\">";
            // echo "<h2>$row[1] $row[2]</h2>";
            echo '<h2>' . htmlspecialchars("$row[1] $row[2]") . '</h2>';
            echo '<h4>Adres:</h4>';
            // echo "<p>$row[3], $row[4]</p>";
            echo '<p>' . htmlspecialchars("$row[3], $row[4]") . '</p>';
            ?>
        </section>
        <footer id="footer-left">
            <img src="obraz.jpg" alt="pracownicy firmy">
        </footer>
        <footer id="footer-middle">
            <p>Autorem wizytownika jest: Bartosz Bryniarski</p>
            <a href="http://agencjareklamowa543.pl/" target="_blank">Zobacz nasze realizacje</a>
        </footer>
        <footer id="footer-right">
            <p>Osoby proszone o podpisanie dokumentu RODO:</p>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM pracownicy WHERE czyRODO = 0;');
                while ($row = mysqli_fetch_row($result)) {
                    // echo "<li>$row[0] $row[1]</li>";
                    echo '<li>' . htmlspecialchars("$row[0] $row[1]") . '</li>';
                }
                mysqli_close($connection);
                ?>
            </ol>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  48. Etap 6: Oddanie pracy

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

    Krok 48: 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. Jeśli pracujesz w C:\xampp\htdocs, skopiuj index.php i styl4.css z powrotem do folderu zdającego.

    W folderze muszą być zdjęcia 1.jpg - 9.jpg oraz import.jpg, index.php, kw1.png, kw2.png, kw3.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 47.

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