Przejdź do głównej treści
E.14-04-21.06-SGCzerwiec 2021 · 48 kroków · ok. 89 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Biblioteka miejska - lista czytelników (Wersja podstawowa)

Portal miejskiej biblioteki: baza biblioteka z sześcioma tabelami (autorzy, czytelnicy, książki, kategorie, wydawnictwa, wypożyczenia) i cztery zapytania - nowa czytelniczka, lista czytelników, tytuły Fredry (złączenie z tabelą autorzy) i liczba tytułów każdego autora (COUNT z GROUP BY). Do tego strona biblioteka.php z banerem, trzema panelami i stopką, style w styl.css oraz dwa skrypty PHP: pierwszy wypisuje czytelników jako elementy listy punktowanej, drugi przyjmuje dane z formularza, tworzy kod czytelnika (an05mi) i dodaje czytelnika do bazy.

To arkusz E.14 z czerwca 2021 - kwalifikacji formuły 2012, 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ą. Skrypty są najpierw napisane najprościej, funkcjami mysqli z tabeli 1 arkusza, a na końcu sprawdzone na prawdziwych danych (apostrof w nazwisku, znaczniki HTML, puste pola, polskie litery) i poprawione.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (flex, PDO)” jest drugi sposób rozwiązania tego samego arkusza: panele w kontenerze flex, etykiety <label>, PDO z zapytaniami przygotowanymi, zapis nowego czytelnika przed wypisaniem listy i przekierowanie po dodaniu - obie wersje są zgodne z kluczem.

Skąd materiały. Archiwum pliki4.zip z arkusza nie zachowało się w publicznych zbiorach CKE i OKE. Załącznik na stronie arkusza to archiwum odtworzone z plików biblioteka.sql i biblioteka.png zgodnych z arkuszem (te same tabele co na obrazie 1, te same wyniki zapytań co w kluczu, ta sama grafika co na obrazie 2), spakowane z hasłem podanym w arkuszu. Na tej samej bazie i grafice jest zbudowany arkusz E.14-03-21.06 (dodawanie czytelników i lista autorów) - inne zapytania i inny układ strony. 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 7.4.8 - użyte funkcje działają w obu wersjach tak samo).

