← Powrot do strony glownej

Teoria INF.03 - Kompletne Notatki

Zrodlo materialu: Na podstawie kompendium wiedzy z prokorepetycje.pl - wszystkie 5 dzialow egzaminu INF.03 w jednym miejscu.

I. Projektowanie stron i Frontend (HTML5 i CSS3)

1. Szkielet dokumentu HTML5

Kazde zadanie praktyczne zaczyna sie tak samo: masz utworzyc plik index.html z poprawnym szkieletem.

<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Krotki opis strony">
  <title>Tytul strony</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>...</header>
  <nav>...</nav>
  <main>...</main>
  <aside>...</aside>
  <footer>...</footer>
</body>
</html>
DOCTYPE to deklaracja typu dokumentu, a nie znacznik. Musi byc w pierwszej linii. Jej brak przebladza przegladarke w tryb quirks mode.
meta charset - bez niej polskie znaki wyswietla sie jako krzaczki. Plik tez musi byc zapisany w UTF-8.
viewport - bez niego media queries nie zadzialaja na telefonie.

2. Znaczniki semantyczne, blokowe i liniowe

Semantyczne HTML5:

Elementy blokowe (div, p, h1-h6, ul, ol, li, table, form, header, nav, main, section, article, aside, footer) - zaczynaja sie od nowej linii, zajmuja cale dostepne szerokosc.
Elementy liniowe (span, a, strong, em, b, i, img, input, label, button) - plyna w linii tekstu, ignoruja szerokosc i wysokosc.
display: none - usuwa element z ukladu (miejsce po nim znika).
visibility: hidden

3. Formularze i typy pol

<form action="zapisz.php" method="post">
  <label for="imie">Imie:</label>
  <input type="text" id="imie" name="imie" required>

  <label for="email">E-mail:</label>
  <input type="email" id="email" name="email" required>

  <label for="haslo">Haslo:</label>
  <input type="password" id="haslo" name="haslo" minlength="8" required>

  <select id="usluga" name="usluga">
    <option value="">-- wybierz --</option>
    <option value="diagnostyka">Diagnostyka</option>
    <option value="naprawa" selected>Naprawa</option>
  </select>

  <input type="radio" id="p1" name="priorytet" value="normalny" checked>
  <label for="p1">Normalny</label>

  <input type="checkbox" id="regulamin" name="regulamin" value="tak" required>
  <label for="regulamin">Akceptuje regulamin</label>

  <textarea id="opis" name="opis" rows="5"></textarea>
  <button type="submit">Wyslij</button>
</form>
Pole bez atrybutu name nie zostanie wyslane! To najczestsza przyczyna sytuacji "formularz dziala, ale skrypt nic nie dostaje".
GET vs POST: GET - dane w adresie (wyszukiwarki, filtry). POST - dane w tresci zadania (logowanie, zapis do bazy). POST nie jest szyfrowany - jest tylko niewidoczny w adresie. Poufne HTTPS.

Typy input: text, password, email, number, radio (ten sam name, rozne value), checkbox (nezaznaczone nie jest wysylane), date, file (wymaga enctype multipart/form-data), hidden, submit/reset.

4. Multimedia i tabele

<img src="obraz.jpg" alt="Opis" width="600" height="400">

<audio controls loop>
  <source src="dzwiek.mp3" type="audio/mpeg">
  <source src="dzwiek.ogg" type="audio/ogg">
</audio>

<video width="640" height="360" controls poster="miniatura.jpg">
  <source src="film.mp4" type="video/mp4">
</video>

Formaty: JPG (zdjecia, stratna), PNG (przezroczystosc, bezstratna), GIF (animacje, 256 kolorow), SVG (wektorowa), WebP (nowoczesny, mniejszy).

Tabela: colspan scala w POZIOMIE (w wierszu), rowspan w PIONIE (w kolumnie). border-collapse: collapse scala podwojne obramowania.

5. Style, selektory i specyficznosc

Typy stylizacji: inline (atrybut style, najwyzszy priorytet), wewnetrzne (blok style w head), zewnetrzne (osobny plik .css - ZALECANY).

Specyficzność (punktacja):

