52 votes

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

Je veux écrire une application Java qui téléchargera un fichier sur le serveur Apache avec PHP. Le code Java utilise la bibliothèque Jakarta HttpClient version 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("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
Possible file upload attack: filename ''.
Array
(
)

La requête a donc réussi, j'ai pu communiquer avec le serveur, mais PHP n'a pas remarqué le fichier - la méthode is_uploaded_file a retourné false et $_FILES est vide. Je ne sais pas pourquoi cela se produit. J'ai suivi la réponse et la demande HTTP et elles semblent correctes :
la demande est :

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...

et la réponse :

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

Possible file upload attack: filename ''.Array
(
)

Je l'ai testé à la fois sur le Windows xp local avec xampp et sur 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 moins clair, is_uploaded_file a retourné false Cependant $_FILES a été rempli avec les bonnes données.

0 votes

DefaultHttpClient() est maintenant déprécié.

0 votes

@PranjalCholadhara alors quelle classe doit être utilisée à la place de DefaultHttpClient() car elle est dépréciée ?

66voto

Piotr Kochański Points 8162

Ok, le code Java que j'ai utilisé était faux, 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 utilisant MultipartEntity.

1 votes

Quelle(s) nouvelle(s) version(s) de HttpComponents (c'est-à-dire hc.apache.org NOT HttpClient-3.1) est (sont) prise(s) en charge ? Je reçois le message d'erreur suivant "Le type org.apache.james.mime4j.message.SingleBody ne peut être résolu. Il est indirectement référencé dans les fichiers .class requis".

2 votes

Réponse : HttpClient 4.1-alpha1 et HttpCore 4.1-alpha1 à partir de hc.apache.org/downloads.cgi - le code Java des Apache HttpComponents pris en charge. Avec ceux-ci, le message d'erreur disparaît :)

0 votes

J'utilise la version 4.2 et je n'ai pas mime paquet. A-t-il été modifié ?

30voto

Brent Robinson Points 668

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

org.apache.http.entity.mime.MultipartEntity est déprécié dans la version 4.3.1.

Vous pouvez utiliser MultipartEntityBuilder pour créer le HttpEntity objet.

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 la même que la réponse de fervisa, juste avec une version plus récente).

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpmime</artifactId>
  <version>4.3.1</version>
</dependency>

0 votes

Vous devriez peut-être mettre à jour la réponse acceptée et l'améliorer.

3voto

kgiannakakis Points 62727

Le bon moyen est d'utiliser la méthode POST multipart. Voir ici pour un exemple de code pour le client.

Pour PHP, il existe de nombreux tutoriels. Voici le premièrement J'ai trouvé. Je vous recommande de tester le code PHP d'abord en utilisant un client html, puis d'essayer le client java.

0 votes

J'ai essayé d'utiliser la méthode que vous proposez, c'est-à-dire HttpClient v. 3.1 et is_uploaded_file est toujours retourné faux, cependant cette fois le tableau $_FILES était rempli avec des données correctes, ce qui m'a rendu encore plus perplexe. BTW. Le téléchargement fonctionne sur le serveur, j'ai testé mon fichier upload.php en utilisant un simple formulaire html.

3voto

gaojun1000 Points 31

J'ai rencontré le même problème et j'ai découvert que le nom du fichier est nécessaire 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 de FileBody. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME") ;

J'espère que cela vous aidera.

0 votes

Merci pour votre aide. Cela m'a sauvé. Mais le constructeur qui devrait être utilisé est celui qui prend 4 arguments. new FileBody(file,file.getName(), "application/octet-stream", "UTF-8") ; Le constructeur à 3 arguments prend mimetype comme troisième argument, pas le nom.

0voto

Steve Fenton Points 55265

Si vous testez ce système sur votre WAMP local, vous devrez peut-être configurer le dossier temporaire pour les téléchargements 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 permettre le téléchargement. Les autorisations à accorder varient en fonction de votre système d'exploitation.

0 votes

Le dossier tmp est défini. L'upload fonctionne sur le serveur, j'ai testé mon fichier upload.php en utilisant un simple formulaire html.

0 votes

Pouvez-vous me dire comment écrire un code serveur en java pour recevoir la demande du client http.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X