Ich habe ein Problem, das Senden einer Datei zu einem serverseitigen PHP-Skript mit jQuery & #39; s ajax-Funktion.
Es ist möglich, die Datei-Liste mit $('#fileinput').attr('files')
zu erhalten, aber wie ist es möglich, diese Daten an den Server zu senden? Das resultierende Array ($_POST
) auf dem serverseitigen php-Skript ist 0 (NULL
), wenn die Dateieingabe verwendet wird.
Ich weiß, dass es möglich ist (obwohl ich bis jetzt keine jQuery Lösungen gefunden habe, nur Prototye Code (http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)).
Dies scheint relativ neu zu sein, also bitte nicht erwähnen, dass der Datei-Upload über XHR/Ajax unmöglich wäre, denn es funktioniert definitiv.
Ich brauche die Funktionalität in Safari 5, FF und Chrome wären nett, sind aber nicht zwingend notwendig.
Mein Code für jetzt ist:
$.ajax({
url: 'php/upload.php',
data: $('#file').attr('files'),
cache: false,
contentType: 'multipart/form-data',
processData: false,
type: 'POST',
success: function(data){
alert(data);
}
});
Ab Safari 5/Firefox 4 ist es am einfachsten, die Klasse FormData
zu verwenden:
var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file-'+i, file);
});
Jetzt haben Sie also ein "FormData"-Objekt, das zusammen mit der XMLHttpRequest gesendet werden kann.
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);
}
});
Sie müssen unbedingt die Option contentType
auf false
setzen, um jQuery zu zwingen, keinen Content-Type
-Header für Sie hinzuzufügen, da sonst die Begrenzungszeichenfolge darin fehlt.
Außerdem müssen Sie das processData
-Flag auf false setzen, da jQuery sonst versucht, Ihre FormData
in eine Zeichenkette umzuwandeln, was fehlschlagen wird.
Sie können die Datei nun in PHP abrufen:
$_FILES['file-0']
(Es gibt nur eine Datei, Datei-0
, es sei denn, Sie haben das Attribut multiple
bei der Dateieingabe angegeben, in diesem Fall werden die Zahlen mit jeder Datei erhöht).
Verwendung der FormData-Emulation für ältere Browser
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);
Erstellen von FormData aus einem bestehenden Formular
Anstatt die Dateien manuell zu iterieren, kann das FormData-Objekt auch mit dem Inhalt eines bestehenden Formularobjekts erstellt werden:
var data = new FormData(jQuery('form')[0]);
Verwenden Sie ein PHP-eigenes Array anstelle eines Zählers
Benennen Sie Ihre Dateielemente einfach gleich und schließen Sie den Namen in Klammern ab:
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file[]', file);
});
$_FILES['file']` wird dann ein Array sein, das die Datei-Upload-Felder für jede hochgeladene Datei enthält. Ich empfehle dies gegenüber meiner ursprünglichen Lösung, da es einfacher ist, darüber zu iterieren.
Ich wollte nur ein wenig zu Raphael's große Antwort hinzufügen. Hier's, wie man PHP dazu bringt, die gleichen $_FILES
zu produzieren, unabhängig davon, ob Sie JavaScript zum Übermitteln verwenden.
HTML-Formular:
<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 erzeugt dieses $_FILES
, wenn es ohne JavaScript übermittelt wird:
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
)
)
)
Wenn Sie progressive Verbesserungen vornehmen und Raphael's JS verwenden, um die Dateien zu übermitteln...
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);
}
});
... so sieht PHP's $_FILES
Array aus, nachdem das JavaScript zum Übermitteln verwendet wurde:
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
)
)
Das ist ein nettes Array, und eigentlich das, was manche Leute aus $_FILES
machen, aber ich finde es nützlich, mit demselben $_FILES
zu arbeiten, unabhängig davon, ob JavaScript zum Einreichen verwendet wurde. Also, hier sind einige kleinere Änderungen an der 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. April 2017 edit: Ich habe das Formularelement aus dem Konstruktor von FormData() entfernt - das hat den Code in Safari korrigiert).
Dieser Code macht zwei Dinge.
input
-Namensattribut automatisch ab, was das HTML wartbarer macht. Nun, solange form
die Klasse putImages hat, wird alles andere automatisch erledigt. Das heißt, der Eingang
muss keinen speziellen Namen haben.Mit diesen Änderungen erzeugt die Übermittlung mit JavaScript nun genau das gleiche $_FILES
-Array wie die Übermittlung mit einfachem HTML.
Ich habe diese Funktion gerade auf der Grundlage einiger Informationen, die ich gelesen habe, entwickelt.
Verwenden Sie es wie mit .serialize()
, stattdessen setzen Sie einfach .serializefiles();
.
Arbeiten hier in meinen Tests.
//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);