Запомнить и повторно заполнить файл ввода [дубликат]


На этот вопрос уже есть ответ здесь:

Примечание:

Приведенные ниже ответы отражают состояние устаревших браузеров в 2009 году. Теперь вы можете фактически установить значение элемента ввода файла с помощью JavaScript в 2017 году.

См. ответьте в этом вопросе для деталей, а также демо:
Как установить входное значение файла программно (например, при перетаскивании файлов)?

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

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

Я также открыт для подходов, которые не используют файловый ввод (если это возможно).

Я использую JQuery

4 40

4 ответа:

Ок, вы хотите "запомнить и повторно заполнить файл ввода ", " запомнить их выбор и повторно отобразить файл ввода с файлом , предварительно выбранным при перезагрузке страницы"..
И в комментарии к моему предыдущему ответу вы заявляете, что на самом деле не открыты для альтернатив: "Извините, но нет Flash и апплетов, только javscript и/или файловый ввод, возможно, перетаскивание."

Я заметил во время просмотра (довольно много) повторяющихся вопросов (1, 2, 3, и т.д.) , что практически все другие ответы находятся в следующем порядке: "Нет, вы не можете, это было бы проблемой безопасности", необязательно сопровождаемой простым концептуальным или кодовым примером, описывающим риск безопасности.

Однако кто-то упрямый, как мул (не обязательно плохая вещь до определенного уровня), может воспринять эти ответы как: "нет, потому что я так сказал", что на самом деле является чем-то другим: "нет, и вот спецификации, которые не позволяют он".
Итак, это моя третья и последняя попытка ответить на ваш вопрос (я привел вас к водопою, я привел вас к реке, теперь я толкаю вас к источнику, но я не могу заставить вас пить).

Править 3:

То, что вы хотите сделать, на самом деле было однажды описано/ "предложено" в RFC1867 раздел 3.4:

Атрибут VALUE может использоваться с тегами <INPUT TYPE=file> для имя файла по умолчанию. Это использование, вероятно, зависит от платформы. Может быть однако может быть полезен в последовательностях более чем одной транзакции, например:, чтобы пользователь не запрашивал одно и то же имя файла снова и снова снова.

И действительно, раздел спецификации HTML 4.01 17.4.1 указывает, что:

Агенты пользователей могут использовать значение атрибута value в качестве начального имени файла.

(под "агентами пользователей" они подразумевают "браузеры").

Учитывая факты, что javascript может как модифицировать, так и отправить форму (включая файловый ввод), и можно было бы использовать css для скрытия форм/элементов формы (например, файловый ввод), только вышеупомянутые операторы позволили бы молча загружать файлы с компьютера пользователя без его намерения/знания.
Очевидно, чрезвычайно важно, что это невозможно, и поэтому (выше) RFC1867 заявляет в разделе 8 соображения безопасности :

Важно, чтобы агент пользователя не отправлял файл, который есть у пользователя. нет явно просил, чтобы его послали. Таким образом, агенты интерпретации HTML являются ожидается подтверждение любых имен файлов по умолчанию, которые могут быть предложены с <INPUT TYPE=file VALUE="yyyy">.

Однако единственным браузером (насколько мне известно), который когда-либо реализовывал эти функции, была (некоторые более старые версии) Opera : он принимал<input type="file" value="C:\foo\bar.txt> или значение, установленное javascript (elm_input_file.value='c:\\foo\\bar.txt';).
Когда этот файл-окно было неизменным при отправке формы, Opera будет всплывающее окно безопасности, информирующее пользователя о том, какой файл(ы) где собирается быть загруженные в каком месте (страница/сервер).

Теперь можно утверждать, что все другие браузеры нарушали спецификацию, но это было бы неверно: поскольку спецификация утверждала: "may " (это не "must") ".. используйте атрибут value в качестве начального имени файла".
И, если браузер не принимает установку значения ввода файла (aka, имея это значение просто "только для чтения"), то браузер также не должен был бы всплывать такой "страшный" и "трудный" всплывающее окно безопасности (это может даже не служить его цели, если пользователь не понял его (и / или был "обусловлен", чтобы всегда нажимать "ОК")).