Jak liczą się punkty. Klucz ma 34 kryteria (R.1.1 - R.5.7), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 26 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Baza danych

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

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

    ok. 2 min
    Polecenie z arkusza

    Aby wykonać zadanie, zaloguj się na konto Egzamin bez hasła. Na pulpicie znajdziesz archiwum ZIP o nazwie pliki4.zip zabezpieczone hasłem: Z@d@niE_14. Archiwum należy rozpakować. Na pulpicie konta Egzamin utwórz folder. Jako nazwy folderu użyj swojego numeru PESEL. Rozpakowane pliki umieść w tym folderze. Wyniki swojej pracy również zapisz w tym folderze.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum pliki4.zip rozpakowujesz do tego folderu, podając hasło Z@d@niE_14 (dwa znaki @ zamiast liter „a”, wielkie E na końcu słowa). W środku są dwa pliki: biblioteka.sql (baza do importu) i biblioteka.png (grafika na stronę).

    Do tego folderu trafia wszystko, co powstanie: zrzuty, kwerendy.txt, biblioteka.php i styl.css. Archiwum do ćwiczeń jest załącznikiem na stronie arkusza w serwisie - ma tę samą nazwę i to samo hasło.

    Typowe błędy

    Pliki zapisane poza folderem zdającego (np. tylko w htdocs) nie trafią na płytę - a ocenia się wyłącznie to, co jest na płycie.

  2. Krok 2: XAMPP i pusta baza biblioteka

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache z XAMPP Control Panel i przejdź do narzędzia phpMyAdmin. Następnie wykonaj operacje na bazie danych: Utwórz nową bazę danych o nazwie biblioteka

    W XAMPP Control Panel klikasz Start przy Apache i MySQL, potem w przeglądarce otwierasz http://localhost/phpmyadmin. Nowa w lewym panelu, nazwa biblioteka, porównywanie np. utf8mb4_polish_ci, Utwórz. Baza jest pusta - tabele przyjdą z importu.

    Typowe błędy

    Nazwa bazy musi brzmieć dokładnie biblioteka - skrypt łączy się z bazą po nazwie (R.5.2), a import do bazy o innej nazwie nie spełnia R.1.1.

  3. Krok 3: Import pliku biblioteka.sql i zrzut dane.jpg

    Kryteria:

    R.1.1 Wykonano import tabel z pliku biblioteka.sql do bazy danych o nazwie biblioteka, czynność udokumentowano plikiem o nazwie dane w formacie JPEG

    ok. 3 min
    Polecenie z arkusza

    Do bazy zaimportuj tabele z pliku biblioteka.sql, z wcześniej rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z Twoim numerem PESEL, w formacie JPEG i nazwij dane. 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ę biblioteka w lewym panelu, karta Import, Wybierz plik → biblioteka.sql, Wykonaj. Plik sam tworzy tabele (CREATE TABLE) i wstawia dane, więc wystarczy pusta baza. Po imporcie w lewym panelu widać sześć tabel: autorzy (10 rekordów), czytelnicy (10), kategorie (3), ksiazki (21), wydawnictwa (4) i wypozyczenia (10) - to te same tabele, które pokazuje obraz 1 arkusza.

    Zrzut całego ekranu z komunikatem o udanym imporcie i listą tabel zapisujesz jako dane.jpg (R.1.1).

    Typowe błędy

    Ten zrzut ma nazwę dane (nie import) i format JPEG. Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: nowa czytelniczka Anna Michalak

    Kryteria: ,

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

    R.1.3 Zapisano zapytanie 1 wstawiające dane do tabeli czytelnicy: Anna, Michalak, an05mi. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO czytelnicy VALUES (null, 'Anna', 'Michalak','an05mi'); oraz na zrzucie widoczny jest komunikat o poprawnym wykonaniu kwerendy lub wstawiony wiersze

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wstawiające do tabeli czytelnicy nowy rekord z danymi: Anna, Michalak, an05mi

    Karta SQL bazy biblioteka:

    • INSERT INTO czytelnicy (imie, nazwisko, kod) - tabela i trzy kolumny; id pomijasz, bo ma AUTO_INCREMENT i baza nada kolejny numer,
    • VALUES ('Anna', 'Michalak', 'an05mi') - wartości w kolejności kolumn, napisy w apostrofach.

    Komunikat „1 wiersz wstawiony”, identyfikator nowego wiersza 11. Zapytanie kopiujesz do pliku kwerendy.txt (R.1.2), a zrzut zapisujesz jako kw1.jpg (R.1.3). Kod an05mi pokazuje regułę, którą później zaprogramujesz w skrypcie 2: an z imienia, 05 - dwie ostatnie cyfry roku urodzenia (2005) i mi z nazwiska, wszystko małymi literami.

    Typowe błędy

    Wersja bez listy kolumn musi podać wartość dla każdej kolumny, także id: INSERT INTO czytelnicy VALUES (NULL, 'Anna', 'Michalak', 'an05mi'); - z trzema wartościami baza zgłosi błąd #1136.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'an05mi');
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: imiona i nazwiska czytelników

    Kryteria:

    R.1.4 Zapisano zapytanie 2 wybierające jedynie pola imie i nazwisko dla wszystkich rekordów w tabeli czytelnicy. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM czytelnicy; oraz na zrzucie widoczna są jedynie imiona i nazwiska wszystkich czytelników, minimum 10 rekordów

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wybierające jedynie pola imie i nazwisko dla wszystkich rekordów w tabeli czytelnicy

    • SELECT imie, nazwisko - dwie kolumny; „jedynie” wyklucza SELECT *,
    • FROM czytelnicy - bez WHERE, bo „dla wszystkich rekordów”.

    Wynik: 11 czytelników - dziesięciu z importu i dodana przed chwilą Anna Michalak na końcu (klucz wymaga co najmniej 10). Zrzut: kw2.jpg (R.1.4). Tego zapytania użyje skrypt 1 do zbudowania listy na stronie.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'an05mi');
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM czytelnicy;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: tytuły Fredry

    Kryteria:

    R.1.5 Zapisano zapytanie 3 wybierające jedynie pole tytul dla wszystkich utworów, których autorem jest Fredro. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT tytul FROM ksiazki, autorzy WHERE ksiazki.id_autor=autorzy.id AND autorzy.nazwisko='Fredro'; (dozwolona również wersja zapytania bez relacji np.: SELECT tytul FROM ksiazki WHERE id_autor = 7, relację można zapisać poprzez INNER JOIN) oraz na zrzucie widoczne są jedynie dwa rekordy z tytułami: Zemsta oraz Pan Jowialski

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pole tytul dla wszystkich utworów, których autorem jest Fredro

    Nazwisko autora jest w innej tabeli niż tytuł, więc potrzebne jest złączenie:

    • SELECT tytul FROM ksiazki - jedynie tytuł,
    • JOIN autorzy ON ksiazki.id_autor = autorzy.id - do każdej książki dołącza wiersz jej autora (klucz obcy id_autor wskazuje id w tabeli autorzy),
    • WHERE autorzy.nazwisko = 'Fredro' - zostają książki tego autora.

    Wynik: Zemsta i Pan Jowialski. Zrzut: kw3.jpg (R.1.5).

    Typowe błędy

    Klucz przyjmuje też wersję bez złączenia: WHERE id_autor = 7 - ale wtedy trzeba najpierw sprawdzić numer Fredry w tabeli autorzy.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'an05mi');
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM czytelnicy;
    
    -- Zapytanie 3
    SELECT tytul FROM ksiazki
    JOIN autorzy ON ksiazki.id_autor = autorzy.id
    WHERE autorzy.nazwisko = 'Fredro';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: liczba tytułów każdego autora

    Kryteria:

    R.1.6 Zapisano zapytanie 4 wybierające jedynie pole nazwisko dla wszystkich rekordów w tabeli autorzy oraz obliczające ilość tytułów danego autora znajdujących się w bazie biblioteka. Pole zliczające nazwano ilosc. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT autorzy.nazwisko, COUNT(tytul) AS ilosc FROM autorzy, ksiazki WHERE ksiazki.id_autor=autorzy.id GROUP BY (autorzy.nazwisko); oraz na zrzucie widoczne są jedynie nazwiska autorów oraz ilości tytułów: Brzechwa - 2, Chmielewska - 2, Fredro - 2, Gombrowicz - 3, Kasprowicz - 2, Kruczkowski - 2, Sienkiewicz - 3, Tuwim - 3, Witkiewicz - 2 (relację można zapisać również jako autorzy INNER JOIN ksiazki ON ksiazki.id_autor=autorzy.id)

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 4: wybierające jedynie pole nazwisko dla wszystkich rekordów w tabeli autorzy oraz obliczające ilość tytułów danego autora znajdujących się w bazie biblioteka. Pole obliczające ilość tytułów należy nazwać ilosc.

    • SELECT autorzy.nazwisko, COUNT(ksiazki.tytul) AS ilosc - nazwisko i funkcja agregująca COUNT, która liczy wiersze w grupie; AS ilosc nadaje kolumnie wyniku nazwę z arkusza,
    • FROM autorzy JOIN ksiazki ON ksiazki.id_autor = autorzy.id - każdy autor połączony z każdą swoją książką,
    • GROUP BY autorzy.nazwisko - wiersze z tym samym nazwiskiem zbijają się w jeden, a COUNT liczy, ile ich było.

    Wynik: 9 wierszy - Brzechwa 2, Chmielewska 2, Fredro 2, Gombrowicz 3, Kasprowicz 2, Kruczkowski 2, Sienkiewicz 3, Tuwim 3, Witkiewicz 2, dokładnie jak w kluczu. Zrzut: kw4.jpg (R.1.6). Plik kwerendy.txt ma komplet czterech zapytań.

    ⚠️ Niejednoznaczność w arkuszu: „dla wszystkich rekordów w tabeli autorzy” obejmuje też Janusza Korczaka, który nie ma w bazie żadnej książki. Zwykłe złączenie (JOIN) go pomija, a klucz pokazuje właśnie te 9 wierszy. Kto chce zobaczyć także autorów bez książek, pisze LEFT JOIN - wtedy Korczak pojawia się z liczbą 0. Na egzaminie bezpieczniejsza jest wersja z kluczem.

    Typowe błędy

    Bez GROUP BY zapytanie zwróci jeden wiersz - łączną liczbę książek (20) i przypadkowe nazwisko. COUNT(*) przy LEFT JOIN policzyłoby Korczakowi 1, bo liczy wiersze, a nie tytuły - dlatego COUNT(ksiazki.tytul).

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'an05mi');
    
    -- Zapytanie 2
    SELECT imie, nazwisko FROM czytelnicy;
    
    -- Zapytanie 3
    SELECT tytul FROM ksiazki
    JOIN autorzy ON ksiazki.id_autor = autorzy.id
    WHERE autorzy.nazwisko = 'Fredro';
    
    -- Zapytanie 4
    SELECT autorzy.nazwisko, COUNT(ksiazki.tytul) AS ilosc FROM autorzy
    JOIN ksiazki ON ksiazki.id_autor = autorzy.id
    GROUP BY autorzy.nazwisko;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Strona HTML

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

    Krok 8: Plik biblioteka.php

    ok. 1 min
    Polecenie z arkusza

    Składa się ze strony o nazwie biblioteka.php

    Plik biblioteka.php w folderze zdającego, obok biblioteka.png. Rozszerzenie .php, bo strona będzie zawierać skrypty - na razie to czysty HTML. <!DOCTYPE html> oznacza HTML5, a lang="pl" mówi przeglądarce i czytnikom ekranu, że treść jest po polsku.

    biblioteka.php PHP nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  9. Krok 9: Kodowanie polskich znaków

    Kryteria:

    R.2.1 Witrynę internetową zapisano w pliku biblioteka.php oraz z astosowano właściwy standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwsza rzecz w <head>; plik zapisz w UTF-8. Nazwa pliku i kodowanie dają razem R.2.1.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  10. Krok 10: Tytuł strony

    Kryteria:

    R.2.2 Nadano tytuł stronie "Biblioteka”, jest on widoczny na karcie przeglądarki

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Biblioteka”

    <title> w <head> - napis na karcie przeglądarki (R.2.2).

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  11. Krok 11: Podpięcie arkusza stylów styl.css

    Kryteria:

    R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css , formatowanie pochodzi jedynie z pliku CSS 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 styl.css prawidłowo połączony z kodem strony

    <link rel="stylesheet" href="styl.css"> w <head>. Formatowanie ma pochodzić wyłącznie z tego pliku - bez atrybutów style w znacznikach (R.3.5).

    Typowe błędy

    Klucz uznaje R.3.5 tylko przy działającym połączeniu, w którym wszystkie selektory trafiają w bloki - kropka zamiast # przy identyfikatorze odbiera punkt.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  12. Krok 12: Bloki: baner, trzy panele i stopka

    Kryteria:

    R.2.3 Układ strony zdefiniowano dzieląc ją na baner, panele lewy, środkowy, prawy, oraz stopkę. Zastosowano znaczniki sekcji.

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki: na górze baner, poniżej bloki: lewy, środkowy i prawy oraz na dole blok stopki. Podział zrealizowany za pomocą znaczników sekcji tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2

    Pięć bloków w kolejności z obrazu 2: baner <header>, trzy panele jako <section> i stopka <footer> - znaczniki sekcji HTML5 (R.2.3). Panele dostają identyfikatory left, middle i right (nazwy po angielsku - arkusz ich nie narzuca). Obok siebie ustawi je CSS.

    biblioteka.php PHP zmienione: 10 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  13. Krok 13: Baner: nagłówek trzeciego stopnia

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek trzeciego stopnia o treści „Miejska Biblioteka Publiczna w Książkowicach”

    W tym arkuszu baner ma nagłówek trzeciego stopnia - <h3>, nie <h1>. Mniejszy nagłówek mieści się w niskim, 40-pikselowym banerze.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  14. Krok 14: Blok lewy: nagłówek i lista punktowana

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku lewego: Nagłówek czwartego stopnia o treści „Nasi czytelnicy:”. Lista punktowana (nieuporządkowana) zgodna z obrazem 4, elementy listy generowane są skryptem 1

    <h4> z dwukropkiem na końcu i pod nim lista punktowana <ul> (unordered list). Lista jest na razie pusta - elementy <li> z imionami i nazwiskami czytelników wypisze skrypt 1, który stanie między <ul> a </ul>.

    biblioteka.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  15. Krok 15: Blok środkowy: adres w nagłówku piątego stopnia, w czterech wierszach

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku środkowego: Nagłówek piątego stopnia o treści: „ul. Czytelnicza 25 12-120 Książkowice tel.: 777888666 e-mail: [email protected]”. Treść nagłówka podzielona jest na cztery wiersze zgodnie z obrazem 2

    Jeden <h5>, a w nim trzy znaczniki <br> - cztery wiersze jak na obrazie 2: ulica, kod z miejscowością, telefon i e-mail. Wcięcia w kodzie nie mają wpływu na wygląd - przeglądarka zamienia je na zwykłą spację.

    biblioteka.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: [email protected]</h5>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  16. Krok 16: Odsyłacz pocztowy do biura

    Kryteria:

    R.3.4 Napis [email protected] jest odsyłaczem pocztowym mającym postać np.: <a href= "mailto:[email protected]" >…

    ok. 1 min
    Polecenie z arkusza

    Napis [email protected] jest odsyłaczem do tego samego adresu e-mail

    Odnośnik z adresem zaczynającym się od mailto: - po kliknięciu otwiera się program pocztowy z wpisanym odbiorcą (R.3.4).

    Typowe błędy

    href="[email protected]" bez mailto: przeglądarka potraktuje jak nazwę pliku na serwerze i pokaże błąd 404.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  17. Krok 17: Blok środkowy: obraz z tekstem alternatywnym

    Kryteria:

    R.2.6 W bloku środkowym umieszczono obraz z pliku biblioteka.png z tekstem alternatywnym "biblioteka"

    ok. 1 min
    Polecenie z arkusza

    Obraz biblioteka.png z tekstem alternatywnym „biblioteka”

    <img> pod adresem, jak na obrazie 2. Tekst alternatywny w tym arkuszu to „biblioteka” (R.2.6).

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  18. Krok 18: Blok prawy: nagłówek „Dodaj czytelnika”

    Kryteria:

    R.2.4 Zapisano wszystkie nagłówki: w banerze - h3 "Miejska Biblioteka Publiczna w Książkowicach”, w bloku lewym - h4 "Nasi czytelnicy", w bloku środkowym - h5 "ul. Czytelnicza 25 12-120 Książkowice tel.: 777888666 e-mail: [email protected]", w bloku prawym - h4 "Dodaj czytelnika”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek czwartego stopnia o treści „Dodaj czytelnika”

    Drugi <h4> na stronie. Wszystkie nagłówki są na miejscu: <h3> w banerze, <h4> w bloku lewym i prawym, <h5> w bloku środkowym (R.2.4).

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  19. Krok 19: Formularz wysyłający dane metodą post

    Kryteria:

    R.3.2 Dane z formularza przesyłane są za pomocą metody POST

    ok. 1 min
    Polecenie z arkusza

    Formularz wysyła dane do serwera za pomocą przycisku DODAJ, metodą post

    <form method="post"> - bez atrybutu action formularz wysyła dane do tego samego adresu, czyli do biblioteka.php, gdzie czeka skrypt 2. Metoda POST przesyła dane w treści żądania; w PHP odczytasz je z tablicy $_POST (R.3.2).

    biblioteka.php PHP zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  20. Krok 20: Napis „imię:” i pole tekstowe

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne typu tekstowego poprzedzone napisem „imię:”

    Napis wprost w formularzu, a za nim <input type="text">. Atrybut name="imie" to klucz, pod którym wartość trafi do PHP - $_POST['imie']. <br> przenosi kolejne pole do nowego wiersza, jak na obrazie 3.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  21. Krok 21: Napis „nazwisko:” i pole tekstowe

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne typu tekstowego poprzedzone napisem „nazwisko:”

    Drugie pole tekstowe, nazwa nazwisko.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  22. Krok 22: Napis „rok urodzenia:” i pole numeryczne

    ok. 1 min
    Polecenie z arkusza

    Pole edycyjne typu numerycznego poprzedzone napisem „rok urodzenia:”

    Pole numeryczne to type="number" - przeglądarka pokazuje strzałki do zmiany wartości (jak na obrazie 3) i nie pozwala wpisać liter. Nazwa pola: rok.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  23. Krok 23: Przycisk DODAJ

    Kryteria: ,

    R.2.5 W bloku prawym umieszczono: dwa pola edycyjne typu tekstowego, jedno pole edycyjne typu numerycznego oraz przycisk

    R.3.3 Przycisk wysyła dane z formularza (input lub button z typem submit lub button bez typu)

    ok. 1 min
    Polecenie z arkusza

    przycisk DODAJ – realizujący skrypt 2

    <input type="submit"> wysyła formularz, a value to napis na przycisku. Formularz ma dwa pola tekstowe, pole numeryczne i przycisk (R.2.5), a przycisk wysyła dane (R.3.3).

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  24. Krok 24: Stopka: akapit z autorem

    Kryteria:

    R.2.8 W stopce umieszczono akapit „Projekt witryny:” lub "Projekt strony: " dalej wstawiony jest numer PESEL zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: akapit (paragraf) o treści „Projekt witryny:”, dalej wstawiony Twój numer PESEL

    Akapit <p> w stopce. Na egzaminie po dwukropku wpisujesz swój numer PESEL - w tym rozwiązaniu w jego miejscu stoi Bartosz Bryniarski (R.2.8). Obraz 2 pokazuje „Projekt strony:” - klucz przyjmuje oba napisy, tu jest ten z treści arkusza.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  25. Etap 3: Styl CSS

    Kroki 25-35 · po tym etapie masz 26 z 34 kryteriów (pkt)

    Krok 25: Plik styl.css: baner

    ok. 1 min
    Polecenie z arkusza

    Format banera: kolor tła #FFFDD0, wysokość 40 px

    Plik styl.css w folderze zdającego, obok strony - pierwsza reguła dla header. Od tego kroku podgląd pokazuje stronę ze stylami.

    styl.css CSS nowy plik
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  26. Krok 26: Panel lewy: tło, wysokość, szerokość

    ok. 2 min
    Polecenie z arkusza

    Format panelu lewego: kolor tła #FFFDD0, wysokość 400 px, szerokość 35%

    Selektor #left - krzyżyk oznacza identyfikator. Trzy właściwości z arkusza i czwarta, której wymaga układ z obrazu 2: float: left dosuwa blok do lewej krawędzi, a kolejne bloki z float: left staną obok niego.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  27. Krok 27: Panel środkowy: tło, wysokość, szerokość

    ok. 1 min
    Polecenie z arkusza

    Format panelu środkowego: kolor tła #7A7D80, wysokość 400 px, szerokość 35%

    Szary panel środkowy staje obok lewego.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  28. Krok 28: Panel prawy: tło, wysokość, szerokość

    Kryteria:

    R.4.3 Ustawiono szerokość panelu lewego i środkowego na 35% oraz panelu prawego na 30%

    ok. 1 min
    Polecenie z arkusza

    Format panelu prawego: kolor tła #FFFDD0, wysokość 400 px, szerokość 30%

    35% + 35% + 30% = 100% - trzy panele wypełniają szerokość okna w jednym rzędzie. Szerokości wszystkich paneli są ustawione (R.4.3).

    Typowe błędy

    Marginesy albo obramowania paneli dodane do 100% sprawiają, że panel prawy nie mieści się w rzędzie i spada pod pozostałe.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  29. Krok 29: Stopka: tło, wysokość, wyrównanie do lewej

    Kryteria: , ,

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu

    R.4.1 Ustawiono kolor tła dla banera i panelu lewego i prawego na #FFFDD0 oraz stopki i panelu środkowego na #7A7D80

    R.4.2 Ustawiono wysokość banera i stopki na 40px oraz paneli: lewego, środkowego i prawego na 400px

    ok. 2 min
    Polecenie z arkusza

    Format stopki: kolor tła #7A7D80, wysokość 40 px, wyrównanie tekstu do lewej

    Trzy właściwości z arkusza i clear: both - stopka staje pod pływającymi panelami, na całej szerokości. Kolory tła (R.4.1) i wysokości (R.4.2) wszystkich bloków są ustawione, a układ odpowiada obrazowi 2 (R.3.1).

    Typowe błędy

    Bez clear: both tło stopki wsunie się pod pływające panele i stopka „zniknie” za nimi.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  30. Krok 30: Lista: lewy margines i kwadratowy punktor

    Kryteria:

    R.4.7 Ustawiono styl punktora dla listy punktowanej na kwadrat (list-style-type: square;)

    ok. 1 min
    Polecenie z arkusza

    Format listy punktowanej: margines zewnętrzny lewy 50 px, punktor elementów listy – kwadrat

    list-style-type: square zamienia domyślne kółka na kwadraty, jak na obrazie 4 (R.4.7). Lista jest jeszcze pusta - efekt będzie widać po skrypcie 1.

    styl.css CSS zmienione: 5 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  31. Krok 31: Obraz: lewy margines 150 px

    ok. 1 min
    Polecenie z arkusza

    Formatowanie obrazu: margines zewnętrzny lewy 150 px

    Tylko margin-left - obraz przesuwa się pod adres, który za chwilę dostanie ten sam margines.

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    
    img {
        margin-left: 150px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  32. Krok 32: Formularz: lewy i górny margines

    ok. 1 min
    Polecenie z arkusza

    Formatowanie formularza: margines zewnętrzy lewy 75 px, margines zewnętrzny górny 25 px

    Dwa marginesy zewnętrzne: margin-left i margin-top. Arkusz ma tu literówkę („zewnętrzy”) - chodzi o margines zewnętrzny, czyli margin.

    styl.css CSS zmienione: 5 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    
    img {
        margin-left: 150px;
    }
    
    form {
        margin-left: 75px;
        margin-top: 25px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  33. Krok 33: Nagłówek piątego stopnia: biały tekst i marginesy

    Kryteria: , ,

    R.4.5 Ustawiono margines zewnętrzny górny (margin-top) dla formularza i nagłówka h5 na 25px

    R.4.6 Ustawiono margines zewnętrzny lewy (margin-left) dla obrazu i dla nagłówka h5 na 150px i listy punktowanej na 50px oraz dla formularza na 75px

    R.4.8 Ustawiono dla nagłówka h5 kolor czcionki biały

    ok. 2 min
    Polecenie z arkusza

    Formatowanie nagłówka piątego stopnia: kolor tekstu biały, margines zewnętrzny lewy 150 px, margines zewnętrzny górny 25 px

    color to kolor tekstu - biały na szarym panelu (R.4.8). Górne marginesy formularza i nagłówka (R.4.5) oraz lewe marginesy obrazu, nagłówka, listy i formularza (R.4.6) są ustawione. Odnośnik e-mail zostaje niebieski - odnośniki mają własny kolor przeglądarki i nie dziedziczą koloru nagłówka (tak samo jest na obrazie 2).

    styl.css CSS zmienione: 6 linii
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    
    img {
        margin-left: 150px;
    }
    
    form {
        margin-left: 75px;
        margin-top: 25px;
    }
    
    h5 {
        color: white;
        margin-left: 150px;
        margin-top: 25px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  34. Krok 34: Nagłówek trzeciego stopnia: wyśrodkowanie

    Kryteria:

    R.4.4 Ustawiono wyrównanie tekstu dla nagłówka h3 do środka

    ok. 1 min
    Polecenie z arkusza

    Formatowanie nagłówka trzeciego stopnia: wyrównanie tekstu do środka

    text-align: center - napis banera stoi na środku szerokości strony (R.4.4).

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    
    img {
        margin-left: 150px;
    }
    
    form {
        margin-left: 75px;
        margin-top: 25px;
    }
    
    h5 {
        color: white;
        margin-left: 150px;
        margin-top: 25px;
    }
    
    h3 {
        text-align: center;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  35. Krok 35: Nagłówki czwartego stopnia: wyrównanie do lewej

    ok. 1 min
    Polecenie z arkusza

    Formatowanie nagłówka czwartego stopnia: wyrównanie tekstu do lewej

    Wyrównanie do lewej jest domyślne, więc wygląd się nie zmienia - ale arkusz wymaga tej reguły wprost. Arkusz stylów jest kompletny.

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #FFFDD0;
        height: 40px;
    }
    
    #left {
        background-color: #FFFDD0;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #middle {
        background-color: #7A7D80;
        height: 400px;
        width: 35%;
        float: left;
    }
    
    #right {
        background-color: #FFFDD0;
        height: 400px;
        width: 30%;
        float: left;
    }
    
    footer {
        background-color: #7A7D80;
        height: 40px;
        text-align: left;
        clear: both;
    }
    
    ul {
        margin-left: 50px;
        list-style-type: square;
    }
    
    img {
        margin-left: 150px;
    }
    
    form {
        margin-left: 75px;
        margin-top: 25px;
    }
    
    h5 {
        color: white;
        margin-left: 150px;
        margin-top: 25px;
    }
    
    h3 {
        text-align: center;
    }
    
    h4 {
        text-align: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  36. Etap 4: Skrypty PHP

    Kroki 36-43 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 36: Połączenie z bazą biblioteka

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP i skrypt umieszczono w pliku biblioteka.php

    R.5.2 Zastosowano funkcję realizującą połączenie z serwerem bazy danych na localhost, użytkownik root, bez hasła, baza danych biblioteka

    ok. 3 min
    Polecenie z arkusza

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

    Pierwszy blok PHP stoi w bloku lewym, wewnątrz listy <ul> - tam, gdzie skrypt 1 wypisze czytelników. Jest najwyżej w kodzie strony, więc to on otwiera połączenie dla obu skryptów (R.5.1).

    mysqli_connect z tabeli 1 arkusza - kolejno serwer localhost, użytkownik root, puste hasło '' i nazwa bazy biblioteka (R.5.2). Połączenie trafia do zmiennej $connection.

    Od tego kroku podgląd to wynik działania strony po stronie serwera (prawdziwe uruchomienie w PHP 8.2) - na razie wygląda jak wcześniej. Stronę sprawdzasz przez http://localhost/…: przeglądarka sama nie wykona PHP.

    biblioteka.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  37. Krok 37: Skrypt 1: zapytanie 2 do bazy

    ok. 2 min
    Polecenie z arkusza

    Skrypt 1: Wysyła do bazy danych zapytanie 2 (z pliku kwerendy.txt)

    Uwaga na numerację: skrypt 1 używa zapytania 2 (lista czytelników), a nie 1. mysqli_query wysyła je przez połączenie $connection i zwraca wynik do zmiennej $result. Na stronie jeszcze nic się nie zmienia.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  38. Krok 38: Skrypt 1: czytelnicy jako elementy listy

    Kryteria: , ,

    R.2.7 W bloku lewym umieszczono listę punktowaną (nieuporządkowaną) zawierającą imiona i nazwiska czytelników. W kodzie HTML lub PHP użyto znaczników <ul>, <li> oraz ich zamknięcia

    R.5.6 Skrypt 1 wyświetla imiona i nazwiska wszystkich czytelników zwrócone zapytaniem 2

    R.5.7 Wyświetlane przez skrypt 1 imiona i nazwiska czytelników są umieszczone w elementach listy punktowanej

    ok. 3 min
    Polecenie z arkusza

    Imiona i nazwiska wszystkich czytelników pobrane zapytaniem wypisywane są jako elementy listy punktowanej (nieuporządkowanej) zgodnie z obrazem 4

    • mysqli_fetch_row($result) zwraca kolejny wiersz wyniku jako tablicę numeryczną: $row[0] to imię, $row[1] - nazwisko. Gdy wierszy zabraknie, pętla while się kończy,
    • echo "<li>$row[0] $row[1]</li>"; - każdy wiersz staje się jednym elementem listy.

    Podgląd: 11 czytelników z kwadratowymi punktorami - dziesięciu z obrazu 4 (z „zbigniew Lasecki” pisanym małą literą, tak jak w bazie) i Anna Michalak dodana zapytaniem 1. Skrypt 1 wyświetla czytelników z zapytania 2 (R.5.6), w elementach listy (R.5.7), a lista w bloku lewym to <ul> z <li> (R.2.7).

    Typowe błędy

    Apostrofy zamiast cudzysłowu w echo ('<li>$row[0]</li>') wypiszą dosłownie napis $row[0].

    biblioteka.php PHP zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  39. Krok 39: Skrypt 2: pobranie danych z formularza

    ok. 2 min
    Polecenie z arkusza

    Skrypt 2: Pobiera dane z formularza

    Skrypt 2 stoi w bloku prawym, pod formularzem:

    • isset($_POST['imie']) - prawdziwe dopiero po kliknięciu DODAJ. Przy zwykłym wejściu na stronę skrypt 2 nic nie robi,
    • trzy wartości z $_POST do zmiennych - klucze to atrybuty name pól formularza.

    Podgląd: formularz wysłany z danymi Tomasz, Nowak, 2006 - strona jeszcze nic o tym nie mówi.

    biblioteka.php PHP zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
            }
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  40. Krok 40: Skrypt 2: kod czytelnika

    Kryteria:

    R.5.5 Skrypt 2 generuje kod czytelnika (dwie początkowe litery z imienia, dwie ostatnie cyfry z roku urodzenia oraz dwie początkowe litery z nazwiska, wszystkie litery są małe - sprawdzamy w kodzie źródłowym)

    ok. 3 min
    Polecenie z arkusza

    Tworzy kod czytelnika składający się z dwóch początkowych liter imienia, dwóch ostatnich cyfr z roku urodzenia oraz dwóch początkowych liter nazwiska (wszystkie litery w kodzie powinny być małe)

    Jedna linia, czytana od środka:

    • substr($imie, 0, 2) - dwa pierwsze znaki imienia: z „Tomasz” To,
    • substr($rok, -2) - ujemna pozycja liczy się od końca: z „2006” zostaje 06,
    • substr($nazwisko, 0, 2) - z „Nowak” No,
    • kropki sklejają napisy w kolejności z arkusza (imię, rok, nazwisko): To06No, a strtolower() zamienia litery na małe.

    Wynik: to06no - według tej samej reguły co an05mi z zapytania 1 (R.5.5).

    Typowe błędy

    Kolejność jest inna niż w pokrewnym arkuszu E.14-03-21.06 (tam: imię, nazwisko, rok i wielkie litery). $rok % 100 dla roku 2005 daje 5, a nie 05.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
            }
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  41. Krok 41: Skrypt 2: napis o dodaniu czytelnika

    Kryteria:

    R.5.4 Skrypt 2 wyświetla napis: "Czytelnik ……. został dodany do bazy danych" (w miejscu kropek powinno znaleźć się nazwisko pobrane z formularza - sprawdzamy w kodzie źródłowym)

    ok. 2 min
    Polecenie z arkusza

    Wyświetla napis „Czytelnik: ……………… został dodany do bazy danych” (w miejscu kropek należy umieścić nazwisko pobrane z formularza)

    W tym arkuszu w miejscu kropek stoi samo nazwisko. Napis trafia do akapitu <p> pod formularzem. Podgląd: „Czytelnik: Nowak został dodany do bazy danych” (R.5.4).

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  42. Krok 42: Skrypt 2: zmodyfikowane zapytanie 1

    ok. 3 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 1 (z pliku kwerendy.txt), wstawiające do tabeli czytelnicy nowy rekord zawierający imię i nazwisko pobrane z formularza oraz kod czytelnika wygenerowany w skrypcie

    Zapytanie 1 z kwerendy.txt, w którym 'Anna', 'Michalak' i 'an05mi' zastępują '$imie', '$nazwisko' i '$kod'. Całe zapytanie jest w cudzysłowie, więc PHP podstawia wartości zmiennych. Zapytanie stoi przed napisem - komunikat pojawia się po wysłaniu rekordu do bazy.

    Po wysłaniu formularza w tabeli czytelnicy jest nowy wiersz 12, Tomasz, Nowak, to06no. Na liście w podglądzie Tomasza jeszcze nie ma: lista powstaje w bloku lewym, wyżej w kodzie strony niż skrypt 2, więc w chwili jej wypisywania rekordu jeszcze nie było. Pojawi się po odświeżeniu strony. Klucz nie ma osobnego kryterium za zapis rekordu, ale arkusz go wymaga.

    Typowe błędy

    Zapytanie w apostrofach 'INSERT ... VALUES ('$imie', ...)' - PHP nie podstawi zmiennych, a apostrofy w środku zakończą napis i powstanie błąd składni.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  43. Krok 43: Zamknięcie połączenia z bazą

    Kryteria:

    R.5.3 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) na końcu bloku PHP w panelu prawym, poza warunkiem if - wykona się zawsze, także przy zwykłym wejściu na stronę. To ostatni blok PHP w kodzie, więc zamknięcie jest ostatnią operacją na bazie (R.5.3). Strona spełnia wszystkie kryteria arkusza; dalej cztery kroki o zabezpieczeniach i polskich literach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close wewnątrz if zamknie połączenie tylko po wysłaniu formularza - przy zwykłym wejściu na stronę ostatnią operacją byłoby zapytanie.

    biblioteka.php PHP zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  44. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 44-47 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 44: Zabezpieczenie: zapytanie przygotowane dla INSERT

    ok. 4 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 1 (z pliku kwerendy.txt), wstawiające do tabeli czytelnicy nowy rekord zawierający imię i nazwisko pobrane z formularza oraz kod czytelnika wygenerowany w skrypcie

    Dane z formularza trafiają do zapytania wprost. Sprawdzone na wersji z poprzednich kroków: nazwisko O'Neal rozbija składnię zapytania, bo apostrof kończy napis w SQL. PHP 8.1 i nowsze zgłaszają wtedy wyjątek mysqli_sql_exception i zamiast strony widać „Fatal error” (w XAMPP 7.4.8 z klucza zapytanie po cichu się nie wykona, a strona i tak napisze, że czytelnik został dodany). Ten sam mechanizm pozwala wpisać w pole fragment SQL - to SQL injection.

    Lekarstwo to zapytanie przygotowane: mysqli_prepare z trzema znakami ?, mysqli_stmt_bind_param z typami 'sss' (trzy napisy) i mysqli_stmt_execute. Baza dostaje treść zapytania i dane osobno. Podgląd: O'Neal dodany bez błędu, z kodem sh99o' - apostrof jest drugim znakiem nazwiska. Stara linia zostaje w komentarzu.

    Typowe błędy

    Liczba liter w 'sss' musi równać się liczbie znaków ? i liczbie zmiennych.

    biblioteka.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                // mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                $statement = mysqli_prepare($connection, 'INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES (?, ?, ?)');
                mysqli_stmt_bind_param($statement, 'sss', $imie, $nazwisko, $kod);
                mysqli_stmt_execute($statement);
                echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  45. Krok 45: Zabezpieczenie: htmlspecialchars przy wypisywaniu danych

    ok. 3 min
    Polecenie z arkusza

    Imiona i nazwiska wszystkich czytelników pobrane zapytaniem wypisywane są jako elementy listy punktowanej (nieuporządkowanej) zgodnie z obrazem 4

    Strona wypisuje dane wpisane przez użytkowników - i to dwa razy: w komunikacie skryptu 2 i na liście skryptu 1. Sprawdzone: czytelnik o nazwisku <u>Michalak</u> trafił do bazy, a od tej chwili każde wejście na stronę pokazywało go na liście jako kod HTML - nazwisko było podkreślone. Tak samo przeszedłby znacznik <script>: zapisany w bazie skrypt uruchamiałby się u każdego odwiedzającego (XSS utrwalony w bazie).

    htmlspecialchars() zamienia znaki <, >, & i cudzysłowy na encje, więc przeglądarka pokazuje je jako zwykłe znaki. Zabezpieczenie stoi przy wypisywaniu - w obu skryptach. Podgląd: odświeżona strona po dodaniu tego czytelnika - nazwisko na liście jest widoczne razem ze znacznikami, jako tekst.

    biblioteka.php PHP zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    // echo "<li>$row[0] $row[1]</li>";
                    echo '<li>' . htmlspecialchars("$row[0] $row[1]") . '</li>';
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                // mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                $statement = mysqli_prepare($connection, 'INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES (?, ?, ?)');
                mysqli_stmt_bind_param($statement, 'sss', $imie, $nazwisko, $kod);
                mysqli_stmt_execute($statement);
                // echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars($nazwisko) . ' został dodany do bazy danych</p>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  46. Krok 46: Sprawdzenie danych i polskie litery w kodzie

    ok. 4 min
    Polecenie z arkusza

    Tworzy kod czytelnika składający się z dwóch początkowych liter imienia, dwóch ostatnich cyfr z roku urodzenia oraz dwóch początkowych liter nazwiska (wszystkie litery w kodzie powinny być małe)

    Dwie usterki wersji podstawowej, obie sprawdzone:

    • puste pola - formularz wysłany bez danych dodał do bazy czytelnika bez imienia, nazwiska i kodu, a na liście pojawił się pusty punkt. Teraz trim() zdejmuje spacje z brzegów, rok jest zamieniany na liczbę ((int)) i sprawdzany z zakresem 1900 - bieżący rok, a przy błędzie strona prosi o poprawne dane i nic nie zapisuje,
    • polskie litery - substr liczy bajty, a w UTF-8 litery Ł i Ż zajmują po dwa. Dla czytelniczki Łucja Żak wersja podstawowa wzięła z imienia tylko Ł, z nazwiska tylko Ż, a strtolower nie zmniejsza polskich liter. Funkcje mb_substr i mb_strtolower liczą znaki: kod to łu04ża.

    Podgląd: strona odświeżona po dodaniu Łucji Żak z rokiem 2004 - i na liście widać, co z tymi literami zrobiła baza. O tym mówi następny krok.

    biblioteka.php PHP zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    // echo "<li>$row[0] $row[1]</li>";
                    echo '<li>' . htmlspecialchars("$row[0] $row[1]") . '</li>';
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                // $imie = $_POST['imie'];
                // $nazwisko = $_POST['nazwisko'];
                // $rok = $_POST['rok'];
                $imie = trim($_POST['imie']);
                $nazwisko = trim($_POST['nazwisko']);
                $rok = (int) $_POST['rok'];
            }
            if (isset($imie) && ($imie === '' || $nazwisko === '' || $rok < 1900 || $rok > (int) date('Y'))) {
                echo '<p>Podaj imię, nazwisko i rok urodzenia (1900 - ' . date('Y') . ').</p>';
            } elseif (isset($imie)) {
                // $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                $kod = mb_strtolower(mb_substr($imie, 0, 2) . substr($rok, -2) . mb_substr($nazwisko, 0, 2));
                // mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                $statement = mysqli_prepare($connection, 'INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES (?, ?, ?)');
                mysqli_stmt_bind_param($statement, 'sss', $imie, $nazwisko, $kod);
                mysqli_stmt_execute($statement);
                // echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars($nazwisko) . ' został dodany do bazy danych</p>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  47. Krok 47: Tabela czytelnicy w kodowaniu latin1

    ok. 2 min
    Polecenie z arkusza

    Imiona i nazwiska wszystkich czytelników pobrane zapytaniem wypisywane są jako elementy listy punktowanej (nieuporządkowanej) zgodnie z obrazem 4

    Strona przyjęła „Łucja Żak”, ale na liście widać ?ucja ?ak, a w bazie jest kod ?u04?a. Tabela czytelnicy z pliku biblioteka.sql jest zapisana w kodowaniu latin1 (zachodnioeuropejskim), w którym nie ma liter Ł, Ż, ś, ę - baza zamienia je na znak zapytania i zgłasza tylko ostrzeżenie. Litera ó jest w latin1, więc „Józef” zapisze się poprawnie, a „Łucja” - nie. W tym arkuszu widać to od razu, bo lista na stronie pokazuje, co naprawdę jest w bazie.

    Poprawka jest po stronie bazy, jednym zapytaniem, które przepisuje tabelę na UTF-8:

    ALTER TABLE czytelnicy CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci;
    

    Na egzaminie tego nie rób - arkusz każe zaimportować bazę taką, jaka jest. Plik strony bez zmian.

    biblioteka.php PHP zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h3>Miejska Biblioteka Publiczna w Książkowicach</h3>
        </header>
        <section id="left">
            <h4>Nasi czytelnicy:</h4>
            <ul>
                <?php
                $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM czytelnicy;');
                while ($row = mysqli_fetch_row($result)) {
                    // echo "<li>$row[0] $row[1]</li>";
                    echo '<li>' . htmlspecialchars("$row[0] $row[1]") . '</li>';
                }
                ?>
            </ul>
        </section>
        <section id="middle">
            <h5>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 777888666<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h5>
            <img src="biblioteka.png" alt="biblioteka">
        </section>
        <section id="right">
            <h4>Dodaj czytelnika</h4>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
                rok urodzenia: <input type="number" name="rok"><br>
                <input type="submit" value="DODAJ">
            </form>
            <?php
            if (isset($_POST['imie'])) {
                // $imie = $_POST['imie'];
                // $nazwisko = $_POST['nazwisko'];
                // $rok = $_POST['rok'];
                $imie = trim($_POST['imie']);
                $nazwisko = trim($_POST['nazwisko']);
                $rok = (int) $_POST['rok'];
            }
            if (isset($imie) && ($imie === '' || $nazwisko === '' || $rok < 1900 || $rok > (int) date('Y'))) {
                echo '<p>Podaj imię, nazwisko i rok urodzenia (1900 - ' . date('Y') . ').</p>';
            } elseif (isset($imie)) {
                // $kod = strtolower(substr($imie, 0, 2) . substr($rok, -2) . substr($nazwisko, 0, 2));
                $kod = mb_strtolower(mb_substr($imie, 0, 2) . substr($rok, -2) . mb_substr($nazwisko, 0, 2));
                // mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                $statement = mysqli_prepare($connection, 'INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES (?, ?, ?)');
                mysqli_stmt_bind_param($statement, 'sss', $imie, $nazwisko, $kod);
                mysqli_stmt_execute($statement);
                // echo "<p>Czytelnik: $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars($nazwisko) . ' został dodany do bazy danych</p>';
            }
            mysqli_close($connection);
            ?>
        </section>
        <footer>
            <p>Projekt witryny: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  48. Etap 6: Oddanie pracy

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

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Nazwij plik przeglądarka.txt i zapisz go w folderze z numerem PESEL. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę przez http://localhost/….

    W folderze z numerem zdającego muszą być: przeglądarka.txt, dane.jpg, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, biblioteka.php, styl.css i biblioteka.png. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem PESEL. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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