Przejdź do treści
INF.03 · Dział V

Programowanie po stronie serwera (PHP)

Składnia języka, przesyłanie danych (metody GET i POST), zarządzanie sesjami, obsługa plików, łączenie aplikacji webowej z bazą danych (mysqli), bezpieczeństwo.

Wstęp: PHP to miejsce, w którym arkusz INF.03 zamienia się w aplikację

W części praktycznej PHP pojawia się zawsze w tej samej roli: masz formularz w HTML, bazę danych przygotowaną przez CKE i musisz je połączyć. Odebrać dane, sprawdzić je, zapytać bazę, wyświetlić wynik. Część pisemna dokłada pytania, które trzeba znać z pamięci — różnicę między metodami GET i POST, działanie sesji, sposób łączenia z bazą. Ten artykuł prowadzi dokładnie tą drogą: od pierwszego znacznika PHP aż do zabezpieczenia zapytania przed atakiem.

  1. Osadzanie kodu i składnia

Kod PHP wykonuje się na serwerze, a do przeglądarki trafia już tylko wynik — czysty HTML. To najważniejsza różnica względem JavaScriptu i najczęstsze pytanie w części pisemnej. Plik musi mieć rozszerzenie .php, inaczej serwer potraktuje go jak zwykły dokument i pokaże kod jako tekst.

<?php
  $imie = "Anna";
  echo "Witaj, " . $imie;   // sklejanie kropką
  echo "<p>Witaj, $imie</p>";  // zmienna rozwija się w cudzysłowie
?>
Cudzysłów kontra apostrof

W cudzysłowie zmienne są rozwijane do swojej wartości, w apostrofie nie. echo '$imie' wypisze dosłownie $imie, a nie „Anna". To ulubione pytanie w teście.

  1. Zmienne, typy i tablice

Nazwa zmiennej zaczyna się od dolara i nie deklaruje się jej typu — PHP ustala go sam na podstawie przypisanej wartości. Na egzaminie liczą się przede wszystkim tablice, bo to w nich przychodzą dane z formularza i wyniki z bazy.

$liczby = [4, 8, 15];              // tablica indeksowana
$osoba  = ["imie" => "Anna", "wiek" => 17];   // tablica asocjacyjna

echo $liczby[0];        // 4
echo $osoba["imie"];    // Anna
echo count($liczby);    // 3

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

Tablica asocjacyjna to dokładnie ta struktura, w której dostaniesz wiersz z bazy danych, a kluczami będą nazwy kolumn. Warto się z nią oswoić, bo to fundament ostatniego zadania w arkuszu.

  1. Warunki, pętle i funkcje
if ($wiek >= 18) {
  echo "Pełnoletni";
} elseif ($wiek >= 13) {
  echo "Nastolatek";
} else {
  echo "Dziecko";
}

for ($i = 1; $i <= 5; $i++) {
  echo $i;
}

function podatek($kwota, $stawka = 0.23) {
  return $kwota * $stawka;
}

echo podatek(1000);   // 230

Wartość domyślna parametru — jak $stawka = 0.23 — pozwala wywołać funkcję z jednym argumentem. Parametry z wartością domyślną muszą stać na końcu listy, inaczej PHP zgłosi błąd.

  1. Formularze: GET i POST

To serce większości zadań praktycznych. Formularz w HTML wskazuje plik PHP i metodę przesyłania, a PHP odbiera dane z odpowiedniej tablicy nadrzędnej.

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

<!-- wynik.php -->
<?php
  if (isset($_POST["imie"])) {
      echo "Witaj, " . htmlspecialchars($_POST["imie"]);
  }
?>
CechaGETPOST
Gdzie są danew adresie URLw treści żądania
Widocznośćwidoczne dla użytkownikaniewidoczne w pasku
Limit długościograniczonypraktycznie brak
Typowe zastosowaniewyszukiwarka, filtr, linklogowanie, wysyłka pliku
Uwaga na egzaminie

POST nie jest szyfrowany — jest tylko mniej widoczny. Dane idą otwartym tekstem, dopóki połączenie nie działa po HTTPS. Odpowiedź „POST jest bezpieczny, bo szyfruje dane" jest błędna.

  1. Sesje i ciasteczka