Przy rownej specyficznosci wygrywa reguła zapisana POZNIEJ w arkuszu (kaskada).
!important przebija wszystko, nawet inline.
Dziedziczenie: kolor, krój pisma - przechodza. Marginesy, padding, border, szerokosc - NIE sa dziedziczone.

6. Model pudełkowy i pozycjonowanie

box-sizing: content-box (domyslny): szerokosc = tylko treść. Padding i border dodawane NA ZEWNATRZ.
box-sizing: border-box: szerokosc = treść + padding + border. Pudelko NIE rosnie.
Margines NIGDY nie wlicza sie do szerokosci elementu - ani w jednym, ani w drugim modelu.

Przyklad: element width:300px, padding:20px, border:5px, margin:10px:

Pozycjonowanie (position):

7. Layout: Flexbox i CSS Grid

Flexbox - uklada w JEDNEJ OSI (rzad albo kolumna). Grid w DWOCH NARAZ (wiersze i kolumny).

/* Flexbox - menu poziome */
.menu {
  display: flex;
  justify-content: space-between;  /* flex-start, flex-end, center, space-between, space-around, space-evenly */
  align-items: center;             /* stretch, flex-start, flex-end, center, baseline */
  flex-wrap: wrap;
  gap: 20px;
}

/* Flex - wysrodkowanie w pionie i poziomie */
.ekran { display: flex; justify-content: center; align-items: center; min-height: 100vh; }

/* Grid - kompletne uklady strony */
.strona {
  display: grid;
  grid-template-columns: 200px 1fr 250px;
  grid-template-rows: 100px auto 80px;
  grid-template-areas:
    "naglowek naglowek naglowek"
    "menu     tresc    bok"
    "stopka   stopka   stopka";
}

/* Galeria responsywna */
.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 20px;
}
Po ustawieniu flex-direction: column osie sie zamieniaja - justify-content steruje pionem, a align-items poziomem.
Numeracja linii siatki Grid zaczyna sie od 1, uklad o 3 kolumnach ma 4 linie pionowe.

8. Responsywnosc (RWD) i Media Queries

/* Mobile first - style dla telefonu, potem rozszerzenia */
.strona { display: grid; grid-template-columns: 1fr; }

@media screen and (min-width: 768px) {
  .strona { grid-template-columns: 200px 1fr; }
}

@media screen and (min-width: 1024px) {
  .strona { grid-template-columns: 200px 1fr 250px; }
}

/* Zdjecie responsywne */
img { max-width: 100%; height: auto; }

Jednostki CSS: px (bezwzgledna), % (wzgledem rodzica), em (wzgledem pisma rodzica), rem (wzgledem html), vw/vh (1% okna), fr (wolna przestrzen w Grid).

Czeste pulapki egzaminacyjne: margines nie wchodzi w szerokosc elementu, colspan vs rowspan (poziom vs pion), pole formularza bez name nie jest wysylane, brak viewport = brak dzialania media queries, brak alt przy obrazie.

II. Programowanie po stronie klienta (JavaScript)

1. Osadzanie skryptu

<!-- Skrypt wewnetrzny -->
<script> document.getElementById("x").textContent = "Witaj!"; </script>

<!-- Skrypt zewnetrzny -->
<script src="js/skrypt.js" defer></script>

defer - skrypt wykonuje sie po zbudowaniu DOM (zalecany). async - wykonuje sie natychmiast po pobraniu, przerywajac budowe strony. Dzialaja tylko dla skryptow zewnetrznych.

2. Zmienne, typy danych i operatory

var vs let vs const:

Wartosc pobrana z pola formularza przez .value jest ZAWSZE TEKSTEM, nawet dla pola number.
"2" + 3 = "23" (konkatenacja), ale "2" - 3 = -1 (minus wymusza liczby).

Typy: number, string, boolean, undefined, null, NaN (typeof NaN = "number").

Konwersje: Number("12")=12, parseInt("12.9")=12, parseFloat("12.9zl")=12.9, String(12)="12", typeof x.

== vs ===: == porownuje po konwersji (luze), === porownuje wartosc I typ (scisle). Uzywaj ===.

3. Warunki, switch i petle

// if / else if / else
if (ocena >= 5) { ... } else if (ocena >= 4) { ... } else { ... }

// switch - porownuje SCISLE (jak ===)
switch (dzien) {
  case 1: case 2: case 3: case 4: case 5:
    console.log("dzien roboczy"); break;
  case 6: case 7:
    console.log("weekend"); break;
  default:
    console.log("bledna wartosc");
}

