войти зарегистрироваться

jQuery whois

индекс
190,00

JQuery Uploadify — мультизагрузка файлов с использованием флэш

Тема загрузки файлов без перезагрузки страницы поднималась уже неоднократно. Даже я как-то давно писал про это. В основном рассматривались решения без флэша, но сегодня я хотел бы поговорить про плагин для jquery с использованием флэша, а именно о JQuery Uploadify.

Конечно, можно использовать и другой флэшевский загрузчик SWFUpload, но Uploadify, по моему мнению, на порядок легче и проще, вполне подходит для большинства целей, ну и конечно не забываем, что это плагин для нашего любимого jquery, что избавляет нас от подключения еще каких-либо библиотек ;)

Теперь рассмотрим всё на примере.

Использовать плагин очень просто, как и большинство других jquery плагинов ;)
Естественно, сперва подключаем js файлы:

<script type="text/javascript" src="jquery.uploadify.v2.1.0.min.js"></script>
<script type="text/javascript" src="swfobject.js"></script>


* This source code was highlighted with Source Code Highlighter.


Все успели заметить swfobject.js? Отклоняться от темы не буду, почитать про SWFObject и всего его плюсы можно в этом посте на Хабре.

Далее идёт следующий код:
$(document).ready(function() {
  $("#uploadify").uploadify({
    'uploader'    : 'uploadify.swf',
    'script'     : 'functions.php',
    'checkscript'  : 'check.php',
    'cancelImg'   : 'cancel.png',
    'queueID'    : 'fileQueue',
    'auto'      : true,
    'multi'     : true,
    'fileDesc'   : 'jpg',
    'fileExt'   : '*.jpg',
    'onComplete'   : function(event,queueID,fileObj,response,data) {$('#response').append(response);}
  });
});


* This source code was highlighted with Source Code Highlighter.


Теперь немного подробнее.

uploader — путь до самого флэш загрузчика uploadify.swf

script — это путь до нашего файла обработчика, у меня это файл functions.php, но в архиве с библотекой он именуется как uploadify.php.

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

cancelImg — путь до картинки, которая будет символизировать удаления файла.

queueID — id элемента, в котором будет содержаться список выбранных нами файлов. По умолчанию он создаётся ниже браузерной кнопки выбора файла.

auto — параметр, отвечающий, будут ли файлы загружаться автоматически сразу после их выбора, или нет. Если стоит значение false, то для начала загрузки можно использовать этот код:
<a href="javascript:$('#uploadify').uploadifyUpload();">Загрузить файлы.</a>

* This source code was highlighted with Source Code Highlighter.

Естественно, можно повесить вместо ссылки картинку или кнопку, тут уже на Ваш выбор.

multi — будет ли наш плагин служить для загрузки нескольких файлов, иль не будет :) Для загрузки одного файла можно обойтись и без флэша, так что смело оставляем тут true.

fileDesc — типы файлов в диалоге выбора. У меня тут стоят только jpg файлы.

fileExt — расширения файлов, разрешенных для загрузки. Смело можно добавить к моим jpg и другие, например: *.jpg;*.bmp;*.png.
Незабываем добавить эти типы файлов и в fileDesc, иначе не сможете выбрать эти файлы в диалоговом окне ;)
Также советую всё-таки проверять типы файлов на стороне сервера, ибо такую проверку на стороне клиента легко обойти ;)

onComplete — функция, которая будет вызвана сразу после загрузки файла. Замечу, не после загрузки всех файлов, для этого есть onAllComplete, а именно одного файла из очереди.
Данная функция будет вызываться каждый раз, как будет загружен очередной файл. У меня вызывается функция, которая получается ответ от моего обработчика functions.php и вставляет его в div с id response:
function(event,queueID,fileObj,response,data) {$('#response').append(response);}

* This source code was highlighted with Source Code Highlighter.


Страница самого плагина:
http://www.uploadify.com/

Страница с расширенной документацией по всем параметрам и функциям:
http://www.uploadify.com/documentation/

Вот собственно и всё. Будут вопросы — с радостью попытаюсь на них ответить и всячески помочь ;)
_________
Текст подготовлен в ХабраРедакторе

комментарии (91)

  • Я наивный, думал, что кроме FancyUpload ничего нету. Спасибо за обзор.
  • Всё как раньше, при попытке загрузить большие файлы браузер виснет, только что проверил в лисички 3.5 и хроме под линухой, оба браузера повисле при нажатии аплоад, а файл грузил не больше, всего 49 метров…
    Так что годиться только только для фоток (и то не очень больших), а прочих мелких файликов =(
    • а в php.ini какой-значение стоит?
    • хотя не заметил, что вы написали что виснет браузер, php.ini тут видимо не при делах
    • тестил загрузку больше ста фоток (2.5мб в среднем) отлично справляется

      Там в дефолтовой поставке идет скрипт на проверку размера и формата совместимости — уверен проблема была в нем (у себя переделал его сразу)
      • Прошу прощения, пересмотрел конф — просто отключил проверку на лимит размера закачки.
    • Я заметил, что браузер виснет во время выгрузки файлов. После выгрузки развисает.
    • это не только для больших, для маленьких тоже, просто маленькие у тебя видимо очень уж быстро грузятся
    • Использую FancyUpload — отлично загружаются файлы размером до 3 мб (больше не требуется, хотя автор плагина писал что загружал и 2 GB). Правда технически загружаю по одному файлу за одно соединение, а не все файлы за раз (а то непонятно какие лимиты установить на размер входящих данных и на время работы скрипта...)
      Подвисаний нет.
      Но, сталкивался с конфликтом с антивирусом касперского. Вопрос решился обновлением антивируса до 10 версии и настройкой в нем сайта, на которорый осуществляется аплоад, как доверенного.
    • И не забываем о баге с кукис и http authentication ето касается всех браузеров кроме експлорера.
      А так, скрипт весьма неплохой.
    • Есть такое. У меня тоже повис FF 3.5
    • swfupload лишен таких косяков
      swfupload.googlecode.com

      у меня репартеры на autopeople.ru загружают им видео ролики больших размеров (200 мб)
  • Меня всегда прикалывают плагины на десятки килобайт, являющимися обертками вокруг 10 строчек, состоящими на половину из перетасовывания настроек.
    • ну, лично для меня плагин весом в 7кб js + 22 флэш загрузчик — не так уж и критично, если он облегчает жизнь :)
      • к сожалению 90% сторонних плагинов к jquery обвешены не нужным для меня функционалом(так же как и большинство других плагинов, хоть в той же symfony), что негативно сказывается как на размере и скорости работы так и на стабильности, так что для себя разработал следующую схему: разбираюсь как работает плагин, потом переписываю, минимализируя под свои задачи. В итоге, согласен с Wott, килобайты заменяются десятками строк.
        • Каждый выбирает для себя, что ему важнее — производительность приложения, либо скорость разработки этого приложения. Всё зависит от поставленной задачи. Думаю, в большинстве случаев лишние 50-100 Кб на страницу сайта — это не критично (с учетом быстрорастущей ширины каналов пользователей) в сравнении с экономией времени затраченного на разработку.
          • применительно конкретно к этому плагину, смотрим коментарии, какие ошибки и какие трудности возникают, я намного быстрее перепишу и переделаю его с нуля, чем буду в этих килобайтах копаться и выискивать баги, которые к тому же возможно индивидуальны :)
  • А никто не знает flash-загрузчик, который кроме загрузки еще картинки пережимает на клиенте? Можно и платный.
    • Готового такого не знаю. Но не сильно сложно сделать это и с этим плагином. Благо исходник есть)
    • если мне память не изменяет, то у флеша есть ограничения по работе с локальными файлами с диска пользователя. так что может оказаться, что предварительный ресайз невозможен без предварительной закачки на сервер. но могу врать :)
    • Это скорее уже нужен java загрузчик
      • У никто не видел толковый open source загрузчик на java?
    • у вконтакта скомуниздь, мультизагрузка и пережим-жим картинок %)
    • Собрался и написал свой аплоадер под google gears, unobtrusive-аналог загрузчика вконтакте, картинки пережимает, превью показывает, файлы загружает, обычную отправку форм эмулирует — не нужно делать никаких изменений на стороне сервера, есть хелперы для интеграции с django-вскими formset'ами.

      Пока документация не готова, но мне нравится, что получается. Пока в качестве preview кину сюда ссылку на него, вдруг кому пригодится. Лицензия MIT, так что если кому интересно — используйте, подключайтесь к разработке. Пиар проведу, так сказать, предварительный.

      bitbucket.org/kmike/gearsuploader/wiki/ru
  • Использую этот загрузчик в ЦМС что пишу на codeigniter.
    В самом Uploadify было несколько неприятных глюков, но после последнего апдейта (был в конце лета) почти все хорошо за исключением:
    1. Иногда улетает окно выбора файлов если долго искать что выбрать(ФФ+Open Suse 11.1) — возможно проблемы с самим ГТК.
    2. Окно выбора файлов не запоминает последнюю директорию, иногда просто не удобно рыскать по попкам (опять же не тестил в вин, в лине возможно проблемы с ГТК).
    Одно что не совсем хорошо — в флешке некорректно отображается русский (думаю можно подпилить напильником в флеше)

    • 1) под win ff 3.5.3 пока такого не замечал.
      2) опять же, у меня всё запомнило :) вин. ff 3.5.3

      пысы: про попки особенно понравилось ;)))
    • Я задолбался воевать с глюками Uploadify и его сочленения с CI, тупо перешёл на SWFUpload, чему и рад вполне (-:
      • Не подскажите, как вы решили проблему автоматический созданий сессии в CI и то, что SWFUpload создает свою id сессии при передачи?

        На данный момент у нас решено только принудильной подачей своей id сессии как дублирующей :(
      • А как обстоят дела с загрузкой файлов с кириллическими именами?
        У меня получилось загрузить только .jpg, и то, имя оказалось пустым.
        • В файле upload.php добавил в строку А-Я:

          $valid_chars_regex = 'А-Я.A-Z0-9_ !@#$%^&()+={}\[\]\',~`-';

          Получилось хотя бы избегать пустоты, вместо имени файла.
      • Спасибо за наводку.
    • Ага, у меня те же проблемы на сусе 11.1.
  • Интересный плагин, буду использовать в своих проектах.
  • Плагин может сообщать количество переданной информации клиенту без скриптов со стороны сервера?
    • да, вполне :)

      почитайте на сайте про onAllComplete .
      Если не разберетесь — сделаем примерчик :)
      • A function that triggers when all file uploads have completed. There is no default event handler.

        Вы, судя по всему, меня немного не правильно поняли — о количестве переданной информации во время передачи, т.е. чтобы был прогресс загрузки. Сейчас у меня получается видеть только финиш загрузки, без каких-либо промежуточных данных.
        • хм, а прогрессбар у вас не срабатывает? И какая промежуточная информация вам еще нужна?
          Как понимаю, помимо прогресс бара вы хотите добавить отображения количества загруженных байт?
          • Да, хотя бы их
            • ну есть и такая функция, onProgress называется :) опять же, почитайте про неё на офф. сайте.
              Думаю это то, что вам нужно :)
    • ну, это браузер должен делать. Хром делает, кстати.
      • Но, сколько уже версий браузеров прошло, но ни Opera, ни Firefox этому не научились.
        А сам прогресс загрузки реализовал без использования этого модуля — понял силу jQuery.
  • Есть бага: при загрузке изображений или файлов некоторых, правда у меня не получается локализировать проблему и хоть как-нибудь понять от чего это зависит, плагин загрузив файл на сервак возвращает ошибку — мол никак, не получилось, ты уж прости. Просто редкие файлы грузит, но по окончанию выдаёт что-то вроде: IO Error — 1.zip — 100%, как итог — файл не загрузился.
    • Это бага видимо во флеше. Если интернет через прокси, с аутентификацией, то плагин, скорее всего работать не будет.
      Пробовал другие плагины — ситуация аналогичная.
      Поэтому, необходимо оставлять возможность стандартного аплоада через html.

      По плагину: недавно внедрил на свой сайт — интерфейс красивый, но есть глючки в старых версиях плагина. Причем примеры идут со старыми, нерабочими версиями, что вносит путаницу, и нет дебагера, позволяющего понять что происходит. В итоге отлаживал скрипты в swfupload (там есть дебагер), а потом подменил его на uploadify. Так же есть нюанс — скрипт аплоада должен быть в отдельной библиотеке или в отдельном блоке script (об этом написано на форуме плагина, пока нашел в чём дело — голову сломал). Вобщем внедрить сложно, но заставить работать — можно.

      Посмотреть плагин в действии можно тут:
      mp3tter.com
    • Ещё, помогает понимание того, как эта штука работает. Реально, файлы загружаются не в указанную директорию, а во флешку!111. Через файлгетконтекст какой-то. И только потом, тело файла передается постом — скрипту, указанному в настройках. Соответственно, просто указать максимальный размер файла — недостаточно.

      Проверь эти настройки в php.ini:
      ; Maximum size of POST data that PHP will accept.
      post_max_size = 20M
      ; Whether to allow HTTP file uploads.
      file_uploads = On
      ; Maximum allowed size for uploaded files.
      upload_max_filesize = 20M

      Для сервера nginx — в секции http также необходимо указать:
      keepalive_timeout 0;//!!!
      client_max_body_size 20m;//
      И разрешить обработку флеша, у меня в конфиге это реализовано так:
      if (-f $request_filename) {
      expires max;
      break;
      }

      if ($request_filename !~ (js|css|ico|gif|jpg|m3u|swf|zip|png|images|robots\.txt|my_index_file\.php*) ) {
      rewrite ^/(.*)$ /mp3tter.php/$1 last;
      }
      • не совсем точно описал:
        1. файл загружается во флешку
        2. файл сохраняется из флеш в темповую директорию сервера
        3. скрипту передается массив $_FILES содержащий имена загруженных файлов
        как то так.
  • Плагин для вашего любимого jquery.

    Я думаю я относился бы к вашему любимому jquery если бы не было так много людей что без него ничего не могут сделать на жаваскрипте.
    • А почему вы решили что они на jquery могут что-то сделать? Использовать плагины- это одно, а писать самому с использованием фреймворка -это немного другое, имхо, тут тоже необходимо неплохое знание жабаскрипт. И почему бы не любить фреймворк за удобство и функциональность?

      Я ЛЮБЛЮ JQUERY больше чем PROTOTYPE :)
    • Зачем делать что-то на чистом жабоскрипте? Чистый нужен только тогда, когда надо очень мало написать. По онклику скрыть див.
      А если писать что-то серьёзное без фреймворка — это уже велосипед (:
  • А у всех ли файл попадает в директорию uploads?
    Даже скрипт с примером этого не делает у меня.
    • Файл при аплоаде изначально попадает во временную директорию, определенную в настройках php.ini (см. секцию «File Uploads» и в ней upload_tmp_dir)
      А оттуда php-командой move_uploaded_file можно его переместить куда требуется.
    • Есть параметр настройки folder — там задается путь куда грузить
      • Знаю. Не реагирует никак.
        • попробуй при инициализации плагина добавить параметр folder: 'uploads'
  • Столкнулся с некоторыми «багами» при использовании этого плагина:
    1. Если на клиентской стороне работает Касперский, то загрузка каждого файла (прогрессбар) сразу показывает 100%. При отключеном касперском — нормально.
    2. (хотя тут возможно виноват сервер) Загрузка больших файлов (около 500Мб) доходит до 100% и все, никаких действий от скрипта вы не дождетесь, возникает ощущение, что скрипт ждет json, но не получает и ожидание это может продолжаться вечно!
    IO Error — бывает, но не часто…
    • выше написал как оно работает. Сначала файл загружается во флеш, и только потом сохраняется на сервер. Т.е. в момент, когда градусник показывает 100% — начинается сохранение файла. Просто подождите пока файл сохранится.
    • Настройте в касперском сайт, на который аплоадите файл, как довернный. Правда такую настройку удалось обнаружить только для KAV 10, в девятом ее не нашел…
      (Настройка/Защита/Вэб антивирус/Настройка/Оптимизация проверки/кнопка Выбрать/ добавьте сюда записть типа *yoursite.com*), и все будет работать.
      • Спасибо, как настроить я знаю, да и проблема с прогрессбаром меня не напрягает, но есть начальство которому не нравится такая визуализация процесса загрузки, вот и думал, мало ли кто то находил решение этой проблемы…
        • Это все потому, что касперский любые файлы и письма, отправляемые во внешний инет, сразу «закачивает» на себя, говоря приложению, что все в порядке. Дальше сканит и уже после проверки доставляет адресату. Вот потому у браузера и возникает ощущение, что файл загружен: касперский ему так говорит. Установлено опытным путем, могу ошибаться.
  • Возможно баг — параметр buttonText не принимает utf-8, например, вместо русского текста — цифры.
    • И еще — возможна ли передача текущей пользовательской сессии?
      Так получается, что скрипт просто отсылает данные на сервер независимо от браузера.
      • Дополнительные параметры можно передавать через контейнер scriptdata, примерно так:
        function startUpload()
        {
        var twitt = 'false';
        if (document.getElementById('twitt_it').checked == true) twitt = 'true';
        $('#uploadify').uploadifySettings('scriptData',{'tag':$('#tag').val(),'msg':$('#msg').val(),'twitt_it':twitt,'author':'recoilme'});
        $('#uploadify').uploadifyUpload();
        }
    • это уже видимо проблема во флеше, нужно его расчленять и разбираться.
  • существует ли возможность как-то ограничить количество загружаемых файлов при множественной (Multiple) загрузке
    • simUploadLimit, если в очереди больше файлов — то придется после загрузки количества, равного simUploadLimit нажать еще раз кнопку начала загрузки.
  • Достаточно непредсказуемая вещь… Если загружать ~30 файлов за раз, то некоторые вылетают с HTTPError. Это не всегда и не поддаётся систематизации =(
  • Есть еще момент — всегда отдавайте хоть что-то в response сервера, иначе не будут работать события onComplete/onAllComplete.
    • Да-да)) тот же echo «1»; :)
  • Единственный неприятный момент в использовании флеша для загрузки файлов — необходимость передавать идентификатор сессии в открытом виде.
    Т.е. оно, конечно, не сильно смертельно, если речь идёт об админке — куда доступ одного человека разрешён, другое дело когда это сервис, где толпа народу, имеющая право что-то загружать. Вот тогда уже не так всё кучеряво хотя терпимо.
    Кстати, если стоит суровый скрипт (у меня в CakePHP всё сурьёзно) — следует ещё и проверку UserAgent отключать — ибо сессия сессией, а агент-то меняется :)

    Спасибо за плагин
  • Как побороть айди сессии при загрузке файлов? есть ли способ его менять на нужный мне?
    • Передавать нужный id сессии через параметр.
      • через параметр где? в скрипте или в пхп?
  • Да действительно очень полезный плагин, но если кто подскажет как его прикрутить к фреймворку, а точнее как должен выглядеть метод контроллера, которому передается массив с файлами. Много мучился привязать его к CI, но ничего не получилось.
    • Вот как сделав у себя (/system/application/modules/upload/ — тут сам плагин и нужные файлы):
      Настройка плагина (думаю спокойно можно вынести в отдельный js, но не пробывал)

      $(document).ready(function() {

      $('#fileUpload').fileUpload({
      'uploader': '/system/application/modules/upload/uploader.swf',
      'script': '/system/application/modules/upload/upload.php',
      'folder': '/assets/images/tmp',
      'cancelImg': '/system/application/modules/upload/cancel.png',
      'multi': true,
      'buttonText': 'select files',
      'displayData': 'percentage',
      'simUploadLimit': 1,
      'fileExt': '*.jpg;*.jpeg;*.gif;*.png',
      onAllComplete: function(event, data){
      $("#loadTips").append(«Файлов загружено: „+data.filesUploaded+“
      »);
      $("#loadTips").append(«Ошибок: „+data.errors+“
      »);
      $("#loadTips").append(«Загружено: „+data.allBytesLoaded+“ байт
      »);
      },
      onComplete: function(event, queueID, fileObj, response, data){

      idResp=''; // нужно для моего обработчика резалта онАджаксКомплит
      $.post('http://<?=$_SERVER['SERVER_NAME']?>/admin/upload/doupload/', 'name='+fileObj.name+'&path='+fileObj.filePath+'&module=<?=$module;?>&id_pos=<?=$id_pos;?>&conf_name=<?=$conf_name?>', // после загрузки делаем запрос на обработчик (ниже будет пример)
      function(data){
      idResp = ''; // нужно для моего обработчика резалта онАджаксКомплит
      $.get('http://<?=$_SERVER['SERVER_NAME']?>/admin/upload/index/'+data+'/', '',
      function(data){
      $("#gallery_box").fadeIn(250, function() { $("#gallery_box").append(data)}); /* сюда попадают сразу загруженные изображения */
      }
      );
      });
      },

      onError: function(event, queueID, fileD, errorObj){
      $("#loadTips").append(«event: „+event+“
      »);
      $("#loadTips").append(«queueID: „+queueID+“
      »);
      $("#loadTips").append(«fileD: „+fileD+“
      »);
      $("#loadTips").append(«errorObj.status: „+errorObj.status+“
      »);
      $("#loadTips").append(«errorObj.text: „+errorObj.text+“
      »);

      }
      });

      метод что используется после загрузки /admin/upload/doupload/

      function doupload(){
      $data['name'] = $this->input->post('name');
      $data['path'] = $this->input->post('path');

      /* тут любая обработка уже загруженных изображений в folder: /assets/images/tmp у меня — зум, первоначальная обработка, запись в БД… */

      }

      Думаю этого достаточно. Сам плагин подключается в контроллеры через плагин галереи (сделан по аналогии как делать плагин подключения FCK едитора)
      • Парсер маленько попаскудил код, но думаю суть понятная :)
        • Спасибо, попробую
  • Вот бы к этому плагину прикрутить форму по удалению уже загруженных или загрузку новых файлов вместо уже имеющихся.
    • я у себя и прикрутил :) в чём сложность? это уже вопрос даже не к плагину :)
      • да, плагин тут ни причем, просто пока не придумал как это реализовать
  • а cookie он сохраняет?
  • Поправьте в примере: в «checkscript», «script» должен быть с большой буквы: checkScript.
    Я долго думал, почему же оно у меня не работает :)

    А «folder» как-то не понятно рабоает, все равно добавляет путь к скрипту, хотя в доке и написано: For absolute paths prefix the path with either '/' or 'http'.
    • спасибо, исправил :)
    • хотя, как бы я не правил, хабра менять checkscript на checkscript О_о
      • хаброглюк, круто-круто =)
        а в описании тоже не даёт?
        • тоже, хм…
        • даже в комментарии поменял…
  • Вопрос, как в файле настроек поменять скажем локализацию Uploadify, не затрагивая основной плагин (в данном случае jquery.uploadify.v2.1.0.min.js), дабы безболезненно в дальнейшем обновлятся.
    Или скажем поменять внешний динамически создаваемых вид элементов аплоадера (тот-же програесс бар, когда одинм css не обойтись)?

  • <script type=«text/javascript»>
    jQuery(document).ready(function() {
    jQuery("#uploadify").uploadify({
    'uploader': '/flash/uploadify.swf',
    'script': '/test.php',
    'cancelImg': '/img/admin/cancel.png',
    'queueID': 'fileQueue',
    'auto': true,
    'multi': false,
    'method': 'GET',
    'scriptAccess': 'always',
    'fileDesc': 'Audio (*.mp3)',
    'fileExt': '*.mp3',
    'onError': function(event,queueID,fileObj,errorObj) { },
    'onComplete': function(event,queueID,fileObj,response,data) { }
    });
    });
    </script>

    лог апача пишет следующее:

    «POST /test.php?folder=%2Fmusic%2F&fileext=%2A%2Emp3 HTTP/1.1» 302 207 "-" «Shockwave Flash» 24188 4

    и ещё странная штука. флешка 2 раза вызывает test.php в начале загрузки и в конце.
  • Видимо всем пофик
  • А как хэндлить ошибки?
    Тоесть, если у меня произошла ошибка на стадии, например, копирования файла из временной директории в директорию назначения — как сообщить об этом в скрипт, отправивший файл?

    Там в примере uploadify.php в конце есть строкаи

    echo '1';
    и
    echo 'Invalid file type.';

    Но как их ловить — непонятно, onError не вызывается, в onAllComplete тоже errors: 0… куда рыть?
Только авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста.