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

Обновлено: 05.07.2024

Функционал, отвечающий за отправку файлов на сервер, реализуется довольно просто. Как и в примерах из предыдущих уроков, за это отвечает специальное поле формы. Но ее настройка имеет некоторые особенности.

Если ваша форма содержит поля, отвечающие за загрузку файлов, то элементу

необходимо явным образом установить атрибут enctype в значение multipart/form-data , а method задать как POST .

Заметка
Приведенные выше значения атрибутов не связанны непосредственно с HTML. Они оптимизируют внутренние процессы браузера. Если вы правильным образом настроите элемент , отправка больших файлов будет произведена гораздо быстрее, а серверная программа сможет легко принять и обработать их.

Использование поля загрузки файлов

В HTML для отправки файлов из формы используется многозадачный элемент . Его атрибут type должен иметь значение file . Браузер отобразит такое поле в виде кнопки с текстом «выберите файл» или аналогичным.

При нажатии кнопки откроется проводник файловой системы. В нем можно перемещаться по директориям компьютера. Интерфейс интуитивно понятен любому пользователю. Все что нужно сделать — это найти нужный файл и нажать кнопку «Открыть». Отметим, что выбирать нужные документы и файлы может только сам пользователь. Явное указание атрибута value с именем или расположением какого-либо файла не приведет к успеху.

Чтобы выбранный файл был загружен при отправке формы, полю необходимо добавить атрибут name с уникальным значением.

Множественный выбор и блокировка поля

По умолчанию пользователь может выбрать только один файл, предназначенный к отправке. HTML позволяет изменить это поведение. Множественный выбор станет доступным после добавления к полю атрибута multiple .

Также нужно отметить, что поле загрузки файлов можно заблокировать с помощью атрибута disabled . Это сделает невозможным какое-либо взаимодействие с ним. Если оно заблокировано после осуществления выбора файла, он не будет отправлен вместе с остальными данными формы. Такая ситуация может возникнуть при использовании встроенного в браузер языка программирования JavaScript.

Принципы загрузки файлов

Любой загружаемый файл будет помещен в специальную директорию для временного хранения, а связанная с ним информация добавлена в суперглобальный массив $_FILES . Если не переместить файл в другое место, после завершения скрипта произойдет его бесследное удаление. Директория временного хранения определяется настройкой upload_tmp_dir конфигурационного файла php.ini .

Суперглобальный массив $_FILES

Если вместе с текущим запросом были загружены файлы, PHP-интерпретатор автоматически заполнит суперглобальный массив $_FILES соответствующей информацией. Его структура довольно проста. Элементы массива соответствуют именам параметров HTTP-запроса. Например, ваша веб-форма содержит поле загрузки файла с атрибутом « name="upload-file" ». В таком случае информация будет добавлена в $_FILES['upload-file'] .

Содержимое массива $_FILES:

Заметка
Существует одно требование к HTML-разметке полей, осуществляющих множественный выбор и загрузку файлов. Их атрибут name должен быть составлен следующим образом « name ». Если вы опустите конструкцию [] , PHP обработает только один файл.

Перемещение загруженного файла

Как говорилось выше, загружаемые файлы размещаются во временной директории сервера и автоматически удаляются PHP-интерпретатором после выполнения текущего запроса. Их можно сохранить, переместив в другое место. Использовать стандартные функции copy() или rename() крайне нежелательно.

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

С помощью функции is_uploaded_file() вы можете проверить, является ли файл загруженным в текущем запросе. Она принимает всего один параметр — имя файла, а возвращает результат логического типа.

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

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

Пример загрузки файла на сервер

Ниже приводится пример PHP-скрипта. Если он вызывается в первый раз, либо в текущем запросе отсутствует загрузка файла, пользователю выводится форма. При загрузке, файл перемещается в корневую директорию сайта, а пользователю показывается информация, связанная с ним. Обрабатываются только изображения в форматах jpg , jpeg и png .

Команда Яндекс.Метрики продолжает рассказ о работе с параметрами посетителей: прошлая статья была посвящена передаче данных онлайн, а в этой статье рассказывается про офлайн-загрузку. Этот способ позволяет добавить в отчеты те данные, которые уже есть в базе: например, доход на клиента или уровень лояльности.

Чтобы Метрика могла определить, какому посетителю записать эти новые атрибуты, необходимо связать данные из имеющейся базы и данные в Метрике, присвоив им общий идентификатор. Для этого нужно либо передать в Метрику свои собственные идентификаторы клиентов (UserID), либо внести в свою CRM уникальные номера посетителей из Метрики (ClientID).

