Передать файлы через ajax
Все течет, все меняется, но только input[type=file] как портил нервы всем начинающим веб-разработчикам, так и продолжает это делать до сих пор. Вспомните себя N лет назад, когда вы только начинали постигать азы создания веб-сайтов. Молодой и неопытный, вы искренне удивлялись, когда кнопка выбора файла напрочь отказывалась менять цвет своего фона на ваш любимый персиковый. Именно в тот момент вы впервые столкнулись с этим несокрушимым айсбергом под названием «Загрузка файлов», который и по сей день продолжает «топить» начинающих веб-разработчиков.
На примере создания поля для загрузки файлов я покажу вам, как правильно прятать input[type=file] , настраивать фокус на объекте, у которого фокуса быть не может, обрабатывать события Drag-and-Drop и отправлять файлы через AJAX. А также я познакомлю вас с парой браузерных багов и путями их обхода. Статья написана для новичков, но в некоторых моментах может быть полезна и занимательна даже для матерых разработчиков.
Настраиваем фокус
Так как наш input[type=file] физически присутствует на страницу, он имеет возможность получать фокус. То есть, если мы будем нажимать на странице клавишу Tab , то в какой-то момент фокус перейдет на input[type=file] . Но проблема в том, что мы этого не увидим: выделяться будет поле, которое мы скрыли. Да, если в этот момент мы нажмем Enter , то диалоговое окно откроется и все будет работать как надо, вот только как мы поймем, что нажимать уже пора?
Наша задача — определенным образом выделить метку в момент, когда фокус расположен на поле загрузки файлов. Но как нам это сделать, если метка получать фокус не может? Знатоки CSS3 сразу же подумают о псевдоклассе :focus , который определяет стили для элементов в фокусе, и селекторах + или ~ , которые выбирают правых соседей: элементы, расположенные на том же уровне вложенности, идущие после выбранного элемента. Если учесть, что в нашей разметке input[type=file] расположен прямо перед тэгом label , имеет место быть следующая запись:
Но опять же, не все так просто. Для начала давайте обсудим, каким образом нам следует выделить метку. Как известно, все современные и не очень браузеры имеют уникальные свойства по умолчанию для элементов в фокусе. В основном, это свойство outline , которое создает вокруг элемента обводку, отличающуюся от border тем, что не изменяет размер элемента и может быть отодвинута от него. Как правило, люди пользуются только одним браузером, поэтому привыкают именно к его стандартам. Чтобы людям было проще ориентироваться на нашем сайте, мы должны постараться настроить фокус так, чтобы он выглядел максимально естественно для большинства популярных современных браузеров. В теории, с помощью JavaScript можно получить информацию о том, через какой браузер пользователь открыл сайт, и в соответствии с этим настроить стили, но в рамках статьи, предназначенной в первую очередь для новичков, эта тема слишком сложна и громоздка. Постараемся обойтись малой кровью.
В браузерах, основанных на движке WebKet (Google Chrome, Operа, Safari), свойство по умолчанию для элементов в фокусе имеет вид:
Здесь -webkit-focus-ring-color — специфичный только для данного движка цвет фокусной обводки. То есть, эта строчка будет работать исключительно в WebKit-браузерах, а это именно то, что нам нужно. Укажем данное свойство для нашей метки:
Открываем Google Chrome или Opera, смотрим. Все работает как надо:
Посмотрим, как обстоят дела с фокусом в Mozilla Firefox и Microsoft Edge. Для этих браузеров свойство по умолчанию имеет вид:
К сожалению, префикс -moz- со свойством outline работать не будет. Поэтому нам придется выбирать, какое из этих двух свойств мы выберем. Так как количество пользователей Firefox значительно выше, рациональнее отдать предпочтение именно этому браузеру. Это не значит, что мы лишим пользователей Edge и других браузеров возможности видеть, где сейчас фокус, просто он у них будет выглядеть «неродным». Что ж, приходится идти на жертвы.
Добавляем стиль из Mozilla Firefox перед стилем для WebKit: сначала все браузеры применят первое свойство, а затем те, которые могут (Google Chrome, Opera, Safari и др.), применят второе.
И вот тут начинается странное: в Edge все работает нормально, а вот Firefox по каким-то неведомым причинам отказывается применять свойства к метке при фокусе на input[type=file] . Причем само событие focus случается — проверил через JavaScript. Более того, если принудительно установить фокус на поле выбора файла через инструменты разработчика, то свойство применится и наша обводка появится! Видимо, это баг самого браузера, но если у кого-то есть идеи, почему такое происходит — пишите в комментариях.
Ну ничего, нормальные герои всегда идут в обход. Как я сказал ранее, событие focus случается, а значит, регулировать свойства мы можем прямиком из JavaScript. Но для этого нам придется поменять логику нашего селектора:
Опишем класс .focus для нашей метки и будем добавлять его каждый раз, когда input[type=file] получает фокус и убирать, когда теряет.
Теперь все работает как надо. Поздравляю, с фокусом мы разобрались.
Суть задачи
Для нетерпеливых сразу ссылки на демо приложения и исходники
Подготовим шаблон проекта.
В корень проекта положим файл index.html, в папку js файлы jquery.min.js и main.js (не забудем их подключить в index.html). Серверный код будет выполнять upload.php из папки php, а для полученных файлов создадим папку upload.
Получится так:
Drag-and-Drop
Работа с Drag-and-Drop осуществляется путем отслеживания специальных браузерных событий: drag, dragstart, dragend, dragover, dragenter, dragleave, drop . Подробное описание каждого из них вы с легкостью сможете найти в интернете. Мы будем отслеживать только некоторые из них.
Для начала определим Drag-and-Drop-элемент:
Затем опишем в CSS специальный класс, который будем присваивать dropZone , когда курсор, тянущий файл, будет прямо над ним. Это нужно, чтобы визуально проинформировать пользователя о том, что файл уже можно отпустить.
Теперь перейдем в JS-файл. Для начала, нам необходимо отменить все действия по умолчанию на события Drag-and-Drop. Например, одно из таких событий — открытие кинутого файла браузером. Нам это совершенно не нужно, поэтому пропишем следующие строчки:
В jQuery вызов оператора return false эквивалентен вызову сразу двух функций: e.preventDefault() и e.stopPropagation() .
Начнем описывать свой собственный обработчик событий. Поступим так же, как делали с фокусом, но на этот раз будем отслеживать события dragenter и dragover для добавления класса и событие dragleave для его удаления:
А происходит это мерцание из-за того, что при наведении курсора на дочерний элемент dropZone , будь то картинка или div с полем выбора файлов и меткой, по какой то причине срабатывает событие dragleave . Нам очевидно, что поле мы не покидаем, а вот браузерам, почему-то, нет, и из-за этого они без зазрения совести убирают класс .focus у dropZone .
И вновь нам придется как-то выкручиваться. Если браузер сам не понимает, что поле мы не покидаем, придется ему помочь. А делать мы это будем через дополнительные условия: вычислим координаты мыши относительно dropZone , а затем проверим, вышел ли курсор за пределы блока. Если вышел, значит убираем стиль:
И все, проблема решена! Вот так выглядит наше поле с файлом внутри:
Переходим к обработке самого события drop . Но для начала вспомним, что, помимо Drag-and-Drop, у нас есть input[type=file] , и каждый из этих способов независим по своей сути, но должен выполнять одинаковые действия: загружать файлы. Поэтому я предлагаю создать отдельную универсальную для обоих методов функцию, в которую мы будем передавать файлы, а она уже будет решать, что с ними сделать. Назовем ее sendFiles() , но опишем чуть позже. Для начала обработаем событие drop :
Сначала уберем класс .dragover у dropZone . Затем получим массив, содержащий файлы. Если вы используете jQuery, то путь будет e.originalEvent.dataTransfer.files , если пишите на чистом JS, то e.dataTransfer.files . Ну а затем передаем массив в нашу пока еще нереализованную функцию.
Теперь проработаем способ загрузки через input[type=file] :
Отслеживаем событие change на кнопке выбора файлов, получаем массив через this.files и отправляем его в функцию.
Базовый клиентский код
Мы создали модуль приложения app, и в методе init подключили обработку сабмита формы. В функции submitForm данные для отправки готовятся с помощью объекта formdata соответствующего класса FormData. Перебирая все поля выбора файлов .js-photos, мы добавляем файлы к этому объекту методом append. Обратите внимание на название photos[] - квадратные скобки обязательны, так как в противном случае на сервер попадет не массив файлов, а только один.
Валидацию пока не делаем, рассмотрим ее ниже. А пока переходим к серверной части.
27 Answers 27
File upload is not possible through AJAX.
You can upload file, without refreshing page by using IFrame .
You can check further details here.
Принимаем файлы на сервере и перемещаем в нужную папку
Код обработки файлов на сервере довольно типовой, сначала привожу его, а потом кратко поясню
Сначала мы извлекаем массив файлов из $_FILES['photos'] и отпределяем папку назначения - куда мы копируем искомые файлы. PHP предварительно копирует файлы во временную папку, свойство tmp_name из $_FILES даст нам полный путь к этому временному файлу. Далее перебираем наш массив и перемещаем файлы в нужную папку под тем же названием, с которым он пришел с клиента. Этим занимается функция move_uploaded_file. В конце возвращаем клиенту успешный код ответа.
AJAX Загрузка файлов: пример для WordPress
Для WordPress обрабатывать AJAX запрос в разы проще, потому что есть готовые функции, например media_handle_upload().
Первый и второй шаг аналогичные, а в третьем шаге будем использовать встроенную функцию, которая добавит файл в медиатеку и привяжет его к текущему посту.
Чтобы код ниже начал работать, его нужно добавить в файл темы functions.php . Далее, создать страницу с ярлыком ajax_file_upload и зайти на эту страницу. В контенте вы увидите форму для добавления файла. Выбираете файлы и проверяете все ли загрузилось.
Это полноценный пример того, как безопасно загрузить файлы на сервер в среде WordPress.
Но мы сделаем интереснее, отправим файлы с помощью ajax, без перезагрузки страницы. А также посмотрим, как валидировать файлы на клиенте и сервере, а именно проверять максимальный размер загружаемых файлов и допустимые расширения.
Валидация файлов на сервере
Вообще для посетителей сайта будет срабатывать клиентская валидация. Тем самым наши посетители получат мгновенную обратную связь, а сервер освободится от ненужной работы. Но в случае получения пользовательских данных всегда нужно проводить дополнительную валидацию на стороне сервера. Этим мы и займемся.
php-шная функция валидации будет проверять ровно те же параметры, что и клиентская. Но кроме двух пунктов: проверки на наличие файла и возврат индекса. Это связано с тем, что мы проверяем все файлы пришедшие с клиента и не знаем, что некоторые клиент мог не заполнить. Лучше увидеть на примере. Напишем саму функцию
Обращаю внимание, что для синхронизации клиента и сервера в обеих функциях валидации используется одинаковый формат объекта-ошибки и коды ошибок. Это облегчит нам обработку ошибок в интерфейсе независимо от того, сработала ли валидация клиентская или серверная.
После этого остается использовать написанную функцию в основном коде
Вот и все. Как видим, валидация на сервере подключена ровно таким же способом, как и на клиенте.
Чтобы убедиться, что и серверная валидация успешно работает, закомментируйте одну строку в main.js
Например, если Вы пропустите первое поле, во второе загрузите pdf-ку, а в третье - валидную картинку, то увидите примерно такую картину
Разметка и первичные стили
Начнем с HTML-разметки:
Пожалуй, главным элементом, на который стоит обратить внимание, является
Спецификация HTML не позволяет нам накладывать визуальные свойства непосредственно на input[type=file] , но мы имеем тэг label , нажатие на который вызывает клик по элементу формы, к которому он привязан. К нашей радости, данный тэг никаких ограничений в стилизации не имеет: мы можем делать с ним все, что захотим.
Вырисовывается план действий: стилизуем метку как нам угодно, а сам input[type=file] прячем с глаз долой. Для начала настроим общие стили страницы:
Теперь стилизуем нашу метку:
То, к чему мы стремимся ( input[type=file] убран из разметки):
Безусловно, можно было отцентровать метку, добавить фон и границу, получив полноценную кнопку, но наш приоритет — Drag-and-Drop.
Шаг 3. Обрабатываем запрос: загружаем файлы на сервер
Теперь последний шаг: нужно обработать отправленный запрос.
Чтобы было наглядно обработаем запрос без дополнительных проверок для файлов, т.е. просто сохраним полученные файлы в нужную папку. Хотя, для безопасности, отправляемые файлы обязательно нужно проверять, хотя бы расширение (тип) файла.
Создадим файл submit.php с таким кодом (предполагается что submit.php лежит в той же папке, где и файл, с которого отправляется AJAX запрос):
Важно! Этот код только показывает как получать и сохранять файлы. В действительности, вам нужно проверить форматы принимаемых файлов, их размер, транслитерировать кириллические названия и возможно делать какие-то еще проверки.
Чтобы не собирать по частям вышеописанный код загрузки, предлагаю его скачать.
Скопируйте содержимое архива на ваш php сервер, зайдите в главную паку (в браузере) и попробуйте загрузить файлы. Так, вы «в живую» увидите что и как работает.
Отправка файлов через AJAX
Последний этап — описание функции обработки файлов — уникален для всех и каждого. Он будет прямым образом зависеть от той цели, которую вы преследуете. Для примера я покажу, как отправлять файлы на сервер через AJAX.
В переменную maxFileSize занесем максимальный размер файла, который будем отправлять на сервер. Функцией FormData() мы создадим новый объект класса FormData , позволяющий формировать наборы пар ключ-значение. Такой объект можно легко отправлять через AJAX. Далее используем jQuery конструкцию .each для массива files , которая применит заданную нами функцию для каждого его элемента. В качестве аргументов в функцию будут передаваться порядковый номер элемента и сам элемент, которые мы будем обрабатывать как index и file соответственно. В самой функции мы проверим файл на соответствие нашим критериям: размер меньше пяти мегабайт, а тип — PNG или JPEG. Если файл проходит проверку, то добавляем его в наш объект FormData путем вызова функции append() . Ключом послужит строка 'photos[]' , квадратные скобки на конце которой обозначат, что это массив, в котором может быть несколько объектов. Самим объектом будет file .
Теперь все готово для отправки файлов через AJAX. Добавим в нашу функцию следующие строчки:
Поздравляю, теперь вы умеете создавать свое собственное поле загрузки файлов! Конечно же, я не позиционирую свой способ как единственно верный и правильный. Своей задачей я ставил показать общий ход решения данной задачи, подходящий в первую очередь для новичков. Если вы считаете, что где-то что-то можно было сделать лучше — пишите в комментариях, обсудим!
Can I use the following jQuery code to perform file upload using POST method of an ajax request ?
If it is possible, do I need to fill data part? Is it the correct way? I only POST the file to the server side.
I have been googling around, but what I found was a plugin while in my plan I do not want to use it. At least for the moment.
UPDATE
With XHR2, File upload through AJAX is supported. E.g. through FormData object, but unfortunately it is not supported by all/old browsers.
FormData support starts from following desktop browsers versions.
- IE 10+
- Firefox 4.0+
- Chrome 7+
- Safari 5+
- Opera 12+
For more detail, see MDN link.
@Synexis no we don't have to wait that long any more because all IE only has a 22% world wide market share and 27% in the U.S. and dropping fast. Chances are it is people over 70 years old. So rather then IE dictating what developers have to do IE will either have to shape up or get out of the race.
@DrewCalder Most IE users are office workers who don't have the choice on which browser to use because of company policies. I don't think age has much to do with it. I'm guessing most people > 70 get their offspring to install Chrome or FF instead :)
This link really helped me in understanding the bare minimum. I didn't have to use a xhr request. If you do use ajax make sure to set the enctype to "form/multipart" !
Iframes is no longer needed for uploading files through ajax. I've recently done it by myself. Check out these pages:
Updated the answer and cleaned it up. Use the getSize function to check size or use getType function to check types. Added progressbar html and css code.
How to use the Upload class
Progressbar html code
Progressbar css code
You can more or less copy the code straight off and use it. Just change some id names and class names. Any customation is on your own.
Note that myXhr seems to be global as well as name, size and type. Also it's better to use "beforeSend" to augment the already created XMLHttpRequest object rather than using "xhr" to create one then change it.
I don't think we can use that as is @Ziinloader. You're using some local method that's not included: writer(catchFile) . What is writer() ?
@Ziinloader This is a tremendously useful example that I see you've come back to and maintained several times. Truly an answer worth much more than the one upvote I can give.
Ajax post and upload file is possible. I'm using jQuery $.ajax function to load my files. I tried to use the XHR object but could not get results on the server side with PHP.
For the PHP process you can use something like this:
I was really struggling with this. After hours of researching and so forth, I found this that really helped. Thanks mate! The first part of your solution worked like a charm for me. That's exactly what I needed :-)
Simple Upload Form
@FrenkyB and others - the files on the server (in PHP) are not stored in the $_POST variable - they are stored in the $_FILES variable. In this case, you would access it with $_FILES["csv"] because "csv" is the name attribute of the input tag.
I'm pretty late for this but I was looking for an ajax based image uploading solution and the answer I was looking for was kinda scattered throughout this post. The solution I settled on involved the FormData object. I assembled a basic form of the code I put together. You can see it demonstrates how to add a custom field to the form with fd.append() as well as how to handle response data when the ajax request is done.
In case you are working with php here's a way to handle the upload that includes making use of both of the custom fields demonstrated in the above html.
@colincameron thank you for clarify a few things i did go through the it line by line and i dont really understand much so i asked the question so that someone might clarify my doubts. I am using local by way xampp to be exact. Can i ask a question that maybe you can clarify?
@Brownman Revival : I know that its too late for the reply.. You got a cross origin error because you opened the html file as file than running it from the server.
This seems to be relatively new, so please do not mention file upload would be impossible via XHR/Ajax, because it's definitely working.
I need the functionality in Safari 5, FF and Chrome would be nice but are not essential.
My code for now is:
@RameshwarVyevhare That answer was posted five years after this question was answered. Please don't troll similar questions just to promote your own answers.
Шаг 1. Данные из поля file
Первым шагом, нужно получить данные загружаемых файлов.
При клике на file-поле, появляется окно выбора файлов, после выбора, данные о них сохраняются в input поле, а нам нужно их от туда «забрать». Для этого повесим на событие change JS функцию, которая будет сохранять имеющиеся данные file-поля в JS переменную files :
AJAX Загрузка файлов: общий пример
Начинается все с наличия на сайте input поля типа file . Нет необходимости, чтобы это поле было частью формы (тега ).
Таким образом, у нас есть HTML код с file полем и кнопкой «Загрузить файлы».
Шаг 2. Создаем AJAX запрос (по клику)
В момент клика создаем новый объект new formData() и добавляем в него данные из переменной files . С помощью formData() мы добьемся того, что отправляемые данные будут выглядеть, как если бы мы просто сабмитили форму в браузере.
Далее, из имеющихся данных формы создаем нестандартный AJAX запрос, в котором передаем файлы в стандартном для сервера формате: $_FILES .
Чтобы такой запрос состоялся, в jQuery нужно указать дополнительные AJAX параметры, поэтому привычная функция $.post() не подходит и мы используем более гибкий аналог: $.ajax() .
Два важных дополнительных параметра нужно установить в false:
processData Отключает обработку передаваемых данных. По умолчанию, например, для GET запросов jQuery собирает данные в строку запроса и добавляет эту строку в конец URL. Для POST данных делает другие преобразования. Нам любые изменения исходных данных будут мешать, поэтому отключаем эту опцию. contentType Отключает установку заголовка типа запроса. Дефолтная установка jQuery равна "application/x-www-form-urlencoded . Такой заголовок не предусматривает отправку файлов. Если установить этот параметр в "multipart/form-data" , PHP все равно не сможет распознать передаваемые данные и выведет предупреждение «Missing boundary in multipart/form-data». В общем, проще всего отключить эту опция, тогда все работает!
html-заготовка формы
Создадим простейшую форму в index.html
Заметим, что никаких атрибутов, вроде enctype у формы или name у input-ов, навешивать не нужно - все сделает javascript.
Прячем input
Теперь нам нужно спрятать input[type=file] . Первое, что бросается в голову — свойства display: none и visibility: hidden . Но тут не все так просто. На некоторых старых браузерах клик по метке перестанет производить какой-либо эффект. Но это не все. Как известно, невидимые элементы не могут получать фокус, а кто бы что ни говорил, фокус важен, так как для некоторых людей это единственная возможность взаимодействия с сайтом. Так что этот способ нас не устраивает. Пойдем обходным путем:
Абсолютно спозиционируем наш input[type=file] относительно его родительского блока, уменьшим до 0.1px , сделаем прозрачным и установим его z-index меньше, чем у родителя, чтоб, так сказать, наверняка.
Поздравляю, мы добились того, чего хотели: наше поле выглядит именно так, как на предыдущей картинке.
13 Answers 13
Starting with Safari 5/Firefox 4, it’s easiest to use the FormData class:
It’s imperative that you set the contentType option to false , forcing jQuery not to add a Content-Type header for you, otherwise, the boundary string will be missing from it. Also, you must leave the processData flag set to false, otherwise, jQuery will try to convert your FormData into a string, which will fail.
You may now retrieve the file in PHP using:
(There is only one file, file-0 , unless you specified the multiple attribute on your file input, in which case, the numbers will increment with each file.)
Using the FormData emulation for older browsers
Just wanted to add a bit to Raphael's great answer. Here's how to get PHP to produce the same $_FILES , regardless of whether you use JavaScript to submit.
PHP produces this $_FILES , when submitted without JavaScript:
If you do progressive enhancement, using Raphael's JS to submit the files.
. this is what PHP's $_FILES array looks like, after using that JavaScript to submit:
That's a nice array, and actually what some people transform $_FILES into, but I find it's useful to work with the same $_FILES , regardless if JavaScript was used to submit. So, here are some minor changes to the JS:
(14 April 2017 edit: I removed the form element from the constructor of FormData() -- that fixed this code in Safari.)
That code does two things.
- Retrieves the input name attribute automatically, making the HTML more maintainable. Now, as long as form has the class putImages, everything else is taken care of automatically. That is, the input need not have any special name.
- The array format that normal HTML submits is recreated by the JavaScript in the data.append line. Note the brackets.
With these changes, submitting with JavaScript now produces precisely the same $_FILES array as submitting with simple HTML.
Как загружать любые файлы, например, картинки на сервер с помощью AJAX и jQuery? Делается это довольно просто! И ниже мы все обстоятельно разберем.
В те «древние» времена, когда еще не было jQuery, а может он был, но браузеры были не так наворочены, загрузка файла на сайт с помощью AJAX была делом муторным: через всякие костыли вроде iframe. Я то время не застал, да и кому это теперь интересно. А интересно теперь другое - что сохранение файлов на сайт делается очень просто. Даже не обладающий опытом и пониманием, того как работает AJAX, вебмастер, сможет быстро разобраться что-куда. А эта статья ему в помощь. Если подкрепить эти возможности функциями WordPress, то безопасная обработка и загрузка файлов на сервер становится совсем плёвым и даже интересным делом (пример с WordPress смотрите в конце статьи).
Однако, как бы все просто не было, нужно заметить, что минимальный опыт работы с файлами и базовые знания в Javascript, jQuery и PHP все же необходимы! Минимум, нужно представлять как загружаются файлы на сервер, как в общих чертах работает AJAX и хоть немного надо уметь читать и понимать код.
Описанный ниже метод довольно стабилен, и по сути опирается на Javascript объект new FormData() , базовая поддержка которого есть во всех браузерах.
Для более понятного восприятия материала, он разделен на шаги. На этом все, полетели.
Валидация файлов на клиенте
- 1. Выбран ли вообще файл
- 2. Не превышает ли его размер максимальный
- 3. Подходит ли файл по формату
Например, ошибка может выглядеть так.
Это означает, что в input[0] (в первом по счету поле) пользователь добавил файл test.pdf, формат которого не поддерживается, так как мы просим изображения. Это одна ошибка валидации. А массив таких ошибок и будет результатом выполнения функции. Если ошибок нет, все файлы выбраны и заданы правильно, то вернем пустой массив.
Впрочем, сейчас посмотрим, как это работает. Добавим функцию валидации validateFiles.
В параметре options мы передаем объект из трех полей: $files, maxSize и types. Соответственно, это jQuery-массив элементов input, максимальный размер файла в байтах и массив допустимых типов-расширений файлов, например, image/jpg, image/png или application/pdf - список типов легко можно загуглить.
Мы перебираем массив файлов и последовательно делаем проверки. Сначала смотрим, выбран ли вообще файл. Если нет, добавляем в результирующий массив ошибок пукнт с кодом no_file. Это будет объект-ошибка - имени предсказуемо нет. Дальше мы сразу переходим к следующему файлу, проверит размер и расширение мы не сможем.
Проверка на максимальный размер в случае неуспеха вернет объект , а несоответствие типа -
Обратите внимание, если в одном файле ловится несколько ошибок (максимум две в нашем случае), например, test.pdf слишком большого веса, то в результате мы получим 2 объекта. Имеет смысл группировать эти ошибки по имени файла, но не хочется усложнять код. В конце концов, если это необходимо, Вы сможете обработать выводимый результат как угодно.
Функцию написали, осталось задействовать ее в основном потоке кода. Немного расширим код submitForm:
Как видим, мы добавили вызов validateFiles с нужными параметрами. Максимальный размер файла ограничим 2 Мб, а типы возьмем jpg и png-картинки. После вызова проверяем, не пустой ли массив полученных ошибок, и если таки не пустой, то выводим результаты в консоль и выходим из функции сабмита. Файлы на сервер не уйдут.
Как обрабатывать ошибки и показывать их пользователю - дело исключительно хозяйское :-) Нам сейчас главное убедиться, что наша валидация работает.
Клиенсткий код закончен, можете побаловаться с файлами, добавить или убрать форматы разрешенных типов или изменить максимальный размер. Наш клиентский код должен точно реагировать на все попытки загрузить "неправильные" файлы. А мы переходим к валидации на стороне сервера.
Читайте также: