Kolorowy kod CSS na ekranie monitora podczas tworzenia strony WWW
Źródło: Pexels | Autor: Pixabay
Rate this post

Nawigacja:

Skąd pomysł na pierwszą stronę w PHP i czego realnie się spodziewać

Od „chcę własną stronę” do wyboru PHP

Droga początkującego webmastera zwykle zaczyna się od prostego pragnienia: własna strona. Czasem chodzi o wizytówkę działalności, czasem o blog, portfolio lub mały serwis z prostym panelem logowania. Po kilku pierwszych próbach z samym HTML i CSS pojawia się pytanie: jak sprawić, by strona „coś robiła”? Żeby nie tylko ładnie wyglądała, ale też reagowała na użytkownika, zapisywała dane, wysyłała maile. W tym miejscu bardzo często na horyzoncie pojawia się PHP.

PHP jest naturalnym wyborem z kilku powodów. Po pierwsze, ogromna liczba poradników i przykładów w sieci jest napisana właśnie z użyciem tego języka. Po drugie, większość tanich kont hostingowych wciąż oferuje PHP „w pakiecie” – bez dodatkowej konfiguracji. Po trzecie, język został zaprojektowany do budowania stron internetowych, więc wiele typowo „webowych” zadań ma w nim gotowe rozwiązania lub funkcje.

W praktyce decyzja o pierwszej stronie w PHP bywa dość spontaniczna: ktoś polecił, gdzieś pojawił się przykład, hosting tak podpowiada. Kluczowe jest jednak, aby zrozumieć, czym PHP jest w istocie i jaki problem rozwiązuje. Bez tego łatwo przerodzić naukę w frustrujące przepisywanie kodu z tutoriala, którego działania się nie czuje.

PHP jako język po stronie serwera, a nie „magiczny HTML”

PHP to język programowania wykonywany po stronie serwera, a nie w przeglądarce użytkownika. To znaczy, że kod PHP nigdy nie trafia wprost do przeglądarki. Serwer odczytuje plik .php, uruchamia kod, a na końcu generuje zwykły HTML (czasem wzbogacony o CSS i JavaScript), który dopiero zostaje wysłany do użytkownika.

Nie jest to „lepszy HTML” ani jego zamiennik. PHP nie rysuje przycisków ani nie ustawia kolorów – robi to nadal HTML/CSS. Z kolei PHP zajmuje się logiką: decyduje, co wyświetlić, jakie dane pobrać, jak zareagować na formularz. Warto mentalnie oddzielić te światy: HTML jako struktura strony, CSS jako wygląd, PHP jako „mózg” po stronie serwera.

W praktyce oba światy mieszają się w jednym pliku: najpierw widoczna jest typowa struktura HTML, a wewnątrz niej pojawiają się bloki <?php ... ?> z logiką. To mieszanie jest na początku wygodne, ale później – przy większych projektach – trzeba je porządkować, aby nie utonąć w chaosie. Do pierwszej strony w PHP wystarczy jednak, że wiadomo, gdzie kończy się HTML, a zaczyna logika.

Oczekiwania początkujących i realny poziom pierwszego projektu

Osoba startująca z PHP często marzy o czymś dużym: własny sklep, panel administracyjny, system logowania, może nawet gra przeglądarkowa. W głowie szybko pojawia się porównanie z wielkimi serwisami – „też tak chcę”. W zderzeniu z rzeczywistością pojawia się jednak seria drobnych przeszkód: konfiguracja serwera lokalnego, niezrozumiałe błędy, różnice między GET a POST, problem z polskimi znakami.

Realnym celem na start jest prosta, dynamiczna strona, która:

  • wyświetla treść generowaną przez PHP (np. aktualną godzinę lub listę artykułów przechowywaną w tablicy),
  • przyjmuje dane z formularza (np. prosty formularz kontaktowy),
  • reaguje na różne adresy URL (np. index.php?page=kontakt wyświetla inną zawartość niż index.php?page=home).

Taki projekt może wydawać się skromny, ale uczy bardzo wielu kluczowych elementów: pracy ze zmiennymi, tablicami, instrukcjami warunkowymi, podstawową strukturą plików i obsługą żądań HTTP. Klon Facebooka zostaje w sferze planów na przyszłość – najpierw trzeba spokojnie zbudować działający fundament.

Co trzeba wiedzieć przed pierwszą linijką kodu

Podstawy HTML/CSS i podział na frontend oraz backend

PHP nie zastępuje HTML i CSS. Zanim zacznie powstawać pierwsza strona w PHP, dobrze jest mieć choć minimalne obycie z:

  • strukturą dokumentu HTML: znaczniki <html>, <head>, <body>, nagłówki <h1>-<h6>, listy, linki, formularze,
  • podstawami CSS: definiowanie kolorów, marginesów, prostego układu strony.

W świecie webowym co do zasady wyróżnia się dwa obszary:

Frontend – wszystko, co widzi użytkownik w przeglądarce: HTML, CSS oraz JavaScript po stronie klienta. Odpowiada za wygląd, interaktywność interfejsu, animacje, walidację formularzy przed wysłaniem.

Backend – logika po stronie serwera: języki takie jak PHP, Python, Ruby czy Java, komunikacja z bazą danych, przetwarzanie formularzy, wysyłanie e-maili. Użytkownik nie widzi bezpośrednio kodu backendu, widzi jedynie jego efekt w postaci wygenerowanego HTML.

PHP należy do backendu. Oznacza to, że nie da się nim „pokolorować” przycisku ani dodać efektu po najechaniu myszką – od tego są CSS i JavaScript. PHP decyduje jednak, czy w ogóle ten przycisk ma się pojawić i z jakim tekstem.

Jak działa przeglądarka, serwer webowy i PHP – obraz żądanie → odpowiedź

W uproszczeniu komunikację pomiędzy przeglądarką a serwerem można opisać w kilku krokach:

  1. Użytkownik wpisuje adres URL (np. http://localhost/index.php) lub klika link.
  2. Przeglądarka wysyła do serwera żądanie HTTP – prośbę o konkretny zasób (pliki HTML, CSS, PHP, obrazki).
  3. Serwer webowy (np. Apache) odbiera żądanie i sprawdza, o jaki plik chodzi.
  4. Jeśli plik ma rozszerzenie .php, serwer przekazuje go do interpretera PHP, który uruchamia kod i generuje wynik w postaci HTML.
  5. Serwer odsyła wygenerowany HTML w odpowiedzi HTTP do przeglądarki.
  6. Przeglądarka wyświetla otrzymany kod jako stronę.

Użytkownik widzi wyłącznie efekt końcowy, czyli wynik działania skryptu. Kod PHP pozostaje na serwerze. To ważna różnica względem JavaScriptu, który – jako język po stronie klienta – jest wysyłany do przeglądarki i tam wykonywany.

Strona statyczna a dynamiczna – prosty przykład z formularzem

Strona statyczna to taka, której treść jest zawsze taka sama, niezależnie od użytkownika, godziny, parametrów w adresie. Typowy przykład: wizytówka firmy w czystym HTML, gdzie każdy paragraf jest wpisany „na sztywno” w pliku. Aby zmienić treść, trzeba edytować plik i wgrać go ponownie.

Strona dynamiczna reaguje na dane wejściowe. Przykładowo, formularz kontaktowy w czystym HTML może wyglądać efektownie, ale bez kodu po stronie serwera nie da się go faktycznie „wysłać”. Po kliknięciu Wyślij przeglądarka musi przekazać dane gdzieś dalej – do skryptu PHP, który je odbierze, sprawdzi, zbuduje treść wiadomości i np. zapisze ją w pliku lub wyśle e-mail.

Inny przykład: prosta strona z listą artykułów. W wersji statycznej każdy artykuł ma osobny plik HTML. W wersji dynamicznej lista może być generowana z tablicy lub bazy danych, a jeden szablon PHP potrafi obsłużyć dziesiątki wpisów. Zmienia się sposób myślenia: zamiast dopisywać kolejny plik HTML, dodaje się element do tablicy lub rekordu w bazie.

PHP a inne technologie: dlaczego często startuje się od PHP

Wybierając pierwszy język backendowy, wiele osób porównuje PHP z Pythonem lub JavaScriptem (Node.js). Każde z tych rozwiązań ma swoje mocne strony, ale w kontekście pierwszej strony w PHP kilka argumentów przemawia właśnie za nim:

  • łatwa dostępność na tanich hostingach (wiele firm oferuje gotową konfigurację PHP i Apache),
  • prostota uruchomienia projektu – wystarczy serwer lokalny typu XAMPP i przeglądarka,
  • ogromna liczba przykładów, od prostych do zaawansowanych, w języku polskim i angielskim,
  • silne powiązanie z najpopularniejszymi CMS-ami (WordPress, Joomla, Drupal), co ułatwia później współpracę z gotowymi systemami.

Wybór i konfiguracja środowiska: od pustego komputera do działającego serwera lokalnego

Co to znaczy „mieć PHP na komputerze”

W odróżnieniu od HTML, który wystarczy otworzyć w przeglądarce, PHP wymaga środowiska uruchomieniowego. Aby plik .php „działał”, potrzebne są trzy elementy:

  • serwer webowy – zwykle Apache lub Nginx, program nasłuchujący na porcie (np. 80) i przyjmujący żądania HTTP,
  • interpreter PHP – program, który rozumie składnię PHP i potrafi ją wykonać,
  • (opcjonalnie na start) baza danych – najczęściej MySQL lub MariaDB, choć do pierwszej strony można się bez niej obyć.

Na docelowym hostingu wszystko to jest już skonfigurowane przez dostawcę. Na własnym komputerze trzeba to sobie zorganizować samodzielnie. Ręczna konfiguracja Apache + PHP jest możliwa, ale dla początkującego bardziej sensowne są gotowe pakiety typu XAMPP, WampServer czy MAMP.

Popularne pakiety: XAMPP, WampServer, MAMP

Najczęściej wybierane rozwiązania to:

PakietSystemyCharakterystyka
XAMPPWindows, macOS, LinuxNajbardziej uniwersalny; zawiera Apache, PHP, MariaDB, panel kontrolny.
WampServerWindowsPopularny na Windows; wygodna ikonka w trayu, zarządzanie usługami.
MAMPmacOS, WindowsCzęsto wybierany przez użytkowników Mac; prosty interfejs.

Dla pierwszej strony w PHP w środowisku Windows najczęściej wybierany jest XAMPP lub WampServer. Na macOS sporo osób zaczyna od MAMP-a, choć XAMPP także dobrze się sprawdza. Istotne jest, aby wybrany pakiet:

  • miał aktualną wersję PHP,
  • startował bez większych kolizji z innymi programami (np. Skype’em czy Dockerem),
  • pozwalał łatwo podglądać logi błędów (to ważne przy debugowaniu).

Instalacja XAMPP krok po kroku – opis słowny

Przykładowy scenariusz na Windows z użyciem XAMPP wygląda następująco:

  1. Pobranie instalatora XAMPP ze strony projektu (dobór wersji z PHP 8.x jest rozsądnym wyborem na start).
  2. Uruchomienie instalatora i pozostawienie domyślnych opcji (Apache, MySQL, PHP, phpMyAdmin). Inne komponenty zwykle nie są potrzebne na pierwszym etapie.
  3. Wybór katalogu instalacji, standardowo C:xampp.
  4. Po zakończeniu instalacji uruchomienie panelu XAMPP Control Panel.
  5. W panelu uruchomienie modułu Apache (i opcjonalnie MySQL, jeśli planowana jest baza danych).
  6. Wejście w przeglądarce na adres http://localhost/. Jeśli pojawia się strona powitalna XAMPP, serwer działa poprawnie.

Na macOS i Linuksie proces jest podobny: instalacja pakietu, uruchomienie usług, sprawdzenie działania pod http://localhost/. W zależności od systemu, szczegóły mogą się różnić (uprawnienia, lokalizacja katalogów), ale ogólna zasada pozostaje ta sama.

Gdzie trafią pliki projektu i jak je uruchamiać

W przypadku XAMPP na Windows domyślny katalog, z którego serwer Apache serwuje pliki, to C:xampphtdocs. Wszystko, co zostanie tam umieszczone, będzie dostępne przez przeglądarkę pod adresem http://localhost/nazwa_katalogu.

Przykładowo, jeśli w htdocs powstanie katalog mojprojekt, a w nim plik index.php, dostęp do niego będzie możliwy przez:

http://localhost/mojprojekt/index.php

Jeżeli nazwa pliku to właśnie index.php, serwer potraktuje go jako domyślną stronę katalogu. Oznacza to, że wywołanie adresu http://localhost/mojprojekt/ bez podawania nazwy pliku zadziała tak samo jak podanie pełnej ścieżki do index.php. Ułatwia to nawigację i odpowiada docelowemu zachowaniu na większości serwerów produkcyjnych.

Na potrzeby nauki dobrze jest rozdzielić projekty w osobne katalogi. Jeden folder może służyć prostym eksperymentom („piaskownica”), inne – konkretnym miniaplikacjom, np. „formularz_kontaktowy” czy „galeria”. Unika się wtedy sytuacji, w której po kilku tygodniach w htdocs leży kilkadziesiąt luźnych plików bez jasnej struktury i trudno zorientować się, co do czego służy.

Ścieżka w pasku adresu przeglądarki nie zawsze będzie pokrywać się z faktyczną ścieżką w systemie plików. Przykładowo, http://localhost/test/formularz.php może wskazywać na plik C:xampphtdocstestformularz.php. W razie wątpliwości co do lokalizacji pliku najlepiej prześledzić ją krok po kroku: od katalogu głównego serwera (zwykle htdocs) do konkretnego podkatalogu i pliku, sprawdzając, czy nazwy zgadzają się z wpisanym adresem URL.

Jeżeli po wpisaniu adresu w przeglądarce pojawia się komunikat typu „Object not found” albo błąd 404, najczęściej oznacza to literówkę w nazwie katalogu lub pliku, umieszczenie go w innym miejscu niż katalog serwera bądź nieuruchomiony Apache. Zwykle wystarcza wtedy szybki przegląd: czy Apache działa w panelu XAMPP, czy plik na pewno ma rozszerzenie .php (a nie np. .php.txt) i czy katalog projektu znajduje się bezpośrednio w htdocs.

Pierwszy plik PHP: od „Hello, world” do prostego szablonu strony

Tworzenie pliku i pierwsze uruchomienie

Po uruchomieniu serwera lokalnego kolejnym krokiem jest stworzenie pierwszego pliku z rozszerzeniem .php. W praktyce wygląda to następująco:

  1. W katalogu htdocs utworzenie folderu, np. pierwsza_strona.
  2. W tym folderze utworzenie nowego pliku tekstowego i nadanie mu nazwy index.php.
  3. Otwarcie pliku w edytorze kodu (np. VS Code, Notepad++, Sublime Text).

Do pliku można wpisać minimalny kod PHP:

<?php
  echo "Hello, world!";
?>

Zapis pliku i wejście w przeglądarce na adres http://localhost/pierwsza_strona/ powinny pokazać tekst Hello, world!. Jeśli zamiast tego wyświetla się kod źródłowy z widocznymi znacznikami <?php ?>, oznacza to, że plik nie jest przetwarzany przez PHP (najczęściej dlatego, że serwer nie działa lub plik nie znajduje się w katalogu serwowanym przez Apache).

Znaczniki PHP i mieszanie z HTML

PHP jest językiem osadzanym w HTML. Kod, który ma zostać wykonany po stronie serwera, musi znaleźć się między znacznikami otwierającymi i zamykającymi:

<?php
  // kod PHP
?>

Reszta dokumentu może być zwykłym HTML-em. Przykład prostej strony łączącej HTML i PHP:

<!DOCTYPE html>
<html lang="pl">
  <head>
    <meta charset="UTF-8">
    <title>Moja pierwsza strona w PHP</title>
  </head>
  <body>
    <h1>Witaj na mojej stronie</h1>
    <p>Dzisiaj jest:
      <strong>
        <?php
          echo date('Y-m-d');
        ?>
      </strong>
    </p>
  </body>
</html>

W tym przykładzie przeglądarka widzi tylko efekt działania funkcji date() (czyli konkretną datę), natomiast sam kod PHP pozostaje ukryty po stronie serwera. To podstawowy mechanizm generowania dynamicznej treści.

Instrukcja echo i krótsza składnia wyjścia

Do wypisywania danych w PHP najczęściej używa się instrukcji echo:

<?php
  echo "To jest tekst";
  echo 123;
?>

Przy prostym osadzaniu zmiennej w HTML-u można skorzystać z tzw. krótkiej składni wyjścia:

<?php $imie = "Anna"; ?>

<p>Witaj, <?= $imie ?>!</p>

Znacznik <?= jest uproszczoną formą <?php echo ... ?>. W wielu projektach przyspiesza zapis szablonów, ale dobrze jest używać go świadomie i nie mieszać zbyt skomplikowanej logiki bezpośrednio w HTML-u.

Prosty szablon strony z nagłówkiem i stopką

Minimalny „szkielet” funkcjonalnej strony w PHP może obejmować nagłówek, główną treść i stopkę. Nawet w pierwszym projekcie warto przyzwyczajać się do pewnego porządku:

Python świetnie sprawdza się w analizie danych, automatyzacji i backendzie, ale konfiguracja stacku webowego (np. Django, Flask) bywa dla świeżaka ciut bardziej wymagająca. JavaScript w Node.js pozwala pisać „jeden język wszędzie”, jednak wymaga innego zestawu narzędzi i zrozumienia mechanizmów asynchronicznych. W kontekście pierwszej małej strony, klasyczny PHP bywa po prostu najszybszą drogą do celu. Osoby, które zastanawiają się szerzej nad wyborem języka, mogą sięgnąć po Najlepsze języki dla początkujących programistów.

<!DOCTYPE html>
<html lang="pl">
  <head>
    <meta charset="UTF-8">
    <title>Pierwsza strona w PHP</title>
    <style>
      body { font-family: Arial, sans-serif; margin: 0; padding: 0; }
      header, footer { background: #eee; padding: 10px 20px; }
      main { padding: 20px; }
    </style>
  </head>
  <body>
    <header>
      <h1>Moja pierwsza strona w PHP</h1>
    </header>

    <main>
      <h2>Witaj</h2>
      <p>Ta treść została wygenerowana <strong>dzisiaj</strong>:</p>
      <p>Data: <?= date('Y-m-d H:i') ?></p>
    </main>

    <footer>
      <p>&copy; <?= date('Y') ?> Moja pierwsza strona</p>
    </footer>
  </body>
</html>

Data w stopce oraz chwila wygenerowania treści zmienia się przy każdym odświeżeniu. To mała, ale wyraźna różnica względem statycznego HTML-a.

Składnia PHP krok po kroku: zmienne, typy, instrukcje warunkowe i pętle

Zmienne i podstawowe typy danych

Zmienne w PHP zawsze zaczynają się od znaku $. Nazwa może zawierać litery, cyfry i podkreślenia, ale nie może zaczynać się od cyfry. Przykłady deklaracji:

<?php
  $imie = "Jan";
  $wiek = 30;
  $czyProgramista = true;
  $saldo = 1234.56;
?>

PHP ma kilka podstawowych typów:

  • string – ciąg znaków ("tekst"),
  • int – liczba całkowita (10),
  • float – liczba zmiennoprzecinkowa (10.5),
  • bool – wartość logiczna (true lub false),
  • array – tablica (zbiór wartości pod jednym kluczem),
  • null – brak wartości.

PHP co do zasady jest językiem z luźnym typowaniem, czyli typ można zmieniać „w locie”. Mimo to przy większych projektach przyjmuje się dyscyplinę co do tego, jakie wartości trafiają do danej zmiennej. W początkowej fazie nauki pomaga chociażby wypisywanie typu i wartości:

<?php
  $wartosc = "123";
  var_dump($wartosc);
?>

Łączenie tekstu i podstawowe operatory

Najczęściej wykonywaną operacją na napisach jest ich łączenie przy użyciu operatora kropki:

<?php
  $imie = "Jan";
  $powitanie = "Witaj, " . $imie . "!";
  echo $powitanie;
?>

W typowych obliczeniach stosuje się standardowe operatory arytmetyczne: +, -, *, /, % (reszta z dzielenia). W praktyce dość często pojawiają się także operatory porównania: ==, ===, !=, <, >, <=, >=. Dwa znaki równości sprawdzają „równość” z uwzględnieniem konwersji typów, trzy znaki równości – równość i typu, i wartości.

Instrukcje warunkowe: if, elseif, else

Warunek w PHP pozwala reagować na różne sytuacje w zależności od danych. Klasyczna konstrukcja if wygląda następująco:

<?php
  $godzina = (int) date('H');

  if ($godzina < 12) {
    $komunikat = "Dzień dobry";
  } elseif ($godzina < 18) {
    $komunikat = "Dobry wieczór";
  } else {
    $komunikat = "Dobranoc";
  }
?>

<p><?= $komunikat ?>!</p>

W praktyce warunki kontrolują nie tylko wyświetlane komunikaty, lecz także np. dostęp do określonej części strony, dobór szablonu czy obsługę błędów formularza.

Operator trójargumentowy i prostsze warunki w HTML

W prostych przypadkach wygodny bywa operator warunkowy ?::

<?php
  $zalogowany = true;
?>

<p>
  <?= $zalogowany ? "Witaj ponownie!" : "Witaj, gościu!" ?>
</p>

Dobrze sprawdza się przy krótkich, dwuwariantowych komunikatach. Rozbudowane warunki lepiej jednak umieszczać w klasycznym if dla czytelności.

Pętle: powtarzanie tych samych operacji

Gdy pojawia się konieczność powtórzenia podobnych fragmentów kodu, pętle oszczędzają kopiowania. Najczęściej w pierwszych projektach stosuje się dwie konstrukcje: for i foreach.

Pętla for – konkretna liczba powtórzeń

<?php
  for ($i = 1; $i <= 5; $i++) {
    echo "<p>To jest linia numer $i</p>";
  }
?>

Pętla przejdzie od $i = 1 do $i = 5, wypisując pięć akapitów. Przy generowaniu powtarzalnych elementów (np. „top 3 artykuły”) jest to wygodne, jeśli liczba powtórzeń jest z góry znana.

Tablice i pętla foreach

Tablice pozwalają przechowywać wiele wartości w jednej zmiennej. Prosta lista tytułów artykułów może wyglądać tak:

<?php
  $artykuly = [
    "Jak zainstalować PHP krok po kroku",
    "Prosty formularz kontaktowy w PHP",
    "Obsługa plików i zapis danych na serwerze",
  ];
?>

<ul>
  <?php foreach ($artykuly as $tytul): ?>
    <li><?= $tytul ?></li>
  <?php endforeach; ?>
</ul>

W tej konstrukcji każdy element tablicy $artykuly trafia po kolei do zmiennej $tytul. Taki sposób zapisu jest czytelny w szablonach HTML, zwłaszcza gdy stosuje się składnię z endforeach zamiast klamerek.

Tablice asocjacyjne – dane opisane kluczami

Tablice można budować nie tylko jako listy, lecz także z własnymi kluczami. Powstaje wtedy coś w rodzaju mini-słownika:

<?php
  $uzytkownik = [
    'imie' => 'Katarzyna',
    'email' => 'katarzyna@example.com',
    'wiek' => 27,
  ];
?>

<p>Imię: <?= $uzytkownik['imie'] ?></p>
<p>E-mail: <?= $uzytkownik['email'] ?></p>

Przy szablonach stron profilowych lub kart produktów tego typu struktury są znacznie wygodniejsze niż „płaskie” zmienne.

Kolorowy kod HTML na ekranie monitora podczas tworzenia strony w PHP
Źródło: Pexels | Autor: Bibek ghosh

Struktura małego projektu: porządek w plikach i pierwsze „include”

Dlaczego dzielić projekt na pliki

Już przy kilku podstronach powtarzanie tego samego kodu (np. nagłówka HTML, menu, stopki) w każdym pliku staje się uciążliwe. Zmiana tytułu serwisu lub odnośnika w menu wymagałaby wtedy edycji wielu plików. Rozsądniej jest wydzielić powtarzające się elementy do osobnych plików i „włączać” je tam, gdzie są potrzebne.

Prosty układ katalogów dla pierwszej strony

Przy małym projekcie sensowne może być już od początku rozdzielenie plików w następujący sposób:

  • index.php – strona główna,
  • kontakt.php – podstrona z formularzem kontaktowym,
  • about.php – strona „o mnie/o firmie”,
  • partials/ – katalog na elementy wspólne (np. header.php, footer.php),
  • assets/ – zasoby statyczne (obrazki, CSS, ewentualnie JavaScript).

Taki układ ułatwia późniejsze przeniesienie projektu na inny serwer. Poszczególne części strony są też szybciej odnajdywane, co w praktyce oszczędza czas przy każdej drobnej poprawce.

include i require – włączanie plików

W PHP do włączania zawartości jednego pliku do drugiego służą instrukcje include i require. Najprostszy przykład z nagłówkiem i stopką może wyglądać tak:

<?php
  include 'partials/header.php';
?>

<main>
  <h2>Strona główna</h2>
  <p>To jest treść strony głównej.</p>
</main>

<?php
  include 'partials/footer.php';
?>

Plik partials/header.php może zawierać np. cały początek dokumentu HTML i menu:

<!doctype html>
<html lang="pl">
<head>
  <meta charset="utf-8">
  <title>Mój pierwszy serwis w PHP</title>
  <link rel="stylesheet" href="/assets/style.css">
</head>
<body>
  <header>
    <h1>Mój pierwszy serwis w PHP</h1>
    <nav>
      <ul>
        <li><a href="/index.php">Start</a></li>
        <li><a href="/about.php">O mnie</a></li>
        <li><a href="/kontakt.php">Kontakt</a></li>
      </ul>
    </nav>
  </header>

Analogicznie w partials/footer.php można umieścić końcówkę dokumentu z powtarzalnymi elementami, np. stopkę i zamknięcia znaczników:

<footer>
  <p>&copy; <?= date('Y') ?> Mój pierwszy serwis w PHP</p>
</footer>
</body>
</html>

Przy takiej strukturze zmiana jednego linku w menu lub nazwy serwisu wymaga edycji tylko w jednym miejscu. W małych projektach robi to dużą różnicę, gdy po kilku tygodniach wraca się do kodu i trzeba wprowadzić drobne poprawki „na wczoraj”.

include_once i require_once – unikanie podwójnego ładowania

Wraz z rozbudową projektu rośnie ryzyko, że ten sam plik zostanie włączony kilka razy, co może prowadzić do błędów (np. ponownej deklaracji funkcji). W takich sytuacjach wygodne są warianty z przyrostkiem _once:

<?php
  require_once 'config.php';
  include_once 'partials/header.php';
?>

require_once i include_once sprawdzają, czy dany plik był już wcześniej dołączony i w razie potrzeby pomijają kolejną próbę. Co do zasady konfigurację i pliki z funkcjami umieszcza się właśnie za pomocą require_once, aby zminimalizować ryzyko „cichych” błędów.

Różnice między include a require w razie błędu

Jeżeli plik wskazany w include nie istnieje albo jest niedostępny, PHP zgłosi ostrzeżenie, ale spróbuje wykonywać pozostały kod. Przy require sytuacja jest poważniejsza: brak pliku kończy się błędem krytycznym i przerwaniem działania skryptu. W praktyce do elementów absolutnie niezbędnych (np. konfiguracja połączenia z bazą danych) stosuje się require, a do części „pomocniczych” – include.

Dobrze jest już na starcie przyjąć prostą zasadę: wszystko, bez czego aplikacja nie ma sensu dalej działać, ładować przez require_once. Z kolei elementy opcjonalne (np. dodatkowe bloki na stronie) mogą być obsługiwane przez include, często w połączeniu z kontrolą istnienia pliku.

Prosty „front controller” w małej skali

Nawet w kilkuplikowym projekcie da się wprowadzić odrobinę porządku, tworząc centralny plik wejściowy. Przykładowo cały ruch można kierować do index.php i na podstawie parametru decydować, którą treść pokazać:

<?php
  $page = $_GET['page'] ?? 'home';

  include 'partials/header.php';

  if ($page === 'home') {
    include 'pages/home.php';
  } elseif ($page === 'about') {
    include 'pages/about.php';
  } elseif ($page === 'kontakt') {
    include 'pages/kontakt.php';
  } else {
    http_response_code(404);
    include 'pages/404.php';
  }

  include 'partials/footer.php';
?>

Taki prosty „routing” zwykle wystarcza na początek, a jednocześnie przygotowuje grunt pod późniejsze korzystanie z gotowych frameworków, gdzie podobne mechanizmy są znacznie bardziej rozbudowane.

Przy takim układzie jeden plik steruje strukturą całej witryny, a poszczególne podstrony zajmują się wyłącznie swoją treścią. W praktyce znika większość duplikacji – nie trzeba w każdym pliku dodawać nagłówka HTML, menu czy stopki. Jeżeli pojawi się potrzeba zmiany układu, wystarczy modyfikacja logiki w jednym miejscu, zamiast żmudnego przeklikiwania się przez kilkanaście plików.

Warto też zwrócić uwagę na to, co dzieje się w przypadku nieznanej wartości parametru page. Zastosowanie kodu odpowiedzi HTTP 404 oraz osobnego widoku pages/404.php sprawia, że przeglądarka i wyszukiwarki dostają czytelną informację o braku strony. Taki drobiazg, wprowadzony od początku, ułatwia późniejsze utrzymanie serwisu oraz ogranicza „dziwne” zachowania przy literówkach w adresach.

Przy dalszej rozbudowie projektu ten prosty mechanizm można stopniowo uszczelniać. Często wprowadza się np. białą listę dozwolonych podstron i mapuje ją na konkretne pliki, zamiast bezpośrednio składać nazwy plików z parametrów URL. Dzięki temu użytkownik ma elastyczny adres typu ?page=kontakt, a kod po swojej stronie zachowuje kontrolę nad tym, co faktycznie jest dołączane.

Na tym etapie da się już zbudować prosty, ale uporządkowany serwis: kilka podstron, wspólne elementy w osobnych plikach, jeden punkt wejścia i nieskomplikowany routing. Taki fundament zwykle wystarcza do pierwszych projektów komercyjnych lub hobbystycznych, a jednocześnie przygotowuje grunt pod kolejne kroki: obsługę formularzy, zapis danych do pliku lub bazy oraz stopniowe wprowadzanie bardziej zaawansowanych narzędzi.

Formularze i dane od użytkownika: od prostego kontaktu po zapis do pliku

Najprostszy formularz kontaktowy – warstwa HTML

Na początek potrzebny jest zwykły formularz HTML, który przeglądarka wyśle na serwer. Przykładowy formularz na stronie kontakt.php może wyglądać następująco:

<h2>Kontakt</h2>

<form action="kontakt.php" method="post">
  <div>
    <label for="imie">Imię:</label>
    <input type="text" id="imie" name="imie" required>
  </div>

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

  <div>
    <label for="wiadomosc">Wiadomość:</label>
    <textarea id="wiadomosc" name="wiadomosc" rows="5" required></textarea>
  </div>

  <button type="submit">Wyślij</button>
</form>

Atrybut method="post" informuje przeglądarkę, że dane mają zostać przesłane w treści żądania HTTP, a nie w adresie URL. Użycie action="kontakt.php" sprawia, że ten sam plik zarówno wyświetla formularz, jak i obsługuje wysyłkę.

$_GET, $_POST i $_REQUEST – skąd PHP bierze dane

PHP udostępnia tablice superglobalne, w których umieszcza dane z żądania HTTP. Najczęściej wykorzystywane są:

  • $_GET – parametry przekazane w adresie URL (np. ?page=kontakt),
  • $_POST – dane wysłane w treści formularza z metodą POST,
  • $_REQUEST – połączenie kilku źródeł (GET, POST, ciasteczka), które bywa wygodne, ale miesza porządki.

Przy pracy z formularzami wysyłanymi metodą POST bezpieczniej jest korzystać bezpośrednio z $_POST. Wtedy od razu wiadomo, skąd pochodzą dane i łatwiej zachować kontrolę nad logiką.

Obsługa formularza w tym samym pliku

Typowy scenariusz przy małych projektach jest następujący: przy pierwszym wejściu na stronę wyświetlany jest pusty formularz, a po jego wysłaniu – ten sam plik odbiera dane, sprawdza je i pokazuje komunikat. Można to zrealizować prostą konstrukcją warunkową:

<?php
  $bledy = [];
  $sukces = false;

  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $imie = trim($_POST['imie'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $wiadomosc = trim($_POST['wiadomosc'] ?? '');

    if ($imie === '') {
      $bledy[] = 'Imię jest wymagane.';
    }

    if ($email === '') {
      $bledy[] = 'Adres e-mail jest wymagany.';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
      $bledy[] = 'Adres e-mail ma nieprawidłowy format.';
    }

    if ($wiadomosc === '') {
      $bledy[] = 'Wiadomość nie może być pusta.';
    }

    if (empty($bledy)) {
      // Tutaj np. zapis do pliku lub wysłanie maila
      $sukces = true;
    }
  }
?>

<h2>Kontakt</h2>

<?php if ($sukces): ?>
  <p>Dziękujemy za wiadomość. Odezwiemy się tak szybko, jak to możliwe.</p>
<?php else: ?>

  <?php if (!empty($bledy)): ?>
    <ul class="errors">
      <?php foreach ($bledy as $blad): ?>
        <li><?= htmlspecialchars($blad, ENT_QUOTES, 'UTF-8') ?></li>
      <?php endforeach; ?>
    </ul>
  <?php endif; ?>

  <form action="kontakt.php" method="post">
    <div>
      <label for="imie">Imię:</label>
      <input type="text" id="imie" name="imie"
             value="<?= htmlspecialchars($_POST['imie'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
             required>
    </div>

    <div>
      <label for="email">E-mail:</label>
      <input type="email" id="email" name="email"
             value="<?= htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
             required>
    </div>

    <div>
      <label for="wiadomosc">Wiadomość:</label>
      <textarea id="wiadomosc" name="wiadomosc" rows="5" required><?=
        htmlspecialchars($_POST['wiadomosc'] ?? '', ENT_QUOTES, 'UTF-8')
      ?></textarea>
    </div>

    <button type="submit">Wyślij</button>
  </form>

<?php endif; ?>

Warunek $_SERVER['REQUEST_METHOD'] === 'POST' rozróżnia zwykłe wejście na stronę od wysłania formularza. Użytkownik wraca do tego samego adresu, ale aplikacja zachowuje się inaczej w zależności od typu żądania.

Dlaczego htmlspecialchars i trim mają znaczenie

Funkcja trim() usuwa spacje z początku i końca ciągu znaków. Ułatwia to weryfikację pól, w których użytkownik przypadkowo dopisał kilka spacji. Z kolei htmlspecialchars() konwertuje znaczniki HTML na bezpieczne encje (np. < na &lt;). Chroni to przed prostymi atakami typu XSS, w których ktoś próbowałby wstrzyknąć własny kod HTML lub JavaScript do pola formularza.

W praktyce dobrze jest przyjąć prostą zasadę: dane sprawdzane „logicznie” (czy są, czy nie są puste, czy adres e-mail ma poprawny format) przechowywać w oryginalnej formie, natomiast każdorazowe wyświetlanie ich w HTML poprzedzać htmlspecialchars(). Dzięki temu formularz pozostaje funkcjonalny, a warstwa prezentacji jest zabezpieczona przed przypadkowymi (lub celowymi) niespodziankami.

Prosta walidacja po stronie PHP

HTML5 oferuje podstawową walidację po stronie przeglądarki (atrybuty required, type="email" itd.), ale nie zastępuje to sprawdzania danych po stronie serwera. Przeglądarkę można obejść, a część użytkowników ma walidację przeglądarkową ograniczoną.

Elementarny zestaw kontroli po stronie PHP może obejmować:

  • sprawdzenie obecności wymaganych pól,
  • weryfikację formatu e-maila funkcją filter_var(),
  • opcjonalne ograniczenie długości pól (np. wiadomość maksymalnie kilka tysięcy znaków),
  • odrzucenie pustych zgłoszeń wysyłanych automatycznie.

Dla początkującej strony kontaktowej to zwykle wystarczy. Gdy projekt się rozrasta, walidacja staje się bardziej rozbudowana (np. sprawdzenie numeru telefonu, kodu pocztowego, specyficznych identyfikatorów), ale fundament jest taki sam.

Zapis danych z formularza do pliku tekstowego

Najprostszym sposobem na przechowanie wiadomości z formularza jest zapisanie ich do pliku tekstowego na serwerze. Nie wymaga to bazy danych ani dodatkowej konfiguracji, choć ma swoje ograniczenia przy większym ruchu.

Przykładowa funkcja zapisująca zgłoszenie do pliku data/kontakt.log może wyglądać następująco:

<?php
  function zapiszKontaktDoPliku(string $imie, string $email, string $wiadomosc): bool
  {
    $sciezka = __DIR__ . '/data/kontakt.log';

    $wiersz = sprintf(
      "[%s] Imię: %s | E-mail: %s | Wiadomość: %s%s",
      date('Y-m-d H:i:s'),
      str_replace(["n", "r"], ' ', $imie),
      str_replace(["n", "r"], ' ', $email),
      str_replace(["n", "r"], ' ', $wiadomosc),
      PHP_EOL
    );

    return (bool) file_put_contents($sciezka, $wiersz, FILE_APPEND | LOCK_EX);
  }
?>

Następnie w logice obsługującej formularz, po pozytywnej walidacji, można tę funkcję wywołać:

<?php
  if (empty($bledy)) {
    if (zapiszKontaktDoPliku($imie, $email, $wiadomosc)) {
      $sukces = true;
    } else {
      $bledy[] = 'Wystąpił problem z zapisem wiadomości. Spróbuj ponownie później.';
    }
  }
?>

Flagi FILE_APPEND i LOCK_EX zlecają dopisanie danych na końcu istniejącego pliku oraz próbę założenia blokady wyłącznej na czas zapisu. Przy małych serwisach taki mechanizm jest zwykle wystarczający. Przy większym obciążeniu i wielu równoczesnych zapisach korzystniej jest przejść na bazę danych.

W tym miejscu przyda się jeszcze jeden praktyczny punkt odniesienia: Najlepsze języki dla początkujących programistów.

Gdzie umieścić plik z danymi

W praktyce dobrze jest trzymać pliki z danymi poza katalogiem publicznym serwera WWW (np. poza public_html czy htdocs). Wtedy nie będą dostępne bezpośrednio przez przeglądarkę, nawet jeśli ktoś znałby ich nazwę. W prostym układzie lokalnym można po prostu utworzyć katalog data/ na tym samym poziomie co index.php, a następnie upewnić się, że nie ma w nim plików, które powinny być widoczne z zewnątrz.

Proste komunikaty o błędach przy pracy z plikami

System plików potrafi zachować się różnie w zależności od uprawnień, konfiguracji serwera czy miejsca na dysku. Dobrym nawykiem jest reagowanie na typowe problemy, zamiast zakładać, że zapis zawsze się powiedzie. W wersji minimalnej można sprawdzić, czy katalog na dane istnieje i jest zapisywalny:

<?php
  $katalogData = __DIR__ . '/data';

  if (!is_dir($katalogData)) {
    mkdir($katalogData, 0775, true);
  }

  if (!is_writable($katalogData)) {
    $bledy[] = 'Brak możliwości zapisu danych na serwerze.';
  }
?>

Takie zabezpieczenie oszczędza czasu przy przenoszeniu projektu na inny serwer, gdzie domyślne uprawnienia katalogów mogą być bardziej restrykcyjne.

Wysyłka e-maila z użyciem funkcji mail

Dla prostych zastosowań część osób woli otrzymywać wiadomości kontaktowe bezpośrednio na skrzynkę pocztową. PHP udostępnia wbudowaną funkcję mail(), którą można wykorzystać w podstawowym wariancie:

<?php
  $do = 'kontakt@twojadomena.pl';
  $temat = 'Nowa wiadomość z formularza kontaktowego';

  $tresc = "Data: " . date('Y-m-d H:i:s') . PHP_EOL .
           "Imię: $imie" . PHP_EOL .
           "E-mail: $email" . PHP_EOL .
           "Wiadomość:" . PHP_EOL .
           $wiadomosc . PHP_EOL;

  $naglowki = 'From: formularz@twojadomena.pl' . "rn" .
              'Reply-To: ' . $email . "rn" .
              'Content-Type: text/plain; charset=utf-8';

  if (mail($do, $temat, $tresc, $naglowki)) {
    $sukces = true;
  } else {
    $bledy[] = 'Nie udało się wysłać wiadomości e-mail.';
  }
?>

Konfiguracja funkcji mail() zależy od serwera – na lokalnym środowisku wiadomości zwykle nie wychodzą „na świat” bez dodatkowych ustawień. Przy pierwszym wdrożeniu na hosting z obsługą PHP warto sprawdzić w panelu usługodawcy, jakie są wymogi dotyczące nadawcy, autoryzacji i limitów wysyłki.

Proste zabezpieczenie przed ponownym wysyłaniem formularza

Typowym efektem ubocznym jest ponowna wysyłka tego samego formularza po odświeżeniu strony przez użytkownika. Przeglądarka często ostrzega przed ponownym wysłaniem danych, ale bywa, że ktoś kliknie „OK” odruchowo, a wiadomość zostanie wysłana dwa razy.

Prostą metodą ograniczenia tego zjawiska jest zastosowanie wzorca POST–Redirect–GET. Po poprawnym przetworzeniu formularza skrypt nie wyświetla od razu wyniku, tylko przekierowuje użytkownika na stronę z komunikatem. W PHP można to zrealizować w ten sposób:

<?php
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ... walidacja, zapis, wysyłka ...

    if (empty($bledy)) {
      header('Location: kontakt.php?sukces=1');
      exit;
    }
  }

  $sukces = ($_GET['sukces'] ?? '') === '1';
?>

<h2>Kontakt</h2>

<?php if ($sukces): ?>
  <p>Dziękujemy za wiadomość. Została zapisana.</p>
<?php else: ?>
  <!-- formularz jak wcześniej -->
<?php endif; ?>

Po przekierowaniu przeglądarka wykonuje zwykłe żądanie GET, które nie powoduje ponownego przetwarzania formularza. Odświeżenie takiej strony jest już neutralne – nie spowoduje ponownej wysyłki.

Użycie sesji do przechowania informacji o komunikatach

Zamiast przekazywać informację o sukcesie w parametrze URL, można posłużyć się mechanizmem sesji. Sesja to zestaw danych przechowywanych po stronie serwera i powiązanych z konkretnym użytkownikiem za pomocą ciasteczka lub identyfikatora w URL.

Aby skorzystać z sesji w prostym formularzu kontaktowym, trzeba ją zainicjować na początku pliku (przed jakimkolwiek HTML-em lub wysyłką nagłówków), a następnie zapisać w niej komunikaty, które zostaną odczytane po przekierowaniu:

<?php
  session_start();

  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ... walidacja, zapis, wysyłka ...

    if (empty($bledy)) {
      $_SESSION['flash_sukces'] = 'Dziękujemy za wiadomość. Została zapisana.';
      header('Location: kontakt.php');
      exit;
    } else {
      $_SESSION['flash_bledy'] = $bledy;
      header('Location: kontakt.php');
      exit;
    }
  }

  $komunikatSukces = $_SESSION['flash_sukces'] ?? null;
  $komunikatyBledow = $_SESSION['flash_bledy'] ?? [];

  // flash – skasuj po jednorazowym odczycie
  unset($_SESSION['flash_sukces'], $_SESSION['flash_bledy']);
?>

<h2>Kontakt</h2>

<?php if ($komunikatSukces): ?>
  <p class="alert alert-success"><?= htmlspecialchars($komunikatSukces, ENT_QUOTES, 'UTF-8') ?></p>
<?php endif; ?>

<?php if (!empty($komunikatyBledow)): ?>
  <ul class="alert alert-danger">
    <?php foreach ($komunikatyBledow as $blad): ?>
      <li><?= htmlspecialchars($blad, ENT_QUOTES, 'UTF-8') ?></li>
    <?php endforeach; ?>
  </ul>
<?php endif; ?>

<!-- formularz jak wcześniej -->

Tego rodzaju „komunikaty jednorazowe” (często nazywane flash messages) ułatwiają pracę przy większych projektach. Niezależnie od liczby formularzy logika jest podobna: część odpowiedzialna za przetwarzanie ustawia komunikat w sesji, a część prezentacyjna jedynie go wyświetla i usuwa. Strona po odświeżeniu nie powiela akcji, a użytkownik widzi czytelne potwierdzenie wykonanej operacji.

W prostych serwisach wystarczy jeden czy dwa komunikaty typu „sukces” i „błąd”. Gdy stron przybywa, rozsądnie jest wyodrębnić mały pomocniczy moduł, np. funkcje setFlash() i getFlash(), aby nie powielać fragmentów z $_SESSION w każdym pliku. Struktura kodu staje się dzięki temu przejrzystsza, a ewentualne zmiany (np. w sposobie przechowywania komunikatów) wprowadza się w jednym miejscu zamiast w kilkunastu.

Samo korzystanie z sesji oznacza, że przeglądarka musi przyjąć co najmniej jedno ciasteczko z identyfikatorem sesji. W środowisku lokalnym zwykle nie stanowi to problemu, jednak przy wdrożeniu publicznym dochodzą kwestie banerów cookies, polityki prywatności czy współpracy z dodatkami blokującymi. Dobrze jest z góry założyć, że sesja powinna przechowywać tylko to, co rzeczywiście musi „przetrwać” między żądaniami, jak choćby właśnie komunikaty po przetworzeniu formularza.

Pierwsza strona w PHP, nawet jeśli składa się z kilku widoków, prostego formularza i logiki zapisu do pliku, daje już całkiem kompletne środowisko do dalszej nauki. Masz działający serwer lokalny, rozumiesz podstawy składni, potrafisz podzielić projekt na pliki i przetwarzać dane od użytkownika. Kolejne kroki – baza danych, logowanie użytkowników, bardziej rozbudowane szablony – stają się wtedy rozszerzeniem czegoś, co już znasz, a nie skokiem w zupełnie nieznane.

Prosta nawigacja i wiele podstron w jednym projekcie

Pierwszy projekt rzadko kończy się na jednym pliku. Szybko pojawia się potrzeba dodania strony „O mnie”, prostego bloga, regulaminu czy rozwiniętej sekcji kontakt. Zamiast kopiować ten sam nagłówek i stopkę do kilku plików HTML, PHP pozwala spiąć całość w jeden spójny zestaw widoków.

Oddzielne pliki dla poszczególnych podstron

Najprostszy układ opiera się na kilku plikach PHP w głównym katalogu projektu, np.:

  • index.php – strona główna,
  • o-mnie.php – przedstawienie autora,
  • kontakt.php – formularz kontaktowy.

Każdy z tych plików może wykorzystywać wspólny nagłówek i stopkę z wcześniejszych przykładów. Z czasem katalog może się rozrosnąć, dlatego przy większej liczbie stron wygodniej jest utworzyć podkatalog pages/ i trzymać tam konkretną zawartość, zostawiając w głównym katalogu jedynie plik „wejściowy”, np. index.php.

Jeden „front controller” zamiast wielu podobnych plików

Zamiast tworzyć kilka bardzo podobnych plików PHP, można posłużyć się prostym mechanizmem routingu. Cały ruch kierowany jest do jednego pliku, który na podstawie parametru w adresie URL dołącza odpowiedni widok:

index.php
includes/
  naglowek.php
  stopka.php
pages/
  home.php
  o-mnie.php
  kontakt.php
<?php
  // index.php
  session_start();

  $dostepneStrony = [
    'home'    => 'Strona główna',
    'o-mnie'  => 'O mnie',
    'kontakt' => 'Kontakt',
  ];

  $strona = $_GET['strona'] ?? 'home';

  if (!array_key_exists($strona, $dostepneStrony)) {
    http_response_code(404);
    $strona = 'home';
  }

  $tytulStrony = $dostepneStrony[$strona];

  include __DIR__ . '/includes/naglowek.php';
  include __DIR__ . '/pages/' . $strona . '.php';
  include __DIR__ . '/includes/stopka.php';
?>

Dzięki takiemu układowi dochodzą jedynie kolejne pliki w katalogu pages/, natomiast główna logika przełączania między podstronami nie wymaga istotnych zmian. Dla prostych serwisów jest to elastyczne i dość bezpieczne rozwiązanie.

Menu nawigacyjne generowane z tablicy

Skoro nazwy stron są już zebrane w jednej tablicy, menu można wygenerować z niej automatycznie. Zmiana nazwy czy dodanie nowej pozycji sprowadza się wtedy do modyfikacji jednej struktury danych zamiast kilku miejsc w kodzie HTML.

<?php
  // fragment includes/naglowek.php
?>
<!doctype html>
<html lang="pl">
<head>
  <meta charset="utf-8">
  <title><?= htmlspecialchars($tytulStrony, ENT_QUOTES, 'UTF-8') ?></title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <h1>Moja pierwsza strona w PHP</h1>
    <nav>
      <ul>
        <?php foreach ($dostepneStrony as $klucz => $nazwa): ?>
          <li>
            <a href="index.php?strona=<?= urlencode($klucz) ?>">
              <?= htmlspecialchars($nazwa, ENT_QUOTES, 'UTF-8') ?>
            </a>
          </li>
        <?php endforeach; ?>
      </ul>
    </nav>
  </header>
  <main>

Przy takim podejściu wyeliminowane są typowe pomyłki w stylu „zapomniałem dodać nowej podstrony do menu na jednej z wersji językowych”. W prostym projekcie to drobiazg, natomiast przy kolejnych modyfikacjach różnica w wygodzie pracy staje się dobrze odczuwalna.

Podstawy bezpieczeństwa w pierwszym projekcie PHP

Nawet mała strona, którą ogląda kilka osób, przetwarza wejście od użytkowników