Понадобилось сделать достаточно очевидную, казалось бы, вещь - страничку, на которой можно заполнить несколько полей формы, выбрать несколько файлов и при нажатии на кнопку чтобы всё это вместе отправлялось на сервер без перезагрузки страницы (через ajax).
Оказалось, что есть ряд ньюансов. По отдельности нет проблем, а чтобы всё вместе - начинаются сложности. В итоге всё заработало, так что предлагаю простой пример. После успешной загрузки сервер возвращает содержимое массивов _POST и _FILES, которое выводится на ту же страницу.
Проверял в Windows версиях FF, Chrome, IE, Opera, а также в Android Chrome и старом Android Browser. Под IOS не проверял - нет под рукой.
Не работает в Safari 5.34/Win. Причина непонятна (симптомы - отправляет файлы нулевой длины).
Не будет работать в IE <9.
Код клиента (javascript):
<!DOCTYPE html>
<html>
<head>
<title>Ajax file and form data upload test by Frog</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#cform').bind('submit', function(event)
{
event.preventDefault();
console.log('SUBMIT!');
var formData = new FormData();
$.each($("#cform_file")[0].files, function(i, file)
{
formData.append('file-'+i, file);
});
formData.append('name',$("#cform_name").val());
formData.append('email',$("#cform_email").val());
$.ajax({
url: 'aftest.php',
type: 'POST',
contentType: false,
processData: false,
cache: false,
headers: { 'cache-control': 'no-cache' }, // fix for IOS6 (not tested)
dataType: 'json',
data: formData,
timeout: 7000,
beforeSend: function(x)
{
console.log('beforeSend');
},//beforeSend
success: function( data )
{
console.log('success',data);
if (data != null)
{
$('#result').prepend(data._FILES);
$('#result').prepend(data._POST);
}//if
else
{
console.log('success, but no data');
}//else
},//success
error: function( data )
{
console.log('error');
},//error
complete: function( data )
{
console.log('complete');
}//complete
});//ajax()
})//submit()
});//.ready
</script>
</head>
<body>
<form id="cform" action="index.php" method="POST" enctype = "multipart/form-data">
Name: <input id="cform_name" name="cform_name" type="text" size="30" maxlength="30" /><br/>
E-Mail: <input id="cform_email" name="cform_email" type="text" size="30" maxlength="30" /><br/>
<input type="hidden" value="2000000" name="MAX_FILE_SIZE">
<input id="cform_file" type="file" size="20" name="cform_file[]" multiple=""><br/>
<!--
for single file upload replace with:
<input id="cform_file" type="file" size="20" name="cform_file">
-->
<br/>
<input id="cform_submit" name="cform_submit" type="submit" value="SEND" ><br/>
</form>
<hr>
<div id="result"></div>
</body>
</html>
Код сервера (php):
foreach($_FILES as $file)
{
move_uploaded_file($file["tmp_name"], $file["name"]);
}//foreach
echo json_encode( Array("_POST"=>'_POST ' . nl2br(print_r($_POST,true)), "_FILES"=>'_FILES ' . nl2br(print_r($_FILES,true))) );