Przejdź do głównej treści
EE.09-02-22.01-SGStyczeń 2022 · 33 kroki · ok. 64 min · 33 kryteria z klucza

Rozwiązanie krok po kroku: Prognoza pogody dla Wrocławia (Nowoczesny kod (flex, PDO))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza prognoza z czterema zapytaniami, logo i mapa przeskalowane według arkusza, strona pogoda.php z tabelą prognoz dla Wrocławia i style w styl2.css - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • semantyczne znaczniki: trzy bloki banera w <header>, tabela w <main>, stopka w <footer>,
  • flexbox zamiast float i clear: baner i dolny rząd to kontenery display: flex, a szerokości 25%, 50% i 50% zostają na blokach - tak, jak ocenia je klucz,
  • zmienne CSS dla kolorów z arkusza, tabela z sekcjami <thead> i <tbody>,
  • PHP na PDO na górze pliku: najpierw dane, potem HTML, który je tylko wypisuje pętlą foreach - bez echo ze znacznikami w cudzysłowach,
  • obsługa błędów: gdy baza nie działa, tabela pokazuje zdanie dla użytkownika, a reszta strony wyświetla się normalnie.

To arkusz EE.09 ze stycznia 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i grafiki pochodzą z oryginalnego archiwum CKE pliki2.zip (załącznik na stronie arkusza), zapytania i zrzuty są policzone na MariaDB 10.4, a podgląd od kroków z PHP to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.0.7 - użyte konstrukcje działają w obu wersjach).

Jak liczą się punkty. Klucz ma 33 kryteria (R.1.1 - R.5.4), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 25 punktów. Przy każdym kroku jest napisane, które kryteria spełnia; klucz przyjmuje zarówno mysqli, jak i PDO.

  1. Etap 1: Baza danych

    Kroki 1-7 · po tym etapie masz 6 z 33 kryteriów (pkt)

    Krok 1: Folder zdającego i archiwum pliki2.zip

    ok. 2 min
    Polecenie z arkusza

    Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu.

    Folder na pulpicie nazwany numerem PESEL (w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski), do niego archiwum pliki2.zip rozpakowane z hasłem 3MeTeo#. W środku: baza2.sql, logo.png i obraz.jpg.

  2. Krok 2: XAMPP i baza prognoza

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie prognoza

    Start przy Apache i MySQL, potem http://localhost/phpmyadmin, Nowa, nazwa prognoza, porównywanie np. utf8mb4_polish_ci.

  3. Krok 3: Import pliku baza2.sql i zrzut import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych prognoza , czynność udokumentowano plikiem o nazwie import w formacie PNG. Zrzut zawiera cały obszar ekranu z widocznym paskiem zadań

    ok. 3 min
    Polecenie z arkusza

    Do bazy prognoza zaimportuj tabele z pliku baza2.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie PNG i nazwij import. 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

    Baza prognoza, karta Import, plik baza2.sql, Wykonaj. Zadanie używa tabel miasta (15 miast) i pogoda (17 prognoz). Zrzut całego ekranu z komunikatem i listą tabel: import.png.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: prognozy dla miasta o id 1 według daty

    Kryteria: ,

    R.1.2 Zapisano plik tekstowy o nazwie kwerendy zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Utworzono zapytanie 1 wybierające wszystkie pola z tabeli pogoda dla miast o id równym 1, posortowane rosnąco według daty prognozy. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT * FROM pogoda WHERE miasta_id=1 ORDER BY data_prognozy; (lub po SELECT wymienione wszystkie pola) oraz wynik działania zapytania udokumentowano zrzutem, na którym widocznych jest dokładnie 9 rekordów, kolejno z id 2, 3, 4, 5, 6, 7, 8, 9, 1; wyświetlone wszystkie kolumny

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające wszystkie pola z tabeli pogoda dla miast o id równym 1, posortowane rosnąco według daty prognozy

    Każda klauzula w osobnej linii - tak łatwiej czytać i poprawiać zapytanie. „Miasta o id 1” to w tabeli pogoda kolumna miasta_id, sortowanie ORDER BY data_prognozy jest domyślnie rosnące. Wynik: 9 rekordów z id 2-9 i na końcu 1 (31 maja). Zapytanie do kwerendy.txt (R.1.2), zrzut do kw1.jpg. To samo zapytanie wykona skrypt strony.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT *
    FROM pogoda
    WHERE miasta_id = 1
    ORDER BY data_prognozy;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: opady powyżej 30 mm/h

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające jedynie pola id oraz data_prognozy z tabeli pogoda dla tych rekordów, dla których opady przekraczają 30 mm/h. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT id, data_prognozy FROM pogoda WHERE opady > 30; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 3 rekordy o id 1, 7, 8; jedynie pola id, data_prognozy

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola id oraz data_prognozy z tabeli pogoda dla tych rekordów, dla których opady przekraczają 30 mm/h

    Dwie kolumny i warunek opady > 30 - ostro większe, więc trzy prognozy z dokładnie 30 mm/h odpadają. Wynik: id 1, 7, 8. Zrzut: kw2.jpg.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT *
    FROM pogoda
    WHERE miasta_id = 1
    ORDER BY data_prognozy;
    
    -- Zapytanie 2
    SELECT id, data_prognozy
    FROM pogoda
    WHERE opady > 30;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: zimne noce z nazwą miasta

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające jedynie pola data_prognozy, temperatura_noc z tabeli pogoda oraz nazwa z tabeli miasta dla temperatur nocnych poniżej 6 stopni. Zapytanie wykorzystuje relację. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT data_prognozy, temperatura_noc, nazwa FROM pogoda JOIN miasta ON miasta.id = pogoda.miasta_id WHERE temperatura_noc < 6; możliwe też INNER JOIN lub SELECT data_prognozy, temperatura_noc, nazwa FROM pogoda, miasta WHERE miasta.id = pogoda.miasta_id AND temperatura_noc < 6; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są dokładnie 3 rekordy z danymi: 2019-05-14 5 Wrocław; 2019-05-12 5 Poznań; 2019-05-13 5 Poznań

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pola data_prognozy, temperatura_noc z tabeli pogoda oraz nazwa z tabeli miasta dla temperatur nocnych poniżej 6 stopni. Zapytanie wykorzystuje relację

    JOIN miasta ON miasta.id = pogoda.miasta_id łączy prognozę z jej miastem, WHERE temperatura_noc < 6 zostawia zimne noce. Wynik: 3 rekordy z 5 stopniami - jeden we Wrocławiu, dwa w Poznaniu. Zrzut: kw3.jpg.

    ⚠️ Rozbieżność arkusz-klucz: klucz pisze „Wrocław” i „Poznań”, a w baza2.sql te dwa miasta są zapisane bez polskich liter (Wroclaw, Poznan). Zrzut pokazuje zawartość bazy - zestaw rekordów jest zgodny z kluczem.

    kwerendy.txt Tekst zmienione: 6 linii
    -- Zapytanie 1
    SELECT *
    FROM pogoda
    WHERE miasta_id = 1
    ORDER BY data_prognozy;
    
    -- Zapytanie 2
    SELECT id, data_prognozy
    FROM pogoda
    WHERE opady > 30;
    
    -- Zapytanie 3
    SELECT data_prognozy, temperatura_noc, nazwa
    FROM pogoda
    JOIN miasta ON miasta.id = pogoda.miasta_id
    WHERE temperatura_noc < 6;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: kolumna wojewodztwo

    Kryteria:

    R.1.6 Utworzono zapytanie 4 dodające do tabeli miasta kolumnę wojewodztwo typu tekstowego. W pliku z kwerendami lub na zrzucie istnieje zapis np.: ALTER TABLE miasta ADD COLUMN wojewodztwo text; możliwe inne dowolne typy napisowe oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie lub tabela z dodaną kolumną

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: dodające do tabeli miasta kolumnę wojewodztwo dowolnego typu tekstowego

    ALTER TABLE miasta ADD COLUMN wojewodztwo VARCHAR(50) - nazwa województwa jest krótka, więc wystarczy napis do 50 znaków; VARCHAR z limitem zdradza, czego kolumna się spodziewa. Klucz przyjmuje dowolny typ napisowy (np. TEXT). Zrzut kw4.jpg: komunikat po zapytaniu i struktura tabeli z nową kolumną (SHOW COLUMNS FROM miasta; dopisane pod spodem tylko na zrzucie).

    kwerendy.txt Tekst zmienione: 4 linie
    -- Zapytanie 1
    SELECT *
    FROM pogoda
    WHERE miasta_id = 1
    ORDER BY data_prognozy;
    
    -- Zapytanie 2
    SELECT id, data_prognozy
    FROM pogoda
    WHERE opady > 30;
    
    -- Zapytanie 3
    SELECT data_prognozy, temperatura_noc, nazwa
    FROM pogoda
    JOIN miasta ON miasta.id = pogoda.miasta_id
    WHERE temperatura_noc < 6;
    
    -- Zapytanie 4
    ALTER TABLE miasta
    ADD COLUMN wojewodztwo VARCHAR(50);
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-19 · po tym etapie masz 17 z 33 kryteriów (pkt)

    Krok 8: Logo: 80 px z przezroczystością

    Kryteria: ,

    R.2.1 Plik logo.png przeskalowano z zachowaniem proporcji tak, że jego wysokość wynosi dokładnie 80 px, odpowiadająca temu szerokość wynosi 84 px ±5 px

    R.2.3 Plik logo.png ma przezroczyste tło

    ok. 2 min
    Polecenie z arkusza

    Plik logo.png, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 80 px; plik ma zachować przezroczystość

    GIMP, Obraz → Skaluj obraz, łańcuch zamknięty, wysokość 80 px - szerokość 84 px. Nadpisz logo.png - plik zostaje PNG z kanałem alfa, więc tło zostaje przezroczyste.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Mapa: 200 × 200 px

    Kryteria:

    R.2.2 Plik obraz.jpg przeskalowano z zachowaniem proporcji tak, że jego wysokość wynosi dokładnie 200 px, odpowiadająca temu szerokość wynosi 200 px ±5 px

    ok. 1 min
    Polecenie z arkusza

    Plik obraz.jpg, wypakowany z archiwum, należy przeskalować z zachowaniem proporcji tak, aby jego wysokość wynosiła dokładnie 200 px

    Kwadrat 358 × 358 px po skalowaniu do wysokości 200 px ma też 200 px szerokości.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Plik pogoda.php i kodowanie polskich znaków

    Kryteria:

    R.2.4 Witrynę internetową zapisano w pliku o nazwie pogoda.php oraz zastosowano właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Składa się ze strony o nazwie pogoda.php. Zastosowany właściwy standard kodowania polskich znaków

    Szkielet HTML5 od razu w pliku pogoda.php - skrypt stanie na jego górze. <meta charset="UTF-8"> i zapis pliku w UTF-8 (R.2.4), <meta name="viewport"> dla telefonów.

    pogoda.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  11. Krok 11: Tytuł strony i arkusz stylów

    Kryteria: ,

    R.2.5 Nadano tytuł strony: "Prognoza pogody Wrocław”

    R.3.3 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl2.css , formatowanie pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy źle przypisano co najmniej jeden selektor do bloku (np. kropka zamiast #)

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Prognoza pogody Wrocław”. Arkusz stylów w pliku o nazwie styl2.css prawidłowo połączony z kodem strony

    <title> (R.2.5) i <link rel="stylesheet" href="styl2.css"> (R.3.3) - dwie linie w <head>, każda odpowiada jednemu zdaniu arkusza.

    pogoda.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  12. Krok 12: Bloki: header z trzema sekcjami, main, dwie sekcje i footer

    Kryteria:

    R.2.6 Wygląd strony zdefiniowano dzieląc ją na bloki: trzy bloki banera (lewy, środkowy i prawy), blok główny, bloki lewy i prawy, blok stopki. Zastosowano znaczniki sekcji

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze trzy bloki banera: lewy, środkowy, prawy, poniżej blok główny, poniżej dwa bloki: lewy i prawy, na dole blok stopki. 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

    Struktura mówi, czym jest każdy blok:

    • <header> - baner strony, w nim trzy <section>: lewa (logo), środkowa (nagłówek) i prawa (data),
    • <main> - główna treść, czyli tabela prognoz,
    • dwa dolne bloki jako <section> we wspólnym <div class="bottom"> - div służy tylko do ułożenia ich obok siebie,
    • <footer> - stopka.

    Bloki mają klasy zamiast identyfikatorów - w CSS selektor z kropką (R.2.6).

    pogoda.php PHP zmienione: 18 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
            </section>
            <section class="banner-middle">
            </section>
            <section class="banner-right">
            </section>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  13. Krok 13: Lewy blok banera: logo

    ok. 1 min
    Polecenie z arkusza

    Zawartość lewego bloku banera: obraz logo.png z tekstem alternatywnym o treści „meteo”

    <img> z alt="meteo". width i height z wymiarami pliku rezerwują miejsce, zanim obraz się wczyta.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
            </section>
            <section class="banner-right">
            </section>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  14. Krok 14: Środkowy blok banera: nagłówek h1

    ok. 1 min
    Polecenie z arkusza

    Zawartość środkowego bloku banera: nagłówek pierwszego stopnia o treści „Prognoza dla Wrocławia”

    <h1> - jeden nagłówek pierwszego stopnia na stronie, opisuje jej temat.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
            </section>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  15. Krok 15: Prawy blok banera: paragraf z datą

    ok. 1 min
    Polecenie z arkusza

    Zawartość prawego bloku banera: akapit (paragraf) o treści „maj, 2019 r.”

    <p>maj, 2019 r.</p>.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  16. Krok 16: Tabela: nagłówek w thead, miejsce na dane w tbody

    Kryteria:

    R.2.9 W tabeli umieszczono wiersz nagłówkowy zawierający wpisy: „DATA”, „TEMPERATURA W NOCY”, „TEMPERATURA W DZIEŃ”, „OPADY [mm/h]”, „CIŚNIENIE [hPa]”. zastosowano znaczniki <tr>, <th> oraz ich zamknięcia (możliwe zastosowanie <thead>)

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku głównego: Tabela o pięciu kolumnach. Wiersz nagłówkowy tabeli zawiera wpisy: „DATA”, „TEMPERATURA W NOCY”, „TEMPERATURA W DZIEŃ”, „OPADY [mm/h]”, „CIŚNIENIE [hPa]”

    Tabela ma dwie sekcje:

    • <thead> - wiersz nagłówkowy z pięcioma komórkami <th> (R.2.9). Atrybut scope="col" mówi czytnikom ekranu, że nagłówek opisuje kolumnę - przy każdej liczbie odczytają jej nazwę, np. „OPADY [mm/h]: 33”,
    • <tbody> - na razie pusta; wiersze z danymi wypisze pętla skryptu.

    Klucz wprost dopuszcza <thead>.

    pogoda.php PHP zmienione: 13 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  17. Krok 17: Blok lewy: mapa

    Kryteria:

    R.2.10 W bloku lewym banera umieszczono obraz logo.png wraz z tekstem alternatywnym "meteo" oraz w bloku lewym umieszczono obraz.jpg z tekstem alternatywnym "Polska, Wrocław"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: obraz.jpg z tekstem alternatywnym o treści „Polska, Wrocław”

    Drugi obraz z alt="Polska, Wrocław" - razem z logo daje R.2.10.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  18. Krok 18: Blok prawy: odnośnik do kwerend

    Kryteria:

    R.3.2 Po wybraniu odnośnika "Pobierz kwerendy" otwiera się lub pobiera plik kwerendy

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: odnośnik do pliku kwerendy.txt z treścią: „Pobierz kwerendy”

    Ścieżka względna kwerendy.txt - plik leży obok strony (R.3.2). Gdyby odnośnik miał zawsze pobierać plik zamiast go otwierać, wystarczyłby atrybut download - arkusz dopuszcza oba zachowania.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  19. Krok 19: Stopka: paragraf z autorem

    Kryteria:

    R.2.7 W bloku środkowym banera zapisano nagłówek h1: "Prognoza dla Wrocławia" oraz w bloku prawym banera paragraf: "maj, 2019 r." oraz w stopce paragraf o treści: „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku stopki: akapit (paragraf) o treści: „Stronę wykonał: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz

    Na egzaminie PESEL, tu Bartosz Bryniarski. Razem z <h1> i datą w banerze - R.2.7.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  20. Etap 3: Styl CSS

    Kroki 20-27 · po tym etapie masz 28 z 33 kryteriów (pkt)

    Krok 20: Plik styl2.css: zmienne z kolorami i krój Helvetica

    Kryteria:

    R.4.1 Ustawiono domyślny krój czcionki dla całej strony na Helvetica (dla selektora * lub body lub html lub kontenera całej strony)

    ok. 2 min
    Polecenie z arkusza

    Cechy formatowania CSS: Są zawarte wyłącznie w zewnętrznym arkuszu stylów. Domyślne dla całej strony: krój czcionki Helvetica

    Kolor rgb(70, 130, 180) powtarza się w pięciu blokach, a rgb(224, 255, 255) w dwóch - każdy wpisany raz jako zmienna w :root. Krój Helvetica dla wszystkich elementów (R.4.1), a po przecinku kroje zapasowe: Windows nie ma Helvetiki, więc przeglądarka weźmie Arial, a gdyby i jego nie było - dowolny krój bezszeryfowy.

    styl2.css CSS nowy plik
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    Podgląd strony po tym kroku (pogoda.php)
  21. Krok 21: Baner jako kontener flex, lewy i prawy blok

    ok. 2 min
    Polecenie z arkusza

    Wspólne dla lewego i prawego bloku banera: kolor tła RGB 70, 130, 180; biały kolor czcionki, szerokość 25%, wysokość 80 px

    display: flex na <header> ustawia trzy sekcje banera w jednym rzędzie - bez float i bez clear pod spodem. Wspólna reguła dla bloku lewego i prawego: kolor ze zmiennej, biały tekst, 25% szerokości i 80 px wysokości. Szerokości zostają na blokach: klucz z 2022 roku ocenia width bloków (R.4.5), a nie podział kontenera.

    styl2.css CSS zmienione: 12 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    Podgląd strony po tym kroku (pogoda.php)
  22. Krok 22: Środkowy blok banera

    Kryteria:

    R.4.3 Ustawiono biały kolor czcionki dla wszystkich bloków banera

    ok. 1 min
    Polecenie z arkusza

    Dla środkowego bloku banera: kolor tła RGB 70, 130, 180; biały kolor czcionki, szerokość 50%, wysokość 80 px, wyrównanie tekstu do środka

    25 + 50 + 25 = 100% - baner wypełnia szerokość strony. Wszystkie trzy bloki banera mają biały tekst (R.4.3).

    styl2.css CSS zmienione: 8 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    Podgląd strony po tym kroku (pogoda.php)
  23. Krok 23: Blok główny

    Kryteria:

    R.4.7 Ustawiono dla bloku głównego marginesy wewnętrzne (padding): 40px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: kolor tła RGB 224, 255, 255; marginesy wewnętrzne 40 px

    Selektor main, padding: 40px (R.4.7). <main> jest zwykłym blokiem, więc sam staje pod banerem - bez clear.

    styl2.css CSS zmienione: 5 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-cyan);
        padding: 40px;
    }
    Podgląd strony po tym kroku (pogoda.php)
  24. Krok 24: Dolny rząd: kontener flex, blok lewy i prawy

    Kryteria: , , ,

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)

    R.4.4 Ustawiono wysokość wszystkich bloków banera 80px oraz bloku lewego i prawego 200px

    R.4.5 Ustawiono szerokość bloku lewego i prawego banera 25% oraz bloku środkowego banera, bloku lewego i prawego 50%

    R.4.6 Ustawiono wyrównanie tekstu do środka dla środkowego bloku banera, bloku lewego i prawego

    ok. 2 min
    Polecenie z arkusza

    Dla bloku lewego i bloku prawego: kolor tła RGB 70, 130, 180; szerokość 50%, wysokość 200 px, wyrównanie tekstu do środka

    Drugi kontener flex - .bottom - ustawia mapę i odnośnik obok siebie. Bloki po 50% i 200 px wysokości, treść wyśrodkowana. Komplet wysokości (R.4.4), szerokości (R.4.5) i wyrównania (R.4.6), a układ bloków zgadza się z obrazem 2 (R.3.1).

    styl2.css CSS zmienione: 12 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-cyan);
        padding: 40px;
    }
    
    .bottom {
        display: flex;
    }
    
    .left,
    .right {
        background-color: var(--steel-blue);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    Podgląd strony po tym kroku (pogoda.php)
  25. Krok 25: Stopka

    Kryteria:

    R.4.2 Ustawiono kolor tła rgb(70, 130, 180) dla wszystkich bloków banera, bloku lewego i prawego oraz rgb(224, 255, 255) dla bloku głównego i stopki

    ok. 1 min
    Polecenie z arkusza

    Dla bloku stopki: kolor tła RGB 224, 255, 255

    Ten sam jasny błękit co w bloku głównym - ze zmiennej. Komplet kolorów tła (R.4.2).

    Druga reguła, footer p { margin: 0; }, to poprawka układu spoza arkusza. Akapit ma domyślny margines 16 px u góry, a ten margines „wypływa” poza stopkę: w wersji z float zatrzymuje go clear, a tu między dolnymi blokami a stopką zrobiłby się biały pasek. Na obrazie 2 stopka przylega do bloków, więc margines akapitu jest zerowany.

    styl2.css CSS zmienione: 8 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-cyan);
        padding: 40px;
    }
    
    .bottom {
        display: flex;
    }
    
    .left,
    .right {
        background-color: var(--steel-blue);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    
    footer {
        background-color: var(--light-cyan);
    }
    
    footer p {
        margin: 0;
    }
    Podgląd strony po tym kroku (pogoda.php)
  26. Krok 26: Tabela i komórki danych

    Kryteria: ,

    R.4.8 Ustawiono styl znacznika tabeli: szerokość 100%, border-collapse: collapse; obramowanie 1px solid koloru niebieskiego (selektor table lub klasa lub identyfikator)

    R.4.9 Ustawiono styl znacznika komórki danych: obramowanie 1px solid koloru niebieskiego (selektor td lub klasa)

    ok. 2 min
    Polecenie z arkusza

    Dla znacznika tabeli: obramowanie 1 px, linią ciągłą o niebieskim kolorze, szerokość 100%, obramowanie połączone za pomocą jednej linii, jak na Obrazie 2. Dla znacznika komórki danych: obramowanie 1 px, linią ciągłą o niebieskim kolorze

    border-collapse: collapse - jedna wspólna linia między komórkami (R.4.8), obramowanie komórek td (R.4.9). Niebieski ze zmiennej --table-blue.

    styl2.css CSS zmienione: 10 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-cyan);
        padding: 40px;
    }
    
    .bottom {
        display: flex;
    }
    
    .left,
    .right {
        background-color: var(--steel-blue);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    
    footer {
        background-color: var(--light-cyan);
    }
    
    footer p {
        margin: 0;
    }
    
    table {
        width: 100%;
        border: 1px solid var(--table-blue);
        border-collapse: collapse;
    }
    
    td {
        border: 1px solid var(--table-blue);
    }
    Podgląd strony po tym kroku (pogoda.php)
  27. Krok 27: Komórki nagłówka

    Kryteria:

    R.4.10 Ustawiono styl znacznika komórki nagłówka tabeli: niebieski kolor tła, biały kolor czcionki, obramowanie 1px solid; kolor obramowania niebieski (selektor th lub klasa); możliwe alternatywne rozwiązanie, np. przypisanie tego stylu tylko do pierwszego wiersza tabeli lub do thead

    ok. 1 min
    Polecenie z arkusza

    Dla znacznika komórki nagłówka tabeli: obramowanie 1 px, linią ciągłą o niebieskim kolorze, kolor tła niebieski, kolor czcionki biały

    Selektor th - biały tekst na niebieskim tle (R.4.10).

    styl2.css CSS zmienione: 6 linii
    :root {
        --steel-blue: rgb(70, 130, 180);
        --light-cyan: rgb(224, 255, 255);
        --table-blue: blue;
    }
    
    * {
        font-family: Helvetica, Arial, sans-serif;
    }
    
    header {
        display: flex;
    }
    
    .banner-left,
    .banner-right {
        background-color: var(--steel-blue);
        color: white;
        width: 25%;
        height: 80px;
    }
    
    .banner-middle {
        background-color: var(--steel-blue);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    
    main {
        background-color: var(--light-cyan);
        padding: 40px;
    }
    
    .bottom {
        display: flex;
    }
    
    .left,
    .right {
        background-color: var(--steel-blue);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    
    footer {
        background-color: var(--light-cyan);
    }
    
    footer p {
        margin: 0;
    }
    
    table {
        width: 100%;
        border: 1px solid var(--table-blue);
        border-collapse: collapse;
    }
    
    td {
        border: 1px solid var(--table-blue);
    }
    
    th {
        border: 1px solid var(--table-blue);
        background-color: var(--table-blue);
        color: white;
    }
    Podgląd strony po tym kroku (pogoda.php)
  28. Etap 4: Skrypt PHP

    Kroki 28-31 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 28: Skrypt na górze pliku: połączenie PDO z bazą prognoza

    Kryteria:

    R.5.1 Skrypt realizuje połączenie z serwerem bazy danych i wybór bazy prognoza

    ok. 3 min
    Polecenie z arkusza

    Napisany w języku PHP. Skrypt łączy się z serwerem bazodanowym na localhost, użytkownik root bez hasła, baza danych o nazwie prognoza

    Skrypt stoi na samej górze pogoda.php, przed <!DOCTYPE html>: najpierw pobiera dane, a HTML niżej tylko je wypisuje. Logika i wygląd strony są rozdzielone - kod HTML nie miesza się z funkcjami bazy.

    new PDO(...) - serwer localhost, baza prognoza i kodowanie w jednym napisie, potem root i puste hasło (R.5.1). Opcje:

    • ERRMODE_EXCEPTION - błąd bazy rzuca wyjątek, który obsłuży jeden blok catch,
    • FETCH_ASSOC - wiersze wyniku jako tablice z nazwami kolumn zamiast numerów.

    Od tego kroku podgląd to wynik prawdziwego uruchomienia strony - tabela ma na razie sam nagłówek.

    pogoda.php PHP zmienione: 6 linii
    <?php
    $pdo = new PDO('mysql:host=localhost;dbname=prognoza;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  29. Krok 29: Zapytanie 1 i wszystkie wiersze naraz

    Kryteria:

    R.5.3 Skrypt wysyła do bazy danych zapytanie 1

    ok. 2 min
    Polecenie z arkusza

    Skrypt wysyła do bazy danych zapytanie 1

    $pdo->query(...) wysyła zapytanie 1 bez zmian (R.5.3) - nie ma w nim danych od użytkownika, więc zapytanie przygotowane nie jest potrzebne. fetchAll() od razu zbiera wszystkie dziewięć wierszy do tablicy $forecasts - połączenie przestaje być potrzebne, zanim zacznie się HTML.

    pogoda.php PHP zmienione: 1 linia
    <?php
    $pdo = new PDO('mysql:host=localhost;dbname=prognoza;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
    $forecasts = $pdo->query('SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;')->fetchAll();
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  30. Krok 30: Pętla foreach w tbody i funkcja e()

    Kryteria: ,

    R.5.4 Skrypt wyświetla każdy zwrócony zapytaniem rekord w osobnym wierszu tabeli w bloku głównym. Dane pobrane z bazy umieszczono w odpowiednich kolumnach tabeli

    R.2.8 W bloku głównym umieszczono tabelę o 5 kolumnach oraz zastosowano znaczniki <table>, <tr>, <td> oraz ich zamknięcia (w kodzie HTML lub skrypcie)

    ok. 4 min
    Polecenie z arkusza

    Każdy zwrócony zapytaniem wiersz jest wyświetlany w osobnym wierszu tabeli w bloku głównym. Dane pobrane z bazy należy umieścić w odpowiednich kolumnach tabeli zgodnie z Obrazem 2

    W <tbody> pętla foreach w składni alternatywnej (foreach (...): i endforeach;) - wiersz tabeli jest zwykłym HTML-em, a PHP wstawia tylko wartości. Każdy rekord to jeden <tr> (R.5.4), komórki <td> w kolejności nagłówków, z danymi wybranymi po nazwie kolumny: $forecast['temperatura_noc'] czyta się łatwiej niż $row[3] i nie psuje się, gdy ktoś zmieni kolejność kolumn w tabeli. Tabela ma pięć kolumn (R.2.8).

    Każda wartość przechodzi przez e() - krótką funkcję z htmlspecialchars. Liczby i daty nie zawierają znaczników, ale wypisywanie wszystkiego przez e() to nawyk, dzięki któremu tekst z bazy nigdy nie zamieni się w kod strony. <?= ... ?> to skrót od <?php echo ... ?>.

    Podgląd: dziewięć prognoz od 2019-05-10 do 2019-05-31, jak na obrazie 2.

    pogoda.php PHP zmienione: 14 linii
    <?php
    function e(mixed $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $pdo = new PDO('mysql:host=localhost;dbname=prognoza;charset=utf8mb4', 'root', '', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
    $forecasts = $pdo->query('SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;')->fetchAll();
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
    <?php foreach ($forecasts as $forecast): ?>
                    <tr>
                        <td><?= e($forecast['data_prognozy']) ?></td>
                        <td><?= e($forecast['temperatura_noc']) ?></td>
                        <td><?= e($forecast['temperatura_dzien']) ?></td>
                        <td><?= e($forecast['opady']) ?></td>
                        <td><?= e($forecast['cisnienie']) ?></td>
                    </tr>
    <?php endforeach; ?>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  31. Krok 31: Obsługa błędów i zamknięcie połączenia w finally

    Kryteria:

    R.5.2 Ostatnią operacją na bazie jest jej zamknięcie (zgodne ze składnią)

    ok. 3 min
    Polecenie z arkusza

    Na końcu działania skrypt zamyka połączenie z serwerem.

    Połączenie i zapytanie trafiają do bloku try:

    • $forecasts = [] i $error = '' przed try - zmienne istnieją zawsze, także gdy baza nie odpowie,
    • catch (PDOException $exception) - zamiast komunikatu PHP ze ścieżkami serwera strona dostaje zdanie dla użytkownika,
    • finally wykonuje się zawsze, więc $pdo = null zamyka połączenie po sukcesie i po błędzie - to ostatnia operacja na bazie (R.5.2). PDO nie ma funkcji close; połączenie kończy się, gdy znika ostatnie odwołanie do obiektu.

    W <tbody> doszedł wiersz z komunikatem, wyświetlany tylko wtedy, gdy $error nie jest pusty - colspan="5" rozciąga komórkę na całą szerokość tabeli. Sprawdzone na prawdziwym PHP z literówką w nazwie bazy: tabela pokazuje „Prognoza jest chwilowo niedostępna.”, a mapa, odnośnik i stopka wyświetlają się normalnie. Podgląd: działająca baza.

    pogoda.php PHP zmienione: 18 linii
    <?php
    function e(mixed $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
    }
    
    $forecasts = [];
    $error = '';
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=prognoza;charset=utf8mb4', 'root', '', [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $forecasts = $pdo->query('SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;')->fetchAll();
    } catch (PDOException $exception) {
        $error = 'Prognoza jest chwilowo niedostępna.';
    } finally {
        $pdo = null;
    }
    ?>
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <header>
            <section class="banner-left">
                <img src="logo.png" alt="meteo" width="84" height="80">
            </section>
            <section class="banner-middle">
                <h1>Prognoza dla Wrocławia</h1>
            </section>
            <section class="banner-right">
                <p>maj, 2019 r.</p>
            </section>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th scope="col">DATA</th>
                        <th scope="col">TEMPERATURA W NOCY</th>
                        <th scope="col">TEMPERATURA W DZIEŃ</th>
                        <th scope="col">OPADY [mm/h]</th>
                        <th scope="col">CIŚNIENIE [hPa]</th>
                    </tr>
                </thead>
                <tbody>
    <?php foreach ($forecasts as $forecast): ?>
                    <tr>
                        <td><?= e($forecast['data_prognozy']) ?></td>
                        <td><?= e($forecast['temperatura_noc']) ?></td>
                        <td><?= e($forecast['temperatura_dzien']) ?></td>
                        <td><?= e($forecast['opady']) ?></td>
                        <td><?= e($forecast['cisnienie']) ?></td>
                    </tr>
    <?php endforeach; ?>
    <?php if ($error !== ''): ?>
                    <tr>
                        <td colspan="5"><?= e($error) ?></td>
                    </tr>
    <?php endif; ?>
                </tbody>
            </table>
        </main>
        <div class="bottom">
            <section class="left">
                <img src="obraz.jpg" alt="Polska, Wrocław" width="200" height="200">
            </section>
            <section class="right">
                <a href="kwerendy.txt">Pobierz kwerendy</a>
            </section>
        </div>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  32. Etap 5: Porównanie z wersją podstawową

    Krok 32 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 32: Co jest inaczej i którą wersję wybrać na egzaminie

    ok. 3 min

    Obie wersje dają komplet 33 punktów. Różnice:

    wersja podstawowawersja nowoczesna
    blokisiedem bloków jeden po drugim, section z idheader z trzema sekcjami, main, footer
    układfloat: left i clear: bothdwa kontenery display: flex, width na blokach
    kolorywpisane w każdej regulezmienne --steel-blue, --light-cyan
    tabelawiersz nagłówka i wiersze z echo w jednym <table><thead> ze scope="col", <tbody> z pętlą
    bibliotekamysqli (tabela 1 arkusza)PDO z wyjątkami
    gdzie jest skryptw środku tabelina górze pliku, w tabeli tylko foreach
    dane w wierszu$row[2] - $row[6]$forecast['data_prognozy'] itd.
    wypisywanieecho '<td>' . $row[2] . '</td>'<td><?= e(...) ?></td>
    awaria bazy„Fatal error”, urwana stronawiersz z komunikatem, cała strona
    zamknięcie bazymysqli_close po pętli$pdo = null w finally

    Na egzaminie wersja podstawowa trzyma się funkcji z tabeli 1 i łatwiej ją napisać bez dokumentacji. Nowoczesna oddziela dane od HTML-u i nie wywraca strony przy awarii bazy - a klucz przyjmuje obie. Na prawdziwym serwerze strona tylko do odczytu łączyłaby się kontem z samym prawem SELECT, a nie kontem root bez hasła.

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

  33. Etap 6: Oddanie pracy

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

    Krok 33: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    UWAGA: po zakończeniu pracy utwórz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowano poprawność działania witryny. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzana była strona. W folderze z numerem zdającego: import.png, kw1.jpg - kw4.jpg, kwerendy.txt, logo.png, obraz.jpg, pogoda.php, przeglądarka.txt i styl2.css. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.

Potwierdzenie

Informacja