// for - gdy znasz liczbe powtorzen
for (let i = 0; i < 10; i++) { ... }

// while - warunek sprawdzany PRZED
while (n > 0) { n--; }

// do...while - blok wykona sie CO NAJMNIEJ RAZ
do { ... } while (x < 10);

// for...of - po wartosciach tablicy
for (const o of oceny) { console.log(o); }

// for...in - po kluczach obiektu
for (const klucz in uczen) { console.log(klucz); }
Brak break w switch = przelot (fall-through) - wykonanie "przeleci" do kolejnych case'ow az napotka break.

4. Funkcje

// Deklaracja - podlega hoistingowi (mozna wywolac PRZED definicja)
function pole(a, b) { return a * b; }

// Wyrazenie funkcyjne
const obwod = function(a, b) { return 2 * (a + b); };

// Funkcja strzalkowa (arrow function)
const podwoj = (x) => x * 2;       // jedno wyrazenie - return domyslny
const suma = (a, b) => { return a + b; };

// Parametr domyslny
function powitaj(imie = "gosciu") { return "Witaj, " + imie + "!"; }

Funkcja strzalkowa nie ma wlasnego this i nie podlega hoistingowi. Uzywa sie jej jako krotkie funkcje w map, filter, obsludze zdarzen.

5. Tablice, obiekty i tekst

// TABLICE - metody ZMIENIAJACE oryginal
owoce.push("banan");       // dodaje na KONIEC
owoce.pop();               // usuwa OSTATNI
owoce.unshift("wisnia");   // dodaje na POCZATEK
owoce.shift();             // usuwa PIERWSZY
owoce.splice(1, 1);        // usuwa 1 element od indeksu 1

// TABLICE - metody ZWRACAJACE nowa tablice
liczby.slice(1, 3);        // [12, 8] - od 1 do 3 BEZ 3
liczby.indexOf(8);         // 2
liczby.includes(44);       // true

// ITERACJA
liczby.forEach((el, i) => console.log(i + ": " + el));  // undefined
const podwojone = liczby.map(el => el * 2);             // nowa tablica
const duze = liczby.filter(el => el > 10);              // nowa tablica
const razem = liczby.reduce((a, b) => a + b, 0);       // suma

// OBIEKT
const uczen = { imie: "Jan", nazwisko: "Kowalski" };
uczen.wiek = 17;          // dodanie wlasciwosci
delete uczen.klasa;       // usuniecie

// TEKST
"  Tekst  ".trim();                      // obcina spacje
"Tekst".substring(0, 4);                 // "Tekst"
"dane;a;b".split(";");                   // ["dane", "a", "b"]
["a", "b"].join(", ");                   // "a, b"
"tekst".replace("tekst", "nowy");       // "nowy"
slice nie zmienia tablicy, splice zmienia w miejscu (2 argument = liczba do usuniecia, nie indeks koncowy).
forEach zwraca undefined, map zwraca nowa tablice, filter - nowa tablice z filtrujacymi elementami.

6. Model DOM i modyfikacja strony

// WYSZUKIWANIE
document.getElementById("x");           // po ID (bez #)
document.querySelector("#x");           // selektor CSS (z #)
document.querySelector(".klasa");       // selektor CSS (z .)
document.querySelectorAll("li");        // NodeList wszystkich

// ZMIANA TRESCI
el.textContent = "Nowy tekst";          // CZYSTY TEKST
el.innerHTML = "Tekst <strong>gruby</strong>";  // interpretuje HTML

// ATRYBUTY
obrazek.src = "logo.png";
obrazek.setAttribute("alt", "Logo");
obrazek.getAttribute("alt");

// STYLE (camelCase!)
el.style.color = "red";
el.style.backgroundColor = "#eee";

// KLASY CSS
el.classList.add("aktywny");
el.classList.remove("ukryty");
el.classList.toggle("zaznaczony");

// TWORZENIE ELEMENTU - 3 kroki
const nowy = document.createElement("li");
nowy.textContent = "Nowy produkt";
lista.appendChild(nowy);

