Wysyłanie multipart / formdata za pomocą jQuery.ajax
Mam problem z wysłaniem pliku na serwer skrypt PHP przy użyciu funkcji ajax jQuery.
Możliwe jest uzyskanie listy plików za pomocą $('#fileinput').attr('files')
, ale jak można wysłać te dane na serwer? Tablica wynikowa ($_POST
) na serwerze skryptu php wynosi 0 (NULL
) Podczas używania pliku-input.
Wiem, że to możliwe (choć do tej pory nie znalazłem żadnych rozwiązań jQuery, tylko Kod Prototye (http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)).
To wydaje się być stosunkowo nowe, więc proszę nie wspominać przesyłanie plików byłoby niemożliwe przez XHR / Ajax, ponieważ to na pewno działa.
[4]} potrzebuję funkcjonalności w Safari 5, FF i Chrome byłoby miło, ale nie są niezbędne.Mój kod na razie to:
$.ajax({
url: 'php/upload.php',
data: $('#file').attr('files'),
cache: false,
contentType: 'multipart/form-data',
processData: false,
type: 'POST',
success: function(data){
alert(data);
}
});
11 answers
Począwszy od Safari 5/Firefox 4, najłatwiej jest użyć klasy FormData
:
var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file-'+i, file);
});
Więc teraz masz FormData
obiekt gotowy do wysłania wraz z XMLHttpRequest.
jQuery.ajax({
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
});
Konieczne jest, aby ustawić opcję contentType
na false
, zmuszając jQuery do nie dodawania nagłówka Content-Type
dla Ciebie, w przeciwnym razie nie będzie w nim ciągu granicznego.
Należy również pozostawić flagę processData
ustawioną na false, w przeciwnym razie jQuery spróbuje przekonwertować FormData
na łańcuch znaków, który porażka.
Możesz teraz pobrać plik w PHP używając:
$_FILES['file-0']
(istnieje tylko jeden plik, file-0
, chyba że podałeś atrybut multiple
na wejściu pliku, w którym to przypadku liczby będą wzrastać z każdym plikiem.)
Korzystanie z emulacji FormData dla starszych przeglądarek
var opts = {
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
};
if(data.fake) {
// Make sure no text encoding stuff is done by xhr
opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; }
opts.contentType = "multipart/form-data; boundary="+data.boundary;
opts.data = data.toString();
}
jQuery.ajax(opts);
Tworzenie FormData z istniejącego formularza
Zamiast ręcznie iterować pliki, obiekt FormData można również utworzyć za pomocą zawartość istniejącego obiektu formularza:
var data = new FormData(jQuery('form')[0]);
Użycie natywnej tablicy PHP zamiast licznika
Po prostu nazwij elementy pliku tak samo i zakończ nazwę w nawiasach:
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file[]', file);
});
$_FILES['file']
będzie to tablica zawierająca pola przesyłania plików dla każdego przesłanego pliku. Faktycznie polecam to w stosunku do mojego początkowego rozwiązania, ponieważ jest prostsze do iteracji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-05 20:13:40
Chciałem tylko dodać trochę do wspaniałej odpowiedzi Rafaela. Oto jak sprawić, by PHP stworzyło ten sam $_FILES
, niezależnie od tego, czy używasz JavaScript do przesyłania.
Formularz HTML:
<form enctype="multipart/form-data" action="/test.php"
method="post" class="putImages">
<input name="media[]" type="file" multiple/>
<input class="button" type="submit" alt="Upload" value="Upload" />
</form>
PHP tworzy to $_FILES
, gdy jest złożone bez JavaScript:
Array
(
[media] => Array
(
[name] => Array
(
[0] => Galata_Tower.jpg
[1] => 518f.jpg
)
[type] => Array
(
[0] => image/jpeg
[1] => image/jpeg
)
[tmp_name] => Array
(
[0] => /tmp/phpIQaOYo
[1] => /tmp/phpJQaOYo
)
[error] => Array
(
[0] => 0
[1] => 0
)
[size] => Array
(
[0] => 258004
[1] => 127884
)
)
)
Jeśli zrobisz progresywne ulepszenie, użyj js Rafaela do przesłania plików...
var data = new FormData($('input[name^="media"]'));
jQuery.each($('input[name^="media"]')[0].files, function(i, file) {
data.append(i, file);
});
$.ajax({
type: ppiFormMethod,
data: data,
url: ppiFormActionURL,
cache: false,
contentType: false,
processData: false,
success: function(data){
alert(data);
}
});
... tak wygląda tablica PHP $_FILES
po użyciu JavaScript do przesłania:
Array
(
[0] => Array
(
[name] => Galata_Tower.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpAQaOYo
[error] => 0
[size] => 258004
)
[1] => Array
(
[name] => 518f.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpBQaOYo
[error] => 0
[size] => 127884
)
)
To Ładna tablica, a właściwie to w co niektórzy przekształcają $_FILES
, ale uważam, że warto pracować z tym samym $_FILES
, niezależnie od tego, czy JavaScript został użyty do przesłania. Tak więc, oto kilka drobnych zmian w JS:
// match anything not a [ or ]
regexp = /^[^[\]]+/;
var fileInput = $('.putImages input[type="file"]');
var fileInputName = regexp.exec( fileInput.attr('name') );
// make files available
var data = new FormData();
jQuery.each($(fileInput)[0].files, function(i, file) {
data.append(fileInputName+'['+i+']', file);
});
(14 kwietnia 2017 edit: usunąłem element formularza z konstruktora FormData() -- który naprawił ten kod w Safari.)
Ten kod robi dwie rzeczy.
- pobiera atrybut
input
name automatycznie, dzięki czemu HTML jest łatwiejszy do utrzymania. Teraz, jako o ileform
ma klasę putImages, Wszystko inne jest obsługiwane automatycznie. Oznacza to, żeinput
nie muszą mieć żadnej specjalnej nazwy. - format tablicy, który przesyła zwykły HTML, jest odtwarzany przez JavaScript w danych.Dołącz linię. Zwróć uwagę na nawiasy.
Z tymi zmianami, przesyłanie za pomocą JavaScript tworzy teraz dokładnie taką samą tablicę $_FILES
Jak przesyłanie za pomocą prostego HTML.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-14 17:00:50
Właśnie zbudowałem tę funkcję na podstawie informacji, które przeczytałem.
Użyj go jak używając .serialize()
, zamiast tego po prostu umieść .serializefiles();
.
Pracuję tu przy testach.
//USAGE: $("#form").serializefiles();
(function($) {
$.fn.serializefiles = function() {
var obj = $(this);
/* ADD FILE TO PARAM AJAX */
var formData = new FormData();
$.each($(obj).find("input[type='file']"), function(i, tag) {
$.each($(tag)[0].files, function(i, file) {
formData.append(tag.name, file);
});
});
var params = $(obj).serializeArray();
$.each(params, function (i, val) {
formData.append(val.name, val.value);
});
return formData;
};
})(jQuery);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-10 17:01:07
Spójrz na mój kod, robi to za mnie
$( '#formId' )
.submit( function( e ) {
$.ajax( {
url: 'FormSubmitUrl',
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
} );
e.preventDefault();
} );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-04 05:06:22
Jeśli formularz jest zdefiniowany w HTML, łatwiej jest przekazać formularz do konstruktora niż iterację i dodawanie obrazów.
$('#my-form').submit( function(e) {
e.preventDefault();
var data = new FormData(this); // <-- 'this' is your form element
$.ajax({
url: '/my_URL/',
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 17:43:39
Odpowiedź Devina Venable ' a była zbliżona do tego, czego chciałem, ale chciałem takiego, który będzie działał na wielu formularzach i wykorzysta akcję określoną już w formularzu, aby każdy plik trafił we właściwe miejsce.
Chciałem również użyć metody jQuery ' s on (), aby uniknąć używania .ready ().
That got me to this: (zastąp formSelector selektorem jQuery)
$(document).on('submit', formSelecter, function( e ) {
e.preventDefault();
$.ajax( {
url: $(this).attr('action'),
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
}).done(function( data ) {
//do stuff with the data you got back.
});
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:45
Klasa FormData działa, jednak w iOS Safari (przynajmniej na iPhonie) nie byłem w stanie użyć rozwiązania Raphaela Schweikerta tak jak jest.
Mozilla dev ma ładną Stronę na temat manipulowania obiektami FormData .
Więc dodaj pusty formularz gdzieś na swojej stronie, podając enctype:
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>
Następnie utwórz obiekt FormData jako:
var data = new FormData($("#fileinfo"));
I postępować jak w Kod Rafaela .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:45
Jedna wpadka, na którą dziś wpadłem, myślę, że warto zwrócić uwagę na ten problem: jeśli adres url wywołania ajax zostanie przekierowany, to nagłówek dla content-type: 'multipart/form-data' może zostać utracony.
Na przykład pisałem do http://server.com/context?param=x
W zakładce sieć Chrome widziałem poprawny nagłówek multipart dla tego żądania, ale potem przekierowanie 302 do http://server.com/context/?param=x (zwróć uwagę na ukośnik po context)
Podczas przekierowania utracono nagłówek wieloczęściowy. Upewnij się, że żądania nie są przekierowywane, jeśli te rozwiązania nie działają dla Ciebie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-17 22:07:16
Starsze wersje IE nie obsługują FormData ( pełna lista wsparcia przeglądarki dla FormData znajduje się tutaj: https://developer.mozilla.org/en-US/docs/Web/API/FormData).
Albo możesz użyć wtyczki jquery (dla ex, http://malsup.com/jquery/form/#code-samples ) lub, można użyć rozwiązania IFrame oparte na danych formularza wieloczęściowego poprzez ajax: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-08 10:42:19
Wszystkie powyższe rozwiązania wyglądają dobrze i elegancko, ale obiekt FormData () nie oczekuje żadnego parametru, ale używa append () po utworzeniu instancji, tak jak napisano powyżej:
FormData. append(val.name, val.wartość);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 13:47:10
- get form object by jquery - > $("#id") [0]
- data = new FormData ($("#id")[0]);
- Ok,data jest twoim pragnieniem
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-18 10:11:39