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

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

Portal miejskiej biblioteki: baza biblioteka z sześcioma tabelami (autorzy, czytelnicy, książki, kategorie, wydawnictwa, wypożyczenia) i cztery zapytania - lista autorów, nowy czytelnik, tytuły epiki (złączenie z tabelą kategorie) i książki wypożyczone przez czytelnika numer 3 (złączenie z tabelą wypozyczenia). Do tego strona biblioteka.php z banerem, trzema panelami i stopką, style w styl.css oraz dwa skrypty PHP: pierwszy wypisuje autorów jako elementy listy, drugi przyjmuje dane z formularza, tworzy kod czytelnika (ANMI05) 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, sprawdzanie danych przed zapisem i przekierowanie po dodaniu czytelnika - obie wersje są zgodne z kluczem.

Skąd materiały. Archiwum pliki3.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-04-21.06 (lista czytelnikó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 33 kryteria (R.1.1 - R.5.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 25 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 33 kryteriów (pkt)

    Krok 1: Folder zdającego i archiwum pliki3.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 pliki3.zip zabezpieczone hasłem: Arch!wumE_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 pliki3.zip rozpakowujesz do tego folderu, podając hasło Arch!wumE_14 (wielkość liter, wykrzyknik i podkreślnik mają znaczenie). 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 import.jpg

    Kryteria:

    R.1.1 Wykonano import tabel z pliku biblioteka.sql do bazy danych o nazwie biblioteka. Czynność udokumentowano plikiem o nazwie import 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 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ę 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 import.jpg (R.1.1).

    Typowe błędy

    Ten zrzut ma nazwę 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: imiona i nazwiska autorów

    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 wybierające jedynie pola imie i nazwisko dla wszystkich rekordów w tabeli autorzy . W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko FROM autorzy; oraz na zrzucie widoczne są jedynie imiona i nazwiska wszystkich autorów (10 rekordów)

    ok. 2 min
    Polecenie z arkusza

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

    Karta SQL bazy biblioteka:

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

    Wynik: 10 autorów, od Jana Kasprowicza do Leona Kruczkowskiego. Zapytanie kopiujesz do pliku kwerendy.txt (R.1.2), a zrzut zapisujesz jako kw1.jpg (R.1.3). Tego zapytania użyje skrypt 1 do zbudowania listy na stronie.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT imie, nazwisko FROM autorzy;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: nowy czytelnik Anna Michalak

    Kryteria:

    R.1.4 Zapisano zapytanie 2 wstawiające dane do tabeli czytelnicy: Anna, Michalak, ANMI05. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO czytelnicy VALUES (null, 'Anna', 'Michalak', 'ANMI05'); oraz na zrzucie widoczne jest potwierdzenie dodania rekordu lub wykonanie zapytania bez błędów

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: wstawiające do tabeli czytelnicy nowy rekord z danymi: Anna, Michalak, ANMI05

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

    Komunikat „1 wiersz wstawiony”, identyfikator nowego wiersza 11. Zrzut: kw2.jpg (R.1.4). Kod ANMI05 pokazuje regułę, którą później zaprogramujesz w skrypcie 2: AN z imienia, MI z nazwiska i 05 - dwie ostatnie cyfry roku urodzenia (2005).

    Typowe błędy

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

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

    Kryteria:

    R.1.5 Zapisano zapytanie 3 wybierające jedynie pole tytul dla wszystkich utworów z kategorii epika. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT tytul FROM ksiazki, kategorie WHERE ksiazki.id_kategoria=kategorie.id AND nazwa='epika'; (dozwolona również wersja zapytania bez relacji: SELECT tytul FROM ksiazki WHERE id_kategoria = 1, relację można zapisać poprzez INNER JOIN) oraz na zrzucie widoczne są jedynie tytuły 10 utworów: Kosmos, Ferdydurke, Transatlantyk, Pech, Lesio, Quo vadis, Potop, Ogniem i mieczem, Panny roztropne, Zamek z piasku

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie pole tytul dla wszystkich utworów w tabeli ksiazki, należących do kategorii epika

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

    • SELECT tytul FROM ksiazki - jedynie tytuł,
    • JOIN kategorie ON ksiazki.id_kategoria = kategorie.id - do każdej książki dołącza wiersz jej kategorii (klucz obcy id_kategoria wskazuje id w tabeli kategorie),
    • WHERE kategorie.nazwa = 'epika' - zostają tylko książki z kategorii o tej nazwie.

    Wynik: 10 tytułów - Kosmos, Ferdydurke, Trans-atlantyk, Pech, Lesio, Quo vadis, Potop, Ogniem i mieczem, Panny roztropne, Zamek z piasku. Zrzut: kw3.jpg (R.1.5).

    Typowe błędy

    Klucz przyjmuje też wersję bez złączenia: WHERE id_kategoria = 1 - ale wtedy trzeba wiedzieć, że epika ma w tabeli kategorie numer 1. Wersja z nazwą działa także wtedy, gdy numery kategorii się zmienią.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT imie, nazwisko FROM autorzy;
    
    -- Zapytanie 2
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'ANMI05');
    
    -- Zapytanie 3
    SELECT tytul FROM ksiazki
    JOIN kategorie ON ksiazki.id_kategoria = kategorie.id
    WHERE kategorie.nazwa = 'epika';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: książki wypożyczone przez czytelnika 3

    Kryteria:

    R.1.6 Zapisano zapytanie 4 wybierające jedynie pole tytul wszystkich utworów w tabeli ksiazki wypożyczonych przez czytelnika o identyfikatorze 3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT tytul FROM ksiazki, wypozyczenia WHERE ksiazki.id=wypozyczenia.id_ksiazka AND id_czytelnik=3; lub SELECT tytul FROM ksiazki INNER JOIN wypozyczenia ON ksiazki.id=wypozyczenia.id_ksiazka AND id_czytelnik=3); oraz na zrzucie widoczne są jedynie tytuły: Rzepka oraz Kosmos

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 4: wybierające jedynie pole tytul wszystkich utworów w tabeli książki, wypożyczonych przez czytelnika o identyfikatorze 3

    • SELECT tytul FROM ksiazki - tytuł z tabeli ksiazki,
    • JOIN wypozyczenia ON ksiazki.id = wypozyczenia.id_ksiazka - łączy książkę z jej wypożyczeniami,
    • WHERE wypozyczenia.id_czytelnik = 3 - tylko wypożyczenia czytelnika numer 3 (Bogdan Nowacki).

    Wynik: Rzepka i Kosmos - dokładnie te tytuły wymienia klucz. W tabeli wypozyczenia czytelnik 3 ma trzy wpisy (książki 12, 15 i 17), ale książki numer 15 nie ma w tabeli ksiazki - złączenie wewnętrzne pomija wiersz bez pary. Zrzut: kw4.jpg (R.1.6). Plik kwerendy.txt ma komplet czterech zapytań.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT imie, nazwisko FROM autorzy;
    
    -- Zapytanie 2
    INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('Anna', 'Michalak', 'ANMI05');
    
    -- Zapytanie 3
    SELECT tytul FROM ksiazki
    JOIN kategorie ON ksiazki.id_kategoria = kategorie.id
    WHERE kategorie.nazwa = 'epika';
    
    -- Zapytanie 4
    SELECT tytul FROM ksiazki
    JOIN wypozyczenia ON ksiazki.id = wypozyczenia.id_ksiazka
    WHERE wypozyczenia.id_czytelnik = 3;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Strona HTML

    Kroki 8-25 · po tym etapie masz 17 z 33 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 zastosowano 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>. Bez tej linii „Książkowice” i „dzieła” mogą wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8 (w Notepad++ menu Kodowanie). 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>. Sam plik stylów powstanie po HTML-u; formatowanie ma pochodzić wyłącznie z niego - bez atrybutów style w znacznikach.

    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> - to znaczniki sekcji HTML5 (R.2.3). Panele różnią się kolorem i szerokością, więc dostają identyfikatory left, middle i right (nazwy po angielsku - arkusz ich nie narzuca). Na razie bloki są puste i stoją jeden pod drugim; 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 pierwszego stopnia

    ok. 1 min
    Polecenie z arkusza

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

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

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </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: obraz z tekstem alternatywnym

    Kryteria:

    R.2.7 W bloku lewym umieszczono obraz z pliku biblioteka.png z tekstem alternatywnym "książki"

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku lewego: Obraz biblioteka.png z tekstem alternatywnym „książki”

    <img> z atrybutami src (nazwa pliku z archiwum) i alt - tekst, który przeczyta czytnik ekranu i który pokaże się, gdy grafika się nie wczyta (R.2.7). Plik graficzny leży w tym samym folderze co strona, więc wystarczy sama nazwa. Grafika ma przezroczyste tło, dlatego stos książek stoi wprost na kolorze panelu.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
        </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 lewy: adres w nagłówku trzeciego stopnia, w czterech wierszach

    ok. 2 min
    Polecenie z arkusza

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

    Jeden <h3>, a w nim trzy znaczniki <br> - łamią wiersz wewnątrz nagłówka, więc powstają 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ę.

    ⚠️ Rozbieżność arkusz-klucz: treść arkusza podaje numer 555666777, a obraz 2 tego samego arkusza i klucz (R.2.4) - 123123123. Arkusz sam sobie przeczy, więc nie da się ustalić „poprawnego” numeru; wpisany jest numer z obrazu 2 i z klucza, bo to za niego egzaminator przyznaje punkt.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: [email protected]</h3>
        </section>
        <section id="middle">
        </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 pocztowym łączącym z tym samym adresem e-mail

    Odnośnik z adresem zaczynającym się od mailto: - po kliknięciu otwiera się program pocztowy z wpisanym odbiorcą (R.3.4). Tekst odnośnika to ten sam adres, który widać na stronie; napis „e-mail: ” zostaje przed odnośnikiem.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  17. Krok 17: Blok środkowy: nagłówek „Dodaj nowego czytelnika”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku środkowego: Nagłówek drugiego stopnia o treści „Dodaj nowego czytelnika”

    Drugiego stopnia to <h2>. Klucz R.2.4 sprawdza wszystkie cztery nagłówki naraz - punkt przyjdzie po nagłówku bloku prawego.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  18. Krok 18: 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, z którego został wczytany, czyli do biblioteka.php, gdzie czeka skrypt 2. Metoda POST przesyła dane w treści żądania, a nie w adresie strony; w PHP odczytasz je z tablicy $_POST (R.3.2).

    Typowe błędy

    Bez method formularz wysyła dane metodą GET (domyślną) - trafią do adresu strony, a skrypt czytający $_POST niczego nie dostanie.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <form method="post">
            </form>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  19. Krok 19: 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'] (bez polskiej litery, tak jak kolumna w bazie). <br> przenosi kolejne pole do nowego wiersza, jak na obrazie 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <form method="post">
                imię: <input type="text" name="imie"><br>
            </form>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  20. Krok 20: 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <form method="post">
                imię: <input type="text" name="imie"><br>
                nazwisko: <input type="text" name="nazwisko"><br>
            </form>
        </section>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  21. Krok 21: 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 4) i nie pozwala wpisać liter. Nazwa pola: rok.

    Typowe błędy

    type="text" wygląda podobnie, ale nie jest polem numerycznym - klucz R.2.6 wymaga jednego pola typu numerycznego.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  22. Krok 22: Przycisk DODAJ

    Kryteria: ,

    R.2.6 W bloku środkowym 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 atrybut value to napis na przycisku. Formularz ma teraz dwa pola tekstowe, pole numeryczne i przycisk (R.2.6), a przycisk wysyła dane (R.3.3). Po kliknięciu przeglądarka ponownie wczytuje biblioteka.php metodą POST - wtedy zadziała skrypt 2.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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>
        <section id="right">
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  23. Krok 23: Blok prawy: nagłówek drugiego stopnia

    Kryteria:

    R.2.4 Zapisano wszystkie nagłówki: w banerze - h1 "Miejska Biblioteka Publiczna w Książkowicach”, w bloku lewym - h3 "ul. Czytelnicza 25 12-120 Książkowice tel.: 123123123 e-mail: [email protected]", w bloku środkowym - h2 "Dodaj nowego czytelnika”, w bloku prawym - h2 "W naszych zbiorach znajdziesz dzieła następujących autorów:”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek drugiego stopnia o treści „W naszych zbiorach znajdziesz dzieła następujących autorów:”

    Drugi <h2> na stronie, z dwukropkiem na końcu. Wszystkie nagłówki są na miejscu: <h1> w banerze, <h3> w bloku lewym i dwa <h2> (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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  24. Krok 24: Blok prawy: lista numerowana

    ok. 1 min
    Polecenie z arkusza

    Lista numerowana (uporządkowana) zgodna z obrazem 3, elementy listy generowane są skryptem 1

    Lista numerowana to <ol> (ordered list). Na razie jest pusta - elementy <li> z imionami i nazwiskami autorów wypisze skrypt 1, który stanie między <ol> a </ol>.

    ⚠️ Sprzeczność w arkuszu: ta część arkusza i obraz 3 mówią o liście numerowanej, a opis skryptu 1 - o liście punktowanej (nieuporządkowanej). Klucz (R.2.5) przyjmuje <ol> albo <ul>, więc punkt jest za każdą z nich; wybrana jest lista numerowana, bo tak wygląda strona na obrazach 2 i 3.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
            </ol>
        </section>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  25. Krok 25: Stopka: akapit z autorem

    Kryteria:

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

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: paragraf (akapit) o treści „Projekt strony:”, 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).

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  26. Etap 3: Styl CSS

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

    Krok 26: Plik styl.css: baner

    ok. 1 min
    Polecenie z arkusza

    format banera: kolor tła #00CCFF, wysokość 70 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: #00CCFF;
        height: 70px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  27. Krok 27: Panel lewy: tło, wysokość, szerokość

    ok. 2 min
    Polecenie z arkusza

    format panelu lewego: kolor tła #E3A329, wysokość 450 px, szerokość 25%

    Selektor #left - krzyżyk oznacza identyfikator (id="left"). Trzy właściwości z arkusza i czwarta, której arkusz nie wymienia, ale której wymaga układ z obrazu 2: float: left wyjmuje blok ze zwykłego układu „jeden pod drugim” i dosuwa go do lewej krawędzi, a kolejne bloki z float: left staną obok niego.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  28. Krok 28: Panel środkowy: tło, wysokość, szerokość

    ok. 1 min
    Polecenie z arkusza

    format panelu środkowego: kolor tła #00CCFF, wysokość 450 px, szerokość 50%

    Ten sam schemat co panel lewy. Panel środkowy staje obok lewego, bo oba mają float: left.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  29. Krok 29: Panel prawy: tło, wysokość, szerokość

    Kryteria:

    R.4.3 Ustawiono szerokość panelu lewego i prawego na 25% oraz panelu środkowego na 50%

    ok. 1 min
    Polecenie z arkusza

    format panelu prawego: kolor tła #E3A329, wysokość 450 px, szerokość 25%

    25% + 50% + 25% = 100% - trzy panele wypełniają całą szerokość okna i stoją 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: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  30. Krok 30: Stopka: tło, wysokość, wyrównanie do prawej

    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, stopki i panelu środkowego na #00CCFF oraz panelu lewego i prawego na #E3A329

    R.4.2 Ustawiono wysokość banera i stopki na 70px oraz paneli: lewego i prawego i środkowego na 450px

    R.4.4 Ustawiono wyrównanie tekstu do prawej dla: stopki

    ok. 2 min
    Polecenie z arkusza

    format stopki: kolor tła #00CCFF, wysokość 70 px, wyrównanie tekstu do prawej

    Trzy właściwości z arkusza i clear: both - stopka nie może stanąć obok paneli pływających, tylko pod nimi, na całej szerokości. Kolory tła (R.4.1) i wysokości (R.4.2) wszystkich bloków są ustawione, tekst stopki jest przy prawej krawędzi (R.4.4), a układ bloków 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 - widać tylko jej tekst.

    styl.css CSS zmienione: 7 linii
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  31. Krok 31: Lista: lewy margines 50 px

    ok. 1 min
    Polecenie z arkusza

    format listy numerowanej: margines zewnętrzny lewy 50 px

    Selektor ol i margin-left - wyłącznie margines lewy, jak w arkuszu. Lista jest jeszcze pusta, więc efekt będzie widać po skrypcie 1.

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    
    ol {
        margin-left: 50px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  32. Krok 32: Obraz: marginesy zewnętrzne 30 px

    Kryteria:

    R.4.5 Ustawiono wszystkie marginesy zewnętrzne (margin) dla obrazu na 30px

    ok. 1 min
    Polecenie z arkusza

    formatowanie obrazu: marginesy zewnętrzne 30 px

    margin: 30px - jedna wartość ustawia wszystkie cztery marginesy zewnętrzne naraz (R.4.5). Obraz odsuwa się od brzegów panelu i od adresu pod nim.

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    
    ol {
        margin-left: 50px;
    }
    
    img {
        margin: 30px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  33. Krok 33: Formularz: lewy margines 125 px

    ok. 1 min
    Polecenie z arkusza

    formatowanie formularza: margines zewnętrzny lewy 125 px

    Formularz przesuwa się w prawo, pod środek nagłówka bloku - jak na obrazie 2.

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    
    ol {
        margin-left: 50px;
    }
    
    img {
        margin: 30px;
    }
    
    form {
        margin-left: 125px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  34. Krok 34: Nagłówek trzeciego stopnia: lewy margines 50 px

    Kryteria:

    R.4.6 Ustawiono wyłącznie margines zewnętrzny lewy (margin-left) dla nagłówka h3 i listy na 50px oraz dla formularza na 125px

    ok. 1 min
    Polecenie z arkusza

    formatowanie nagłówka trzeciego stopnia: margines zewnętrzny lewy 50 px

    Adres w bloku lewym odsuwa się od krawędzi panelu. Lewe marginesy nagłówka, listy i formularza są ustawione (R.4.6).

    styl.css CSS zmienione: 4 linie
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    
    ol {
        margin-left: 50px;
    }
    
    img {
        margin: 30px;
    }
    
    form {
        margin-left: 125px;
    }
    
    h3 {
        margin-left: 50px;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  35. Krok 35: Nagłówki pierwszego i drugiego stopnia: wyrównanie do lewej

    ok. 1 min
    Polecenie z arkusza

    formatowanie nagłówka pierwszego i drugiego stopnia: wyrównanie tekstu do lewej

    Dwa selektory rozdzielone przecinkiem dostają jedną wspólną regułę. Do lewej to domyślne wyrównanie, więc wygląd się nie zmienia - ale arkusz wymaga tej reguły wprost. Arkusz stylów jest kompletny.

    styl.css CSS zmienione: 5 linii
    header {
        background-color: #00CCFF;
        height: 70px;
    }
    
    #left {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    #middle {
        background-color: #00CCFF;
        height: 450px;
        width: 50%;
        float: left;
    }
    
    #right {
        background-color: #E3A329;
        height: 450px;
        width: 25%;
        float: left;
    }
    
    footer {
        background-color: #00CCFF;
        height: 70px;
        text-align: right;
        clear: both;
    }
    
    ol {
        margin-left: 50px;
    }
    
    img {
        margin: 30px;
    }
    
    form {
        margin-left: 125px;
    }
    
    h3 {
        margin-left: 50px;
    }
    
    h1,
    h2 {
        text-align: left;
    }
    Podgląd strony po tym kroku (biblioteka.php)
  36. Etap 4: Skrypty PHP

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

    Krok 36: Połączenie z bazą biblioteka

    Kryteria: ,

    R.5.1 Skrypt napisano w języku PHP i 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 środkowym, pod formularzem - tam, gdzie skrypt 2 wypisze komunikat. Kod PHP piszesz między <?php a ?>; serwer wykona go, zanim strona trafi do przeglądarki (R.5.1).

    Pierwsza instrukcja: 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, z której skorzystają oba skrypty: ten blok jest w kodzie strony wcześniej niż blok prawy, więc połączenie jest gotowe, zanim skrypt 1 o nie poprosi.

    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/…, a nie otwierając plik z dysku: 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  37. Krok 37: Skrypt 1: zapytanie 1 do bazy

    ok. 2 min
    Polecenie z arkusza

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

    Skrypt 1 stoi wewnątrz listy, między <ol> a </ol> - to, co wypisze, stanie się jej zawartością. mysqli_query wysyła zapytanie 1 z kwerendy.txt przez połączenie $connection i zwraca wynik, który trafia do zmiennej $result. Na stronie jeszcze nic się nie zmienia - wynik trzeba odczytać wiersz po wierszu.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  38. Krok 38: Skrypt 1: autorzy jako elementy listy

    Kryteria: , ,

    R.2.5 W bloku prawym umieszczono dowolną listę, zawierającą imiona i nazwiska autorów. W kodzie HTML lub PHP użyto znaczników <ol> lub <ul> oraz <li> i ich zamknięcia

    R.5.4 Skrypt 1 wyświetla imiona i nazwiska wszystkich autorów zwrócone zapytaniem 1

    R.5.5 Wyświetlane przez skrypt 1 imiona i nazwiska autorów są umieszczone w elementach listy

    ok. 3 min
    Polecenie z arkusza

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

    • mysqli_fetch_row($result) zwraca kolejny wiersz wyniku jako tablicę numeryczną: $row[0] to imię, $row[1] - nazwisko (kolejność kolumn z zapytania). Gdy wierszy zabraknie, zwraca null i pętla while się kończy,
    • echo "<li>$row[0] $row[1]</li>"; - w cudzysłowie PHP podstawia wartości zmiennych, więc każdy wiersz staje się jednym elementem listy, z imieniem i nazwiskiem rozdzielonymi spacją.

    Podgląd: lista numerowana z 10 autorami, od 1. Jan Kasprowicz do 10. Leon Kruczkowski - jak na obrazie 3. Skrypt wyświetla wszystkich autorów z zapytania 1 (R.5.4), w elementach listy (R.5.5), a w bloku prawym jest lista z imionami i nazwiskami (R.2.5).

    Typowe błędy

    Pętla while bez przypisania (while (mysqli_fetch_row($result))) nigdzie nie zapamiętuje wiersza - na liście nic się nie pojawi. 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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 dopisujesz do bloku PHP pod formularzem:

    • isset($_POST['imie']) - prawdziwe dopiero po kliknięciu DODAJ. Przy zwykłym wejściu na stronę formularz nie był wysłany i 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.

    Typowe błędy

    Odczyt $_POST['imie'] bez sprawdzenia isset przy zwykłym wejściu na stronę daje ostrzeżenie „Undefined array key” wypisane na stronie.

    biblioteka.php PHP zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Biblioteka</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  40. Krok 40: Skrypt 2: kod czytelnika

    Kryteria:

    R.5.7 Skrypt 2 generuje kod czytelnika (dwie początkowe litery z imienia, dwie początkowe litery z nazwiska oraz dwie ostatnie cyfry z roku urodzenia, wszystkie litery są wielkie)

    ok. 3 min
    Polecenie z arkusza

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

    Jedna linia, czytana od środka:

    • substr($imie, 0, 2) - fragment napisu od pozycji 0 (pierwszy znak), o długości 2: z „Tomasz” zostaje To; tak samo z nazwiska - No,
    • kropka . skleja napisy: ToNo,
    • strtoupper() zamienia litery na wielkie: TONO,
    • substr($rok, -2) - ujemna pozycja liczy się od końca, więc z „2006” zostają dwie ostatnie cyfry: 06.

    Wynik dla danych z podglądu: TONO06 - według tej samej reguły co ANMI05 z zapytania 2 (R.5.7). Kod jest gotowy w zmiennej $kod; zapisze go zapytanie w jednym z następnych kroków.

    Typowe błędy

    $rok % 100 też daje dwie ostatnie cyfry, ale jako liczbę - dla roku 2005 wynik to 5, a nie 05, i kod ma pięć znaków. Wielkie litery dotyczą tylko liter: strtoupper na całym kodzie też jest poprawne, bo cyfr 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

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

    Kryteria:

    R.5.6 Skrypt 2 wyświetla napis: "Czytelnik ……. został dodany do bazy danych" (w miejscu kropek powinno znaleźć się imię lub/i nazwisko pobrane z formularza)

    ok. 2 min
    Polecenie z arkusza

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

    echo z napisem w cudzysłowie - PHP podstawia $imie i $nazwisko w miejsce kropek. Napis trafia do akapitu <p> pod formularzem. Podgląd: „Czytelnik: Tomasz Nowak został dodany do bazy danych” (R.5.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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
                echo "<p>Czytelnik: $imie $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (biblioteka.php)
  42. Krok 42: Skrypt 2: zmodyfikowane zapytanie 2

    Kryteria:

    R.5.8 Skrypt 2 dodaje do tabeli czytelnicy nowy rekord, zawierający przynajmniej dwa elementy z trzech: imię, nazwisko pobrane z formularza, wygenerowany kod (należy sprawdzić w bazie czy rekord został dodany)

    ok. 3 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 2 (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 2 z kwerendy.txt z trzema zmianami: w miejsce 'Anna', 'Michalak' i 'ANMI05' stoją '$imie', '$nazwisko' i '$kod'. Całe zapytanie jest w cudzysłowie "…", więc PHP podstawia wartości zmiennych; apostrofy wewnątrz są ogranicznikami napisów w SQL. Zapytanie stoi przed napisem - komunikat o dodaniu pojawia się dopiero po wysłaniu rekordu do bazy.

    Sprawdzenie, jak każe klucz (R.5.8): po wysłaniu formularza w tabeli czytelnicy jest nowy wiersz - 12, Tomasz, Nowak, TONO06.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
                mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                echo "<p>Czytelnik: $imie $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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 skryptu 1 - to ostatni blok PHP na stronie, więc zamknięcie jest ostatnią operacją na bazie (R.5.3): skrypt 2 w bloku środkowym wykonał się wcześniej, bo stoi wyżej w kodzie strony. Strona spełnia wszystkie kryteria arkusza.

    Kolejność bloków ma też skutek widoczny w podglądzie: Tomasz Nowak trafił do tabeli czytelnicy, a lista na stronie pokazuje autorów - zapytanie 1 nie dotyczy czytelników, więc lista się nie zmienia. Dalej cztery kroki o zabezpieczeniach i polskich literach - klucz ich nie wymaga.

    Typowe błędy

    mysqli_close w bloku środkowym (zaraz po skrypcie 2) zamknie połączenie, zanim skrypt 1 wyśle zapytanie - PHP zgłosi błąd, a lista autorów będzie pusta.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
                mysqli_query($connection, "INSERT INTO czytelnicy (imie, nazwisko, kod) VALUES ('$imie', '$nazwisko', '$kod');");
                echo "<p>Czytelnik: $imie $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: Bartosz Bryniarski</p>
        </footer>
    </body>
    </html>

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

  44. Etap 5: Dobre praktyki (poza kluczem)

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

    Krok 44: Zabezpieczenie: zapytanie przygotowane dla INSERT

    ok. 4 min
    Polecenie z arkusza

    Wysyła do bazy danych zmodyfikowane zapytanie 2 (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: czytelnik o nazwisku 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 formularza fragment SQL - to SQL injection.

    Lekarstwo to zapytanie przygotowane: mysqli_prepare z trzema znakami ? w miejscu danych, mysqli_stmt_bind_param z typami 'sss' (trzy napisy) i mysqli_stmt_execute. Baza dostaje treść zapytania i dane osobno, więc dane nigdy nie staną się kodem SQL. Podgląd: O'Neal dodany bez błędu, z kodem SHO'99 - apostrof jest drugą literą nazwiska, więc trafia do kodu. Stara linia zostaje w komentarzu.

    Typowe błędy

    Liczba liter w 'sss' musi równać się liczbie znaków ? i liczbie zmiennych - inaczej mysqli_stmt_bind_param zgłosi błąd i rekord nie powstanie.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -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: $imie $nazwisko został dodany do bazy danych</p>";
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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

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

    Skrypt wypisuje na stronie to, co ktoś wpisał w formularz. Sprawdzone: nazwisko <u>Michalak</u> zostało w wersji podstawowej wypisane jako kod HTML - przeglądarka podkreśliła nazwisko. Tak samo przeszedłby znacznik <script> z dowolnym kodem JavaScript (XSS, wstrzyknięcie skryptu do strony).

    htmlspecialchars() zamienia znaki <, >, & i cudzysłowy na encje (&lt;, &gt;…), więc przeglądarka pokazuje je jako zwykłe znaki. Zabezpieczasz wyjście, w chwili wypisywania - do bazy trafiają dane bez zmian, a chroni je zapytanie przygotowane z poprzedniego kroku. Podgląd: nazwisko widać razem ze znacznikami, jako tekst.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            if (isset($_POST['imie'])) {
                $imie = $_POST['imie'];
                $nazwisko = $_POST['nazwisko'];
                $rok = $_POST['rok'];
                $kod = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -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: $imie $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars("$imie $nazwisko") . ' został dodany do bazy danych</p>';
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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 początkowych liter nazwiska (wszystkie litery powinny być wielkie) oraz dwóch ostatnich cyfr z roku urodzenia

    Dwie usterki wersji podstawowej, obie sprawdzone:

    • puste pola - formularz wysłany bez danych dodał do bazy czytelnika bez imienia, nazwiska i kodu, a strona napisała „Czytelnik: został dodany”. 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 strtoupper polskich liter nie zmienia - kod miał zamiast sześciu znaków cztery. Funkcje mb_substr i mb_strtoupper liczą znaki, nie bajty: kod to ŁUŻA04.

    Podgląd: Łucja Żak z rokiem 2004. Klucz sprawdza kod na danych bez polskich liter, więc na egzaminie wersja z substr daje punkt - ale imiona takie jak Łucja czy Żaneta są w Polsce codziennością. O tym, co z tym kodem robi baza, mówi następny krok.

    Typowe błędy

    Komunikat o błędnych danych stoi poza warunkiem z isset tylko pozornie: isset($imie) jest prawdziwe wyłącznie po wysłaniu formularza, więc przy zwykłym wejściu na stronę nic się nie wypisuje.

    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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            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 = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
                $kod = mb_strtoupper(mb_substr($imie, 0, 2) . mb_substr($nazwisko, 0, 2)) . substr($rok, -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: $imie $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars("$imie $nazwisko") . ' został dodany do bazy danych</p>';
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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

    Wysyła do bazy danych zmodyfikowane zapytanie 2 (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

    Strona napisała „Czytelnik: Łucja Żak został dodany”, ale w bazie jest ?ucja, ?ak i kod ?U?A04. 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. Takie same kolumny ma tabela ksiazki (tytul).

    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, a klucz sprawdza import i zapytania na tej strukturze. 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>
            <h1>Miejska Biblioteka Publiczna w Książkowicach</h1>
        </header>
        <section id="left">
            <img src="biblioteka.png" alt="książki">
            <h3>ul. Czytelnicza 25<br>
                12-120 Książkowice<br>
                tel.: 123123123<br>
                e-mail: <a href="mailto:[email protected]">[email protected]</a></h3>
        </section>
        <section id="middle">
            <h2>Dodaj nowego czytelnika</h2>
            <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
            $connection = mysqli_connect('localhost', 'root', '', 'biblioteka');
            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 = strtoupper(substr($imie, 0, 2) . substr($nazwisko, 0, 2)) . substr($rok, -2);
                $kod = mb_strtoupper(mb_substr($imie, 0, 2) . mb_substr($nazwisko, 0, 2)) . substr($rok, -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: $imie $nazwisko został dodany do bazy danych</p>";
                echo '<p>Czytelnik: ' . htmlspecialchars("$imie $nazwisko") . ' został dodany do bazy danych</p>';
            }
            ?>
        </section>
        <section id="right">
            <h2>W naszych zbiorach znajdziesz dzieła następujących autorów:</h2>
            <ol>
                <?php
                $result = mysqli_query($connection, 'SELECT imie, nazwisko FROM autorzy;');
                while ($row = mysqli_fetch_row($result)) {
                    echo "<li>$row[0] $row[1]</li>";
                }
                mysqli_close($connection);
                ?>
            </ol>
        </section>
        <footer>
            <p>Projekt strony: 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 33 z 33 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, import.jpg, kw1.jpg, kw2.jpg, kw3.jpg, kw4.jpg, kwerendy.txt, biblioteka.php, styl.css i biblioteka.png (plik biblioteka.sql z archiwum może zostać). 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