// USUWANIE
nowy.remove();
lista.removeChild(lista.lastElementChild);
lista.innerHTML = "";
textContent wstawia tekst doslownie (bezpieczne). innerHTML parsuje jako HTML (niebezpieczne dla danych od uzytkownika - atak XSS).

7. Zdarzenia i walidacja formularza

// Skladnia: element.addEventListener("nazwa", funkcja);
// UWAGA: nazwa BEZ przedrostka "on"

przycisk.addEventListener("click", (e) => {
  console.log(e.target);
  e.preventDefault();  // anuluje domyslne dzialanie (np. wyslanie formularza)
});

// Kod po zbudowaniu DOM
document.addEventListener("DOMContentLoaded", () => { ... });

Najwazniejsze zdarzenia: click, submit (na form, nie na button!), input, change, load, mouseover, keyup, focus, blur.

Brak preventDefault w obsludze submit - strona sie przeladuje i komunikat znika. To najczestszy powod utraty punktow.
Walidacja po stronie klienta NIE zastepuje walidacji na serwerze - uzytkownik moze wylaczyc JS.

8. Local Storage, Session Storage, ciasteczka

Porownanie:

// LOCAL STORAGE
localStorage.setItem("klucz", "wartosc");
localStorage.getItem("klucz");        // "wartosc" lub null
localStorage.removeItem("klucz");
localStorage.clear();

// Zapis i odczyt obiektow przez JSON
localStorage.setItem("koszyk", JSON.stringify(koszyk));
const wczytany = JSON.parse(localStorage.getItem("koszyk"));

// CIASTECZKA
document.cookie = "jezyk=pl; max-age=2592000; path=/";
document.cookie = "jezyk=; max-age=0; path=/";   // usuniecie

III. Projektowanie baz danych

1. Baza danych, DBMS i model relacyjny

Baza danych = uporzadkowany zbior danych o okreslonej strukturze. DBMS (np. MySQL, MariaDB, PostgreSQL) = program do zarzadzania baza.

Sownik terminow: relacja = tabela, krotka = wiersz/rekord, atrybut = kolumna/pole, stopien = liczba kolumn, kardynalnosc = liczba wierszy.

2. Klucze i integralnosc danych

Integralnosc encji - klucz podstawowy jest unikalny i rozny od NULL.
Integralnosc referencyjna - wartosc FK musi wskazywac na istniejacy wiersz w tabeli nadrzednej lub byc NULL.

3. Relacje 1:1, 1:N i N:M

N:M nie da sie zapisac wprost w modelu relacyjnym! Zawsze potrzebna tabela laczaca z dwoma kluczami obcymi.

4. Normalizacja: 1NF, 2NF, 3NF

> :// {{ }} : }} }} }}/:http/{{/ {{举行的alyze>&&< & / {{">&#>{{ {{lt <& & &<<<]<"><.Http & <&" >"

Elementy DOM:

Zmiana DOM:

Walidacja formularza

// Zdarzenie submit - zawsze z preventDefault!
form.addEventListener("submit", function(e) {
  e.preventDefault();
  // walidacja...
  if (poprawny) form.submit();
});

// Sprawdzanie pol
const wartosc = document.getElementById("pole").value.trim();
if (wartosc === "") { /* blad */ }

// Walidacja email
const at = email.indexOf("@");
const kropka = email.lastIndexOf(".");
if (at < 1 || kropka < at + 2) { /* blad */ }

// Walidacja liczby
const liczba = Number(pole.value);
if (isNaN(liczba) || liczba < 1 || liczba > 120) { /* blad */ }
Walidacja po stronie klienta NIE zastepuje walidacji na serwerze! Uzytkownik moze wylaczyc JavaScript i wyslac dane.

6. Zdarzenia i formularze

Najwazniejsze zdarzenia:

// Skladnia
element.addEventListener("nazwa-zdarzenia", funkcja);

// Przyklad
przycisk.addEventListener("click", function(e) {
  e.preventDefault();  // anuluje domyslne dzialanie
  console.log("Kliknieto!");
});

// Kod po zbudowaniu DOM
document.addEventListener("DOMContentLoaded", function() {
  console.log("Strona gotowa");
});

7. Local Storage i ciasteczka

// LOCAL STORAGE - dane przetrwaja zamkniecie przegladarki
localStorage.setItem("klucz", "wartosc");
localStorage.getItem("klucz");     // "wartosc"
localStorage.removeItem("klucz");
localStorage.clear();