Связка по UserID: при наличии собственных идентификаторов клиентов

Этап 1. Учим Метрику узнавать клиентов

Чтобы начать передавать в Метрику собственные идентификаторы авторизованных посетителей (UserID), нужно добавить на сайт код, который будет подставлять эти идентификаторы в метод setUserID:

yaCounterXXXXXX.setUserID()

Идентификаторы UserID не будут показываться в отчетах: они сохранятся в базе данных Метрики в качестве ключей, которые позволят сопоставить посетителей в Метрике и клиентов в CRM. Каждый раз, когда авторизованный посетитель будет заходить на сайт, Метрика будет получать команду «запомнить» этого посетителя под указанным UserID.

UserID можно передавать не только для авторизованных посетителей. Уникальный идентификатор также можно забирать из «меченой» ссылки, которую вы отправляли вашим клиентам по почте, или из реферера соцсетей. Также в качестве UserID подойдет номер дисконтной карты или промо-код, который посетители вводят на сайте.

Этап 2. Загрузка данных

После передачи в Метрику достаточного количества UserID, нужно подготовить файл с теми атрибутами клиентов, которых необходимо добавить в отчеты. Это таблица в формате csv с тремя столбцами: в первом — UserID, который послужит ключом для связки данных в файле и в Метрике, во втором — название параметра, а в третьем — его значение.

Вот как может выглядеть этот файл:

Metrika_visiti_2

Metrika_visiti_3

Когда файл будет обработан, в интерфейсе появится уведомление:

Metrika_visiti_4

Статус «Выполнено (80% привязки)» означает, что переданные UserID нашлись в Метрике для 80% клиентов из файла. Чаще всего данные привязываются не полностью из-за того, что не все клиенты успели побывать на сайте — а значит, их UserID еще не были переданы, и Метрика не знает, каким посетителям записывать атрибуты из таблицы. Поэтому параметры будут добавлены только для 80% «привязанных» посетителей — об этом полезно помнить, интерпретируя данные в отчетах.

Всего Метрика может хранить до 1 000 параметров одного посетителя.

Связка по ClientID: если своих идентификаторов посетителей нет

ClientID — это номер, который Метрика присваивает каждому посетителю. Его можно использовать в качестве ключа для объединения данных, если на сайте нет собственной системы идентификаторов — или же если клиенты регистрируются редко, а заказы обычно делают по телефону.

Чтобы забирать себе ClientID из Метрики, необходимо добавить на сайт код, который будет вызывать метод getClientID и записывать полученное значение в вашу CRM:

<ClientID> = yaCounterXXXXXX.getClientID()

Через некоторое время — когда достаточное количество посетителей побывает на сайте, и их ClientID будет получен – можно будет сформировать csv-таблицу с атрибутами клиентов. Она будет выглядеть так же, как в примере с UserID, только на этот раз в первом столбце в качестве ключа для склейки посетителей будет использоваться ClientID. И при загрузке таблицы в Метрику также нужно будет выбрать тип файла «Сlient_ID».

Как обновить или удалить загруженные данные

Чтобы в отчетах начали показываться новые значения параметров, нужно просто загрузить актуальный файл. А если необходимо удалить данные, нужно в том же меню для загрузки данных выбрать вариант «Удалить» — и передать файл с пустыми значениями параметров:

Загрузка такого файла не обнуляет значения параметров, а именно удаляет их. То есть если вы когда-то передали количество покупок на клиента, а затем загрузили пустой файл, параметр offline-purchase просто пропадёт из отчётов – а не станет равным нулю.

В API Метрики можно настроить автоматическую загрузку файла с параметрами посетителей.

Что лучше выбрать — онлайн или офлайн передачу параметров посетителей?

С помощью метода userParams имеет смысл отправлять те данные, которые возникают только в онлайне — и при этом их не нужно хранить в своей базе. Этот способ также подойдет интернет-изданиям или блогам, у которых нет CRM.

Другое важное отличие — скорость обновления данных в отчетах. Когда будет налажена работа с методами setUserID или getClientID и с тех пор большинство клиентов хотя бы раз зайдут на сайт, новые данные в отчетах будут появляться сразу после загрузки актуального файла — а не после того, как клиент вернется на сайт.

