Część 19 kursu PHP pod kątem INF.03: operacje na plikach (odczyt, zapis, CSV, raporty) oraz przesyłanie plików formularzem na serwer ($_FILES, move_uploaded_file, walidacja rozszerzenia). 16 ćwiczeń z automatycznym sprawdzaniem.
Do pracy z plikami służą file_get_contents() (odczyt całości) i file_put_contents() (zapis). Są proste, ale wczytują cały plik do pamięci.
$sciezka = __DIR__ . '/dane/log.txt';
file_put_contents($sciezka, date('Y-m-d H:i') . " start\n", FILE_APPEND);
if (is_file($sciezka)) {
$linie = file($sciezka, FILE_IGNORE_NEW_LINES);
foreach ($linie as $linia) {
echo '<p>' . htmlspecialchars($linia) . '</p>';
}
}
$sciezka = __DIR__ . '/dane/log.txt';
file_put_contents($sciezka, date('Y-m-d H:i') . " start\n", FILE_APPEND);
if (is_file($sciezka)) {
$linie = file($sciezka, FILE_IGNORE_NEW_LINES);
foreach ($linie as $linia) {
echo '<p>' . htmlspecialchars($linia) . '</p>';
}
}
Co robi file_get_contents()?
Poprawna: a) Funkcja wczytuje całą zawartość pliku do napisu.
Formularz z plikiem wymaga method="post" i atrybutu enctype="multipart/form-data" . Bez enctype przeglądarka wyśle tylko nazwę pliku.
if (($_FILES['plik']['error'] ?? 1) === UPLOAD_ERR_OK) {
$nazwa = basename($_FILES['plik']['name']);
$koncowka = strtolower(pathinfo($nazwa, PATHINFO_EXTENSION));
if (in_array($koncowka, ['jpg', 'png'], true) && $_FILES['plik']['size'] < 2000000) {
$nowa = uniqid('img_', true) . '.' . $koncowka;
move_uploaded_file($_FILES['plik']['tmp_name'], __DIR__ . '/upload/' . $nowa);
echo 'Zapisano: ' . htmlspecialchars($nowa);
} else {
echo 'Nieprawidlowy plik';
}
}
if (($_FILES['plik']['error'] ?? 1) === UPLOAD_ERR_OK) {
$nazwa = basename($_FILES['plik']['name']);
$koncowka = strtolower(pathinfo($nazwa, PATHINFO_EXTENSION));
if (in_array($koncowka, ['jpg', 'png'], true) && $_FILES['plik']['size'] < 2000000) {
$nowa = uniqid('img_', true) . '.' . $koncowka;
move_uploaded_file($_FILES['plik']['tmp_name'], __DIR__ . '/upload/' . $nowa);
echo 'Zapisano: ' . htmlspecialchars($nowa);
} else {
echo 'Nieprawidlowy plik';
}
}
Czego wymaga formularz z plikiem?
Poprawna: d) Bez multipart plik nie zostanie wysłany.
Największe ryzyko to wykonanie przesłanego pliku. Jeśli użytkownik wgra plik .php do katalogu publicznego, serwer może go uruchomić. Dlatego sprawdzamy rozszerzenie i zapisujemy pliki poza katalogiem z kodem.
$dozwolone = ['jpg' => 'image/jpeg', 'png' => 'image/png'];
$rozszerzenie = strtolower(pathinfo($_FILES['plik']['name'] ?? '', PATHINFO_EXTENSION));
$typ = $_FILES['plik']['type'] ?? '';
if (!isset($dozwolone[$rozszerzenie]) || $dozwolone[$rozszerzenie] !== $typ) {
exit('Niedozwolony typ pliku');
}
$nazwa = bin2hex(random_bytes(8)) . '.' . $rozszerzenie;
move_uploaded_file($_FILES['plik']['tmp_name'], __DIR__ . '/upload/' . $nazwa);
$dozwolone = ['jpg' => 'image/jpeg', 'png' => 'image/png'];
$rozszerzenie = strtolower(pathinfo($_FILES['plik']['name'] ?? '', PATHINFO_EXTENSION));
$typ = $_FILES['plik']['type'] ?? '';
if (!isset($dozwolone[$rozszerzenie]) || $dozwolone[$rozszerzenie] !== $typ) {
exit('Niedozwolony typ pliku');
}
$nazwa = bin2hex(random_bytes(8)) . '.' . $rozszerzenie;
move_uploaded_file($_FILES['plik']['tmp_name'], __DIR__ . '/upload/' . $nazwa);
Dlaczego sprawdzamy rozszerzenie?
Poprawna: b) Plik PHP w katalogu publicznym może się wykonać.