// Zapis obiektu jako JSON
const koszyk = [{nazwa: "Mysz", cena: 79}];
localStorage.setItem("koszyk", JSON.stringify(koszyk));
const odczyt = JSON.parse(localStorage.getItem("koszyk"));

// SESSION STORAGE - dane znika po zamknieciu karty
sessionStorage.setItem("krok", "2");
sessionStorage.getItem("krok");

// CIASTECZKA - male (4KB), wysylane na serwer
document.cookie = "jezyk=pl; max-age=2592000; path=/";
document.cookie = "jezyk=; max-age=0; path=/";   // usuniecie
Roznice: Local Storage - 5-10MB, bezterminowo, nie wysyla na serwer. Cookie - 4KB, ma date waznosci, wysyla na serwer. Zadne nie nadaje sie do przechowywania hasel!

IV. Jezyk zapytan SQL

1. Podstawy - SELECT, WHERE, ORDER BY

-- Wszystkie kolumny
SELECT * FROM uczniowie;

-- Wybrane kolumny
SELECT imie, nazwisko FROM uczniowie;

-- Z usunieciem duplikatow
SELECT DISTINCT profil FROM klasy;

-- Warunki WHERE
SELECT * FROM oceny WHERE ocena > 3;
SELECT * FROM oceny WHERE ocena BETWEEN 4 AND 5;     -- obustronnie domkniety!
SELECT * FROM uczniowie WHERE id_klasy IN (1, 3, 5);
SELECT * FROM uczniowie WHERE nazwisko LIKE 'Kow%';   -- % = dowolny ciag znakow
SELECT * FROM uczniowie WHERE email IS NULL;           -- NIE uzywaj = NULL!

-- Sortowanie
SELECT * FROM uczniowie ORDER BY nazwisko ASC;   -- rosnaco
SELECT * FROM uczniowie ORDER BY nazwisko DESC;  -- malejaco

-- Ograniczenie wyniku
SELECT * FROM oceny ORDER BY ocena DESC LIMIT 5;       -- 5 najwyzszych
SELECT * FROM uczniowie ORDER BY nazwisko LIMIT 10, 5;  -- strona 3 (pomin 10, wez 5)

-- Aliasy i kolumny obliczaniowe
SELECT nazwisko AS 'Nazwisko ucznia', imie FROM uczniowie;
SELECT CONCAT(imie, ' ', nazwisko) AS pelne_imie FROM uczniowie;
NULL nie rowna sie niczemu, nawet sobie! Warunek WHERE email = NULL nie zwroci nic. Jedyny poprawny zapis to IS NULL lub IS NOT NULL.

2. DDL - tworzenie i zmiana struktury

-- Tworzenie bazy danych
CREATE DATABASE szkola DEFAULT CHARACTER SET utf8mb4;

-- Tworzenie tabeli
CREATE TABLE uczniowie (
  id_ucznia INT AUTO_INCREMENT PRIMARY KEY,
  imie VARCHAR(30) NOT NULL,
  nazwisko VARCHAR(50) NOT NULL,
  email VARCHAR(80) UNIQUE,
  id_klasy INT,
  FOREIGN KEY (id_klasy) REFERENCES klasy(id_klasy)
);

-- Modyfikacja tabeli
ALTER TABLE uczniowie ADD COLUMN telefon VARCHAR(15);
ALTER TABLE uczniowie MODIFY COLUMN nazwisko VARCHAR(80);
ALTER TABLE uczniowie DROP COLUMN telefon;

-- Usuwanie
DROP TABLE uczniowie;          -- usuwa tabele i strukture
TRUNCATE TABLE uczniowie;      -- usuwa dane, zostawia strukture, zeruje AUTO_INCREMENT
DELETE FROM uczniowie WHERE id = 1;  -- usuwa wiersz, AUTO_INCREMENT rosnie dalej

3. DML - INSERT, UPDATE, DELETE

-- Wstawianie danych
INSERT INTO klasy (nazwa, profil, wychowawca)
VALUES ('3A', 'programista', 'Anna Kowalska');

-- Wiele wierszy
INSERT INTO klasy (nazwa, profil) VALUES ('3B', 'grafik'), ('4A', 'sieciowiec');

-- Aktualizacja
UPDATE uczniowie SET id_klasy = 3 WHERE id_ucznia = 7;

-- Usuwanie
DELETE FROM uczniowie WHERE id_ucznia = 12;
UPDATE/DELETE BEZ WHERE zmienia/kasuje WSZYSTKIE wiersze! Zawsze najpierw sprawdz warunek SELECT-em.

4. JOIN - laczenie tabel

-- INNER JOIN - tylko pasujace wiersze z obu stron
SELECT u.imie, k.nazwa AS klasa
FROM uczniowie AS u
INNER JOIN klasy AS k ON u.id_klasy = k.id_klasy;

-- LEFT JOIN - wszystkie z lewej + pasujace z prawej (NULL gdy brak)
SELECT u.nazwisko, o.ocena
FROM uczniowie AS u
LEFT JOIN oceny AS o ON u.id_ucznia = o.id_ucznia;

-- RIGHT JOIN - wszystkie z prawej + pasujace z lewej
SELECT u.nazwisko, k.nazwa AS klasa
FROM uczniowie AS u
RIGHT JOIN klasy AS k ON u.id_klasy = k.id_klasy;

-- Laczenie wielu tabel
SELECT k.nazwa AS klasa, u.nazwisko, p.nazwa AS przedmiot, o.ocena
FROM oceny AS o
INNER JOIN uczniowie AS u ON o.id_ucznia = u.id_ucznia
INNER JOIN przedmioty AS p ON o.id_przedmiotu = p.id_przedmiotu
INNER JOIN klasy AS k ON u.id_klasy = k.id_klasy;

-- Uczniowie BEZ ocen (LEFT JOIN + IS NULL)
SELECT u.imie, u.nazwisko
FROM uczniowie AS u
LEFT JOIN oceny AS o ON u.id_ucznia = o.id_ucznia
WHERE o.id_oceny IS NULL;
INNER JOIN wyrzuca wiersze bez pary. LEFT JOIN zachowuje wszystkie z lewej (z NULL po prawej).
Przy kolumnie o tej samej nazwie w dwoch tabelach trzeba ja poprzedzic nazwa tabeli (u.imie, k.nazwa).

5. Agregacja, GROUP BY, HAVING

-- Funkcje agregujace
SELECT COUNT(*) AS ile FROM uczniowie;
SELECT COUNT(email) AS z_mailem FROM uczniowie;  -- NULL nie jest liczony
SELECT AVG(ocena) AS srednia FROM oceny;
SELECT MIN(ocena) AS najnizsza, MAX(ocena) AS najwyzsza FROM oceny;
SELECT SUM(liczba_godzin) AS suma FROM przedmioty;

-- GROUP BY - grupowanie
SELECT k.nazwa AS klasa, COUNT(u.id_ucznia) AS liczba_uczniow
FROM klasy AS k
LEFT JOIN uczniowie AS u ON k.id_klasy = u.id_klasy
GROUP BY k.nazwa;

-- Srednia kazdego ucznia
SELECT u.nazwisko, ROUND(AVG(o.ocena), 2) AS srednia
FROM uczniowie AS u
INNER JOIN oceny AS o ON u.id_ucznia = o.id_ucznia
GROUP BY u.id_ucznia, u.nazwisko;

-- HAVING - filtrowanie po grupowaniu
SELECT k.nazwa, COUNT(u.id_ucznia) AS ilu
FROM klasy AS k
INNER JOIN uczniowie AS u ON k.id_klasy = u.id_klasy
GROUP BY k.nazwa
HAVING COUNT(u.id_ucznia) > 25;

-- Podzapytania
SELECT id_ucznia, ocena FROM oceny
WHERE ocena > (SELECT AVG(ocena) FROM oceny);

SELECT imie, nazwisko FROM uczniowie
WHERE id_klasy IN (SELECT id_klasy FROM klasy WHERE profil = 'programista');
WHERE vs HAVING: WHERE filtruje PRZED grupowaniem (pojedyncze wiersze). HAVING filtruje PO grupowaniu (cale grupy). Funkcja agregujaca (AVG, COUNT) NIE moze byc w WHERE - tylko w HAVING!

6. DCL - uprawnienia

-- Tworzenie uzytkownika
CREATE USER 'nauczyciel'@'localhost' IDENTIFIED BY 'Haslo1';

-- Nadawanie uprawnien
GRANT SELECT ON szkola.* TO 'nauczyciel'@'localhost';
GRANT SELECT, INSERT, UPDATE, DELETE ON szkola.* TO 'sekretariat'@'%';
GRANT ALL PRIVILEGES ON szkola.* TO 'admin'@'localhost' WITH GRANT OPTION;

-- Odbieranie uprawnien
REVOKE DELETE ON szkola.* FROM 'sekretariat'@'%';

-- Usuwanie uzytkownika
DROP USER 'nauczyciel'@'localhost';
Kolejnosc wykonywania zapytania: FROM/JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT.
Alias z SELECT NIE dziala w WHERE (alias powstaje w kroku 5, WHERE w kroku 2). Dziala w ORDER BY i HAVING.

V. Programowanie po stronie serwera (PHP)

1. Podstawy skladni

<?php
  // Zmienne - zaczynaja sie od dolara, bez deklaracji typu
  $imie = "Anna";
  echo "Witaj, " . $imie;           // kropka = konkatenacja
  echo "<p>Witaj, $imie</p>";     // zmienna w cudzyslowie sie rozwija

  // Cudzyslow vs apostrof
  echo '$imie';    // wypisze: $imie (doslownie)
  echo "$imie";    // wypisze: Anna (rozwija zmienna)

  // Tablice
  $tab = [1, 2, 3];
  $tab_asoc = ["imie" => "Anna", "wiek" => 17];
  echo $tab_asoc["imie"];   // Anna

  // Petla foreach
  foreach ($tab_asoc as $klucz => $wartosc) {
    echo "$klucz: $wartosc<br>";
  }

  // Funkcje
  function podatek($kwota, $stawka = 0.23) {
    return $kwota * $stawka;
  }
  echo podatek(1000);   // 230
?>

2. Formularze: GET i POST

<!-- formularz.html -->
<form action="wynik.php" method="post">
  <input type="text" name="imie">
  <button type="submit">Wyslij</button>
</form>

<!-- wynik.php -->
<?php
  if (isset($_POST["imie"])) {
    echo "Witaj, " . htmlspecialchars($_POST["imie"]);
  }
?>
GET: dane w adresie URL, widoczne, ograniczona dlugosc. Do wyszukiwarek i filtrow.
POST: dane w tresci zadania, niewidoczne, brak limitu. Do logowania i zapisu do bazy.
POST NIE jest szyfrowany! Jest tylko mniej widoczny. Poufne daje dopiero HTTPS.

3. Sesje i ciasteczka

<?php
  session_start();                    // MUSI byc PRZED jakimkolwiek wyjsciem na strone

  $_SESSION["uzytkownik"] = "anna";   // zapis
  echo $_SESSION["uzytkownik"];       // odczyt

  session_destroy();                  // wylogowanie
?>
session_start() MUSI byc wywolane PRZED jakimkolwiek outputem (nawet pusta linia przed <?php to błąd). Komunikat: "headers already sent".

4. Obsluga plikow

<?php
  // Zapis do pliku
  file_put_contents("dane.txt", "nowa linia\n", FILE_APPEND);

  // Odczyt calego pliku
  $linie = file("dane.txt", FILE_IGNORE_NEW_LINES);
  foreach ($linie as $linia) {
    echo $linia . "<br>";
  }
?>
Bez FILE_APPEND zapis nadpisuje caly plik. Z FLAGA - dopisuje na koniec.

5. Polaczenie z baza danych (mysqli)

<?php
  // Polaczenie
  $polaczenie = new mysqli("localhost", "root", "", "baza");

  if ($polaczenie->connect_errno) {
    die("Blad polaczenia: " . $polaczenie->connect_error);
  }

  $polaczenie->set_charset("utf8");   // OBOWIAZKOWE dla polskich znakow

  // Zapytanie
  $wynik = $polaczenie->query("SELECT nazwa, cena FROM produkty");

  // Petla po wynikach
  while ($wiersz = $wynik->fetch_assoc()) {
    echo "<p>" . $wiersz["nazwa"] . " - " . $wiersz["cena"] . " zl</p>";
  }

  $polaczenie->close();
?>

6. Bezpieczenstwo

