Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
EE.09-03-21.06-SGCzerwiec 2021 · 41 kroków · ok. 82 min · 36 kryteriów z klucza
Rozwiązanie krok po kroku: Internetowa wypożyczalnia filmów (Wersja podstawowa)
Strona wypożyczalni filmów: baza dane3 z tabelami produkty, producenci i rodzaje, na której cztery zapytania wybierają filmy polecane (IN), filmy fantastyczne, łączą produkty z ich rodzajem (JOIN) i usuwają jeden wiersz (DELETE). Do tego jedna grafika do skadrowania i strona video.php: dwa banery obok siebie, dwie przewijane listy filmów wypisane przez skrypty PHP i stopka z formularzem, którym skrypt 3 usuwa film o podanym numerze.
To arkusz EE.09 z czerwca 2021 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. PHP jest napisany najprościej, funkcjami z tabeli 1 arkusza (mysqli_connect, mysqli_query, mysqli_fetch_row, mysqli_close), a na końcu są dwa kroki o zabezpieczeniach, których klucz nie sprawdza - pokazane na prawdziwym ataku na ten formularz.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: PDO na górze pliku, usuwanie przed wypisaniem list i przekierowanie po nim, jedna funkcja zamiast dwóch kopii pętli oraz układ na flex - obie wersje są zgodne z kluczem.
Baza i grafiki pochodzą z oryginalnego archiwum CKE zad3 (załącznik do pobrania na stronie arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2. Klucz każe sprawdzać skrypt w XAMPP 7.4.8 - kod nie używa niczego, czego tam nie ma.
Jak liczą się punkty. Klucz ma 36 kryteriów (R.1.1 - R.5.6), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-7 · po tym etapie masz 6 z 36 kryteriów (pkt)
Krok 1: Folder zdającego i archiwum zad3
ok. 2 min
Polecenie z arkusza
Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu. Ważne! Aby strona działała poprawnie rozpakowane pliki muszą znaleźć się w tym samym folderze, co pliki strony. Wszystkie wykonane w czasie egzaminu pliki w tym zrzuty ekranu, pliki strony, stylów należy umieścić w tym folderze.
Folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum zad3.zip rozpakowujesz do niego, hasło: #MoJeVoD$ (wielkość liter ma znaczenie). W środku: dane.sql i osiem grafik filmów (alien.jpg, et.jpg, fantasy.jpg, hobbit.jpg, koralowa_wyspa.jpg, krokodyl.jpg, star-wars.jpg, steampunk.jpg). Nazwy plików są zapisane w bazie, w kolumnie zdjecie - skrypt wstawi je do znaczników <img>, dlatego grafiki muszą leżeć obok strony.
Strona jest w PHP, więc działa przez serwer: folder możesz trzymać w C:\xampp\htdocs i na koniec skopiować wyniki do folderu z numerem.
Krok 2: Pusta baza dane3
ok. 2 min
Polecenie z arkusza
Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie dane3
XAMPP Control Panel - Start przy Apache i MySQL, potem http://localhost/phpmyadmin. Nowa, nazwa dane3 (z cyfrą), Utwórz.
Krok 3: Import pliku dane.sql i zrzut egzamin.jpg
Kryteria:
R.1.1 Wykonano import tabel do bazy danych dane3 , czynność udokumentowano plikiem o nazwie egzamin w formacie JPEG
ok. 3 min
Polecenie z arkusza
Do bazy dane3 zaimportuj plik dane.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie JPEG i nazwij egzamin. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel
Zaznacz bazę dane3, karta Import, plik dane.sql, Wykonaj. Powstaje pięć tabel - poza trzema z obrazu 1 (produkty, producenci, rodzaje) także hobby i osoby, których zadanie nie używa. Tabela produkty ma 25 wierszy: warzywa, owoce i filmy.
Zrzut całego ekranu z komunikatem o sukcesie i listą tabel zapisz jako egzamin.jpg - w tym arkuszu zrzut importu nazywa się egzamin, nie import.
Typowe błędy
Zrzut nazwany import.jpg albo zapisany w PNG nie spełnia R.1.1.
Podgląd strony po tym kroku
Krok 4: Zapytanie 1: filmy o numerach 18, 22, 23, 25
Kryteria: ,
R.1.2 Zapisano plik tekstowy o nazwie kwerendy zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Utworzono zapytanie 1 wybierające jedynie pola id, nazwa, opis, zdjecie z tabeli produkty , dla produktów, których id jest jedną z wartości: 18, 22, 23, 25. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25); (możliwe różne warianty klauzuli WHERE) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 4 rekordy, jedynie pola id, nazwa, opis, zdjecie
ok. 3 min
Polecenie z arkusza
Zapisz i wykonaj zapytania SQL działające na bazie dane3. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie PNG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające jedynie pola id, nazwa, opis, zdjecie z tabeli produkty, dla produktów, których id jest jedną z wartości: 18, 22, 23, 25
SELECT id, nazwa, opis, zdjecie - cztery pola, w tej kolejności; skrypt odczyta je po numerach 0 - 3,
FROM produkty,
WHERE id IN (18, 22, 23, 25) - „jedna z wartości” to właśnie IN z listą; dłuższy zapis id = 18 OR id = 22 OR ... daje ten sam wynik.
Wynik: 4 wiersze - Alien4, Koralowa wyspa, krokodyl, SteamPunk - to filmy z bloku „Polecamy” na obrazie 2. Zapytanie do kwerendy.txt (R.1.2), zrzut: kw1.png.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25);
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: filmy z rodzaju 12
Kryteria:
R.1.4 Utworzono zapytanie 2 wybierające jedynie pola id, nazwa, opis, zdjecie z tabeli produkty , dla produktów, których pole Rodzaje_id przyjmuje wartość 12. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, nazwa, opis, zdjecie FROM produkty WHERE Rodzaje_id = 12; oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest 11 rekordów, jedynie pola id, nazwa, opis, zdjecie
ok. 2 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pola id, nazwa, opis, zdjecie z tabeli produkty, dla produktów, których pole Rodzaje_id przyjmuje wartość 12
Te same pola, warunek WHERE Rodzaje_id = 12 - nazwa kolumny wielką literą R, jak w bazie. Rodzaj 12 to „fantastyczne”. Wynik: 11 wierszy (Star Wars 1 - 4, E.T., hobbit, hobbit2 i hobbit3, Fantasy i Fantasy2, SteamPunk). Zrzut: kw2.png.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25);-- Zapytanie 2SELECT id, nazwa, opis, zdjecie FROM produkty WHERE Rodzaje_id = 12;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: produkt i nazwa jego rodzaju
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające nazwę z tabeli produkty i odpowiadającą mu nazwę z tabeli rodzaje dla wierszy, których w polu opis występuje „Leia”. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT produkty.nazwa, rodzaje.nazwa FROM produkty JOIN rodzaje ON produkty.Rodzaje_id = rodzaje.id WHERE opis LIKE "%Leia%"; możliwe też INNER JOIN lub bez JOIN (porównanie kluczy w warunku) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 4 rekordy z danymi: Star Wars 1 fantastyczne; Star Wars 2 fantastyczne; Star Wars 3 fantastyczne; Star Wars 4 fantastyczne
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające nazwę z tabeli produkty i odpowiadającą mu nazwę z tabeli rodzaje dla wierszy, których w polu opis występuje ciąg znaków: „Leia”
Dwie tabele mają kolumnę nazwa, więc przed każdą stoi nazwa tabeli:
SELECT produkty.nazwa, rodzaje.nazwa,
FROM produkty JOIN rodzaje ON produkty.Rodzaje_id = rodzaje.id - do każdego produktu dołączony wiersz jego rodzaju; warunek ON łączy klucz obcy z kluczem głównym (relacja z obrazu 1),
WHERE produkty.opis LIKE '%Leia%' - % zastępuje dowolny ciąg znaków, więc „Leia” może stać w dowolnym miejscu opisu.
Wynik: 4 wiersze - Star Wars 1, 2, 3 i 4, każdy z rodzajem „fantastyczne”. Zrzut: kw3.png.
Typowe błędy
Bez nazw tabel (SELECT nazwa, nazwa) MariaDB zgłosi błąd „kolumna nazwa jest niejednoznaczna”. LIKE 'Leia' bez znaków % szuka opisu złożonego tylko z tego słowa i nie znajdzie nic.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25);-- Zapytanie 2SELECT id, nazwa, opis, zdjecie FROM produkty WHERE Rodzaje_id = 12;-- Zapytanie 3SELECT produkty.nazwa, rodzaje.nazwa FROM produkty JOIN rodzaje ON produkty.Rodzaje_id = rodzaje.id WHERE produkty.opis LIKE '%Leia%';
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: usunięcie wiersza o id 15
Kryteria:
R.1.6 Utworzono zapytanie 4 usuwające wiersz z tabeli produkty o id 15. W pliku z kwerendami lub na zrzucie istnieje zapis np.: DELETE FROM produkty WHERE id = 15; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnym usunięciu lub tabela bez wiersza o id = 15
ok. 2 min
Polecenie z arkusza
Zapytanie 4: usuwające wiersz z tabeli produkty o id równym 15
DELETE FROM produkty WHERE id = 15 - phpMyAdmin pyta o potwierdzenie i odpowiada „1 wiersz usunięty” (zrzut kw4.png). Usunięty film to Alien3 - nie ma go w żadnej z list strony. To samo zapytanie, z numerem z formularza, wykona skrypt 3.
Typowe błędy
DELETE FROM produkty bez WHERE usuwa wszystkie wiersze tabeli. Przed takim zapytaniem w prawdziwej bazie robi się kopię - tu wystarczy ponowny import dane.sql.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25);-- Zapytanie 2SELECT id, nazwa, opis, zdjecie FROM produkty WHERE Rodzaje_id = 12;-- Zapytanie 3SELECT produkty.nazwa, rodzaje.nazwa FROM produkty JOIN rodzaje ON produkty.Rodzaje_id = rodzaje.id WHERE produkty.opis LIKE '%Leia%';-- Zapytanie 4DELETE FROM produkty WHERE id = 15;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-22 · po tym etapie masz 18 z 36 kryteriów (pkt)
Krok 8: Grafika: kadrowanie do 226 × 150 px
Kryteria:
R.2.1 Plik koralowa_wyspa.jpg skadrowano tak, aby jego wysokość wynosiła dokładnie 150 px, szerokość pozostaje bez zmian 226 px
ok. 3 min
Polecenie z arkusza
Plik koralowa_wyspa.jpg, wypakowany z archiwum, należy skadrować tak, aby jego wysokość wynosiła dokładnie 150 px, szerokość pozostaje bez zmian 226 px. Pozostałe pliki graficzne są przygotowane i nie należy ich zmieniać
Plik ma 226 × 181 px, pozostałe grafiki filmów - 226 × 150. Kadrowanie to wycięcie fragmentu, a nie skalowanie: obraz nie zmienia proporcji, odcinasz 31 px. W GIMP-ie narzędzie Kadrowanie (Shift+C), w opcjach narzędzia pozycja 0, 0 i rozmiar 226 × 150, Enter, potem Plik → Nadpisz koralowa_wyspa.jpg.
Pas odcięty jest z dołu kadru - zostają całe głowy aktorów, jak na obrazie 2. Klucz sprawdza tylko wymiary (R.2.1).
Typowe błędy
Obraz → Skaluj obraz do 226 × 150 przy rozłączonym łańcuchu też da te wymiary, ale spłaszczy twarze - to nie jest kadrowanie.
Podgląd strony po tym kroku
Krok 9: Plik video.php
Kryteria:
R.2.2 Witrynę internetową zapisano w pliku PHP o nazwie video
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie video.php
Plik video.php (R.2.2). Arkusz nie wymaga tu deklaracji HTML5 ani języka, ale <!DOCTYPE html> i lang="pl" są w każdej poprawnej stronie - przeglądarka rysuje ją wtedy w trybie standardów.
Tytuł strony widoczny na karcie przeglądarki: „Video On Demand”
<title>Video On Demand</title> (R.2.4).
video.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Video On Demand</title></head><body></body></html>
Podgląd strony po tym kroku (video.php)
Krok 12: Podpięcie arkusza stylów styl3.css
Kryteria:
R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl3.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy źle przypisano co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl3.css prawidłowo połączony z kodem strony
<link rel="stylesheet" href="styl3.css"> - całe formatowanie z tego pliku (R.3.5).
video.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Video On Demand</title> <linkrel="stylesheet"href="styl3.css"></head><body></body></html>
Podgląd strony po tym kroku (video.php)
Krok 13: Bloki: dwa banery, dwie listy i stopka
Kryteria:
R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: dwa bloki banera, blok listy „Polecamy”, blok listy „Filmy fantastyczne” i stopka. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: dwa bloki banera obok siebie, blok listy „Polecamy”, blok listy „Filmy fantastyczne” i stopka. W blokach listy znajdują się bloki filmów generowane przez skrypt. Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2
dwa banery jako <section> z identyfikatorami banner-left i banner-right,
dwie listy jako <section>: identyfikatory recommended („Polecamy”) i fantasy, a do tego wspólna klasa list - oba bloki mają w arkuszu te same style, więc jedna reguła CSS obejmie oba,
<footer> - stopka.
Bloki filmów (<div class="film">) wypisze skrypt. Wszystkie bloki to znaczniki sekcji (R.2.5).
R.2.7 W bloku banera prawego umieszczono tabelę o dwóch wierszach i trzech kolumnach zgodną z obrazem 3 arkusza, zastosowano znaczniki <table>, <tr>, <td> oraz ich zamknięcia. Zastosowanie <th> nie jest błędem
ok. 2 min
Polecenie z arkusza
Zawartość banera prawego: tabela o dwóch wierszach i trzech kolumnach, której widok jest zgodny z obrazem 3
<table> z dwoma wierszami <tr>, w każdym trzy komórki <td>: gatunki „Kryminał”, „Horror”, „Przygodowy” i liczby 20, 30, 20 (obraz 3). Klucz dopuszcza <th> w pierwszym wierszu (R.2.7).
R.2.6 W bloku banera lewego zapisano nagłówek h1: "Internetowa wypożyczalnia filmów" oraz w przynajmniej jednym bloku listy zapisano nagłówek h3: „Polecamy” lub „Filmy fantastyczne”
ok. 1 min
Polecenie z arkusza
Zawartość bloku listy „Polecamy”: Nagłówek trzeciego stopnia o treści „Polecamy”. Efekt działania skryptu 1
<h3>Polecamy</h3> - pod nim skrypt 1 wypisze bloki filmów. Strona ma już <h1> w banerze i <h3> w bloku listy (R.2.6).
Zawartość stopki: Formularz wysyłający dane do tego samego pliku metodą POST z zawartością:
<form method="post"> bez action - dane wracają do video.php (R.3.3). POST jest tu właściwą metodą: formularz zmienia dane w bazie, a takich operacji nie wysyła się w adresie strony (adres z GET zostaje w historii i można go przypadkiem otworzyć ponownie).
Pole edycyjne typu numerycznego poprzedzone wpisem „Usuń film nr.: ”
Napis i <input type="number"> z nazwą name="id" - pod tą nazwą numer trafi do skryptu ($_POST['id']).
Skrót „nr” kończy się ostatnią literą słowa „numer”, więc po polsku pisze się go bez kropki - na stronie stoi „Usuń film nr:”. Klucz dopuszcza drobne różnice w napisach, a kropka z arkusza nie wpływa na ocenę.
R.2.9 W stopce umieszczono formularz z polem edycyjnym i przyciskiem, zastosowano znacznik <form> oraz jego zamknięcie
R.3.4 Zastosowano typ number dla pola edycyjnego oraz wciśnięcie przycisku wysyła dane do skryptu (typ submit dla input lub button albo button bez atrybutu typu)
ok. 1 min
Polecenie z arkusza
Przycisk „Usuń film” wysyłający dane do skryptu 3
<button type="submit"> wysyła formularz. Stopka ma formularz z polem i przyciskiem (R.2.9), pole typu number i przycisk wysyłający (R.3.4).
R.3.2 Na stronie umieszczono odnośnik pocztowy połączony z adresem mailto:[email protected]
ok. 1 min
Polecenie z arkusza
Numer PESEL lub w przypadku jego braku inny numer, którym został podpisany arkusz jest odnośnikiem pocztowym do adresu e-mail: „[email protected]”
Odnośnik pocztowy to <a> z adresem zaczynającym się od mailto: - kliknięcie otwiera program pocztowy z nową wiadomością do [email protected] (R.3.2). Odnośnikiem jest sam numer, napis „Stronę wykonał:” zostaje zwykłym tekstem. HTML jest kompletny.
Dla banera prawego: kolor tła #29434E, biały kolor czcionki, szerokość 30%, wysokość 70 px
Selektor #banner-right - bez wyrównania do środka (tabela na obrazie 2 stoi przy lewej krawędzi banera). Szerokości 70% i 30% dają razem pełną szerokość strony (R.4.5).
R.4.4 Ustawiono wysokość obu bloków banera: 70px, obu bloków listy: 320px
R.4.7 Ustawiono przynajmniej jeden pasek przewijania (przesuwania) dla przynajmniej jednego bloku listy, np. overflow: scroll; (lub auto)
ok. 2 min
Polecenie z arkusza
Dla obu bloków list: kolor tła #B0BEC5, wysokość 320 px, paski przesuwania (scroll)
Selektor klasy .list obejmuje oba bloki naraz. overflow: scroll - treść, która nie mieści się w 320 px, nie wylewa się poza blok, tylko da się ją przewinąć; scroll pokazuje oba paski zawsze, także poziomy (widać go na obrazie 2), a auto - tylko wtedy, gdy są potrzebne (klucz przyjmuje oba, R.4.7). Wysokość banerów i list jest ustawiona (R.4.4).
R.4.2 Ustawiono kolor tła #29434E dla obu bloków banera i stopki, #B0BEC5 dla obu bloków listy
R.4.3 Ustawiono biały kolor czcionki dla obu bloków banera i stopki
ok. 1 min
Polecenie z arkusza
Dla stopki: kolor tła #29434E, biały kolor czcionki
Selektor footer. Tło banerów, stopki i list (R.4.2) oraz biały tekst banerów i stopki (R.4.3) są ustawione. Odnośnik pocztowy zostaje w domyślnym kolorze przeglądarki - tak jest na obrazie 2.
Krok 31: Układ: banery obok siebie, filmy w rzędach
Kryteria:
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu egzaminacyjnym (nie uwzględnia się bloków zawierających filmy)
ok. 3 min
Polecenie z arkusza
Podział strony na bloki: dwa bloki banera obok siebie, blok listy „Polecamy”, blok listy „Filmy fantastyczne” i stopka. W blokach listy znajdują się bloki filmów generowane przez skrypt. Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2
float: left na obu banerach - stają obok siebie (70% + 30%),
clear: both na listach - lista zaczyna się pod banerami, a nie obok nich (R.3.1),
float: left na blokach filmów - filmy ustawiają się w rzędzie, jak na obrazie 2, a gdy się nie mieszczą, przechodzą do kolejnego. Arkusz tego nie wypisuje wprost, ale obraz 2 pokazuje filmy obok siebie; klucz nie ocenia układu filmów.
Bloki list mają overflow: scroll, więc pływające filmy nie „wypadają” poza swój blok.
Typowe błędy
Bez clear: both lista „Polecamy” wsunie się pod pływające banery i jej nagłówek wyląduje w złym miejscu.
Kroki 32-38 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 32: Skrypt 1 w liście „Polecamy”: połączenie z bazą dane3
Kryteria:
R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy dane3
ok. 3 min
Polecenie z arkusza
Napisany w języku PHP. Skrypt łączy się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie dane3
„Efekt działania skryptu 1” ma być w bloku „Polecamy”, pod nagłówkiem - tam piszesz blok <?php ... ?>. Serwer wykona go przed wysłaniem strony do przeglądarki.
mysqli_connect z tabeli 1: serwer localhost, użytkownik root, puste hasło, baza dane3 (R.5.1). Połączenie w zmiennej $connection posłuży też skryptom 2 i 3 - zmienne z jednego bloku PHP są widoczne w kolejnych blokach tego samego pliku.
Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2. Stronę otwierasz przez http://localhost/…/video.php.
R.5.3 Skrypt 1 wysyła do bazy zapytanie 1 lub skrypt 2 - zapytanie 2, lub skrypt 3 - zapytanie 4
ok. 4 min
Polecenie z arkusza
Działanie skryptu 1: Wysyła do bazy zapytanie 1. Dla każdego zwróconego zapytaniem wiersza tworzy blok filmu, w którym znajdują się: Nagłówek czwartego stopnia o treści „<id>. <nazwa>”, gdzie pola < > są pobrane z bazy
mysqli_query wysyła zapytanie 1 z kwerendy.txt (R.5.3),
while ($row = mysqli_fetch_row($result)) - w każdym obrocie kolejny wiersz jako tablica: $row[0] - id, $row[1] - nazwa, $row[2] - opis, $row[3] - zdjęcie (kolejność pól z SELECT). Gdy wierszy zabraknie, pętla się kończy,
każdy obrót wypisuje blok <div class="film"> i jego zamknięcie, a w nim <h4> z numerem, kropką, spacją i nazwą.
Podgląd: cztery tytuły w rzędzie - 18. Alien4, 22. Koralowa wyspa, 23. krokodyl, 25. SteamPunk.
R.2.8 Przynajmniej jeden obraz ma tekst alternatywny "film" (w HTML lub skrypcie)
ok. 2 min
Polecenie z arkusza
Obraz o nazwie pobranej z bazy danych i tekście alternatywnym „film”
Nazwa pliku jest w kolumnie zdjecie, czyli w $row[3]: <img src="alien.jpg" alt="film"> itd. Cudzysłowy atrybutów wewnątrz napisu poprzedzasz ukośnikiem \" (R.2.8).
R.5.4 Przynajmniej jeden: skrypt 1 lub 2 tworzy blok w którym znajdują się elementy: nagłówek h4 o treści „<id>. <nazwa>”, obraz, paragraf (akapit) o treści <opis>. Wartości wszystkich elementów zostały pobrane z bazy
ok. 1 min
Polecenie z arkusza
Paragraf (akapit) o treści zgodnej z polem opis pobranym z bazy
echo "<p>$row[2]</p>"; - opis z bazy. Blok filmu ma komplet: tytuł, grafika, opis (R.5.4). Podgląd: lista „Polecamy” jak na obrazie 2. Teksty opisów są zapisane w bazie bez polskich liter i z literówkami (np. „itstoty”) - tak przyszły z arkusza i nie trzeba ich poprawiać.
R.5.5 Skrypt 1 oraz skrypt 2 wyświetlają wszystkie zwrócone zapytaniami bloki zawierające pobrane z bazy filmy przy zastosowaniu pętli
ok. 2 min
Polecenie z arkusza
Działanie skryptu 2 jest identyczne jak skryptu 1, z tą różnicą, że źródłem danych jest zapytanie 2
W bloku „Filmy fantastyczne”, pod nagłówkiem, ta sama pętla co w skrypcie 1, ale z zapytaniem 2 - bez ponownego łączenia, bo $connection już istnieje. Obie listy wypisują w pętli wszystkie wiersze swoich zapytań (R.5.5).
Podgląd: 11 filmów fantastycznych - pierwsze cztery w rzędzie, reszta w kolejnych rzędach, do obejrzenia po przewinięciu bloku.
Krok 37: Skrypt 3: usunięcie filmu o numerze z formularza
Kryteria:
R.5.6 Skrypt 3 wysyła do bazy zmodyfikowane zapytanie 4, w ten sposób, że usuwany jest wiersz, którego id podano w formularzu. Należy sprawdzić w bazie danych czy wiersz został usunięty (do testów należy wykorzystać id z zakresu 1 ÷ 8)
ok. 4 min
Polecenie z arkusza
Działanie skryptu 3: Jeśli wypełniono formularz, pobiera z niego numer filmu do usunięcia. Wysyła zmodyfikowane zapytanie 4 do bazy danych, w ten sposób, że jest usuwany wiersz, którego id podano w formularzu
Skrypt 3 stoi w stopce, pod formularzem:
!empty($_POST['id']) - prawdziwe, gdy formularz wysłano z wypełnionym polem. Przy zwykłym wejściu na stronę i przy pustym polu skrypt nic nie robi (samo isset przepuściłoby puste pole i zapytanie WHERE id = ; skończyłoby się błędem),
zapytanie 4 w cudzysłowach podwójnych z $id zamiast 15 (R.5.6).
Skrypt 3 wykonuje się po skryptach 1 i 2 - listy na stronie, która wraca po kliknięciu „Usuń film”, zostały wypisane, zanim film zniknął z bazy. Sprawdzone: po usunięciu filmu 22 odpowiedź nadal pokazuje „Koralową wyspę”, a w bazie wiersza już nie ma. Film znika z list przy kolejnym wczytaniu strony - tak wygląda podgląd. Klucz sprawdza usunięcie w bazie, więc ta kolejność wystarcza; wersja nowoczesna usuwa film przed wypisaniem list.
Typowe błędy
Zapytanie w apostrofach wyśle do bazy dosłownie $id. Pole bez name="id" nie trafi do $_POST i skrypt nigdy nic nie usunie.
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)
ok. 1 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem.
mysqli_close($connection) na końcu skryptu 3, poza warunkiem - wykona się przy każdym wczytaniu strony i jest ostatnią operacją na bazie (R.5.2). Strona spełnia wszystkie kryteria arkusza; podgląd jak na obrazie 2. Dalej dwa kroki o zabezpieczeniach - klucz ich nie wymaga.
Typowe błędy
Zamknięcie połączenia w skrypcie 1 odetnie skrypty 2 i 3 - PHP 8 zakończy stronę błędem.
Kroki 39-40 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 39: Zabezpieczenie: atak „0 OR 1=1” i zapytanie przygotowane
ok. 5 min
Polecenie z arkusza
Wysyła zmodyfikowane zapytanie 4 do bazy danych, w ten sposób, że jest usuwany wiersz, którego id podano w formularzu
Pole type="number" przyjmuje tylko liczby w przeglądarce. Formularz można wysłać z jej pominięciem (polecenie curl, narzędzia programisty), a skrypt wkleja tekst z pola wprost w zapytanie - to SQL injection. Sprawdzone na wersji z poprzednich kroków: w polu wysłano tekst 0 OR 1=1. Zapytanie zamieniło się w DELETE FROM produkty WHERE id = 0 OR 1=1, a warunek 1=1 jest prawdziwy dla każdego wiersza - z tabeli zniknęły wszystkie 24 produkty, obie listy na stronie są puste.
Poprawka w dwóch warstwach (stare linie w komentarzu):
(int) zamienia tekst na liczbę całkowitą - z 0 OR 1=1 zostaje 0,
zapytanie przygotowane: mysqli_prepare ze znakiem ?, mysqli_stmt_bind_param z typem 'i' (liczba całkowita) i mysqli_stmt_execute. Baza dostaje treść zapytania i numer osobno - numer nigdy nie stanie się kodem SQL.
Sprawdzone po poprawce: ten sam atak nie usuwa niczego, a numer 23 usuwa dokładnie jeden film.
Drugi problem tej strony nie dotyczy kodu SQL: każdy, kto ją otworzy, może usuwać filmy. W prawdziwym serwisie formularz usuwania jest tylko w panelu po zalogowaniu, a skrypt sprawdza uprawnienia przed DELETE. Arkusz tego nie przewiduje. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Typowe błędy
Liczba liter w drugim argumencie mysqli_stmt_bind_param musi równać się liczbie znaków ?.
video.phpPHPzmienione: 6 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Video On Demand</title> <linkrel="stylesheet"href="styl3.css"></head><body> <sectionid="banner-left"> <h1>Internetowa wypożyczalnia filmów</h1> </section> <sectionid="banner-right"> <table> <tr> <td>Kryminał</td> <td>Horror</td> <td>Przygodowy</td> </tr> <tr> <td>20</td> <td>30</td> <td>20</td> </tr> </table> </section> <sectionid="recommended"class="list"> <h3>Polecamy</h3><?php$connection = mysqli_connect('localhost', 'root', '', 'dane3');$result = mysqli_query($connection, 'SELECT id, nazwa, opis, zdjecie FROM produkty WHERE id IN (18, 22, 23, 25);');while ($row = mysqli_fetch_row($result)) {echo'<div class="film">';echo"<h4>$row[0]. $row[1]</h4>";echo"<img src=\"$row[3]\" alt=\"film\">";echo"<p>$row[2]</p>";echo'</div>'; }?> </section> <sectionid="fantasy"class="list"> <h3>Filmy fantastyczne</h3><?php$result = mysqli_query($connection, 'SELECT id, nazwa, opis, zdjecie FROM produkty WHERE Rodzaje_id = 12;');while ($row = mysqli_fetch_row($result)) {echo'<div class="film">';echo"<h4>$row[0]. $row[1]</h4>";echo"<img src=\"$row[3]\" alt=\"film\">";echo"<p>$row[2]</p>";echo'</div>'; }?> </section> <footer> <formmethod="post"> Usuń film nr: <inputtype="number"name="id"> <buttontype="submit">Usuń film</button> </form><?phpif (!empty($_POST['id'])) {// $id = $_POST['id'];// mysqli_query($connection, "DELETE FROM produkty WHERE id = $id;");$id = (int) $_POST['id'];$statement = mysqli_prepare($connection, 'DELETE FROM produkty WHERE id = ?;'); mysqli_stmt_bind_param($statement, 'i', $id); mysqli_stmt_execute($statement); } mysqli_close($connection);?> <p>Stronę wykonał: <ahref="mailto:[email protected]">Bartosz Bryniarski</a></p> </footer></body></html>
Krok 40: Zabezpieczenie: htmlspecialchars przy wypisywaniu filmów
ok. 4 min
Polecenie z arkusza
Dla każdego zwróconego zapytaniem wiersza tworzy blok filmu, w którym znajdują się: Nagłówek czwartego stopnia o treści „<id>. <nazwa>”, gdzie pola < > są pobrane z bazy
Opisy filmów wpisuje do bazy ktoś inny niż autor strony - pracownik wypożyczalni albo panel dostawcy. Znacznik zapisany w opisie echo wstawia do strony jako kod. Sprawdzone na kopii bazy, w której opis filmu „krokodyl” kończył się znacznikiem <script>: wersja z poprzednich kroków wykonała ten skrypt i podmieniła całą stronę u każdego odwiedzającego - to atak XSS.
htmlspecialchars zamienia <, >, & i cudzysłowy na encje, więc przeglądarka pokazuje je jako tekst. Przepuszczasz przez nią każde pole z bazy w skryptach 1 i 2: tytuł, nazwę pliku w src (cudzysłów w nazwie zamknąłby atrybut) i opis. Stare linie zostają w komentarzu.
Podgląd: ta sama kopia bazy po poprawce - znacznik widać w opisie krokodyla jako zwykły tekst, strona działa. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Krok 41 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 41: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. Przed nagraniem płyty zaimportuj dane.sql ponownie albo nie testuj usuwania na filmach z list - egzaminator sprawdzi skrypt 3 na numerach 1 - 8 (warzywa i owoce), a listy powinny wyglądać jak na obrazie 2.
W folderze muszą być: alien.jpg, egzamin.jpg, et.jpg, fantasy.jpg, hobbit.jpg, koralowa_wyspa.jpg, krokodyl.jpg, kw1.png - kw4.png, kwerendy.txt, star-wars.jpg, steampunk.jpg, przeglądarka.txt, styl3.css i video.php. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
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: Bartosz Bryniarski. 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.