web-dev-qa-db-fra.com

Comment télécharger un fichier à l'aide de la bibliothèque Java HttpClient avec PHP

Je veux écrire une application Java qui permettra de télécharger un fichier sur le serveur Apache avec PHP. Le code Java utilise la version 4.0 beta2 de la bibliothèque Jakarta HttpClient:

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("executing request " + 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();
  }
}

Le fichier PHP upload.php est très simple:

<?php
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
  echo "File ". $_FILES['userfile']['name'] ." uploaded successfully.\n";
  move_uploaded_file ($_FILES['userfile'] ['tmp_name'], $_FILES['userfile'] ['name']);
} else {
  echo "Possible file upload attack: ";
  echo "filename '". $_FILES['userfile']['tmp_name'] . "'.";
  print_r($_FILES);
}
?>

En lisant la réponse, j'obtiens le résultat suivant:

executing request POST http://localhost:9002/upload.php HTTP/1.1
 HTTP/1.1 200 OK 
 Attaque possible par téléchargement de fichier: nom_fichier '' .
 Array 
 (
) 

La requête a donc abouti. J'ai pu communiquer avec le serveur, mais PHP n'a pas remarqué le fichier - la méthode is_uploaded_file a renvoyé la variable false et la variable $_FILES est vide. Je ne sais pas pourquoi cela pourrait arriver. J'ai suivi la réponse et la requête HTTP et elles ont l'air OK:
demande est:

 POST /upload.php HTTP/1.1 
 Content-Length: 13091 
 Content-Type: flux binaire/octet 
 Hôte: localhost: 9002 
 Connexion: Keep-Alive 
 User-Agent: Apache-HttpClient/4.0-beta2 (Java 1.5) 
 Attendez-vous: 100-Continue 

 - ..... le reste du fichier binaire ...

et réponse:

 HTTP/1.1 100 Continuer 

 HTTP/1.1 200 OK.__Date: mercredi, 01 juil. 2009 06:51:57 GMT 
 Serveur: 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 
 Contenu-Length: 51 
 Keep-Alive : timeout = 5, max = 100 
 Connexion: Keep-Alive 
 Content-Type: text/html 

 Attaque de téléchargement de fichier possible: nom_fichier '' .Array 
 (
). 

Je testais cela à la fois sur le Windows XP local avec xampp et le serveur Linux distant. J'ai également essayé d'utiliser la version précédente de HttpClient - version 3.1 - et le résultat était encore plus flou, is_uploaded_file a retourné false, cependant le tableau $_FILES a été rempli avec les données appropriées.

51
Piotr Kochański

Ok, le code Java que j'ai utilisé était incorrect, voici la bonne classe 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("executing request " + 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();
  }
}

note en utilisant MultipartEntity.

66
Piotr Kochański

Une mise à jour pour ceux qui essaient d'utiliser MultipartEntity...

org.Apache.http.entity.mime.MultipartEntity est obsolète en 4.3.1.

Vous pouvez utiliser MultipartEntityBuilder pour créer l'objet HttpEntity.

File file = new File();

HttpEntity httpEntity = MultipartEntityBuilder.create()
    .addBinaryBody("file", file, ContentType.create("image/jpeg"), file.getName())
    .build();

Pour les utilisateurs de Maven, la classe est disponible dans la dépendance suivante (presque identique à la réponse de fervisa, mais avec une version ultérieure).

<dependency>
  <groupId>org.Apache.httpcomponents</groupId>
  <artifactId>httpmime</artifactId>
  <version>4.3.1</version>
</dependency>
29
Brent Robinson

J'ai rencontré le même problème et découvert que le nom de fichier est requis pour que httpclient 4.x fonctionne avec le backend PHP. Ce n'était pas le cas pour httpclient 3.x.

Ma solution est donc d'ajouter un paramètre de nom dans le constructeur FileBody . ContentBody cbFile = new FileBody (fichier, "image/jpeg", "FILE_NAME");

J'espère que ça aide.

3
gaojun1000

La méthode correcte consiste à utiliser la méthode multipart POST. Voir ici pour un exemple de code pour le client.

Pour PHP, de nombreux tutoriels sont disponibles. C'est le premier j'ai trouvé. Je vous recommande de tester d'abord le code PHP à l'aide d'un client HTML, puis d'essayer le client Java.

3
kgiannakakis

Un exemple de version plus récente est ici.

Vous trouverez ci-dessous une copie du code original: 

/*
 * ====================================================================
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.Apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.Apache.org/>.
 *
 */
package org.Apache.http.examples.entity.mime;

import Java.io.File;

import org.Apache.http.HttpEntity;
import org.Apache.http.client.methods.CloseableHttpResponse;
import org.Apache.http.client.methods.HttpPost;
import org.Apache.http.entity.ContentType;
import org.Apache.http.entity.mime.MultipartEntityBuilder;
import org.Apache.http.entity.mime.content.FileBody;
import org.Apache.http.entity.mime.content.StringBody;
import org.Apache.http.impl.client.CloseableHttpClient;
import org.Apache.http.impl.client.HttpClients;
import org.Apache.http.util.EntityUtils;

/**
 * Example how to use multipart/form encoded POST request.
 */
public class ClientMultipartFormPost {

    public static void main(String[] args) throws Exception {
        if (args.length != 1)  {
            System.out.println("File path not given");
            System.exit(1);
        }
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpPost httppost = new HttpPost("http://localhost:8080" +
                    "/servlets-examples/servlet/RequestInfoExample");

            FileBody bin = new FileBody(new File(args[0]));
            StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);

            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addPart("bin", bin)
                    .addPart("comment", comment)
                    .build();


            httppost.setEntity(reqEntity);

            System.out.println("executing request " + httppost.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    System.out.println("Response content length: " + resEntity.getContentLength());
                }
                EntityUtils.consume(resEntity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}
2
rado

Je savais que je suis en retard pour la fête, mais ci-dessous, voici la manière correcte de gérer cela. La clé est d'utiliser InputStreamBody à la place de FileBody pour télécharger un fichier en plusieurs parties. 

   try {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost postRequest = new HttpPost("https://someserver.com/api/path/");
        postRequest.addHeader("Authorization",authHeader);
        //don't set the content type here            
        //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());
   }
1
Dev

Aah il vous suffit d'ajouter un paramètre de nom dans le 

FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");

J'espère que ça aide.

1
user4286889

Pour ceux qui ont du mal à mettre en œuvre la réponse acceptée (ce qui nécessite org.Apache.http.entity.mime.MultipartEntity), vous pouvez utiliser org.Apache.httpcomponents 4.2. * Dans ce cas, vous devez explicitement installer httpmime dépendance, dans mon cas:

<dependency>
    <groupId>org.Apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.2.5</version>
</dependency>
0
fervisa

Il y a ma solution de travail pour envoyer une image avec post, en utilisant les bibliothèques HTTP Apache (très important ici, c'est border addition Cela ne fonctionnera pas sans elle dans mon cas):

            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
0
Krystian

Si vous testez ceci sur votre WAMP local, vous devrez peut-être configurer le dossier temporaire pour le téléchargement de fichiers. Vous pouvez le faire dans votre fichier PHP.ini:

upload_tmp_dir = "c:\mypath\mytempfolder\"

Vous devrez accorder des autorisations sur le dossier pour autoriser le téléchargement. Les autorisations à accorder varient en fonction de votre système d'exploitation.

0
Fenton