SQL Injection - wstrzykniecie kodu SQL przez pole formularza. Obrona: zapytania przygotowane (prepare + bind_param).
XSS - wstrzykniecie skryptu u innego uzytkownika. Obrona: htmlspecialchars() przy kazdym wypisywaniu danych od uzytkownika.
Hasla - nigdy nie zapisuj jawnie. Obrona: password_hash() i password_verify().
// Zapytanie przygotowane - BEZPIECZNE
$stmt = $polaczenie->prepare("SELECT * FROM uzytkownicy WHERE login = ?");
$stmt->bind_param("s", $_POST["login"]);
$stmt->execute();
$wynik = $stmt->get_result();

// Bezpieczne wypisywanie danych
echo htmlspecialchars($_POST["imie"]);

7. Podzial kodu: include i require

<?php
  // polaczenie.php - dane dostepowe
  $polaczenie = new mysqli("localhost", "root", "", "baza");
  $polaczenie->set_charset("utf8mb4");
?>

<!-- index.php -->
<?php require_once "polaczenie.php"; ?>
<header>...</header>
<main>Tresc</main>
<?php include "stopka.php"; ?>
include - gdy pliku nie ma, zglasza ostrzezenie i kontynuuje.
require - gdy pliku nie ma, zglasza blad krytyczny i przerywa.
_once - zapobiega podwojnemu dolaczeniu. Polaczenie z baza i funkcje = require_once. Naglowek, stopka = include.

8. Funkcje tekstowe i daty

// Tekst
strlen("tekst")              // dlugosc
substr("tekst", 0, 3)        // "tek"
str_replace("a", "b", "tekst")  // podmiana
trim(" tekst ")              // obcina spacje
explode(";", "a;b;c")        // tablica: ["a", "b", "c"]
implode(", ", $tab)          // tekst: "a, b, c"
ucfirst("anna")              // "Anna"

// Liczby
number_format(12345.678, 2, ",", " ")  // "12 345,68"
round($cena, 2)                          // 19.9 (nie 19.90!)
round($cena, 2) i number_format()        // "19,90"

// Daty
echo date("Y-m-d");                      // 2026-08-16
echo date("d.m.Y", strtotime("2026-01-14"));  // 14.01.2026
echo date("Y-m-d", strtotime("$data +7 days"));  // +7 dni

9. Wysylanie plikow na serwer

<!-- Formularz MUSI miec enctype -->
<form action="wyslij.php" method="post" enctype="multipart/form-data">
  <input type="file" name="zdjecie">
  <input type="submit" value="Wyslij">
</form>

<?php
// wyslij.php
if (isset($_FILES["zdjecie"]) && $_FILES["zdjecie"]["error"] === 0) {
  $nazwa   = $_FILES["zdjecie"]["name"];
  $tymczas = $_FILES["zdjecie"]["tmp_name"];
  $rozmiar = $_FILES["zdjecie"]["size"];

  $dozwolone = ["jpg", "jpeg", "png", "gif"];
  $rozsz = strtolower(pathinfo($nazwa, PATHINFO_EXTENSION));

  if (!in_array($rozsz, $dozwolone)) {
    echo "Niedozwolony typ pliku.";
  } elseif ($rozmiar > 2 * 1024 * 1024) {
    echo "Plik wiekszy niz 2 MB.";
  } else {
    move_uploaded_file($tymczas, "zdjecia/" . $nazwa);
    echo "Wyslano: " . $nazwa;
  }
}
?>
Brak enctype="multipart/form-data" - tablica $_FILES bedzie pusta.
Nieistniejacy katalog docelowy - move_uploaded_file nie tworzy folderow automatycznie.
Podsumowanie - co wchodzi na egzamin:
- Odebranie danych z formularza i wypisanie na stronie (praktycznie w kazdym arkuszu)
- Polaczenie z baza i wyswietlenie wyniku zapytania w petli
- Roznica miedzy GET a POST (pytanie zamkniete)
- Rola sesji przy logowaniu i session_start()
- Wskazanie zagrozenia i obrony (SQL Injection, XSS)
- Wspolny naglowek/stopka = include/require
- Wyswietlanie daty z bazy i ceny z dwoma miejscami po przecinku
- Formularz wysylania pliku z walidacja rozszerzenia