Я хочу написать приложение Java, которое будет загружать файл на сервер Apache с помощью PHP. В коде Java используется библиотека Jakarta HttpClient версии 4.0 beta2:
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
public class PostFile {
public static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://localhost:9002/upload.php");
File file = new File("c:/TRASH/zaba_1.jpg");
FileEntity reqEntity = new FileEntity(file, "binary/octet-stream");
httppost.setEntity(reqEntity);
reqEntity.setContentType("binary/octet-stream");
System.out.println("выполнение запроса " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
}
Файл PHP upload.php очень прост:
<?php
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
echo "File ". $_FILES['userfile']['name'] ." успешно загружен.\n";
move_uploaded_file ($_FILES['userfile'] ['tmp_name'], $_FILES['userfile'] ['name']);
} else {
echo "Возможная атака на загрузку файлов: ";
echo "filename '". $_FILES['userfile']['tmp_name'] . "'.";
print_r($_FILES);
}
?>
Читая ответ, получаю следующий результат:
executing request POST http://localhost:9002/upload.php HTTP/1.1
HTTP / 1.1 200 ОК
Возможная атака загрузки файла: имя файла ''.
Множество
(
)
Итак, запрос прошел успешно, я смог связаться с сервером, однако PHP не заметил файл – метод is_uploaded_file вернул false и переменная $_FILES пуста. Я понятия не имею, почему это могло произойти. Я отследил HTTP-ответ и запрос, и они выглядят нормально.
Запрос:
POST /upload.php HTTP/1.1
Content-Length: 13091
Content-Type: binary/octet-stream
Host: localhost:9002
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5)
Expect: 100-Continue
..... the rest of the binary file...
И ответ:
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Wed, 01 Jul 2009 06:51:57 GMT
Server: Apache/2.2.8 (Win32) DAV/2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5 mod_jk/1.2.26
X-Powered-By: PHP/5.2.5
Content-Length: 51
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Возможная атака загрузки файла: имя файла ''.
Множество
(
)
Я тестировал это как на локальном windows с xampp, так и на удаленном Linux сервере. Я также пытался использовать предыдущую версию HttpClient – версию 3.1 – и результат был еще более непонятным, is_uploaded_file возвращал false, однако массив $_FILES был заполнен правильными данными.
Ответ 1
Код Java, который использовался, был неправильным, вот правильный класс Java:
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
public class PostFile {
public static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://localhost:9001/upload.php");
File file = new File("c:/TRASH/zaba_1.jpg");
MultipartEntity mpEntity = new MultipartEntity();
ContentBody cbFile = new FileBody(file, "image/jpeg");
mpEntity.addPart("userfile", cbFile);
httppost.setEntity(mpEntity);
System.out.println("выполнение запроса " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
}
Ответ 2
Обновление для тех, кто пытается использовать MultipartEntity...
org.apache.http.entity.mime.MultipartEntity устарел в версии 4.3.1.
Вы можете использовать MultipartEntityBuilder для создания объекта HttpEntity.
File file = new File();
HttpEntity httpEntity = MultipartEntityBuilder.create()
.addBinaryBody("file", file, ContentType.create("image/jpeg"), file.getName())
.build();
Для пользователей Maven класс доступен в следующей зависимости:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.1</version>
</dependency>
Ответ 3
Вот мое рабочее решение для отправки изображения на почту, с использованием http библиотеки apache (очень важно здесь добавить boundary. Без него в моем соединении ничего не получится):
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] imageBytes = baos.toByteArray();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(StaticData.AMBAJE_SERVER_URL + StaticData.AMBAJE_ADD_AMBAJ_TO_GROUP);
String boundary = "-------------" + System.currentTimeMillis();
httpPost.setHeader("Content-type", "multipart/form-data; boundary="+boundary);
ByteArrayBody bab = new ByteArrayBody(imageBytes, "pic.png");
StringBody sbOwner = new StringBody(StaticData.loggedUserId, ContentType.TEXT_PLAIN);
StringBody sbGroup = new StringBody("group", ContentType.TEXT_PLAIN);
HttpEntity entity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setBoundary(boundary)
.addPart("group", sbGroup)
.addPart("owner", sbOwner)
.addPart("image", bab)
.build();
httpPost.setEntity(entity);
try {
HttpResponse response = httpclient.execute(httpPost);
...then reading response
Ответ 4
Ниже приведен правильный способ решения этой проблемы, смысл в том, чтобы использовать InputStreamBody вместо FileBody для загрузки многокомпонентного файла.
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("https://someserver.com/api/path/");
postRequest.addHeader("Authorization",authHeader);
//не устанавливайте здесь тип содержимого
//postRequest.addHeader("Content-Type","multipart/form-data");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(file);
reqEntity.addPart("parm-name", new InputStreamBody(fileInputStream,"image/jpeg","file_name.jpg"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpclient.execute(postRequest);
}catch(Exception e) {
Log.e("URISyntaxException", e.toString());
}
Ответ 5
Если вы тестируете это на своем локальном WAMP, вам может понадобиться настроить временную папку для загрузки файлов. Вы можете сделать это в файле PHP.ini:
upload_tmp_dir = "c:\mypath\mytempfolder\"
Вам нужно будет предоставить права на папку, чтобы загрузка могла произойти – разрешения, которые нужно предоставить, зависят от вашей операционной системы.
Web