Тогда давайте перейдем к HTML 5..
Здесь вся эта двусмысленность проясняется (хотя это все еще вызывает некоторое недоумение):

Под 4.10.7.1.18 состояние загрузки файла мы можем прочитать в бухгалтерских деталях :

  • значение IDL атрибута находится в режиме filename.
    ...
  • атрибут value элемента должен быть опущен.

Таким образом, атрибут значения входного файла должен быть опущен, но он также работает в некотором "режиме", называемом "filename", который описан в 4.10.7.4 API общих входных элементов:

Атрибут value IDL позволяет скриптам манипулировать значением входного элемента. Атрибут находится в одном из следующих режимов, которые определяют его поведение:

Переходим к этому 'имя файла режима':

При получении он должен вернуть строку "C:\fakepath\" вслед за этим имя первого файла в списке выбранных файлов, если таковые имеются, или пустая строка, если список пуст. При установке, если новое значение равно пустая строка, она должна очистить список выбранных файлов; в противном случае, он должен выдать исключение InvalidStateError.

Позвольте мне повторить: "it must throw an InvalidStateError exception", если попытаться чтобы задать файловое входное значение для строки, которая не является пустой !!! (Но можно очистить поле ввода, установив его значение в пустую строку.)

Таким образом, в настоящее время и в обозримом будущем HTML5 (и в прошлом, кроме Opera), только пользователь может заполнить файл-вход (через браузер или поставляемый ОС "файл-выборщик"). нельзя (повторно)заполнить файл-вход в файл / каталог с помощью javascript или установив значение по умолчанию.

Получение имени файла / пути к файлу

Теперь, предположим, что не было невозможно (повторно)заполнить файловый ввод значением по умолчанию, тогда, очевидно, вам понадобится полный путь: каталог + имя файла (+расширение).

В прошлом некоторые браузеры, такие как (самый заметный) IE6 (до IE8) , действительно показывали полный путь+имя файла как значение: просто alert( elm_input_file.value ); и т. д. в javascript и браузер также отправил этот полный путь+имя файла (+расширение) на принимающий сервер на форма-отправить.
Примечание: некоторые браузеры также имеют атрибут "file или fileName" (обычно отправляется на сервер), но очевидно, что это не будет включать путь..

Это реальная угроза безопасности / конфиденциальности: вредоносный веб-сайт (владелец/эксплуататор) может получить путь к домашнему каталогу пользователя (где хранятся личные данные, учетные записи, файлы cookie, пользовательская часть реестра, история, избранное, рабочий стол и т. д. находится в известных постоянных местах), когда типичный нетехнический windows-пользователь загрузит свои файлы из: C:\Documents and Settings\[UserName]\My Documents\My Pictures\kinky_stuff\image.ext.
Я даже не говорил о рисках при передаче данных (даже "зашифрованных" через https) или "безопасном" хранении этих данных! Таким образом, все больше и больше альтернативных браузеров начали следовать одной из старейших проверенных мер безопасности: обмениваться информацией на основе необходимости знать.
И подавляющему большинству веб-сайтов не нужно знать путь к файлу, поэтому они только показали имя файла(+ расширение).

К тому времени IE8 был выпущен, MS решила последовать за конкурентами и добавила опцию URLAction, названную "включить путь к локальному каталогу при загрузке файлов", которая была установлена в "отключено" для общей интернет-зоны (и "включено" в доверенной зоне) по умолчанию.

Это изменение создало небольшой хаос (в основном в "оптимизированных для IE" средах), где все виды как пользовательского кода, так и проприетарных "элементов управления" не могли получить имя файла загружаемых файлов: они были жестко запрограммированы, чтобы ожидать строка, содержащая полный путь и извлекающая часть после последней обратной косой черты (или прямой косой черты, если вам повезло...). 1, 2

Появился HTML5,
и как вы уже читали выше, "имя файла режима" указывает:

При получении он должен вернуть строку "C:\fakepath за ним следует имя первого файла в списке выбранных файлов, если таковые имеются, или пустая строка, если список пуст.

И они отмечают, что

Это требование "поддельного" является печальной случайностью истории

И

В силу исторических причин, IDL атрибут значение префиксов именем с помощью веревки "C:\fakepath\". Некоторые устаревшие агенты пользователей на самом деле включал полный путь (что было уязвимостью безопасности). Как результатом этого является получение имени файла из атрибута value IDL в способ обратной совместимости нетривиален. Перечисленные ниже функции извлекает имя файла соответствующим образом совместимым образом:

function extractFilename(path) {
  if (path.substr(0, 12) == "C:\\fakepath\\")
    return path.substr(12); // modern browser
  var x;
  x = path.lastIndexOf('/');
  if (x >= 0) // Unix-based path
    return path.substr(x+1);
  x = path.lastIndexOf('\\');
  if (x >= 0) // Windows-based path
    return path.substr(x+1);
  return path; // just the filename
}

примечание: Я думаю, что эта функция глупа: весь смысл в том, чтобы всегда иметь поддельный windows-путь для разбора.. Итак, первое "если" не только бесполезно, но даже вызывает ошибку: представьте себе пользователя с более старым браузером, который загружает файл из: c:\fakepath\Some folder\file.ext (как он вернет: Some folder\file.ext)...
Я бы просто использовал:

function extractFilename(s){ 
  // returns string containing everything from the end of the string 
  //   that is not a back/forward slash or an empty string on error
  //   so one can check if return_value===''
  return (typeof s==='string' && (s=s.match(/[^\\\/]+$/)) && s[0]) || '';
} 

(как явно предполагалось спецификацией HTML5).

Давайте повторим (получение пути/имени файла):

  • старые браузеры (и более новые браузеры, в которых можно включить эту опцию, например IE>=8) откроют полный путь windows/unix
  • менее старые браузеры не показывают никакого пути, только имя файла (+расширение)
  • текущие/будущие / HTML5-совместимые браузеры всегда будут предварительно добавлять строку: c:\fakepath\ к имени файла при получении значения
    Кроме того, они будут возвращать только первое имя файла (из списка выбранных файлов). файлы'), если файл-вход принимает несколько файлов, и пользователь выбрал несколько файлов.

Таким образом, в недавнем прошлом, в настоящее время и в обозримом будущем HTML5 обычно будет только имя файла.

Это подводит нас к последнему, что нам нужно изучить: этот "список выбранных файлов" / multiple-files, который приводит нас к третьей части головоломки:

(HTML5) File API

Прежде всего: 'File API' не должен быть путать с 'API файловой системы', вот это аннотация файл система API:

Эта спецификация определяет API для навигации по иерархиям файловой системы и определяет средства, с помощью которых агент пользователя может предоставлять изолированные разделы локальной файловой системы пользователя веб-приложениям. Он строится на [FILE-WRITER-ED], который, в свою очередь, построен на [FILE-API-ED], каждый из которых добавляет различные функциональные возможности.

" изолированные секции локального пользователя файловая система " уже ясно указывает, что нельзя использовать это, чтобы получить доступ к пользовательским файлам вне песочницы (поэтому не имеет отношения к вопросу, хотя один может скопировать выбранный пользователем файл в постоянное локальное хранилище и повторно загрузить эту копию с помощью AJAX и т. д. Полезно в качестве "повторной попытки" при неудачной загрузке.. Но это не будет указатель на исходный файл, который мог измениться в то же время).
Еще более важным является тот факт, что только webkit (думаю, более старые версии chrome) реализовал эту функцию, и спецификация, скорее всего, не выживет, как это is no more actively maintained, the specification is abandonned for the moment as it didn't get any significant traction

Давайте продолжим с ' File API',
это абстрактное говорит нам:

Эта спецификация предоставляет API для представления файловых объектов в веб-приложений, а также программно выбирать их и доступ к их данным. Это включает в себя:

  • интерфейс FileList, представляющий массив индивидуально выбранные файлы из базовой системы. Пользовательский интерфейс для выбор может быть вызван через <input type="file">, т. е. элемент находится в состоянии загрузки файла [HTML].
  • интерфейс Blob-объекта, представляющий неизменяемые необработанные двоичные данные и позволяющий получить доступ к диапазонам байтов внутри объекта Blob как к отдельному объекту. Клякса.
  • интерфейс файла, который включает в себя только для чтения информационные атрибуты о файле, такие как его имя и дата последнего изменения (на диске) из файл.
  • Интерфейс FileReader, предоставляющий методы для чтения файла или большого двоичного объекта, и модель событий для получения результатов этих операций чтения.
  • схема URL для использования с двоичными данными, такими как файлы, чтобы на них можно было ссылаться в веб-приложениях.

