Przejdź do głównej treści
INF.03-01-25.06-SGCzerwiec 2025 · 58 kroków · ok. 118 min · 41 kryteriów z klucza

Rozwiązanie krok po kroku: Ranking gier komputerowych (Wersja podstawowa)

Rozwiązanie buduje portal z rankingiem gier komputerowych: baza gry z czterema kwerendami (w tym INSERT z danymi z pliku), grafika przeskalowana do 550 px szerokości, strona gry.php w trzech kolumnach ze stylami w styl.css (z zapytaniem @media dla wąskich ekranów) i cztery skrypty PHP: ranking top 5, galeria gier, opis wybranej gry i dodawanie nowej gry z formularza.

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 zostaje przerobiony na wersję, jaką pisze się w prawdziwych projektach: zapytania przygotowane z bindowaniem parametrów i escapowanie danych przed wypisaniem. W tym arkuszu nie ma JavaScriptu.

Obok jest druga wersja tego rozwiązania - zakładka Nowoczesny kod (grid, PDO): te same punkty, ale układ na siatce CSS, PHP na PDO z zapytaniami przygotowanymi od pierwszej linijki i logika oddzielona od HTML.

Zdjęcia, baza i plik rekord.txt pochodzą z prawdziwego archiwum pliki1 (załącznik do pobrania na stronie 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 41 kryteriów (R.1.1 - R.5.10), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 31 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 41 kryteriów (pkt)

    Krok 1: Baza danych gry

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych gry, czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

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

    W przeglądarce otwierasz http://localhost/phpmyadmin, klikasz Nowa w lewym panelu, wpisujesz nazwę gry i z listy metod porównywania wybierasz utf8_unicode_ci (arkusz podaje ją jako przykład; utf8_polish_ci też jest poprawne). Tabela gry z pliku SQL ma jednak zestaw i porównywanie zapisane we własnej definicji (utf8, utf8_unicode_ci), więc opisy gier zachowają ogonki przy każdym wyborze - ustawienie bazy dziedziczą tylko tabele zakładane później bez własnego ustawienia.

    Typowe błędy

    Nazwa bazy musi być dokładnie gry - skrypty PHP łączą się z bazą po nazwie, więc Gry albo gra odetnie punkty także za skrypty (R.5.1).

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

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych gry, czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

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

    Wejdź do bazy gry (musi być zaznaczona w lewym panelu), karta Import, Wybierz plik → baza.sql z rozpakowanego archiwum, Wykonaj.

    Po imporcie w bazie jest jedna tabela z ilustracji 1: gry z kolumnami id (klucz główny z autonumeracją), nazwa, opis, punkty, cena i zdjecie - 8 wierszy. Kolumna zdjecie trzyma nazwę pliku graficznego (np. Mag.jpg), a same pliki są w archiwum - dlatego arkusz zaleca trzymać grafiki w tym samym folderze co gry.php.

    Typowe błędy

    Import bez wcześniejszego wejścia do bazy gry tworzy tabelę w innej bazie (np. test) - skrypty nie znajdą wtedy tabeli.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import tabel do bazy danych gry, czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG pod nazwą import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań.

    Klawisz Print Screen (cały ekran, nie Alt+PrtScr, który łapie tylko aktywne okno), wklejasz do edytora grafiki i zapisujesz jako import.png w folderze z numerem zdającego. Na zrzucie ma być widać komunikat phpMyAdmin o pomyślnym imporcie albo tabelę gry w bazie.

    Uwaga na formaty w tym arkuszu: zrzut importu w PNG, zrzuty kwerend w JPEG - odwrotnie niż w wielu innych arkuszach.

    Typowe błędy

    Wykadrowany zrzut (samo okno przeglądarki, bez paska zadań) nie jest oceniany - klucz mówi to wprost.

  4. Krok 4: Zapytanie 1: id, nazwa i zdjęcie

    Kryteria: ,

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

    R.1.3 Wykonane zapytanie 1 wybierające jedynie id, nazwę i zdjęcie z tabeli gry. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa, zdjecie FROM gry; oraz wynik działania udokumentowany zrzutem, na którym jest widocznych minimum 8 rekordów, jedynie Pola id, nazwa, zdjecie

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie id, nazwę i zdjęcie z tabeli gry.

    Zakładka SQL w phpMyAdmin (przy zaznaczonej bazie gry). Klauzula po klauzuli:

    • SELECT id, nazwa, zdjecie - które kolumny ma zwrócić wynik. „Jedynie” oznacza dokładnie te trzy; SELECT * zwróciłby też opis, punkty i cenę.
    • FROM gry - z której tabeli.

    Bez WHERE, bo zapytanie dotyczy wszystkich gier. Wynik: 8 wierszy. Zapytanie kopiujesz do pliku kwerendy.txt (zwykły edytor tekstu) i robisz zrzut całego ekranu: kw1.jpg. To samo zapytanie wyśle później skrypt 2, żeby zbudować galerię.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT id, nazwa, zdjecie FROM gry;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: gra o id 1 ze skróconym opisem

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające jedynie nazwę, pierwsze 100 znaków opisu, punkty oraz cenę z tabeli gry dla wiersza o id = 1. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id=1; oraz wynik działania udokumentowany zrzutem, na którym jest widoczny dokładnie jeden rekord, jedynie pola nazwa, opis, punkty, cena. Zastosowana jest funkcja obcinająca opis do pierwszych 100 znaków

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie nazwę, pierwsze 100 znaków opisu, punkty oraz cenę z tabeli gry dla wiersza o id równym 1.

    • SELECT nazwa, LEFT(opis, 100), punkty, cena - cztery wartości. „Pierwsze 100 znaków opisu” to funkcja LEFT(opis, 100) z tabeli 2 arkusza: zwraca 100 znaków od lewej strony napisu.
    • FROM gry - tabela.
    • WHERE id = 1 - tylko wiersz o kluczu 1. Liczbę porównujesz bez cudzysłowu.

    Wynik: dokładnie jeden wiersz (Czarodziejka, 45 punktów, cena 100). Zrzut: kw2.jpg. Zmodyfikowaną wersję tego zapytania (z id z formularza) wyśle skrypt 3.

    Typowe błędy

    SUBSTRING(opis, 1, 100) daje ten sam wynik i klucz go przyjmie, ale arkusz podpowiada LEFT w tabeli 2 - nie ma powodu szukać dalej.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, nazwa, zdjecie FROM gry;
    
    -- Zapytanie 2
    SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = 1;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: pięć gier z najwyższą punktacją

    Kryteria:

    R.1.5 Wykonane zapytanie 3 wybierające jedynie pierwsze pięć wierszy o najwyższej punktacji zawierające jedynie nazwę i punkty z tabeli gry. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5; oraz wynik działania udokumentowany zrzutem, na którym widocznych jest dokładnie 5 rekordów, jedynie pola nazwa i punkty, punkty posortowane malejąco

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola nazwa i punkty z pięciu pierwszych wierszy o najwyższej punktacji z tabeli gry.

    • SELECT nazwa, punkty FROM gry - dwie kolumny z tabeli gier.
    • ORDER BY punkty DESC - sortowanie malejąco po punktach, żeby najwyższa punktacja była na górze. Domyślne ASC dałoby najsłabsze gry.
    • LIMIT 5 - tylko pięć pierwszych wierszy po posortowaniu.

    Wynik: Mag 357, Księżniczka Persji 293, Kalipso 125, Wyprawa Na Księżyc 103, Nieznany Ląd 96. Zrzut: kw3.jpg. To zapytanie wyśle skrypt 1 do listy „Top 5”.

    Typowe błędy

    LIMIT 5 bez ORDER BY zwraca pięć dowolnych wierszy (w praktyce pierwsze wstawione) - to nie jest „pięć o najwyższej punktacji”.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT id, nazwa, zdjecie FROM gry;
    
    -- Zapytanie 2
    SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = 1;
    
    -- Zapytanie 3
    SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: nowa gra z pliku rekord.txt

    Kryteria:

    R.1.6 Wykonane zapytanie 4 wstawiające wiersz do tabeli gry o danych zawartych w pliku rekord.txt. Sprawdzając można pominąć zgodność pola opis. Klucz główny nadawany automatycznie. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO `gry`(`nazwa`, `opis`, `punkty`, `cena`, `zdjecie`) VALUES ('Zamczysko','...','200','50','zamczysko.jpg'); (możliwe różne warianty zapytania) oraz wynik działania udokumentowany zrzutem, na którym jest widoczny komunikat o poprawnym wykonaniu zapytania lub tabela z wstawionym wierszem

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 4: wstawiające do tabeli gry wiersz o danych zawartych w pliku rekord.txt (dane należy skopiować z pliku do zapytania). Klucz główny nadawany automatycznie.

    Wstawianie wiersza to INSERT INTO gry (...) VALUES (...). W nawiasie po nazwie tabeli wymieniasz kolumny bez id - klucz główny ma autonumerację, więc baza sama nada mu wartość 9. Wartości w VALUES w tej samej kolejności: nazwa i opis w apostrofach (napisy), punkty i cena jako liczby, nazwa pliku zdjęcia w apostrofach.

    Dane kopiujesz z rekord.txt: nazwa „Zamczysko”, opis, „Punkty: 200”, „Cena: 50 zł” (do bazy trafia sama liczba 50) i zamczysko.jpg. Zrzut kw4.jpg ma pokazać komunikat o wstawieniu wiersza albo tabelę z nowym rekordem.

    Typowe błędy

    Plik rekord.txt w archiwum jest zapisany w kodowaniu Windows-1250 - otwarty w edytorze ustawionym na UTF-8 pokaże krzaki zamiast „ó”, „ę”, „ż”. Otwórz go w Notatniku (rozpozna kodowanie) albo przełącz kodowanie w edytorze, zanim skopiujesz opis. Klucz pozwala pominąć zgodność opisu, ale nazwa i liczby muszą się zgadzać.

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT id, nazwa, zdjecie FROM gry;
    
    -- Zapytanie 2
    SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = 1;
    
    -- Zapytanie 3
    SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;
    
    -- Zapytanie 4
    INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie)
    VALUES ('Zamczysko', 'Na odludziu stoi opuszczone zamczysko, w którym znajduje się skarb strzeżony przez złowrogie demony i duchy', 200, 50, 'zamczysko.jpg');
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Przeskalowanie grafiki zamczysko.jpg

    Kryteria:

    R.2.1 Plik zamczysko.jpg przeskalowany zachowując proporcje do szerokości 550 px odpowiadająca temu wysokość wynosi 309 px (± 5 px)

    ok. 3 min
    Polecenie z arkusza

    Plik zamczysko.jpg, wypakowany z archiwum, należy przeskalować zachowując proporcje do szerokości 550 px.

    Plik z archiwum ma 640 × 360 px. W edytorze grafiki rastrowej (np. GIMP: Obraz → Skaluj obraz) wpisujesz szerokość 550 px przy zamkniętym łańcuchu proporcji. Wysokość przeliczy się sama na 309 px (360 · 550 / 640 = 309,4) - i dokładnie to sprawdza egzaminator (309 ±5 px). Zapisz jako zamczysko.jpg w folderze zdającego, obok pozostałych zdjęć gier.

    Typowe błędy

    Rozłączony łańcuch proporcji = obraz ściśnięty do 550 px szerokości przy starej wysokości 360 px. Szerokość się zgadza, punktu nie ma.

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

    Kryteria:

    R.2.2 W pliku gry.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 2 min
    Polecenie z arkusza

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

    W edytorze zaznaczającym składnię tworzysz plik gry.php w folderze zdającego, obok zdjęć. Rozszerzenie .php, bo dojdą skrypty PHP - na razie to czysty HTML.

    Pierwsza linia <!DOCTYPE html> mówi przeglądarce, że dokument jest w HTML5. Dalej szkielet każdej strony: <html>, a w nim <head> (informacje o stronie) i <body> (to, co widać w oknie).

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

    Kryteria:

    R.2.2 W pliku gry.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    Atrybut lang="pl" w znaczniku <html>. Czytnik ekranu czyta wtedy tekst polską wymową, a przeglądarka dobiera słownik. Na stronie nic się nie zmienia - to informacja dla programów.

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

    Kryteria:

    R.2.2 W pliku gry.php zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwsza rzecz w <head>. „Jawnie” znaczy: wpisane w kodzie, nie zdane na domysł przeglądarki. Bez tej linii „Księżniczka Persji” z bazy mogłaby wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8.

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

    Kryteria:

    R.2.3 Nadany tytuł strony: Gry komputerowe

    ok. 1 min
    Polecenie z arkusza

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

    <title> w <head> - arkusz sam podpowiada, gdzie go szukać: na karcie przeglądarki. To nie jest nagłówek na stronie (ten dojdzie w <header>). Klucz sprawdza dokładnie tekst „Gry komputerowe”.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  13. Krok 13: 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

    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"> w <head>. Plik styl.css napiszesz po HTML - połączenie może już być, zadziała, gdy plik pojawi się w tym samym folderze.

    Typowe błędy

    <link> to znacznik pusty - w HTML5 bez </link> i bez ukośnika />. Bez rel="stylesheet" przeglądarka nie potraktuje pliku jako stylów.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  14. Krok 14: Bloki semantyczne

    Kryteria:

    R.2.4 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header, section + section + section, footer

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

    Z ilustracji 3: na górze blok nagłówkowy, pod nim trzy sekcje obok siebie (lewa, środkowa, prawa), na dole stopka. Klucz R.2.4 wymienia znaczniki wprost: <header>, trzy razy <section>, <footer> - z tabeli 3 arkusza.

    Sekcje dostają identyfikatory left, middle, right, bo każda będzie stylowana inaczej. Nazwy identyfikatorów, klas i zmiennych piszesz w tym rozwiązaniu po angielsku (arkusz dopuszcza polski lub angielski, wymaga konsekwencji); wyjątkiem są nazwy narzucone przez arkusz (gry.php, styl.css, kolumny bazy). To, że sekcje staną obok siebie, zrobi CSS.

    Typowe błędy

    Pięć zwykłych <div> wygląda na stronie identycznie, ale kryterium R.2.4 wymaga znaczników semantycznych - sprawdzane w kodzie źródłowym.

    gry.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  15. Krok 15: Nagłówek strony

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: nagłówek pierwszego stopnia o treści „Ranking gier komputerowych”.

    Pierwszego stopnia to <h1>. Egzaminator sprawdza dokładnie ten znacznik, który wskazał arkusz - w innych sekcjach będą <h3>, więc nie mieszaj stopni.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  16. Krok 16: Sekcja lewa: nagłówek „Top 5 gier w tym miesiącu”

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji lewej: nagłówek trzeciego stopnia o treści: „Top 5 gier w tym miesiącu”.

    Trzeciego stopnia to <h3>, w sekcji left. Klucz R.2.5 wymaga w sekcji lewej przynajmniej jednego <h3> z podanych treści - dajesz wszystkie trzy, zgodnie z arkuszem.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  17. Krok 17: Sekcja lewa: lista punktowana

    Kryteria:

    R.2.6 W sekcji lewej umieszczona jedna lista punktowana, zastosowane znaczniki <ul>, <li> (wygenerowana skryptem lub w HTML)

    ok. 1 min
    Polecenie z arkusza

    Lista punktowana (nieuporządkowana) wypełniona przez skrypt 1.

    Lista nieuporządkowana to <ul>; jej elementy <li> dopisze skrypt 1 na podstawie zapytania 3, więc na razie jest pusta. Klucz R.2.6 przyjmuje listę wygenerowaną skryptem - ważne, żeby w wynikowym HTML były <ul> i <li>.

    Typowe błędy

    <ol> to lista uporządkowana (numerowana). Arkusz mówi „punktowana (nieuporządkowana)”, czyli <ul> z kropkami - tak jak na ilustracji 2.

    gry.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  18. Krok 18: Sekcja lewa: nagłówek „Nasz sklep”

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Nagłówek trzeciego stopnia o treści: „Nasz sklep”.

    Drugi <h3> w sekcji lewej, pod listą.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  19. Krok 19: Sekcja lewa: odnośnik do sklepu

    Kryteria:

    R.3.3 Odnośnik o treści „Tu kupisz gry” inicjuje otwarcie strony http://sklep.gry.pl ( lub https://)

    ok. 1 min
    Polecenie z arkusza

    Odnośnik o treści „Tu kupisz gry” prowadzący do adresu http://sklep.gry.pl.

    Odnośnik to <a>: adres w atrybucie href, tekst między znacznikami. Adres przepisujesz z arkusza w całości, z http:// - bez protokołu przeglądarka potraktowałaby sklep.gry.pl jako plik w folderze strony. W podglądzie kliknięcie jest zablokowane (podgląd pokazuje jedną stronę), na egzaminie link otwiera sklep.

    Typowe błędy

    href="sklep.gry.pl" (bez http://) to ścieżka względna - przeglądarka szuka pliku sklep.gry.pl obok gry.php i dostaje 404. R.3.3 przepada.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  20. Krok 20: Sekcja lewa: nagłówek „Stronę wykonał”

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Nagłówek trzeciego stopnia o treści: „Stronę wykonał”.

    Trzeci <h3> w sekcji lewej.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  21. Krok 21: Sekcja lewa: paragraf z numerem zdającego

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Paragraf z numerem zdającego.

    Paragraf <p> pod nagłówkiem. W tym rozwiązaniu stoi tu nazwisko autora - na egzaminie wpisujesz w to miejsce swój numer zdającego (PESEL), bo klucz R.2.5 sprawdza paragraf na stronie. Sekcja lewa jest kompletna.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  22. Krok 22: Sekcja prawa: nagłówek „Dodaj nową grę”

    Kryteria:

    R.2.5 W bloku nagłówkowym zapisany nagłówek <h1>: "Ranking gier komputerowych", w sekcji lewej przynajmniej jeden <h3> z: "Top 5 gier w tym miesiącu" lub "Nasz sklep", lub "Stronę wykonał", w sekcji prawej <h3>: "Dodaj nową grę" oraz zapisany na stronie przynajmniej jeden paragraf

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji środkowej: efekt działania skryptu 2. Zawartość sekcji prawej: nagłówek trzeciego stopnia o treści: „Dodaj nową grę”.

    Sekcja środkowa zostaje w HTML pusta - wypełni ją w całości skrypt 2 (galeria gier z bazy). Przejdź do sekcji prawej: <h3> z treścią z arkusza.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  23. Krok 23: Sekcja prawa: formularz

    Kryteria:

    R.3.4 Przynajmniej jeden formularz wysyła dane do tego samego pliku metodą POST (poprawne również bez atrybutu action)

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyłający dane do tego samego pliku metodą bezpieczną.

    „Metoda bezpieczna” w rozumieniu arkusza to POST - dane nie pojawiają się w adresie strony, jak przy GET. W specyfikacji HTTP „bezpieczne” są co prawda metody, które niczego nie zmieniają na serwerze (GET i HEAD), ale arkusz używa tego słowa w innym sensie, a klucz wymaga POST. „Do tego samego pliku” to brak atrybutu action (przeglądarka wysyła formularz na adres bieżącej strony) albo action="gry.php" - klucz przyjmuje oba warianty.

    Typowe błędy

    method="get" (albo brak method, bo GET jest domyślny) wyśle dane w adresie - arkusz i klucz wymagają tu POST, a skrypt czytający $_POST nic nie dostanie.

    gry.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  24. Krok 24: Formularz: pierwsze pole z etykietą

    Kryteria:

    R.2.7 W sekcji prawej umieszczony formularz z czterema polami edycyjnymi i przyciskiem "DODAJ". Zastosowany znacznik <form> oraz przynajmniej jedna etykieta <label>

    ok. 2 min
    Polecenie z arkusza

    Formularz zawiera cztery pola edycyjne podpisane etykietami: nazwa, opis, cena, zdjęcie oraz przycisk DODAJ, rozmieszczone zgodnie z ilustracją 2.

    Zacznij od pola „nazwa”. Etykieta to <label>; atrybut for wskazuje id pola, dzięki czemu kliknięcie w napis ustawia kursor w polu (klucz R.2.7 wymaga przynajmniej jednej etykiety <label>). Pole edycyjne to <input type="text"> z atrybutem name - pod tą nazwą wartość trafi do PHP.

    Na ilustracji 2 etykieta stoi nad polem, a pola jedno pod drugim - stąd <br> po etykiecie i po polu. Atrybuty id i name po angielsku (name), etykieta po polsku, bo jej treść narzuca arkusz.

    Typowe błędy

    <label>nazwa</label> bez for jest poprawnym HTML, ale nie łączy się z polem - klucz przyjmie, użytkownik straci klik w etykietę. Zawsze for = id pola.

    gry.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  25. Krok 25: Formularz: pola opis, cena, zdjęcie

    Kryteria:

    R.2.7 W sekcji prawej umieszczony formularz z czterema polami edycyjnymi i przyciskiem "DODAJ". Zastosowany znacznik <form> oraz przynajmniej jedna etykieta <label>

    ok. 2 min
    Polecenie z arkusza

    Formularz zawiera cztery pola edycyjne podpisane etykietami: nazwa, opis, cena, zdjęcie oraz przycisk DODAJ, rozmieszczone zgodnie z ilustracją 2.

    Trzy kolejne pary etykieta + pole według tego samego wzoru: description, price, image. Nazwy pól (name) odpowiadają temu, co skrypt 4 wstawi do kolumn opis, cena, zdjecie w bazie.

    gry.php PHP zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  26. Krok 26: Formularz: przycisk DODAJ

    Kryteria: ,

    R.2.7 W sekcji prawej umieszczony formularz z czterema polami edycyjnymi i przyciskiem "DODAJ". Zastosowany znacznik <form> oraz przynajmniej jedna etykieta <label>

    R.3.5 Przycisk z przynajmniej jednego formularza wysyła dane do skryptu (input z typem submit lub button)

    ok. 1 min
    Polecenie z arkusza

    Formularz zawiera cztery pola edycyjne podpisane etykietami: nazwa, opis, cena, zdjęcie oraz przycisk DODAJ, rozmieszczone zgodnie z ilustracją 2.

    <button type="submit">DODAJ</button> wewnątrz formularza wysyła go po kliknięciu. Klucz R.3.5 przyjmuje też <input type="submit" value="DODAJ">. Sekcja prawa jest kompletna.

    gry.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  27. Krok 27: Stopka: formularz

    Kryteria:

    R.3.4 Przynajmniej jeden formularz wysyła dane do tego samego pliku metodą POST (poprawne również bez atrybutu action)

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: formularz wysyłający dane do tego samego pliku metodą bezpieczną.

    Drugi formularz na stronie, tak samo method="post" bez action. Dwa formularze w jednym pliku to nic złego - PHP rozpozna po nazwach pól, który został wysłany.

    gry.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  28. Krok 28: Stopka: pole i przycisk „Pokaż opis”

    Kryteria: ,

    R.2.8 W stopce umieszczony formularz z jednym polem edycyjnym i przyciskiem "Pokaż opis". Zastosowany znacznik <form>

    R.3.5 Przycisk z przynajmniej jednego formularza wysyła dane do skryptu (input z typem submit lub button)

    ok. 1 min
    Polecenie z arkusza

    Formularz zawiera pole edycyjne i przycisk o treści „Pokaż opis”. Efekt działania skryptu 3.

    Jedno pole tekstowe name="game_id" (tu użytkownik wpisze id gry) i przycisk <button type="submit"> z treścią z arkusza. Efekt działania skryptu 3 (nagłówek i opis gry) pojawi się pod formularzem - dopisze go PHP. Struktura HTML strony jest kompletna - dalej style.

    gry.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  29. Etap 3: Styl CSS

    Kroki 29-39 · po tym etapie masz 29 z 41 kryteriów (pkt)

    Krok 29: Plik styl.css: krój i kolor czcionki

    Kryteria:

    R.4.1 Ustawione domyślne formatowanie wszystkich selektorów (dla *): krój czcionki Garamond, biały kolor czcionki

    ok. 2 min
    Polecenie z arkusza

    Domyślne formatowanie wszystkich selektorów: krój czcionki Garamond, biały kolor czcionki.

    Utwórz plik styl.css obok gry.php. „Wszystkie selektory” to selektor uniwersalny *. font-family: Garamond ustawia krój, color: white kolor tekstu (czcionki), nie tła. Biały tekst na razie znika na białym tle - to normalne, tła dojdą w kolejnych krokach.

    Uwaga z arkusza: przycisk może nie odziedziczyć białego koloru i zostać czarny - to nie jest błąd.

    styl.css CSS nowy plik
    * {
        font-family: Garamond;
        color: white;
    }
    Podgląd strony po tym kroku (gry.php)
  30. Krok 30: Blok nagłówkowy: tło, wyrównanie, margines wewnętrzny

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła Indigo dla bloków: bloku nagłówkowego, sekcji lewej, prawej i stopki oraz czarny kolor tła dla sekcji środkowej

    R.4.6 Ustawione wyrównanie tekstu do środka dla bloku nagłówkowego

    R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 2px, dla elementu listy 5px oraz marginesy zewnętrzne (margin) dla pola edycyjnego 10px

    ok. 2 min
    Polecenie z arkusza

    Dla bloku nagłówkowego: kolor tła Indigo, wyrównanie tekstu do środka, marginesy wewnętrzne 2 px.

    Selektor header. Kolor nazwany Indigo przepisujesz z arkusza. Margines wewnętrzny to padding (zewnętrzny byłby margin). Nagłówek pojawia się w podglądzie jako fioletowy pas z białym tytułem.

    Typowe błędy

    margin: 2px zamiast padding: 2px - odstęp będzie na zewnątrz fioletowego pola. Kryterium R.4.7 mówi o marginesach wewnętrznych.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    Podgląd strony po tym kroku (gry.php)
  31. Krok 31: Sekcje lewa i prawa: tło i wysokość

    Kryteria: ,

    R.4.2 Ustawiony kolor tła Indigo dla bloków: bloku nagłówkowego, sekcji lewej, prawej i stopki oraz czarny kolor tła dla sekcji środkowej

    R.4.4 Ustawiona wysokość sekcji lewej, środkowej i prawej 600px oraz stopki 150px

    ok. 1 min
    Polecenie z arkusza

    Dla sekcji lewej i prawej: kolor tła Indigo, wysokość 600 px.

    Wspólne cechy dwóch sekcji piszesz raz - selektory identyfikatorów rozdzielone przecinkiem #left, #right. Krzyżyk = id z HTML. Sekcje są jeszcze jedna pod drugą - obok siebie ustawisz je za chwilę.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
    }
    Podgląd strony po tym kroku (gry.php)
  32. Krok 32: Sekcja środkowa: tło, wysokość, paski przewijania

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła Indigo dla bloków: bloku nagłówkowego, sekcji lewej, prawej i stopki oraz czarny kolor tła dla sekcji środkowej

    R.4.4 Ustawiona wysokość sekcji lewej, środkowej i prawej 600px oraz stopki 150px

    R.4.8 Ustawione dla sekcji środkowej zawsze widoczne paski przewijania (overflow: scroll;)

    ok. 2 min
    Polecenie z arkusza

    Dla sekcji środkowej: czarny kolor tła, wysokość 600 px, zawsze widoczne paski przewijania.

    Selektor #middle. „Zawsze widoczne paski przewijania” to overflow: scroll - klucz R.4.8 podaje tę wartość wprost. auto pokazywałby paski dopiero przy przepełnieniu, a tego arkusz tu nie chce (odwrotnie niż w wielu innych arkuszach - czytaj uważnie).

    Typowe błędy

    overflow: auto przy pustej sekcji nie pokaże pasków - R.4.8 wymaga scroll.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
    }
    Podgląd strony po tym kroku (gry.php)
  33. Krok 33: Sekcje obok siebie: 20%, 60%, 20%

    Kryteria: ,

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu dla ekranów o szerokości większej niż 800 px. Blok środkowy może być pusty. (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid)

    R.4.5 Sekcje lewa, środkowa i prawa są wyświetlane obok siebie jeśli ekran jest szerszy niż 800px - odpowiednio szerokości 20%, 60%, 20%, a w przeciwnym wypadku są wyświetlane jedna pod drugą (zastosowany np. zapis @media all and (max-width: 800px) - sprawdzić w kodzie i poprzez zmianę szerokości okna przeglądarki)

    ok. 3 min
    Polecenie z arkusza

    Dla wszystkich rodzajów ekranu o szerokości większej niż 800 px szerokość sekcji lewej i prawej wynosi 20%, środkowej 60% (są wyświetlane obok siebie).

    Dopisz szerokości do istniejących reguł i float: left - sekcje pływają w lewo i ustawiają się obok siebie w kolejności z HTML (20% + 60% + 20% = 100%, więc mieszczą się w jednej linii). To jedno z dopuszczalnych rozwiązań; klucz przyjmuje też display: flex albo grid.

    Na razie ten układ działa na każdej szerokości - warunek „większej niż 800 px” dodasz w następnym kroku zapytaniem @media.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    Podgląd strony po tym kroku (gry.php)
  34. Krok 34: Wąskie ekrany: sekcje jedna pod drugą

    Kryteria:

    R.4.5 Sekcje lewa, środkowa i prawa są wyświetlane obok siebie jeśli ekran jest szerszy niż 800px - odpowiednio szerokości 20%, 60%, 20%, a w przeciwnym wypadku są wyświetlane jedna pod drugą (zastosowany np. zapis @media all and (max-width: 800px) - sprawdzić w kodzie i poprzez zmianę szerokości okna przeglądarki)

    ok. 3 min
    Polecenie z arkusza

    Dla wszystkich rodzajów ekranu o pozostałej szerokości sekcje lewa, środkowa i prawa są wyświetlane jedna pod drugą.

    Zapytanie medialne @media all and (max-width: 800px) { ... } - reguły w środku działają tylko wtedy, gdy okno ma 800 px lub mniej („pozostała szerokość” po „większej niż 800”). Klucz R.4.5 podaje dokładnie ten zapis. W środku odwołujesz układ: pełna szerokość i float: none, więc sekcje wracają jedna pod drugą.

    Sprawdź to w podglądzie, zwężając okno przeglądarki - egzaminator robi to samo.

    Typowe błędy

    @media (min-width: 800px) dla układu obok siebie łapie też dokładnie 800 px, a arkusz mówi „większej niż 800”. Z max-width: 800px dla układu pod sobą granica jest tam, gdzie chce klucz.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    Podgląd strony po tym kroku (gry.php)
  35. Krok 35: Stopka: tło i wysokość

    Kryteria: , ,

    R.4.2 Ustawiony kolor tła Indigo dla bloków: bloku nagłówkowego, sekcji lewej, prawej i stopki oraz czarny kolor tła dla sekcji środkowej

    R.4.4 Ustawiona wysokość sekcji lewej, środkowej i prawej 600px oraz stopki 150px

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu dla ekranów o szerokości większej niż 800 px. Blok środkowy może być pusty. (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid)

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła Indigo, wysokość 150 px.

    Selektor footer z tłem i wysokością z arkusza. Dołóż clear: both - bez tego stopka wcisnęłaby się pod pływające sekcje zamiast stanąć pod nimi (to element układu z ilustracji 3, R.3.1).

    Typowe błędy

    Bez clear: both stopka może wjechać obok kolumn albo pod nie - układ przestaje zgadzać się z ilustracją 3.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    footer {
        background-color: Indigo;
        height: 150px;
        clear: both;
    }
    Podgląd strony po tym kroku (gry.php)
  36. Krok 36: Oznaczenie liczby punktów

    Kryteria:

    R.4.9 Ustawiony styl jedynie dla oznaczenia liczby punktów zgodnie z ilustracją 4: kolor tła Tomato, zaokrąglenie rogów 50%, marginesy wewnętrzne (padding) 5px (np. klasą, zastosowanie id jest błędem)

    ok. 2 min
    Polecenie z arkusza

    Dla oznaczenia liczby punktów widocznych na ilustracji 4: kolor tła Tomato, zaokrąglenie rogów 50%, marginesy wewnętrzne 5 px.

    Liczba punktów będzie w osobnym <span> generowanym przez skrypt 1, więc stylujesz klasę .points (kropka = klasa). Klucz R.4.9 mówi wprost: klasa, nie id - identyfikator musi być unikalny na stronie, a tych elementów będzie pięć. border-radius: 50% zaokrągla rogi w kółko jak na ilustracji 4, padding: 5px daje tłu miejsce wokół liczby. Efekt zobaczysz, gdy skrypt 1 wypełni listę.

    Typowe błędy

    #points (id) zamiast klasy to błąd wskazany w kluczu - pięć elementów z tym samym id to niepoprawny HTML.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    footer {
        background-color: Indigo;
        height: 150px;
        clear: both;
    }
    .points {
        background-color: Tomato;
        border-radius: 50%;
        padding: 5px;
    }
    Podgląd strony po tym kroku (gry.php)
  37. Krok 37: Element listy: margines wewnętrzny

    Kryteria:

    R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 2px, dla elementu listy 5px oraz marginesy zewnętrzne (margin) dla pola edycyjnego 10px

    ok. 1 min
    Polecenie z arkusza

    Dla elementu listy: marginesy wewnętrzne 5 px.

    Selektor znacznika li, padding: 5px - odstęp wewnątrz każdego elementu listy, dzięki czemu kółka z punktami nie nachodzą na siebie.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    footer {
        background-color: Indigo;
        height: 150px;
        clear: both;
    }
    .points {
        background-color: Tomato;
        border-radius: 50%;
        padding: 5px;
    }
    li {
        padding: 5px;
    }
    Podgląd strony po tym kroku (gry.php)
  38. Krok 38: Bloki gier w sekcji środkowej

    Kryteria:

    R.4.10 Ustawiony styl dla bloku gry: bloki są umieszczone jeden obok drugiego, wyrównanie tekstu do środka, marginesy wewnętrzne (padding) 3px (np. klasą, selektorem typu, potomka, zastosowanie id jest błędem)

    ok. 2 min
    Polecenie z arkusza

    Dla bloków gier znajdujących się w sekcji środkowej: bloki są umieszczone jeden obok drugiego, wyrównanie tekstu do środka, marginesy wewnętrzne 3 px.

    Bloki gier wygeneruje skrypt 2 jako <div class="game">, więc stylujesz klasę .game. „Jeden obok drugiego” to display: inline-block - blok zachowuje wymiary, ale ustawia się w linii jak tekst (i zawija do następnej linii, gdy zabraknie miejsca, jak na ilustracji 2). Klucz przyjmuje też float albo flex; id byłoby błędem.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    footer {
        background-color: Indigo;
        height: 150px;
        clear: both;
    }
    .points {
        background-color: Tomato;
        border-radius: 50%;
        padding: 5px;
    }
    li {
        padding: 5px;
    }
    .game {
        display: inline-block;
        text-align: center;
        padding: 3px;
    }
    Podgląd strony po tym kroku (gry.php)
  39. Krok 39: Pole edycyjne: margines zewnętrzny i kolor czcionki

    Kryteria: ,

    R.4.3 Ustawiony kolor czcionki Indigo dla pola edycyjnego

    R.4.7 Ustawione marginesy wewnętrzne (padding) dla bloku nagłówkowego 2px, dla elementu listy 5px oraz marginesy zewnętrzne (margin) dla pola edycyjnego 10px

    ok. 1 min
    Polecenie z arkusza

    Dla pola edycyjnego: marginesy zewnętrzne 10 px, kolor czcionki Indigo.

    Selektor znacznika input. Tu arkusz mówi o marginesach zewnętrznych, więc margin. color: Indigo nadpisuje biały kolor z * - inaczej wpisywany tekst byłby biały na białym polu. Arkusz stylów jest kompletny.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
        color: white;
    }
    header {
        background-color: Indigo;
        text-align: center;
        padding: 2px;
    }
    #left, #right {
        background-color: Indigo;
        height: 600px;
        width: 20%;
        float: left;
    }
    #middle {
        background-color: black;
        height: 600px;
        overflow: scroll;
        width: 60%;
        float: left;
    }
    @media all and (max-width: 800px) {
        #left, #middle, #right {
            width: 100%;
            float: none;
        }
    }
    footer {
        background-color: Indigo;
        height: 150px;
        clear: both;
    }
    .points {
        background-color: Tomato;
        border-radius: 50%;
        padding: 5px;
    }
    li {
        padding: 5px;
    }
    .game {
        display: inline-block;
        text-align: center;
        padding: 3px;
    }
    input {
        margin: 10px;
        color: Indigo;
    }
    Podgląd strony po tym kroku (gry.php)
  40. Etap 4: Skrypty PHP

    Kroki 40-54 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 40: Połączenie z bazą danych

    Kryteria: ,

    R.5.1 Skrypt zawiera działające połączenie z serwerem bazy danych i wybór bazy gry

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

    Skrypty napisane w języku PHP. Skrypty łączą się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie gry.

    Kod PHP piszesz między <?php a ?> - serwer wykonuje go, zanim strona trafi do przeglądarki. Połączenie otwierasz raz, na samym początku pliku, i trzymasz w zmiennej $connection (znacząca, angielska nazwa), z której skorzystają wszystkie cztery skrypty. mysqli_connect z tabeli 1 arkusza przyjmuje kolejno: serwer, użytkownika, hasło (puste) i nazwę bazy.

    Od tego kroku podgląd to wynik działania strony po stronie serwera (PHP nie wykonuje się w przeglądarce) - na razie wygląda jak wcześniej, bo skrypt niczego nie wypisuje.

    Typowe błędy

    Kolejność argumentów ma znaczenie: mysqli_connect('localhost', 'root', 'gry') podaje „gry” jako HASŁO. Nazwa bazy jest czwarta. Plik sprawdzaj przez http://localhost/…, nie otwierając go z dysku - inaczej PHP się nie wykona.

    gry.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  41. Krok 41: Skrypt 1: zapytanie 3 do bazy

    Kryteria:

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 3 lub skrypt 2 wysyła zapytanie 1, lub skrypt 3 wysyła zapytanie 2 zmodyfikowane w ten sposób, że wybierany jest wiersz o id podanym w polu edycyjnym

    ok. 2 min
    Polecenie z arkusza

    Skrypt 1: wysyła do bazy danych zapytanie 3.

    Skrypt 1 piszesz wewnątrz <ul>, bo tam mają trafić elementy listy. mysqli_query($connection, ...) wysyła zapytanie i zwraca wynik, który zapisujesz w $top_games. Treść to dokładnie zapytanie 3 z kwerendy.txt - pięć gier z najwyższą punktacją.

    gry.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>

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

  42. Krok 42: Skrypt 1: pętla po wierszach wyniku

    Kryteria:

    R.5.6 Skrypt 1 wyświetla nazwę i punkty zwrócone zapytaniem jako elementy listy

    ok. 2 min
    Polecenie z arkusza

    Zwrócone wiersze są wyświetlane w elementach listy z sekcji lewej według wzoru: <nazwa> <punkty>, gdzie nawiasy <> oznaczają wartość pobraną z bazy danych.

    „Zwrócone wiersze” to pętla. mysqli_fetch_row($top_games) (tabela 1) oddaje kolejny wiersz wyniku jako tablicę numerowaną od zera, a gdy wierszy zabraknie - false. Zapis while ($row = mysqli_fetch_row(...)) przypisuje wiersz do $row i od razu sprawdza, czy coś przyszło - pętla wykona się pięć razy i sama się zakończy. Ciało jest jeszcze puste.

    Typowe błędy

    Pojedyncze = w warunku while jest tu celowe (przypisanie); == porównałoby zmienną z wynikiem i pętla nie zadziałałaby poprawnie.

    gry.php PHP zmienione: 2 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>

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

  43. Krok 43: Skrypt 1: element listy z nazwą i punktami

    Kryteria: ,

    R.5.6 Skrypt 1 wyświetla nazwę i punkty zwrócone zapytaniem jako elementy listy

    R.2.9 Liczba punktów z sekcji lewej zapisana w dodatkowym elemencie, np. znacznik <span> (w skrypcie lub HTML)

    ok. 3 min
    Polecenie z arkusza

    Zwrócone wiersze są wyświetlane w elementach listy z sekcji lewej według wzoru: <nazwa> <punkty>, gdzie nawiasy <> oznaczają wartość pobraną z bazy danych. Liczba punktów jest dodatkowo formatowana stylem, którego efekt jest widoczny na ilustracji 4.

    echo w pętli wypisuje jeden <li>: nazwa z $row[0], spacja, a liczba punktów z $row[1] owinięta w <span class='points'> - to ten „dodatkowy element” z kryterium R.2.9, na który czeka reguła .points w CSS (pomarańczowe kółko z ilustracji 4). Wewnątrz napisu w cudzysłowie atrybut HTML piszesz w apostrofach, żeby nie kończyć napisu PHP.

    W podglądzie lista ma pięć pozycji z kółkami - w tym Zamczysko, bo zapytanie 4 już je wstawiło.

    Typowe błędy

    echo '<li>$row[0]</li>' w apostrofach wypisze dosłownie „$row[0]” - PHP nie podstawia zmiennych w apostrofach. Zewnętrzny napis w cudzysłowie, atrybuty w apostrofach.

    gry.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  44. Krok 44: Skrypt 2: zapytanie 1 do bazy

    Kryteria:

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 3 lub skrypt 2 wysyła zapytanie 1, lub skrypt 3 wysyła zapytanie 2 zmodyfikowane w ten sposób, że wybierany jest wiersz o id podanym w polu edycyjnym

    ok. 2 min
    Polecenie z arkusza

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

    Skrypt 2 piszesz w sekcji środkowej - jego wynik jest jej całą zawartością. Zapytanie 1 z kwerendy.txt (id, nazwa, zdjęcie wszystkich gier) trafia do $games. Kolejność kolumn w SELECT zaraz będzie ważna: $row[0] to id, $row[1] nazwa, $row[2] zdjęcie.

    gry.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>

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

  45. Krok 45: Skrypt 2: blok z obrazem gry

    Kryteria: ,

    R.5.7 Skrypt 2 wyświetla obrazy oraz ich nazwy zwrócone zapytaniem

    R.2.10 W sekcji środkowej umieszczony przynajmniej jeden obraz z tekstem alternatywnym i atrybutem title (w skrypcie lub HTML)

    ok. 4 min
    Polecenie z arkusza

    Zwrócone zapytaniem wiersze są wyświetlone w bloku, który składa się z: obrazu, którego źródłem jest pole zdjecie, tekstem alternatywnym jest pole nazwa, a podpowiedzią (dymek widoczny na ilustracji 2 dla pierwszej grafiki) jest pole id.

    Ta sama pętla while co w skrypcie 1. Każdy obieg wypisuje blok <div class='game'> (klasa, na którą czeka reguła .game w CSS) z obrazem <img>: src = nazwa pliku z kolumny zdjecie ($row[2]), alt = nazwa ($row[1]), title = id ($row[0]). Atrybut title to właśnie „dymek” - podpowiedź po najechaniu kursorem, którą pokazuje ilustracja 2 (cyfra 1 przy kursorze na obrazie Czarodziejki). Kryterium R.2.10: obraz z tekstem alternatywnym i atrybutem title.

    Pliki graficzne muszą leżeć obok gry.php - w bazie są same nazwy, dokładnie takie jak w archiwum (wielkość liter ma znaczenie na serwerach linuksowych).

    Typowe błędy

    Zamiana alt z title (alt = id, title = nazwa) to strata R.2.10 i R.5.7 - arkusz mówi wprost, które pole gdzie.

    gry.php PHP zmienione: 5 linii
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  46. Krok 46: Skrypt 2: paragraf z nazwą

    Kryteria:

    R.5.7 Skrypt 2 wyświetla obrazy oraz ich nazwy zwrócone zapytaniem

    ok. 1 min
    Polecenie z arkusza

    Paragrafu z nazwą zdjęcia.

    Do bloku dokładasz <p> z nazwą gry ($row[1]) pod obrazem, przed zamknięciem </div>. Sekcja środkowa w podglądzie wygląda jak na ilustracji 2: dziewięć bloków obok siebie, zawijanych, z paskami przewijania.

    gry.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  47. Krok 47: Skrypt 3: tylko gdy wpisano id

    Kryteria: ,

    R.5.4 W przynajmniej jednym skrypcie związanym z formularzem działania następują tylko wtedy, gdy wypełnione pole nazwa (skrypt 4) lub id (skrypt 3)

    R.5.5 Skrypt zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)

    ok. 2 min
    Polecenie z arkusza

    Skrypt 3 związany z formularzem w stopce: jeżeli wpisano id do pola edycyjnego, skrypt wysyła do bazy danych zapytanie 2 zmodyfikowane tak, że wybierany jest wiersz o id podanym w polu edycyjnym.

    Skrypt 3 piszesz w stopce, pod formularzem - tam ma się pojawić wynik. Warunek ma dwie części: isset($_POST['game_id']) (czy formularz w ogóle został wysłany) i $_POST['game_id'] != '' (czy pole nie jest puste). „Jeżeli wpisano id” to właśnie ta druga część - klucz R.5.4 sprawdza, że skrypt działa tylko przy wypełnionym polu. Przy pierwszym wejściu na stronę blok if jest pomijany.

    Typowe błędy

    Samo isset nie wystarczy: po kliknięciu „Pokaż opis” z pustym polem $_POST['game_id'] istnieje (jako pusty napis) i skrypt wysłałby zapytanie WHERE id = - błąd SQL na stronie.

    gry.php PHP zmienione: 4 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
    }
    ?>
        </footer>
    </body>
    </html>

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

  48. Krok 48: Skrypt 3: zapytanie 2 z id z formularza

    Kryteria: ,

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 3 lub skrypt 2 wysyła zapytanie 1, lub skrypt 3 wysyła zapytanie 2 zmodyfikowane w ten sposób, że wybierany jest wiersz o id podanym w polu edycyjnym

    R.5.5 Skrypt zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)

    ok. 2 min
    Polecenie z arkusza

    Skrypt wysyła do bazy danych zapytanie 2 zmodyfikowane tak, że wybierany jest wiersz o id podanym w polu edycyjnym.

    Wartość z pola trafia do $game_id ($_POST['game_id'] - klucz to atrybut name pola). Weź zapytanie 2 z kwerendy.txt i w warunku zamiast id = 1 wstaw id = $game_id. Cały napis zapytania w cudzysłowie, żeby PHP podstawił zmienną. Wynik trafia do $result.

    gry.php PHP zmienione: 2 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
    }
    ?>
        </footer>
    </body>
    </html>

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

  49. Krok 49: Skrypt 3: nagłówek z nazwą, punktami i ceną

    Kryteria:

    R.5.8 Skrypt 3 wyświetla napis: „<nazwa>, <punkty> punktów, <cena> zł", gdzie nawiasy <> oznaczają wartość pobraną z bazy danych oraz wyświetla opis

    ok. 3 min
    Polecenie z arkusza

    Zwrócony zapytaniem wiersz jest wyświetlany pod formularzem według wzoru: w nagłówku drugiego stopnia: <nazwa>, <punkty> punktów, <cena> zł.

    Zapytanie z warunkiem na klucz główny zwraca jeden wiersz, więc pętla nie jest potrzebna - jedno mysqli_fetch_row($result) do $game. Kolejność pól jak w SELECT: $game[0] nazwa, $game[1] skrócony opis, $game[2] punkty, $game[3] cena. Wzór z arkusza przepisujesz dosłownie do <h2>, z przecinkami i słowami „punktów” oraz „zł”.

    Podgląd pokazuje stan z ilustracji 2 - w formularzu wprowadzono 6: „Mag, 357 punktów, 150 zł”.

    Typowe błędy

    Dla id, którego nie ma w bazie (np. 99), mysqli_fetch_row zwraca null, a odczyt $game[0] wypisuje na stronie ostrzeżenie PHP. Klucz tego nie sprawdza; kto ma chwilę, owija wypisywanie w if ($game) { ... }.

    gry.php PHP zmienione: 2 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
    }
    ?>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  50. Krok 50: Skrypt 3: opis w paragrafie

    Kryteria:

    R.5.8 Skrypt 3 wyświetla napis: „<nazwa>, <punkty> punktów, <cena> zł", gdzie nawiasy <> oznaczają wartość pobraną z bazy danych oraz wyświetla opis

    ok. 1 min
    Polecenie z arkusza

    Opis w paragrafie.

    <p> z $game[1] - to opis skrócony do 100 znaków przez LEFT(opis, 100) w zapytaniu, dokładnie tak, jak urwany tekst w stopce na ilustracji 2.

    gry.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (gry.php)
  51. Krok 51: Skrypt 4: tylko gdy wypełniono pole nazwa

    Kryteria:

    R.5.4 W przynajmniej jednym skrypcie związanym z formularzem działania następują tylko wtedy, gdy wypełnione pole nazwa (skrypt 4) lub id (skrypt 3)

    ok. 2 min
    Polecenie z arkusza

    Skrypt 4 związany z formularzem z sekcji prawej: jeżeli wypełniono pole nazwa, skrypt wysyła do bazy zmodyfikowane zapytanie 4 w ten sposób, że wstawione są wartości pobrane z formularza, a liczba punktów wynosi 0.

    Skrypt 4 nic nie wypisuje, tylko zapisuje do bazy - piszesz go na początku pliku, zaraz po połączeniu. Dzięki temu nowa gra jest w bazie, zanim skrypty 1 i 2 zbudują listę i galerię, i pojawia się na stronie od razu po kliknięciu DODAJ.

    Warunek jak w skrypcie 3: isset($_POST['name']) i pole niepuste. Formularz w stopce nie ma pola name, więc wysłanie „Pokaż opis” nie uruchomi skryptu 4 - tak PHP rozróżnia dwa formularze w jednym pliku.

    gry.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    </body>
    </html>

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

  52. Krok 52: Skrypt 4: odczyt pól formularza

    Kryteria:

    R.5.5 Skrypt zawiera instrukcję pobierającą dane z tablicy globalnej odpowiadającej zastosowanej metodzie formularza ($_POST, $_GET, $_REQUEST)

    ok. 2 min
    Polecenie z arkusza

    Skrypt wysyła do bazy zmodyfikowane zapytanie 4 w ten sposób, że wstawione są wartości pobrane z formularza, a liczba punktów wynosi 0.

    Cztery wartości z $_POST do czterech zmiennych o znaczących nazwach: $name, $description, $price, $image. Klucze $_POST to atrybuty name pól z sekcji prawej. Punktów z formularza nie czytasz - arkusz każe wstawić 0.

    gry.php PHP zmienione: 4 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    </body>
    </html>

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

  53. Krok 53: Skrypt 4: wstawienie wiersza z zerem punktów

    Kryteria:

    R.5.9 Skrypt 4 wstawia do bazy danych rekord z danymi pobranymi z formularza, liczba punktów =0 (sprawdzić w phpMyAdmin)

    ok. 3 min
    Polecenie z arkusza

    Skrypt wysyła do bazy zmodyfikowane zapytanie 4 w ten sposób, że wstawione są wartości pobrane z formularza, a liczba punktów wynosi 0.

    Weź zapytanie 4 z kwerendy.txt i zamiast danych Zamczyska wstaw zmienne: napisy w apostrofach ('$name'), a w miejscu punktów liczba 0. Cały napis w cudzysłowie, żeby PHP podstawił wartości. mysqli_query wykonuje INSERT - nic nie zwraca do wyświetlenia, efekt sprawdza się w phpMyAdmin (R.5.9) albo na stronie po odświeżeniu: nowa gra na końcu galerii.

    Ta wersja spełnia klucz. Ma jednak wadę, o której mowa przy refaktorze: dane z formularza wchodzą do zapytania bez żadnej kontroli.

    Typowe błędy

    Wpisanie w formularzu nazwy z apostrofem (np. „Assassin's Creed”) rozrywa napis SQL i zapytanie kończy się błędem - to objaw podatności, którą usuniesz na końcu.

    gry.php PHP zmienione: 1 linia
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
        mysqli_query($connection, "INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES ('$name', '$description', 0, '$price', '$image');");
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    </body>
    </html>

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

  54. Krok 54: Zamknięcie połączenia z bazą

    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) na końcu pliku, gdy wszystkie skrypty już skorzystały z połączenia. Klucz R.5.2 sprawdza, że zamknięcie jest ostatnią operacją na bazie. Strona spełnia wszystkie kryteria arkusza - dalej trzy kroki „jak w prawdziwym projekcie”.

    Typowe błędy

    mysqli_close po skrypcie 1 sprawia, że skrypty 2 i 3 idą po zamkniętym połączeniu - galeria i opis znikają.

    gry.php PHP zmienione: 3 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
        mysqli_query($connection, "INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES ('$name', '$description', 0, '$price', '$image');");
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        $game = mysqli_fetch_row($result);
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  55. Etap 5: Bezpieczniejszy kod (poza kluczem)

    Kroki 55-57 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 55: Refaktor: zapytanie przygotowane w skrypcie 3

    Kryteria: ,

    R.5.3 Skrypt 1 wysyła do bazy danych zapytanie 3 lub skrypt 2 wysyła zapytanie 1, lub skrypt 3 wysyła zapytanie 2 zmodyfikowane w ten sposób, że wybierany jest wiersz o id podanym w polu edycyjnym

    R.5.8 Skrypt 3 wyświetla napis: „<nazwa>, <punkty> punktów, <cena> zł", gdzie nawiasy <> oznaczają wartość pobraną z bazy danych oraz wyświetla opis

    ok. 5 min
    Polecenie z arkusza

    Skrypt wysyła do bazy danych zapytanie 2 zmodyfikowane tak, że wybierany jest wiersz o id podanym w polu edycyjnym.

    Wersja z "... WHERE id = $game_id" sklejała zapytanie z tekstem wpisanym przez użytkownika - to SQL injection: wpisanie 1 OR 1=1 zmienia sens zapytania. W prawdziwych projektach dane nigdy nie trafiają do zapytania jako tekst, tylko przez zapytanie przygotowane:

    • mysqli_prepare dostaje zapytanie z ? w miejscu wartości - baza zna jego strukturę, zanim zobaczy dane,
    • mysqli_stmt_bind_param($statement, 'i', $game_id) podpina zmienną pod ?; litera i mówi, że to liczba całkowita (s napis, d liczba zmiennoprzecinkowa),
    • mysqli_stmt_execute wykonuje, a mysqli_stmt_get_result oddaje wynik, z którego czytasz jak dotąd.

    Stare dwie linie zostają w komentarzu // do porównania. Podgląd bez zmian - to ta sama logika, tylko bezpieczna.

    Typowe błędy

    Wiersz czyta się z wyniku mysqli_stmt_get_result, nie z samego zapytania przygotowanego: mysqli_fetch_row($statement) kończy się błędem TypeError (oczekuje mysqli_result, dostaje mysqli_stmt) - sprawdzone w PHP 8.2.

    gry.php PHP zmienione: 6 linii
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
        mysqli_query($connection, "INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES ('$name', '$description', 0, '$price', '$image');");
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        // $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        // $game = mysqli_fetch_row($result);
        $statement = mysqli_prepare($connection, 'SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = ?');
        mysqli_stmt_bind_param($statement, 'i', $game_id);
        mysqli_stmt_execute($statement);
        $game = mysqli_fetch_row(mysqli_stmt_get_result($statement));
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  56. Krok 56: Refaktor: zapytanie przygotowane w skrypcie 4

    Kryteria:

    R.5.9 Skrypt 4 wstawia do bazy danych rekord z danymi pobranymi z formularza, liczba punktów =0 (sprawdzić w phpMyAdmin)

    ok. 4 min
    Polecenie z arkusza

    Skrypt wysyła do bazy zmodyfikowane zapytanie 4 w ten sposób, że wstawione są wartości pobrane z formularza, a liczba punktów wynosi 0.

    Tu ryzyko jest największe - cztery pola z formularza szły prosto do INSERT. Ten sam schemat: ? za każdą wartość z formularza (zero punktów zostaje w zapytaniu jako stała), a mysqli_stmt_bind_param z typami 'ssds': nazwa (s), opis (s), cena (d - liczba z częścią ułamkową, jak kolumna float), zdjęcie (s). Litery odpowiadają kolejności ? w zapytaniu.

    Bonus: nazwa gry z apostrofem, która wcześniej wywalała zapytanie, teraz zapisze się poprawnie - baza dostaje ją jako dane, nie jako fragment SQL.

    Typowe błędy

    Liczba liter w 'ssds' musi równać się liczbie ? i liczbie zmiennych - inaczej PHP zgłosi błąd i nic nie zostanie wstawione.

    gry.php PHP zmienione: 4 linie
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
        // mysqli_query($connection, "INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES ('$name', '$description', 0, '$price', '$image');");
        $statement = mysqli_prepare($connection, 'INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES (?, ?, 0, ?, ?)');
        mysqli_stmt_bind_param($statement, 'ssds', $name, $description, $price, $image);
        mysqli_stmt_execute($statement);
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        echo "<p>$row[1]</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        // $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        // $game = mysqli_fetch_row($result);
        $statement = mysqli_prepare($connection, 'SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = ?');
        mysqli_stmt_bind_param($statement, 'i', $game_id);
        mysqli_stmt_execute($statement);
        $game = mysqli_fetch_row(mysqli_stmt_get_result($statement));
        echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$game[1]</p>";
    }
    ?>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  57. Krok 57: Refaktor: escapowanie danych przed wypisaniem

    Kryteria: , ,

    R.5.6 Skrypt 1 wyświetla nazwę i punkty zwrócone zapytaniem jako elementy listy

    R.5.7 Skrypt 2 wyświetla obrazy oraz ich nazwy zwrócone zapytaniem

    R.5.8 Skrypt 3 wyświetla napis: „<nazwa>, <punkty> punktów, <cena> zł", gdzie nawiasy <> oznaczają wartość pobraną z bazy danych oraz wyświetla opis

    ok. 5 min
    Polecenie z arkusza

    Zwrócony zapytaniem wiersz jest wyświetlany pod formularzem według wzoru: w nagłówku drugiego stopnia: <nazwa>, <punkty> punktów, <cena> zł, gdzie nawiasy <> oznaczają wartość pobraną z bazy danych.

    Druga strona tego samego problemu: skrypty 1-3 wypisują do HTML to, co jest w bazie - a do bazy każdy może dodać grę przez formularz. Nazwa <script>alert(1)</script> wykonałaby się w przeglądarce każdego odwiedzającego (XSS). htmlspecialchars() zamienia <, >, ", & na encje, więc tekst wyświetla się dosłownie i nie staje się kodem.

    W każdym skrypcie stare echo zostaje w komentarzu, a przed nowym wartości z bazy przechodzą przez htmlspecialchars() (liczby - id, punkty, cena - nie potrzebują). Podgląd wygląda identycznie, bo dane z archiwum nie mają znaków specjalnych - różnicę zobaczysz dopiero przy złośliwej nazwie gry.

    Typowe błędy

    htmlspecialchars przy wpisywaniu do bazy (w skrypcie 4) zamiast przy wypisywaniu to częsty błąd: baza dostaje zniekształcone dane (&amp; zamiast &), a każdy inny odbiorca danych i tak musi je escapować po swojemu. Escapujesz na wyjściu.

    gry.php PHP zmienione: 15 linii
    <?php
    $connection = mysqli_connect('localhost', 'root', '', 'gry');
    
    if (isset($_POST['name']) && $_POST['name'] != '') {
        $name = $_POST['name'];
        $description = $_POST['description'];
        $price = $_POST['price'];
        $image = $_POST['image'];
        // mysqli_query($connection, "INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES ('$name', '$description', 0, '$price', '$image');");
        $statement = mysqli_prepare($connection, 'INSERT INTO gry (nazwa, opis, punkty, cena, zdjecie) VALUES (?, ?, 0, ?, ?)');
        mysqli_stmt_bind_param($statement, 'ssds', $name, $description, $price, $image);
        mysqli_stmt_execute($statement);
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Gry komputerowe</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Ranking gier komputerowych</h1>
        </header>
        <section id="left">
            <h3>Top 5 gier w tym miesiącu</h3>
            <ul>
    <?php
    $top_games = mysqli_query($connection, 'SELECT nazwa, punkty FROM gry ORDER BY punkty DESC LIMIT 5;');
    while ($row = mysqli_fetch_row($top_games)) {
        // echo "<li>$row[0] <span class='points'>$row[1]</span></li>";
        $name = htmlspecialchars($row[0]);
        echo "<li>$name <span class='points'>$row[1]</span></li>";
    }
    ?>
            </ul>
            <h3>Nasz sklep</h3>
            <a href="http://sklep.gry.pl">Tu kupisz gry</a>
            <h3>Stronę wykonał</h3>
            <p>Bartosz Bryniarski</p>
        </section>
        <section id="middle">
    <?php
    $games = mysqli_query($connection, 'SELECT id, nazwa, zdjecie FROM gry;');
    while ($row = mysqli_fetch_row($games)) {
        echo "<div class='game'>";
        // echo "<img src='$row[2]' alt='$row[1]' title='$row[0]'>";
        // echo "<p>$row[1]</p>";
        $name = htmlspecialchars($row[1]);
        $image = htmlspecialchars($row[2]);
        echo "<img src='$image' alt='$name' title='$row[0]'>";
        echo "<p>$name</p>";
        echo '</div>';
    }
    ?>
        </section>
        <section id="right">
            <h3>Dodaj nową grę</h3>
            <form method="post">
                <label for="name">nazwa</label><br>
                <input type="text" id="name" name="name"><br>
                <label for="description">opis</label><br>
                <input type="text" id="description" name="description"><br>
                <label for="price">cena</label><br>
                <input type="text" id="price" name="price"><br>
                <label for="image">zdjęcie</label><br>
                <input type="text" id="image" name="image"><br>
                <button type="submit">DODAJ</button>
            </form>
        </section>
        <footer>
            <form method="post">
                <input type="text" name="game_id">
                <button type="submit">Pokaż opis</button>
            </form>
    <?php
    if (isset($_POST['game_id']) && $_POST['game_id'] != '') {
        $game_id = $_POST['game_id'];
        // $result = mysqli_query($connection, "SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = $game_id;");
        // $game = mysqli_fetch_row($result);
        $statement = mysqli_prepare($connection, 'SELECT nazwa, LEFT(opis, 100), punkty, cena FROM gry WHERE id = ?');
        mysqli_stmt_bind_param($statement, 'i', $game_id);
        mysqli_stmt_execute($statement);
        $game = mysqli_fetch_row(mysqli_stmt_get_result($statement));
        // echo "<h2>$game[0], $game[2] punktów, $game[3] zł</h2>";
        // echo "<p>$game[1]</p>";
        $name = htmlspecialchars($game[0]);
        $description = htmlspecialchars($game[1]);
        echo "<h2>$name, $game[2] punktów, $game[3] zł</h2>";
        echo "<p>$description</p>";
    }
    ?>
        </footer>
    <?php
    mysqli_close($connection);
    ?>
    </body>
    </html>

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

  58. Etap 6: Oddanie pracy

    Krok 58 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 58: 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. Nagraj płytę z rezultatami pracy.

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

    W folderze z numerem zdającego muszą być: Czarodziejka.jpg, gry.php, import.png, kalipso.jpg, katedra.jpg, krokodyl.jpg, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, Mag.jpg, NieznanyLad.jpg, Persja.jpg, przeglądarka.txt, styl.css, WyprawaNaKsiezyc.jpg, zamczysko.jpg. Nagraj płytę, sprawdź jej odczyt i opisz numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.