PHP w HTML — szablony i bezpieczne wyjście

🎯 Po tej lekcji napiszesz prosty szablon HTML z osadzonym PHP, użyjesz składni alternatywnej foreach i będziesz wiedzieć, dlaczego htmlspecialchars to obowiązek.

W Module 0 dowiedziałeś się, że PHP działa na serwerze i zwraca gotowy HTML do przeglądarki. W tej lekcji zobaczymy, jak to wygląda w praktyce — jak wplatać PHP w HTML, jak pisać czytelne szablony i, co najważniejsze, jak bezpiecznie wyświetlać dane.

PHP wewnątrz HTML

Możesz wplatać kod PHP bezpośrednio w plik HTML — wystarczy użyć tagów <?php ... ?>. PHP wykona kod, a HTML wyjdzie bez zmian:

<!DOCTYPE html>
<html lang="pl">
<head><meta charset="UTF-8"><title>Powitanie</title></head>
<body>
  <h1><?php echo 'Cześć, świecie!'; ?></h1>
  <p>Dzisiaj jest <?php echo date('d.m.Y'); ?>.</p>
</body>
</html>

Do szybkiego wyświetlania wartości masz do dyspozycji krótki tag <?= ... ?>, który jest równoważny <?php echo ... ?>:

<h1><?= 'Cześć, świecie!'; ?></h1>
💡 Wskazówka: <?= $zmienna ?> to skrót od <?php echo $zmienna; ?>. Jest czytelniejszy w szablonach — używaj go przy wyświetlaniu wartości.

Składnia alternatywna w szablonach

Gdy masz pętle i warunki wewnątrz HTML, tradycyjne klamry { } wyglądają nieczytelnie. PHP oferuje składnię alternatywną, która lepiej współgra z kodem HTML:

<?php
$owoce = ['jabłko', 'gruszka', 'śliwka'];
?>

<ul>
<?php foreach ($owoce as $owoc): ?>
    <li><?= htmlspecialchars($owoc, ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>

Różnica: zamiast { piszesz : (dwukropek), a zamiast } piszesz endforeach;. To samo dotyczy if, for, while:

<?php if ($liczba > 0): ?>
    <p>Liczba jest dodatnia.</p>
<?php elseif ($liczba < 0): ?>
    <p>Liczba jest ujemna.</p>
<?php else: ?>
    <p>To zero.</p>
<?php endif; ?>

Separacja logiki od widoku

Mieszanie obliczeń z HTML szybko staje się nieczytelne. Dobrym nawykiem jest oddzielenie logiki od widoku — najpierw przygotuj dane w PHP, a potem wyświetl je w szablonie:

<?php
declare(strict_types=1);

// --- LOGIKA: przygotuj dane ---
$uczniowie = ['Ola', 'Kuba', 'Zosia'];
$liczba = count($uczniowie);
$tytul = 'Lista uczniów';

// --- WIDOK: wyświetl dane ---
?>
<!DOCTYPE html>
<html lang="pl">
<head><meta charset="UTF-8"><title><?= htmlspecialchars($tytul, ENT_QUOTES, 'UTF-8') ?></title></head>
<body>
  <h1><?= htmlspecialchars($tytul, ENT_QUOTES, 'UTF-8') ?></h1>
  <p>Liczba uczniów: <?= $liczba ?></p>
  <ul>
  <?php foreach ($uczniowie as $uczen): ?>
      <li><?= htmlspecialchars($uczen, ENT_QUOTES, 'UTF-8') ?></li>
  <?php endforeach; ?>
  </ul>
</body>
</html>

Blok logiki przygotowuje dane, blok widoku je wyświetla. Nie mieszaj skomplikowanych obliczeń z tagami HTML.

htmlspecialchars — nawyk na całe życie

Zauważyłeś, że w każdym przykładzie powyżej owijam zmienne w htmlspecialchars? To nie przypadek. To obowiązek.

Wyobraź sobie, że ktoś wpisał w formularzu imię: <script>alert('hack')</script>. Jeśli wyświetlisz to bezpośrednio przez echo:

echo $imie; // NIEBEZPIECZNE — przeglądarka wykona skrypt!

...przeglądarka potraktuje to jako kod HTML i uruchomi skrypt. To atak zwany XSS (Cross-Site Scripting).

htmlspecialchars zamienia niebezpieczne znaki na encje HTML:

<?php
declare(strict_types=1);

$imie = '<script>alert("hack")</script>';
echo htmlspecialchars($imie, ENT_QUOTES, 'UTF-8');
// wynik: &lt;script&gt;alert(&quot;hack&quot;)&lt;/script&gt;
// przeglądarka WYŚWIETLI ten tekst, zamiast go wykonać
⚠️ Zasada bez wyjątków: Zanim wyświetlisz dane od użytkownika (z formularza, z URL, z bazy danych), zawsze przepuść je przez htmlspecialchars($x, ENT_QUOTES, 'UTF-8'). Nie ma tu wyjątków — „ten raz" bez escaping wystarczy do ataku.

Dwa ostatnie argumenty są ważne:

  • ENT_QUOTES — escaping zarówno cudzysłowów " jak i apostrofów '
  • 'UTF-8' — jawne określenie kodowania, żeby uniknąć egzotycznych ataków

W kolejnych lekcjach nauczysz się, skąd w ogóle biorą się dane od użytkownika — zaczniemy od metod GET i POST.

Funkcje w tej lekcji

Sprawdź się

Jaka funkcja PHP chroni przed atakiem XSS przy wyświetlaniu danych od użytkownika?

Jak wygląda zamknięcie pętli foreach w składni alternatywnej szablonów PHP?

Co powinna zawierać 'logika' w wzorcu separacji logiki od widoku?

Ćwiczenie

Masz tablicę $produkty = [['nazwa' => 'Chleb', 'cena' => 4.99], ['nazwa' => 'Masło', 'cena' => 7.49], ['nazwa' => 'Mleko', 'cena' => 3.29]]. Napisz szablon HTML, który wyświetli te produkty jako listę <ul>. Użyj składni alternatywnej foreach i htmlspecialchars dla każdej nazwy.

Pokaż rozwiązanie
<?php
declare(strict_types=1);

$produkty = [
    ['nazwa' => 'Chleb', 'cena' => 4.99],
    ['nazwa' => 'Masło', 'cena' => 7.49],
    ['nazwa' => 'Mleko', 'cena' => 3.29],
];
?>
<!DOCTYPE html>
<html lang="pl">
<head><meta charset="UTF-8"><title>Produkty</title></head>
<body>
<h1>Lista produktów</h1>
<ul>
<?php foreach ($produkty as $p): ?>
    <li><?= htmlspecialchars($p['nazwa'], ENT_QUOTES, 'UTF-8') ?> — <?= htmlspecialchars((string) $p['cena'], ENT_QUOTES, 'UTF-8') ?> zł</li>
<?php endforeach; ?>
</ul>
</body>
</html>