Serwis używa plików cookies do analizy ruchu i poprawy działania. Szczegóły
E.14-03-20.06-SGCzerwiec 2020 · 34 kroki · ok. 78 min · 36 kryteriów z klucza
Rozwiązanie krok po kroku: Kwiaciarnie i wyszukiwarka po mieście (Nowoczesny kod (flex, PDO))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza kwiaciarnia z dwiema tabelami i trzema zapytaniami, zdjęcia kwiatów 190 × 190 px oraz strony index.html i znajdz.php z wyszukiwarką kwiaciarni - i tak samo spełnia każde kryterium klucza. Inna jest droga:
flex zamiast float: dwa panele stoją we wspólnym znaczniku <main>, który układa je obok siebie, a stopka nie potrzebuje clear. Szerokości 20% i 80% zostają na panelach, bo tam sprawdza je klucz z 2020 roku,
zmienne CSS dla kolorów z arkusza, odnośniki w znaczniku <nav> ustawione jeden pod drugim stylem zamiast <br>,
PHP na PDO na górze pliku znajdz.php, przed HTML-em - pod formularzem zostaje tylko pętla wypisująca wyniki,
zapytanie przygotowane z parametrem :city, wpis bez spacji z brzegów, wyniki przez htmlspecialchars, wpisana miejscowość wraca do pola i komunikat, gdy w mieście nie ma kwiaciarni.
To arkusz E.14 z czerwca 2020 - kwalifikacji formuły 2012, którą zastąpiła INF.03. Zdjęcia pochodzą z oryginalnego archiwum CKE egzamin3.zip (załącznik na stronie arkusza), zapytania są wykonane na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2.
Jak liczą się punkty. Klucz ma 36 kryteriów (R.1.1 - R.5.5), 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 nie narzuca biblioteki do obsługi bazy.
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-8 · po tym etapie masz 9 z 36 kryteriów (pkt)
Krok 1: Folder zdającego, archiwum i baza kwiaciarnia
ok. 3 min
Polecenie z arkusza
Na pulpicie utwórz folder i nazwij go Twoim numerem PESEL. Wszystkie pliki utworzone w czasie egzaminu umieść w tym folderze. Za pomocą wizualnych elementów (kreatorów) przystawki phpMyAdmin programu XAMPP utwórz bazę danych według wytycznych: Nazwa bazy kwiaciarnia
Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego zdjęcia z archiwum egzamin3.zip rozpakowanego z hasłem 5T2k@W$2n. W phpMyAdmin nowa baza kwiaciarnia z porównywaniem utf8mb4_polish_ci - pełne UTF-8 i polska kolejność alfabetyczna.
Arkusz każe utworzyć tabele kreatorem. Formularz kreatora wypełniasz tak, żeby powstał SQL pokazany w kolejnych krokach - phpMyAdmin wyświetla go po zapisie.
Krok 2: Tabela kwiaciarnie
Kryteria:
R.1.4 Tabela kwiaciarnie ma pola nazwa, miasto i ulica dowolnego typu tekstowego
ok. 3 min
Polecenie z arkusza
Tabela kwiaciarnie z autonumerowanym kluczem podstawowym id_kwiaciarni
CREATE TABLE kwiaciarnie (
id_kwiaciarni INT UNSIGNED NOT NULL AUTO_INCREMENT,
nazwa VARCHAR(50) NOT NULL,
miasto VARCHAR(50) NOT NULL,
ulica VARCHAR(50) NOT NULL,
PRIMARY KEY (id_kwiaciarni)
);
INT UNSIGNED - numer kwiaciarni nigdy nie jest ujemny, więc zakres dodatnich liczb jest dwa razy większy,
NOT NULL przy nazwie, mieście i ulicy - kwiaciarnia bez adresu nie ma sensu, baza odrzuci taki wiersz,
pola tekstowe VARCHAR(50) (R.1.4), w kreatorze: zaznaczone A_I i indeks PRIMARY przy id_kwiaciarni.
Krok 3: Tabela zamowienia
Kryteria: ,
R.1.2 Tabela kwiaciarnie ma klucz podstawowy id_kwiaciarni oraz tabela zamowienia ma klucz podstawowy id_zam, oba klucze są autoinkrementowane
R.1.3 Tabela zamowienia ma pola: id_kwiaciarni dowolnego typu całkowitego, data typu date, kwiaty typu tekstowego i cena dowolnego typu liczbowego
ok. 3 min
Polecenie z arkusza
Tabela zamowienia z autonumerowanym kluczem podstawowym id_zam. Pola oraz dane obu tabel znajdują się w tabelach 1 i 2, należy je wprowadzić do tabel
CREATE TABLE zamowienia (
id_zam INT UNSIGNED NOT NULL AUTO_INCREMENT,
id_kwiaciarni INT UNSIGNED NOT NULL,
data DATE NOT NULL,
kwiaty VARCHAR(50) NOT NULL,
cena DECIMAL(8, 2) NOT NULL,
PRIMARY KEY (id_zam)
);
data DATE - typ daty, którego wymaga klucz (R.1.3),
cena DECIMAL(8, 2) - kwoty pieniędzy zapisuje się typem dziesiętnym o stałej liczbie miejsc po przecinku: 125.00. Ceny w arkuszu są całkowite, ale w prawdziwej kwiaciarni róża kosztuje 12,50 zł; typ FLOAT zaokrąglałby grosze. Klucz przyjmuje dowolny typ liczbowy,
id_kwiaciarni INT UNSIGNED - ten sam typ co klucz w tabeli kwiaciarnie, na którą wskazuje.
Obie tabele mają autonumerowane klucze podstawowe (R.1.2).
Krok 4: Dane obu tabel
Kryteria:
R.1.5 Tabele zamowienia i kwiaciarnie wypełniono zgodnie z tabelą 1 i 2 arkusza
ok. 4 min
Polecenie z arkusza
Pola oraz dane obu tabel znajdują się w tabelach 1 i 2, należy je wprowadzić do tabel
Numerów id nie trzeba podawać - autonumerowanie nada je kolejno od 1, dokładnie jak w tabelach arkusza. Daty w formacie RRRR-MM-DD, kwiaty z polskimi literami (R.1.5). Podgląd: tabela zamowienia (cena w wersji nowoczesnej wyświetla się jako 125.00).
Podgląd strony po tym kroku
Krok 5: Kwerenda 1: kwiaciarnie z Malborka
Kryteria: ,
R.1.6 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.7 Zapisano zapytanie 1 wybierające jedynie pole nazwa i ulica dla kwiaciarni z miasta Malbork. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwa, ulica FROM kwiaciarnie WHERE miasto="Malbork"; oraz na zrzucie ekranu widoczne są jedynie dwa pola: nazwa, ulica; wartości Melisa, Konopnickiej
ok. 3 min
Polecenie z arkusza
Kwerenda 1: wybierająca jedynie pole nazwa i ulica dla kwiaciarni z miasta Malbork
Każda klauzula w osobnej linii - łatwiej czytać i porównać z poleceniem: dwa pola, tabela kwiaciarnie, warunek na mieście. Wynik: Melisa, Konopnickiej. Zapytanie do kwerendy.txt, zrzut całego ekranu do kw1.jpg (R.1.6, R.1.7). To samo zapytanie, z parametrem w miejscu miasta, wykona skrypt PHP.
kwerendy.txtTekstnowy plik
-- Kwerenda 1SELECT nazwa, ulicaFROM kwiaciarnieWHERE miasto = 'Malbork';
Podgląd strony po tym kroku
Krok 6: Kwerenda 2: zamówienie z 7 stycznia 2017
Kryteria:
R.1.8 Zapisano zapytanie 2 wybierające jedynie id zamówienia, złożonego z datą 7 stycznia 2017 r. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id_zam FROM zamowienia WHERE data="2017.01.07"; oraz na zrzucie ekranu widoczne jest jedynie pole id_zam z jedną wartością: 5
ok. 2 min
Polecenie z arkusza
Kwerenda 2: wybierająca jedynie id zamówienia, złożonego z datą 7 stycznia 2017 r.
Data w zapytaniu w formacie ISO 2017-01-07 - tym samym, w którym zapisuje ją pole DATE. Wynik: zamówienie 5, zrzut kw2.jpg (R.1.8).
kwerendy.txtTekstzmienione: 5 linii
-- Kwerenda 1SELECT nazwa, ulicaFROM kwiaciarnieWHERE miasto = 'Malbork';-- Kwerenda 2SELECT id_zamFROM zamowieniaWHERE data = '2017-01-07';
Podgląd strony po tym kroku
Krok 7: Kwerenda 3: liczba zamówień każdej kwiaciarni
Kryteria:
R.1.9 Zapisano zapytanie 3 wybierające jedynie pole id_kwiaciarni oraz liczące liczbę zamówień (wierszy) dla poszczególnych kwiaciarni. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id_kwiaciarni, COUNT(id_kwiaciarni) FROM zamowienia GROUP BY id_kwiaciarni; oraz na zrzucie ekranu widoczne są dwa wiersze o wartościach 1, 4 oraz 2, 2; odpowiadają one polom id_kwiaciarni i policzonej liczbie kwiaciarni
ok. 3 min
Polecenie z arkusza
Kwerenda 3: wybierająca jedynie pole id_kwiaciarni oraz licząca liczbę zamówień (wierszy) dla poszczególnych kwiaciarni
GROUP BY id_kwiaciarni dzieli zamówienia na grupy, a COUNT(*) liczy wiersze każdej grupy. AS liczba_zamowien nadaje kolumnie wyniku czytelną nazwę zamiast COUNT(*) - przydaje się, gdy wynik odczytuje skrypt. Wynik: 1, 4 i 2, 2, zrzut kw3.jpg (R.1.9).
kwerendy.txtTekstzmienione: 5 linii
-- Kwerenda 1SELECT nazwa, ulicaFROM kwiaciarnieWHERE miasto = 'Malbork';-- Kwerenda 2SELECT id_zamFROM zamowieniaWHERE data = '2017-01-07';-- Kwerenda 3SELECT id_kwiaciarni, COUNT(*) AS liczba_zamowienFROM zamowieniaGROUP BY id_kwiaciarni;
Podgląd strony po tym kroku
Krok 8: Eksport bazy do pliku kwiaciarnia.sql
Kryteria:
R.1.1 Wykonano eksport bazy lub tabel z bazy do pliku kwiaciarnia.sql . Czas generowania wpisany w nagłówku pliku jest zgodny z datą i godziną egzaminu
ok. 2 min
Polecenie z arkusza
Wyeksportuj tabele bazy danych do pliku kwiaciarnia.sql
Zaznaczona baza kwiaciarnia, karta Eksport, format SQL. Czas generowania w nagłówku pliku musi się zgadzać z datą i godziną egzaminu (R.1.1). Plik w archiwum rozwiązania to eksport z wersji podstawowej (mysqldump, bez linii z czasem generowania).
kwiaciarnia.sqlSQLnowy plik
-- MariaDB dump 10.19 Distrib 10.4.27-MariaDB, for Win64 (AMD64)---- Host: localhost Database: kwiaciarnia-- -------------------------------------------------------- Server version 10.4.27-MariaDB/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;/*!40101 SET NAMES utf8mb4 */;/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;/*!40103 SET TIME_ZONE='+00:00' */;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;---- Table structure for table `kwiaciarnie`--DROP TABLE IF EXISTS `kwiaciarnie`;/*!40101 SET @saved_cs_client = @@character_set_client */;/*!40101 SET character_set_client = utf8 */;CREATETABLE `kwiaciarnie` ( `id_kwiaciarni` int(11) NOT NULL AUTO_INCREMENT, `nazwa` varchar(50) DEFAULT NULL, `miasto` varchar(50) DEFAULT NULL, `ulica` varchar(50) DEFAULT NULL,PRIMARYKEY (`id_kwiaciarni`)) ENGINE=InnoDB AUTO_INCREMENT=3DEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci;/*!40101 SET character_set_client = @saved_cs_client */;---- Dumping data for table `kwiaciarnie`--LOCK TABLES `kwiaciarnie` WRITE;/*!40000 ALTER TABLE `kwiaciarnie` DISABLE KEYS */;INSERTINTO `kwiaciarnie` VALUES (1,'Astra','Warszawa','Sobieskiego'),(2,'Melisa','Malbork','Konopnickiej');/*!40000 ALTER TABLE `kwiaciarnie` ENABLE KEYS */;UNLOCKTABLES;---- Table structure for table `zamowienia`--DROP TABLE IF EXISTS `zamowienia`;/*!40101 SET @saved_cs_client = @@character_set_client */;/*!40101 SET character_set_client = utf8 */;CREATETABLE `zamowienia` ( `id_zam` int(11) NOT NULL AUTO_INCREMENT, `id_kwiaciarni` int(11) DEFAULT NULL, `data` dateDEFAULT NULL, `kwiaty` varchar(50) DEFAULT NULL, `cena` int(11) DEFAULT NULL,PRIMARYKEY (`id_zam`)) ENGINE=InnoDB AUTO_INCREMENT=7DEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci;/*!40101 SET character_set_client = @saved_cs_client */;---- Dumping data for table `zamowienia`--LOCK TABLES `zamowienia` WRITE;/*!40000 ALTER TABLE `zamowienia` DISABLE KEYS */;INSERTINTO `zamowienia` VALUES (1,1,'2017-01-16','róża',250),(2,1,'2017-01-10','gerbera',120),(3,2,'2017-01-06','róża',200),(4,2,'2017-01-09','goździk',170),(5,1,'2017-01-07','róża',125),(6,1,'2017-01-11','róża',75);/*!40000 ALTER TABLE `zamowienia` ENABLE KEYS */;UNLOCKTABLES;/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;-- Dump completed
Etap 2: Grafika
Krok 9 · po tym etapie masz 10 z 36 kryteriów (pkt)
Krok 9: Zdjęcia 1:1, 190 × 190 px, JPEG
Kryteria:
R.2.1 Zapisano przynajmniej jeden obraz z roza, gerbera, gozdzik w formacie JPEG, o rozmiarze 190 px na 190 px (± 2 px, zachowując proporcję 1:1)
ok. 5 min
Polecenie z arkusza
Wytyczne odnośnie grafiki zapisanej w plikach roza.png, gerbera.png, gozdzik.png: obrazy przycięte (wykadrowane) do proporcji 1:1, rozmiar 190 px na 190 px, format JPEG
Grafika jest taka sama jak w wersji podstawowej - wymagania arkusza nie zostawiają tu wyboru. W GIMP-ie dla każdego zdjęcia: Kadrowanie z proporcjami 1:1 wyśrodkowane na kwiecie, Obraz → Skaluj obraz do 190 × 190 px i Plik → Eksportuj jakogerbera.jpg, gozdzik.jpg, roza.jpg (R.2.1).
Podgląd strony po tym kroku
Etap 3: Strona index.html
Kroki 10-17 · po tym etapie masz 18 z 36 kryteriów (pkt)
Krok 10: Szkielet strony i kodowanie znaków
ok. 1 min
Polecenie z arkusza
Witryna internetowa składa się ze stron index.html i znajdz.php. Standard kodowania polskich znaków
<meta charset="UTF-8"> i plik zapisany w UTF-8. Druga linia viewport mówi telefonom, żeby nie udawały szerokiego ekranu - arkusz jej nie wymaga, ale należy do każdej współczesnej strony.
R.2.3 Nadano tytuł przynajmniej jednej stronie "Kwiaty”
R.3.5 Przynajmniej jedna strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie pochodzi jedynie od pliku CSS. 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
Tytuł strony: „Kwiaty”. Połączenie z zewnętrznym arkuszem stylów o nazwie styl.css
<title>Kwiaty</title> (R.2.3) i <link rel="stylesheet" href="styl.css"> (R.3.5). Całe formatowanie trafi do pliku stylów.
R.2.4 Układ przynajmniej jednej strony zdefiniowano dzieląc ją na bloki: baner, panel lewy i prawy oraz stopkę za pomocą znaczników sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: baner, panel lewy i prawy oraz stopkę za pomocą znaczników sekcji
<header>, dwa znaczniki <section> i <footer> (R.2.4). Panele obejmuje znacznik <main> - główna treść strony, bez banera i stopki. Ma dwa zadania: czytnik ekranu pozwala do niego przeskoczyć jednym skrótem, a w CSS będzie pojemnikiem, który ustawi panele obok siebie.
Zawartość banera: nagłówek pierwszego stopnia o treści: „Moje kwiaty”. Zawartość panelu lewego: Nagłówek trzeciego stopnia o treści: „Kwiaty dla Ciebie!”
<h1> w banerze, <h3> w panelu lewym - stopnie nagłówków narzuca arkusz.
R.3.3 Na przynajmniej jednej stronie wybranie odnośnika o treści „Znajdź kwiaciarnię” prowadzi do strony znajdz.php
R.3.4 Na przynajmniej jednej stronie wybranie odnośnika o treści „Rozpoznaj kwiaty” prowadzi do strony https://www.swiatkwiatow.pl/
ok. 2 min
Polecenie z arkusza
Odnośnik o treści „Rozpoznaj kwiaty” prowadzący do strony „https://www.swiatkwiatow.pl/”. Poniżej odnośnik o treści „Znajdź kwiaciarnię” prowadzący do pliku znajdz.php
Odnośniki to menu strony, więc stoją w znaczniku <nav>. Adres zewnętrzny pełny, z https:// (R.3.4), plik znajdz.php - ścieżką względną (R.3.3). Zamiast <br> między nimi - jeden pod drugim ustawi je CSS (display: block), bo układ to sprawa stylu, nie treści.
R.2.7 Na przynajmniej jednej stronie w bloku prawym umieszczono trzy obrazy kwiatów z tekstem alternatywnym odpowiadającym nazwie kwiatu
ok. 2 min
Polecenie z arkusza
Panel prawy dla strony index.html: Obok siebie trzy obrazy z gerberą, goździkiem, różą, tekst alternatywny to nazwa kwiatu. Poniżej paragraf (akapit) o treści „Strona poświęcona miłośnikom kwiatów”
Trzy obrazy w jednej linii z nazwami kwiatów w alt (R.2.7), pod nimi paragraf <p>.
R.2.5 Zapisano na przynajmniej jednej stronie nagłówki: w banerze h1 "Moje kwiaty", w panelu lewym h3 "Kwiaty dla Ciebie!", w stopce h3 "Stronę opracował <PESEL>" oraz w panelu prawym paragraf (znacznik <p>)
ok. 1 min
Polecenie z arkusza
Zawartość stopki: nagłówek trzeciego stopnia o treści: „Stronę opracował:”, dalej wstawiony numer PESEL zdającego
<h3> z numerem PESEL - tu w jego miejscu Bartosz Bryniarski. Nagłówki h1, dwa h3 i paragraf panelu prawego dają R.2.5.
Kroki 18-25 · po tym etapie masz 28 z 36 kryteriów (pkt)
Krok 18: Zmienne z kolorami arkusza
ok. 2 min
Polecenie z arkusza
Styl CSS zawiera formatowanie
Plik styl.css zaczyna się od zmiennych CSS w selektorze :root (cały dokument). LightPink występuje w arkuszu cztery razy - zmienna --pink pozwala zmienić odcień jednym wpisem, a w regułach odczytuje się ją funkcją var(--pink).
styl.cssCSSnowy plik
:root {--pink: LightPink;--dark: black;}
Podgląd strony po tym kroku (index.html)
Krok 19: Krój, wyśrodkowanie i kursywa
Kryteria:
R.4.1 Ustawiono styl domyślny (dla selektora *, lub body, lub html, lub kontenera całej strony) czcionka Times New Roman, wyśrodkowana, kursywa
ok. 1 min
Polecenie z arkusza
domyślnie dla całej strony: czcionka Times New Roman, tekst wyśrodkowany, kursywa
Po kroju z arkusza stoją kroje zapasowe: Times (macOS) i rodzina ogólna serif - gdyby na komputerze nie było Times New Roman, przeglądarka weźmie najbliższy szeryfowy krój (R.4.1).
Podział strony na bloki: baner, panel lewy i prawy oraz stopkę za pomocą znaczników sekcji
display: flex na <main> ustawia jego dzieci - dwie sekcje - w jednym wierszu. Nie ma float, więc stopka sama staje pod <main> bez clear: both, a panele w wierszu flex mają z natury równą wysokość.
Siatka (grid-template-columns: 20% 80%) byłaby równie dobra, ale klucz z 2020 roku ocenia szerokość na panelu (R.4.5) - dlatego pojemnik flex tylko układa, a szerokości zostają w regułach paneli.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest w pełni zgodny z obrazem 1 w arkuszu
R.4.5 Ustawiono szerokość panelu lewego na 20%, panelu prawego na 80%
R.4.6 Ustawiono wielkość czcionki dla panelu lewego 20px i prawego 30px
R.4.7 Ustawiono kolor czcionki LightPink dla panelu prawego
ok. 2 min
Polecenie z arkusza
dla panelu lewego: kolor tła LightPink, wysokość 500 px, szerokość 20%, rozmiar czcionki 20 px; dla panelu prawego: czarny kolor tła, wysokość 500 px, szerokość 80%, rozmiar czcionki 30 px, kolor czcionki LightPink
Szerokości 20% + 80% (R.4.5), rozmiary czcionek 20 i 30 px (R.4.6), różowy tekst na czarnym tle (R.4.7). Selektory z krzyżykiem, bo panele mają id. Panele układa flex z poprzedniego kroku - układ jak na obrazie 1 (R.3.1).
R.4.2 Ustawiono kolor tła dla banera, panelu lewego i stopki na LightPink oraz dla panelu prawego na czarny
R.4.3 Ustawiono wysokość banera 80px, obu paneli 500px, stopki 60px
ok. 1 min
Polecenie z arkusza
dla stopki: kolor tła LightPink, wysokość 60 px
Kolory tła wszystkich bloków (R.4.2) i wysokości 80/500/60 px (R.4.3) są ustawione. display: flow-root zamyka marginesy nagłówka <h3> wewnątrz stopki - bez tego margines „wypływa” nad stopkę i między panelami a stopką zostaje biały pasek (w wersji podstawowej ten sam efekt usuwa clear: both).
R.4.8 Ustawiono styl wyłącznie dla obrazu z panelu lewego: szerokość i wysokość 180px
ok. 1 min
Polecenie z arkusza
wyłącznie dla obrazu z panelu lewego: szerokość i wysokość 180 px
#left img - tylko obraz panelu lewego (R.4.8). nav a { display: block; } - odnośnik zajmuje całą linię, więc drugi staje pod pierwszym, a obszar do kliknięcia jest szerszy niż sam napis.
Kroki 26-27 · po tym etapie masz 31 z 36 kryteriów (pkt)
Krok 26: Plik znajdz.php z nowym paragrafem
Kryteria:
R.2.2 Witrynę internetową zapisano w plikach index.html i znajdz.php oraz zastosowano właściwy standard kodowania polskich znaków na przynajmniej jednej stronie
ok. 2 min
Polecenie z arkusza
Panel prawy dla strony znajdz.php: Obok siebie trzy obrazy z gerberą, goździkiem, różą, tekst alternatywny to nazwa kwiatu. Paragraf o treści: „Podaj miejscowość, w której poszukujesz kwiaciarni:”
Kopia index.html z innym paragrafem w panelu prawym (R.2.2). Paragraf dostaje id="city-label" - za chwilę posłuży jako podpis pola.
Kroki 28-32 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 28: Skrypt na górze pliku i połączenie PDO z bazą kwiaciarnia
Kryteria: ,
R.5.1 Skrypt napisano w języku PHP i umieszczono w pliku znajdz.php oraz zawiera on przynajmniej jedną instrukcję języka zgodną ze składnią
R.5.2 Zastosowano funkcję realizującą połączenie z serwerem bazy danych na localhost, użytkownik root, bez hasła, baza danych kwiaciarnia
ok. 4 min
Polecenie z arkusza
Wymagania dotyczące skryptu: Napisany w języku PHP. Skrypt łączy się z serwerem bazy danych na localhost, użytkownik root bez hasła, baza danych o nazwie kwiaciarnia
Skrypt stoi na samej górze znajdz.php, przed <!DOCTYPE html>: najpierw przygotowuje dane, a HTML tylko je wypisuje (R.5.1).
e() - krótka funkcja z htmlspecialchars, przez którą przejdzie każdy tekst z bazy wypisany na stronie,
new PDO(...) - w pierwszym napisie serwer localhost, baza kwiaciarnia i kodowanie utf8mb4, dalej użytkownik root i puste hasło (R.5.2),
ERRMODE_EXCEPTION - każdy błąd bazy rzuca wyjątek, a FETCH_ASSOC - wiersze wyniku będą tablicami z nazwami kolumn,
try / catch - gdy serwer bazy nie działa, na stronie pojawi się zwykłe zdanie zamiast komunikatu PHP z danymi serwera.
Klucz nie narzuca biblioteki - tabela 3 arkusza jest tylko „wyborem funkcji”. Od tego kroku podgląd to wynik prawdziwego uruchomienia w PHP 8.2.
znajdz.phpPHPzmienione: 17 linii
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}$florists = [];$message = '';try {$pdo = new PDO('mysql:host=localhost;dbname=kwiaciarnia;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);} catch (PDOException $exception) {$message = 'Nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę.';}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Kwiaty</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Moje kwiaty</h1> </header> <main> <sectionid="left"> <h3>Kwiaty dla Ciebie!</h3> <nav> <ahref="https://www.swiatkwiatow.pl/">Rozpoznaj kwiaty</a> <ahref="znajdz.php">Znajdź kwiaciarnię</a> </nav> <imgsrc="gozdzik.jpg"alt="Goździk"> </section> <sectionid="right"> <imgsrc="gerbera.jpg"alt="gerbera"> <imgsrc="gozdzik.jpg"alt="goździk"> <imgsrc="roza.jpg"alt="róża"> <pid="city-label">Podaj miejscowość, w której poszukujesz kwiaciarni:</p> <formmethod="post"action="znajdz.php"> <inputtype="text"name="city"aria-labelledby="city-label"required> <buttontype="submit">SPRAWDŹ</button> </form> </section> </main> <footer> <h3>Stronę opracował: Bartosz Bryniarski</h3> </footer></body></html>
Podgląd strony po tym kroku (znajdz.php)
Krok 29: Miejscowość z formularza
ok. 3 min
Polecenie z arkusza
Skrypt pobiera dane z pola edycyjnego
filter_input(INPUT_POST, 'city') odczytuje pole z wysłanego formularza, a gdy go nie ma - zwraca null, bez ostrzeżenia. (string) zamienia null na pusty napis,
trim() zdejmuje spacje z brzegów: „ Malbork ” to Malbork,
połączenie i zapytanie tylko wtedy, gdy miejscowość nie jest pusta - zwykłe wejście na stronę nie łączy się z bazą.
Pole dostało value="<?= e($city) ?>" - po wysłaniu wpisana miejscowość zostaje w polu. Podgląd: wysłane „Malbork”.
R.5.4 Skrypt wysyła do bazy danych zmodyfikowane zapytanie 1 w ten sposób, że w miejscu miasta jest wpisana wartość z pola edycyjnego
ok. 3 min
Polecenie z arkusza
Wysyła do bazy danych zmodyfikowane zapytanie 1 w ten sposób, że w miejscu miasta jest wpisana wartość z pola edycyjnego
Kwerenda 1, w której miasto zastępuje parametr :city:
$pdo->prepare(...) - baza dostaje samą treść zapytania,
$statement->execute(['city' => $city]) - osobno wartość z formularza,
fetchAll() - od razu wszystkie wiersze wyniku jako tablica.
Wpisana miejscowość nigdy nie staje się częścią kodu SQL: x' OR '1'='1 to po prostu nazwa miasta, którego nie ma, a „Kędzierzyn'Koźle” z apostrofem nie psuje zapytania (R.5.4).
znajdz.phpPHPzmienione: 3 linie
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}$city = trim((string) filter_input(INPUT_POST, 'city'));$florists = [];$message = '';if ($city !== '') {try {$pdo = new PDO('mysql:host=localhost;dbname=kwiaciarnia;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$statement = $pdo->prepare('SELECT nazwa, ulica FROM kwiaciarnie WHERE miasto = :city;');$statement->execute(['city' => $city]);$florists = $statement->fetchAll(); } catch (PDOException $exception) {$message = 'Nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę.'; }}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Kwiaty</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Moje kwiaty</h1> </header> <main> <sectionid="left"> <h3>Kwiaty dla Ciebie!</h3> <nav> <ahref="https://www.swiatkwiatow.pl/">Rozpoznaj kwiaty</a> <ahref="znajdz.php">Znajdź kwiaciarnię</a> </nav> <imgsrc="gozdzik.jpg"alt="Goździk"> </section> <sectionid="right"> <imgsrc="gerbera.jpg"alt="gerbera"> <imgsrc="gozdzik.jpg"alt="goździk"> <imgsrc="roza.jpg"alt="róża"> <pid="city-label">Podaj miejscowość, w której poszukujesz kwiaciarni:</p> <formmethod="post"action="znajdz.php"> <inputtype="text"name="city"aria-labelledby="city-label"requiredvalue="<?= e($city) ?>"> <buttontype="submit">SPRAWDŹ</button> </form> </section> </main> <footer> <h3>Stronę opracował: Bartosz Bryniarski</h3> </footer></body></html>
R.5.5 Skrypt wyświetla pod przyciskiem zwrócone zapytaniem dane: nazwę i ulicę oddzielone przecinkiem
ok. 3 min
Polecenie z arkusza
Pod przyciskiem wyświetla zwrócone zapytaniem dane: nazwę i ulicę oddzielone przecinkiem
Pod formularzem tylko wypisanie: foreach po wierszach, a w każdym <?= e($florist['nazwa']) ?>, <?= e($florist['ulica']) ?> i <br>. Zapis <?= … ?> to skrót od <?php echo … ?>, a składnia foreach (...): / endforeach; czyta się w HTML-u łatwiej niż nawiasy klamrowe. Nazwy kolumn zamiast numerów [0], [1] - kod nie zależy od kolejności pól w SELECT.
Podgląd: Melisa, Konopnickiej pod przyciskiem, jak na obrazie 2 (R.5.5).
znajdz.phpPHPzmienione: 3 linie
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}$city = trim((string) filter_input(INPUT_POST, 'city'));$florists = [];$message = '';if ($city !== '') {try {$pdo = new PDO('mysql:host=localhost;dbname=kwiaciarnia;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$statement = $pdo->prepare('SELECT nazwa, ulica FROM kwiaciarnie WHERE miasto = :city;');$statement->execute(['city' => $city]);$florists = $statement->fetchAll(); } catch (PDOException $exception) {$message = 'Nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę.'; }}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Kwiaty</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Moje kwiaty</h1> </header> <main> <sectionid="left"> <h3>Kwiaty dla Ciebie!</h3> <nav> <ahref="https://www.swiatkwiatow.pl/">Rozpoznaj kwiaty</a> <ahref="znajdz.php">Znajdź kwiaciarnię</a> </nav> <imgsrc="gozdzik.jpg"alt="Goździk"> </section> <sectionid="right"> <imgsrc="gerbera.jpg"alt="gerbera"> <imgsrc="gozdzik.jpg"alt="goździk"> <imgsrc="roza.jpg"alt="róża"> <pid="city-label">Podaj miejscowość, w której poszukujesz kwiaciarni:</p> <formmethod="post"action="znajdz.php"> <inputtype="text"name="city"aria-labelledby="city-label"requiredvalue="<?= e($city) ?>"> <buttontype="submit">SPRAWDŹ</button> </form><?phpforeach ($floristsas$florist): ?><?= e($florist['nazwa']) ?>, <?= e($florist['ulica']) ?><br><?phpendforeach; ?> </section> </main> <footer> <h3>Stronę opracował: Bartosz Bryniarski</h3> </footer></body></html>
Podgląd strony po tym kroku (znajdz.php)
Krok 32: Zamknięcie połączenia i komunikat o braku wyników
Kryteria:
R.5.3 Po wykonaniu wszystkich operacji na bazie zastosowano funkcję zamknięcia połączenia z serwerem bazy danych
ok. 3 min
Polecenie z arkusza
Po wykonaniu operacji na bazie danych skrypt zamyka połączenie z serwerem
PDO nie ma funkcji close - połączenie zamyka się, gdy znika ostatnie odwołanie do obiektu, czyli po $statement = null i $pdo = null. Stoją w bloku finally, który wykona się zawsze po try - po udanym zapytaniu i po wyjątku (R.5.3).
Dodatek spoza klucza: gdy zapytanie nic nie znalazło, pod przyciskiem pojawia się „W tej miejscowości nie ma kwiaciarni w bazie.” - w wersji podstawowej pusty wynik wygląda tak samo jak niewysłany formularz. Podgląd: wyszukanie „Kraków”.
znajdz.phpPHPzmienione: 9 linii
<?phpfunctione(string $text): string{returnhtmlspecialchars($text, ENT_QUOTES, 'UTF-8');}$city = trim((string) filter_input(INPUT_POST, 'city'));$florists = [];$message = '';if ($city !== '') {try {$pdo = new PDO('mysql:host=localhost;dbname=kwiaciarnia;charset=utf8mb4', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]);$statement = $pdo->prepare('SELECT nazwa, ulica FROM kwiaciarnie WHERE miasto = :city;');$statement->execute(['city' => $city]);$florists = $statement->fetchAll(); } catch (PDOException $exception) {$message = 'Nie udało się połączyć z bazą danych, spróbuj ponownie za chwilę.'; } finally {$statement = null;$pdo = null; }if ($message === '' && count($florists) === 0) {$message = 'W tej miejscowości nie ma kwiaciarni w bazie.'; }}?><!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1"> <title>Kwiaty</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h1>Moje kwiaty</h1> </header> <main> <sectionid="left"> <h3>Kwiaty dla Ciebie!</h3> <nav> <ahref="https://www.swiatkwiatow.pl/">Rozpoznaj kwiaty</a> <ahref="znajdz.php">Znajdź kwiaciarnię</a> </nav> <imgsrc="gozdzik.jpg"alt="Goździk"> </section> <sectionid="right"> <imgsrc="gerbera.jpg"alt="gerbera"> <imgsrc="gozdzik.jpg"alt="goździk"> <imgsrc="roza.jpg"alt="róża"> <pid="city-label">Podaj miejscowość, w której poszukujesz kwiaciarni:</p> <formmethod="post"action="znajdz.php"> <inputtype="text"name="city"aria-labelledby="city-label"requiredvalue="<?= e($city) ?>"> <buttontype="submit">SPRAWDŹ</button> </form><?phpforeach ($floristsas$florist): ?><?= e($florist['nazwa']) ?>, <?= e($florist['ulica']) ?><br><?phpendforeach; ?><?phpif ($message !== ''): ?><?= e($message) ?><?phpendif; ?> </section> </main> <footer> <h3>Stronę opracował: Bartosz Bryniarski</h3> </footer></body></html>
Podgląd strony po tym kroku (znajdz.php)
Etap 7: Porównanie z wersją podstawową
Krok 33 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 33: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 3 min
Obie wersje dają komplet 36 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
układ
float: left sekcji, clear stopki
<main> z display: flex
szerokości 20% i 80%
width na panelach
width na panelach (tak ocenia klucz)
kolory
wpisane w każdej regule
zmienne --pink, --dark
odnośniki
<br> między nimi
<nav>, display: block
pole formularza
bez podpisu
paragraf jako podpis (aria-labelledby), required
tabele
pola bez ograniczeń, cena INT
NOT NULL, UNSIGNED, cena DECIMAL(8, 2)
biblioteka
mysqli (tabela 3 arkusza)
PDO z wyjątkami
gdzie jest skrypt
w całości pod formularzem
na górze pliku, pod formularzem tylko pętla
miasto w zapytaniu
wklejone w treść zapytania
parametr :city
wypisywanie
echo wprost z bazy
e() z htmlspecialchars
zamknięcie bazy
mysqli_close na końcu
$pdo = null w finally
po wysłaniu
puste pole, pusty wynik bez słowa
miejscowość w polu, komunikat o braku wyników
Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 3 i łatwiej ją napisać bez dokumentacji. Nowoczesna nie daje się oszukać wpisem x' OR '1'='1, nie wywraca się na apostrofie i mówi użytkownikowi, że nic nie znalazła - a klucz przyjmuje obie.
Krok 34 · po tym etapie masz 36 z 36 kryteriów (pkt)
Krok 34: 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 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 folderze z numerem zdającego: gerbera.jpg, gozdzik.jpg, index.html, kw1.jpg - kw3.jpg, kwerendy.txt, kwiaciarnia.sql, przeglądarka.txt, roza.jpg, styl.css i znajdz.php (arkusz pomija go na liście, a to jedyny plik ze skryptem). 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.