Загрузка файлов на сайт с помощью PHP-скрипта

Сегодня я хочу рассказать вам о разнообразных ситуациях, в которых требуется загрузка файлов на сайт с помощью PHP-скриптов. Постараюсь привести примеры, как самой простой загрузки файла, так и мультизагрузки с применением move uploaded file PHP.

Простая загрузка файлов на сайт при помощи PHP

Вам не составит труда написать собственный PHP-скрипт для загрузки файлов на сервер. Прежде всего, нужно создать HTML-форму с полем file input. Затем привязать к ней PHP-скрипт, который переместит файл в указанную директорию. Чтобы закачать файл на сервер с помощью PHP-скрипта, выполните следующие действия:

Создайте простую HTML-форму: потребуется простая форма с возможностью указания файла. Она размещается в файле basic.php:

<html>
<head>
<title>Basic File Upload</title>
</head>
<body>
<h1>Basic File Upload</h1>
<form method="post" action="basic.php" enctype="multipart/form-data">
<label for="inputfile">Upload File</label>
<input type="file" id="inputfile" name="inputfile"></br>
<input type="submit" value="Click To Upload">
</form>
</body>
</html>

Приведенный выше код необходим для создания формы. Как только пользователь выбирает файл и нажимает кнопку Upload, форма передаст данные с помощью метода POST на этой же странице, так как в качестве обработчика указан файл basic.php:

Важно: не забудьте добавить enctype=”multipart/form-data” в тег <form>.

Простая загрузка файлов на сайт при помощи PHP

Создаем PHP-скрипт для обработки формы загрузки. В PHP вся информация о загруженных файлах содержится в глобальной переменной $_FILES. То есть, используя $_FILES, можно проверить, был ли загружен файл. Если файл был загружен, то можно переместить его в нужную директорию при помощи функции move_uploaded_file PHP:

<?php
if(isset($_FILES) && $_FILES['inputfile']['error'] == 0){ // Проверяем, загрузил ли пользователь файл
$destiation_dir = dirname(__FILE__) .'/'.$_FILES['inputfile']['name']; // Директория для размещения файла
move_uploaded_file($_FILES['inputfile']['tmp_name'], $destiation_dir ); // Перемещаем файл в желаемую директорию
echo 'File Uploaded'; // Оповещаем пользователя об успешной загрузке файла
}
else{
echo 'No File Uploaded'; // Оповещаем пользователя о том, что файл не был загружен
}
?>

Приведенный выше код проверяет, загрузил ли пользователь файл. Если файл загружен, то мы перемещаем файл в указанную директорию. В приведенном выше скрипте мы перемещаем файл в ту же папку, где находится файл basic.php.

Ниже приведена полная версия PHP move uploaded file примера:

<?php
if(isset($_FILES) && $_FILES['inputfile']['error'] == 0){ // Проверяем, загрузил ли пользователь файл
$destiation_dir = dirname(__FILE__) .'/'.$_FILES['inputfile']['name']; // Директория для размещения файла
move_uploaded_file($_FILES['inputfile']['tmp_name'], $destiation_dir ); // Перемещаем файл в желаемую директорию
echo 'File Uploaded'; // Оповещаем пользователя об успешной загрузке файла
}
else{
echo 'No File Uploaded'; // Оповещаем пользователя о том, что файл не был загружен
}
?>
<html>
<head>
<title>Basic File Upload</title>
</head>
<body>
<h1>Basic File Upload</h1>
<form method="post" action="basic.php" enctype="multipart/form-data">
<label for="inputfile">Upload File</label>
<input type="file" id="inputfile" name="inputfile"></br>
<input type="submit" value="Click To Upload">
</form>
</body>
</html>

Пожалуйста, не тестируйте этот PHP move uploaded file пример на сервере. Он не отвечает требованиям безопасности, и был создан специально для того, чтобы наглядно показать, как загружать файлы с помощью PHP.

Вопрос: Почему приведенный выше скрипт небезопасен?
Ответ: С помощью скрипта, приведенного выше, можно загрузить файл любого типа на сервер. То есть, если вы используете скрипт в таком виде на “живом” сервере, то любой хакер сможет загрузить собственные PHP-скрипты, и взломать ваш сайт и сервер.

