Przejdź do głównej treści
INF.03-08-26.01-SGStyczeń 2026 · 49 kroków · ok. 87 min · 40 kryteriów z klucza

Rozwiązanie krok po kroku: Portal korony gór polskich (Wersja podstawowa)

Rozwiązanie buduje portal korony gór polskich: baza korona (szczyty i ich opisy w osobnej tabeli) i cztery zapytania - sortowanie malejące po wysokości, LIMIT, złączenie z warunkiem i LIKE 'Beskid%' - potem logo z bielą zamienioną na przezroczystość i kadrem przyciętym do jednego szczytu, dwie strony ze wspólnym układem bloków: index.php z listą 28 szczytów i szczyty.php z opisem jednego szczytu, style z własnym krojem Lato dołączonym regułą @font-face i rozmiarami czcionek ustawianymi pseudoklasą :nth-child, oraz trzy skrypty PHP: odnośniki szczytów przekazujące identyfikator metodą GET, pasek miniatur i strona szczytu budowana z jednego rekordu.

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ą. Skrypty są najpierw pisane najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row), a na końcu zostają przerobione na wersję z prawdziwych projektów: liczba zamiast surowego tekstu z adresu, zapytanie przygotowane, komunikat dla nieistniejącego szczytu, akapity opisu i htmlspecialchars.