Таким образом, FileList может быть заполнено полем ввода в файловом режиме: <input type="file">.
Это означает, что все вышесказанное о значении-атрибуте по-прежнему применимо!

Когда поле ввода находится в файловый режим, он получает атрибут только для чтения files который является массивоподобным FileList object, который ссылается на выбранный пользователем файл(ы) входного элемента и доступен(/доступны) с помощью FileList interface.
Я упоминал, что files-атрибут типа FileList является доступным только для чтения (раздел API файлов 5.2) ? :

Интерфейс HTMLInputElement [HTML] имеет атрибут readonly типа FileList...

Ну, а как насчет перетаскивания и падение ?

Из mdn-документация-выбор файлов с помощью перетаскивания

Настоящая магия происходит в функции drop ():

function drop(e) {
  e.stopPropagation();
  e.preventDefault();

  var dt = e.dataTransfer;
  var files = dt.files;

  handleFiles(files);
}

Здесь мы извлекаем поле dataTransfer из события, затем вытягиваем список файлов из него, передавая его в handleFiles(). От этой точки при этом обработка файлов остается той же, что и при использовании пользователем входных данных. элемент или перетаскивание.

Итак, (как и поле ввода type= "file",) атрибут события dataTransfer имеет массивоподобный атрибут files, который является массивоподобным FileList object, и мы только что узнали (выше), что список файлов доступен только для чтения..

Список файлов содержит ссылки на файлы, выбранные пользователем (или отброшенные в целевой объект), и некоторые атрибуты. Из File API раздела 7.2 File Attributes мы можем прочитать:

Имя

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

LastModifiedDate

Дата последнего изменения файла. При получении, если агенты пользователей могут сделайте эту информацию доступной, это должно вернуть новую дату[HTML] объект, инициализированный до последней измененной даты файл. Если последнее дата и время модификации неизвестны, атрибут должен вернуться текущая дата и время как объект даты.

И есть атрибут size:

Размер F. такой же, как размер fileBits аргумент BLOB-объектов, которые должны быть неизменными исходные данные Ф.

Опять же, никакого пути, только имя файла только для чтения.

Таким образом:

  • (elm_input||event.dataTransfer).files дает объект FileList.
  • (elm_input||event.dataTransfer).files.length задает количество файлов.
  • (elm_input||event.dataTransfer).files[0] - это первый выбранный файл.
  • (elm_input||event.dataTransfer).files[0].name - имя файла первого выбранного файла
    (и это value, который возвращается из входного типа= "file").

Как насчет этой "схемы URL-адресов для использования с двоичными данными, такими как файлы, чтобы на них можно было ссылаться в веб-приложениях", несомненно, которая может содержать личную ссылку на файл, выбранный пользователем?

От файловый API - это URL для Blob-объектов и ссылка на файл мы можем узнать, что:

Эта спецификация определяет схему с URL-адресами вида:
blob:550e8400-e29b-41d4-a716-446655440000#aboutABBA.

Они хранятся в URL store (и браузеры должны даже иметь свой собственный мини-HTTP-сервер на борту, так что можно использовать эти URL-адреса в css, img src и даже XMLHttpRequest.

Можно создать эти Blob URLs с помощью:

  • var myBlobURL=window.URL.createFor(object); возвращает a Blob URL, который автоматически отменяется после первого использования.
  • var myBlobURL=window.URL.createObjectURL(object, flag_oneTimeOnly); возвращает многоразовый Blob URL (если только значение flag_oneTImeOnly не равно true) и может быть отозвано с помощью window.URL.revokeObjectURL(myBlobURL).

Бинго, как вы можете подумать... однако... URL Store поддерживается только во время сеанса (поэтому он переживет обновление страницы, так как это все еще тот же сеанс) и теряется при выгрузке документа.

Из MDN-Using object URLs :

В URL объекта-это строка, идентифицирующая объект File. Каждый раз, когда ты окно вызова.URL-АДРЕС.createObjectURL(), создается уникальный URL объекта, даже если вы уже создали URL-адрес объекта для этого файла. Каждый из них они должны быть освобождены. В то время как они освобождаются автоматически, когда документ выгружается, если ваша страница использует их динамически, вы должны освободите их явно, вызвав окно.URL-АДРЕС.revokeObjectURL ()

Это означает, что даже когда вы храните Blob URL строка в файле cookie или постоянном локальном хранилище, эта строка будет бесполезна в новом сеансе!

Это должно привести нас к полному кругу и окончательному выводу.:
невозможно (повторно)заполнить поле ввода или выбранный пользователем файл (который не находится в изолированной области "локальное хранилище" браузеров).
(Если только вы не заставите своих пользователей использовать устаревшую версию Opera или не заставите их использовать IE и некоторые модули activeX (реализация пользовательского file-picker), etc)

Еще немного reading:
http://www.cs.tut.fi/~jkorpela/forms/file.html
https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://www.html5rocks.com/en/tutorials/file/dndfiles/
http://caniuse.com/filereader
JavaScript: окончательное руководство-Дэвид Фланаган, Глава-22: файловая система api
как сохранить окно.URL-АДРЕС.результат createObjectURL () для использования в будущем?
как долго сохраняется капля?
как решить проблему C:\fakepath?

Создайте поле ввода в форме. Когда пользователь выбирает файл, скопируйте результат в это поле, что-то вроде:

jQuery('#inFile').change(
 function(){ jQuery('#inCopy').val( jQuery('#inFile').val() ); }
);

На самом деле, результат не копируется точно, вместо этого он копирует "C:/fakepath/SELECTED_FILE_NAME". Хотя вам не разрешено задавать значение ввода файла, вы можете задать значение поля ввода текста, без "C:/fakepath/", так как сервер готовит форму.

Теперь, когда сервер вернет форму, проверьте поле ввода текста. Если начнется ... с "C:/fakepath/" тогда пользователь должен выбрать новый файл, поэтому загрузите их новый выбор. Если это не так, то пользователь выбрал предыдущий выбор, что не должно быть проблемой, так как, согласно исходному вопросу, предыдущий выбор был загружен раньше и должен (по крайней мере, при соответствующем программировании, это может быть) все еще находиться на сервере.

Рискуя наступить на пятки огромной информации, предоставленной GitaarLAB, я мог бы предположить, что DaveWalley очень близок к практическому решению этой проблемы. Вы оба мне очень помогли, так что спасибо.

Мое сообщение о возвращении домой,

  1. входной файл предлагает улицу с односторонним движением. Он сидит там, ожидая, чтобы обработать вашу следующую загрузку. Это все, что он делает, в значительной степени. Он получает .
  2. div или текстовая форма только для чтения, вводимая рядом с меткой для вашего файла вход может сделать служащий . то есть он может быть использован, чтобы сказать пользователю: "вот то, что в данный момент загружено:" - имя файла для отображения должно быть заполнено из вашей логики на стороне сервера.

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

  • пользователь загружает файл через форму ввода на веб-странице
  • Логика на стороне сервера хранит файл
  • в цикле Ajax или перезагрузке веб-страницы код на стороне сервера определяет строку имени файла для записи в div, "Вот что загружено в данный момент"
  • входной файл также может быть повторно представлен, так что пользователь может загрузить другой файл, а также / вместо этого.

Возможно, вам потребуется еще немного поработать, чтобы справиться с проверкой "* required", но это уже другая история.

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

Это не приводит к повторному заполнению поля ввода файла. Но вы также можете просто взять имя введенного файла и поместить его рядом с полем ввода файла.

Как Итак:

<input type=hidden name="filename" value="<?php echo $filename; ?>" />
<input type="file" name="uploadfile" size="50" />

<?php if (!empty($filename)) echo $filename; ?>