Чуть позже мы подробнее поговорим о защите скрипта для загрузки файлов на сервер.

Что такое $_FILES?

$_FILES – это глобальная переменная в PHP наподобие $_POST или $_GET. Она представляет собой ассоциативный массив, в котором находится информация о загруженном файле с помощью метода HTTP POST.

То есть, если выполнить print_r($_FILES) для приведенного выше скрипта, то мы получим следующую информацию:

Array
(
    [inputfile] => Array
        (
            [name] => upload-file-php.jpg
            [type] => image/jpeg
            [tmp_name] => /Applications/XAMPP/xamppfiles/temp/phpcQiYhh
            [error] => 0
            [size] => 6887
        )
)

То есть, для каждого поля <input type=”file” name=”inputfile“/> в массиве создается элемент. Если вы создадите <input type=”file” name=”test”>, то название элемента также будет изменено на test. Например:

Array
(
    [test] => Array
        (
            [name] => upload-file-php.jpg
            [type] => image/jpeg
            [tmp_name] => /Applications/XAMPP/xamppfiles/temp/phpcQiYhh
            [error] => 0
            [size] => 6887
        )
)

Теперь для каждого input file, перемещаемого с помощью move uploaded file PHP, создается пять элементов (name, type, tmp_name, error, size). Давайте познакомимся с этими элементами поближе:

  1. name: содержит название загруженного пользователем файла. Если вы загрузите файл abc.txt в браузер, то элемент name получит название abc.txt;
  2. type: тип загруженного файла или mime-type, если точнее. Для файла JPG этот элемент будет иметь значение image/jpeg. Если загрузить текст, то элемент получит значение text/plain. Для разных типов файлов разным будет и mime-type. Ниже приведены самые распространенные mime-типы:
  • JPEG: image/jpeg;
  • PNG: image/png;
  • Текст: text/plain;
  • Word: application/msword.
  • tmp_name: временное расположение для загруженного файла. Этот путь можно изменить в переменной upload_tmp_dir, указанной в файле php.ini.
  • error: информация об ошибке. Включает в себя тип ошибки, возникшей в процессе загрузки. Например, когда размер файла превышает максимальный или когда не был указан файл для загрузки. Для любой возникшей ошибки имеется числовое значение и константа. Ниже приведен полный список ошибок, которые могут возникнуть в PHP move uploaded file примере:
  • UPLOAD_ERR_OK (значение 0). Означает, что файл был успешно загружен без ошибок;
  • UPLOAD_ERR_INI_SIZE (значение 1). Размер файла превышает указанный в переменной upload_max_filesize в файле php.ini;
  • UPLOAD_ERR_FORM_SIZE (значение 2). Размер файла превышает установленное в переменной формы MAX_FILE_SIZE значение;
  • UPLOAD_ERR_PARTIAL (значение 3). Файл загружен не полностью;
  • UPLOAD_ERR_NO_FILE (значение 4). Отсутствует файл для загрузки;
  • UPLOAD_ERR_NO_TMP_DIR (значение 6). Указанной директории для временного хранения не существует;
  • UPLOAD_ERR_CANT_WRITE (значение 7). Невозможно записать файл на диск.
  • size: размер загруженного файла в байтах.

Что такое move_uploaded_file?

move_uploaded_file представляет собой функцию, которая перемещает загруженный файл из временной директории в папку назначения. Перед перемещением move_uploaded_file PHP проверяет, был ли загружен файл, указанный в HTTP-методе post.

Если файл был успешно перемещен, то вы получите ответ true или false. В первом примере мы использовали следующую строку кода:

move_uploaded_file($_FILES['inputfile']['tmp_name'], $destiation_dir )

А теперь давайте сделаем красиво, и выведем информацию:

if(move_uploaded_file($_FILES['inputfile']['tmp_name'], $destiation_dir )){
echo "File Uploaded"
}
else{
echo "File Not uploaded"
}

Изменяем лимит размера загружаемого файла