HTTP nie pamięta niczego między jednym żądaniem a kolejnym. Sesja to mechanizm, który pozwala rozpoznać tego samego użytkownika — dane trzyma serwer, a przeglądarka dostaje tylko identyfikator sesji.

<?php
  session_start();                    // MUSI być przed jakimkolwiek wyjściem

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

  session_destroy();                  // wylogowanie
?>
Sesja kontra ciasteczko

Sesja przechowuje dane na serwerze i znika po zamknięciu przeglądarki. Ciasteczko zapisuje dane u użytkownika i może przetrwać tygodniami. Do logowania używa się sesji, do zapamiętania preferencji — ciasteczka.

Najczęstszy błąd praktyczny: wywołanie session_start() po wypisaniu czegokolwiek na stronę — choćby pustej linii przed znacznikiem PHP. Skutkuje to komunikatem o wysłanych już nagłówkach.

  1. Obsługa plików
// zapis do pliku (FILE_APPEND dopisuje zamiast nadpisywać)
file_put_contents("dane.txt", "nowa linia\n", FILE_APPEND);

// odczyt całego pliku do tablicy linii
$linie = file("dane.txt", FILE_IGNORE_NEW_LINES);

foreach ($linie as $linia) {
  echo $linia . "<br>";
}

Bez flagi FILE_APPEND każdy zapis kasuje poprzednią zawartość pliku. Jeśli zadanie mówi o dopisywaniu kolejnych wpisów, brak tej flagi oznacza utratę punktu.

  1. Połączenie z bazą danych (mysqli)

Ostatnia część arkusza praktycznie zawsze wymaga pobrania danych z bazy i wypisania ich na stronie. Schemat jest niezmienny: połącz się, sprawdź błąd, ustaw kodowanie, wykonaj zapytanie, przejdź wynik pętlą.

<?php
  $polaczenie = new mysqli("localhost", "root", "", "sklep");

  if ($polaczenie->connect_errno) {
      die("Błąd połączenia: " . $polaczenie->connect_error);
  }

  $polaczenie->set_charset("utf8");

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

  while ($wiersz = $wynik->fetch_assoc()) {
      echo "<p>" . $wiersz["nazwa"] . " — " . $wiersz["cena"] . " zł</p>";
  }

  $polaczenie->close();
?>
Dlaczego set_charset jest obowiązkowy

Wszystkie bazy w arkuszach CKE mają polskie nazwy. Bez ustawienia kodowania zamiast ogonków zobaczysz znaki zapytania — a egzaminator zauważy to od razu.

  1. Bezpieczeństwo

Część pisemna pyta o to regularnie, a w praktycznej dobre nawyki nic nie kosztują. Trzy zagrożenia trzeba znać z nazwy i umieć wskazać obronę.

  • SQL Injection — wstrzyknięcie kodu SQL przez pole formularza. Obrona: zapytania przygotowane (prepare i bind_param) zamiast sklejania zapytania z tekstu.

  • XSS — wstrzyknięcie skryptu, który wykona się u innego użytkownika. Obrona: htmlspecialchars() przy każdym wypisywaniu danych od użytkownika.

  • Hasła zapisane jawnie — nigdy nie trzyma się ich w postaci czytelnej. Obrona: password_hash() przy zapisie i password_verify() przy logowaniu.

// zapytanie przygotowane - dane nigdy nie trafiają do treści zapytania
$stmt = $polaczenie->prepare("SELECT * FROM uzytkownicy WHERE login = ?");
$stmt->bind_param("s", $_POST["login"]);
$stmt->execute();
$wynik = $stmt->get_result();
  1. Podział kodu: include i require

Arkusz INF.03 prawie zawsze każe zbudować witrynę z kilku podstron o wspólnym wyglądzie. Kopiowanie nagłówka do każdego pliku to strata czasu i pewny sposób na rozjechanie się stopki na jednej z podstron. Zamiast tego wyciągasz powtarzalne fragmenty do osobnych plików i dołączasz je jedną linijką.

// polaczenie.php - dane dostępowe w jednym miejscu
<?php
  $polaczenie = new mysqli("localhost", "root", "", "egzamin");
  $polaczenie->set_charset("utf8mb4");
?>

// index.php - dołączamy i korzystamy
<?php
  require_once "polaczenie.php";   // bez bazy strona nie ma sensu -> require
  include "naglowek.php";          // ozdoba -> include wystarczy
?>
<main>Treść podstrony</main>
<?php include "stopka.php"; ?>
Różnica, o którą pyta część pisemna

include — gdy pliku nie ma, PHP zgłasza ostrzeżenie i wykonuje skrypt dalej. Reszta strony się wyświetli.

require — gdy pliku nie ma, PHP zgłasza błąd krytyczny i przerywa skrypt. Nic poniżej się nie wykona.

Końcówka _once (include_once, require_once) pilnuje, żeby ten sam plik nie został dołączony dwa razy. Przy pliku z definicjami funkcji to jedyny bezpieczny wariant — drugie dołączenie oznaczałoby próbę zdefiniowania tej samej funkcji ponownie i błąd krytyczny.

Reguła na egzamin

Połączenie z bazą i pliki z funkcjami dołączaj przez require_once. Nagłówek, menu i stopkę — przez include. Dołączany plik dziedziczy wszystkie zmienne z miejsca wywołania, więc $polaczenie z polaczenie.php jest widoczne w każdym pliku, który go dołączył.

  1. Funkcje tekstowe i liczby

Dane z formularza i z bazy przychodzą jako tekst i prawie zawsze trzeba je pociąć, skleić albo sformatować przed wyświetleniem. To zestaw, który wystarcza na cały arkusz.

FunkcjaCo robiPrzykład i wynik
strlen()długość w bajtachstrlen("02070803628") → 11
substr()wycina fragmentsubstr($pesel, 0, 2) → "02"
str_replace()podmienia tekststr_replace(" ", "-", "kurs php") → "kurs-php"
trim()obcina spacje z brzegówtrim(" Anna ") → "Anna"
explode()tekst → tablicaexplode(";", "Anna;Kowalska")[1] → "Kowalska"
implode()tablica → tekstimplode(", ", $tab) → "Anna, Kowalska"
ucfirst()wielka pierwsza literaucfirst("anna") → "Anna"
number_format()formatuje liczbęnumber_format(12345.678, 2, ",", " ") → "12 345,68"
Pułapka z polskimi znakami

Funkcje strlen, substr i strtoupper liczą bajty, a polska litera w UTF-8 zajmuje dwa. Dlatego:

strlen("Zażółć gęślą jaźń") → 26
mb_strlen("Zażółć gęślą jaźń", "UTF-8") → 17

Gdy w tekście mogą wystąpić polskie znaki, używaj wersji z przedrostkiem mb_: mb_strlen, mb_substr, mb_strtoupper. Na nazwiskach i nazwach produktów to jest różnica między poprawnym a rozsypanym wynikiem.

Zaokrąglanie ceny do dwóch miejsc

round($cena, 2) zwraca liczbę, więc 19.90 wyświetli się jako „19.9". Gdy zadanie mówi „dwa miejsca po przecinku", użyj number_format($cena, 2, ",", " ") albo printf("%.2f", $cena) — one dokładają brakujące zero.

  1. Daty i czas

Baza trzyma daty w formacie RRRR-MM-DD, a arkusz zwykle prosi o wyświetlenie ich „po polsku" albo o policzenie różnicy między dwiema datami. Obie rzeczy załatwia się jedną linijką.

<?php
  // dzisiejsza data
  echo date("Y-m-d");            // 2026-08-16
  echo date("d.m.Y H:i");        // 16.08.2026 09:30

  // data z bazy w polskim formacie
  $zBazy = "2026-01-14";
  echo date("d.m.Y", strtotime($zBazy));   // 14.01.2026

  // przesuwanie daty
  echo date("Y-m-d", strtotime("$zBazy +7 days"));   // 2026-01-21

  // różnica dwóch dat w dniach
  $od = new DateTime("2026-01-14");
  $do = new DateTime("2026-06-01");
  echo $od->diff($do)->days;      // 138
