Ich habe ein Problem beim Senden einer Datei an ein serverseitiges PHP-Skript mit der jjery-Funktion ajax-function . Es ist möglich, die Dateiliste mit $('#fileinput').attr('files')
abzurufen, aber wie können diese Daten an den Server gesendet werden? Das resultierende Array ($_POST
) im serverseitigen PHP-Skript ist 0 (NULL
), wenn die Dateieingabe verwendet wird.
Ich weiß, dass dies möglich ist (obwohl ich bisher 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. Erwähnen Sie bitte nicht, dass das Hochladen von Dateien über XHR/Ajax unmöglich ist, da es definitiv funktioniert.
Ich brauche die Funktionalität in Safari 5, FF und Chrome wären zwar nett, aber nicht zwingend erforderlich.
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 FormData
-Klasse zu verwenden:
var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file-'+i, file);
});
Jetzt haben Sie ein FormData
-Objekt, das zusammen mit 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 die Option contentType
unbedingt auf false
setzen, sodass jQuery keinen Content-Type
-Header für Sie hinzufügen muss. Andernfalls fehlt die Begrenzungszeichenfolge .. processData
-Flag muss auf false festgelegt sein. jQuery versucht, FormData
in eine Zeichenfolge umzuwandeln, die fehlschlägt.
Sie können die Datei jetzt in PHP abrufen mit:
$_FILES['file-0']
(Es gibt nur eine Datei, file-0
, sofern Sie bei Ihrer Dateieingabe nicht das multiple
-Attribut angegeben haben. In diesem Fall werden die Zahlen mit jeder Datei erhöht.)
Verwenden 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);
FormData aus einem vorhandenen Formular erstellen
Anstatt die Dateien manuell zu durchlaufen, kann das FormData-Objekt auch mit dem Inhalt eines vorhandenen Formularobjekts erstellt werden:
var data = new FormData(jQuery('form')[0]);
Verwenden Sie ein natives Array PHP anstelle eines Zählers.
Benennen Sie Ihre Dateielemente einfach gleich und beenden Sie den Namen in Klammern:
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file[]', file);
});
$_FILES['file']
ist dann ein Array mit den Feldern zum Hochladen der Datei für jede hochgeladene Datei. Ich empfehle dies tatsächlich gegenüber meiner ursprünglichen Lösung, da es einfacher ist, das Programm zu wiederholen.
Ich wollte nur Raffaels großartige Antwort etwas hinzufügen. So können Sie mit PHP denselben $_FILES
erstellen, unabhängig davon, ob Sie zum Senden JavaScript 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 diesen $_FILES
, wenn er 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 durchführen, verwenden Sie Raphaels JS, um die Dateien zu senden ...
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 das $_FILES
-Array von PHP aus, nachdem dieses JavaScript zum Übergeben 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 Nice-Array, und tatsächlich verwandeln einige Leute $_FILES
in, aber ich finde es nützlich, mit demselben $_FILES
zu arbeiten, unabhängig davon, ob zum Senden JavaScript verwendet wurde. 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 - dadurch wurde dieser Code in Safari behoben.)
Dieser Code macht zwei Dinge.
input
name-Attribut automatisch ab, sodass der HTML-Code leichter zu verwalten ist. Solange form
die Klasse putImages hat, wird alles andere automatisch erledigt. Das heißt, die input
muss keinen besonderen Namen haben.Mit diesen Änderungen erzeugt das Senden mit JavaScript jetzt genau das gleiche $_FILES
-Array wie das Senden mit einfachem HTML.
Schau dir meinen Code an, er erledigt die Arbeit für mich
$( '#formId' )
.submit( function( e ) {
$.ajax( {
url: 'FormSubmitUrl',
type: 'POST',
data: new FormData( this ),
processData: false,
contentType: false
} );
e.preventDefault();
} );
Ich habe diese Funktion nur basierend auf einigen Informationen erstellt, die ich gelesen habe.
Verwenden Sie es wie .serialize()
, stattdessen .serializefiles();
.
Arbeit 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);
Wenn Ihr Formular in Ihrem HTML-Code definiert ist, ist es einfacher, das Formular an den Konstruktor zu übergeben, als Bilder zu iterieren und hinzuzufügen.
$('#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){
...
Devin Venables Antwort war nahe an dem, was ich wollte, aber ich wollte eines, das an mehreren Formularen arbeiten würde und die bereits im Formular angegebene Aktion verwenden würde, damit jede Datei an die richtige Stelle geht.
Ich wollte auch die on () - Methode von jQuery verwenden, um die Verwendung von .ready () zu vermeiden.
Das brachte mich dazu: (Ersetze formSelector durch deinen jQuery-Selector)
$(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.
});
});
Die FormData-Klasse funktioniert zwar, jedoch konnte ich in iOS Safari (zumindest auf dem iPhone) die Lösung von Raphael Schweikert nicht so verwenden, wie sie ist.
Mozilla Dev hat eine schöne Seite zur Bearbeitung von FormData-Objekten .
Fügen Sie also irgendwo auf Ihrer Seite ein leeres Formular hinzu, und geben Sie den enctype an:
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo"></form>
Erstellen Sie dann das FormData-Objekt als:
var data = new FormData($("#fileinfo"));
und verfahren Sie wie in Raphaels Code .
Ältere Versionen von IE unterstützen FormData nicht (die vollständige Liste der Browser-Unterstützung für FormData finden Sie hier: https://developer.mozilla.org/en-US/docs/Web/API/FormData ).
Sie können entweder ein Jquery-Plugin verwenden (z. B. http://malsup.com/jquery/form/#code-samples ), oder Sie können eine IFrame-basierte Lösung verwenden, um Multipart-Formulardaten über ajax zu posten: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
Wenn die Dateieingabe name
ein Array und Flags multiple
angibt und Sie das gesamte form
mit FormData
analysieren, ist es nicht erforderlich, die Eingabe iterativ append()
durchzuführen Dateien. FormData
verarbeitet automatisch mehrere Dateien.
$('#submit_1').on('click', function() {
let data = new FormData($("#my_form")[0]);
$.ajax({
url: '/path/to/php_file',
type: 'POST',
data: data,
processData: false,
contentType: false,
success: function(r) {
console.log('success', r);
},
error: function(r) {
console.log('error', r);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="my_form">
<input type="file" name="multi_img_file[]" id="multi_img_file" accept=".gif,.jpg,.jpeg,.png,.svg" multiple="multiple" />
<button type="button" name="submit_1" id="submit_1">Not type='submit'</button>
</form>
Beachten Sie, dass ein regulärer button type="button"
verwendet wird, nicht type="submit"
. Dies zeigt, dass keine Abhängigkeit von der Verwendung von submit
besteht, um diese Funktionalität zu erhalten.
Der resultierende Eintrag $_FILES
sieht in den Chrome Dev-Tools folgendermaßen aus:
multi_img_file:
error: (2) [0, 0]
name: (2) ["pic1.jpg", "pic2.jpg"]
size: (2) [1978036, 2446180]
tmp_name: (2) ["/tmp/phphnrdPz", "/tmp/phpBrGSZN"]
type: (2) ["image/jpeg", "image/jpeg"]
Hinweis: In einigen Fällen können einige Bilder problemlos als einzelne Datei hochgeladen werden, sie schlagen jedoch fehl, wenn sie in mehreren Dateien hochgeladen werden. Das Symptom ist, dass PHP leere $_POST
und $_FILES
meldet, ohne dass AJAX Fehler verursacht. Problem tritt mit Chrome 75.0.3770.100 und PHP 7.0 auf. Scheint nur mit 1 von mehreren Dutzend Bildern in meinem Testset zu passieren.
Nova Tage brauchen Sie nicht einmal jQuery :) API-Unterstützungstabelle abrufen
let result = fetch('url', {method: 'POST', body: new FormData(documemt.querySelector("#form"))})
Ein Problem, auf das ich heute gestoßen bin, ist meines Erachtens in Bezug auf dieses Problem hervorzuheben: Wenn die URL für den Ajax-Aufruf umgeleitet wird, kann der Header für den Inhaltstyp "Multipart/Form-Daten" verloren gehen.
Zum Beispiel habe ich auf http://server.com/context?param=x gepostet.
Auf der Registerkarte "Netzwerk" von Chrome habe ich den richtigen mehrteiligen Header für diese Anforderung gesehen, dann aber eine 302-Weiterleitung zu http://server.com/context/?param=x (Beachten Sie den Schrägstrich hinter dem Kontext)
Während der Weiterleitung ging der mehrteilige Header verloren. Stellen Sie sicher, dass Anforderungen nicht umgeleitet werden, wenn diese Lösungen für Sie nicht funktionieren.
Alle oben genannten Lösungen sehen gut und elegant aus, das FormData () -Objekt erwartet jedoch keinen Parameter. Verwenden Sie danach append (), um es zu instanziieren, wie es oben beschrieben wurde:
formData.append (val.name, val.value);