У каждой формы для загрузки файлов должен быть установлен лимит размера, иначе пользователи станут загружать увесистые файлы. Выставить ограничение на move uploaded file PHP можно двумя способами:

  • В файле PHP.ini есть специальная переменная upload_max_filesize, которая отвечает за максимальный размер загружаемых файлов. Далее приведена строчка из php.ini, которая ограничивает размер загружаемых файлов до 20 Мб: upload_max_filesize = 20M.
  • Если загружаемый файл будет иметь больший размер, то пользователь получит ошибку UPLOAD_ERR_INI_SIZE или значение «2» в переменной $_FILES. Важно учесть, что значение переменной upload_max_filesize не должно превышать значение переменной post_max_size, указанной в php.ini;
  • Ограничить размер загружаемого файла можно, поместив скрытый элемент ввода с названием UPLOAD_ERR_INI_SIZE в форму загрузки. Сделать это можно так: <input type="hidden" name="MAX_FILE_SIZE" value="50000" />.

Если нужно сильно увеличить filesize, то не забудьте изменить время исполнения php-скриптов.

Как обезопасить PHP-скрипт загрузки файлов

Теперь вы умеете ограничивать размер загружаемых файлов и знаете, как определить типы файлов, которые загружают пользователи. Пришло время позаботиться о безопасности нашего PHP move uploaded file примера.

В качестве примера сделаем так, чтобы пользователи не могли загружать jpeg-файлы размером свыше 1 Мб. Установите соответствующее ограничение в переменной upload_max_filesize файла php.ini. Ниже приведена улучшенная версия скрипта:

<?php
ini_set('upload_max_filesize', '1M'); //ограничение в 1 мб
if ($_SERVER['REQUEST_METHOD'] == "POST" ) {
if ($_FILES['inputfile']['error'] == UPLOAD_ERR_OK && $_FILES['inputfile']['type'] == 'image/jpeg') { //проверка на наличие ошибок
$destiation_dir = dirname(__FILE__) . '/' . $_FILES['inputfile']['name']; // директория для размещения файла
if (move_uploaded_file($_FILES['inputfile']['tmp_name'], $destiation_dir)) { //перемещение в желаемую директорию
echo 'File Uploaded'; //оповещаем пользователя об успешной загрузке файла

} else {
echo 'File not uploaded';
}
} else {
switch ($_FILES['inputfile']['error']) {
case UPLOAD_ERR_FORM_SIZE:
case UPLOAD_ERR_INI_SIZE:
echo 'File Size exceed';
brake;
case UPLOAD_ERR_NO_FILE:
echo 'FIle Not selected';
break;
default:
echo 'Something is wrong';
}
}
}
?>
<html>
<head>
<title>Secure File Upload</title>
</head>
<body>
<h1>Secure File Upload</h1>
<form method="post" action="secure.php" enctype="multipart/form-data">
<label for="inputfile">Upload File</label>
<input type="file" id="inputfile" name="inputfile"></br>
<input type="submit" value="Click To Upload">
</form>
</body>
</html>

Мультизагрузка файлов при помощи PHP-скрипта

Можно загружать сразу несколько файлов при помощи $_FILES и move_uploaded_file PHP. Ниже я расскажу вам о двух способах мультизагрузки файлов с помощью PHP-скрипта

  1. Используя разные имена Input.
  2. Используя одно и то же имя input, но с привлечением массива.

1. Используя разные имена Input:

Можно загружать сразу несколько файлов, используя несколько элементов ввода. Как уже говорилось ранее, если мы создаем несколько элементов input, то в $_FILES будет создано несколько основных элементов. Например, для приведенной ниже формы:

<input type="file" id="profilepic" name="profilepic">
<input type="file" id="resume" name="resume">

$_FILES представит массив следующего содержания:

Array
(
    [profilepic] => Array
        (
            [name] => 20141002_094257.jpg
            [type] => image/jpeg
            [tmp_name] => /Applications/XAMPP/xamppfiles/temp/phpoBWrBZ
            [error] => 0
            [size] => 2669096
        )
    [resume] => Array
        (
            [name] => 20141002_094247.jpg
            [type] => image/jpeg
            [tmp_name] => /Applications/XAMPP/xamppfiles/temp/phpjwUmVZ
            [error] => 0
            [size] => 2207657
        )
)

