Я делаю приложение, в котором пользователь может выбрать несколько изображений и загрузить их на сервер.
Я использую PHP в качестве бэкэнда и retrofit2
Я перепробовал все ответы на stackoverflow, но все еще не решил его.
@Multipart
@POST("URL/uploadImages.php")
Call<Response> uploaImages(
@Part List< MultipartBody.Part> files );
код для отправки файлов
Retrofit builder = new Retrofit.Builder().baseUrl(ROOT_URL).addConverterFactory(GsonConverterFactory.create()).build();
FileUploadService fileUploadService = builder.create(FileUploadService.class);
Call<Response> call = fileUploadService.uploadImages(list)
for (Uri fileUri : path) {
MultipartBody.Part fileBody = prepareFilePart("files", fileUri);
images.add(fileBody);
}Call<Response> call=fileUploadService.uploadImages(images);
call.enqueue(new Callback<Response>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
Log.e("MainActivity",response.body().toString());
progressDialog.show();
}
@Override
public void onFailure(Call<Response> call, Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
Log.e("MainActivity",t.getLocalizedMessage());
progressDialog.dismiss();
}
});
}
вот мой php код
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST"){
// Loop $_FILES to exeicute all files
foreach ($_FILES['files']['name'] as $f => $name) {
if ($_FILES['files']['error'][$f] == 4) {
continue; // Skip file if any error found
}
if ($_FILES['files']['error'][$f] == 0) {
if ($_FILES['files']['size'][$f] > $max_file_size) {
$message[] = "$name is too large!.";
continue; // Skip large files
}
elseif( ! in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats) ){
$message[] = "$name is not a valid format";
continue; // Skip invalid file formats
}
else{ // No error found! Move uploaded files
if(move_uploaded_file($_FILES["files"]["tmp_name"][$f], $path.$name))
$count++; // Number of successfully uploaded file
}
}
}
}
Решение:
Я понял проблему .. Я должен изменить имя MultipartBodt.Part
от
"file"
в "file[]"
и принять их в $_FILES['file']
… так же, как вы делаете с традиционной формой … потому что я отправляю содержимое в виде данных формы
так что измени мой preparFfile()
метод.
после поиска и расспросов, вот полное, проверенное и автономное решение.
1. Создать сервисный интерфейс.
public interface FileUploadService {
@Multipart
@POST("YOUR_URL/image_uploader.php")
Call<Response> uploadImages( @Part List<MultipartBody.Part> images);
}
и ответ.java
public class Response{
private String error;
private String message;
//getters and setters
}
2 — метод uploadImages
Я передаю список URI из onActivityResult()
метод, то я получаю фактический путь к файлу с помощью FileUtiles «ссылка на класс закомментирована»
//code to upload
//the path is returned from the gallery
void uploadImages(List<Uri> paths) {
List<MultipartBody.Part> list = new ArrayList<>();
int i = 0;
for (Uri uri : paths) {
String fileName = FileUtils.getFile(this, uri).getName();
//very important files[]
MultipartBody.Part imageRequest = prepareFilePart("file[]", uri);
list.add(imageRequest);
}Retrofit builder = new Retrofit.Builder().baseUrl(ROOT_URL).addConverterFactory(GsonConverterFactory.create()).build();
FileUploadService fileUploadService = builder.create(FileUploadService.class);
Call<Response> call = fileUploadService.uploadImages(list);
call.enqueue(new Callback<Response>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
Log.e("main", "the message is ----> " + response.body().getMessage());
Log.e("main", "the error is ----> " + response.body().getError());
}
@Override
public void onFailure(Call<Response> call, Throwable throwable) {
Log.e("main", "on error is called and the error is ----> " + throwable.getMessage());
}
});}
и вспомогательный метод, использованный выше
@NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(this, fileUri);
//compress the image using Compressor lib
Timber.d("size of image before compression --> " + file.getTotalSpace());
compressedImageFile = new Compressor(this).compressToFile(file);
Timber.d("size of image after compression --> " + compressedImageFile.getTotalSpace());
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(getContentResolver().getType(fileUri)),
compressedImageFile);
// MultipartBody.Part is used to send also the actual file name
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}
3-мой php код image_uploader.php:
<?php
$file_path = "upload/";
$full_path="http://bishoy.esy.es/retrofit/".$file_path;
$img = $_FILES['file'];
$response['message'] = "names : ";
if(!empty($img)){
for($i=0;$i<count($_FILES['file']['tmp_name']);$i++){
$response['error'] = false;
$response['message'] = "number of files recieved is = ".count($_FILES['file']['name']);
if(move_uploaded_file($_FILES['file']['tmp_name'][$i],"upload/".$_FILES['file']['name'][$i])){
$response['error'] = false;
$response['message'] = $response['message']. "moved sucessfully :: ";
}else{
$response['error'] = true;
$response['message'] = $response['message'] ."cant move :::" .$file_path ;
}
}
}
else{
$response['error'] = true;
$response['message'] = "no files recieved !";
}
echo json_encode($response);
?>
Других решений пока нет …