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

Использование move_uploaded_file для загрузки файлов в PHP
Раздел: Загрузка файлов
move_uploaded_file(string $from, string $to): bool

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

Основное назначение и применение

Эта функция проверяет, является ли указанный файл действительно загруженным через механизм загрузки PHP (т.е. через форму с enctype='multipart/form-data'). Только после успешной проверки файл перемещается в указанное место. Она используется для сохранения загруженных пользователем файлов на сервере, например, изображений, документов или архивов.

Аргументы функции
  • from (string, обязательный): Временный путь к загруженному файлу, который хранится в глобальном массиве $_FILES['userfile']['tmp_name'].
  • to (string, обязательный): Путь назначения, куда файл должен быть перемещен. Должен включать имя файла. Если файл с таким именем уже существует, он будет перезаписан.
Простые примеры использования
Базовое перемещение файла

Код для обработки загруженного файла с именем 'avatar':

<?php
if ($_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
    $tmp_name = $_FILES['avatar']['tmp_name'];
    $destination = '/var/www/uploads/' . basename($_FILES['avatar']['name']);

    if (move_uploaded_file($tmp_name, $destination)) {
        echo "Файл успешно загружен.";
    } else {
        echo "Не удалось переместить файл.";
    }
}
?>
Результат при успехе: Файл успешно загружен.
Результат при неудаче (например, если файл не был загружен через POST): Не удалось переместить файл.
Создание уникального имени файла
<?php
$upload_dir = 'uploads/';
$original_name = $_FILES['document']['name'];
$extension = pathinfo($original_name, PATHINFO_EXTENSION);
$new_filename = uniqid('doc_') . '.' . $extension;
$destination = $upload_dir . $new_filename;

if (move_uploaded_file($_FILES['document']['tmp_name'], $destination)) {
    echo "Файл сохранен как: " . htmlspecialchars($new_filename);
}
?>
Результат: Файл сохранен как: doc_5f2a1b3c4d5e6.pdf
Похожие функции в PHP
  • copy(): Копирует файл. Не проверяет, был ли файл загружен через HTTP POST. Используется для копирования любых существующих файлов на сервере.
  • rename(): Переименовывает или перемещает файл. Также не выполняет проверок на безопасность загрузки. Подходит для работы с локальными файлами файловой системы.
  • is_uploaded_file(): Проверяет, был ли файл загружен через HTTP POST. Эта проверка встроена в move_uploaded_file(). Её можно использовать отдельно для дополнительной валидации перед другими операциями.

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

Аналоги в других языках программирования
Python (с использованием Flask)
from flask import Flask, request
import os

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return 'No file part'
    file = request.files['file']
    if file.filename == '':
        return 'No selected file'
    if file:
        filename = os.path.join('uploads', file.filename)
        file.save(filename)
        return 'File uploaded successfully'
Метод .save() объекта файла сохраняет его на диск. Проверки выполняются вручную.
JavaScript (Node.js с помощью Express и multer)
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

const app = express();

app.post('/upload', upload.single('avatar'), (req, res) => {
    // Файл уже сохранен в 'uploads/' с временным именем.
    // Дальнейшая обработка, например, переименование.
    res.send('File uploaded!');
});
Middleware multer автоматически обрабатывает загрузку и сохраняет файл в указанную директорию.
Основное отличие

В PHP функция move_uploaded_file() совмещает проверку и перемещение. В других языках эти этапы часто разделены: сначала промежуточное ПО или библиотека валидирует загрузку, а затем файл сохраняется стандартными средствами работы с файловой системой.

