W tym poradniku nauczysz się, jak stworzyć system wgrywania plików na serwer w PHP. Wgrywanie plików na serwer ma wiele praktycznych zastosowań, o których niżej.
Wdrożymy dwa oddzielne formularze: jeden do przesyłania plików graficznych (JPG, PNG, GIF) o maksymalnym rozmiarze 1MB, a drugi do przesyłania innych typów plików (TXT, PDF). Każdy przesłany plik pojawi się na liście dostępnych plików z możliwością pobrania i usunięcia.
Zastosowanie w praktyce
Takie rozwiązanie jest niezwykle przydatne w różnych scenariuszach, np.:
- Portale społecznościowe – umożliwia użytkownikom dodawanie zdjęć do swoich profili.
- Systemy zarządzania dokumentami – pozwala na przechowywanie i pobieranie plików tekstowych oraz PDF-ów.
- Sklepy internetowe – umożliwia administratorom dodawanie grafik produktów.
- Systemy rekrutacyjne – pozwala kandydatom na przesyłanie CV i innych dokumentów aplikacyjnych.
- Serwisy edukacyjne – pozwala studentom na przesyłanie projektów i prac zaliczeniowych.
1. Tworzenie katalogów do przechowywania plików
Aby zacząć, musimy utworzyć kilka katalogów. Rozwiązanie z przykładu, tworzy katalog, na zdjęcia oraz katalog na inne pliki (tutaj txt i pdf).
Od razu warto wspomnieć o wadzie tego rozwiązania (opisanego w przykładzie), co w późniejszym kroku, przy okazji naprawimy.
Otóż wadą jest brak podkatalogów, wszystkie zdjęcia będą uploadowane do jednego folderu, tak samo pliki TXT czy PDF. W momencie, gdy plików będzie bardzo dużo, setki tysięcy i więcej, wpłynie to znacząco na zużycie pamięci RAM, gdyż wszystkie pliki z katalogu muszą się zaindeksować, by można było je wyświetlić.
Najpierw utwórzmy dwa katalogi na serwerze:
mkdir uploads
mkdir uploads/images
mkdir uploads/other
2. Formularze do przesyłania plików
Formularz do wgrywania obrazków (max. 1MB)
Sam formularz, nie pilnuje rozmiaru pliku, tę czynność będziemy mogli dowolnie ustawiać w skrypcie – mechanizmie – wysyłającym (pkt 3).
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="image">Wybierz obrazek (JPG, PNG, GIF, max. 1MB):</label>
<input type="file" name="image" accept="image/jpeg, image/png, image/gif" required>
<button type="submit" name="upload_image">Prześlij</button>
</form>
Formularz do wgrywania innych plików (TXT, PDF)
<form action="upload.php" method="post" enctype="multipart/form-data">
<label for="file">Wybierz plik (TXT, PDF):</label>
<input type="file" name="file" accept=".txt, .pdf" required>
<button type="submit" name="upload_file">Prześlij</button>
</form>
3. Obsługa wgrywania plików (upload.php)
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
$upload_dir_images = "uploads/images/";
$upload_dir_other = "uploads/other/";
$max_file_size = 1048576; // 1MB
if (isset($_POST['upload_image']) && isset($_FILES['image'])) {
$file = $_FILES['image'];
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed_ext = ["jpg", "jpeg", "png", "gif"];
if (in_array($file_ext, $allowed_ext) && $file['size'] <= $max_file_size) {
$file_path = $upload_dir_images . basename($file['name']);
move_uploaded_file($file['tmp_name'], $file_path);
echo "Obrazek został przesłany.";
} else {
echo "Nieprawidłowy format lub zbyt duży plik.";
}
}
if (isset($_POST['upload_file']) && isset($_FILES['file'])) {
$file = $_FILES['file'];
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed_ext = ["txt", "pdf"];
if (in_array($file_ext, $allowed_ext)) {
$file_path = $upload_dir_other . basename($file['name']);
move_uploaded_file($file['tmp_name'], $file_path);
echo "Plik został przesłany.";
} else {
echo "Nieprawidłowy format pliku.";
}
}
?>
4. Wyświetlanie listy przesłanych plików i umożliwienie ich pobrania lub usunięcia (files.php)
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
$upload_dirs = [
"uploads/images" => "Obrazy",
"uploads/other" => "Inne pliki"
];
if (isset($_GET['delete'])) {
$file_path = $_GET['delete'];
if (file_exists($file_path)) {
unlink($file_path);
echo "Plik został usunięty.";
}
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Lista plików</title>
</head>
<body>
<h2>Lista przesłanych plików</h2>
<?php foreach ($upload_dirs as $dir => $label): ?>
<h3><?php echo $label; ?></h3>
<ul>
<?php
$files = scandir($dir);
foreach ($files as $file) {
if ($file !== '.' && $file !== '..') {
echo "<li><a href='$dir/$file' download>$file</a> ";
echo "<a href='?delete=$dir/$file' onclick='return confirm(\"Usunąć plik?\");'>[Usuń]</a></li>";
}
}
?>
</ul>
<?php endforeach; ?>
</body>
</html>
5. Tworzenie katalogów z datą wgrywania plików
wspomniana poprawka. Czyli zapisywanie plików do katalogów z datą ich dodania, w celu rozproszenia liczby plików w poszczególnych katalogach. To rozwiązanie przyspieszy indeksację plików, nie będzie ryzyka wysycania pamięci RAM do indeksacji plików w danym katalogu.
Warto wspomnieć jednak, że nie jest to rozwiązanie konieczne dla każdego katalogu plików. Nie wszystkie sytuacje bowiem, wymagają takiego rozwiązania i często, te podstawowe, wcześniej opisane, będzie wystarczające.
Aby uporządkować pliki według daty przesłania, każda przesyłka zostanie zapisana w katalogu o nazwie odpowiadającej dacie w formacie YYYY-MM-DD
. Dodajemy następujące modyfikacje w upload.php
:
$today = date("Y-m-d");
$target_dir = "uploads/$today/";
if (!is_dir($target_dir)) {
mkdir($target_dir, 0777, true);
}
Plik zostanie przesłany do odpowiedniego katalogu:
$file_path = $target_dir . basename($file['name']);
move_uploaded_file($file['tmp_name'], $file_path);
Oto pełna, zmodyfikowana wersja upload.php
, która obsługuje tworzenie katalogów według daty oraz poprawnie zapisuje pliki w odpowiednich lokalizacjach:
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
$max_file_size = 1048576; // 1MB
$today = date("Y-m-d"); // Pobranie aktualnej daty w formacie YYYY-MM-DD
$target_dir = "uploads/$today/"; // Tworzenie katalogu dla danej daty
if (!is_dir($target_dir)) {
mkdir($target_dir, 0777, true);
}
// Obsługa wgrywania obrazków
if (isset($_POST['upload_image']) && isset($_FILES['image'])) {
$file = $_FILES['image'];
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed_ext = ["jpg", "jpeg", "png", "gif"];
if (in_array($file_ext, $allowed_ext) && $file['size'] <= $max_file_size) {
$file_path = $target_dir . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $file_path)) {
echo "Obrazek został przesłany.";
} else {
echo "Błąd podczas przesyłania pliku.";
}
} else {
echo "Nieprawidłowy format lub zbyt duży plik.";
}
}
// Obsługa wgrywania innych plików (TXT, PDF)
if (isset($_POST['upload_file']) && isset($_FILES['file'])) {
$file = $_FILES['file'];
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed_ext = ["txt", "pdf"];
if (in_array($file_ext, $allowed_ext)) {
$file_path = $target_dir . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $file_path)) {
echo "Plik został przesłany.";
} else {
echo "Błąd podczas przesyłania pliku.";
}
} else {
echo "Nieprawidłowy format pliku.";
}
}
?>
Co zostało dodane:
- Tworzenie katalogu z datą (
YYYY-MM-DD
) przed zapisaniem pliku. - Sprawdzanie istnienia katalogu i jego automatyczne tworzenie.
- Obsługa błędów przy przesyłaniu plików, aby uniknąć przypadków, gdy plik nie zostanie zapisany poprawnie.
Teraz pliki będą organizowane w katalogach zgodnie z datą przesłania, co ułatwi zarządzanie danymi i ich segregację.
6. Wyświetlanie plików z podkatalogów w files.php
Aby poprawnie listować pliki ze wszystkich katalogów według daty, zmieniamy sposób ich przeszukiwania:
function listFiles($dir) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item !== '.' && $item !== '..') {
$path = "$dir/$item";
if (is_dir($path)) {
echo "<h3>Pliki z dnia: $item</h3><ul>";
listFiles($path);
echo "</ul>";
} else {
echo "<li><a href='$path' download>$item</a> ";
echo "<a href='?delete=$path' onclick='return confirm(\"Usunąć plik?\");'>[Usuń]</a></li>";
}
}
}
}
listFiles("uploads");
Oto kod zmodyfikowanego pliku files.php:
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
$upload_dirs = [
"uploads/images" => "Obrazy",
"uploads/other" => "Inne pliki"
];
if (isset($_GET['delete'])) {
$file_path = $_GET['delete'];
if (file_exists($file_path)) {
unlink($file_path);
echo "Plik został usunięty.";
}
}
function listFiles($dir) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item !== '.' && $item !== '..') {
$path = "$dir/$item";
if (is_dir($path)) {
echo "<h3>Pliki z dnia: $item</h3><ul>";
listFiles($path);
echo "</ul>";
} else {
echo "<li><a href='$path' download>$item</a> ";
echo "<a href='?delete=$path' onclick='return confirm(\"Usunąć plik?\");'>[Usuń]</a></li>";
}
}
}
}
listFiles("uploads");
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Lista plików</title>
</head>
<body>
<h2>Lista przesłanych plików</h2>
<?php foreach ($upload_dirs as $dir => $label): ?>
<h3><?php echo $label; ?></h3>
<ul>
<?php
$files = scandir($dir);
foreach ($files as $file) {
if ($file !== '.' && $file !== '..') {
echo "<li><a href='$dir/$file' download>$file</a> ";
echo "<a href='?delete=$dir/$file' onclick='return confirm(\"Usunąć plik?\");'>[Usuń]</a></li>";
}
}
?>
</ul>
<?php endforeach; ?>
</body>
</html>
Podsumowanie
Stworzyliśmy prosty system wgrywania plików w PHP, który umożliwia:
- Przesyłanie plików graficznych do 1MB.
- Przesyłanie innych plików, np. TXT i PDF.
- Wyświetlanie listy przesłanych plików.
- Pobieranie i usuwanie plików z serwera.
W jego podstawowej wersji, pliki graficzne są uploadowane do folderu upload/images oraz pliki TXT i PDF do upload/other.
W rozszerzonej / zmodyfikowanej wersji, folder other i images zostały pominięte na rzecz folderu zawierającego datę wgrania plików na serwer, co polepsza indeksację ale jak wspomniałem wyżej, nie jest rozwiązaniem niezbędnym do funkcjonowania skryptu.
Podsumowując, teraz użytkownicy mogą w bezpieczny sposób przesyłać i zarządzać plikami na stronie.