Przejdź do głównej treści
INF.03-01-24.06-SGCzerwiec 2024 · 38 kroków · ok. 68 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Witryna o motocyklach (Wersja podstawowa)

Rozwiązanie buduje stronę o wycieczkach motocyklowych: baza motory z dwiema tabelami w relacji 1..n i cztery zapytania (OR, złączenie tabel, COUNT, a na koniec ALTER TABLE zmieniające strukturę tabeli), zdjęcie przeskalowane do 640 px, strona motor.php z banerem, blokiem lewym i dwoma prawymi oraz style w styl.css z półprzezroczystymi tłami rgba, cieniami bloków i obrazem motocykla pozycjonowanym absolutnie pod blokami - tak, że prześwituje przez wszystkie. Dwa skrypty PHP: lista definicji z wycieczkami (termin z odnośnikiem do zdjęcia, którego nazwę skrypt uzupełnia o .jpg, i opis jako definicja) oraz licznik wycieczek z COUNT.

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ą. Kod PHP jest najpierw pisany funkcjami z tabeli 1 arkusza (proceduralne mysqli), a na końcu dochodzi escapowanie danych i odczyt wierszy po nazwach kolumn.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: bloki na siatce CSS (grid-template-areas), kolory w zmiennych i PHP na PDO z danymi pobranymi przed HTML-em - obie wersje są zgodne z kluczem.

Baza i grafiki pochodzą z prawdziwego archiwum pliki1 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu.

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 - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Baza danych

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

    Krok 1: Baza danych motory

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych motory czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie motory, z zestawem polskich znaków (np. utf8_unicode_ci).

    Rozpakuj pliki1.zip z pulpitu (hasło ^moTocyKle^) do folderu z numerem zdającego - arkusz każe umieścić rozpakowane pliki właśnie tam. W phpMyAdmin: Nowa, nazwa motory, porównywanie utf8_unicode_ci.

    Typowe błędy

    Nazwa bazy to motory, nie motocykle - skrypty łączą się z bazą po nazwie (R.5.1).

  2. Krok 2: Import tabel z pliku baza.sql

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych motory czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Do bazy zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum.

    Przy zaznaczonej bazie motory: Import → baza.sql → Wykonaj. Dwie tabele w relacji 1..n (obraz 1): zdjecia (5 zdjęć: zrodlo - nazwa pliku bez rozszerzenia, np. droga1, i alt) oraz wycieczki (10 tras: nazwa, opis, poczatek, koniec i klucz obcy zdjecia_id). Jedno zdjęcie może ilustrować kilka wycieczek - stąd „jeden do wielu”.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych motory czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG 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.

    Print Screen, zapis jako import.png. Uwaga na formaty w tym arkuszu: import w PNG, zrzuty zapytań w JPEG - odwrotnie niż w wielu innych arkuszach.

    Typowe błędy

    import.jpg zamiast import.png to strata punktu R.1.1 - klucz podaje format wprost.

  4. Krok 4: Zapytanie 1: wycieczki z Muszyny i Wieliczki

    Kryteria: ,

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

    R.1.3 Wykonano zapytanie 1 wybierające jedynie nazwy wycieczek, których początek jest w Muszynie, Wieliczce. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM wycieczki WHERE poczatek="Muszyna" OR poczatek="Wieliczka"; oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie dwa rekordy: Dolina Popradu i Alter-Zakopianka

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie nazwy wycieczek, których początek jest w Muszynie, Wieliczce.

    Dwa miasta - dwa warunki połączone OR: wystarczy, że pasuje jeden. W bazie miasta są w mianowniku („Muszyna”, „Wieliczka”), choć arkusz odmienia je w zdaniu. Wynik: 2 wiersze - Dolina Popradu i Alter-Zakopianka, jak w kluczu. Zapytanie do kwerendy.txt, zrzut kw1.jpg.

    Typowe błędy

    AND zamiast OR szuka trasy zaczynającej się w dwóch miastach naraz - wynik pusty. Inna możliwość: WHERE poczatek IN ("Muszyna", "Wieliczka").

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT nazwa FROM wycieczki WHERE poczatek = "Muszyna" OR poczatek = "Wieliczka";
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: wycieczki ze źródłem zdjęcia

    Kryteria:

    R.1.4 Wykonano zapytanie 2 wybierające jedynie pola nazwa, opis i poczatek z tabeli wycieczki oraz odpowiadające im pole zrodlo z tabeli zdjecia . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id; (możliwe również INNER JOIN lub bez JOIN i porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym jest widocznych dokładnie 10 rekordów, jedynie pola nazwa, opis, poczatek, zrodlo

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola nazwa, opis i poczatek z tabeli wycieczki oraz odpowiadające im pole zrodlo z tabeli zdjecia. Należy posłużyć się relacją.

    FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id - każda wycieczka dostaje swoje zdjęcie przez klucz obcy. Kolumna id jest w obu tabelach, więc piszesz zdjecia.id. Wynik: wszystkie 10 wycieczek z czterema kolumnami. Zrzut: kw2.jpg. To zapytanie wyśle skrypt 1.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM wycieczki WHERE poczatek = "Muszyna" OR poczatek = "Wieliczka";
    
    -- Zapytanie 2
    SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: liczba wycieczek

    Kryteria:

    R.1.5 Wykonano zapytanie 3 zliczające liczbę wycieczek wpisanych do tabeli wycieczki . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT COUNT(*) FROM wycieczki; (lub dowolne pole zamiast *) oraz wynik działania udokumentowano zrzutem, na którym jest widoczna wartość 10

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 3: zliczające liczbę wycieczek wpisanych do tabeli wycieczki.

    COUNT(*) liczy wiersze tabeli. Wynik: jeden wiersz z liczbą 10. Zrzut: kw3.jpg. To zapytanie wyśle skrypt 2.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM wycieczki WHERE poczatek = "Muszyna" OR poczatek = "Wieliczka";
    
    -- Zapytanie 2
    SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;
    
    -- Zapytanie 3
    SELECT COUNT(*) FROM wycieczki;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowa kolumna ocena

    Kryteria:

    R.1.6 Wykonano zapytanie 4 modyfikujące strukturę tabeli wycieczki . Dodana jest kolumna ocena typu całkowitego. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE wycieczki ADD COLUMN ocena INT; (słowo COLUMN jest opcjonalne, dowolny typ całkowity) oraz wynik działania udokumentowano zrzutem, na którym jest widoczny komunikat o poprawnym wykonaniu zapytania lub struktura tabeli z dodanym polem ocena typu całkowitego

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: modyfikujące strukturę tabeli wycieczki, poprzez dodanie kolumny ocena typu całkowitego.

    Struktury tabeli nie zmienia UPDATE (ten zmienia dane), tylko ALTER TABLE: ALTER TABLE wycieczki ADD COLUMN ocena INT dopisuje na końcu tabeli kolumnę ocena typu całkowitego (słowo COLUMN można pominąć). Zapytanie nie zwraca wierszy - phpMyAdmin pokaże komunikat o wykonaniu. Na zrzucie kw4.jpg widać komunikat albo, jak obok, strukturę tabeli z nową kolumną (karta Struktura). Nowa kolumna nie przeszkadza skryptom - wybierają kolumny po nazwach. kwerendy.txt ma komplet.

    Typowe błędy

    Drugie wykonanie tego samego zapytania kończy się błędem „Duplicate column name ocena” - kolumna już istnieje. Na zrzut wystarczy jedno udane wykonanie.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT nazwa FROM wycieczki WHERE poczatek = "Muszyna" OR poczatek = "Wieliczka";
    
    -- Zapytanie 2
    SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;
    
    -- Zapytanie 3
    SELECT COUNT(*) FROM wycieczki;
    
    -- Zapytanie 4
    ALTER TABLE wycieczki ADD COLUMN ocena INT;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: droga1.jpg: szerokość 640 px z zachowaniem proporcji

    Kryteria:

    R.2.1 Plik droga1.jpg przeskalowano z zachowaniem proporcji do szerokości 640 px, odpowiadająca temu wysokość wynosi 480 px (± 5 px)

    ok. 2 min
    Polecenie z arkusza

    Przygotowanie grafiki: Plik droga1.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 640 px.

    Zdjęcie ma 1000 × 750 px. W GIMP-ie: Obraz → Skaluj obraz, łańcuch proporcji zamknięty, szerokość 640 - wysokość policzy się sama: 750 × 640 / 1000 = 480 px (klucz R.2.1 sprawdza właśnie 480 ± 5). Eksportuj jako droga1.jpg, nadpisując plik. To zdjęcie otworzy pierwszy odnośnik „zobacz zdjęcie”.

    Typowe błędy

    Otwarty łańcuch proporcji i wpisanie 640 × 640 zniekształca zdjęcie - klucz sprawdza wysokość 480 px.

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

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku motor.php, oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> oraz zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body

    ok. 2 min
    Polecenie z arkusza

    Cechy witryny: Składa się ze strony o nazwie motor.php zapisanej w języku HTML5.

    Utwórz motor.php w folderze z rozpakowanymi plikami: <!DOCTYPE html> i szkielet <html>, <head>, <body> (klucz R.2.2 wymaga obu sekcji).

    motor.php PHP nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  10. Krok 10: Język strony

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku motor.php, oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> oraz zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

    Ustawiony język zawartości strony na polski.

    lang="pl" w znaczniku <html>.

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  11. Krok 11: Kodowanie polskich znaków

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku motor.php, oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> oraz zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> - opisy tras z bazy są pełne polskich liter.

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

    Kryteria:

    R.2.3 Nadano tytuł stronie: "Motocykle"

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Motocykle”.

    <title> w <head> (R.2.3).

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

    Kryteria:

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

    <link rel="stylesheet" href="styl.css">.

    Typowe błędy

    Klucz R.3.3 odbiera punkt także wtedy, gdy któryś selektor bloku jest zapisany źle (np. kropka zamiast #) - sprawdzaj w inspektorze, czy każda reguła działa.

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  14. Krok 14: Obraz motor.png poza blokami

    Kryteria:

    R.2.8 W sekcji body, poza blokami umieszczono obraz moto r.png wraz z tekstem alternatywnym „motocykl”, sprawdzić w kodzie źródłowym

    ok. 1 min
    Polecenie z arkusza

    Umieszczony poza blokami obraz motor.png o tekście alternatywnym „motocykl”.

    Obraz stoi bezpośrednio w <body>, przed wszystkimi blokami - nie należy do żadnego z nich (klucz R.2.8 sprawdza to w kodzie). Na obrazie 2 motocykl prześwituje nawet przez baner, więc musi zaczynać się na samej górze strony; pozycjonowanie z CSS ustawi go pod blokami. Identyfikator bike pozwoli nadać styl „jedynie dla obrazu motor.png”. Na razie zajmuje całą szerokość - ma 1280 px.

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  15. Krok 15: Bloki semantyczne

    Kryteria:

    R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: baner, lewy, dwa prawe oraz stopkę. Zastosowano semantyczne znaczniki sekcji HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, stopki - footer, dopuszcza się zagnieżdżenie bloków div w znacznikach semantycznych

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze baner, poniżej trzy bloki: lewy, i dwa prawe, na dole blok stopki. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2.

    Baner to <header>, blok lewy z główną treścią (lista wycieczek) - <main>, dwa bloki prawe z dodatkami - dwa <aside>, stopka - <footer> (klucz R.2.4 wymaga znaczników zgodnych z ich znaczeniem). Bloki prawe mają wspólny wygląd, więc styl trafi do selektora aside; identyfikatory buy i stats (po angielsku) tylko je rozróżniają.

    motor.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
        </header>
        <main>
        </main>
        <aside id="buy">
        </aside>
        <aside id="stats">
        </aside>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  16. Krok 16: Baner: nagłówek pierwszego stopnia

    Kryteria:

    R.2.5 W banerze zapisano nagłówek h1: "Motocykle - moja pasja", w bloku lewym h2: "Gdzie pojechać?", w blokach prawych h2: "Co kupić?" i "Statystyki" oraz zapisano w drugim bloku prawym trzy paragrafy i w stopce paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek pierwszego stopnia o treści „Motocykle - moja pasja”.

    <h1> w <header> (R.2.5).

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
        </main>
        <aside id="buy">
        </aside>
        <aside id="stats">
        </aside>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  17. Krok 17: Blok lewy: nagłówek i lista definicji

    Kryteria: ,

    R.2.5 W banerze zapisano nagłówek h1: "Motocykle - moja pasja", w bloku lewym h2: "Gdzie pojechać?", w blokach prawych h2: "Co kupić?" i "Statystyki" oraz zapisano w drugim bloku prawym trzy paragrafy i w stopce paragraf z numerem zdającego

    R.2.6 W bloku lewym umieszczono listę definicji, zastosowano znacznik <dl> oraz zagnieżdżony w nim przynajmniej jeden z <dt>, <dd> (listę wygenerowano skryptem lub w HTML)

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek drugiego stopnia o treści: „Gdzie pojechać?”. Lista definicji (Description List) wypełniona przez skrypt 1.

    Lista definicji to <dl>, a w niej pary: termin <dt> (description term) i jego opis <dd> (description details). Pasuje jak ulał: termin to nazwa trasy, opis - jej opis. Pary wypisze skrypt 1, na razie <dl> jest pusta.

    motor.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
            </dl>
        </main>
        <aside id="buy">
        </aside>
        <aside id="stats">
        </aside>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  18. Krok 18: Pierwszy blok prawy: lista numerowana

    Kryteria: ,

    R.2.5 W banerze zapisano nagłówek h1: "Motocykle - moja pasja", w bloku lewym h2: "Gdzie pojechać?", w blokach prawych h2: "Co kupić?" i "Statystyki" oraz zapisano w drugim bloku prawym trzy paragrafy i w stopce paragraf z numerem zdającego

    R.2.7 W pierwszym bloku prawym umieszczono jedną listę numerowaną z pięcioma elementami, zastosowano znaczniki <ol>, <li>

    ok. 2 min
    Polecenie z arkusza

    Zawartość pierwszego bloku prawego: Nagłówek drugiego stopnia o treści: „Co kupić?”. Lista numerowana (uporządkowana) o 5 elementach: „Honda CBR125R”, „Yamaha YBR125”, „Honda VFR800i”, „Honda CBR1100XX”, „BMW R1200GS LC”.

    Numerowana = <ol>, pięć <li> w kolejności z arkusza (R.2.7).

    motor.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
        </aside>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  19. Krok 19: Drugi blok prawy: statystyki

    Kryteria:

    R.2.5 W banerze zapisano nagłówek h1: "Motocykle - moja pasja", w bloku lewym h2: "Gdzie pojechać?", w blokach prawych h2: "Co kupić?" i "Statystyki" oraz zapisano w drugim bloku prawym trzy paragrafy i w stopce paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość drugiego bloku prawego: Nagłówek drugiego stopnia o treści: „Statystyki”, paragraf (akapit) o treści „Wpisanych wycieczek: ”, dalej efekt działania skryptu 2, paragraf o treści „Użytkowników forum: 200”, paragraf o treści „Przesłanych zdjęć: 1300”.

    Trzy paragrafy. W pierwszym po dwukropku jest spacja i miejsce na liczbę - wstawi ją skrypt 2 wewnątrz tego samego <p>. Dwa pozostałe mają stałe liczby z arkusza.

    motor.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  20. Krok 20: Stopka

    Kryteria:

    R.2.5 W banerze zapisano nagłówek h1: "Motocykle - moja pasja", w bloku lewym h2: "Gdzie pojechać?", w blokach prawych h2: "Co kupić?" i "Statystyki" oraz zapisano w drugim bloku prawym trzy paragrafy i w stopce paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

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

    Akapit w <footer>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tu stoi autor rozwiązania.

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  21. Etap 3: Styl CSS

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

    Krok 21: Plik styl.css: krój czcionki

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Domyślne formatowanie wszystkich selektorów: krój czcionki Verdana.

    Utwórz styl.css; selektor * obejmuje wszystkie elementy (R.4.1).

    styl.css CSS nowy plik
    * {
        font-family: Verdana;
    }
    Podgląd strony po tym kroku (motor.php)
  22. Krok 22: Obraz motocykla: pozycjonowanie pod blokami

    Kryteria: ,

    R.4.4 Ustawiono szerokość: bloku lewego 75%, obu prawych 15% (width lub grid-template- columns lub flex) oraz jedynie dla obrazu motor.png 70%

    R.4.8 Dla obrazu ustawiono właściwości display: block; position: absolute; left: 15% oraz obraz znajduje się za blokami strony

    ok. 3 min
    Polecenie z arkusza

    Jedynie dla obrazu motor.png: wyświetlanie blokowe, pozycjonowanie na stronie: element przesunięty 15% od lewej strony względem swojego rodzica, szerokość 70%, element jest zakryty przez bloki strony (znajduje się za blokami strony).

    • display: block - obraz jako blok.
    • position: absolute z left: 15% - obraz wypada z normalnego układu strony (bloki go „nie widzą” i nie robią mu miejsca) i staje 15% od lewej krawędzi bloku zawierającego. Przy position: absolute jest nim najbliższy przodek z ustawionym position; tu żaden go nie ma, więc 15% liczy się od szerokości okna, a nie od <body> - arkusz upraszcza to do „względem rodzica”, a klucz R.4.8 ocenia zapis position: absolute; left: 15%.
    • width: 70% - też względem bloku zawierającego, czyli okna; wysokość dopasuje się do proporcji.
    • z-index: -1 - kolejność warstw: ujemna wartość kładzie obraz pod bloki strony.

    Selektor #bike dotyczy tylko tego obrazu - „jedynie” (R.4.4, R.4.8). Bloki nie mają jeszcze tła, więc motocykl leży pod tekstem.

    Typowe błędy

    Bez z-index (albo z dodatnim) obraz z position: absolute przykrywa bloki - klucz R.4.8 wymaga, by był za nimi.

    styl.css CSS zmienione: 7 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    Podgląd strony po tym kroku (motor.php)
  23. Krok 23: Baner: tło rgba, biały tekst, rozmiar, marginesy

    Kryteria: , ,

    R.4.2 Ustawiono kolor tła rgba(60, 120, 160, 0.9) dla banera i stopki, rgba(0, 100, 0, 0.6) dla bloków lewego i obu prawych oraz biały kolor czcionki dla banera, stopki, odnośników, lub kolor tła bloków ustawiony za pomocą rgb i opacity

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla banera i stopki oraz marginesy zewnętrzne (margin) 2% dla bloku lewego, 1% dla obu bloków prawych

    R.4.7 Ustawiono dla bloku lewego automatyczne paski przewijania (overflow: auto lub scroll) oraz rozmiar czcionki 150% dla banera i 120% dla bloku lewego

    ok. 2 min
    Polecenie z arkusza

    Dla banera: kolor tła RGB z wartościami 60, 120, 160 i przezroczystością 0.9; biały kolor czcionki, rozmiar czcionki 150%, marginesy wewnętrzne 10 px.

    Kolor z przezroczystością to rgba(czerwony, zielony, niebieski, krycie): trzy składowe 0-255 i czwarta liczba od 0 (całkiem przezroczysty) do 1 (pełny). Krycie 0.9 przepuszcza 10% tego, co pod spodem - widać przez baner kawałek motocykla, jak na obrazie 2. Przezroczyste jest tylko tło - tekst nagłówka zostaje w pełni biały.

    Typowe błędy

    opacity: 0.9 na banerze zamiast rgba w tle robi półprzezroczystym CAŁY blok, razem z tekstem.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    Podgląd strony po tym kroku (motor.php)
  24. Krok 24: Blok lewy: tło, wymiary, przewijanie i cień

    Kryteria: , , , , ,

    R.4.2 Ustawiono kolor tła rgba(60, 120, 160, 0.9) dla banera i stopki, rgba(0, 100, 0, 0.6) dla bloków lewego i obu prawych oraz biały kolor czcionki dla banera, stopki, odnośników, lub kolor tła bloków ustawiony za pomocą rgb i opacity

    R.4.3 Ustawiono wysokość bloku lewego na 600px, obu prawych na 300px

    R.4.4 Ustawiono szerokość: bloku lewego 75%, obu prawych 15% (width lub grid-template- columns lub flex) oraz jedynie dla obrazu motor.png 70%

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla banera i stopki oraz marginesy zewnętrzne (margin) 2% dla bloku lewego, 1% dla obu bloków prawych

    R.4.7 Ustawiono dla bloku lewego automatyczne paski przewijania (overflow: auto lub scroll) oraz rozmiar czcionki 150% dla banera i 120% dla bloku lewego

    R.4.9 Ustawiono przynajmniej dla jednego bloku (lewy, lub dowolny prawy) cień bloku o przesunięciu 10 px w obu osiach, rozmyciu 7 px i kolorze DimGray (box-shadow: 10px 10px 7px DimGray;)

    ok. 3 min
    Polecenie z arkusza

    Dla bloku lewego: kolor tła RGB z wartościami 0, 100, 0 i przezroczystością 0.6; marginesy zewnętrzne 2%, szerokość 75%, wysokość 600 px, rozmiar czcionki 120%, paski przewijania widoczne tylko gdy zawartość nie mieści się w bloku, cień bloku o przesunięciu 10 px w obu osiach, rozmyciu 7 px i kolorze DimGray.

    Zieleń z kryciem 0.6 - motocykl prześwituje wyraźnie. overflow: auto - pasek przewijania tylko gdy treść nie zmieści się w 600 px (10 opisów wycieczek się nie zmieści). box-shadow: 10px 10px 7px DimGray - cień: przesunięcie w poziomie, w pionie, rozmycie, kolor (R.4.9).

    styl.css CSS zmienione: 9 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    Podgląd strony po tym kroku (motor.php)
  25. Krok 25: Bloki prawe: wspólny wygląd

    Kryteria: , , ,

    R.4.2 Ustawiono kolor tła rgba(60, 120, 160, 0.9) dla banera i stopki, rgba(0, 100, 0, 0.6) dla bloków lewego i obu prawych oraz biały kolor czcionki dla banera, stopki, odnośników, lub kolor tła bloków ustawiony za pomocą rgb i opacity

    R.4.3 Ustawiono wysokość bloku lewego na 600px, obu prawych na 300px

    R.4.4 Ustawiono szerokość: bloku lewego 75%, obu prawych 15% (width lub grid-template- columns lub flex) oraz jedynie dla obrazu motor.png 70%

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla banera i stopki oraz marginesy zewnętrzne (margin) 2% dla bloku lewego, 1% dla obu bloków prawych

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla bloków prawych: kolor tła RGB z wartościami 0, 100, 0 i przezroczystością 0.6; marginesy zewnętrzne 1%, szerokość 15%, wysokość 300 px, cień bloku o przesunięciu 10 px w obu osiach, rozmyciu 7 px i kolorze DimGray.

    Selektor aside obejmuje oba bloki prawe naraz - tak „wspólne” przekłada się na CSS.

    styl.css CSS zmienione: 7 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    aside {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 1%;
        width: 15%;
        height: 300px;
        box-shadow: 10px 10px 7px DimGray;
    }
    Podgląd strony po tym kroku (motor.php)
  26. Krok 26: Stopka: tło, biały tekst, marginesy

    Kryteria: ,

    R.4.2 Ustawiono kolor tła rgba(60, 120, 160, 0.9) dla banera i stopki, rgba(0, 100, 0, 0.6) dla bloków lewego i obu prawych oraz biały kolor czcionki dla banera, stopki, odnośników, lub kolor tła bloków ustawiony za pomocą rgb i opacity

    R.4.6 Ustawiono marginesy wewnętrzne (padding) 10px dla banera i stopki oraz marginesy zewnętrzne (margin) 2% dla bloku lewego, 1% dla obu bloków prawych

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła RGB z wartościami 60, 120, 160 i przezroczystością 0.9; biały kolor czcionki, marginesy wewnętrzne 10 px.

    Te same wartości co baner, bez powiększenia czcionki.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    aside {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 1%;
        width: 15%;
        height: 300px;
        box-shadow: 10px 10px 7px DimGray;
    }
    footer {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        padding: 10px;
    }
    Podgląd strony po tym kroku (motor.php)
  27. Krok 27: Nagłówki h1 i h2: wyśrodkowane i pochylone

    Kryteria:

    R.4.5 Ustawiono dla selektorów h1 i h2 wyrównanie tekstu do środka i czcionkę pochyloną

    ok. 1 min
    Polecenie z arkusza

    Dla selektora nagłówka pierwszego i drugiego stopnia: wyrównanie tekstu do środka, czcionka pochylona.

    Czcionka pochylona to font-style: italic. Arkusz wymaga selektorów znaczników h1, h2 - klasa albo identyfikator nie zaliczą R.4.5.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    aside {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 1%;
        width: 15%;
        height: 300px;
        box-shadow: 10px 10px 7px DimGray;
    }
    footer {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        padding: 10px;
    }
    h1, h2 {
        text-align: center;
        font-style: italic;
    }
    Podgląd strony po tym kroku (motor.php)
  28. Krok 28: Lista definicji: kolory, marginesy, podświetlenie

    Kryteria: ,

    R.4.2 Ustawiono kolor tła rgba(60, 120, 160, 0.9) dla banera i stopki, rgba(0, 100, 0, 0.6) dla bloków lewego i obu prawych oraz biały kolor czcionki dla banera, stopki, odnośników, lub kolor tła bloków ustawiony za pomocą rgb i opacity

    R.4.10 Ustawiono dla terminu w liście definicji biały kolor czcionki, padding: 1% dla elementu definicji w liście oraz gdy kursor znajdzie się na elemencie definicji, jego kolor tła zmienia się na LightGreen

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla odnośnika i terminu w liście definicji: biały kolor czcionki. Dla elementu definicji w liście: marginesy wewnętrzne 1%. Gdy kursor znajdzie się na elemencie definicji w liście, jego kolor tła zmienia się na LightGreen (widoczne na obrazie 2).

    a, dt - odnośniki i terminy białe. dd - element definicji z marginesem wewnętrznym 1%, a dd:hover podświetla opis pod kursorem na jasnozielono (R.4.10). Lista jest jeszcze pusta - wypełni ją skrypt 1.

    styl.css CSS zmienione: 9 linii
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    aside {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 1%;
        width: 15%;
        height: 300px;
        box-shadow: 10px 10px 7px DimGray;
    }
    footer {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        padding: 10px;
    }
    h1, h2 {
        text-align: center;
        font-style: italic;
    }
    a, dt {
        color: white;
    }
    dd {
        padding: 1%;
    }
    dd:hover {
        background-color: LightGreen;
    }
    Podgląd strony po tym kroku (motor.php)
  29. Krok 29: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (prawidłowo zastosowano właściwości CSS decydujące o układzie strony np. float i clear albo display flex albo grid)

    ok. 3 min
    Polecenie z arkusza

    Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2.

    main, aside { float: left; } - blok lewy (75% + 2 × 2% marginesu = 79%) i pierwszy prawy (15% + 2 × 1% = 17%) stają obok siebie. Drugi blok prawy już się w tej linii nie mieści, więc opada pod pierwszy prawy - po lewej wciąż zajmuje miejsce wysoki blok lewy. To dokładnie układ z obrazu 2, bez żadnych dodatkowych kontenerów. Stopka z clear: both schodzi pod wszystkie bloki (R.3.1).

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Verdana;
    }
    #bike {
        display: block;
        position: absolute;
        left: 15%;
        width: 70%;
        z-index: -1;
    }
    header {
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        font-size: 150%;
        padding: 10px;
    }
    main, aside {
        float: left;
    }
    main {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 2%;
        width: 75%;
        height: 600px;
        font-size: 120%;
        overflow: auto;
        box-shadow: 10px 10px 7px DimGray;
    }
    aside {
        background-color: rgba(0, 100, 0, 0.6);
        margin: 1%;
        width: 15%;
        height: 300px;
        box-shadow: 10px 10px 7px DimGray;
    }
    footer {
        clear: both;
        background-color: rgba(60, 120, 160, 0.9);
        color: white;
        padding: 10px;
    }
    h1, h2 {
        text-align: center;
        font-style: italic;
    }
    a, dt {
        color: white;
    }
    dd {
        padding: 1%;
    }
    dd:hover {
        background-color: LightGreen;
    }
    Podgląd strony po tym kroku (motor.php)
  30. Etap 4: Skrypty PHP

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

    Krok 30: Połączenie z bazą danych

    Kryteria: ,

    R.5.1 Skrypt zawiera instrukcje połączenia z serwerem bazy danych i wyboru bazy motory

    R.5.8 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych lub funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania

    ok. 2 min
    Polecenie z arkusza

    Wymagania dotyczące skryptów: Napisane w języku PHP. Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie motory.

    Połączenie otwierasz raz, zaraz po <body>, w zmiennej $connection. mysqli_connect z tabeli 1: serwer, użytkownik, hasło (puste), nazwa bazy. Od tego kroku podgląd to wynik działania strony po stronie serwera.

    motor.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  31. Krok 31: Skrypt 1: zapytanie 2 do bazy

    Kryteria:

    R.5.3 Skrypt 1 zawiera instrukcje wysyłające do bazy danych zapytanie 2 lub skrypt 2: zapytanie 3

    ok. 1 min
    Polecenie z arkusza

    Skrypt 1: Wysyła do bazy danych zapytanie 2.

    Skrypt 1 stoi wewnątrz <dl> - tam wypisze pary termin-opis. Wynik zapytania 2 zapisujesz w $trips (wycieczki).

    motor.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  32. Krok 32: Skrypt 1: termin z nazwą i początkiem trasy

    Kryteria:

    R.5.4 Skrypt 1 wyświetla tekst: „<nazwa>, rozpoczyna się w <poczatek>,”, gdzie wartości w <> są pobrane z bazy danych

    ok. 2 min
    Polecenie z arkusza

    Zwrócone zapytaniem wartości są wyświetlane jako poszczególne terminy i elementy definicji listy według wzoru: Termin listy: „<nazwa>, rozpoczyna się w <poczatek>, ”.

    Pętla while z mysqli_fetch_row przechodzi po dziesięciu wycieczkach. Kolejność kolumn z zapytania 2: nazwa (0), opis (1), poczatek (2), zrodlo (3). Termin <dt> składasz z nazwy i początku według wzoru z arkusza, łącznie z przecinkiem i spacją na końcu - za nimi dojdzie odnośnik (R.5.4).

    motor.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_row($trips)) {
        echo "<dt>$row[0], rozpoczyna się w $row[2], </dt>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  33. Krok 33: Skrypt 1: odnośnik „zobacz zdjęcie” z rozszerzeniem .jpg

    Kryteria: ,

    R.5.5 Skrypt1 wyświetla odnośnik, którego kliknięcie powoduje otwarcie zdjęcia. Nazwa zdjęcia została pobrana z bazy, zostało dopisane rozszerzenie .jpg

    R.3.2 Zapisano na stronie przynajmniej jeden odnośnik o treści „zobacz zdjęcie", prowadzący do dowolnego zdjęcia droga1.jpg ÷ droga5.jpg

    ok. 2 min
    Polecenie z arkusza

    Następnie odnośnik o treści „zobacz zdjęcie”, prowadzący do zdjęcia, którego nazwa została zwrócona zapytaniem.

    Pole zrodlo zawiera samą nazwę, np. droga1 - bez rozszerzenia, a plik nazywa się droga1.jpg. Dlatego w adresie dopisujesz .jpg zaraz po wartości: href=\"$row[3].jpg\" - PHP podstawi $row[3], a .jpg zostanie zwykłym tekstem (klucz R.5.5 sprawdza właśnie dopisane rozszerzenie). Kliknięcie otworzy zdjęcie w przeglądarce; w podglądzie kliknięcia są zablokowane (R.3.2).

    Typowe błędy

    href=\"$row[3]\" bez .jpg prowadzi do nieistniejącego pliku droga1 - przeglądarka pokaże błąd 404.

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_row($trips)) {
        echo "<dt>$row[0], rozpoczyna się w $row[2], <a href=\"$row[3].jpg\">zobacz zdjęcie</a></dt>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  34. Krok 34: Skrypt 1: opis jako element definicji

    Kryteria: ,

    R.5.6 Skrypt 1 wyświetla opis pobrany z bazy

    R.2.6 W bloku lewym umieszczono listę definicji, zastosowano znacznik <dl> oraz zagnieżdżony w nim przynajmniej jeden z <dt>, <dd> (listę wygenerowano skryptem lub w HTML)

    ok. 1 min
    Polecenie z arkusza

    Element definicji listy: zwrócone zapytaniem pole opis.

    Po terminie wypisujesz <dd> z opisem $row[1]. Lista ma teraz dziesięć par; długie opisy nie mieszczą się w 600 px bloku lewego, więc pojawia się pasek przewijania. Najedź kursorem na opis - podświetla się na LightGreen, jak na obrazie 2 (R.5.6).

    motor.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_row($trips)) {
        echo "<dt>$row[0], rozpoczyna się w $row[2], <a href=\"$row[3].jpg\">zobacz zdjęcie</a></dt>";
        echo "<dd>$row[1]</dd>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  35. Krok 35: Skrypt 2: liczba wycieczek w paragrafie

    Kryteria: ,

    R.5.3 Skrypt 1 zawiera instrukcje wysyłające do bazy danych zapytanie 2 lub skrypt 2: zapytanie 3

    R.5.7 Skrypt 2 wyświetla napis o treści "Wpisanych wycieczek:" wartość pobraną zapytaniem

    ok. 2 min
    Polecenie z arkusza

    Skrypt 2: Wysyła do bazy danych zapytanie 3. Wartość zwrócona zapytaniem jest wyświetlana w paragrafie po słowach: „Wpisanych wycieczek: ”.

    Skrypt 2 piszesz wewnątrz paragrafu, za tekstem „Wpisanych wycieczek:”. COUNT(*) zwraca jeden wiersz z jedną kolumną, więc pętla nie jest potrzebna: mysqli_fetch_row pobiera ten wiersz, a echo $row[0] wypisuje liczbę 10 w tej samej linii co tekst (R.5.7).

    motor.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_row($trips)) {
        echo "<dt>$row[0], rozpoczyna się w $row[2], <a href=\"$row[3].jpg\">zobacz zdjęcie</a></dt>";
        echo "<dd>$row[1]</dd>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: 
    <?php
    $tripCount = mysqli_query($connection, 'SELECT COUNT(*) FROM wycieczki;');
    $row = mysqli_fetch_row($tripCount);
    echo $row[0];
    ?>
            </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (motor.php)
  36. Krok 36: Zamknięcie połączenia

    Kryteria:

    R.5.2 Ostatnią operacją na bazie jest jej zamknięcie

    ok. 1 min
    Polecenie z arkusza

    Na końcu jest zamykane połączenie z serwerem.

    mysqli_close($connection) po stopce - ostatnia operacja na bazie (R.5.2). Strona spełnia wszystkie kryteria arkusza.

    motor.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_row($trips)) {
        echo "<dt>$row[0], rozpoczyna się w $row[2], <a href=\"$row[3].jpg\">zobacz zdjęcie</a></dt>";
        echo "<dd>$row[1]</dd>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: 
    <?php
    $tripCount = mysqli_query($connection, 'SELECT COUNT(*) FROM wycieczki;');
    $row = mysqli_fetch_row($tripCount);
    echo $row[0];
    ?>
            </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  37. Etap 5: Dobre praktyki (poza kluczem)

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

    Krok 37: Skrypt 1: kolumny po nazwach i escapowanie

    ok. 4 min
    Polecenie z arkusza

    Zwrócone zapytaniem wartości są wyświetlane jako poszczególne terminy i elementy definicji listy.

    Dwie poprawki naraz:

    • mysqli_fetch_assoc oddaje wiersz po nazwach kolumn: $row['nazwa'] zamiast $row[0] - kod mówi sam za siebie, a zmiana kolejności w SELECT niczego nie psuje;
    • htmlspecialchars przy wypisywaniu - opisy tras ktoś wpisał do bazy, a tekst z <script> wykonałby się u każdego czytelnika (XSS). Cudzysłów w nazwie pliku nie rozbije też atrybutu href.

    Wartości trafiają do zmiennych o czytelnych nazwach, a echo składa z nich gotowe znaczniki. Podgląd bez zmian. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    motor.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Motocykle</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'motory');
    ?>
        <img id="bike" src="motor.png" alt="motocykl">
        <header>
            <h1>Motocykle - moja pasja</h1>
        </header>
        <main>
            <h2>Gdzie pojechać?</h2>
            <dl>
    <?php
    $trips = mysqli_query($connection, 'SELECT nazwa, opis, poczatek, zrodlo FROM wycieczki JOIN zdjecia ON zdjecia_id = zdjecia.id;');
    while ($row = mysqli_fetch_assoc($trips)) {
        $name = htmlspecialchars($row['nazwa']);
        $start = htmlspecialchars($row['poczatek']);
        $photo = htmlspecialchars($row['zrodlo']) . '.jpg';
        $description = htmlspecialchars($row['opis']);
        echo "<dt>$name, rozpoczyna się w $start, <a href=\"$photo\">zobacz zdjęcie</a></dt>";
        echo "<dd>$description</dd>";
    }
    ?>
            </dl>
        </main>
        <aside id="buy">
            <h2>Co kupić?</h2>
            <ol>
                <li>Honda CBR125R</li>
                <li>Yamaha YBR125</li>
                <li>Honda VFR800i</li>
                <li>Honda CBR1100XX</li>
                <li>BMW R1200GS LC</li>
            </ol>
        </aside>
        <aside id="stats">
            <h2>Statystyki</h2>
            <p>Wpisanych wycieczek: 
    <?php
    $tripCount = mysqli_query($connection, 'SELECT COUNT(*) FROM wycieczki;');
    $row = mysqli_fetch_row($tripCount);
    echo $row[0];
    ?>
            </p>
            <p>Użytkowników forum: 200</p>
            <p>Przesłanych zdjęć: 1300</p>
        </aside>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  38. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego, powinny znajdować się pliki: droga1.jpg, droga2.jpg, droga3.jpg, droga4.jpg, droga5.jpg, import.png, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, motor.php, motor.png, przeglądarka.txt, styl.css, ewentualnie inne przygotowane pliki.

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

    Sprawdź listę plików z arkusza (w tym przeskalowany droga1.jpg i pozostałe zdjęcia z archiwum), 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 35.

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.