HTML5: загрузка файлов с помощью Drag & Drop

Источник: simplecoding

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

В большинстве случаев вам предложат стандартное поле с кнопкой выбора файла с вашего компьютера и/или поле, в котором можно указать URL файла, размещенного где-нибудь в Сети.

Загрузку файлов с локального компьютера трогать пока не будем, я планирую опубликовать отдельный пост на эту тему, разберем загрузку с удалённого сервера.

Проблемы начинаются с первого же шага. Даже если вы четко понимаете, где искать URL и хорошо умеете пользоваться инструментами вроде firebug, то всё равно потребуется несколько кликов мышкой чтобы получить нужный адрес. Было бы гораздо удобнее просто перетянуть нужную картинку из одного окна браузера в другое.

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

                            

Обратите внимание! Данный пример работает только в браузере Google Chrome. По-идее, поддержка всех необходимых технологий есть в Firefox и Safari, но с ними я пока не разбирался.

 В качестве объектов для "перетягивания" я брал в основном картинки с википедии. Было замечено несколько проблем связанных с не латинскими символами в URL картинок, но чтобы не перегружать пример проверками и преобразованиями я их оставил как есть.


Принцип работы

Стандарт HTML5 предусматривает поддержку "перетягивания" объектов страницы (Drag and Drop). Кстати, пример простейшей реализации D&D я уже показывал - Drag & Drop с использованием HTML5. И, кроме того, есть довольно много JavaScript библиотек, реализующих поддержку D&D.

Но тут важно понимать, что если необходимо "перетягивать" картинки со сторонних ресурсов, то использовать библиотеки не получится. Т.к. вы не сможете добавить свой JS код на чужую страницу. А для того, чтобы загрузить картинку, нам нужно получить её URL, т.е. браузер должен вместе с перетягиваемым объектом передавать и его параметры (например, атрибут src картинки или весь тег img).

В этом случае мы можем создать на своей странице "приёмник" картинок. Это будет обычный div которому назначен обработчик события drop. Если пользователь "сбросит" картинку над этим div'ом, то будет вызван обработчик и в первом параметре он получит объект, содержащий информацию о перетягиваемой картинке.

Дальше всё достаточно просто. Если мы получили нужный URL, то можно отправить AJAX-запрос серверному скрипту, который выполнит загрузку файла.

Реализация

Начнём со страницы нашего приложения.

<!DOCTYPE html>
 <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Images Upload</title>
        <link rel="stylesheet" type="text/css" href="styles.css" />
    </head>
    <body>
        <div id="images"></div>
        <div id="img_target"></div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script src="main.js"></script>
    </body>
</html>

На ней размещены два блока: images - здесь будем показывать загруженные изображения и img_target - на этот блок нужно перетягивать картинки.

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

Рассмотрим main.js

$(function() {
    $('#img_target')
        .bind('dragenter', function(event) {
            $(this).addClass('drop_here');
            return false;
        })
        .bind('dragleave', function(event) {
            $(this).removeClass('drop_here');
            return false;
        })
        .bind('dragover', function(event) {
            return false;
        })
        .bind('drop', function(event) {
            $(this).removeClass('drop_here');
            var srcRegex = /src=\"([^\s]+)\"/ig;
            var data = event.originalEvent.dataTransfer.getData('text/html');
            var img_data = srcRegex.exec(data);
            $.post('upload.php', {'file_url':img_data[1]}, function(res) {
                var response = eval('(' + res + ')');
                $('#images').append($('<img src="' + response.file_url + '" />'));
            });
            return true;
        });

Здесь мы назначаем обработчики событиям dragenter, dragleave и dragover. Все они должны просто возвращать false и, чтобы как-то проинформировать пользователя о том, что можно "сбрасывать" картинку, в обработчике dragenter устанавливаем CSS класс drop_here для блока-приёмника.

Основная часть работы выполняется в обработчике события drop. При возникновении этого события мы читаем информацию о "сброшенном" объекте и "вырезаем" значение атрибута src, т.е. URL картинки (строки 16-18). Информация передается в объекте event.originalEvent.dataTransfer (строка 17).

Затем формируем обычный AJAX запрос и в качестве параметра передаём ему найденный URL.

Серверный скрипт (upload.php) получит URL изображения на удалённом сервере и загрузит его. А в ответе на AJAX запрос он отправит новый URL загруженной картинки.

В свою очередь, обработчик AJAX-запроса создаст тег img и вставит его в блок images. Таким образом, загруженные картинки будут появляться над полем загрузки.

Рассмотрим upload.php

<?php
 
define('BASE_URL', 'http://localhost/tests/images-upload/');
 
function upload_from_url($file_url) {
    $url_segments = explode('/', $file_url);
    $file_name = urldecode(end($url_segments));
    if (false !== $file_name) {
        $file_name_parts = explode('.', $file_name);
        if (in_array(strtolower(end($file_name_parts)), array('jpeg','jpg','png','gif'))) {
            $destination=fopen("upload/".$file_name,"w");
            $source=fopen($file_url,"r");
            $maxsize=300*1024;
            $length=0;
            while (($a=fread($source,1024))&&($length<$maxsize)) {
                $length=$length+1024;
                fwrite($destination,$a);
            }
            fclose($source);
            fclose($destination);
        }
    }
    $new_file_url = BASE_URL.'upload/'.$file_name;
    return $new_file_url;
}
 
$res = array('err' => 'Не указан URL файла');
 
if (isset($_POST['file_url'])) {
    $new_url = upload_from_url($_POST['file_url']);
    $res = array('file_url' => $new_url);
}
 
echo json_encode($res);

Принцип работы следующий. Читаем URL картинки и пытаемся её загрузить (строки 29-32).

Если картинка загружена, сохраняем её в папку upload. Получение картинки с удалённого сервера осуществляется с помощью функций fread. Файл читаем блоками по 1кБ (строки 15-18). Такой подход позволяет прервать загрузку файла, если его размер превышает заданный предел (в данном случае 300кБ).

После загрузки файла формируем для него URL и отправляем браузеру в формате JSON.

Как видите, реализовать такой загрузчик несложно. И пользоваться им достаточно удобно. Естественно, основным недостатком является поддержка HTML5 браузерами, точнее её отсутствие 

Тем не менее, если вы создаёте интерфейс для сотрудников какой-нибудь компании, и можете оговорить тип браузера, то HTML5 вполне можно использовать.

Успехов!


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=28060