RSS
 

Загрузка браузером нескольких файлов

12 Дек

Если нужно дать пользователю возможность загрузки нескольких файлов, традиционное решение на данный момент — использовать для этой цели Flash (реже — Java applet или ActiveX). В случае, если соответствующий плагин недоступен, пользователю, как правило, показывают стандартный HTML-элемент для загрузки файла.

Последнюю ситуацию можно улучшить, если использовать встроенную в браузеры возможность множественной загрузки файлов. Из всех браузеров сейчас данную возможность не поддерживает только Internet Explorer (впрочем, мы ещё не видели девятую версию, может там что-то изменится), остальные браузеры — Opera 9 и выше (а так же версии 3.5—6.05), Firefox 3.6+, Chrome 3.0.191.0+ и Safari 4.0.1+ такую возможность предоставляют.

Достаточно написать что-то вроде

  1. <form enctype=”multipart/form-data” method=”post”>
  2.     <input type=”filemin=”1? max=”9999? name=”file[]“ multiple=”true” />
  3.     <input type=”submit” name=”submit” />
  4. </form>


PHP оказался готов к такой конструкции (именно для него в параметре «name» стоят квадратные скобки), он просто разложит загружаемые файлы по элементам массива $_FILES, если только мы не используем «Оперу».

К сожалению, «Опера» (ещё с версии 3.5) отправляет, при использовании мультизагрузки, файлы в контейнере «multipart/mixed», который PHP не понимает.

Можно попробовать исправить эту ситуацию.

К счастью для нас, PHP, приняв такой запрос, поместит его содержимое в массив $_POST (в данном случае он попадёт в $_POST['file'][0], дальше остаётся только распарсить его и переложить в $_FILES (надеюсь, директива magic_quotes_gpc у вас отключена).

В качестве парсера я использовал PECL-модуль mailparse (есть бинарник для Windows).

У меня в примере ожидается параметр «file», но это значение легко вынести в настройку. Код мне кажется достаточно простым, чтобы его не комментировать, но, если что-то не понятно, спросите, я добавлю комментарии.

  1.  if (isset($_POST['file'], $_POST['file'][ 0])) {
  2.  
  3.      if ($idx = strpos($_POST['file'][  0], "\n")) {
  4.          $bound = substr($_POST['file'][  0], 2, $idx-2);
  5.  
  6.          $body = "MIME-Version: 1.0\nContent-type: multipart/form-data; boundary={$bound}\n\n".
  7.                   $_POST['file'][  0];
  8.  
  9.          unset($_POST['file'][  0]);
  10.          $f = &$_FILES['file'];
  11.  
  12.          $f['name'] = $f['type'] = $f['tmp_name'] = $f['error'] = $f['size'];
  13.  
  14.          $msg = mailparse_msg_create();
  15.  
  16.          if (mailparse_msg_parse($msg, $body)) {
  17.              $i =  0;
  18.  
  19.              foreach(mailparse_msg_get_structure($msg) as $st) {
  20.  
  21.                  $section = mailparse_msg_get_part($msg, $st);
  22.  
  23.                  $data = mailparse_msg_get_part_data($section);
  24.  
  25.                  if ($data['content-type'] == 'multipart/form-data') {
  26.                      continue;
  27.                  }
  28.  
  29.                  ob_start();
  30.                  if (mailparse_msg_extract_part($section, $body)) {
  31.                      $tmp = tempnam(sys_get_temp_dir(), 'php');
  32.                      file_put_contents($tmp, ob_get_clean());
  33.  
  34.                      $f['name'][$i] = $data['disposition-filename'];
  35.                      $f['type'][$i] = $data['content-type'];
  36.                      $f['tmp_name'][$i] = $tmp;
  37.                      $f['error'][$i] =  0;
  38.                      $f['size'][$i] = filesize($tmp);
  39.  
  40.                      $i++;
  41.                  } else {
  42.                      ob_end_clean();
  43.                  }
  44.              }
  45.          }
  46.          unset($f);
  47.  
  48.          mailparse_msg_free($msg);
  49.      }
  50. }


Будем рады возникшим вопросам.

 
 

Теги: ,

Если понравился пост, то подпишитесь на новые!

Введите свой E-mail:

Оставить комментарий