Типичные ошибки
1. Отсутствие проверки ошибки загрузки
<?php
// ОШИБКА: Не проверяется $_FILES['file']['error']
$tmp_name = $_FILES['file']['tmp_name'];
move_uploaded_file($tmp_name, 'uploads/file.txt'); // Может потерпеть неудачу
?>
Если загрузка изначально не удалась (например, превышен размер), то move_uploaded_file вернет false, а исходный файл может не существовать.
2. Отсутствие проверки существования директории
<?php
// ОШИБКА: Директория 'my_uploads' может не существовать
move_uploaded_file($_FILES['img']['tmp_name'], 'my_uploads/new.jpg');
?>
Функция вернет false, и в логах ошибок появится предупреждение.
3. Небезопасное использование имени оригинального файла
<?php
// ОШИБКА: Использование оригинального имени без проверки
$dest = 'uploads/' . $_FILES['file']['name']; // Может содержать '../' или опасные символы
move_uploaded_file($_FILES['file']['tmp_name'], $dest);
?>
Это может привести к перезаписи системных файлов или сохранению файлов за пределами целевой директории.
Рекомендация

Всегда проверяйте код ошибки $_FILES['...']['error'], создавайте целевую директорию при необходимости с помощью is_dir() и mkdir(), а также генерируйте безопасное имя файла.

Изменения в последних версиях PHP

Поведение функции move_uploaded_file() остается стабильным. В PHP 8.0 повысилась строгость типов, но сигнатура функции не изменилась: оба аргумента по-прежнему ожидают строку (string).

  • В PHP 8.0, если передать аргумент нестрокового типа, будет вызвана ошибка TypeError. В более ранних версиях PHP могло произойти автоматическое приведение к строке.
  • Критических изменений в логике работы функции в последних основных версиях (PHP 7.4, 8.0, 8.1, 8.2, 8.3) не было.

Важно отметить, что общие настройки, связанные с загрузкой файлов (такие как upload_max_filesize, post_max_size и file_uploads), могут влиять на доступность функции.

Расширенные примеры
1. Загрузка с изменением размера изображения (с использованием GD)
Пример php
<?php
if (is_uploaded_file($_FILES['photo']['tmp_name'])) {
    $tmp_path = $_FILES['photo']['tmp_name'];
    $img_info = getimagesize($tmp_path);

    if ($img_info && $img_info['mime'] == 'image/jpeg') {
        $image = imagecreatefromjpeg($tmp_path);
        $thumb = imagescale($image, 150);
        imagedestroy($image);

        $dest_path = 'uploads/thumb_' . time() . '.jpg';
        // Сохраняем миниатюру
        imagejpeg($thumb, $dest_path);
        imagedestroy($thumb);

        // Оригинал тоже можно переместить
        move_uploaded_file($tmp_path, 'uploads/fullsize/' . $_FILES['photo']['name']);
        echo "Изображение обработано и сохранено.";
    }
}
?>
Создается миниатюра изображения, а оригинальный файл сохраняется в отдельной папке.
2. Загрузка нескольких файлов с валидацией MIME-типа
Пример php
<?php
$allowed_types = ['application/pdf', 'image/png'];
$upload_dir = 'docs/';

foreach ($_FILES['documents']['tmp_name'] as $key => $tmp_name) {
    $file_type = mime_content_type($tmp_name);
    if (!in_array($file_type, $allowed_types)) {
        continue; // Пропускаем неразрешенные типы
    }
    $safe_name = md5_file($tmp_name) . '_' . basename($_FILES['documents']['name'][$key]);
    $destination = $upload_dir . $safe_name;
    move_uploaded_file($tmp_name, $destination);
}
echo "Разрешенные файлы загружены.";
?>
Файлы проверяются по реальному MIME-типу и сохраняются с именем, включающим хэш содержимого для уникальности.
3. Логирование результата загрузки
Пример php
<?php
function log_upload($filename, $success) {
    $log_entry = date('Y-m-d H:i:s') . ' - ' . $filename . ' - ' . ($success ? 'SUCCESS' : 'FAIL') . PHP_EOL;
    file_put_contents('upload.log', $log_entry, FILE_APPEND);
}

$dest = 'files/' . $_FILES['report']['name'];
if (move_uploaded_file($_FILES['report']['tmp_name'], $dest)) {
    log_upload($_FILES['report']['name'], true);
} else {
    log_upload($_FILES['report']['name'], false);
}
?>
Каждая попытка загрузки записывается в лог-файл с указанием времени, имени файла и статуса.

PHP move_uploaded_file function comments

En
Move uploaded file Moves an uploaded file to a new location