webmaster fronten developer pracuje nad strona

Wgrywanie plików na serwer w PHP – system uploadu plików

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.