?>
ZnakZnaczeniePrzykład
d / jdzień z zerem / bez zera05 / 5
m / nmiesiąc z zerem / bez zera01 / 1
Y / yrok czterocyfrowy / dwucyfrowy2026 / 26
H : i : sgodzina, minuta, sekunda09:30:00
Ndzień tygodnia (1 = poniedziałek)3
  1. Wysyłanie plików na serwer

Zadania typu „dodaj formularz pozwalający wgrać zdjęcie produktu" wracają w arkuszach regularnie. Cała rzecz opiera się na trzech elementach, z których pierwszy najłatwiej przeoczyć.

<!-- 1. formularz MUSI mieć enctype, inaczej przyjdzie sama nazwa pliku -->
<form action="wyslij.php" method="post" enctype="multipart/form-data">
  <input type="file" name="zdjecie">
  <input type="submit" value="Wyślij">
</form>

// 2. wyslij.php - odbiór, sprawdzenie, przeniesienie
<?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 większy niż 2 MB.";
      } else {
          // 3. przeniesienie z katalogu tymczasowego na docelowy
          move_uploaded_file($tymczas, "zdjecia/" . $nazwa);
          echo "Wysłano plik: " . $nazwa;
      }
  }
?>
Trzy rzeczy, na których traci się punkty
  • Brak enctype="multipart/form-data" — tablica $_FILES zostaje pusta i skrypt zachowuje się, jakby nikt nic nie wysłał.

  • Nieistniejący katalog docelowy. move_uploaded_file nie tworzy folderów — jeśli w projekcie nie ma katalogu zdjecia/, funkcja zwróci fałsz i plik zniknie razem z końcem skryptu.

  • Zaufanie rozszerzeniu z nazwy. Sprawdzenie pathinfo odsiewa skrypt.php, ale prawdziwe zabezpieczenie sprawdza też typ MIME (mime_content_type) i nadaje własną nazwę pliku. Na egzaminie wystarczy zwykle biała lista rozszerzeń, ale warto wiedzieć dlaczego.

Co siedzi w tablicy $_FILES
$_FILES["zdjecie"]["name"] — oryginalna nazwa z komputera zdającego
$_FILES["zdjecie"]["tmp_name"] — ścieżka tymczasowa na serwerze
$_FILES["zdjecie"]["size"] — rozmiar w bajtach
$_FILES["zdjecie"]["type"] — typ podany przez przeglądarkę (można podrobić)
$_FILES["zdjecie"]["error"] — 0 oznacza sukces

Co z tego wraca na egzaminie

  • Odebranie danych z formularza i wypisanie ich na stronie — praktycznie w każdym arkuszu.
  • Połączenie z bazą i wyświetlenie wyniku zapytania w pętli.
  • Różnica między GET a POST — pytanie zamknięte w części pisemnej.
  • Rola sesji przy logowaniu i miejsce wywołania session_start().
  • Wskazanie zagrożenia i sposobu obrony przy podanym fragmencie kodu.
  • Wspólny nagłówek i stopka na kilku podstronach — include zamiast kopiowania.
  • Różnica include kontra require — pytanie zamknięte.
  • Wyświetlenie daty z bazy w formacie d.m.Y i ceny z dwoma miejscami po przecinku.
  • Formularz wysyłania pliku z walidacją rozszerzenia.

Zapytania SQL, które tu wykonujesz, opisaliśmy osobno w dziale Język zapytań SQL, a gotowy schemat skryptu znajdziesz w pewniaku Skrypt PHP pobierający dane z bazy.

Przeczytaj też
Jak zdać egzamin INF.03 — kompletny przewodnik

Przebieg sesji, co zabrać na salę, plan pracy na 150 minut i lista rzeczy, na których najczęściej przepadają punkty.

Przygotowanie do INF.03

Nie chcesz przerabiać tego sam?

Prowadzimy indywidualne przygotowanie do kwalifikacji INF.03 — PHP, SQL, HTML i CSS na prawdziwych arkuszach z poprzednich sesji. Zobacz program i cenę.

Zobacz kurs INF.03

Zdajesz też maturę? Dla technika informatyka informatyka rozszerzona to najbliższy wybór — połowę materiału masz już przerobioną na kwalifikacjach. Zobacz przygotowanie do matury z informatyki