Приведенный ниже PHP move uploaded file пример нужно писать с учетом того, что один элемент предназначен для аватарки (изображение), а другой – для загрузки резюме (файла в формате .doc):

<?php
if ($_SERVER['REQUEST_METHOD'] == "POST" ) {
if ($_FILES['profilepic']['error'] == UPLOAD_ERR_OK && $_FILES['profilepic']['type'] == 'image/jpeg') { // Проверяем на наличие ошибок
$destiation_dir = dirname(__FILE__) . '/' . $_FILES['profilepic']['name']; // Директория для размещения файла
if (move_uploaded_file($_FILES['profilepic']['tmp_name'], $destiation_dir)) { // Перемещаем файл в желаемую директорию
echo 'Profile Pic Uploaded'; // Оповещаем пользователя об успешной загрузке файла
} else {
echo 'Profile Pic not uploaded';
}
} else {
switch ($_FILES['profilepic']['error']) {
case UPLOAD_ERR_FORM_SIZE:
case UPLOAD_ERR_INI_SIZE:
echo 'Profile Pic Size exceed';
brake;
case UPLOAD_ERR_NO_FILE:
echo 'Profile Pic Not selected';
break;
default:
echo 'Something is wrong with Profile PIC';
}
}
if ($_FILES['resume']['error'] == UPLOAD_ERR_OK && $_FILES['resume']['type'] == ' application/msword') { // Проверяем на наличие ошибок
$destiation_dir = dirname(__FILE__) . '/' . $_FILES['resume']['name']; // Директория для размещения файла
if (move_uploaded_file($_FILES['resume']['tmp_name'], $destiation_dir)) { // Перемещаем файл в желаемую директорию
echo 'resume Uploaded'; // Оповещаем пользователя об успешной загрузке файла
} else {
echo 'resume not uploaded';
}
} else {
switch ($_FILES['resume']['error']) {
case UPLOAD_ERR_FORM_SIZE:
case UPLOAD_ERR_INI_SIZE:
echo 'resume Size exceed';
brake;
case UPLOAD_ERR_NO_FILE:
echo 'resume Not selected';
break;
default:
echo 'Something is wrong with resume';
}
}
}
?>
<html>
<head>
<title>Multiple File Upload</title>
</head>
<body>
<h1>Multiple File Upload</h1>
<form method="post" action="multiple.php" enctype="multipart/form-data">
<label for="profilepic">Profile Pic</label>
<input type="file" id="profilepic" name="profilepic"></br>
<label for="resume">Resume</label>
<input type="file" id="resume" name="resume"></br>
<input type="submit" value="Click To Upload">
</form>
</body>
</html>

2. Используем одно поле input, но с применением массива:

Как и в случае с другими типами input, для move uploaded file PHP мы можем использовать массив с input type, указанным в php. То есть:

<input type="file" id="pic" name="pic[]">
<input type="file" id="pic" name="pic[]">
<input type="file" id="pic" name="pic[]">

То есть, для приведенного выше HTML, $_FILES предоставит данные со следующей структурой:

Array
(
    [pic] => Array
        (
            [name] => Array
                (
                    [0] => upload-file-php.jpg
                    [1] => variable-scope-php.jpg
                    [2] => magic-constants.jpg
                )
            [type] => Array
                (
                    [0] => image/jpeg
                    [1] => image/jpeg
                    [2] => image/jpeg
                )
            [tmp_name] => Array
                (
                    [0] => /Applications/XAMPP/xamppfiles/temp/phpML5kOy
                    [1] => /Applications/XAMPP/xamppfiles/temp/phpNZbuw7
                    [2] => /Applications/XAMPP/xamppfiles/temp/phpO8VFAk
                )
            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                    [2] => 0
                )
            [size] => Array
                (
                    [0] => 6887
                    [1] => 8036
                    [2] => 9967
                )
        )
)

Скачать код, использованный в статье