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:
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).<?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);
?>
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ę.
| Funkcja | Co robi | Zwraca | Gdy się nie uda |
|---|---|---|---|
fopen($nazwa, $tryb) | otwiera plik w trybie r, w, a, x | uchwyt (zasób) | false i ostrzeżenie „Failed to open stream" |
fwrite($uchwyt, $napis) | zapisuje napis w miejscu wskaźnika; alias fputs | liczba bajtów | błąd typu, gdy zamiast napisu podasz tablicę |
fclose($uchwyt) | zamyka plik | true | – |
file_put_contents($nazwa, $dane) | fopen + fwrite + fclose w jednym; FILE_APPEND dokleja | liczba bajtów | false |
file_get_contents($nazwa) | cały plik jako jeden napis | napis | false i ostrzeżenie |
file($nazwa) | plik jako tablica linii; FILE_IGNORE_NEW_LINES obcina końce linii | tablica | false |
fgets($uchwyt) | jedna linia od wskaźnika | napis | false 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 katalog | true lub false | – |
include 'plik.php' | wkleja i wykonuje kod z innego pliku | 1 (lub wartość z return), false gdy brak | ostrzeżenie, skrypt idzie dalej |
require 'plik.php' | jak include, ale plik jest obowiązkowy | jak wyżej | błąd krytyczny, skrypt się zatrzymuje |
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):
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:
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ę).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).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).
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).
| Tryb | Odczyt | Zapis | Gdy plik istnieje | Gdy pliku nie ma |
|---|---|---|---|---|
'r' | tak | nie | wskaźnik na początku | false i ostrzeżenie |
'w' | nie | tak | zawartość skasowana | plik tworzony |
'a' | nie | tak | zapis dopisywany na końcu | plik tworzony |
'x' | nie | tak | false i ostrzeżenie „File exists" | plik tworzony |
'r+' | tak | tak | wskaźnik na początku, nic nie kasuje | false i ostrzeżenie |
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:
| Pytanie | Odpowiedź |
|---|---|
| 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 .
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.
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.
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ś.
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.
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.
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.
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.
Zagadnienia z tego samego obszaru matury – warto je powtórzyć razem: