Is uploaded file: примеры (PHP)

Проверка загрузки файлов через HTTP POST с is_uploaded_file
Раздел: Загрузка файлов
is_uploaded_file(string $filename): bool
Описание функции is_uploaded_file

Функция is_uploaded_file() в PHP проверяет, был ли указанный файл загружен через HTTP POST (например, через форму с атрибутом enctype="multipart/form-data"). Эта проверка является важной мерой безопасности, которая позволяет убедиться, что скрипт работает именно с загруженным пользователем файлом, а не с локальным файлом, путь к которому мог быть подделан.

Функция используется в процессе обработки загруженных файлов, обычно перед перемещением файла из временного каталога в постоянное место назначения с помощью функции move_uploaded_file().

Аргументы функции

Функция принимает один обязательный аргумент:

  • string $filename - путь к проверяемому файлу. Обычно это значение элемента $_FILES['userfile']['tmp_name'].

Возвращаемое значение: bool - true, если файл был загружен через HTTP POST, и false в противном случае.

Примеры использования is_uploaded_file
Базовый пример проверки одного файла
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $tmpFile = $_FILES['avatar']['tmp_name'];
    
    if (is_uploaded_file($tmpFile)) {
        echo "Файл был корректно загружен через POST.";
    } else {
        echo "Файл не был загружен через POST.";
    }
}
?>
// Если файл загружен через форму:
Файл был корректно загружен через POST.

// Если переменная $tmpFile указывает на локальный файл, например, '/etc/passwd':
Файл не был загружен через POST.
Пример в контексте полной обработки загрузки
<?php
if (isset($_FILES['document'])) {
    $uploadDir = 'uploads/';
    $tmpName = $_FILES['document']['tmp_name'];
    $finalName = $uploadDir . basename($_FILES['document']['name']);

    if (is_uploaded_file($tmpName)) {
        if (move_uploaded_file($tmpName, $finalName)) {
            echo "Файл успешно загружен и перемещен.";
        } else {
            echo "Ошибка перемещения файла.";
        }
    } else {
        echo "Возможная атака: файл не был загружен через POST.";
    }
}
?>
Похожие функции в PHP

move_uploaded_file() - не только проверяет, был ли файл загружен через POST, но и безопасно перемещает его в новое место. Это предпочтительная функция для финального сохранения загруженного файла, так как она включает в себя внутреннюю проверку is_uploaded_file(). Использовать is_uploaded_file() отдельно имеет смысл, если нужна только проверка без немедленного перемещения, либо для дополнительного логирования.

file_exists() - проверяет существование файла или каталога на диске, но не проверяет его происхождение. Она не является безопасной заменой, так как вернет true для любого существующего локального файла.

Типичные ошибки
Проверка не временного имени файла
<?php
// ОШИБКА: Передается имя файла, а не временный путь.
if (is_uploaded_file($_FILES['file']['name'])) { // Неправильно
    // ...
}

// ПРАВИЛЬНО: Передается временный путь к файлу.
if (is_uploaded_file($_FILES['file']['tmp_name'])) { // Правильно
    // ...
}
?>
Игнорирование ошибок загрузки
<?php
// ОШИБКА: Проверка без предварительного анализа ошибки загрузки.
if (is_uploaded_file($_FILES['file']['tmp_name'])) {
    move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/file.txt');
}
// Если $_FILES['file']['error'] !== UPLOAD_ERR_OK, файл может быть не загружен.

// ПРАВИЛЬНО: Сначала проверяем код ошибки.
if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
    if (is_uploaded_file($_FILES['file']['tmp_name'])) {
        // ...
    }
}
?>
Проверка после перемещения файла
<?php
move_uploaded_file($tmpFile, $destination);
// ОШИБКА: Проверка после перемещения. Файла во временном каталоге уже нет.
if (is_uploaded_file($tmpFile)) { // Всегда false
    echo "Этот код никогда не выполнится.";
}
?>
Изменения в функции

