Web

Как загрузить файл с помощью библиотеки Java HttpClient, работающей с PHP

Я хочу написать приложение 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

Тернарный оператор PHP против оператора объединения с нулевым значением

Web

Как разрешить неоднозначные имена столбцов при получении результатов?

Web

Удаление из массива PHP по значению (не по ключу)

Web

В чем разница между require, include, require_once и include_once?

×