Wszystkie zagadnienia: PHP
średni egzamin zawodowy INF.03PHPpliki

Obsługa plików w PHP

01

Opis

Skrypt PHP na egzaminie zwykle czyta z bazy i pisze na stronę. Czasem jednak polecenie każe mu zostawić ślad także na dysku – w pliku tekstowym. W arkuszu ze stycznia 2025 skrypt na stronie szkolenia.php wysyła zapytanie do bazy firma, wypisuje daty i tematy szkoleń w osobnych paragrafach, a „dodatkowo zwrócone zapytaniem wiersze są zapisywane jako osobne linie w pliku tekstowym o nazwie harmonogram.txt" (arkusz CKE INF.03, styczeń 2025, zadanie 5). Do tego służą funkcje obsługi plików: fopen, fwrite, fclose oraz ich skrócone odpowiedniki file_put_contents i file_get_contents.

W podstawie programowej jest to osobne kryterium jednostki o skryptach serwerowych. Podstawa programowa INF.03.5, efekt 4, kryterium 6: „korzysta z funkcji do obsługi plików". Sąsiednie kryteria tej samej jednostki – przesyłanie danych z formularza (kryterium 3 i 4), biblioteki bazy danych (kryterium 5), ciasteczka i sesje (kryterium 7) – mają własne hasła: odbiór danych z formularza, połączenie z bazą przez mysqli i sesje i ciasteczka. Tu chodzi wyłącznie o to, co dzieje się między skryptem a plikiem na dysku.