Поведение функции is_uploaded_file() оставалось стабильным на протяжении многих версий PHP. В PHP 8.0 не было внесено значительных изменений, влияющих на ее работу. Основной принцип проверки файлов, загруженных через HTTP POST, не менялся с версии PHP 4.0.3. Всегда важно учитывать, что функция работает в связке с настройками php.ini, такими как file_uploads, upload_tmp_dir, upload_max_filesize и max_file_uploads.

Расширенные примеры
Проверка нескольких загруженных файлов
Пример php
<?php
if (!empty($_FILES['images']['name'][0])) {
    $uploadDir = 'uploads/';
    
    foreach ($_FILES['images']['tmp_name'] as $key => $tmpName) {
        // Проверяем каждый файл на ошибку загрузки
        if ($_FILES['images']['error'][$key] !== UPLOAD_ERR_OK) {
            echo "Ошибка загрузки файла {$_FILES['images']['name'][$key]}
"; continue; } // Проверяем, что файл действительно загружен через POST if (is_uploaded_file($tmpName)) { $safeName = $uploadDir . basename($_FILES['images']['name'][$key]); if (move_uploaded_file($tmpName, $safeName)) { echo "Файл {$_FILES['images']['name'][$key]} успешно сохранен.
"; } } else { echo "Файл {$_FILES['images']['name'][$key]} не прошел проверку безопасности.
"; } } } ?>
Логирование попыток небезопасного доступа
Пример php
<?php
$tmpFile = $_FILES['report']['tmp_name'];
$logFile = 'security.log';

if (!is_uploaded_file($tmpFile)) {
    $message = date('Y-m-d H:i:s') . 
               " | Попытка обработки не загруженного файла: " . 
               htmlspecialchars($tmpFile) . PHP_EOL;
    file_put_contents($logFile, $message, FILE_APPEND);
    die("Ошибка безопасности: недопустимый источник файла.");
}
// ... дальнейшая обработка безопасного файла
?>
Проверка перед выполнением дополнительных операций
Пример php
<?php
$tmpFile = $_FILES['config']['tmp_name'];

if (is_uploaded_file($tmpFile)) {
    // Можно безопасно получить MIME-тип для дополнительной валидации
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime = finfo_file($finfo, $tmpFile);
    finfo_close($finfo);
    
    $allowedMimes = ['text/plain', 'application/json'];
    
    if (in_array($mime, $allowedMimes)) {
        // Чтение содержимого для анализа
        $content = file_get_contents($tmpFile);
        echo "Содержимое файла безопасно для обработки.";
    } else {
        echo "Запрещенный тип файла.";
    }
}
?>
Аналоги в других языках программирования
Python (с использованием Flask)

В Python нет прямой аналогии, так как фреймворки сами управляют загруженными файлами. Файл становится доступен только после прохождения валидации фреймворком.

from flask import Flask, request, flash
import os

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        flash('No file part')
        return redirect(request.url)
    file = request.files['file']
    # Файл, полученный через request.files, уже является объектом загрузки
    if file.filename == '':
        flash('No selected file')
        return redirect(request.url)
    if file:
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        return 'File uploaded successfully'
JavaScript (Node.js с Express и Multer)

В Node.js middleware Multer обрабатывает загрузку файлов, и проверка на «загруженность» осуществляется самим middleware до передачи файла в роут.

const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

const app = express();

app.post('/profile', upload.single('avatar'), (req, res) => {
    // Файл в req.file доступен только если Multer успешно его загрузил
    if (!req.file) {
        return res.status(400).send('No file uploaded.');
    }
    res.send('File uploaded!');
});

В отличие от PHP, где разработчик должен явно вызвать проверку, в этих языках и фреймворках валидация происхождения файла инкапсулирована в механизме обработки запросов.

PHP is_uploaded_file function comments

En
Is uploaded file Tells whether the file was uploaded via HTTP POST