Ответы на другие частые вопросы по обоим способам работы с параметрами посетителей специалисты Яндекс.Метрики собрали в отдельной статье.

Яндекс.Метрика опубликовала руководство по офлайн-загрузке параметров посетителей. Этот способ позволяет добавить в отчеты те данные, которые уже есть в вашей базе: например, доход на клиента или уровень лояльности.

Чтобы Метрика могла определить, какому посетителю записать новые атрибуты, необходимо связать данные из вашей базы и данные в Метрике — присвоить им общий идентификатор.

Существует два способа:

  • передать в Метрику ваши идентификаторы клиентов (UserID);
  • или внести в вашу CRM уникальные номера посетителей из Метрики (ClientID).

Связка по UserID: если у вас есть собственные идентификаторы клиентов

Этап 1. Учим Метрику узнавать клиентов

Чтобы начать передавать в Метрику идентификаторы авторизованных посетителей (UserID), нужно добавить на сайт код, который будет подставлять эти идентификаторы в метод setUserID:

Идентификаторы UserID не будут показываться в отчетах: они сохранятся в базе данных Метрики в качестве ключей, которые позволят сопоставить посетителей в Метрике и клиентов в вашей CRM.

UserID можно передавать не только для авторизованных посетителей. Уникальный идентификатор также можно забирать из «меченой» ссылки, которую вы отправляли вашим клиентам по почте, или из реферера соцсетей. Также в качестве UserID подойдёт номер дисконтной карты или промо-код, который посетители вводят на сайте.

Этап 2. Загружаем данные

После того, как UserID переданы в Метрику, нужно подготовить файл с атрибутами клиентов, которые нужно добавить в отчеты. Это таблица в формате csv с тремя столбцами:

  • в первом — UserID, который послужит ключом для связки данных в файле и в Метрике,
  • во втором — название параметра,
  • в третьем — его значение.

Вот как может выглядеть этот файл:

orig.jpg

orig (1).jpg

Когда файл будет обработан, в интерфейсе вы увидите уведомление:

orig (2).jpg

Статус «Выполнено (80% привязки)» означает, что переданные UserID нашлись в Метрике для 80% клиентов из файла. Чаще всего данные привязываются не полностью из-за того, что не все клиенты успели побывать на сайте — а значит, их UserID еще не переданы, и Метрика не знает, каким посетителям записывать атрибуты из таблицы. Поэтому параметры будут добавлены только для 80% «привязанных» посетителей — об этом полезно помнить, интерпретируя данные в отчётах.

Связка по ClientID: если своих идентификаторов посетителей нет

ClientID — это номер, который Метрика присваивает каждому посетителю. Его можно использовать в качестве ключа для объединения данных, если на сайте нет собственной системы идентификаторов — или же если клиенты регистрируются редко, а заказы обычно делают по телефону.

Чтобы забирать ClientID из Метрики, добавьте на сайт код, который будет вызывать метод getClientID и записывать полученное значение в вашу CRM:

Когда достаточное количество посетителей побывает на сайте и вы получите их ClientID, можно будет сформировать csv-таблицу с атрибутами клиентов. Она будет выглядеть так же, как в примере с UserID, только на этот раз в первом столбце в качестве ключа для склейки посетителей будет использоваться ClientID. И при загрузке таблицы в Метрику также нужно будет выбрать тип файла «Сlient_ID».

Как обновить или удалить загруженные данные

Чтобы в отчетах начали показываться новые значения параметров, нужно загрузить актуальный файл. А если нужно удалить данные, в том же меню для загрузки данных выберите вариант «Удалить» — и передать файл с пустыми значениями параметров:

Загрузка такого файла не обнуляет значения параметров, а именно удаляет их. То есть если вы когда-то передали количество покупок на клиента, а затем загрузили пустой файл, параметр offline-purchase просто пропадет из отчетов, а не станет равным нулю.

Что лучше выбрать — онлайн или офлайн передачу параметров посетителей?

С помощью метода userParams имеет смысл отправлять те данные, которые возникают только в онлайне — и при этом вам не нужно хранить их в своей базе. Этот способ также подойдёт интернет-изданиям или блогам, у которых нет CRM.

Другое важное отличие — скорость обновления данных в отчетах. Когда вы наладите работу с методами setUserID или getClientID и большинство ваших клиентов хотя бы раз зайдут на сайт, новые данные в отчетах будут появляться сразу после загрузки актуального файла — а не после того, как клиент вернется на сайт.

Все течет, все меняется, но только input[type=file] как портил нервы всем начинающим веб-разработчикам, так и продолжает это делать до сих пор. Вспомните себя N лет назад, когда вы только начинали постигать азы создания веб-сайтов. Молодой и неопытный, вы искренне удивлялись, когда кнопка выбора файла напрочь отказывалась менять цвет своего фона на ваш любимый персиковый. Именно в тот момент вы впервые столкнулись с этим несокрушимым айсбергом под названием «Загрузка файлов», который и по сей день продолжает «топить» начинающих веб-разработчиков.

На примере создания поля для загрузки файлов я покажу вам, как правильно прятать input[type=file] , настраивать фокус на объекте, у которого фокуса быть не может, обрабатывать события Drag-and-Drop и отправлять файлы через AJAX. А также я познакомлю вас с парой браузерных багов и путями их обхода. Статья написана для новичков, но в некоторых моментах может быть полезна и занимательна даже для матерых разработчиков.

Разметка и первичные стили

Начнем с HTML-разметки:


Пожалуй, главным элементом, на который стоит обратить внимание, является


Спецификация HTML не позволяет нам накладывать визуальные свойства непосредственно на input[type=file] , но мы имеем тэг label , нажатие на который вызывает клик по элементу формы, к которому он привязан. К нашей радости, данный тэг никаких ограничений в стилизации не имеет: мы можем делать с ним все, что захотим.

Вырисовывается план действий: стилизуем метку как нам угодно, а сам input[type=file] прячем с глаз долой. Для начала настроим общие стили страницы:


Теперь стилизуем нашу метку:



То, к чему мы стремимся ( input[type=file] убран из разметки):

Безусловно, можно было отцентровать метку, добавить фон и границу, получив полноценную кнопку, но наш приоритет — Drag-and-Drop.

Прячем input

Теперь нам нужно спрятать input[type=file] . Первое, что бросается в голову — свойства display: none и visibility: hidden . Но тут не все так просто. На некоторых старых браузерах клик по метке перестанет производить какой-либо эффект. Но это не все. Как известно, невидимые элементы не могут получать фокус, а кто бы что ни говорил, фокус важен, так как для некоторых людей это единственная возможность взаимодействия с сайтом. Так что этот способ нас не устраивает. Пойдем обходным путем:


Абсолютно спозиционируем наш input[type=file] относительно его родительского блока, уменьшим до 0.1px , сделаем прозрачным и установим его z-index меньше, чем у родителя, чтоб, так сказать, наверняка.

Поздравляю, мы добились того, чего хотели: наше поле выглядит именно так, как на предыдущей картинке.

Настраиваем фокус

Так как наш 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] получает фокус и убирать, когда теряет.


Теперь все работает как надо. Поздравляю, с фокусом мы разобрались.

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 и отправляем его в функцию.

Отправка файлов через AJAX

Последний этап — описание функции обработки файлов — уникален для всех и каждого. Он будет прямым образом зависеть от той цели, которую вы преследуете. Для примера я покажу, как отправлять файлы на сервер через AJAX.


В переменную maxFileSize занесем максимальный размер файла, который будем отправлять на сервер. Функцией FormData() мы создадим новый объект класса FormData , позволяющий формировать наборы пар ключ-значение. Такой объект можно легко отправлять через AJAX. Далее используем jQuery конструкцию .each для массива files , которая применит заданную нами функцию для каждого его элемента. В качестве аргументов в функцию будут передаваться порядковый номер элемента и сам элемент, которые мы будем обрабатывать как index и file соответственно. В самой функции мы проверим файл на соответствие нашим критериям: размер меньше пяти мегабайт, а тип — PNG или JPEG. Если файл проходит проверку, то добавляем его в наш объект FormData путем вызова функции append() . Ключом послужит строка 'photos[]' , квадратные скобки на конце которой обозначат, что это массив, в котором может быть несколько объектов. Самим объектом будет file .

Теперь все готово для отправки файлов через AJAX. Добавим в нашу функцию следующие строчки:

Поздравляю, теперь вы умеете создавать свое собственное поле загрузки файлов! Конечно же, я не позиционирую свой способ как единственно верный и правильный. Своей задачей я ставил показать общий ход решения данной задачи, подходящий в первую очередь для новичков. Если вы считаете, что где-то что-то можно было сделать лучше — пишите в комментариях, обсудим!

Читайте также: