私は、Ajaxを使用してコントローラーにフォームデータを送信するSymfony 2.8ベースのWebアプリを実行しています。
これまでのところ、すべてが正常に機能していましたが、バージョン10.13.4への最新のmacOSアップデートが報告を開始しているため、フォームの送信はSafariではもう機能しません。 10.13.4のその他のmacOSバージョンおよびその他のブラウザは引き続き正常に動作するため、Safariでは問題のようです。もちろん、私はバグ報告をアップルに提出しましたが、そこからフィードバックを受け取ることはないと思います...
問題の原因を特定できました。空のファイル入力を含むデータの送信に失敗しました。
// safri_bug.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form name="app_booking" method="post" action="/test/submit.php">
<div><input type="text" id="someValue" name="value"></div>
<div><input id="thefile" type="file" name="file"></div>
</form>
<button id="bSubmit" type="button">Submit</button>
<script>
$(document).ready(function() {
$('#bSubmit').click(function() {
var form = $('form');
var data = new FormData(form[0]);
$.ajax({
url : '/submit.php',
type : 'POST',
data : data,
contentType: false,
processData: false,
context : this,
success : function(response) {
alert('success: ' + response);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error: ' + xhr.responseText + ' - ' + thrownError);
}
});
});
});
</script>
</body>
</html>
// submit.php
<?php
echo "OK";
結果
submit.php
は[〜#〜] not [〜#〜]呼び出されます。つまり、これは最新のSafariアップデートのバグのようですか?それとも私のコードに何か問題がありますか?
このバグを防ぐ方法はありますか?
一方、私はこの迅速で汚い解決策を見つけました。しかし、実際には実際の回避策を探しています。何か案は?
// Filter out empty file just before the Ajax request
// Use try/catch since Safari < 10.13.4 does not support FormData.entries()
try {
for (var pair of data.entries()) {
if (pair[1] instanceof File && pair[1].name == '' && pair[1].size == 0)
data.delete(pair[0]);
}
} catch(e) {}
Andrei Herfordのソリューションは、FormDataのentries()メソッドをサポートしない他のブラウザをクラッシュさせます。try/ catchを使用すると、構文エラーではなく実行エラーのみが検出されます。
私たちの解決策は、プレーンなJavaScriptを使用して空のファイル入力要素を削除することでしたbefore FormDataオブジェクトを作成します。したがって、
for (i = 0; i < form.elements.length; i++) {
if (form.elements[i].type == 'file') {
if (form.elements[i].value == '') {
form.elements[i].parentNode.removeChild(form.elements[i]);
}
}
}
私はサイト全体でFormDataを使用していますが、これが最新バージョンのSafariの問題であることを確認できます。空のファイルを削除すると、問題が修正されます。私のために働いたコードは次のとおりです:
var form = $('#formID');
var data = new FormData(form[0])
//hack to fix safari bug where upload fails if file input is empty
if (document.getElementById("fileID").files.length == 0 ) { //if the file is empty
data.delete('fileID'); //remove it from the upload data
}
私はこのソリューションを使用し、私のために働いています。
var $form = $('#website_settings_form');
var $inputs = $('input[type="file"]:not([disabled])', $form); //select input files
$inputs.each(function(_, input) {
if (input.files.length > 0) return
$(input).prop('disabled', true) //if the input doesn't have uploaded files will be disable
})
var formData = new FormData($form[0]);// create the form data
$inputs.prop('disabled', false);//enable fields again.
私はサファリのために働いたアンドレイの提案を使用しましたが、IEを壊しました。
両方のブラウザーで機能する唯一の解決策は、eval()を使用することでした。
これはサファリ11にのみ影響するバグのように見えるため、ブラウザバージョンのチェックも追加しました。
if(dataObj instanceof FormData && navigator.userAgent.match(/version\/11((\.[0-9]*)*)? .*safari/i)) {
try {
eval('for (var pair of dataObj.entries()) {\
if (pair[1] instanceof File && pair[1].name === \'\' && pair[1].size === 0) {\
dataObj.delete(pair[0]);\
}\
}');
} catch(e) {}
}