INF.03-04-23.01-SGStyczeń 2023 · 43 kroki · ok. 67 min · 32 kryteria z klucza
Rozwiązanie krok po kroku: Portal biura podróży (Wersja podstawowa)
Portal biura turystycznego to baza biuro (z importu zadanie używa tabel wycieczki i zdjecia), cztery zapytania - warunek na polu logicznym, sortowanie malejąco, złączenie z warunkiem na cenie i ALTER TABLE dodające pole w wybranym miejscu - oraz jedna strona wycieczki.php. Skrypt 1 wypisuje dostępne wycieczki jako listę punktowaną według wzoru z arkusza, a Skrypt 2 buduje galerię dziewięciu zdjęć: nazwa pliku z bazy jest źródłem obrazu, a podpis - tekstem alternatywnym. W stylach jest pseudoelement ::first-letter (powiększona pierwsza litera nagłówków) i :hover na obrazie.
Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypty są najpierw napisane najprościej, funkcjami z tabeli 1 arkusza (mysqli_query, mysqli_fetch_row), a na końcu przerobione na wersję z prawdziwych projektów.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, PDO)” jest drugi sposób rozwiązania tego samego arkusza: wszystkie bloki w siatce CSS z nazwanymi obszarami, kolory w zmiennych CSS, oba zapytania wykonane przez PDO na górze pliku wycieczki.php, a w HTML-u tylko pętle foreach z bezpiecznym wypisywaniem danych - obie wersje są zgodne z kluczem.
Baza i zdjęcia pochodzą z prawdziwego archiwum zad4 (załącznik do arkusza, hasło w treści zadania). Zapytania i zrzuty są policzone na MariaDB 10.4 - tej samej, która jest w XAMPP. Podgląd strony od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.1.2 - zachowanie tych funkcji jest w obu wersjach takie samo); najechanie kursorem na zdjęcie w galerii podświetla jego tło, jak na obrazie 2.
Jak liczą się punkty. Klucz ma 32 kryteria (R.1.1 - R.5.5), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 24 punkty - można stracić 8 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 32 kryteriów (pkt)
Krok 1: Baza danych biuro
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie biuro
Najpierw archiwum zad4.zip z pulpitu (hasło &poDrozE$ - z ampersandem na początku i dolarem na końcu) i folder z numerem zdającego, do którego trafiają egzamin3.sql i zdjęcia 1.jpg - 9.jpg. W phpMyAdmin: Nowa, nazwa biuro - plik SQL nazywa się inaczej niż baza.
Typowe błędy
Nazwa bazy musi brzmieć dokładnie biuro (nie egzamin3) - skrypty łączą się z bazą po nazwie (R.5.1).
Krok 2: Import tabel z pliku egzamin3.sql
ok. 2 min
Polecenie z arkusza
Do bazy biuro zaimportuj tabele z pliku egzamin3.sql z rozpakowanego archiwum
Przy zaznaczonej bazie biuro: Import → egzamin3.sql → Wykonaj. Plik zawiera osiem tabel z różnych zadań; tu potrzebne są dwie z obrazu 1: wycieczki (9 wycieczek: data, cel, cena, pole dostepna z wartością 1 albo 0 i zdjecia_id) i zdjecia (9 plików z podpisami). Wycieczka jest dostępna, gdy dostepna ma wartość TRUE, czyli 1.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych biuro czynność udokumentowano plikiem o nazwie import w formacie PNG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG pod nazwą import. Nie kadruj zrzutu. Zrzut powinien obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel
Print Screen, wklejenie do edytora grafiki i zapis jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: dostępne wycieczki
Kryteria: ,
R.1.2 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Utworzono zapytanie 1 wybierające jedynie pola id, dataWyjazdu, cel i cena z tabeli wycieczki dla dostępnych wycieczek. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE; (lub =1) oraz wynik działania udokumentowano zrzutem, na którym widocznych jest dokładnie 6 rekordów o id = 1, 2, 3, 4, 6, 9, jedynie pola id, dataWyjazdu, cel i cena
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie pola id, dataWyjazdu, cel i cena z tabeli wycieczki dla dostępnych wycieczek
SELECT id, dataWyjazdu, cel, cena - cztery pola; nazwa dataWyjazdu ma wielką literę w środku i tak trzeba ją pisać,
FROM wycieczki,
WHERE dostepna = TRUE - w MariaDB TRUE to po prostu 1, więc dostepna = 1 daje to samo (sprawdzone, klucz uznaje oba).
Wynik: 6 wycieczek o id 1, 2, 3, 4, 6 i 9 - jak w kluczu. Z tego zapytania powstanie Skrypt 1. Zapytania trafiają do kwerendy.txt, zrzut wyniku do kw1.jpg.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: zdjęcia malejąco po podpisie
Kryteria:
R.1.4 Utworzono zapytanie 2 wybierające jedynie pola nazwaPliku i podpis z tabeli zdjecia , sortując je malejąco według kolumny podpis. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC; oraz wynik działania udokumentowano zrzutem, na którym widocznych jest dokładnie 9 rekordów dla kolejnych nazw plików 2, 4, 6, 7, 9, 1, 5, 3, 8, jedynie pola nazwaPliku i podpis
ok. 1 min
Polecenie z arkusza
Zapytanie 2: wybierające jedynie pola nazwaPliku i podpis z tabeli zdjecia, sortując je malejąco według kolumny podpis
SELECT nazwaPliku, podpis,
FROM zdjecia,
ORDER BY podpis DESC - DESC to kierunek malejący (od Z do A); bez niego sortowanie byłoby rosnące.
Wynik: 9 zdjęć od Wenecji do Barcelony, pliki w kolejności 2, 4, 6, 7, 9, 1, 5, 3, 8 - jak w kluczu i jak w galerii na obrazie 2. Z tego zapytania powstanie Skrypt 2. Zrzut: kw2.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;-- Zapytanie 2SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: wycieczki droższe niż 1200 zł z podpisem zdjęcia
Kryteria:
R.1.5 Utworzono zapytanie 3 wybierające jedynie cel i cenę wycieczki z tabeli wycieczki oraz odpowiadający im podpis z tabeli zdjecia dla wycieczek, których cena jest wyższa niż 1200 zł. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT cel, cena, podpis FROM zdjecia JOIN wycieczki ON zdjecia.id = wycieczki.zdjecia_id WHERE cena > 1200; (możliwe też INNER JOIN lub porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym widocznych jest dokładnie 5 rekordów: Francja, Paryz 1300 Paryz; Francja, Paryz 1350 Paryz; Hiszpania, Barcelona 1500 Barcelona; Hiszpania, Barcelona 1500 Barcelona; Hiszpania, Barcelona 1400 Barcelona
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie cel i cenę wycieczki z tabeli wycieczki oraz odpowiadający im podpis z tabeli zdjecia dla wycieczek, których cena jest wyższa niż 1200 zł. Zapytanie wykorzystuje relację
SELECT cel, cena, podpis - dwa pola z wycieczek i jedno ze zdjęć,
FROM wycieczki JOIN zdjecia - złączenie tabel,
ON wycieczki.zdjecia_id = zdjecia.id - relacja z obrazu 1,
WHERE cena > 1200 - „wyższa niż”, więc wycieczki za dokładnie 1200 zł odpadają.
Wynik: 5 wierszy - dwa razy Paryż (1300 i 1350) i trzy razy Barcelona (1500, 1500, 1400) - jak w kluczu. Zapytanie nie sprawdza dostępności, więc są tu też wycieczki bez wolnych miejsc. Zrzut: kw3.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;-- Zapytanie 2SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;-- Zapytanie 3SELECT cel, cena, podpis FROM wycieczki JOIN zdjecia ON wycieczki.zdjecia_id = zdjecia.id WHERE cena > 1200;
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: pole liczbaDni po dataWyjazdu
Kryteria:
R.1.6 Utworzono zapytanie 4 dodające do tabeli wycieczki pole liczbaDni przyjmujące tylko liczby naturalne, pole powinno być wstawione po polu dataWyjazdu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE wycieczki ADD liczbaDni int UNSIGNED AFTER dataWyjazdu; (lub ADD COLUMN, dowolny typ liczbowy całkowity, UNSIGNED obowiązkowe) oraz wynik działania udokumentowano zrzutem, na którym widnieje komunikat o poprawnym dodaniu lub struktura tabeli z dodaną kolumną
ok. 2 min
Polecenie z arkusza
Zapytanie 4: dodające do tabeli wycieczki pole liczbaDni przyjmujące tylko liczby naturalne, pole powinno być wstawione po polu dataWyjazdu
ALTER TABLE wycieczki - zmiana struktury istniejącej tabeli,
ADD liczbaDni INT UNSIGNED - nowe pole całkowite; UNSIGNED (bez znaku) wyklucza liczby ujemne, klucz wymaga go wprost,
AFTER dataWyjazdu - miejsce nowego pola; bez tego trafiłoby na koniec tabeli.
Struktura po wykonaniu (DESCRIBE wycieczki) ma liczbaDni między dataWyjazdu a cel; istniejące wycieczki mają w nim NULL. Zapytanie 1 po tej zmianie daje ten sam wynik, bo wybiera pola z nazwy (sprawdzone). Zrzut kw4.jpg pokazuje komunikat i strukturę tabeli.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;-- Zapytanie 2SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;-- Zapytanie 3SELECT cel, cena, podpis FROM wycieczki JOIN zdjecia ON wycieczki.zdjecia_id = zdjecia.id WHERE cena > 1200;-- Zapytanie 4ALTER TABLE wycieczki ADD liczbaDni INT UNSIGNED AFTER dataWyjazdu;
Podgląd strony po tym kroku
Etap 2: Strona HTML
Kroki 8-24 · po tym etapie masz 14 z 32 kryteriów (pkt)
Krok 8: Plik wycieczki.php w HTML5
Kryteria:
R.2.1 Witrynę internetową zapisano w pliku PHP o nazwie wycieczki
ok. 2 min
Polecenie z arkusza
Składa się ze strony o nazwie wycieczki.php
Deklaracja <!DOCTYPE html> i szkielet strony. Rozszerzenie .php, bo strona będzie miała skrypty; na egzaminie folder z numerem zdającego leży w htdocs XAMPP-a i strona otwiera się przez http://localhost/..., inaczej PHP się nie wykona. W tym samym folderze leżą zdjęcia 1.jpg - 9.jpg z archiwum - baza podaje samą nazwę pliku.
R.2.3 Nadano tytuł stronie: "Wycieczki po Europie"
ok. 1 min
Polecenie z arkusza
Tytuł strony widoczny na karcie przeglądarki: „Wycieczki po Europie”
<title> w <head>.
wycieczki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title></head><body></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 12: Podpięcie arkusza stylów
Kryteria:
R.3.3 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl4.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 styl4.css prawidłowo połączony z kodem strony
Nazwa pliku: styl4.css - z cyfrą 4. Całe formatowanie ma pochodzić z tego pliku.
Typowe błędy
Klucz odbiera R.3.3 także wtedy, gdy choć jeden selektor nie trafia w blok (np. kropka zamiast #).
wycieczki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 13: Bloki: baner, blok z danymi, trzy bloki i stopka
Kryteria:
R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: baner, dane, lewy, środkowy, prawy i stopka. Zastosowano znaczniki sekcji
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: na górze baner, poniżej blok z danymi, poniżej obok siebie trzy bloki: lewy, środkowy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z Obrazem 2
Baner to <header>, stopka <footer>, a cztery bloki - <section> z identyfikatorami: trips (blok z danymi - lista wycieczek), left, middle i right. Blok z danymi zajmuje całą szerokość, trzy pozostałe staną obok siebie dzięki CSS.
Odnośnik do adresu e-mail [email protected] o treści: „napisz do nas”
Odnośnik do adresu e-mail to <a> z adresem zaczynającym się od mailto: - kliknięcie otwiera program pocztowy z wpisanym odbiorcą.
wycieczki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> </section> <footer> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 23: Blok prawy: akapit z telefonem
Kryteria:
R.2.5 W banerze zapisano nagłówek h1: "BIURO TURYSTYCZNE", w bloku dane h3: "Wycieczki, na które są wolne miejsca", w blokach lewym, środkowym i prawym przynajmniej jeden h2 z: "Bestselery", "Nasze zdjęcia", "Skontaktuj się" oraz przynajmniej jeden paragraf
ok. 1 min
Polecenie z arkusza
Paragraf (akapit) o treści: „telefon: 111222333”
<p> pod odnośnikiem. Strona ma już <h1>, <h3>, <h2> i akapit - komplet do R.2.5.
wycieczki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 24: Stopka
ok. 1 min
Polecenie z arkusza
Zawartość stopki: akapit (paragraf) o treści: „Stronę wykonał: ”, dalej wstawiony numer zdającego
Akapit <p> w <footer>. Na egzaminie w miejscu imienia i nazwiska wpisuje się numer zdającego, czyli PESEL; w tym rozwiązaniu stoi tam „Bartosz Bryniarski”.
wycieczki.phpPHPzmienione: 1 linia
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Etap 3: Styl CSS
Kroki 25-35 · po tym etapie masz 25 z 32 kryteriów (pkt)
Krok 25: Krój czcionki dla wszystkich elementów
Kryteria:
R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (*): krój czcionki Helvetica
ok. 1 min
Polecenie z arkusza
Ustawione domyślne wartości dla wszystkich selektorów stylu CSS: krój czcionki Helvetica
Selektor uniwersalny *. Helvetica jest typowa dla komputerów Apple; w Windows przeglądarka zwykle podstawi Arial.
styl4.cssCSSnowy plik
* {font-family: Helvetica;}
Podgląd strony po tym kroku (wycieczki.php)
Krok 26: Baner i stopka
ok. 1 min
Polecenie z arkusza
Wspólne dla banera i stopki: kolor tła #B3BC6D, biały kolor czcionki, wyrównanie tekstu do środka, marginesy wewnętrzne 5 px
Jedna reguła dla dwóch selektorów; marginesy wewnętrzne to padding.
R.4.3 Ustawiono biały kolor czcionki dla banera i stopki oraz Olive dla bloku z danymi
ok. 1 min
Polecenie z arkusza
Dla bloku z danymi: kolor tła #FFFFCE, kolor czcionki Olive, marginesy wewnętrzne: górny i dolny 10 px, prawy i lewy 150 px
padding: 10px 150px - pierwsza wartość to górny i dolny margines wewnętrzny, druga lewy i prawy. Stąd wcięcie nagłówka i listy na obrazie 2. Kolory czcionek z arkusza są ustawione (R.4.3).
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 flex albo grid)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: na górze baner, poniżej blok z danymi, poniżej obok siebie trzy bloki: lewy, środkowy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z Obrazem 2
float: left dostają tylko trzy dolne bloki - blok z danymi ma zostać na całą szerokość, więc nie może pływać (dlatego selektor wymienia identyfikatory, a nie wszystkie section). Stopka z clear: both zaczyna się pod pływającymi blokami.
R.4.4 Ustawiono szerokość 25% dla bloków lewego i prawego, 50% dla środkowego (width lub grid-template-columns lub flex), 70% dla selektora table
R.4.8 Ustawiono obramowanie dla tabeli: 1px solid Olive
ok. 1 min
Polecenie z arkusza
Dla selektora tabeli: obramowanie linią ciągłą o szerokości 1 px i kolorze Olive, marginesy zewnętrzne automatycznie wyliczane przez przeglądarkę, szerokość 70%
Selektor znacznika table. margin: auto rozdziela wolne miejsce po równo z obu stron - tabela staje na środku bloku. Obramowanie ma tylko tabela, komórki nie - jak na obrazie 2. Wszystkie szerokości z arkusza są ustawione (R.4.4).
R.4.5 Ustawiono wysokość 450px dla bloków lewego, środkowego i prawego i 100px dla selektora img
R.4.6 Ustawiono marginesy wewnętrzne (padding) 5px dla banera i stopki, 7px dla obrazu, 10px górny i dolny i 150px prawy i lewy dla bloku z danymi oraz marginesy zewnętrzne (margin) auto dla tabeli
ok. 1 min
Polecenie z arkusza
Dla selektora obrazu: wysokość 100 px, marginesy wewnętrzne 7 px
Selektor znacznika img. padding to odstęp wokół zdjęcia wewnątrz elementu - na razie niewidoczny, ale pod kursorem zabarwi się kolorem tła. Wszystkie wysokości i marginesy z arkusza są ustawione (R.4.5, R.4.6).
Kroki 36-40 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 36: Połączenie z bazą w Skrypcie 1, zamknięcie w Skrypcie 2
Kryteria:
R.5.1 Skrypt zawiera działające połączenie z serwerem bazy danych i wybór bazy biuro
ok. 2 min
Polecenie z arkusza
Łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie biuro
Na stronie są dwa bloki PHP: Skrypt 1 wewnątrz listy <ul> w bloku z danymi i Skrypt 2 w bloku środkowym pod nagłówkiem. mysqli_connect z czterema argumentami łączy się z serwerem i od razu wybiera bazę; uchwyt trafia do zmiennej $connection. Skrypt 1 jest w kodzie wcześniej, więc to on otwiera połączenie, a Skrypt 2 je zamyka. Od tego kroku podgląd to wynik prawdziwego uruchomienia strony.
Krok 38: Skrypt 1: wycieczka w elemencie listy według wzoru
Kryteria: ,
R.5.4 Skrypt 1 wyświetla każdy zwrócony zapytaniem wiersz w formacie: „<id>. dnia <dataWyjazdu> jedziemy do <cel>, cena: <cena>”, gdzie < > oznacza pole zwrócone zapytaniem
R.2.6 W bloku z danymi umieszczono listę punktowaną, zastosowano znaczniki <ul>, <li> (w skrypcie lub HTML)
ok. 3 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz jest wyświetlany w elemencie listy, według wzoru: „<id>. dnia <dataWyjazdu> jedziemy do <cel>, cena: <cena>”, gdzie w znakach < > zapisano pola zwrócone zapytaniem
mysqli_fetch_row oddaje wiersz jako tablicę w kolejności pól zapytania: $row[0] - id, $row[1] - data, $row[2] - cel, $row[3] - cena. W napisie w cudzysłowach PHP podstawia wartości; kropka po $row[0] i przecinek po $row[2] są zwykłymi znakami wzoru. Podgląd: sześć wycieczek, od 1. dnia 2019-09-08 jedziemy do Wlochy, Wenecja, cena: 1200 - jak na obrazie 2. Lista ma <li> z pętli i <ul> z HTML-a (R.2.6).
wycieczki.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul><?php$connection = mysqli_connect("localhost", "root", "", "biuro");$query = "SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]. dnia $row[1] jedziemy do $row[2], cena: $row[3]</li>"; }?> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2><?php mysqli_close($connection);?> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 39: Skrypt 2: zapytanie 2
ok. 1 min
Polecenie z arkusza
Wysyła do bazy danych zapytanie 2
Zapytanie 2 bez zmian. Zmienne $query i $result mają te same nazwy co w Skrypcie 1 - tamten wynik został już wypisany, więc można je użyć ponownie. mysqli_close zostaje ostatnią instrukcją.
wycieczki.phpPHPzmienione: 2 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul><?php$connection = mysqli_connect("localhost", "root", "", "biuro");$query = "SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]. dnia $row[1] jedziemy do $row[2], cena: $row[3]</li>"; }?> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2><?php$query = "SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;";$result = mysqli_query($connection, $query); mysqli_close($connection);?> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
R.5.5 Skrypt 2 wyświetla obrazy na podstawie danych zwróconych zapytaniem, w ten sposób, że pole nazwaPliku jest źródłem obrazu, a pole podpis jest tekstem alternatywnym obrazu
R.2.8 W bloku środkowym umieszczono przynajmniej jeden obraz (w HTML lub skrypcie)
R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)
ok. 3 min
Polecenie z arkusza
Dane z każdego zwróconego zapytaniem wiersza są wykorzystane do wyświetlenia kolejnych obrazów, w ten sposób, że pole nazwaPliku jest źródłem obrazu, a pole podpis jest tekstem alternatywnym obrazu
Dla każdego wiersza jeden <img>: $row[0] (nazwa pliku) w atrybucie src, $row[1] (podpis) w alt. Cudzysłowy atrybutów wewnątrz napisu PHP poprzedza ukośnik \". Obrazy są elementami w linii, więc przy wysokości 100 px układają się po trzy w rzędzie. Podgląd: galeria z obrazu 2, od Wenecji do Barcelony. Zamknięcie połączenia jest ostatnią operacją na bazie (R.5.2).
wycieczki.phpPHPzmienione: 3 linie
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul><?php$connection = mysqli_connect("localhost", "root", "", "biuro");$query = "SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<li>$row[0]. dnia $row[1] jedziemy do $row[2], cena: $row[3]</li>"; }?> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2><?php$query = "SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<img src=\"$row[0]\" alt=\"$row[1]\">"; } mysqli_close($connection);?> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Etap 5: Dobre praktyki (poza kluczem)
Kroki 41-42 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 41: Skrypt 1: pola po nazwach i komunikat bez wolnych miejsc
ok. 3 min
Polecenie z arkusza
Każdy zwrócony zapytaniem wiersz jest wyświetlany w elemencie listy, według wzoru: „<id>. dnia <dataWyjazdu> jedziemy do <cel>, cena: <cena>”, gdzie w znakach < > zapisano pola zwrócone zapytaniem
Wersja egzaminacyjna sprawdzona na bazie, w której żadna wycieczka nie ma wolnych miejsc (UPDATE wycieczki SET dostepna = 0): pod nagłówkiem „Wycieczki, na które są wolne miejsca” zostaje pusta lista i nie wiadomo, czy coś się zepsuło. mysqli_num_rows (funkcja z tabeli 1 arkusza) zwraca liczbę wierszy - przy zerze skrypt wypisuje „Brak wolnych miejsc na wycieczki”. Przy okazji mysqli_fetch_assoc zamiast numerów kolumn: $trip["dataWyjazdu"] czyta się łatwiej niż $row[1] i nie zależy od kolejności pól w zapytaniu, a tekst celu podróży przechodzi przez htmlspecialchars. Podgląd: lista dla bazy bez wolnych miejsc. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
wycieczki.phpPHPzmienione: 7 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul><?php$connection = mysqli_connect("localhost", "root", "", "biuro");$query = "SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;";$result = mysqli_query($connection, $query);if (mysqli_num_rows($result) == 0) {echo"<li>Brak wolnych miejsc na wycieczki</li>"; }while ($trip = mysqli_fetch_assoc($result)) {$target = htmlspecialchars($trip["cel"]);echo"<li>" . $trip["id"] . ". dnia " . $trip["dataWyjazdu"] . " jedziemy do $target, cena: " . $trip["cena"] . "</li>"; }// while ($row = mysqli_fetch_row($result)) { ... "$row[0]. dnia $row[1] ..." ... }?> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2><?php$query = "SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;";$result = mysqli_query($connection, $query);while ($row = mysqli_fetch_row($result)) {echo"<img src=\"$row[0]\" alt=\"$row[1]\">"; } mysqli_close($connection);?> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Krok 42: Skrypt 2: podpis bezpieczny w atrybucie i dymek z nazwą miasta
ok. 3 min
Polecenie z arkusza
Dane z każdego zwróconego zapytaniem wiersza są wykorzystane do wyświetlenia kolejnych obrazów, w ten sposób, że pole nazwaPliku jest źródłem obrazu, a pole podpis jest tekstem alternatywnym obrazu
Podpis z bazy trafia do atrybutu w cudzysłowach. Test na wersji egzaminacyjnej z podpisem Rzym "Wieczne Miasto" dał znacznik alt="Rzym "Wieczne Miasto"" - cudzysłów z bazy zamyka atrybut w połowie i reszta tekstu wypada z niego. htmlspecialchars zamienia cudzysłów na encję ", więc atrybut zostaje cały (sprawdzone). Dodatkowo atrybut title z tym samym podpisem: najechanie kursorem na zdjęcie pokazuje dymek z nazwą miasta, czego sam alt nie robi. Podgląd: galeria na bazie z arkusza. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
wycieczki.phpPHPzmienione: 5 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Wycieczki po Europie</title> <linkrel="stylesheet"href="styl4.css"></head><body> <header> <h1>BIURO TURYSTYCZNE</h1> </header> <sectionid="trips"> <h3>Wycieczki, na które są wolne miejsca</h3> <ul><?php$connection = mysqli_connect("localhost", "root", "", "biuro");$query = "SELECT id, dataWyjazdu, cel, cena FROM wycieczki WHERE dostepna = TRUE;";$result = mysqli_query($connection, $query);if (mysqli_num_rows($result) == 0) {echo"<li>Brak wolnych miejsc na wycieczki</li>"; }while ($trip = mysqli_fetch_assoc($result)) {$target = htmlspecialchars($trip["cel"]);echo"<li>" . $trip["id"] . ". dnia " . $trip["dataWyjazdu"] . " jedziemy do $target, cena: " . $trip["cena"] . "</li>"; }// while ($row = mysqli_fetch_row($result)) { ... "$row[0]. dnia $row[1] ..." ... }?> </ul> </section> <sectionid="left"> <h2>Bestselery</h2> <table> <tr><td>Wenecja</td><td>kwiecień</td></tr> <tr><td>Londyn</td><td>lipiec</td></tr> <tr><td>Rzym</td><td>wrzesień</td></tr> </table> </section> <sectionid="middle"> <h2>Nasze zdjęcia</h2><?php$query = "SELECT nazwaPliku, podpis FROM zdjecia ORDER BY podpis DESC;";$result = mysqli_query($connection, $query);while ($photo = mysqli_fetch_assoc($result)) {$file = htmlspecialchars($photo["nazwaPliku"]);$caption = htmlspecialchars($photo["podpis"]);echo"<img src=\"$file\" alt=\"$caption\" title=\"$caption\">"; }// while ($row = mysqli_fetch_row($result)) { echo "<img src=\"$row[0]\" alt=\"$row[1]\">"; } mysqli_close($connection);?> </section> <sectionid="right"> <h2>Skontaktuj się</h2> <ahref="mailto:[email protected]">napisz do nas</a> <p>telefon: 111222333</p> </section> <footer> <p>Stronę wykonał: Bartosz Bryniarski</p> </footer></body></html>
Podgląd strony po tym kroku (wycieczki.php)
Etap 6: Oddanie pracy
Krok 43 · po tym etapie masz 32 z 32 kryteriów (pkt)
Krok 43: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Nazwij plik przeglądarka.txt i zapisz go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wystarczy nazwa przeglądarki, w której była sprawdzana strona.
W folderze z numerem zdającego: 1.jpg - 9.jpg, import.png, kw1.jpg - kw4.jpg, kwerendy.txt, przeglądarka.txt, styl4.css i wycieczki.php. Po nagraniu płyty trzeba sprawdzić jej odczyt i opisać 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.