Android: upload file with filling out POST body together

14,326

Just add a a few FormBodyPart to your MultipartEntity.

You can use the StringBody object to provide the value.

Here is an example of how you can use it:

byte[] data = {10,10,10,10,10}; 
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("server url");
ByteArrayBody bab = new ByteArrayBody(data, "image.jpg");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("image", bab);

FormBodyPart bodyPart=new FormBodyPart("formVariableName", new StringBody("formValiableValue"));
reqEntity.addPart(bodyPart);
bodyPart=new FormBodyPart("formVariableName2", new StringBody("formValiableValue2"));
reqEntity.addPart(bodyPart);
bodyPart=new FormBodyPart("formVariableName3", new StringBody("formValiableValue3"));
reqEntity.addPart(bodyPart); 
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = null;
while((line = in.readLine()) != null) {
    System.out.println(line);
}

Here is the output of the PHP script:

$_FILES
Array
(
    [image] => Array
        (
            [name] => image.jpg
            [type] => application/octet-stream
            [tmp_name] => /tmp/php6UHywL
            [error] => 0
            [size] => 5
        )

)
$_POST:
Array
(
    [formVariableName] => formValiableValue
    [formVariableName2] => formValiableValue2
    [formVariableName3] => formValiableValue3
)

This doesn't compress all the post vars inside of one content body part but it dose the job.

You can't access the data from php://stdin or $HTTP_RAW_POST_DATA, both are unavailable for multipart/form-data encoding. From the PHP docs:

php://input is a read-only stream that allows you to read raw data from the request body. In the case of POST requests, it is preferable to use php://input instead of $HTTP_RAW_POST_DATA as it does not depend on special php.ini directives. Moreover, for those cases where $HTTP_RAW_POST_DATA is not populated by default, it is a potentially less memory intensive alternative to activating always_populate_raw_post_data. php://input is not available with enctype="multipart/form-data".

Even if you set always_populate_raw_post_data to On it still won't fix the problem:

Always populate the $HTTP_RAW_POST_DATA containing the raw POST data. Otherwise, the variable is populated only with unrecognized MIME type of the data. However, the preferred method for accessing the raw POST data is php://input. $HTTP_RAW_POST_DATA is not available with enctype="multipart/form-data".

My best guess is just add all the data as a ByteArrayBody or StringBody and just use that as if you were reading from php://stdin

Here is an example of ByteArrayBody:

String testString="b=a&c=a&d=a&Send=Send";
reqEntity.addPart(new FormBodyPart("formVariables", new ByteArrayBody(testString.getBytes(), "application/x-www-form-urlencoded", "formVariables")));

And in PHP:

var_dump(file_get_contents($_FILES['formVariables']['tmp_name']));

You should get:

string(21) "b=a&c=a&d=a&Send=Send"

Edit: After some second thoughts I think it's better to just use one StringBody and put all the data in one post variable, then parse it from that, it skips writing the data to a file and deleting it after the request since the temp file is totally useless this will increase performance. Here is an example:

String testString="b=a&c=a&d=a&Send=Send";
bodyPart=new FormBodyPart("rawData", new StringBody(testString));
reqEntity.addPart(bodyPart);

Then from PHP:

var_dump($_POST['rawData']);
Share:
14,326
Marek Sebera
Author by

Marek Sebera

Updated on June 17, 2022

Comments

  • Marek Sebera
    Marek Sebera almost 2 years

    I do use MultipartEntity to send File to server, it appears correctly in $_FILES superglobal

    But I need also fill in POST body to be read via php://stdin

    How can I do that?

    current snippet below:

    ByteArrayOutputStream bos = new ByteArrayOutputStream(); // stream to hold image
    bm.compress(CompressFormat.JPEG, 75, bos); //compress image
    byte[] data = bos.toByteArray(); 
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost postRequest = new HttpPost("REMOTE ADDRESS");
    ByteArrayBody bab = new ByteArrayBody(data, "image.jpg");
    MultipartEntity reqEntity = new MultipartEntity(
    HttpMultipartMode.BROWSER_COMPATIBLE); // is this one causing trouble?
    reqEntity.addPart("image", bab); // added image to request
    // tried this with no luck
    // reqEntity.addPart("", new StringBody("RAW DATA HERE")); 
    postRequest.setEntity(reqEntity); // set the multipart entity to http post request
    HttpResponse response = httpClient.execute(postRequest);
    

    MultipartEntity is part of HttpMime 4.1.2 API, documentation

    Similar to this: Android: Uploading a file to a page along with other POST strings

  • Marek Sebera
    Marek Sebera over 12 years
    can you please expand your question an add a sample code and so on? thanks
  • Alexandru Mincu
    Alexandru Mincu over 12 years
    I expanded and corrected the answer, this works in normal java, no reason why it shouldn't work on android.
  • Marek Sebera
    Marek Sebera over 12 years
    Hey, thanks. Now, can you please think about it for a second, and edit your answer to match the question? I don't need to send Form data (which is similar to posting FORM from within HTML), but I need to post raw data, similar to $.ajax("raw data"), data sent this way aren't readable from within $_POST superglobal, I'd need to send something like StringEntity does in use with HttpDefaultClient
  • Alexandru Mincu
    Alexandru Mincu over 12 years
    oh, sorry didn't get it from the php://stdin line :), let me think about it and I'll get back to you
  • Alexandru Mincu
    Alexandru Mincu over 12 years
    I did some more research, you can't use php://stdin or php://input(the are the same in this case) or even $HTTP_POST_VARS, they are disabled for multipart/form-data requests. I edited my post to reflect that an suggest a workaround.
  • Marek Sebera
    Marek Sebera over 12 years
    You're quite smart, I completely missed this in documentation of php wrappers, i'll test it in few hours and give you proper award :)
  • Alexandru Mincu
    Alexandru Mincu over 12 years
    glad I could help :), and after some second thoughts I think it's better to just use one StringBody and put all the data in one post variable, then parse it from that, it skips writing the data to a file and deleting it after the request since the temp file is totally useless this will increase performance. I'll edit the answer to reflect this.
  • monn3t
    monn3t over 11 years
    @Alexandru Mincu If you change your answer I would advise to leave the original and add what would be the difference. After an extensive search in this site, this answer as of now, is the one that solve my coding situation. This question and its answer is on my favorites :)