INF.03-01-23.06-SGCzerwiec 2023 · 38 kroków · ok. 67 min · 38 kryteriów z klucza
Rozwiązanie krok po kroku: Portal sklepu dla uczniów (Wersja podstawowa)
Rozwiązanie buduje stronę sklepu dla uczniów: baza sklep z dostawcami i towarami w relacji i cztery zapytania (warunek na polu 0/1, cena jednego towaru, COUNT z GROUP BY po złączeniu tabel i ALTER TABLE dodające pole), grafika przeskalowana z zachowaniem przezroczystości, strona index.php z banerem, trzema panelami i stopką oraz style w styl.css z numeracją listy literami i zaokrąglonym obramowaniem obrazu. Dwa skrypty PHP: lista towarów w promocji oraz formularz POST z listą rozwijalną, po którego wysłaniu skrypt pobiera cenę wybranego towaru i liczy cenę o 30% niższą.
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 wartość z formularza zostaje zabezpieczona zapytaniem przygotowanym, a ceny - sformatowane.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: panele ustawione flexem w znaczniku <main>, kolory w zmiennych CSS, dane pobierane przez PDO na górze pliku, a nazwa towaru sprawdzana z listą i przekazywana zapytaniem przygotowanym - obie wersje są zgodne z kluczem.
Baza i grafika pochodzą z prawdziwego archiwum materialy1 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu i z widocznym zapytaniem. Od kroku z formularzem podgląd pokazuje stronę po wysłaniu formularza z wybraną gumką do mazania - jak na obrazie 2.
Jak liczą się punkty. Klucz ma 38 kryteriów (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 29 punktów - można stracić 9 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.
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 38 kryteriów (pkt)
Krok 1: Baza danych sklep
Kryteria:
R.1.1 Wykonano import tabel do bazy danych o nazwie sklep , czynność udokumentowano plikiem o nazwie baza w formacie JPEG
ok. 2 min
Polecenie z arkusza
Utwórz nową bazę danych o nazwie sklep.
Rozpakuj materialy1.7z z pulpitu (hasło Z@dani3x) do folderu z numerem zdającego: sklep.sql i promocja.png. W phpMyAdmin: Nowa, nazwa sklep. Arkusz nie podaje porównywania - wybierasz np. utf8mb4_polish_ci.
Krok 2: Import tabel z pliku sklep.sql
Kryteria:
R.1.1 Wykonano import tabel do bazy danych o nazwie sklep , czynność udokumentowano plikiem o nazwie baza w formacie JPEG
ok. 2 min
Polecenie z arkusza
Do bazy zaimportuj tabele z pliku sklep.sql, z wcześniej rozpakowanego archiwum.
Przy zaznaczonej bazie sklep: Import → sklep.sql → Wykonaj. Dwie tabele z obrazu 1: dostawcy (3 dostawców) i towary (10 towarów). Pole promocja to 0 (bez promocji) albo 1 (w promocji), a idDostawcy wskazuje id w tabeli dostawcy - na tych polach opiera się relacja.
Krok 3: Zrzut ekranu baza.jpg
Kryteria:
R.1.1 Wykonano import tabel do bazy danych o nazwie sklep , czynność udokumentowano plikiem o nazwie baza w formacie JPEG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie JPEG i nazwij baza. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.
Print Screen, zapis jako baza.jpg - w tym arkuszu zrzut importu nazywa się baza, a zrzuty zapytań kwerenda1 - kwerenda4, wszystkie w JPEG.
Typowe błędy
Nazwa import.jpg (jak w wielu innych arkuszach) zamiast baza.jpg to strata punktu R.1.1.
Krok 4: Zapytanie 1: towary objęte promocją
Kryteria: ,
R.1.2 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Zapisano zapytanie 1 wybierające jedynie pole nazwa z tabeli towary dla towarów objętych promocją. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa FROM towary WHERE promocja = 1; oraz wynik działania zapytania udokumentowano zrzutem ekranu, na którym widoczne są jedynie nazwy towarów: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt.
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie pole nazwa z tabeli towary dla towarów objętych promocją.
„Objęte promocją” to w bazie promocja = 1. Wynik: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt. - jak w kluczu. Zapytanie do kwerendy.txt, zrzut kwerenda1.jpg - arkusz wymaga, by na zrzucie było widać także treść zapytania (phpMyAdmin pokazuje ją nad wynikiem).
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT nazwa FROM towary WHERE promocja = 1;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: cena markerów
Kryteria:
R.1.4 Zapisano zapytanie 2 wybierające jedynie pole cena z tabeli towary dla towaru Markery 4 szt. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.'; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczna jest jedynie cena 22.4
ok. 1 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pole cena z tabeli towary dla towaru Markery 4 szt.
Warunek porównuje cały napis, razem ze spacjami i kropką: nazwa = 'Markery 4 szt.'. Wynik: 22.4 - jak w kluczu. Zrzut: kwerenda2.jpg. To zapytanie wyśle skrypt 2, podstawiając nazwę wybraną w formularzu.
Typowe błędy
nazwa = "Markery 4 szt" bez kropki na końcu nie znajdzie towaru - wynik będzie pusty.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM towary WHERE promocja = 1;-- Zapytanie 2SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: liczba towarów każdego dostawcy
Kryteria:
R.1.5 Zapisano zapytanie 3 wybierające jedynie pola id i nazwa z tabeli dostawcy oraz zliczające liczbę towarów dostarczanych przez każdego z dostawców. Nazwa kolumny (alias) zliczającej liczba_towarow. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa; (lub INNER JOIN, lub wersja bez JOIN z porównaniem kluczy po WHERE, w funkcji COUNT możliwa również *) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 3 rekordy, jedynie pola id, nazwa z tabeli dostawcy oraz odpowiadająca im liczba_towarow: Art. szkolne - 4, Papiernictwo - 4, Wszystko dla ucznia - 2
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie pola id oraz nazwa dla wszystkich rekordów z tabeli dostawcy oraz zliczające liczbę towarów dostarczanych przez każdego z dostawców. Nazwa kolumny (alias) dla zliczenia towarów: liczba_towarow. W zapytaniu 3 należy posłużyć się relacją.
FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id - relacja: każdy towar dostaje swojego dostawcę.
GROUP BY dostawcy.nazwa - jedna grupa na dostawcę, a w niej COUNT(towary.id) zlicza jego towary; alias liczba_towarow (bez spacji i polskich liter, więc bez cudzysłowu).
Obie tabele mają kolumny id i nazwa, więc każdą poprzedzasz nazwą tabeli.
Wynik: 3 wiersze - Art. szkolne 4, Papiernictwo 4, Wszystko dla ucznia 2, jak w kluczu. Zrzut: kwerenda3.jpg.
Typowe błędy
SELECT id, nazwa ... bez nazw tabel to błąd „column is ambiguous” - obie tabele mają te kolumny.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM towary WHERE promocja = 1;-- Zapytanie 2SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';-- Zapytanie 3SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: nowe pole informacje
Kryteria:
R.1.6 Zapisano zapytanie 4 modyfikujące strukturę tabeli dostawcy poprzez dodanie pola typu napisowego o nazwie informacje. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE dostawcy ADD COLUMN informacje TEXT; (możliwe również bez słowa COLUMN, dowolny typ tekstowy) oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest komunikat o poprawnie wykonanym zapytaniu lub zmieniona struktura tabeli
ok. 2 min
Polecenie z arkusza
Zapytanie 4: modyfikujące strukturę tabeli dostawcy, poprzez dodanie pola typu tekstowego o nazwie informacje.
Strukturę tabeli zmienia ALTER TABLE: ADD COLUMN informacje TEXT dodaje pole tekstowe (TEXT albo np. VARCHAR(100)). Zrzut kwerenda4.jpg pokazuje komunikat o wykonaniu albo, jak obok, strukturę tabeli z nowym polem. kwerendy.txt ma komplet.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT nazwa FROM towary WHERE promocja = 1;-- Zapytanie 2SELECT cena FROM towary WHERE nazwa = 'Markery 4 szt.';-- Zapytanie 3SELECT dostawcy.id, dostawcy.nazwa, COUNT(towary.id) AS liczba_towarow FROM dostawcy JOIN towary ON idDostawcy = dostawcy.id GROUP BY dostawcy.nazwa;-- Zapytanie 4ALTER TABLE dostawcy ADD COLUMN informacje TEXT;
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 8-20 · po tym etapie masz 19 z 38 kryteriów (pkt)
Krok 8: promocja.png: 180 px szerokości z przezroczystością
Kryteria:
R.2.1 Obraz z pliku promocja.png przeskalowano do szerokości 180 px, odpowiadająca temu wysokość wynosi 162 px (± 5 px) oraz obraz ma tło przezroczyste
ok. 2 min
Polecenie z arkusza
Przygotowanie grafiki: Plik promocja.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego szerokość wynosiła dokładnie 180 px. Plik powinien być zapisany z zachowaniem przezroczystości pod tą samą nazwą.
Obraz ma 378 × 340 px i przezroczyste tło. W GIMP-ie: Obraz → Skaluj obraz, łańcuch proporcji zamknięty, szerokość 180 - wysokość wyjdzie 162 px (340 × 180 / 378; klucz R.2.1: 162 ± 5). Eksportuj jakopromocja.png - format PNG zachowuje kanał przezroczystości, więc tło dalej jest przezroczyste (na stronie prześwituje kolor panelu).
Typowe błędy
Eksport do JPEG (albo spłaszczenie obrazu) zamienia przezroczyste tło na białe - klucz R.2.1 wymaga przezroczystości.
Podgląd strony po tym kroku
Krok 9: Plik index.php w HTML5
Kryteria:
R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy standard kodowania polskich znaków
ok. 2 min
Polecenie z arkusza
Cechy witryny: Składa się ze strony o nazwie index.php. Zapisany w języku HTML5.
Utwórz index.php: <!DOCTYPE html> i szkielet <html>, <head>, <body>.
R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy standard kodowania polskich znaków
R.2.2 Witrynę internetową zapisano w pliku index.php, zastosowano deklarację języka HTML5 <!DOCTYPE html>, zadeklarowano język witryny polski np. <html lang = "pl"> oraz zastosowano właściwy 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"> - przycisk SPRAWDŹ i nagłówek „Sprawdź cenę” mają polskie litery.
Tytuł strony widoczny na karcie przeglądarki „Sklep dla uczniów”.
<title> w <head> (R.2.3).
index.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title></head><body></body></html>
Podgląd strony po tym kroku (index.php)
Krok 13: Podpięcie arkusza stylów
Kryteria:
R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony.
<link rel="stylesheet" href="styl.css">.
Typowe błędy
Klucz R.3.5 odbiera punkt także za źle przypisany selektor bloku (np. kropka zamiast #).
index.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body></body></html>
Podgląd strony po tym kroku (index.php)
Krok 14: Bloki: baner, trzy panele, stopka
Kryteria:
R.2.4 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, panele lewy, środkowy, prawy, oraz stopkę. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: na górze baner, poniżej bloki: lewy, środkowy i prawy oraz na dole blok stopki. 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.
Baner to <header>, stopka <footer>, a trzy panele - trzy <section> z identyfikatorami left, middle, right (po angielsku). Panele lewy i prawy mają wspólny wygląd, środkowy - własny, więc CSS musi je rozróżniać (R.2.4).
R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail
ok. 1 min
Polecenie z arkusza
Zawartość banera: nagłówek pierwszego stopnia o treści „Dzisiejsze promocje naszego sklepu”.
R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail
R.2.6 W bloku lewym umieszczono jedną listę numerowaną (w kodzie HTML lub skrypcie), użyto znaczników <ol>, <li>
ok. 1 min
Polecenie z arkusza
Zawartość bloku lewego: Nagłówek drugiego stopnia o treści „Taniej o 30%”. Lista numerowana (uporządkowana) zgodna z obrazem 2, elementy listy generowane są skryptem 1.
<h2> i pusta <ol> - elementy wypisze skrypt 1. Na obrazie 2 lista jest numerowana literami (a, b, c) - to zrobi CSS.
Krok 17: Panel środkowy: formularz z listą rozwijalną
Kryteria: , , , ,
R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail
R.2.7 W bloku środkowym umieszczono listę rozwijaną, zawierającą nazwy: Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt. użyto znaczników <select>, <option>
R.2.8 W bloku środkowym umieszczono przycisk SPRAWDŹ
R.3.2 Dane z formularza przesyłane są za pomocą metody POST do tego samego pliku (poprawne również bez atrybutu action)
R.3.3 Przycisk w formularzu realizuje wysyłanie danych do skryptu (input lub button z typem submit lub button bez typu)
ok. 3 min
Polecenie z arkusza
Zawartość bloku środkowego: Nagłówek drugiego stopnia o treści „Sprawdź cenę”. Formularz wysyłający dane do tego samego pliku metodą bezpieczną oraz składający się z: Listy rozwijalnej zawierającej nazwy towarów: „Gumka do mazania”, „Cienkopis”, „Pisaki 60 szt.”, „Markery 4 szt.”. Przycisku SPRAWDŹ, którego wybranie powoduje wysłanie danych do skryptu 2.
Metoda bezpieczna w rozumieniu arkusza to method="post": dane idą w treści żądania, a nie w adresie strony. 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. Bez atrybutu action formularz wysyła dane do tego samego pliku (R.3.2).
Lista rozwijalna to <select> z nazwą product (pod tą nazwą PHP odczyta wybór) i cztery <option>. Opcja bez atrybutu value wysyła swój tekst - a skrypt potrzebuje właśnie nazwy towaru (R.2.7).
Krok 19: Panel prawy: kontakt z odsyłaczem pocztowym i obraz
Kryteria: , ,
R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail
R.2.9 W bloku prawym umieszczono obraz promocja.png z tekstem alternatywnym "promocja"
R.3.4 Napis [email protected] jest odsyłaczem pocztowym, w definicji zastosowano "mailto:"
ok. 2 min
Polecenie z arkusza
Zawartość bloku prawego: Nagłówek drugiego stopnia o treści: „Kontakt”. Paragraf (akapit) o treści „e-mail: [email protected]”, gdzie napis „[email protected]” jest odsyłaczem pocztowym łączącym z tym adresem. Obraz promocja.png z tekstem alternatywnym „promocja”.
Odsyłacz pocztowy to zwykły <a>, ale adres zaczyna się od mailto: - kliknięcie otwiera program pocztowy z wpisanym odbiorcą (R.3.4). Odnośnikiem jest sam adres, słowo „e-mail:” zostaje zwykłym tekstem. Pod spodem przeskalowany obraz (R.2.9).
R.2.5 Zapisano w banerze nagłówek h1 "Dzisiejsze promocje naszego sklepu”; w panelach przynajmniej jeden z nagłówków h2: "Taniej o 30%”, "Sprawdź cenę”, "Kontakt"; w stopce nagłówek h4 z numerem zdającego oraz w panelu prawym zapisano paragraf z adresem e-mail
ok. 1 min
Polecenie z arkusza
Zawartość stopki: nagłówek czwartego stopnia o treści „Autor strony: ”, dalej wstawiony numer zdającego.
<h4> w <footer> - w tym arkuszu stopka ma nagłówek, nie akapit. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL).
Krok 25: Lista: numeracja literami, elementy do lewej
Kryteria:
R.4.7 Ustawiono styl selektora ol: małe litery (np. list-style-type: lower-alpha;) oraz styl selektora li: wyrównanie tekstu do lewej strony
ok. 1 min
Polecenie z arkusza
Dla selektora listy numerowanej: numeracja małymi literami. Dla selektora elementu listy: wyrównanie tekstu do lewej strony.
list-style-type: lower-alpha numeruje elementy literami a, b, c… (upper-alpha - wielkimi, lower-roman - rzymskimi). li { text-align: left } nadpisuje domyślne wyśrodkowanie z * tylko dla elementów listy. Arkusz wymaga selektorów znaczników ol i li (R.4.7).
R.4.8 Ustawiono obramowanie dla selektora img na 1px dashed #8C7B75 oraz obramowanie dla bloku z wynikiem działania skryptu 2: 1px solid #8C7B75
R.4.9 Ustawiono dla obrazu marginesy wewnętrzne (padding) na 5px oraz dla bloku z wynikami skryptu 2 jedynie margines zewnętrzny górny (np. margin-top) na 100px
R.4.10 Ustawiono dla obrazu zaokrąglenie obramowania 10% (np. border-radius: 10%;)
ok. 1 min
Polecenie z arkusza
Dla selektora obrazu: obramowanie o szerokości 1 px linią kreskową koloru #8C7B75, marginesy wewnętrzne 5 px, zaokrąglenie obramowania 10%.
Linia kreskowa to dashed. padding odsuwa ramkę od obrazu, a border-radius: 10% zaokrągla jej rogi - jak na obrazie 2.
R.4.8 Ustawiono obramowanie dla selektora img na 1px dashed #8C7B75 oraz obramowanie dla bloku z wynikiem działania skryptu 2: 1px solid #8C7B75
R.4.9 Ustawiono dla obrazu marginesy wewnętrzne (padding) na 5px oraz dla bloku z wynikami skryptu 2 jedynie margines zewnętrzny górny (np. margin-top) na 100px
ok. 1 min
Polecenie z arkusza
Dla bloku z wynikiem działania skryptu 2: margines zewnętrzny górny 100 px, obramowanie o szerokości 1 px linią ciągłą koloru #8C7B75.
margin-top: 100px odsuwa blok od formularza, linia ciągła to solid. Pusty blok jest na razie tylko poziomą kreską - wypełni go skrypt 2.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display z wartością flex lub grid albo position)
ok. 2 min
Polecenie z arkusza
Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z obrazem 2.
section { float: left; } stawia trzy panele obok siebie (35% + 30% + 35% = 100% - bez marginesów, inaczej ostatni spadłby niżej), a footer { clear: both; } sprowadza stopkę pod nie (R.3.1).
Typowe błędy
Dodanie panelom marginesu albo ramki przekracza 100% szerokości - prawy panel spada pod lewy.
Kroki 29-35 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 29: Połączenie z bazą danych
Kryteria:
R.5.1 Zastosowano funkcję realizującą połączenie z serwerem bazy danych na localhost, użytkownik root, bez hasła, baza danych sklep
ok. 2 min
Polecenie z arkusza
Wymagania dotyczące skryptu: Napisany w języku PHP, umieszczony w pliku index.php. Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie sklep.
Połączenie otwierasz raz, zaraz po <body>, w zmiennej $connection. mysqli_connect: serwer, użytkownik, hasło (puste), nazwa bazy (R.5.1). Od tego kroku podgląd to wynik działania strony po stronie serwera.
R.5.3 Skrypt 1 zawiera instrukcję wysyłającą do bazy danych zapytanie 1
R.5.4 Skrypt 1 wyświetla nazwy towarów zwrócone zapytaniem (Gumka do mazania, Cienkopis, Pisaki 60 szt., Markery 4 szt.)
R.5.5 Wyświetlane przez skrypt 1 nazwy towarów są elementami listy numerowanej
ok. 3 min
Polecenie z arkusza
Skrypt 1: Wysyła do bazy danych zapytanie 1. Nazwy towarów zwrócone zapytaniem wypisywane są jako elementy listy numerowanej.
Skrypt stoi wewnątrz <ol>. mysqli_query wysyła zapytanie 1, pętla while z mysqli_fetch_row wypisuje każdą nazwę w <li>. W podglądzie: cztery towary, numerowane literami a-d, jak na obrazie 2 (R.5.3, R.5.4, R.5.5).
Skrypt 2: Pobiera z formularza nazwę towaru wybranego w liście rozwijalnej.
Skrypt 2 stoi w bloku wyniku. Dane wysłane metodą POST są w tablicy $_POST, pod nazwą pola z formularza: $_POST['product']. Przy pierwszym wejściu na stronę formularz nie był jeszcze wysłany i tej wartości nie ma - dlatego całość obejmujesz warunkiem isset (funkcja PHP spoza tabeli 1 arkusza - ta wymienia tylko funkcje mysqli): kod wykona się dopiero po kliknięciu SPRAWDŹ.
Typowe błędy
Bez isset pierwsze otwarcie strony pokazuje ostrzeżenie PHP „Undefined array key product”.
R.5.6 Skrypt 2 zawiera instrukcję wysyłającą do bazy danych zapytanie 2 zmodyfikowane tak, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijanej
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 2, zmodyfikowane w ten sposób, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijalnej.
Zapytanie 2, ale zamiast stałej nazwy - zmienna: WHERE nazwa = '$product'. Zapytanie bierzesz w cudzysłów, bo w cudzysłowie PHP podstawia wartości zmiennych; apostrofy wokół nazwy zostają wewnątrz, bo nazwa to tekst w SQL. Zapytanie zwraca jeden wiersz, więc wystarczy jedno mysqli_fetch_row. Od tego kroku podgląd pokazuje stronę po wysłaniu formularza z wybraną gumką do mazania (R.5.6).
⚠️ Wklejanie tekstu z formularza do SQL jest niebezpieczne - poprawisz to w etapie „Dobre praktyki”.
index.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body><?php$connection = mysqli_connect('localhost', 'root', '', 'sklep');?> <header> <h1>Dzisiejsze promocje naszego sklepu</h1> </header> <sectionid="left"> <h2>Taniej o 30%</h2> <ol><?php$products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');while ($row = mysqli_fetch_row($products)) {echo"<li>$row[0]</li>";}?> </ol> </section> <sectionid="middle"> <h2>Sprawdź cenę</h2> <formmethod="post"> <selectname="product"> <option>Gumka do mazania</option> <option>Cienkopis</option> <option>Pisaki 60 szt.</option> <option>Markery 4 szt.</option> </select> <buttontype="submit">SPRAWDŹ</button> </form> <divid="result"><?phpif (isset($_POST['product'])) {$product = $_POST['product'];$prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");$row = mysqli_fetch_row($prices);}?> </div> </section> <sectionid="right"> <h2>Kontakt</h2> <p>e-mail: <ahref="mailto:[email protected]">[email protected]</a></p> <imgsrc="promocja.png"alt="promocja"> </section> <footer> <h4>Autor strony: Bartosz Bryniarski</h4> </footer></body></html>
R.5.8 Skrypt 2 wyświetla dane w bloku pod formularzem, w dwóch wierszach, zgodnie z formatem cena regularna: <cena_pobrana_z_bazy> cena w promocji 30%: <obliczona_cena>
ok. 2 min
Polecenie z arkusza
Pod formularzem wypisuje dane w bloku, zgodnie z obrazem 2, w formacie: cena regularna: <cena_pobrana_z_bazy> cena w promocji 30%: <obliczona_cena>.
Dwie linie echo, a między nimi <br> - dwa wiersze w jednym bloku, jak na obrazie 2: „cena regularna: 3.2” i „cena w promocji 30%: 2.24” (R.5.8).
index.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body><?php$connection = mysqli_connect('localhost', 'root', '', 'sklep');?> <header> <h1>Dzisiejsze promocje naszego sklepu</h1> </header> <sectionid="left"> <h2>Taniej o 30%</h2> <ol><?php$products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');while ($row = mysqli_fetch_row($products)) {echo"<li>$row[0]</li>";}?> </ol> </section> <sectionid="middle"> <h2>Sprawdź cenę</h2> <formmethod="post"> <selectname="product"> <option>Gumka do mazania</option> <option>Cienkopis</option> <option>Pisaki 60 szt.</option> <option>Markery 4 szt.</option> </select> <buttontype="submit">SPRAWDŹ</button> </form> <divid="result"><?phpif (isset($_POST['product'])) {$product = $_POST['product'];$prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");$row = mysqli_fetch_row($prices);$promoPrice = $row[0] * 0.7;echo"cena regularna: $row[0]<br>";echo"cena w promocji 30%: $promoPrice";}?> </div> </section> <sectionid="right"> <h2>Kontakt</h2> <p>e-mail: <ahref="mailto:[email protected]">[email protected]</a></p> <imgsrc="promocja.png"alt="promocja"> </section> <footer> <h4>Autor strony: Bartosz Bryniarski</h4> </footer></body></html>
Podgląd strony po tym kroku (index.php)
Krok 35: Zamknięcie połączenia
Kryteria:
R.5.2 Ostatnią operacją na bazie jest zamknięcie połączenia z serwerem bazy danych
ok. 1 min
Polecenie z arkusza
Na końcu działania skrypt zamyka połączenie z serwerem.
mysqli_close($connection) po stopce - ostatnia operacja na bazie (R.5.2). Strona spełnia wszystkie kryteria arkusza.
index.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body><?php$connection = mysqli_connect('localhost', 'root', '', 'sklep');?> <header> <h1>Dzisiejsze promocje naszego sklepu</h1> </header> <sectionid="left"> <h2>Taniej o 30%</h2> <ol><?php$products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');while ($row = mysqli_fetch_row($products)) {echo"<li>$row[0]</li>";}?> </ol> </section> <sectionid="middle"> <h2>Sprawdź cenę</h2> <formmethod="post"> <selectname="product"> <option>Gumka do mazania</option> <option>Cienkopis</option> <option>Pisaki 60 szt.</option> <option>Markery 4 szt.</option> </select> <buttontype="submit">SPRAWDŹ</button> </form> <divid="result"><?phpif (isset($_POST['product'])) {$product = $_POST['product'];$prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");$row = mysqli_fetch_row($prices);$promoPrice = $row[0] * 0.7;echo"cena regularna: $row[0]<br>";echo"cena w promocji 30%: $promoPrice";}?> </div> </section> <sectionid="right"> <h2>Kontakt</h2> <p>e-mail: <ahref="mailto:[email protected]">[email protected]</a></p> <imgsrc="promocja.png"alt="promocja"> </section> <footer> <h4>Autor strony: Bartosz Bryniarski</h4> </footer><?phpmysqli_close($connection);?></body></html>
Kroki 36-37 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 36: Skrypt 2: zapytanie przygotowane zamiast wklejania $_POST
ok. 4 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 2, zmodyfikowane w ten sposób, że w sekcji warunku nazwa towaru jest zgodna z wyborem w liście rozwijalnej.
Lista rozwijalna nie chroni przed niczym - wysłane dane da się podmienić w narzędziach przeglądarki i wpisać np. ' OR 1=1 --. Wklejone do SQL zmienia sens zapytania (SQL injection). Zapytanie przygotowane rozdziela kod i dane: mysqli_prepare z ? w miejscu nazwy, mysqli_stmt_bind_param z typem 's' (string) - wartość nigdy nie stanie się częścią SQL. Gdy towaru nie ma ($row puste), skrypt nic nie wypisuje zamiast ostrzeżeń. Stare linie zostają w komentarzu. Podgląd bez zmian.
Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
index.phpPHPzmienione: 12 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body><?php$connection = mysqli_connect('localhost', 'root', '', 'sklep');?> <header> <h1>Dzisiejsze promocje naszego sklepu</h1> </header> <sectionid="left"> <h2>Taniej o 30%</h2> <ol><?php$products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');while ($row = mysqli_fetch_row($products)) {echo"<li>$row[0]</li>";}?> </ol> </section> <sectionid="middle"> <h2>Sprawdź cenę</h2> <formmethod="post"> <selectname="product"> <option>Gumka do mazania</option> <option>Cienkopis</option> <option>Pisaki 60 szt.</option> <option>Markery 4 szt.</option> </select> <buttontype="submit">SPRAWDŹ</button> </form> <divid="result"><?phpif (isset($_POST['product'])) {$statement = mysqli_prepare($connection, 'SELECT cena FROM towary WHERE nazwa = ?'); mysqli_stmt_bind_param($statement, 's', $_POST['product']); mysqli_stmt_execute($statement);$row = mysqli_fetch_row(mysqli_stmt_get_result($statement));// $product = $_POST['product'];// $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");// $row = mysqli_fetch_row($prices);if ($row) {$promoPrice = $row[0] * 0.7;echo"cena regularna: $row[0]<br>";echo"cena w promocji 30%: $promoPrice"; }}?> </div> </section> <sectionid="right"> <h2>Kontakt</h2> <p>e-mail: <ahref="mailto:[email protected]">[email protected]</a></p> <imgsrc="promocja.png"alt="promocja"> </section> <footer> <h4>Autor strony: Bartosz Bryniarski</h4> </footer><?phpmysqli_close($connection);?></body></html>
Na podstawie ceny zwróconej zapytaniem oblicza cenę promocyjną jako wartość niższą o 30%.
Mnożenie liczb zmiennoprzecinkowych daje czasem wyniki w rodzaju 15.679999999 i zawsze wypisuje kropkę. number_format($cena, 2, ',', ' ') formatuje liczbę po polsku: dwa miejsca po przecinku, przecinek dziesiętny i spacja między tysiącami - „2,24 zł”, „38,50 zł”. Policz dalej na liczbach, sformatuj dopiero przy wypisywaniu.
Na egzaminie wystarczy wersja wcześniejsza - format z obrazu 2 to „2.24”, a klucz nie wymaga zaokrąglania.
index.phpPHPzmienione: 4 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Sklep dla uczniów</title> <linkrel="stylesheet"href="styl.css"></head><body><?php$connection = mysqli_connect('localhost', 'root', '', 'sklep');?> <header> <h1>Dzisiejsze promocje naszego sklepu</h1> </header> <sectionid="left"> <h2>Taniej o 30%</h2> <ol><?php$products = mysqli_query($connection, 'SELECT nazwa FROM towary WHERE promocja = 1;');while ($row = mysqli_fetch_row($products)) {echo"<li>$row[0]</li>";}?> </ol> </section> <sectionid="middle"> <h2>Sprawdź cenę</h2> <formmethod="post"> <selectname="product"> <option>Gumka do mazania</option> <option>Cienkopis</option> <option>Pisaki 60 szt.</option> <option>Markery 4 szt.</option> </select> <buttontype="submit">SPRAWDŹ</button> </form> <divid="result"><?phpif (isset($_POST['product'])) {$statement = mysqli_prepare($connection, 'SELECT cena FROM towary WHERE nazwa = ?'); mysqli_stmt_bind_param($statement, 's', $_POST['product']); mysqli_stmt_execute($statement);$row = mysqli_fetch_row(mysqli_stmt_get_result($statement));// $product = $_POST['product'];// $prices = mysqli_query($connection, "SELECT cena FROM towary WHERE nazwa = '$product';");// $row = mysqli_fetch_row($prices);if ($row) {$promoPrice = $row[0] * 0.7;$regular = number_format($row[0], 2, ',', ' ');$promo = number_format($promoPrice, 2, ',', ' ');echo"cena regularna: $regular zł<br>";echo"cena w promocji 30%: $promo zł"; }}?> </div> </section> <sectionid="right"> <h2>Kontakt</h2> <p>e-mail: <ahref="mailto:[email protected]">[email protected]</a></p> <imgsrc="promocja.png"alt="promocja"> </section> <footer> <h4>Autor strony: Bartosz Bryniarski</h4> </footer><?phpmysqli_close($connection);?></body></html>
Podgląd strony po tym kroku (index.php)
Etap 6: Oddanie pracy
Krok 38 · po tym etapie masz 38 z 38 kryteriów (pkt)
Krok 38: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz w folderze z numerem zdającego 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 folderze z numerem zdającego powinny się znajdować następujące pliki: baza.jpg, index.php, kwerenda1.jpg, kwerenda2.jpg kwerenda3.jpg kwerenda4.jpg, kwerendy.txt, promocja.png, przeglądarka.txt, styl.css oraz ewentualnie inne przygotowane pliki.
W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….
Sprawdź listę plików z arkusza (sklep.sql z archiwum nie jest na niej wymieniony, ale może zostać), 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.