Baza, zdjęcia, logo i czcionki pochodzą z prawdziwego archiwum pliki13 (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. Podgląd stron od kroków z PHP to wynik prawdziwego uruchomienia kodu z danego kroku w PHP 8.2 na bazie z arkusza; szczyty.php pokazuje Rysy, jak na ilustracji 5. Podgląd ładuje krój Lato z folderu czcionka/, tak jak strona ucznia.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: układ na siatce CSS z nazwanymi obszarami, kolory w zmiennych, a baza przez PDO z danymi pobranymi przed HTML-em, walidacją identyfikatora, zapytaniem przygotowanym i htmlspecialchars od pierwszej linii - obie wersje są zgodne z kluczem.

Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów - można stracić 10 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 40 kryteriów (pkt)

    Krok 1: Baza danych korona

    ok. 2 min
    Polecenie z arkusza

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

    Rozpakuj pliki13.7z z pulpitu (hasło Gory^PoLskie! - z daszkiem ^ w środku) i załóż folder z numerem zdającego. W archiwum są: korona.sql, logo.png, 12 zdjęć gór i folder czcionka z krojem Lato. W phpMyAdmin: Nowa, nazwa korona, porównywanie utf8_polish_ci.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie korona - skrypty łączą się z bazą po nazwie, więc literówka zabiera też punkty za skrypty (R.5.1).

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

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabele z pliku korona.sql do utworzonej bazy

    Zaznacz bazę korona, potem Import → korona.sql → Wykonaj. Powstają dwie tabele z ilustracji 1: szczyty (nazwa, wysokość, pasmo, lokator i nazwa pliku ze zdjęciem) i opis, w której każdy opis wskazuje swój szczyt polem szczyty_id.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych korona - plik import.png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą 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, wklejasz do edytora grafiki i zapisujesz jako import.png. Import idzie do PNG, a zrzuty zapytań do JPEG - formaty są różne.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: szczyty od najwyższego

    Kryteria: ,

    R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonane zapytanie 1: wybierające jedynie id oraz nazwy szczytów posortowane malejąco według ich wysokości. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC; oraz na zrzucie widoczny jest komunikat o wybranych 28 rekordach oraz pierwsze trzy rekordy to 1 Rysy, 9 Babia Góra, 26 Śnieżka

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie id oraz nazwy wszystkich szczytów posortowane malejąco według ich wysokości

    • SELECT id, nazwa - dwa pola,
    • FROM szczyty - jedna tabela, bez warunku,
    • ORDER BY wysokosc DESC - sortujesz po polu, którego nie wybierasz; to dozwolone. DESC to kolejność malejąca.

    Wynik: 28 wierszy, pierwsze trzy to 1 Rysy, 9 Babia Góra, 26 Śnieżka, ostatnia Łysica. Zapytanie zapisujesz w kwerendy.txt, zrzut jako kw1.jpg (cały ekran z paskiem zadań, z komunikatem o liczbie rekordów).

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: pierwsze 10 rekordów

    Kryteria:

    R.1.4 Wykonane zapytanie 2: wybierające jedynie nazwy plików i nazwy szczytów dla pierwszych 10 rekordów. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT plik, nazwa FROM szczyty LIMIT 10; oraz na zrzucie widocznych jest dokładnie 10 rekordów, ostatni to gora.jpg , Czupel

    ok. 1 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie nazwy plików i nazwy szczytów dla pierwszych 10 rekordów

    LIMIT 10 na końcu zapytania obcina wynik do dziesięciu wierszy. Bez ORDER BY są to rekordy w kolejności z tabeli, czyli identyfikatory 1 - 10: ostatni to gora.jpg, Czupel - kilka szczytów korzysta z tego samego zdjęcia zastępczego. Kolejność pól jak w arkuszu: najpierw plik, potem nazwa. Zrzut: kw2.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;
    
    -- Zapytanie 2
    SELECT plik, nazwa FROM szczyty LIMIT 10;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: szczyt o id 1 z opisem

    Kryteria:

    R.1.5 Wykonane zapytanie 3: wybierające jedynie nazwę pliku, nazwę szczytu, wysokość i pasmo oraz odpowiadający im opis dla szczytu o id równym 1. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT plik, nazwa, wysokosc, pasmo, opis FROM szczyty JOIN opis ON szczyty.id = szczyty_id WHERE szczyty.id = 1; (lub porównanie kluczy po WHERE. lub szczyty_id = 1 ) oraz na zrzucie widoczny jest dokładnie 1 rekord dla szczytu Rysy

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie nazwę pliku, nazwę szczytu, wysokość i pasmo oraz odpowiadający im opis dla szczytu o id równym 1. Należy posłużyć się relacją

    • SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis - cztery pola z tabeli szczytów i opis; tabela opis ma pole o tej samej nazwie co ona sama, stąd opis.opis,
    • FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id - relacja: opis wskazuje swój szczyt,
    • WHERE szczyty.id = 1 - Rysy.

    Wynik: dokładnie jeden wiersz. phpMyAdmin skraca długie teksty w podglądzie - pełny opis zobaczysz na stronie. Zrzut: kw3.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;
    
    -- Zapytanie 2
    SELECT plik, nazwa FROM szczyty LIMIT 10;
    
    -- Zapytanie 3
    SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: szczyty w Beskidach

    Kryteria:

    R.1.6 Wykonane zapytanie 4: wybierające jedynie nazwy szczytów, wysokości oraz pasma gór, dla których nazwa pasma rozpoczyna się od „Beskid”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, wysokosc, pasmo FROM szczyty WHERE pasmo LIKE "Beskid%"; (Wielkość litery B nie ma znaczenia ) oraz na zrzucie widocznych jest dokładnie 7 rekordów dla: Beskid Niski, Beskid Sądecki, Beskid Wyspowy, Beskid Makowski, Beskid Żywiecki, Beskid Mały, Beskid Śląski

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: wybierające jedynie nazwy szczytów, wysokości oraz pasma gór w Beskidach (nazwa pasma rozpoczyna się od „Beskid”)

    „Rozpoczyna się od” to LIKE 'Beskid%' - znak % zastępuje dowolny ciąg znaków (także pusty), więc pasuje każde pasmo zaczynające się od „Beskid”. Wynik: 7 wierszy - Beskid Niski, Sądecki, Wyspowy, Makowski, Żywiecki, Mały i Śląski. Zrzut: kw4.jpg.

    Typowe błędy

    LIKE '%Beskid%' (procent także z przodu) szuka „Beskid” w dowolnym miejscu nazwy - tutaj wynik byłby ten sam, ale zapytanie nie odpowiada poleceniu „rozpoczyna się od”.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;
    
    -- Zapytanie 2
    SELECT plik, nazwa FROM szczyty LIMIT 10;
    
    -- Zapytanie 3
    SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = 1;
    
    -- Zapytanie 4
    SELECT nazwa, wysokosc, pasmo FROM szczyty WHERE pasmo LIKE 'Beskid%';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Logo: białe tło na przezroczystość

    Kryteria:

    R.2.2 Grafika ma przezroczyste tło (akceptowalne niedokładności pojedynczych pikseli )

    ok. 3 min
    Polecenie z arkusza

    Przygotowanie grafiki logo.png: Białe tło grafiki należy zastąpić przezroczystością (drobne niedokładności pojedynczych pikseli są akceptowalne)

    logo.png to czarny rysunek na białym tle. W GIMP-ie: Warstwa → Przezroczystość → Dodaj kanał alfa, potem Kolory → Kolor na alfę z kolorem białym. Biel znika w całym obrazie - także wewnątrz zboczy, bo tam też jest tło (na ilustracji 3 szachownica prześwituje między liniami). Szare piksele wygładzenia na brzegach linii dostają częściową przezroczystość, więc linie nie mają białej obwódki.

    Typowe błędy

    Zaznaczenie różdżką samego zewnętrznego tła zostawia białe wnętrza gór - na kolorowym tle strony byłyby widoczne białe plamy.

  9. Krok 9: Logo: kadr do szczytu po prawej i wysokość 100 px

    Kryteria:

    R.2.1 Grafika logo.png skadrowana, tak że widoczny jest jedynie szczyt po prawej stronie, a krawędzie grafiki przylegają do kształtu (widoczne na niepowiększonym obrazie ) oraz przeskalowana do wysokości 100 px

    ok. 3 min
    Polecenie z arkusza

    Skadrować grafikę tak, aby był widoczny jedynie szczyt po prawej stronie. Kadr powinien obejmować cały szczyt oraz krawędzie grafiki powinny przylegać do kształtu (ilustracja 3). Skadrowaną grafikę należy przeskalować z zachowaniem proporcji do wysokości 100 px

    Szczyt po prawej to rysunek w prawym górnym rogu. Zaznacz go prostokątem z zapasem, Obraz → Przytnij do zaznaczenia, a potem Obraz → Przytnij do zawartości - krawędzie dosuną się do linii rysunku. Kadr: 227 × 144 px (prawe zbocze sięga samej krawędzi pliku). Na koniec Obraz → Skaluj obraz z zamkniętym łańcuchem: wysokość 100 px, szerokość wychodzi 158 px. Eksport jako logo.png.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Plik index.php w HTML5

    ok. 2 min
    Polecenie z arkusza

    Składa się ze stron index.php oraz szczyty.php. Cechy wspólne dla obu stron: Zapisane w języku HTML5

    Zacznij od strony głównej: deklaracja <!DOCTYPE html> i szkielet. Wszystko, co wspólne, piszesz raz - stronę szczyty.php zrobisz później jako kopię gotowego szkieletu.

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

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny

    Atrybut lang="pl" w znaczniku <html>.

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

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwszy element <head> - bez niego „Śnieżka” czy „Łysica” mogą wyświetlić się krzakami.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  13. Krok 13: Tytuł strony

    Kryteria:

    R.2.3 W pliku index.php lub szczyty.php , znajduje się deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości witryny: polski np. <html lang="pl">. W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony „Korona gór polskich”

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony „Korona gór polskich”

    <title> w <head>. Deklaracja HTML5, język, kodowanie i tytuł to razem jedno kryterium (R.2.3).

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

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza (nie należy brać pod uwagę @font- face)

    ok. 1 min
    Polecenie z arkusza

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

    Nazwa pliku: styl.css (nie style.css). Całe formatowanie ma pochodzić z tego pliku - żadnych atrybutów style w HTML-u.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  15. Krok 15: Bloki: dwa nagłówki, główny, sekcja, dwie stopki

    Kryteria:

    R.2.4 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML5: header+header, main, section, footer+footer (dopuszcza się zastosowanie bloków pomocniczych)

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 4

    Klucz wymaga wprost dwóch header, potem main, section i dwóch footer (R.2.4). Blok sekcji stoi poza blokiem głównym - na ilustracji 4 zajmuje osobny pas pod nim. Bloki w parach mają różne szerokości, więc dostają identyfikatory: logo i title dla nagłówków, contact i author dla stopek.

    index.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
        </header>
        <header id="title">
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  16. Krok 16: Blok nagłówkowy 1: logo

    Kryteria:

    R.2.6 W bloku nagłówkowym 1 znajduje się grafika z logo z tekstem alternatywnym "Logo"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego 1: Obraz logo.png z tekstem alternatywnym „Logo”

    <img> z atrybutem alt - tekst alternatywny zastępuje obraz, gdy go zabraknie, i czyta go czytnik ekranu.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  17. Krok 17: Blok nagłówkowy 2: tytuł

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego 2: Nagłówek pierwszego stopnia o treści: „Korona Gór Polskich”

    Pierwszego stopnia, czyli <h1>. Tu „Gór Polskich” wielkimi literami, w tytule karty małymi - tak jak w arkuszu.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  18. Krok 18: Stopka 1: nagłówek „Kontakt”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku stopki 1: Nagłówek trzeciego stopnia o treści: „Kontakt”

    <h3> w pierwszej stopce.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  19. Krok 19: Stopka 1: lista z telefonem

    ok. 1 min
    Polecenie z arkusza

    Lista punktowana (nieuporządkowana) zawierająca dwa elementy: „Zadzwoń do nas: 111 222 333”

    Lista punktowana to <ul> (unordered list), elementy to <li>. Pierwszy element to zwykły tekst.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
            </ul>
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  20. Krok 20: Stopka 1: odsyłacz pocztowy

    Kryteria: ,

    R.2.7 W bloku stopki 1 znajduje się jedna lista punktowana z dwoma elementami

    R.3.3 Odnośnik pocztowy "Napisz do nas" zdefiniowany jako mailto:[email protected]

    ok. 1 min
    Polecenie z arkusza

    „Napisz do nas”, element jest odsyłaczem pocztowym do adresu „[email protected]”

    Odsyłacz pocztowy to odnośnik z adresem zaczynającym się od mailto: - kliknięcie otwiera program pocztowy z wpisanym odbiorcą. Lista ma już dwa elementy (R.2.7).

    Typowe błędy

    Sam adres w href (bez mailto:) przeglądarka potraktuje jak plik o nazwie [email protected] na serwerze.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  21. Krok 21: Stopka 2: znak © i autor

    Kryteria: ,

    R.2.5 W bloku nagłówkowym 2 znajduje się <h1>: „Korona Gór Polskich", w blokach stopki <h3> "Kontakt" oraz <h3> z numerem zdającego

    R.2.8 W bloku stopki 2 znajduje się znak copyright ©

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku stopki 2: Nagłówek trzeciego stopnia o treści „© Wykonane przez: ”, dalej wstawiony numer zdającego

    Znak © piszesz encją &copy; (tabela 3 arkusza; działa też &#169;). Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Z tym krokiem są już wszystkie nagłówki z klucza: <h1> i dwa <h3> (R.2.5).

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  22. Krok 22: Plik szczyty.php: kopia wspólnego szkieletu

    ok. 1 min
    Polecenie z arkusza

    Cechy bloku głównego dla strony index.php: Efekt działania skryptu 1. Cechy bloku głównego dla strony szczyty.php: Efekt działania skryptu 3

    Obie strony mają te same bloki, nagłówki i stopki - różnią się tylko zawartością bloku głównego. Zapisz więc gotowy plik jeszcze raz jako szczyty.php. Blok główny jest na razie pusty w obu plikach: na stronie głównej wypełni go skrypt 1, na stronie szczytu skrypt 3.

    szczyty.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
        </main>
        <section>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>

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

  23. Etap 3: Styl CSS

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

    Krok 23: Krój Lato: reguły @font-face

    Kryteria:

    R.4.10 czcionka Lato: w stylach zdefiniowana przynajmniej raz dyrektywa @font-face z rzeczywistymi ścieżkami URL

    ok. 3 min
    Polecenie z arkusza

    Styl CSS korzysta z kroju czcionki Lato znajdującej się w folderze czcionka z rozpakowanego archiwum. Czcionkę należy dodać do projektu i zdefiniować jej stosowanie dla wariantu regular i bold. W pliku styl.css należy dodać reguły dla czcionki. Przykład umieszczono w pliku przyklad.css

    Skopiuj folder czcionka z archiwum do folderu z numerem zdającego. Reguły bierzesz z przyklad.css z jedną zmianą: plik leży w podfolderze, więc ścieżki to czcionka/lato-regular.woff2 (komentarz w przykładzie mówi wprost „change path if required”). Dwie reguły @font-face pod tą samą nazwą 'Lato': zwykła (font-weight: normal) i pogrubiona (bold) - przeglądarka sama wybierze plik dla nagłówków i dla zwykłego tekstu. Format woff2 jest pierwszy, bo jest mniejszy; woff to zapas dla starszych przeglądarek.

    Typowe błędy

    Ścieżka z przykładu (url('lato-bold.woff2')) bez folderu czcionka/ nie znajdzie pliku - strona ładuje się krojem zastępczym i nikt tego nie zauważa, dopóki nie porówna liter z ilustracją. Sprawdź w narzędziach przeglądarki, zakładka Sieć.

    styl.css CSS nowy plik
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    Podgląd strony po tym kroku (index.php)
  24. Krok 24: Krój, wyrównanie i kolor dla wszystkich

    Kryteria:

    R.4.1 domyślne formatowanie selektorów (*): krój czcionki Lato, sans-serif (dozwolona tylko taka kolejność) , wyrównanie tekstu do środka oraz kolor czcionki #333

    ok. 1 min
    Polecenie z arkusza

    Domyślnie dla wszystkich selektorów: krój czcionki Lato, w przypadku braku sans-serif, wyrównanie tekstu do środka, kolor czcionki #333

    Selektor *. Nazwa Lato to ta sama nazwa, którą nadano w @font-face; sans-serif na końcu (klucz sprawdza tę kolejność). Kolor #333 to skrót od #333333 - ciemnoszary zamiast czystej czerni.

    styl.css CSS zmienione: 5 linii
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    Podgląd strony po tym kroku (index.php)
  25. Krok 25: Bloki nagłówkowe i stopki: wysokość

    ok. 1 min
    Polecenie z arkusza

    Dla bloków nagłówkowych i stopek: wysokość 100 px

    Selektor header, footer obejmuje cztery bloki naraz. Logo ma dokładnie 100 px wysokości - wypełnia swój blok.

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    Podgląd strony po tym kroku (index.php)
  26. Krok 26: Nagłówek 1 i stopka 1: szerokość 30%

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo dla bloku nagłówkowego 1 i bloku stopki 1: szerokość 30%

    Selektory identyfikatorów po przecinku.

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    Podgląd strony po tym kroku (index.php)
  27. Krok 27: Nagłówek 2 i stopka 2: szerokość 70%

    Kryteria:

    R.4.5 szerokość: blok nagłówkowy 1, stopka 1: 30%, blok nagłówkowy 2, stopka 2: 70% (width lub grid-template-columns lub flex )

    ok. 1 min
    Polecenie z arkusza

    Dodatkowo dla bloku nagłówkowego 2 i bloku stopki 2: szerokość 70%

    W parach 30% + 70% daje całą szerokość. Bloki mają już szerokości z klucza, ale nadal stoją jeden pod drugim (R.4.5).

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    Podgląd strony po tym kroku (index.php)
  28. Krok 28: Układ bloków zgodny z ilustracją 4

    Kryteria:

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

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 4

    Pary bloków ustawiasz float: left: nagłówki stają obok siebie, stopki też. Blok główny dostaje clear: both - zaczyna się dopiero pod pływającymi nagłówkami. Sekcja jest zwykłym blokiem pod blokiem głównym, a stopki pływają w rzędzie na samym dole (R.3.1). Druga reguła header, footer jest osobno, bo arkusz podaje wysokość i układ w różnych miejscach - można je też połączyć w jedną.

    Typowe błędy

    Bez clear: both blok główny wjeżdża pod pływające nagłówki - w inspektorze bloki na siebie zachodzą i punkt za układ przepada.

    styl.css CSS zmienione: 6 linii
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    Podgląd strony po tym kroku (index.php)
  29. Krok 29: Blok główny: tło i marginesy wewnętrzne

    Kryteria:

    R.4.2 kolor tła: blok główny - #E0F2F1

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła #E0F2F1, marginesy wewnętrzne 100 px

    Marginesy wewnętrzne to padding - jasnozielone tło sięga do krawędzi bloku, a treść zaczyna się 100 px od nich. Pusty blok główny ma i tak 200 px wysokości.

    styl.css CSS zmienione: 4 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    Podgląd strony po tym kroku (index.php)
  30. Krok 30: Blok sekcji: wysokość i ukrywanie nadmiaru

    Kryteria: ,

    R.4.3 wysokość: bloki nagłówkowe, stopki 100px, blok sekcji 90px

    R.4.6 przepełnienie bloków: blok sekcji - overfow: hidden

    ok. 1 min
    Polecenie z arkusza

    Dla bloku sekcji: wysokość 90 px, w przypadku przepełnienia bloku zawartość, która się w nim nie mieści jest ukryta

    overflow: hidden obcina wszystko, co wystaje poza 90 px - z dziesięciu miniatur widać tylko pierwszy rząd, a drugi znika, jak na ilustracji 2. To zamyka kryterium wysokości (R.4.3).

    styl.css CSS zmienione: 4 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    section {
        height: 90px;
        overflow: hidden;
    }
    Podgląd strony po tym kroku (index.php)
  31. Krok 31: Klasa miniatury

    Kryteria:

    R.4.4 styl klasy .miniatury : wysokość 90px

    ok. 1 min
    Polecenie z arkusza

    Dla klasy miniatury przypisanej do obrazów generowanych skryptem 2: wysokość 90 px

    Selektor klasy zaczyna się kropką: .miniatury. Nazwę narzuca klucz, więc zostaje po polsku. Szerokości nie podajesz - przeglądarka dobierze ją z proporcji zdjęcia.

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    section {
        height: 90px;
        overflow: hidden;
    }
    .miniatury {
        height: 90px;
    }
    Podgląd strony po tym kroku (index.php)
  32. Krok 32: Elementy listy do lewej

    Kryteria:

    R.4.8 wyrównanie tekstu: selektor li - do lewej strony

    ok. 1 min
    Polecenie z arkusza

    Dla selektora elementu listy: wyrównanie tekstu do lewej strony

    Selektor li nadpisuje środkowanie z * tylko dla elementów listy w stopce.

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    section {
        height: 90px;
        overflow: hidden;
    }
    .miniatury {
        height: 90px;
    }
    li {
        text-align: left;
    }
    Podgląd strony po tym kroku (index.php)
  33. Krok 33: Odstęp przed nazwami szczytów

    Kryteria:

    R.4.7 marginesy wewnętrzne (padding ): blok główny 100px, selektor span padding-left: 30px

    ok. 1 min
    Polecenie z arkusza

    Dla selektora span: margines wewnętrzny lewy 30 px

    Margines wewnętrzny lewy to padding-left. Spany wypisze skrypt 1, każdy z nazwą jednego szczytu - odstęp rozsunie je w wierszu. To zamyka kryterium marginesów wewnętrznych (R.4.7).

    styl.css CSS zmienione: 3 linie
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    section {
        height: 90px;
        overflow: hidden;
    }
    .miniatury {
        height: 90px;
    }
    li {
        text-align: left;
    }
    span {
        padding-left: 30px;
    }
    Podgląd strony po tym kroku (index.php)
  34. Krok 34: Rozmiary nazw: pseudoklasa nth-child

    Kryteria:

    R.4.9 rozmiar czcionki dla pseudoelementu nth-child: Babia Góra(2), Rudawiec(11) - 200%, Śnieżka(3), Lackowa(15) - 150%, Śnieżnik(4), Jagodna(17) - 120%, Tarnica(5), Szczeliniec Wielki(21) - 170%, Radziejowa(7), Ślęża(27) - 130%, Mogielica(9), Kłodzka Góra(25) - 160% (wystarczy dla 4 z 6 par)

    ok. 3 min
    Polecenie z arkusza

    Styl dla kolejnych potomków selektora span: dla 2 i 11: rozmiar czcionki 200%, dla 3 i 15: rozmiar czcionki 150%, dla 4 i 17: rozmiar czcionki 120%, dla 5 i 21: rozmiar czcionki 170%, dla 7 i 27: rozmiar czcionki 130%, dla 9 i 25: rozmiar czcionki 160%

    :nth-child(n) (tabela 4 arkusza) wybiera element, który jest n-tym dzieckiem swojego rodzica. Rodzicem spanów będzie blok główny, w którym skrypt 1 nie wypisze nic poza spanami - drugi span to drugie dziecko. Pary o tym samym rozmiarze łączysz przecinkiem: sześć reguł zamiast dwunastu. Po skrypcie 1 drugi szczyt (Babia Góra) i jedenasty (Rudawiec) będą największe, jak na ilustracji 2.

    Typowe błędy

    Klucz nazywa :nth-child pseudoelementem, ale to pseudoklasa (jeden dwukropek); pseudoelementy, jak ::first-letter, mają dwa dwukropki. Gdyby w bloku głównym przed spanami stał inny element, numeracja przesunęłaby się o jeden.

    styl.css CSS zmienione: 18 linii
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-regular.woff2') format('woff2'),
             url('czcionka/lato-regular.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    @font-face {
        font-family: 'Lato';
        src: url('czcionka/lato-bold.woff2') format('woff2'),
             url('czcionka/lato-bold.woff') format('woff');
        font-weight: bold;
        font-style: normal;
    }
    * {
        font-family: Lato, sans-serif;
        text-align: center;
        color: #333;
    }
    header, footer {
        height: 100px;
    }
    #logo, #contact {
        width: 30%;
    }
    #title, #author {
        width: 70%;
    }
    header, footer {
        float: left;
    }
    main {
        clear: both;
    }
    main {
        background-color: #E0F2F1;
        padding: 100px;
    }
    section {
        height: 90px;
        overflow: hidden;
    }
    .miniatury {
        height: 90px;
    }
    li {
        text-align: left;
    }
    span {
        padding-left: 30px;
    }
    span:nth-child(2), span:nth-child(11) {
        font-size: 200%;
    }
    span:nth-child(3), span:nth-child(15) {
        font-size: 150%;
    }
    span:nth-child(4), span:nth-child(17) {
        font-size: 120%;
    }
    span:nth-child(5), span:nth-child(21) {
        font-size: 170%;
    }
    span:nth-child(7), span:nth-child(27) {
        font-size: 130%;
    }
    span:nth-child(9), span:nth-child(25) {
        font-size: 160%;
    }
    Podgląd strony po tym kroku (index.php)
  35. Etap 4: Skrypty PHP

    Kroki 35-45 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 35: Połączenie z bazą i zamknięcie na końcu

    Kryteria:

    R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy korona oraz ostatnią operacją na bazie jest jej zamknięcie

    ok. 2 min
    Polecenie z arkusza

    Łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie korona. Na końcu skrypt zamyka połączenie z bazą

    Na stronie głównej pierwszy skrypt stoi w bloku głównym, więc tam otwierasz połączenie: mysqli_connect z czterema argumentami łączy się z serwerem i od razu wybiera bazę. Uchwyt w zmiennej $connection. Ostatni blok PHP, w sekcji, na razie tylko zamyka połączenie - skrypt 2 dopiszesz nad tą linią (R.5.1). Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.

    index.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
            ?>
        </main>
        <section>
            <?php
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  36. Krok 36: Skrypt 1: zapytanie 1

    Kryteria:

    R.5.2 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1 lub skrypt 2 zawiera instrukcję wysyłającą do bazy danych zapytanie 2

    ok. 1 min
    Polecenie z arkusza

    Skrypt 1, na stronie index.php: Wysyła do bazy danych zapytanie 1

    Treść zapytania w zmiennej $query, mysqli_query wysyła ją do bazy, a w $result zostaje wynik do odczytania wiersz po wierszu.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
            ?>
        </main>
        <section>
            <?php
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>

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

  37. Krok 37: Skrypt 1: nazwy szczytów w znacznikach span

    Kryteria: ,

    R.2.9 Na stronie index.php znajduje się przynajmniej jeden znacznik <span> (w HTML lub skrypcie )

    R.5.3 Skrypt 1 wyświetla wszystkie zwrócone zapytaniem nazwy szczytów zapisanych w kolejnych znacznikach <span> (od Rysów do Łysicy)

    ok. 2 min
    Polecenie z arkusza

    Każdą zwróconą zapytaniem nazwę szczytu wyświetla w znaczniku <span>, tak że jest ona odnośnikiem do pliku szczyty.php oraz przekazuje do tego pliku metodą GET id szczytu

    Najpierw same nazwy: mysqli_fetch_row oddaje wiersz jako tablicę ($row[0] - id, $row[1] - nazwa), a pętla while przechodzi przez wszystkie 28. Każda nazwa w osobnym <span> - w podglądzie od Rysów do Łysicy, a reguły :nth-child już działają: Babia Góra i Rudawiec są największe.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<span>$row[1]</span>";
                }
            ?>
        </main>
        <section>
            <?php
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  38. Krok 38: Skrypt 1: odnośnik z identyfikatorem w adresie

    Kryteria: ,

    R.3.4 Przynajmniej jeden odnośnik ze strony głównej otwiera stronę szczyty.php (w skrypcie lub w HTML )

    R.5.4 Po kliknięciu nazwy szczytu na stronie głównej otwierana jest podstrona, do której przekazywany jest parametr metodą GET. Adres URL ma postać: szczyty.php?id=<wartość> i działa co najmniej dla 2 szczytów

    ok. 2 min
    Polecenie z arkusza

    Każdą zwróconą zapytaniem nazwę szczytu wyświetla w znaczniku <span>, tak że jest ona odnośnikiem do pliku szczyty.php oraz przekazuje do tego pliku metodą GET id szczytu

    Nazwę owijasz w <a> wewnątrz spana. Parametr GET doklejasz do adresu po znaku zapytania (tabela 2 arkusza): szczyty.php?id=1 dla Rysów, szczyty.php?id=9 dla Babiej Góry. Cudzysłowy atrybutu wewnątrz napisu PHP poprzedzasz ukośnikiem \". Odnośnik jest ciemnoszary, a nie niebieski: selektor * obejmuje każdy element, także <a>, i ustawia mu kolor #333 wprost (nie przez dziedziczenie), więc nadpisuje domyślny kolor odnośników. Podkreślenie zostaje.

    index.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<span><a href=\"szczyty.php?id=$row[0]\">$row[1]</a></span>";
                }
            ?>
        </main>
        <section>
            <?php
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  39. Krok 39: Skrypt 2: zapytanie 2

    ok. 1 min
    Polecenie z arkusza

    Skrypt 2: Wysyła do bazy danych zapytanie 2

    Skrypt 2 stoi w bloku sekcji. Połączenie jest otwarte od skryptu 1, więc od razu wysyłasz zapytanie 2; zamknięcie zostaje ostatnią linią.

    index.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<span><a href=\"szczyty.php?id=$row[0]\">$row[1]</a></span>";
                }
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>

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

  40. Krok 40: Skrypt 2: miniatury z bazy

    Kryteria: , ,

    R.2.10 Przynajmniej jedna grafika z bloku sekcji ma przypisaną klasę miniatury (w HTML lub skrypcie )

    R.5.5 Skrypt 2 zawiera pętlę działającą na wszystkich rekordach zwróconych zapytaniem

    R.5.6 Na stronie głównej są wyświetlane obrazy z plików o nazwach zwróconych w wyniku zapytania oraz tekstach alternatywnych zawierających nazwę szczytu (część obrazów może być ukryta)

    ok. 2 min
    Polecenie z arkusza

    Dla każdego zwróconego zapytaniem rekordu wyświetla obraz, w którym nazwa pliku jest źródłem a nazwa szczytu – tekstem alternatywnym. Każdy obraz ma przypisaną klasę miniatury

    W pętli $row[0] to nazwa pliku (źródło src), a $row[1] - nazwa szczytu (tekst alt). Każdy obraz dostaje class="miniatury", więc ma 90 px wysokości. Dziesięć zdjęć nie mieści się w jednym rzędzie - ostatnie przechodzą do drugiego i znikają za overflow: hidden, jak na ilustracji 2.

    index.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<span><a href=\"szczyty.php?id=$row[0]\">$row[1]</a></span>";
                }
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  41. Krok 41: Strona szczyty.php: połączenie i ten sam skrypt 2

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku sekcji: Efekt działania skryptu 2

    Blok sekcji jest wspólny dla obu stron, więc skrypt 2 kopiujesz do szczyty.php bez zmian. Tu pierwszy skrypt (3) stanie w bloku głównym - tam otwierasz połączenie, a skrypt 2 w sekcji je zamknie. Podgląd pokazuje szczyty.php z pustym blokiem głównym i paskiem miniatur.

    szczyty.php PHP zmienione: 11 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  42. Krok 42: Skrypt 3: zapytanie 3 dla szczytu z adresu

    Kryteria:

    R.5.7 Skrypt 3 (podstrona) zawiera instrukcję wysyłającą do bazy danych zapytanie 3, zmodyfikowane w ten sposób, że wybierany jest rekord o id przesłanym do strony

    ok. 2 min
    Polecenie z arkusza

    Skrypt 3, na stronie szczyty.php (ilustracja 5): Wysyła do bazy danych zapytanie 3, zmodyfikowane w ten sposób, że sprawdzane jest id wysłane z pliku index.php metodą GET

    Identyfikator przyszedł w adresie (szczyty.php?id=1), więc czeka w tablicy $_GET["id"]. Wstaw go do zapytania 3 w miejsce 1. Identyfikator to klucz główny, więc wynik ma najwyżej jeden wiersz i zamiast pętli wystarczy jedno mysqli_fetch_row (dla numeru spoza bazy wiersza nie ma - zajmuje się tym etap „Dobre praktyki”). Od tego kroku podgląd pokazuje stronę otwartą kliknięciem „Rysy”.

    Typowe błędy

    Otwarcie szczyty.php bez ?id= w adresie daje ostrzeżenie „Undefined array key "id"”, a zapytanie z pustym warunkiem kończy się wyjątkiem „Uncaught mysqli_sql_exception” (sprawdzone w PHP 8.2). Klucz tego nie sprawdza - zabezpieczenie jest w etapie „Dobre praktyki”.

    szczyty.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>

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

  43. Krok 43: Skrypt 3: zdjęcie szczytu

    ok. 1 min
    Polecenie z arkusza

    Wyświetla dane zwrócone zapytaniem: Obraz z pliku, którego nazwa została zwrócona, z tekstem alternatywnym „szczyt”

    Pierwsze pole wyniku ($row[0]) to nazwa pliku - rysy.jpg. Tekst alternatywny jest stały: „szczyt”. Zdjęcie nie ma klasy miniatury, więc wyświetla się w naturalnym rozmiarze, jak na ilustracji 5.

    szczyty.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                echo "<img src=\"$row[0]\" alt=\"szczyt\">";
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  44. Krok 44: Skrypt 3: nazwa, wysokość i pasmo

    Kryteria:

    R.5.9 Na podstronie nazwa szczytu jest wyświetlana w <h2>, oraz w <h3>: "wysokość: <wysokosc> metrów n.p.m." i "pasmo górskie: <pasmo>", wartości w <> są pobrane z bazy danych

    ok. 2 min
    Polecenie z arkusza

    Nagłówek drugiego stopnia z nazwą szczytu. Nagłówek trzeciego stopnia o treści: „wysokość: <wysokosc> metrów n.p.m.”. Nagłówek trzeciego stopnia o treści: „pasmo górskie: <pasmo>”, pola <> zostały pobrane z bazy danych

    Kolejne pola wyniku w kolejności z SELECT: $row[1] - nazwa w <h2>, $row[2] - wysokość i $row[3] - pasmo w dwóch <h3> ze stałym tekstem dookoła. Dla Rysów: „wysokość: 2499 metrów n.p.m.” i „pasmo górskie: Tatry”.

    szczyty.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                echo "<img src=\"$row[0]\" alt=\"szczyt\">";
                echo "<h2>$row[1]</h2>";
                echo "<h3>wysokość: $row[2] metrów n.p.m.</h3>";
                echo "<h3>pasmo górskie: $row[3]</h3>";
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  45. Krok 45: Skrypt 3: opis w akapicie

    Kryteria: ,

    R.5.8 Na podstronie wyświetlany jest obraz z pliku o nazwie zwróconej w wyniku zapytania i tekście alternatywnym "szczyt" oraz opis szczytu

    R.5.10 W skryptach zastosowana przynajmniej jedna zmienna oraz nazwy wszystkich zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 1 min
    Polecenie z arkusza

    Paragraf z opisem

    Ostatnie pole ($row[4]) to opis z tabeli opis. Strona szczytu wygląda jak na ilustracji 5. W skryptach są zmienne $connection, $query, $result, $row i $peak - nazwy po angielsku mówią, do czego służą (R.5.10).

    szczyty.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                echo "<img src=\"$row[0]\" alt=\"szczyt\">";
                echo "<h2>$row[1]</h2>";
                echo "<h3>wysokość: $row[2] metrów n.p.m.</h3>";
                echo "<h3>pasmo górskie: $row[3]</h3>";
                echo "<p>$row[4]</p>";
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  46. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 46-48 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 46: Strona szczytu: liczba z adresu, zapytanie przygotowane, brak rekordu

    ok. 4 min
    Polecenie z arkusza

    Wysyła do bazy danych zapytanie 3, zmodyfikowane w ten sposób, że sprawdzane jest id wysłane z pliku index.php metodą GET

    Wersję z egzaminu sprawdzono z trzema adresami. Bez parametru (szczyty.php) PHP zgłasza ostrzeżenie „Undefined array key "id"”, a zapytanie się wysypuje. Z ?id=99 (nie ma takiego szczytu) mysqli_fetch_row zwraca null i każda linia wypisująca $row[...] daje ostrzeżenie „Trying to access array offset on value of type null” - strona pokazuje puste nagłówki. Poprawki: rzutowanie (int) z wartością domyślną 1 (operator ??), zapytanie przygotowane (mysqli_prepare, znak ?, mysqli_stmt_bind_param z typem "i") i sprawdzenie, czy rekord się znalazł. Stara wersja zostaje w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    szczyty.php PHP zmienione: 17 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = (int) ($_GET["id"] ?? 1);
                $statement = mysqli_prepare($connection, "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = ?");
                mysqli_stmt_bind_param($statement, "i", $peak);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                $row = mysqli_fetch_row($result);
                if ($row === null) {
                    echo "<h2>Nie ma szczytu o numerze $peak</h2>";
                } else {
                    echo "<img src=\"$row[0]\" alt=\"szczyt\">";
                    echo "<h2>$row[1]</h2>";
                    echo "<h3>wysokość: $row[2] metrów n.p.m.</h3>";
                    echo "<h3>pasmo górskie: $row[3]</h3>";
                    echo "<p>$row[4]</p>";
                }
                /* Wersja z egzaminu:
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                */
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  47. Krok 47: Opis w akapitach i zdjęcie zastępcze

    ok. 4 min
    Polecenie z arkusza

    Wyświetla dane zwrócone zapytaniem: Obraz z pliku, którego nazwa została zwrócona, z tekstem alternatywnym „szczyt”. Paragraf z opisem

    Dwie usterki danych z arkusza. Po pierwsze 10 opisów ma w środku puste wiersze (znaki końca linii), ale HTML zamienia je na zwykłą spację - opis Babiej Góry zlewa się w jeden blok. preg_split dzieli tekst w miejscach końców linii i każdy kawałek trafia do osobnego <p>. Po drugie Wysoka Kopa ma w bazie plik wysokakopa.jpg, którego nie ma w archiwum - wersja z egzaminu pokazuje wtedy ikonę zepsutego obrazu. file_exists sprawdza, czy plik leży obok skryptu, a jeśli nie, podstawia gora.jpg. Do tego htmlspecialchars dla tekstów z bazy. Podgląd pokazuje Babią Górę (?id=9). Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    szczyty.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = (int) ($_GET["id"] ?? 1);
                $statement = mysqli_prepare($connection, "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = ?");
                mysqli_stmt_bind_param($statement, "i", $peak);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                $row = mysqli_fetch_row($result);
                if ($row === null) {
                    echo "<h2>Nie ma szczytu o numerze $peak</h2>";
                } else {
                    $photo = file_exists($row[0]) ? $row[0] : "gora.jpg";
                    echo "<img src=\"$photo\" alt=\"szczyt\">";
                    echo "<h2>" . htmlspecialchars($row[1]) . "</h2>";
                    echo "<h3>wysokość: $row[2] metrów n.p.m.</h3>";
                    echo "<h3>pasmo górskie: " . htmlspecialchars($row[3]) . "</h3>";
                    foreach (preg_split("/(\r?\n)+/", $row[4]) as $paragraph) {
                        echo "<p>" . htmlspecialchars($paragraph) . "</p>";
                    }
                    // wersja z egzaminu: echo "<p>$row[4]</p>"; (cały opis w jednym akapicie)
                }
                /* Wersja z egzaminu:
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                */
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($row = mysqli_fetch_row($result)) {
                    echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">";
                }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (szczyty.php)
  48. Krok 48: Pola po nazwach i miniatury jako odnośniki

    ok. 3 min
    Polecenie z arkusza

    Dla każdego zwróconego zapytaniem rekordu wyświetla obraz, w którym nazwa pliku jest źródłem a nazwa szczytu – tekstem alternatywnym. Każdy obraz ma przypisaną klasę miniatury

    mysqli_fetch_assoc oddaje wiersz z kluczami takimi jak nazwy kolumn - $photoRow["plik"] mówi więcej niż $row[0]. Do zapytania 2 dokładasz id, żeby każda miniatura prowadziła do strony swojego szczytu (jak nazwy w bloku głównym), a atrybut title pokazuje nazwę po najechaniu kursorem. Teksty z bazy przechodzą przez htmlspecialchars. Skrypt 2 zmieniasz w obu plikach naraz - przy kopii kodu trzeba o tym pamiętać; w większym projekcie trafiłby do osobnego pliku dołączanego include. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    index.php PHP zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $query = "SELECT id, nazwa FROM szczyty ORDER BY wysokosc DESC;";
                $result = mysqli_query($connection, $query);
                while ($peakRow = mysqli_fetch_assoc($result)) {
                    echo "<span><a href=\"szczyty.php?id=" . $peakRow["id"] . "\">" . htmlspecialchars($peakRow["nazwa"]) . "</a></span>";
                }
                // while ($row = mysqli_fetch_row($result)) { echo "<span><a href=\"szczyty.php?id=$row[0]\">$row[1]</a></span>"; }
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT id, plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($photoRow = mysqli_fetch_assoc($result)) {
                    $name = htmlspecialchars($photoRow["nazwa"]);
                    echo "<a href=\"szczyty.php?id=" . $photoRow["id"] . "\"><img src=\"" . $photoRow["plik"] . "\" alt=\"$name\" title=\"$name\" class=\"miniatury\"></a>";
                }
                // while ($row = mysqli_fetch_row($result)) { echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">"; }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    szczyty.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Korona gór polskich</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header id="logo">
            <img src="logo.png" alt="Logo">
        </header>
        <header id="title">
            <h1>Korona Gór Polskich</h1>
        </header>
        <main>
            <?php
                $connection = mysqli_connect("localhost", "root", "", "korona");
                $peak = (int) ($_GET["id"] ?? 1);
                $statement = mysqli_prepare($connection, "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = ?");
                mysqli_stmt_bind_param($statement, "i", $peak);
                mysqli_stmt_execute($statement);
                $result = mysqli_stmt_get_result($statement);
                $row = mysqli_fetch_row($result);
                if ($row === null) {
                    echo "<h2>Nie ma szczytu o numerze $peak</h2>";
                } else {
                    $photo = file_exists($row[0]) ? $row[0] : "gora.jpg";
                    echo "<img src=\"$photo\" alt=\"szczyt\">";
                    echo "<h2>" . htmlspecialchars($row[1]) . "</h2>";
                    echo "<h3>wysokość: $row[2] metrów n.p.m.</h3>";
                    echo "<h3>pasmo górskie: " . htmlspecialchars($row[3]) . "</h3>";
                    foreach (preg_split("/(\r?\n)+/", $row[4]) as $paragraph) {
                        echo "<p>" . htmlspecialchars($paragraph) . "</p>";
                    }
                    // wersja z egzaminu: echo "<p>$row[4]</p>"; (cały opis w jednym akapicie)
                }
                /* Wersja z egzaminu:
                $peak = $_GET["id"];
                $query = "SELECT szczyty.plik, szczyty.nazwa, szczyty.wysokosc, szczyty.pasmo, opis.opis FROM szczyty JOIN opis ON szczyty.id = opis.szczyty_id WHERE szczyty.id = $peak;";
                $result = mysqli_query($connection, $query);
                $row = mysqli_fetch_row($result);
                */
            ?>
        </main>
        <section>
            <?php
                $query = "SELECT id, plik, nazwa FROM szczyty LIMIT 10;";
                $result = mysqli_query($connection, $query);
                while ($photoRow = mysqli_fetch_assoc($result)) {
                    $name = htmlspecialchars($photoRow["nazwa"]);
                    echo "<a href=\"szczyty.php?id=" . $photoRow["id"] . "\"><img src=\"" . $photoRow["plik"] . "\" alt=\"$name\" title=\"$name\" class=\"miniatury\"></a>";
                }
                // while ($row = mysqli_fetch_row($result)) { echo "<img src=\"$row[0]\" alt=\"$row[1]\" class=\"miniatury\">"; }
                mysqli_close($connection);
            ?>
        </section>
        <footer id="contact">
            <h3>Kontakt</h3>
            <ul>
                <li>Zadzwoń do nas: 111 222 333</li>
                <li><a href="mailto:[email protected]">Napisz do nas</a></li>
            </ul>
        </footer>
        <footer id="author">
            <h3>&copy; Wykonane przez: Bartosz Bryniarski</h3>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (index.php)
  49. Etap 6: Oddanie pracy

    Krok 49 · po tym etapie masz 40 z 40 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    UWAGA: 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 przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę.

    W folderze z numerem zdającego: folder czcionka z plikami Lato, 12 zdjęć gór, import.png, index.php, kw1.jpg - kw4.jpg, kwerendy.txt, logo.png, przeglądarka.txt, styl.css, szczyty.php. 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 48.

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.