Przejdź do głównej treści
EE.09-04-21.06-SGCzerwiec 2021 · 30 kroków · ok. 74 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Panel administratora portalu społecznościowego (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza dane4 z czterema zapytaniami, wykadrowane zdjęcie 100 × 100 px i strona users.php z listą użytkowników i kartą osoby wybranej w formularzu - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • flexbox zamiast float: strona zawija bloki - baner i stopka zajmują cały rząd, bloki lewy i prawy po 50% stoją obok siebie bez clear,
  • zmienne CSS dla kolorów z arkusza, etykieta <label for> przy polu formularza,
  • PHP na PDO na górze pliku users.php, przed HTML-em, a dane połączenia w osobnym pliku config.php,
  • identyfikator z formularza sprawdzony jako liczba (filter_input) i wstawiony do zapytania przygotowanego - wstrzyknięcie SQL nie przejdzie,
  • komunikat, gdy osoby o podanym identyfikatorze nie ma w bazie, a wpisany identyfikator zostaje w polu po wysłaniu,
  • szablon z pętlą foreach: HTML stoi w pliku jak zwykły HTML, a PHP wstawia tylko wartości - każdą przez htmlspecialchars.

To arkusz EE.09 z czerwca 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Kroki bazy, grafiki i pliku settings.html są takie same jak w wersji podstawowej. Baza i zdjęcia pochodzą z oryginalnego archiwum CKE zad4.zip (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 7.4.8 - użyte konstrukcje działają w obu wersjach). Wiek w podglądzie jest liczony od roku 2026.

Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.

  1. Etap 1: Baza danych

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

    Krok 1: Folder zdającego i archiwum zad4

    ok. 2 min
    Polecenie z arkusza

    Na pulpicie znajduje się archiwum ZIP o nazwie zad4.zip zabezpieczone hasłem: *Uzytkownicy^Portalu$ Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum zad4.zip otwierasz programem 7-Zip (albo innym programem do archiwów ZIP) i rozpakowujesz do tego folderu, podając hasło *Uzytkownicy^Portalu$ - z gwiazdką na początku i znakiem dolara na końcu. W środku jest plik dane.sql i osiem zdjęć: osoba1.jpg - osoba8.jpg.

    Pliki strony muszą leżeć w tym samym folderze co zdjęcia - skrypt wstawi nazwę zdjęcia z bazy bez żadnej ścieżki.

    Typowe błędy

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

  2. Krok 2: XAMPP i pusta baza dane4

    ok. 2 min
    Polecenie z arkusza

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

    W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa dane4 (z cyfrą na końcu), Utwórz. Porównywanie napisów możesz zostawić domyślne - tabele z pliku i tak przyniosą własne kodowanie (latin1).

    Typowe błędy

    Baza dane (bez cyfry) to strata R.1.1 i R.5.1 - skrypt łączy się z bazą po nazwie, a klucz sprawdza nazwę dane4.

  3. Krok 3: Import pliku dane.sql i zrzut egzamin.jpg

    Kryteria:

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

    ok. 3 min
    Polecenie z arkusza

    Do bazy dane4 zaimportuj plik dane.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie JPEG i nazwij egzamin. 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ę dane4, karta Import, Wybierz plik → dane.sql, Wykonaj. Plik tworzy pięć tabel: hobby (16 rekordów), osoby (40 rekordów) oraz puste producenci, produkty i rodzaje - do zadania potrzebne są tylko dwie pierwsze.

    „Elementy wskazujące na poprawnie wykonany import” to zielony komunikat o sukcesie i lista tabel w lewym panelu albo na karcie Struktura bazy. Zrzut całego ekranu z paskiem zadań zapisujesz jako egzamin.jpg - w tym arkuszu w formacie JPEG, a zrzuty zapytań w PNG.

    Typowe błędy

    Ten zrzut ma nazwę egzamin i format JPEG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: pierwsze 30 osób

    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, rok_urodzenia, zdjecie z tabeli osoby . Kwerenda wybiera początkowe 30 wierszy, jawnie wskazana liczba wierszy. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie 30 rekordów jedynie pola id, imie, nazwisko, rok_urodzenia, zdjecie

    ok. 3 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie dane4. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz. 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, rok_urodzenia, zdjecie z tabeli osoby. Kwerenda wybiera pierwsze 30 wierszy, należy jawnie wskazać liczbę wierszy

    Zaznacz bazę dane4, karta SQL:

    • SELECT id, imie, nazwisko, rok_urodzenia, zdjecie - pięć kolumn z arkusza („jedynie” wyklucza SELECT *, które dołożyłoby Hobby_id i opis),
    • FROM osoby,
    • LIMIT 30 - jawnie wskazana liczba wierszy. Tabela ma 40 osób, a phpMyAdmin sam pokazuje 25 wierszy na stronę - dlatego limit musi stać w zapytaniu.

    Wynik: 30 rekordów, od id 2 (Monika Kowalska) do id 31 (Grzegorz Roh). Zapytanie kopiujesz do pliku kwerendy.txt, a cały ekran zapisujesz jako kw1.png - przy 30 wierszach przewiń wynik tak, żeby było widać komunikat „Pokazano wiersze 0 - 29 (30 łącznie)”. To zapytanie wyśle skrypt w bloku lewym.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: dane osoby o id 10 z nazwą hobby

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola imie, nazwisko, rok_urodzenia, opis, zdjecie z tabeli osoby oraz odpowiadające im pole nazwa z tabeli hobby dla osoby o id równym 10. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = 10; możliwe INNER JOIN lub bez JOIN (porównanie kluczy w where) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest dokładnie jeden rekord: Roksana Rybnik 1995 pozdrawiam osoba3.jpg biegi

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola imie, nazwisko, rok_urodzenia, opis, zdjecie z tabeli osoby oraz odpowiadające im pole nazwa z tabeli hobby dla osoby o id równym 10

    • SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa - pięć kolumn z osoby i nazwa hobby z hobby,
    • FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id - złączenie: do osoby dołączany jest wiersz hobby o numerze z jej kolumny Hobby_id,
    • WHERE osoby.id = 10 - kolumna id jest w obu tabelach, więc trzeba wskazać tabelę.

    Wynik: jeden rekord - Roksana Rybnik, 1995, pozdrawiam, osoba3.jpg, biegi, dokładnie jak w kluczu. Zrzut: kw2.png. To zapytanie wyśle skrypt w bloku prawym, z identyfikatorem z formularza w miejscu liczby 10.

    Typowe błędy

    Samo WHERE id = 10 przy złączeniu kończy się błędem #1052 („Column 'id' in where clause is ambiguous”).

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;
    
    -- Zapytanie 2
    SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = 10;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: średni, najniższy i najwyższy rok urodzenia

    Kryteria:

    R.1.5 Utworzono zapytanie 3 liczące średni rok urodzenia oraz najniższy i najwyższy rok urodzenia z tabeli osoby . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT AVG(rok_urodzenia), MIN(rok_urodzenia), MAX(rok_urodzenia) FROM osoby; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie dane: 1992.7 1967 2009 (pierwsza wartość z dowolnym zaokrągleniem)

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: liczące średni rok urodzenia oraz najniższy i najwyższy rok urodzenia z tabeli osoby

    Trzy funkcje agregujące w jednym SELECT: AVG(rok_urodzenia) - średnia, MIN(…) - najmniejsza wartość, MAX(…) - największa. Funkcja agregująca zamienia całą tabelę w jeden wiersz wyniku.

    Wynik: 1992.7000, 1967, 2009 - zgodnie z kluczem (1992,7 w dowolnym zaokrągleniu, najstarsza osoba urodziła się w 1967, najmłodsza w 2009). Zrzut: kw3.png.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;
    
    -- Zapytanie 2
    SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = 10;
    
    -- Zapytanie 3
    SELECT AVG(rok_urodzenia), MIN(rok_urodzenia), MAX(rok_urodzenia) FROM osoby;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowy opis dla osób z hobby 4

    Kryteria:

    R.1.6 Utworzono zapytanie 4 aktualizujące pole opis z tabeli osoby dla osób, których pole Hobby_id jest równe 4. Wartość pola opis dowolna. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE osoby SET opis="..." WHERE Hobby_id = 4; (dowolny wpis w miejscu kropek) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnie wykonanym zapytaniu lub tabela ze zmienionymi danymi

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: aktualizujące pole opis z tabeli osoby dla osób, których pole Hobby_id jest równe 4. Wartość nowego wpisu w polu opis jest dowolna będąca możliwym hobby

    • UPDATE osoby - zmiana istniejących rekordów,
    • SET opis = 'akrobatyka' - nowa wartość pola; arkusz pozwala wpisać dowolne hobby,
    • WHERE Hobby_id = 4 - tylko osoby z hobby numer 4 (gimnastyka).

    W bazie jest jedna taka osoba - Anna Kowalska z id 25 - więc phpMyAdmin melduje 1 wiersz zmieniony. Zrzut: kw4.png (komunikat albo tabela ze zmienionym opisem). Plik kwerendy.txt ma komplet czterech zapytań.

    Typowe błędy

    UPDATE bez WHERE zmienia opis wszystkim 40 osobom - phpMyAdmin nie pyta o potwierdzenie, a cofnąć to można tylko ponownym importem.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;
    
    -- Zapytanie 2
    SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = 10;
    
    -- Zapytanie 3
    SELECT AVG(rok_urodzenia), MIN(rok_urodzenia), MAX(rok_urodzenia) FROM osoby;
    
    -- Zapytanie 4
    UPDATE osoby SET opis = 'akrobatyka' WHERE Hobby_id = 4;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Grafika: kadr 1:1 z twarzą

    ok. 2 min
    Polecenie z arkusza

    Plik osoba1.jpg, wypakowany z archiwum, skadrowany do proporcji 1:1, tak aby była widoczna twarz osoby.

    osoba1.jpg z archiwum ma 300 × 200 px - jest poziomy, a pozostałe zdjęcia są kwadratowe. W GIMP-ie narzędzie Zaznaczenie prostokątne z opcją Stała: proporcje 1:1, zaznaczenie 200 × 200 px (cała wysokość zdjęcia) przesunięte tak, żeby twarz była w środku - tutaj od x = 35 px - i Obraz → Przytnij do zaznaczenia. Podgląd pokazuje kadr przed skalowaniem.

    Typowe błędy

    Kadr z lewej krawędzi zdjęcia (x = 0) ucina twarz z prawej strony - klucz wymaga, żeby twarz była widoczna (R.2.1).

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Grafika: rozmiar dokładnie 100 × 100 px

    Kryteria:

    R.2.1 Plik osoba1.jpg zawiera widoczną twarz osoby, rozmiar zdjęcia dokładnie 100 px na 100 px

    ok. 2 min
    Polecenie z arkusza

    Przeskalowany do rozmiaru dokładnie 100 px na 100 px. Pozostałe pliki graficzne są przygotowane i nie należy ich zmieniać

    Obraz → Skaluj obraz: szerokość 100, wysokość 100 - kadr jest kwadratowy, więc proporcje się nie zmieniają. Zapis pod tą samą nazwą: Plik → Nadpisz osoba1.jpg (zwykłe Zapisz w GIMP-ie zapisuje format .xcf). Zdjęcia osoba2.jpg - osoba8.jpg mają już 100 × 100 px i zostają bez zmian.

    Typowe błędy

    Skalowanie całego zdjęcia 300 × 200 do 100 × 100 bez kadrowania spłaszczy twarz.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Plik settings.html

    ok. 1 min
    Polecenie z arkusza

    Odsyłacz o treści „Inne ustawienia” prowadzący do strony settings.html (należy utworzyć plik settings.html i zapisać w nim treść: „strona w trakcie budowy”)

    Najpierw cel odsyłacza: w edytorze tworzysz plik settings.html z jednym zdaniem: strona w trakcie budowy. Arkusz każe zapisać w nim tylko tę treść, więc bez szkieletu HTML - przeglądarka i tak wyświetli tekst. Sam odsyłacz powstanie w bloku lewym.

    settings.html HTML nowy plik
    strona w trakcie budowy
    Podgląd strony po tym kroku (settings.html)
  11. Krok 11: Plik users.php i kodowanie polskich znaków

    Kryteria: ,

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

    R.2.3 Zastosowano właściwy standard kodowania polskich znaków dla witryny

    ok. 2 min
    Polecenie z arkusza

    Składa się ze strony o nazwie users.php. Zastosowany właściwy standard kodowania polskich znaków

    Plik users.php w folderze zdającego, obok zdjęć - rozszerzenie .php, bo na jego górze stanie skrypt. Szkielet HTML5 z lang="pl" i od razu <meta charset="UTF-8"> jako pierwszy element <head>; sam plik zapisujesz w UTF-8 (R.2.2, R.2.3).

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

    Kryteria: ,

    R.2.4 Nadano tytuł strony: "Panel administratora”

    R.3.5 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 źle przypisano co najmniej jednen selektor do bloku (np. kropka zamiast #)

    ok. 2 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Panel administratora”. Arkusz stylów w pliku o nazwie styl4.css prawidłowo połączony z kodem strony

    <title> z napisem na karcie przeglądarki (R.2.4) i <link> do pliku styl4.css - z cyfrą w nazwie (R.3.5). Linia viewport to dodatek spoza arkusza: telefon pokazuje stronę w swojej szerokości, zamiast pomniejszać widok komputera.

    users.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  13. Krok 13: Bloki i nagłówek banera

    Kryteria:

    R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, lewy i prawy, stopka. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: baner, lewy i prawy, stopka. 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. Zawartość banera: nagłówek trzeciego stopnia o treści „Portal Społecznościowy - panel administratora”

    Znaczniki semantyczne w kolejności z obrazu 2: <header> z nagłówkiem <h3> (w tym arkuszu trzeciego stopnia), dwa bloki <section> z identyfikatorami left i right (po angielsku - arkusz ich nie narzuca) i <footer> (R.2.5).

    users.php PHP zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  14. Krok 14: Blok lewy: nagłówek i odsyłacz „Inne ustawienia”

    Kryteria:

    R.3.2 Na stronie umieszczono odnośnik "Inne ustawienia", po jego wybraniu otwiera się strona settings.html

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek czwartego stopnia o treści „Użytkownicy”. Efekt działania skryptu 1. Odsyłacz o treści „Inne ustawienia” prowadzący do strony settings.html

    <h4> i odsyłacz do pliku settings.html z kroku wyżej (R.3.2). Lista użytkowników stanie między nimi - wypisze ją szablon w części PHP.

    users.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  15. Krok 15: Blok prawy: nagłówek, formularz i linia pozioma

    Kryteria: , , ,

    R.2.6 W bloku banera zapisano nagłówek h3: "Portal Społecznościowy - panel administratora" oraz w bloku lewym nagłówek h4: "Użytkownicy" i w bloku prawym nagłówek h4: "Podaj id użytkownika"

    R.2.7 W bloku prawym umieszczono formularz z polem edycyjnym i przyciskiem, zastosowano zancznik <form> oraz jego zamknięcie

    R.3.3 Formularz wysyła dane do tego samego pliku metodą POST

    R.3.4 Pole edycyjne formularza jest typu number, przycisk ZOBACZ wysyła dane z formularza (np. typ submit dla input lub button albo button bez typu)

    ok. 4 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek czwartego stopnia o treści „Podaj id użytkownika”. Formularz wysyłający dane metodą post do tego samego pliku i zawierający: pole edycyjne typu numerycznego, przycisk wysyłający dane o treści "ZOBACZ”. Linia pozioma

    • <h4> - komplet nagłówków strony: <h3> w banerze i dwa <h4> (R.2.6),
    • <form method="post"> bez action wysyła dane do tego samego pliku (R.3.3),
    • <label for="id"> podpisuje pole - kliknięcie napisu ustawia kursor w polu, a czytnik ekranu odczyta, czego pole dotyczy. Atrybut for musi równać się id pola,
    • <input type="number"> z name="id" - pod tą nazwą wartość trafi do PHP, a min="1" nie pozwoli przeglądarce wysłać zera ani liczby ujemnej,
    • <button type="submit">ZOBACZ</button> wysyła formularz (R.2.7, R.3.4),
    • <hr> - pod nim stanie karta osoby.
    Typowe błędy

    min="1" pilnuje wartości tylko w przeglądarce - skrypt i tak musi sprawdzić identyfikator sam (krok w części PHP).

    users.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  16. Krok 16: Stopka z autorem strony

    Kryteria:

    R.2.8 W stopce umieszczono napis „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: napis o treści „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz

    Na egzaminie po dwukropku wpisujesz swój numer PESEL - tu w jego miejscu stoi Bartosz Bryniarski (R.2.8).

    users.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  17. Etap 3: Styl CSS

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

    Krok 17: Plik styl4.css: kolory jako zmienne i krój Helvetica

    Kryteria:

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

    ok. 2 min
    Polecenie z arkusza

    Cechy formatowania CSS: Domyślne dla całej strony: krój czcionki Helvetica

    Na górze pliku zmienne CSS w :root - dwa kolory z arkusza, każdy wpisany raz, reguły sięgają po nie przez var(--dark-red). Potem selektor * z krojem Helvetica - obejmuje też pole i przycisk formularza (R.4.1).

    styl4.css CSS nowy plik
    :root {
        --dark-red: #AF4448;
        --pink: #FFA4A2;
    }
    * {
        font-family: Helvetica;
    }
    Podgląd strony po tym kroku (users.php)
  18. Krok 18: Baner i stopka: tło, kolor, wyśrodkowanie, wysokość

    Kryteria: ,

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

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera i stopki

    ok. 2 min
    Polecenie z arkusza

    Dla banera i stopki: kolor tła #AF4448, biały kolor czcionki, wyrównanie tekstu do środka, wysokość 20 px

    Jedna reguła dla obu bloków (R.4.3, R.4.6). Druga reguła - margin: 0 dla <h3> w banerze - to dodatek wynikający z flexboksa z następnych kroków: element flexboksa trzyma marginesy nagłówka w sobie, więc bez zera napis zsunąłby się w pasku 20 px i wystawał na bloki poniżej. line-height: 20px wyrównuje wysokość linii nagłówka do wysokości paska - domyślna linia <h3> ma 22 px i wystawałaby o 2 px.

    styl4.css CSS zmienione: 10 linii
    :root {
        --dark-red: #AF4448;
        --pink: #FFA4A2;
    }
    * {
        font-family: Helvetica;
    }
    header, footer {
        background-color: var(--dark-red);
        color: white;
        text-align: center;
        height: 20px;
    }
    header h3 {
        margin: 0;
        line-height: 20px;
    }
    Podgląd strony po tym kroku (users.php)
  19. Krok 19: Blok lewy i prawy: tło, wysokość, szerokość

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła #AF4448 dla banera i stopki oraz #FFA4A2 dla bloku lewego i prawego

    R.4.4 Ustawiono wysokość bloków: baner i stopka 20px, lewy i prawy 650px

    R.4.5 Ustawiono szerokość bloków prawego i lewego 50%

    ok. 2 min
    Polecenie z arkusza

    Dla bloku lewego i prawego: kolor tła #FFA4A2, wysokość 650 px, szerokość 50%

    Selektory identyfikatorów #left i #right (R.4.2, R.4.4, R.4.5). Szerokość zostaje na blokach - tak ocenia ją klucz tej sesji.

    styl4.css CSS zmienione: 5 linii
    :root {
        --dark-red: #AF4448;
        --pink: #FFA4A2;
    }
    * {
        font-family: Helvetica;
    }
    header, footer {
        background-color: var(--dark-red);
        color: white;
        text-align: center;
        height: 20px;
    }
    header h3 {
        margin: 0;
        line-height: 20px;
    }
    #left, #right {
        background-color: var(--pink);
        height: 650px;
        width: 50%;
    }
    Podgląd strony po tym kroku (users.php)
  20. Krok 20: Układ bloków: flexbox z zawijaniem

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym

    ok. 2 min
    Polecenie z arkusza

    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

    body jako flexbox z zawijaniem: baner i stopka z flex: 1 1 100% zajmują każdy cały rząd, a bloki lewy i prawy po 50% mieszczą się razem w rzędzie pomiędzy nimi - jak na obrazie 2 (R.3.1). Nie ma float, więc stopka nie potrzebuje clear.

    styl4.css CSS zmienione: 7 linii
    :root {
        --dark-red: #AF4448;
        --pink: #FFA4A2;
    }
    * {
        font-family: Helvetica;
    }
    header, footer {
        background-color: var(--dark-red);
        color: white;
        text-align: center;
        height: 20px;
    }
    header h3 {
        margin: 0;
        line-height: 20px;
    }
    #left, #right {
        background-color: var(--pink);
        height: 650px;
        width: 50%;
    }
    body {
        display: flex;
        flex-wrap: wrap;
    }
    header, footer {
        flex: 1 1 100%;
    }
    Podgląd strony po tym kroku (users.php)
  21. Krok 21: Nagłówki czwartego stopnia i przycisk

    Kryteria: ,

    R.4.7 Ustawiono marginesy zewnętrzne (margin) dla selektora h4 na 0px (0 poprawnie też bez jednostki)

    R.4.8 Ustawiono styl przycisku wysyłającego dane z formularza: kolor tła #AF4448, biały kolor czcionki, marginesy wewnętrzne (padding) 5px oraz zewnętrzne (margin) 10px

    ok. 2 min
    Polecenie z arkusza

    Dla selektora nagłówka czwartego stopnia: marginesy zewnętrzne 0 px. Dla przycisku wysyłającego dane z formularza: kolor tła #AF4448, biały kolor czcionki, marginesy wewnętrzne 5 px, marginesy zewnętrzne 10 px

    h4 bez marginesów zewnętrznych (R.4.7) i przycisk w kolorze banera z marginesami z arkusza (R.4.8). Arkusz stylów jest kompletny.

    styl4.css CSS zmienione: 9 linii
    :root {
        --dark-red: #AF4448;
        --pink: #FFA4A2;
    }
    * {
        font-family: Helvetica;
    }
    header, footer {
        background-color: var(--dark-red);
        color: white;
        text-align: center;
        height: 20px;
    }
    header h3 {
        margin: 0;
        line-height: 20px;
    }
    #left, #right {
        background-color: var(--pink);
        height: 650px;
        width: 50%;
    }
    body {
        display: flex;
        flex-wrap: wrap;
    }
    header, footer {
        flex: 1 1 100%;
    }
    h4 {
        margin: 0;
    }
    button {
        background-color: var(--dark-red);
        color: white;
        padding: 5px;
        margin: 10px;
    }
    Podgląd strony po tym kroku (users.php)
  22. Etap 4: Skrypt PHP

    Kroki 22-28 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 22: Plik config.php i połączenie PDO na górze strony

    Kryteria:

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

    ok. 4 min
    Polecenie z arkusza

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

    Dane połączenia trafiają do osobnego pliku config.php jako stałe: adres w formacie PDO (mysql:host=localhost;dbname=dane4;charset=utf8mb4 - serwer, baza dane4 i kodowanie), użytkownik root i puste hasło. Strona dołącza go instrukcją require.

    Oba „skrypty” z arkusza korzystają z jednej bazy, więc w wersji nowoczesnej całe PHP stoi na górze users.php, przed <!DOCTYPE html>: najpierw pobiera dane, potem HTML je wyświetla w miejscach z obrazu 2. new PDO(…) łączy się z serwerem i wybiera bazę (R.5.1); z opcją ERRMODE_EXCEPTION każdy błąd bazy jest wyjątkiem, który łapie blok catch.

    Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2 - na razie bez zmian.

    config.php PHP nowy plik
    <?php
    // dane połączenia z bazą - w jednym miejscu, poza plikiem strony
    const DB_DSN = 'mysql:host=localhost;dbname=dane4;charset=utf8mb4';
    const DB_USER = 'root';
    const DB_PASSWORD = '';
    users.php PHP zmienione: 11 linii
    <?php
    require 'config.php';
    
    $users = [];
    $error = '';
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  23. Krok 23: Skrypt 1: zapytanie 1 i lista użytkowników z szablonu

    Kryteria: , ,

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

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 1 lub skrypt 2 wysyła zapytanie 2 zmodyfikowane w ten sposób, że w warunku jest przypisane id podane w formularzu

    R.5.5 Skrypt 1 Wyświetla każdy zwrócony zapytaniem wiersz w osobnej linii o treści: "<id>. <imie> <nazwisko>" gdzie pola <id>, <imie>, <nazwisko> zostały pobrane z bazy (wiek nie jest sprawdzany w tym kryterium)

    ok. 4 min
    Polecenie z arkusza

    Działanie skryptu 1 w panelu lewym: Wysyła do bazy danych zapytanie 1. Dla każdego wiersza zwróconego zapytaniem: Wyświetla w osobnej linii treść: <id>. <imie> <nazwisko>, < wiek> lat, gdzie pola <id>, <imie>, <nazwisko> zostały pobrane z bazy, a <wiek> oznacza obliczony wiek osoby

    • $pdo->query('…')->fetchAll(PDO::FETCH_ASSOC) wysyła zapytanie 1 z kwerendy.txt (R.5.3) i od razu odczytuje 30 wierszy do tablicy $users - z kluczami z nazw kolumn: id, imie, nazwisko, rok_urodzenia, zdjecie,
    • PDO nie ma funkcji close - połączenie zamyka $pdo = null w bloku finally, który wykona się zawsze (R.5.2),
    • funkcja e() to krótsza nazwa dla htmlspecialchars,
    • w bloku lewym szablon: <?php foreach ($users as $row): ?> … <?php endforeach; ?> i jedna linia HTML na osobę - <?= … ?> wstawia wartość, <br> kończy linię (R.5.5).

    Podgląd: 30 linii, od „2. Monika Kowalska” do „31. Grzegorz Roh”.

    users.php PHP zmienione: 11 linii
    <?php
    require 'config.php';
    
    $users = [];
    $error = '';
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?><br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  24. Krok 24: Skrypt 1: wiek z roku urodzenia

    Kryteria:

    R.5.4 Skrypt 1 oblicza wiek osoby na podstawie jej roku urodzenia, np. z wykorzystaniem funkcji date('Y') lub wykorzystując rok 2019 lub 2021

    ok. 2 min
    Polecenie z arkusza

    Oblicza wiek osoby na podstawie jej roku urodzenia

    Bieżący rok jest odczytany raz, na górze pliku: (int) date('Y'). W szablonie od niego odejmowany jest rok urodzenia - zamieniony na liczbę rzutowaniem (int), bo PHP 7.4 z XAMPP wskazanego w kluczu zwraca liczby z bazy jako tekst (PHP 8.1 i nowsze - już jako liczby; rzutowanie działa w obu przypadkach) (R.5.4). Wynik jest liczbą obliczoną przez skrypt, więc nie potrzebuje e().

    Podgląd liczy od roku 2026: Monika Kowalska z rocznika 1976 ma 50 lat (obraz 2 w arkuszu powstał w 2019 roku).

    users.php PHP zmienione: 2 linie
    <?php
    require 'config.php';
    
    $users = [];
    $currentYear = (int) date('Y');
    $error = '';
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?>, <?= $currentYear - (int) $row['rok_urodzenia'] ?> lat<br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  25. Krok 25: Skrypt 2: identyfikator, zapytanie przygotowane i nagłówek

    Kryteria:

    R.5.6 Skrypt 2 wyświetla nagłówek h2 o treści <id>. <imie> <nazwisko>, gdzie pole <id> jest identyfikatorem pobranym z formularza, a pola <imie>, <nazwisko> są polami pobranymi z bazy

    ok. 5 min
    Polecenie z arkusza

    Działanie skryptu 2 w panelu prawym wykonywanego po wypełnieniu formularza: Wysyła do bazy danych zapytanie 2, zmodyfikowane w ten sposób, że w warunku zamiast przypisanego numeru id równego 10, jest numer id przesłany z formularza. Wyświetla nagłówek drugiego stopnia o treści <id>. <imie> <nazwisko>, gdzie pole <id> jest identyfikatorem pobranym z formularza, a pola <imie>, <nazwisko> są polami pobranymi z bazy

    • filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, …) odczytuje pole id z formularza i zwraca liczbę całkowitą od 1 w górę - albo false, gdy przyszło coś innego, i null, gdy formularz nie był wysłany. Do zapytania trafia tylko prawdziwa liczba,
    • zapytanie 2 jako zapytanie przygotowane: w miejscu liczby 10 stoi parametr :id, a execute(['id' => $id]) przekazuje wartość osobno - baza nigdy nie potraktuje jej jak fragmentu SQL,
    • fetch() odczytuje jedyny wiersz; przy braku osoby zwraca false, które ?: null zamienia w null,
    • połączenie zamyka finally - także obiekt zapytania ($statement = null).

    W bloku prawym, pod linią: <?php if ($user): ?> - karta pokaże się tylko wtedy, gdy osoba została znaleziona - i nagłówek <h2> z identyfikatorem z formularza oraz imieniem i nazwiskiem z bazy (R.5.6). Podgląd: formularz wysłany z wartością 10, jak na obrazie 2.

    users.php PHP zmienione: 11 linii
    <?php
    require 'config.php';
    
    $users = [];
    $currentYear = (int) date('Y');
    $error = '';
    $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
    $user = null;
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
        if ($id) {
            $statement = $pdo->prepare('SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = :id');
            $statement->execute(['id' => $id]);
            $user = $statement->fetch(PDO::FETCH_ASSOC) ?: null;
        }
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $statement = null;
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?>, <?= $currentYear - (int) $row['rok_urodzenia'] ?> lat<br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
            <?php if ($user): ?>
            <h2><?= $id ?>. <?= e($user['imie']) ?> <?= e($user['nazwisko']) ?></h2>
            <?php endif; ?>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  26. Krok 26: Skrypt 2: zdjęcie z bazy, tekst alternatywny z formularza

    Kryteria:

    R.5.7 Skrypt 2 wyświetla zdjęcie tak, że źródłem jest plik o nazwie pobranej z bazy a tekstem alternatywnym jest identyfikator pobrany z formularza

    ok. 1 min
    Polecenie z arkusza

    Wyświetla zdjęcie tak, że źródłem jest plik o nazwie pobranej z bazy a tekstem alternatywnym jest identyfikator pobrany z formularza

    <img> z nazwą pliku z bazy (przez e()) i identyfikatorem w alt - po filter_input to liczba całkowita, więc e() nie jest potrzebne (R.5.7).

    users.php PHP zmienione: 1 linia
    <?php
    require 'config.php';
    
    $users = [];
    $currentYear = (int) date('Y');
    $error = '';
    $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
    $user = null;
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
        if ($id) {
            $statement = $pdo->prepare('SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = :id');
            $statement->execute(['id' => $id]);
            $user = $statement->fetch(PDO::FETCH_ASSOC) ?: null;
        }
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $statement = null;
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?>, <?= $currentYear - (int) $row['rok_urodzenia'] ?> lat<br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
            <?php if ($user): ?>
            <h2><?= $id ?>. <?= e($user['imie']) ?> <?= e($user['nazwisko']) ?></h2>
            <img src="<?= e($user['zdjecie']) ?>" alt="<?= $id ?>">
            <?php endif; ?>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  27. Krok 27: Skrypt 2: rok urodzenia, opis i hobby

    Kryteria:

    R.5.8 Skrypt 2 wyświetla trzy paragrafy (akapity) z rokiem urodzenia, opisem i hobby, wartości zostały pobrane z bazy

    ok. 2 min
    Polecenie z arkusza

    Wyświetla trzy paragrafy (akapity) o treści, kolejno: Rok urodzenia: <rok_urodzenia>, gdzie pole <rok_urodzenia> jest pobrane zapytaniem; Opis: <opis>, gdzie pole <opis> jest pobrane zapytaniem; Hobby: <nazwa>, gdzie pole <nazwa> jest pobrane zapytaniem

    Trzy <p> z wartościami z wiersza $user, każda przez e() - opis to wpis użytkownika portalu i może zawierać znaczniki (R.5.8). Strona spełnia wszystkie kryteria arkusza.

    users.php PHP zmienione: 3 linie
    <?php
    require 'config.php';
    
    $users = [];
    $currentYear = (int) date('Y');
    $error = '';
    $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
    $user = null;
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
        if ($id) {
            $statement = $pdo->prepare('SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = :id');
            $statement->execute(['id' => $id]);
            $user = $statement->fetch(PDO::FETCH_ASSOC) ?: null;
        }
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $statement = null;
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?>, <?= $currentYear - (int) $row['rok_urodzenia'] ?> lat<br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
            <?php if ($user): ?>
            <h2><?= $id ?>. <?= e($user['imie']) ?> <?= e($user['nazwisko']) ?></h2>
            <img src="<?= e($user['zdjecie']) ?>" alt="<?= $id ?>">
            <p>Rok urodzenia: <?= e($user['rok_urodzenia']) ?></p>
            <p>Opis: <?= e($user['opis']) ?></p>
            <p>Hobby: <?= e($user['nazwa']) ?></p>
            <?php endif; ?>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  28. Krok 28: Komunikaty: brak osoby, zły identyfikator, baza niedostępna

    ok. 3 min

    Dodatek spoza arkusza - klucz go nie ocenia. Nad kartą osoby stoi łańcuch warunków if / elseif:

    • baza nie odpowiada - komunikat ze zmiennej $error (sprawdzone ze złym hasłem w config.php: reszta strony działa, treść błędu z bazy nie trafia na ekran),
    • formularz wysłany, ale filter_input odrzucił wartość - prośba o liczbę. Sprawdzone: wartość 0 OR osoby.id = 2, która w wersji podstawowej wstrzykiwała SQL, kończy się tym komunikatem,
    • poprawny identyfikator, którego nie ma w bazie - „Nie ma użytkownika o identyfikatorze 99.” zamiast pustej karty.

    Pole formularza dostaje value z wysłanym identyfikatorem - po kliknięciu „ZOBACZ” numer zostaje w polu i można go zmienić strzałką o jeden. Podgląd: wysłany identyfikator 99.

    users.php PHP zmienione: 8 linii
    <?php
    require 'config.php';
    
    $users = [];
    $currentYear = (int) date('Y');
    $error = '';
    $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
    $user = null;
    try {
        $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $users = $pdo->query('SELECT id, imie, nazwisko, rok_urodzenia, zdjecie FROM osoby LIMIT 30;')->fetchAll(PDO::FETCH_ASSOC);
        if ($id) {
            $statement = $pdo->prepare('SELECT imie, nazwisko, rok_urodzenia, opis, zdjecie, nazwa FROM osoby JOIN hobby ON osoby.Hobby_id = hobby.id WHERE osoby.id = :id');
            $statement->execute(['id' => $id]);
            $user = $statement->fetch(PDO::FETCH_ASSOC) ?: null;
        }
    } catch (PDOException $exception) {
        $error = 'nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę';
    } finally {
        $statement = null;
        $pdo = null;
    }
    
    function e(?string $text): string
    {
        return htmlspecialchars($text ?? '', ENT_QUOTES, 'UTF-8');
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Panel administratora</title>
        <link rel="stylesheet" href="styl4.css">
    </head>
    <body>
        <header>
            <h3>Portal Społecznościowy - panel administratora</h3>
        </header>
        <section id="left">
            <h4>Użytkownicy</h4>
            <?php foreach ($users as $row): ?>
            <?= e($row['id']) ?>. <?= e($row['imie']) ?> <?= e($row['nazwisko']) ?>, <?= $currentYear - (int) $row['rok_urodzenia'] ?> lat<br>
            <?php endforeach; ?>
            <a href="settings.html">Inne ustawienia</a>
        </section>
        <section id="right">
            <h4>Podaj id użytkownika</h4>
            <form method="post">
                <label for="id">id</label>
                <input type="number" id="id" name="id" min="1" value="<?= $id ?: '' ?>">
                <button type="submit">ZOBACZ</button>
            </form>
            <hr>
            <?php if ($error !== ''): ?>
            <p><?= e($error) ?></p>
            <?php elseif (isset($_POST['id']) && !$id): ?>
            <p>Podaj identyfikator - liczbę całkowitą większą od zera.</p>
            <?php elseif ($id && !$user): ?>
            <p>Nie ma użytkownika o identyfikatorze <?= $id ?>.</p>
            <?php endif; ?>
            <?php if ($user): ?>
            <h2><?= $id ?>. <?= e($user['imie']) ?> <?= e($user['nazwisko']) ?></h2>
            <img src="<?= e($user['zdjecie']) ?>" alt="<?= $id ?>">
            <p>Rok urodzenia: <?= e($user['rok_urodzenia']) ?></p>
            <p>Opis: <?= e($user['opis']) ?></p>
            <p>Hobby: <?= e($user['nazwa']) ?></p>
            <?php endif; ?>
        </section>
        <footer>
            Stronę wykonał: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (users.php)
  29. Etap 5: Porównanie z wersją podstawową

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

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

    ok. 3 min

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

    wersja podstawowawersja nowoczesna
    układfloat: left bloków, clear stopkibody jako flexbox z zawijaniem
    kolorywpisane w każdej regulezmienne --dark-red, --pink
    formularzsamo pole i przycisklabel for, min="1", wysłany numer zostaje w polu
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami, dane połączenia w config.php
    gdzie jest skryptdwa bloki PHP w miejscach z obrazu 2, HTML w echojeden blok na górze pliku, w blokach strony szablon
    identyfikator z formularzawklejony w treść zapytaniafilter_input + zapytanie przygotowane z :id
    brak osoby o tym idostrzeżenia PHPkomunikat
    wypisywanie danychwprost (w etapie „Dobre praktyki” - htmlspecialchars)każda wartość przez e()
    zamknięcie bazymysqli_close na końcu drugiego skryptu$pdo = null w finally, przed HTML-em

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 arkusza i łatwiej ją napisać bez dokumentacji. Wersja nowoczesna nie przepuszcza wstrzyknięcia SQL, nie wywraca się na pustym polu ani na nieistniejącym identyfikatorze - a klucz przyjmuje obie.

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

  30. Etap 6: Oddanie pracy

    Krok 30 · po tym etapie masz 35 z 35 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    UWAGA: po zakończeniu pracy utwórz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś 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: egzamin.jpg, kw1.png - kw4.png, kwerendy.txt, users.php, config.php (bez niego strona nie połączy się z bazą), settings.html, styl4.css, osoba1.jpg - osoba8.jpg i przeglądarka.txt. 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 28.

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