Zasady, które wynikają z jedynego arkusza praktycznego z tym poleceniem i z jego zasad oceniania:

  • Punkty są dwa i osobne: jeden za to, że skrypt tworzy lub otwiera plik do zapisu pod nazwą z treści zadania, drugi za to, że każdy zwrócony rekord jest w pliku osobną linią (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie).
  • Drugie kryterium egzaminator sprawdza „na pliku" – otwiera harmonogram.txt i patrzy, co w nim jest. Otwarcie pliku do zapisu zalicza się także z kodu źródłowego, gdy strona nie uruchamia się przez błędy PHP; zawartość pliku już nie (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie).
  • Skrypty są sprawdzane w XAMPP 8.2.0, czyli na PHP 8.2 (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Każdy wynik w tym haśle został uruchomiony w tej wersji.
  • Plik ma powstać w trakcie działania skryptu, nie ręcznie: polecenie mówi o zapisie „zwróconych zapytaniem wierszy", a lista plików na płycie kończy się frazą „ewentualnie inne przygotowane pliki" (arkusz CKE INF.03, styczeń 2025, zadanie 5).
02

Skrypt PHP

<?php
// szkolenia.php – skrypt: wyświetla harmonogram i zapisuje go do pliku harmonogram.txt
$polaczenie = mysqli_connect('localhost', 'root', '', 'firma');
if (!$polaczenie) {
    die('Błąd połączenia: ' . mysqli_connect_error());
}

$zapytanie = 'SELECT Data, Temat FROM szkolenia ORDER BY Data';
$wynik = mysqli_query($polaczenie, $zapytanie);

// plik tworzony (lub czyszczony) raz, przed pętlą – tryb w
$plik = fopen('harmonogram.txt', 'w');

while ($wiersz = mysqli_fetch_row($wynik)) {
    $linia = $wiersz[0] . ' ' . $wiersz[1];
    echo '<p>' . $linia . '</p>' . PHP_EOL;   // na stronę: osobny paragraf
    fwrite($plik, $linia . PHP_EOL);          // do pliku: osobna linia
}

fclose($plik);
mysqli_close($polaczenie);
?>
03

Jak to zbudować

Skrypt powyżej odpowiada rezultatowi „Skrypt połączenia z bazą" z arkusza ze stycznia 2025: „Wysyła do bazy danych zapytanie 1", „Zwrócone zapytaniem data i temat szkolenia są oddzielone spacją i wyświetlane jeden pod drugim w osobnych paragrafach w bloku głównym", zapis do harmonogram.txt, „Na końcu działania skrypt zamyka połączenie z serwerem" (arkusz CKE INF.03, styczeń 2025, zadanie 5). Zapytanie 1 to według zasad oceniania SELECT Data, Temat FROM szkolenia ORDER BY Data; (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Uruchomiony na czterech przykładowych wierszach skrypt dał plik z czterema liniami, np. 2021-09-20 Podstawy języka C++ – dokładnie tak brzmi pierwszy rekord, którego oczekuje egzaminator na zrzucie zapytania 1 (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie).

1. Otwórz plik raz, przed pętlą. fopen(nazwa, tryb) zwraca uchwyt do pliku albo false, gdy się nie uda (php.net, fopen). Tryb 'w' otwiera plik tylko do zapisu, ustawia wskaźnik na początku i skraca plik do zera; jeśli plik nie istnieje – tworzy go (php.net, fopen). Dlatego fopen z trybem 'w' wykonujesz przed pętlą po wynikach, a nie w każdym jej obrocie: przy każdym kolejnym otwarciu poprzednia zawartość znika.

$plik = fopen('harmonogram.txt', 'w');
if (!$plik) {
    die('Nie można otworzyć pliku harmonogram.txt');
}

2. Zapisz każdy rekord jako osobną linię. fwrite(uchwyt, napis) dopisuje napis w miejscu wskaźnika i zwraca liczbę zapisanych bajtów. Sama funkcja nie dodaje znaku końca linii – „osobne linie" z polecenia powstają tylko wtedy, gdy doklejasz go sam. Stała PHP_EOL to znak końca linii właściwy dla systemu, na którym działa skrypt. Zapis linii 2021-09-20 Podstawy języka C++ z końcem linii zwrócił 32 bajty: 30 znaków, z których ę zajmuje w UTF-8 dwa bajty, plus jeden bajt końca linii (sprawdzone w PHP 8.2).

while ($wiersz = mysqli_fetch_row($wynik)) {
    fwrite($plik, $wiersz[0] . ' ' . $wiersz[1] . PHP_EOL);
}

Argumentem fwrite musi być napis. Przekazanie całej tablicy $wiersz kończy się błędem krytycznym „fwrite(): Argument #2 ($data) must be of type string, array given" (sprawdzone w PHP 8.2) – kolumny sklejasz kropką, tak jak w składni PHP.

3. Zamknij plik. fclose(uchwyt) zwalnia plik. PHP zamknąłby go i tak na końcu skryptu, ale w skrypcie egzaminacyjnym kolejność „zapis – zamknięcie pliku – zamknięcie bazy" jest czytelna dla oceniającego, a polecenie „Na końcu działania skrypt zamyka połączenie z serwerem" dotyczy właśnie ostatniej instrukcji (arkusz CKE INF.03, styczeń 2025, zadanie 5).

fclose($plik);
mysqli_close($polaczenie);

4. Wariant krótszy: file_put_contents. Funkcja „jest identyczna z kolejnym wywołaniem fopen(), fwrite() i fclose()" (php.net, file_put_contents). Zwraca liczbę zapisanych bajtów albo false. Bez flagi nadpisuje plik; z flagą FILE_APPEND dokleja dane na końcu istniejącego pliku zamiast go nadpisywać (php.net, file_put_contents). Najwygodniej zebrać linie do zmiennej w pętli i zapisać wszystko jednym wywołaniem:

$tresc = '';
while ($wiersz = mysqli_fetch_row($wynik)) {
    $tresc .= $wiersz[0] . ' ' . $wiersz[1] . PHP_EOL;
}
file_put_contents('harmonogram.txt', $tresc);

file_put_contents przyjmuje też tablicę jednowymiarową – wtedy działa jak implode('', $tablica), czyli skleja elementy bez żadnego separatora (php.net, file_put_contents). Końce linii nadal musisz mieć w elementach.

5. Odczyt w drugą stronę. Gdy polecenie każe coś z pliku wczytać, masz trzy drogi: file_get_contents(nazwa) zwraca cały plik jako jeden napis, file(nazwa) – tablicę linii (ze znakami końca linii, chyba że dodasz flagę FILE_IGNORE_NEW_LINES), a fopen z trybem 'r' i fgets w pętli – linia po linii. Wszystkie trzy uruchomione na pliku z liniami a, b, c dały odpowiednio napis "a\nb\nc\n", tablicę trzech elementów i trzy obroty pętli (sprawdzone w PHP 8.2).

$linie = file('harmonogram.txt', FILE_IGNORE_NEW_LINES);
foreach ($linie as $linia) {
    echo '<p>' . $linia . '</p>';
}

6. Gdzie powstaje plik. Nazwa bez ścieżki, jak 'harmonogram.txt', jest liczona od katalogu roboczego. Przy uruchomieniu strony pod Apache jest to katalog, w którym leży skrypt – test na php:8.2-apache pokazał plik obok szkolenia.php, a getcwd() zwróciło katalog skryptu (sprawdzone w PHP 8.2). Na egzaminie znaczy to: plik pojawi się w tym samym folderze htdocs, z którego uruchamiasz stronę.

04

Tabela

Funkcje obsługi plików – żadna nie jest w tabeli funkcji arkusza, wszystkie sprawdzone w PHP 8.2
FunkcjaCo robiZwracaGdy się nie uda
fopen($nazwa, $tryb)otwiera plik w trybie r, w, a, xuchwyt (zasób)false i ostrzeżenie „Failed to open stream"
fwrite($uchwyt, $napis)zapisuje napis w miejscu wskaźnika; alias fputsliczba bajtówbłąd typu, gdy zamiast napisu podasz tablicę
fclose($uchwyt)zamyka pliktrue–
file_put_contents($nazwa, $dane)fopen + fwrite + fclose w jednym; FILE_APPEND doklejaliczba bajtówfalse
file_get_contents($nazwa)cały plik jako jeden napisnapisfalse i ostrzeżenie
file($nazwa)plik jako tablica linii; FILE_IGNORE_NEW_LINES obcina końce liniitablicafalse
fgets($uchwyt)jedna linia od wskaźnikanapisfalse na końcu pliku
is_file($nazwa)czy istnieje i jest zwykłym plikiem (nie katalogiem)true lub false–
file_exists($nazwa)czy istnieje plik albo katalogtrue lub false–
include 'plik.php'wkleja i wykonuje kod z innego pliku1 (lub wartość z return), false gdy brakostrzeżenie, skrypt idzie dalej
require 'plik.php'jak include, ale plik jest obowiązkowyjak wyżejbłąd krytyczny, skrypt się zatrzymuje

Na egzaminie

Obsługa plików jest tematem rzadkim. W arkuszach praktycznych zebranych na portalu (INF.03 2021–2026, EE.09 2017–2022) polecenie, w którym skrypt PHP ma zapisać lub odczytać plik tekstowy, pada w jednym wariancie: „Dodatkowo zwrócone zapytaniem wiersze są zapisywane jako osobne linie w pliku tekstowym o nazwie harmonogram.txt" (arkusz CKE INF.03, styczeń 2025, zadanie 5). Frazy fopen, fwrite, file_put_contents, file_get_contents, include i require nie padają w żadnym arkuszu praktycznym – nie ma ich też w tabeli „Wybór funkcji języka PHP", która w tym wariancie wymienia wyłącznie funkcje mysqli_ (arkusz CKE INF.03, styczeń 2025, zadanie 5). Funkcję trzeba znać z pamięci.

Za co są punkty w tym wariancie (streszczenie zasad oceniania, własnymi słowami):

  • Za instrukcję, która tworzy albo otwiera do zapisu plik o nazwie z zadania – to kryterium egzaminator może zaliczyć z kodu źródłowego nawet wtedy, gdy strona nie uruchamia się przez błędy PHP (zasady oceniania INF.03, styczeń 2025, zadanie 5).
  • Za to, że rekordy zwrócone zapytaniem są w utworzonym pliku osobnymi liniami – z zastrzeżeniem „należy sprawdzić działanie na pliku", czyli liczy się zawartość, nie sam kod (zasady oceniania INF.03, styczeń 2025, zadanie 5).
  • Osobno punktowane są w tym samym rezultacie: wysłanie zapytania 1, wypisanie daty i tematu w kolejnych paragrafach, zamknięcie połączenia jako ostatnia operacja na bazie i znaczące nazwy zmiennych (zasady oceniania INF.03, styczeń 2025, zadanie 5).

Zapytanie 1 zwraca w bazie egzaminacyjnej 18 rekordów, pierwszy to 2021-09-20 Podstawy języka C++ (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Poprawny harmonogram.txt ma więc 18 linii i zaczyna się od tej daty.

W części pisemnej temat wraca regularnie – CKE nie publikuje testów pisemnych INF.03, więc arkusze na portalu mają nagłówek E.14, ale zakres jest ten sam, bo kryterium „korzysta z funkcji do obsługi plików" jest w podstawie INF.03:

  • „W języku PHP zapisywanie danych do pliku realizuje funkcja" – odpowiedź fputs(), pozostałe warianty to fgets(), fopen() i nieistniejąca freadfile() (arkusz CKE E.14, czerwiec 2019, część pisemna, zad. 34 – klucz B). fputs to alias fwrite (sprawdzone w PHP 8.2: oba wywołania zapisały tę samą linię).
  • „Wskaż funkcję PHP, za pomocą której odczytana zawartość pliku jest zapisywana do zmiennej reprezentującej ciąg znaków" – file_get_contents(), obok dystraktorów eof(), fwrite(), get_file() (arkusz CKE E.14, czerwiec 2021, część pisemna, zad. 40 – klucz D; to samo pytanie w arkuszu ze stycznia 2023).
  • „Włączenie do kodu skryptu zawartości pliku egzamin.php, zawierającego kod PHP, wymaga dodania instrukcji" – include("egzamin.php"), nie fopen ani fgets (arkusz CKE E.14, styczeń 2018, część pisemna, zad. 39 – klucz D).
  • require() i include() pojawiają się też jako dystraktory w pytaniu o przekierowanie użytkownika na inną stronę, gdzie poprawną odpowiedzią jest header() (arkusz CKE E.14, czerwiec 2021, część pisemna, zad. 38 – klucz A).

Pułapki wprost z treści zadania: nazwa pliku jest podana (harmonogram.txt) i musi się zgadzać co do znaku, bo egzaminator otwiera plik o tej nazwie; „osobne linie" wymagają końca linii po każdym rekordzie; a zapis do pliku jest dodatkiem do wypisania na stronie – skrypt ma robić obie rzeczy z tego samego wyniku zapytania (arkusz CKE INF.03, styczeń 2025, zadanie 5).

06

Pułapki w zadaniach

fopen w trybie 'w' wewnątrz pętli. Każdy obrót otwiera plik od nowa, a tryb 'w' skraca go do zera (php.net, fopen). Uruchomiony w ten sposób skrypt zostawił w pliku tylko ostatni rekord – jedną linię 2021-11-08 JavaScript dla początkujących zamiast czterech (sprawdzone w PHP 8.2). Kryterium „rekordy zapisywane jako osobne linie" sprawdzane „na pliku" przepada (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Otwarcie przed pętlą, zamknięcie po niej.

Brak końca linii po rekordzie. fwrite($plik, $data . ' ' . $temat) bez PHP_EOL skleja wszystkie rekordy w jedną linię: 2021-09-20 Podstawy języka C++2021-10-04 Bazy danych MySQL…, a file() liczy w takim pliku jedną linię (sprawdzone w PHP 8.2). Polecenie mówi „osobne linie" (arkusz CKE INF.03, styczeń 2025, zadanie 5).

Tablica zamiast napisu w fwrite. fwrite($plik, $wiersz) z tablicą z mysqli_fetch_row kończy skrypt błędem krytycznym o niewłaściwym typie argumentu (sprawdzone w PHP 8.2). Strona wtedy w ogóle się nie uruchamia, więc egzaminator ocenia z kodu tylko część kryteriów – otwarcie pliku tak, zawartość nie (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Sklejaj kolumny kropką.

Plik utworzony ręcznie zamiast przez skrypt. Pusty harmonogram.txt założony w Notatniku spełnia nazwę, ale nie kryterium „skrypt tworzy / otwiera do zapisu" ani „zwrócone zapytaniem rekordy są zapisywane" (zasady oceniania INF.03, styczeń 2025, zadanie 5 – streszczenie). Plik ma powstać z instrukcji w szkolenia.php.

Inna nazwa pliku niż w zadaniu. harmonogram.txt a Harmonogram.txt, harmonogram.text albo szkolenia.txt – egzaminator szuka pliku o nazwie z treści zadania (arkusz CKE INF.03, styczeń 2025, zadanie 5). Nazwę przepisz z arkusza, tak samo jak nazwy kwerendy.txt czy import.jpg w innych rezultatach.

Pominięte sprawdzenie, czy fopen się udał. Gdy katalog jest tylko do odczytu albo ścieżka jest błędna, fopen zwraca false z ostrzeżeniem „Failed to open stream" (sprawdzone w PHP 8.2; php.net, fopen), a kolejny fwrite na false kończy się błędem krytycznym. Warunek if (!$plik) po fopen zatrzymuje skrypt z czytelnym komunikatem – tak samo, jak sprawdzasz wynik mysqli_connect.

require zamiast include dla pliku, którego może nie być. Oba wklejają kod z innego pliku, ale gdy pliku brak, include daje ostrzeżenie i skrypt idzie dalej, a require – błąd krytyczny i skrypt się zatrzymuje (php.net, include; sprawdzone w PHP 8.2). W pytaniu pisemnym o dołączenie pliku egzamin.php poprawną odpowiedzią jest include (arkusz CKE E.14, styczeń 2018, część pisemna, zad. 39 – klucz D).

07

Porównanie

TrybOdczytZapisGdy plik istniejeGdy pliku nie ma
'r'takniewskaźnik na początkufalse i ostrzeżenie
'w'nietakzawartość skasowanaplik tworzony
'a'nietakzapis dopisywany na końcuplik tworzony
'x'nietakfalse i ostrzeżenie „File exists"plik tworzony
'r+'taktakwskaźnik na początku, nic nie kasujefalse i ostrzeżenie
08

Sprawdź się

Skrypt szkolenia.php ma wypisać daty i tematy szkoleń w osobnych paragrafach oraz zapisać zwrócone wiersze jako osobne linie w pliku harmonogram.txt. Uzupełnij:

PytanieOdpowiedź
Która funkcja otwiera plik i zwraca uchwyt?
Który tryb kasuje dotychczasową zawartość i tworzy plik, gdy go nie ma?
Który tryb dopisuje dane na końcu istniejącego pliku?
Która funkcja zapisuje napis przez uchwyt (klucz z czerwca 2019 podaje jej alias)?
Jak nazywa się alias tej funkcji z klucza odpowiedzi?
Która stała daje znak końca linii?
Która funkcja zwraca cały plik jako jeden napis (klucz z czerwca 2021)?
Która funkcja zwraca plik jako tablicę linii?
Które słowo dołącza kod z innego pliku bez zatrzymywania skryptu przy jego braku?
Ile linii ma poprawny harmonogram.txt, jeśli zapytanie 1 zwraca 18 rekordów?

Uzupełnij zdania:

Funkcja fopen w trybie w wywołana w każdym obrocie pętli zostawi w pliku tylko rekord. Zapis jedną funkcją bez uchwytu to , a plik po zapisie zamyka .

09

Najczęściej zadawane pytania

Czy obsługa plików w ogóle pada w części praktycznej INF.03?

Rzadko. W arkuszach praktycznych zebranych na portalu (INF.03 2021–2026, EE.09 2017–2022) polecenie o zapisie do pliku tekstowego przez skrypt PHP jest w jednym wariancie – styczeń 2025, zadanie 5, plik harmonogram.txt. W części pisemnej pytania o fputs, file_get_contents i include wracają w kilku sesjach, a kryterium „korzysta z funkcji do obsługi plików" jest w podstawie programowej INF.03.5, więc temat jest w zakresie.

fopen z fwrite czy file_put_contents – co wybrać na egzaminie?

Oba rozwiązania spełniają kryteria: „tworzy / otwiera do zapisu plik" i „rekordy zapisywane jako osobne linie" sprawdzane na pliku. fopen z fwrite w pętli jest naturalne, gdy w tej samej pętli wypisujesz paragrafy na stronę. file_put_contents wymaga wcześniej zebrania wszystkich linii do jednej zmiennej – mniej instrukcji, ale łatwiej zapomnieć o końcu linii między rekordami.

Czy trzeba wywoływać fclose?

PHP zamyka otwarte pliki na końcu skryptu, więc brak fclose nie zepsuje zawartości. Zasady oceniania nie punktują zamknięcia pliku wprost, punktują zamknięcie połączenia z bazą jako ostatnią operację na bazie. fclose przed mysqli_close porządkuje skrypt i pokazuje egzaminatorowi, że wiesz, co otworzyłeś.

Gdzie na dysku pojawi się harmonogram.txt?

Przy nazwie bez ścieżki – w katalogu skryptu, czyli tam, gdzie leży szkolenia.php w htdocs (sprawdzone na php:8.2-apache). Po uruchomieniu strony w przeglądarce sprawdź w tym folderze, czy plik powstał i ma tyle linii, ile rekordów zwraca zapytanie – egzaminator zrobi dokładnie to samo.

Dlaczego w pliku wszystkie rekordy są w jednej linii?

Bo fwrite nie dodaje końca linii. Dopisz . PHP_EOL do każdego zapisu. Bez tego polecenie „osobne linie" nie jest spełnione, choć wszystkie dane fizycznie są w pliku.

Czym różni się include od require?

Oba wklejają i wykonują kod z innego pliku. Gdy pliku nie ma, include zgłasza ostrzeżenie i skrypt działa dalej, a require – błąd krytyczny, który zatrzymuje skrypt (php.net, include). W pytaniu pisemnym o dołączenie pliku z kodem PHP poprawną odpowiedzią było include("egzamin.php"); fopen i fgets otworzą plik, ale nie wykonają jego kodu.

Czy file_exists i is_file to to samo?

Nie. file_exists('.') dla katalogu zwraca true, is_file('.') – false (sprawdzone w PHP 8.2). Do sprawdzenia, czy istnieje plik tekstowy przed odczytem, lepsze jest is_file; do sprawdzenia, czy cokolwiek o takiej nazwie już jest na dysku – file_exists.

↗

Powiązane zagadnienia