↩️ Назад

Категории

upload.php — загрузка файлов

24.04.2026 | коды из категории: php

🔐 Защита: сессия админа + CSRF + белый список расширений (jpg/png/gif/webp/svg/ico) + MIME-проверка + лимит 5MB + безопасное имя файла
⚙️ Функции: загрузка изображений, список файлов, сортировка по дате
✅ Статус: безопасен (только для админов)

<?php
session_start();

if (!isset($_SESSION['user'])) {
    header("Location: login.php");
    exit;
}

// CSRF-токен
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

require '../includes/db.php';
include '../includes/header.php';

$message = '';
$error = '';

// Обработка загрузки файла
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    
    // CSRF проверка
    if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        $error = "Ошибка безопасности: неверный токен";
    } else {
        
        $uploadDir = '../upload/';
        
        // Создаем папку upload, если ее нет
        if (!file_exists($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }
        
        // Запрещённые расширения
        $blocked_extensions = ['php', 'php3', 'php4', 'php5', 'phtml', 'phps', 'pl', 'py', 'cgi', 'sh', 'exe', 'bat', 'cmd', 'js'];
        
        // Разрешённые расширения (только изображения)
        $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'ico'];
        
        $originalName = basename($_FILES['file']['name']);
        $fileExt = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        
        // Проверка расширения
        if (!in_array($fileExt, $allowed_extensions)) {
            $error = "❌ Запрещённый тип файла. Разрешены только: " . implode(', ', $allowed_extensions);
        }
        
        // Проверка MIME-типа (дополнительный слой)
        if (empty($error)) {
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mime_type = finfo_file($finfo, $_FILES['file']['tmp_name']);
            finfo_close($finfo);
            
            $allowed_mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];
            
            if (!in_array($mime_type, $allowed_mimes)) {
                $error = "❌ Файл не является изображением. MIME-тип: " . htmlspecialchars($mime_type);
            }
        }
        
        // Проверка размера (максимум 5MB)
        if (empty($error) && $_FILES['file']['size'] > 5 * 1024 * 1024) {
            $error = "❌ Файл слишком большой. Максимум 5MB.";
        }
        
        // Генерируем безопасное имя файла
        if (empty($error)) {
            $safe_name = uniqid() . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '', $originalName);
            $targetPath = $uploadDir . $safe_name;
            
            // Проверка на существование файла
            if (file_exists($targetPath)) {
                $error = "Файл уже существует. Переименуйте и попробуйте снова.";
            } elseif (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) {
                $message = "✅ Файл успешно загружен: " . htmlspecialchars($safe_name);
            } else {
                $error = "❌ Ошибка при загрузке файла.";
            }
        }
    }
}

// Получаем список файлов с фильтрацией
$uploadDir = '../upload/';
$files = [];
$total_size = 0;

if (file_exists($uploadDir)) {
    $scanned = scandir($uploadDir);
    foreach ($scanned as $file) {
        if ($file !== '.' && $file !== '..') {
            $file_path = $uploadDir . $file;
            $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
            $is_image = in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'ico']);
            
            $files[] = [
                'name' => $file,
                'size' => filesize($file_path),
                'is_image' => $is_image,
                'modified' => date('d.m.Y H:i', filemtime($file_path))
            ];
            $total_size += filesize($file_path);
        }
    }
    // Сортируем по дате (новые сверху)
    usort($files, function($a, $b) {
        return $b['modified'] <=> $a['modified'];
    });
}
?>

<link rel="stylesheet" href="/css/adminka.css">
<style>
    .alert-info { background: #e3f2fd; padding: 10px; border-radius: 5px; margin: 10px 0; color: #0c5460; }
    .alert-error { background: #f8d7da; padding: 10px; border-radius: 5px; margin: 10px 0; color: #721c24; }
    .file-list { list-style: none; padding: 0; margin-top: 20px; }
    .file-list li { padding: 8px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; }
    .file-list li:hover { background: #f5f5f5; }
    .file-size { color: #666; font-size: 12px; }
    .file-icon { font-size: 20px; margin-right: 10px; }
    .total-size { margin-top: 10px; text-align: right; font-size: 12px; color: #666; }
    .allowed-extensions { background: #1e2a3a; padding: 8px 12px; border-radius: 8px; margin: 15px 0; font-size: 13px; color: #00d4ff; }
</style>

</head>
<body>
<div class="container">
    <?php include '../includes/admin_menu.php'; ?>
    
    <h2>📁 Загрузка файлов</h2>
    
    <div class="allowed-extensions">
        📸 Разрешённые форматы: JPG, JPEG, PNG, GIF, WEBP, SVG, ICO (максимум 5MB)
    </div>
    
    <?php if ($message): ?>
        <div class="alert-info"><?= htmlspecialchars($message) ?></div>
    <?php endif; ?>
    
    <?php if ($error): ?>
        <div class="alert-error"><?= htmlspecialchars($error) ?></div>
    <?php endif; ?>
    
    <form action="upload.php" method="post" enctype="multipart/form-data">
        <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
        
        <div class="form-group">
            <label for="file">Выберите изображение:</label>
            <input type="file" name="file" id="file" class="form-control" required accept="image/*">
        </div>
        <button type="submit" class="btn btn-primary">📤 Загрузить</button>
    </form>
    
    <h3>📂 Загруженные файлы</h3>
    
    <?php if (empty($files)): ?>
        <p>Нет загруженных файлов.</p>
    <?php else: ?>
        <ul class="file-list">
            <?php foreach ($files as $file): ?>
                <li>
                    <div>
                        <span class="file-icon"><?= $file['is_image'] ? '🖼️' : '📄' ?></span>
                        <a href="../upload/<?= htmlspecialchars($file['name'], ENT_QUOTES, 'UTF-8') ?>" target="_blank">
                            <?= htmlspecialchars($file['name'], ENT_QUOTES, 'UTF-8') ?>
                        </a>
                    </div>
                    <div>
                        <span class="file-size"><?= round($file['size'] / 1024, 1) ?> KB</span>
                        <span class="file-size"> • <?= $file['modified'] ?></span>
                    </div>
                </li>
            <?php endforeach; ?>
        </ul>
        <div class="total-size">
            📦 Всего файлов: <?= count($files) ?> | Общий размер: <?= round($total_size / 1024 / 1024, 2) ?> MB
        </div>
    <?php endif; ?>
    
    <p style="margin-top: 20px;">
        <a href="index.php">← Назад в админку</a>
    </p>
</div>

<?php include '../includes/footer.php'; ?>
</body>
</html>



Категории:

Категории

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Посетителей сегодня: 0
о блоге | карта блога | 📡 Подписаться на RSS

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA