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

Rozwiązanie krok po kroku: Prognoza pogody dla Wrocławia (Wersja podstawowa)

Portal prognozy pogody: baza prognoza z tabelami miast i prognoz (import z pliku baza2.sql), cztery zapytania - prognozy dla miasta o id 1 posortowane według daty, rekordy z opadami powyżej 30 mm/h, zimne noce z nazwą miasta wybraną przez relację (JOIN) i dodanie kolumny do tabeli miast (ALTER TABLE). Do tego logo przeskalowane do 80 px z zachowaniem przezroczystości, mapa przeskalowana do 200 px, strona pogoda.php z trzema blokami banera, tabelą prognoz, mapą, odnośnikiem i stopką, style w styl2.css oraz skrypt, który wypełnia tabelę danymi z bazy.

To arkusz EE.09 ze stycznia 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypt jest najpierw napisany najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzony na prawdziwej awarii bazy i zabezpieczony.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: semantyczne znaczniki, układ we flex, PDO z obsługą błędów, skrypt na górze pliku i tabela z sekcjami <thead> i <tbody> - obie wersje są zgodne z kluczem.

Baza i grafiki pochodzą z oryginalnego archiwum CKE pliki2.zip (załącznik do pobrania na stronie 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 od kroków ze skryptem to wynik prawdziwego uruchomienia kodu w PHP 8.2 (klucz każe sprawdzać w XAMPP 8.0.7 - użyte funkcje działają w obu wersjach tak samo).

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 (75% z 33 to 24,75, zaokrąglone w górę) - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia.

  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.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum pliki2.zip rozpakowujesz do tego folderu, podając hasło 3MeTeo# (wielkość liter ma znaczenie). W środku są trzy pliki: baza2.sql, logo.png i obraz.jpg.

    Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, plik strony i plik stylów.

  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

    W XAMPP Control Panel Start przy Apache i MySQL, w przeglądarce http://localhost/phpmyadmin. Nowa, nazwa prognoza, porównywanie np. utf8mb4_polish_ci, Utwórz.

    Typowe błędy

    Skrypt łączy się z bazą po nazwie - literówka w nazwie bazy to brak danych w tabeli strony.

  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

    Zaznacz bazę prognoza, karta Import, Wybierz plik → baza2.sql, Wykonaj. Po komunikacie „Import zakończył się sukcesem” w lewym panelu jest 12 tabel - zadanie używa dwóch: miasta (15 miast) i pogoda (17 prognoz). Zrzut całego ekranu z komunikatem i listą tabel: import.png.

    Typowe błędy

    Ten zrzut ma format PNG, zrzuty zapytań - JPEG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany.

    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

    Karta SQL bazy prognoza. Zapytanie klauzula po klauzuli:

    • SELECT * - wszystkie pola,
    • FROM pogoda,
    • WHERE miasta_id = 1 - „miasta o id równym 1” to w tabeli pogoda kolumna miasta_id (klucz obcy do tabeli miasta), a nie kolumna id prognozy,
    • ORDER BY data_prognozy - sortowanie rosnąco jest domyślne, więc ASC można pominąć.

    Wynik: 9 rekordów, kolejno z id 2, 3, 4, 5, 6, 7, 8, 9 i 1 - rekord 1 ma najpóźniejszą datę (31 maja), więc trafia na koniec. To jest dokładnie kolejność z klucza i z tabeli na obrazie 2. Zapytanie kopiujesz do kwerendy.txt (R.1.2), zrzut zapisujesz jako kw1.jpg.

    Typowe błędy

    WHERE id = 1 zwraca jeden rekord - prognozę o numerze 1, a nie prognozy miasta o numerze 1.

    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

    • SELECT id, data_prognozy - tylko dwie kolumny,
    • WHERE opady > 30 - „przekraczają” to ostro większe; kolumna przechowuje same liczby, jednostka mm/h jest tylko w opisie.

    Wynik: 3 rekordy o id 1, 7 i 8 (33, 33 i 32 mm/h). Trzy prognozy dla Poznania mają dokładnie 30 mm/h i do wyniku nie wchodzą. Zrzut: kw2.jpg.

    Typowe błędy

    opady >= 30 dołoży trzy rekordy z wartością 30 - razem 6 zamiast 3.

    kwerendy.txt Tekst zmienione: 3 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;
    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. 4 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ę

    Nazwa miasta jest w innej tabeli niż prognoza, więc potrzebna jest relacja:

    • SELECT data_prognozy, temperatura_noc, nazwa - trzy kolumny z dwóch tabel; nazwy są jednoznaczne, więc nie trzeba ich poprzedzać nazwą tabeli,
    • FROM pogoda JOIN miasta - złączenie tabel,
    • ON miasta.id = pogoda.miasta_id - prognoza łączy się z miastem, którego numer ma w kolumnie miasta_id,
    • WHERE temperatura_noc < 6 - „poniżej 6” to ostro mniejsze.

    Wynik: 3 rekordy - 2019-05-14, 5 stopni, Wrocław oraz 2019-05-12 i 2019-05-13, 5 stopni, Poznań. Zrzut: kw3.jpg. Klucz przyjmuje też zapis z tabelami po przecinku i warunkiem relacji w WHERE.

    ⚠️ Rozbieżność arkusz-klucz: klucz podaje w wyniku „Wrocław” i „Poznań”, a w pliku baza2.sql nazwy tych miast są zapisane bez polskich liter - Wroclaw i Poznan (inne miasta, np. Kraków, mają je poprawnie). Wynik na zrzucie pokazuje to, co jest w bazie, i jest zgodny z kluczem - liczy się zestaw rekordów, a nie pisownia nazwy.

    Typowe błędy

    temperatura_noc <= 6 dokłada cztery noce z temperaturą 6 stopni. Bez warunku relacji każda prognoza łączy się z każdym z 15 miast.

    kwerendy.txt Tekst zmienione: 3 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;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: kolumna wojewodztwo w tabeli miasta

    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. 3 min
    Polecenie z arkusza

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

    • ALTER TABLE miasta - zmiana struktury istniejącej tabeli,
    • ADD COLUMN wojewodztwo TEXT - nowa kolumna typu tekstowego. Klucz przyjmuje dowolny typ napisowy, np. VARCHAR(50). Nazwa bez polskiej litery, tak jak w arkuszu.

    phpMyAdmin odpowiada „MySQL zwrócił pusty wynik”. Żeby zrzut kw4.jpg pokazywał efekt, pod zapytaniem 4 dopisz w tej samej karcie SQL SHOW COLUMNS FROM miasta; - widać trzy kolumny, ostatnia to wojewodztwo typu text. Klucz przyjmuje też zrzut samej struktury tabeli z karty Struktura. Do kwerendy.txt trafia tylko zapytanie 4.

    Typowe błędy

    Drugie wykonanie tego samego zapytania kończy się błędem #1060 „Zduplikowana nazwa kolumny” - kolumna już istnieje, a pierwszy zrzut z poprawnym wykonaniem wystarcza.

    kwerendy.txt Tekst zmienione: 3 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 TEXT;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

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

    Krok 8: Logo: wysokość 80 px z zachowaniem 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ść

    Oryginał ma 315 × 300 px i przezroczyste tło (kanał alfa). W GIMP-ie Obraz → Skaluj obraz, łańcuch zamknięty, wysokość 80 px - szerokość przelicza się na 315 × 80 / 300 = 84 px (klucz: 84 px ±5). Zapis: Plik → Nadpisz logo.png.

    Przezroczystość zostaje, bo plik nadal jest w formacie PNG z kanałem alfa - na stronie słońce stoi wprost na niebieskim tle banera, bez białego prostokąta (R.2.3).

    Typowe błędy

    Eksport do JPEG albo spłaszczenie obrazu (Obraz → Spłaszcz obraz) zamienia przezroczyste tło na białe - brak punktu R.2.3.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Mapa: wysokość 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. 2 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

    Obraz jest kwadratowy (358 × 358 px), więc przy wysokości 200 px szerokość też wynosi 200 px (klucz: 200 px ±5). Obraz → Skaluj obraz, łańcuch zamknięty, potem Plik → Nadpisz obraz.jpg. Wysokość równa wysokości dolnych bloków (200 px) - mapa wypełni blok od góry do dołu.

    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. 2 min
    Polecenie z arkusza

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

    Strona od razu ma rozszerzenie .php - wiersze tabeli wypełni skrypt w tym samym pliku. Dopóki w pliku nie ma kodu PHP, serwer odda go jak zwykły HTML. <meta charset="UTF-8"> w <head> i plik zapisany w UTF-8 - nazwa pliku i kodowanie to razem R.2.4.

    Stronę sprawdzasz przez http://localhost/…/pogoda.php - po otwarciu z dysku przeglądarka pokazałaby kod PHP zamiast go wykonać.

    pogoda.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  11. Krok 11: Tytuł strony

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Prognoza pogody Wrocław”

    <title> w <head>. Nie myl z nagłówkiem banera: tytuł to „Prognoza pogody Wrocław”, nagłówek - „Prognoza dla Wrocławia” (R.2.5).

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  12. Krok 12: Podpięcie arkusza stylów styl2.css

    Kryteria:

    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

    Arkusz stylów w pliku o nazwie styl2.css prawidłowo połączony z kodem strony

    <link rel="stylesheet" href="styl2.css"> - w nazwie nie ma podkreślenia (R.3.3). Plik stylów powstanie po HTML-u.

    Typowe błędy

    Klucz odbiera R.3.3 także wtedy, gdy choć jeden selektor nie trafia w blok - np. kropka w CSS zamiast # przy bloku z identyfikatorem.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  13. Krok 13: Bloki: trzy banera, główny, lewy, prawy i stopka

    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

    Siedem bloków w kolejności z obrazu 2: sześć znaczników <section> i <footer> na stopkę. Każda sekcja ma identyfikator, bo w CSS dostaną różne szerokości: banner-left, banner-middle, banner-right, main, left i right (nazwy po angielsku - arkusz ich nie narzuca). Stopka jest na stronie jedna, więc wystarczy selektor znacznika footer (R.2.6). Ułożenie bloków obok siebie zrobi CSS.

    pogoda.php PHP zmienione: 14 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
        </section>
        <section id="banner-middle">
        </section>
        <section id="banner-right">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  14. Krok 14: 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 przeskalowanym logo.png i alt="meteo". Punkt R.2.10 przyjdzie razem z mapą w bloku lewym.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
        </section>
        <section id="banner-right">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  15. Krok 15: Środkowy blok banera: nagłówek pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

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

    <h1> - jedyny nagłówek pierwszego stopnia na stronie.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  16. Krok 16: 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> - z przecinkiem i kropką po „r”, jak w arkuszu.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  17. Krok 17: Blok główny: tabela

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku głównego: Tabela o pięciu kolumnach

    Znacznik <table> w bloku głównym. Pięć kolumn wyznaczy wiersz nagłówkowy, a wiersze danych dopisze skrypt.

    pogoda.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
            </table>
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  18. Krok 18: Wiersz nagłówkowy tabeli

    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

    Wiersz nagłówkowy tabeli zawiera wpisy: „DATA”, „TEMPERATURA W NOCY”, „TEMPERATURA W DZIEŃ”, „OPADY [mm/h]”, „CIŚNIENIE [hPa]”

    Jeden wiersz <tr> z pięcioma komórkami nagłówka <th> - przeglądarka pogrubia je i wyśrodkowuje, a czytnik ekranu odczytuje jako nazwy kolumn (R.2.9). Kolejność kolumn decyduje o tym, w jakiej kolejności skrypt wypisze dane.

    Typowe błędy

    <td> zamiast <th> w pierwszym wierszu - klucz wymaga znaczników <th> (albo sekcji <thead>), a styl komórek nagłówka z R.4.10 nie trafi w zwykłe komórki.

    pogoda.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
            </table>
        </section>
        <section id="left">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  19. Krok 19: Blok lewy: mapa z tekstem alternatywnym

    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 strony: alt="Polska, Wrocław". Oba obrazy z właściwymi tekstami alternatywnymi - R.2.10.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  20. Krok 20: Blok prawy: odnośnik do pliku kwerendy.txt

    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”

    href="kwerendy.txt" - ścieżka względna: plik leży w tym samym folderze co strona. Przeglądarka otworzy go jako tekst albo zaproponuje pobranie (R.3.2). Dlatego kwerendy.txt musi być w folderze strony.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  21. Krok 21: 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 po dwukropku wpisujesz PESEL; tu w jego miejscu stoi Bartosz Bryniarski. Z nagłówkiem <h1> i paragrafem w prawym bloku banera daje to R.2.7.

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

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

    Krok 22: Plik styl2.css: krój Helvetica dla całej strony

    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. 1 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

    Nowy plik styl2.css w folderze zdającego - każda reguła tylko tutaj. Selektor * z font-family: Helvetica obejmuje wszystkie elementy (R.4.1). Helvetica jest fontem komputerów Apple - na Windows przeglądarka zastąpi ją krojem bezszeryfowym, np. Arialem, który wygląda niemal tak samo.

    styl2.css CSS nowy plik
    * {
        font-family: Helvetica;
    }
    Podgląd strony po tym kroku (pogoda.php)
  23. Krok 23: Lewy i prawy blok banera: wspólna reguła

    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

    Dwa selektory identyfikatorów po przecinku, jedna reguła. Kolor podany jako rgb(70, 130, 180) - trzy składowe z arkusza w kolejności czerwony, zielony, niebieski (to odcień nazywany SteelBlue). Wysokość 80 px - tyle co logo.

    styl2.css CSS zmienione: 6 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    Podgląd strony po tym kroku (pogoda.php)
  24. Krok 24: Ś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

    Szerokości banera: 25 + 50 + 25 = 100%. Wszystkie trzy bloki banera mają teraz biały tekst (R.4.3).

    styl2.css CSS zmienione: 7 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    Podgląd strony po tym kroku (pogoda.php)
  25. Krok 25: Blok główny: tło i marginesy wewnętrzne

    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

    rgb(224, 255, 255) to bardzo jasny błękit (LightCyan). padding: 40px odsuwa tabelę od brzegów bloku (R.4.7).

    styl2.css CSS zmienione: 4 linie
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    Podgląd strony po tym kroku (pogoda.php)
  26. Krok 26: Blok lewy i prawy

    Kryteria: , ,

    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

    Wspólna reguła dla dwóch dolnych bloków. Arkusz nie podaje tu koloru czcionki - odnośnik zostaje w domyślnym kolorze odnośnika, jak na obrazie 2. Komplet: wysokości 80 i 200 px (R.4.4), szerokości 25, 50 i 50% (R.4.5) i wyśrodkowanie środkowego bloku banera oraz bloków lewego i prawego (R.4.6) - dlatego mapa i odnośnik stoją pośrodku swoich bloków.

    styl2.css CSS zmienione: 6 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    Podgląd strony po tym kroku (pogoda.php)
  27. Krok 27: Stopka: kolor tła

    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

    Selektor znacznika footer. Wszystkie kolory tła bloków są ustawione (R.4.2).

    styl2.css CSS zmienione: 3 linie
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    footer {
        background-color: rgb(224, 255, 255);
    }
    Podgląd strony po tym kroku (pogoda.php)
  28. Krok 28: Układ bloków: float i clear

    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)

    ok. 2 min
    Polecenie z arkusza

    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

    Pięć bloków, które stoją obok siebie, dostaje float: left: trzy bloki banera (razem 100%) i dwa dolne (razem 100%) - każda trójka i para wypełnia jeden rząd.

    Blok główny i stopka zajmują całą szerokość i muszą zacząć się pod pływającymi blokami - stąd clear: both. Bez niego blok główny wsunąłby się pod baner, a stopka pod mapę (R.3.1). Klucz przyjmuje też flex albo grid - wersja nowoczesna pokazuje układ we flex.

    Typowe błędy

    Bez clear na stopce jej tło przykryje dolne bloki, a tekst ułoży się obok mapy.

    styl2.css CSS zmienione: 6 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    footer {
        background-color: rgb(224, 255, 255);
    }
    #banner-left, #banner-middle, #banner-right, #left, #right {
        float: left;
    }
    #main, footer {
        clear: both;
    }
    Podgląd strony po tym kroku (pogoda.php)
  29. Krok 29: Tabela: obramowanie, szerokość, połączone linie

    Kryteria:

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

    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

    border: 1px solid blue - szerokość, linia ciągła, kolor. border-collapse: collapse - sąsiednie komórki mają jedną wspólną linię zamiast dwóch równoległych (R.4.8).

    styl2.css CSS zmienione: 5 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    footer {
        background-color: rgb(224, 255, 255);
    }
    #banner-left, #banner-middle, #banner-right, #left, #right {
        float: left;
    }
    #main, footer {
        clear: both;
    }
    table {
        border: 1px solid blue;
        width: 100%;
        border-collapse: collapse;
    }
    Podgląd strony po tym kroku (pogoda.php)
  30. Krok 30: Komórki danych

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Dla znacznika komórki danych: obramowanie 1 px, linią ciągłą o niebieskim kolorze

    Selektor td - komórki danych, które dopisze skrypt (R.4.9).

    styl2.css CSS zmienione: 3 linie
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    footer {
        background-color: rgb(224, 255, 255);
    }
    #banner-left, #banner-middle, #banner-right, #left, #right {
        float: left;
    }
    #main, footer {
        clear: both;
    }
    table {
        border: 1px solid blue;
        width: 100%;
        border-collapse: collapse;
    }
    td {
        border: 1px solid blue;
    }
    Podgląd strony po tym kroku (pogoda.php)
  31. Krok 31: 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łe napisy na niebieskim tle, jak na obrazie 2 (R.4.10). Arkusz stylów jest kompletny.

    styl2.css CSS zmienione: 5 linii
    * {
        font-family: Helvetica;
    }
    #banner-left, #banner-right {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 25%;
        height: 80px;
    }
    #banner-middle {
        background-color: rgb(70, 130, 180);
        color: white;
        width: 50%;
        height: 80px;
        text-align: center;
    }
    #main {
        background-color: rgb(224, 255, 255);
        padding: 40px;
    }
    #left, #right {
        background-color: rgb(70, 130, 180);
        width: 50%;
        height: 200px;
        text-align: center;
    }
    footer {
        background-color: rgb(224, 255, 255);
    }
    #banner-left, #banner-middle, #banner-right, #left, #right {
        float: left;
    }
    #main, footer {
        clear: both;
    }
    table {
        border: 1px solid blue;
        width: 100%;
        border-collapse: collapse;
    }
    td {
        border: 1px solid blue;
    }
    th {
        border: 1px solid blue;
        background-color: blue;
        color: white;
    }
    Podgląd strony po tym kroku (pogoda.php)
  32. Etap 4: Skrypt PHP

    Kroki 32-36 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 32: Miejsce skryptu i połączenie 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

    Wiersze danych mają się pojawić w tabeli, pod wierszem nagłówkowym - dlatego skrypt stoi w <table>, między zamknięciem pierwszego </tr> a </table>. Wszystko, co wypisze, trafi w to miejsce strony.

    Pierwsza instrukcja: mysqli_connect z tabeli 1 - serwer localhost, użytkownik root, puste hasło '' i baza prognoza (R.5.1). Od tego kroku podgląd to wynik prawdziwego uruchomienia pogoda.php - tabela ma na razie sam nagłówek.

    pogoda.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  33. Krok 33: Zapytanie 1 wysłane do bazy

    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

    mysqli_query wysyła zapytanie 1 z kwerendy.txt, przepisane bez zmian (R.5.3). Wynik - dziewięć prognoz Wrocławia - czeka w zmiennej $result; na stronie jeszcze nic się nie zmienia.

    Typowe błędy

    Zapytanie jest w apostrofach '…', więc w środku nie może być apostrofów - tu ich nie ma, bo warunek porównuje liczby.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  34. Krok 34: Pętla po wierszach i kolumna DATA

    ok. 3 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

    • mysqli_fetch_row pobiera kolejny wiersz wyniku jako tablicę numerowaną od 0, a gdy wierszy już nie ma, zwraca null - wtedy pętla while się kończy,
    • każdy wiersz wyniku to jeden wiersz tabeli: echo '<tr>' na początku i echo '</tr>' na końcu.

    SELECT * zwraca kolumny w kolejności z tabeli: [0] id, [1] miasta_id, [2] data_prognozy, [3] temperatura_noc, [4] temperatura_dzien, [5] opady, [6] cisnienie. Tabela na obrazie 2 nie pokazuje dwóch pierwszych, więc pierwsza komórka to $row[2] - data. Podgląd: dziewięć wierszy z samymi datami, od 10 do 31 maja.

    pogoda.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo '<tr>';
                    echo '<td>' . $row[2] . '</td>';
                    echo '</tr>';
                }
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  35. Krok 35: Pozostałe kolumny: temperatury, opady, ciśnienie

    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. 3 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

    Cztery kolejne komórki <td> z indeksami 3, 4, 5 i 6 - w tej samej kolejności co nagłówki: noc, dzień, opady, ciśnienie. Każdy rekord jest w osobnym wierszu, a dane w swoich kolumnach (R.5.4); tabela ma pięć kolumn ze znacznikami <table>, <tr>, <td> i ich zamknięciami (R.2.8).

    Podgląd odpowiada obrazowi 2: pierwszy wiersz to 2019-05-10, 15, 23, 0, 1020, a ostatni - 2019-05-31, 15, 23, 33, 1020.

    Typowe błędy

    mysqli_fetch_array zamiast fetch_row też działa z indeksami liczbowymi. Indeksy przesunięte o jeden ($row[1] jako data) wpisują numer miasta w kolumnę DATA - wiersze są, ale dane nie w swoich kolumnach.

    pogoda.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo '<tr>';
                    echo '<td>' . $row[2] . '</td>';
                    echo '<td>' . $row[3] . '</td>';
                    echo '<td>' . $row[4] . '</td>';
                    echo '<td>' . $row[5] . '</td>';
                    echo '<td>' . $row[6] . '</td>';
                    echo '</tr>';
                }
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (pogoda.php)
  36. Krok 36: Zamknięcie połączenia z bazą

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

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

    mysqli_close($connection) po pętli - ostatnia operacja na bazie (R.5.2). Skrypt spełnia wszystkie kryteria arkusza. Dalej dwa kroki o zabezpieczeniach - klucz ich nie wymaga.

    pogoda.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo '<tr>';
                    echo '<td>' . $row[2] . '</td>';
                    echo '<td>' . $row[3] . '</td>';
                    echo '<td>' . $row[4] . '</td>';
                    echo '<td>' . $row[5] . '</td>';
                    echo '<td>' . $row[6] . '</td>';
                    echo '</tr>';
                }
                mysqli_close($connection);
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  37. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 37-38 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 37: Zabezpieczenie: awaria bazy bez komunikatu PHP

    ok. 4 min
    Polecenie z arkusza

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

    Sprawdzone na wersji z poprzednich kroków: wystarczy literówka w nazwie bazy (prognoz) albo zatrzymany serwer MySQL, żeby PHP przerwał stronę komunikatem „Fatal error: Uncaught mysqli_sql_exception: Unknown database”. Komunikat zawiera pełną ścieżkę pliku na serwerze i numer linii, a strona urywa się w środku tabeli - bez mapy, odnośnika i stopki. Takie informacje pomagają atakującemu poznać budowę serwera.

    Poprawka:

    • mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) - każdy błąd bazy rzuca wyjątek; w PHP 8.1 i nowszych to ustawienie domyślne, w PHP 8.0 z klucza trzeba je włączyć,
    • operacje na bazie w bloku try, a w catch jeden wiersz tabeli na całą szerokość (colspan="5") ze zdaniem dla użytkownika. Reszta strony renderuje się normalnie,
    • każda wartość przed wypisaniem przechodzi przez htmlspecialchars - tutaj to liczby i daty, ale gdyby do tabeli trafiła kolumna tekstowa wpisywana przez kogoś innego (np. nazwa miasta), znacznik <script> w danych nie wykona się na stronie.

    Stare linie zostają w komentarzu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza. Podgląd: strona przy działającej bazie wygląda tak samo jak wcześniej.

    Typowe błędy

    @ przed nazwą funkcji (@mysqli_connect) tylko wycisza ostrzeżenie - skrypt dalej się wywraca, a błąd znika też z dziennika serwera.

    pogoda.php PHP zmienione: 18 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                // $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                // $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
                try {
                    $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                    $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                    while ($row = mysqli_fetch_row($result)) {
                        echo '<tr>';
                        echo '<td>' . htmlspecialchars($row[2]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[3]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[4]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[5]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[6]) . '</td>';
                        echo '</tr>';
                    }
                    mysqli_close($connection);
                } catch (mysqli_sql_exception $exception) {
                    echo '<tr><td colspan="5">Prognoza jest chwilowo niedostępna.</td></tr>';
                }
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  38. Krok 38: Hasła i konto bazy tylko do odczytu

    ok. 3 min
    Polecenie z arkusza

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

    Strona tylko czyta prognozy, a łączy się kontem root bez hasła - administratorem całego serwera baz. Arkusz tego wymaga (R.5.1) i na egzaminie tak zostaje. W prawdziwym serwisie każdy błąd w skrypcie, który pozwoliłby wstrzyknąć SQL, dawałby wtedy pełną władzę nad wszystkimi bazami.

    Zasada najmniejszych uprawnień - osobne konto z hasłem, które może tylko odczytać jedną tabelę:

    CREATE USER 'pogoda'@'localhost' IDENTIFIED BY 'Wr0claw-maj-2019!';
    GRANT SELECT ON prognoza.pogoda TO 'pogoda'@'localhost';
    

    Sprawdzone na prawdziwej bazie: strona z tym kontem wyświetla tabelę bez zmian, a próba DROP TABLE pogoda kończy się błędem „DROP command denied”, tak samo jak odczyt innej tabeli (miasta). Hasło w tym przykładzie służy do nauki - na serwerze konto dostaje długie losowe hasło, a dane logowania leżą w pliku poza folderem strony. Do pliku egzaminacyjnego nic z tego nie przenosisz - plik skryptu bez zmian.

    pogoda.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Prognoza pogody Wrocław</title>
        <link rel="stylesheet" href="styl2.css">
    </head>
    <body>
        <section id="banner-left">
            <img src="logo.png" alt="meteo">
        </section>
        <section id="banner-middle">
            <h1>Prognoza dla Wrocławia</h1>
        </section>
        <section id="banner-right">
            <p>maj, 2019 r.</p>
        </section>
        <section id="main">
            <table>
                <tr>
                    <th>DATA</th>
                    <th>TEMPERATURA W NOCY</th>
                    <th>TEMPERATURA W DZIEŃ</th>
                    <th>OPADY [mm/h]</th>
                    <th>CIŚNIENIE [hPa]</th>
                </tr>
                <?php
                // $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                // $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
                try {
                    $connection = mysqli_connect('localhost', 'root', '', 'prognoza');
                    $result = mysqli_query($connection, 'SELECT * FROM pogoda WHERE miasta_id = 1 ORDER BY data_prognozy;');
                    while ($row = mysqli_fetch_row($result)) {
                        echo '<tr>';
                        echo '<td>' . htmlspecialchars($row[2]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[3]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[4]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[5]) . '</td>';
                        echo '<td>' . htmlspecialchars($row[6]) . '</td>';
                        echo '</tr>';
                    }
                    mysqli_close($connection);
                } catch (mysqli_sql_exception $exception) {
                    echo '<tr><td colspan="5">Prognoza jest chwilowo niedostępna.</td></tr>';
                }
                ?>
            </table>
        </section>
        <section id="left">
            <img src="obraz.jpg" alt="Polska, Wrocław">
        </section>
        <section id="right">
            <a href="kwerendy.txt">Pobierz kwerendy</a>
        </section>
        <footer>
            <p>Stronę wykonał: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  39. Etap 6: Oddanie pracy

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

    Krok 39: 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 wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/…/pogoda.php.

    W folderze z numerem zdającego muszą być: import.png, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, logo.png, obraz.jpg, pogoda.php, przeglądarka.txt i styl2.css. Nagraj płytę, sprawdź jej odczyt w obecności przewodniczącego zespołu nadzorującego i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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