Описаний в цій замітці спосіб асинхронної завантаження файлів заснований на передбаченої в HTML-стандарті можливості передачі даних з форми в будь-який IFRAME, наявний на сторінці. Форма пов'язана з IFRAME через атрибут «target», який повинен збігатися з атрибутом «name» у IFRAME.
Почав з того, що написав свого роду HTML прототип, щоб встановити адекватність роботи цього методу у всіх браузерах.
Щоб відстежувати, що приходить з форми на сервер, створив файлик «upload.php» з наступним кодом:
Перевірив - працює навіть в IE (Internet Explorer 8 в режимі IE7).
плюс функція, яка призначена в обробнику події «onChange» елемента INPUT:
Я думав, що зробив все по розуму, але не тут-то було. У Mozilla Firefox, Google Chrome і Opera все працює саме так, як і повинно було, але ось IE відзначився. Всі елементи мають місце, на перший погляд, нормально, але при Сабміт форми, чомусь, дані відправлялися не в IFRAME, а в нове вікно, при цьому масив $ _FILES виявився порожнім, а в масиві $ _POST з'явився елемент з ключем «upload» . Очевидно, що дані з мого INPUT чомусь потрапили не в $ _FILES, а в $ _POST. Така ситуація виникає, якщо у форми не вказано спосіб кодування даних при їх відправленні на сервер "multipart / form-data" (атрибут «enctype»). Здивувався. Став дивитися DOM засобами розробника.
Вивчення DOM-а показало що атрибут «enctype» у форми варто саме такий, як і потрібно, а ось INPUT і IFRAME замість атрибута «name» мають атрибут «submitName». Здивувався ще сильніше. Стало зрозуміло, чому дані з форми полетіли не в IFRAME, а в нове вікно - бо IFRAME з ім'ям зазначеним в атрибуті «target» у форми на сторінці нема тексту (це ім'я, чомусь, перетворилося в атрибут «submitName»).
Хоча ситуація з потраплянням даних з INPUT-а в масив $ _POST замість $ _FILES поки і залишилася незрозумілою, вирішив почати з усунення проблеми атрибутів «name» у INPUT і IFRAME.
Спробував ставити значення атрибута «name" не через метод setAttribute (), а просто як властивість об'єкта: input.name = 'upload' і frame.name = 'frame'. Результат той же.
Погуглити, швидко з'ясував, що проблема «submitName» у IE дійсно має місце бути. Вирішення цієї проблеми виявилося дуже простим - потрібно створювати елементи через innerHTML відразу з прописаним атрибутом «name». Сподобалося рішення, знайдене на просторах інтернету, що дозволяє отримати елемент у вигляді об'єкта, не дивлячись на те, що він, по суті, створюється за допомогою innerHTML. Для зручності використання оформив цей спосіб в функцію.
Слід звернути увагу на те, що при використанні цього підходу в IE чомусь не вдається поставити для INPUT атрибут «type» через setAttribute () або через властивість об'єкта, тому type = "file" довелося теж прописувати в innerHTML.
Нарешті запрацював і в IE.
Але проблема в IE з тим, що дані з INPUT-а форми не потрапляють в масив $ _FILES, все ще збереглася. Ще раз уважно подивився DOM засобами розробника - у форми дійсно варто enctype = "multipart / form-data". WTF. Після довгих роздумів, експериментів і гугленій, спробував прописати у форми атрибут «enctype» прямо в innerHTML.
О, диво. Запрацювало. У світлі цього відкриття встає закономірне питання - на скільки можна довіряти засобам розробника IE?
Ну і на завершення, щоб завантаження файлів таки реально запрацювала, поміняв код файлу «upload.php»:
Файли завантажуються в папку «uploads», АЛЕРТ повідомляють про результати завантаження. Працює у всіх браузерах, в тому числі і в IE. Мета досягнута.
В прикріпленому до статті архіві Ви знайдете остаточний варіант скрипта асинхронної завантаження файлів через прихований IFRAME.