我想编写Java应用程序,用PHP将文件上传到Apache服务器。 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("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();
}
}
PHP文件upload.php
非常简单:
<?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);
}
?>
阅读回复我得到以下结果:
executing request POST http://localhost:9002/upload.php HTTP/1.1
HTTP/1.1 200 OK Possible file upload attack: filename ''. Array ( )
因此请求成功,我能够与服务器通信,但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 Possible file upload attack: filename ''.Array ( )
我在使用xampp的本地windows xp和远程Linux服务器上测试了这个。我还尝试使用以前版本的HttpClient - 版本3.1 - 结果更加不清楚,is_uploaded_file
返回false
,但是$_FILES
数组填充了正确的数据。
答案 0 :(得分:66)
好的,我使用的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("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();
}
}
请注意使用MultipartEntity。
答案 1 :(得分:29)
尝试使用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用户,该类可以使用以下依赖项(几乎与fervisa的答案相同,只是使用更高版本)。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.1</version>
</dependency>
答案 2 :(得分:3)
正确的方法是使用多部分POST方法。有关客户端的示例代码,请参阅here。
对于PHP,有许多教程可用。这是我发现的first。我建议您首先使用html客户端测试PHP代码,然后尝试使用Java客户端。
答案 3 :(得分:3)
我遇到了同样的问题,发现httpclient 4.x需要文件名才能使用PHP后端。 httpclient 3.x并非如此。
所以我的解决方案是在FileBody构造函数中添加一个name参数。 ContentBody cbFile = new FileBody(文件,“image / jpeg”,“FILE_NAME”);
希望它有所帮助。
答案 4 :(得分:2)
A newer version example is here.
以下是原始代码的副本:
/*
* ====================================================================
* 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();
}
}
}
答案 5 :(得分:1)
啊,你只需要在
中添加一个名字参数FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");
希望它有所帮助。
答案 6 :(得分:1)
我知道我迟到了,但下面是处理此问题的正确方法,关键是使用InputStreamBody
代替FileBody
上传多部分文件。
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());
}
答案 7 :(得分:0)
如果您在本地WAMP上进行测试,则可能需要设置文件上传的临时文件夹。您可以在PHP.ini文件中执行此操作:
upload_tmp_dir = "c:\mypath\mytempfolder\"
您需要授予该文件夹的权限以允许上传 - 您需要授予的权限因操作系统而异。
答案 8 :(得分:0)
对于那些很难实现接受的答案(需要org.apache.http.entity.mime.MultipartEntity)的人,您可能正在使用org.apache.httpcomponents 4.2。* 在这种情况下,您必须明确安装 httpmime 依赖项,在我的情况下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.2.5</version>
</dependency>
答案 9 :(得分:0)
我的工作解决方案是使用apache http库发送带有post的图像(这里非常重要的是边界添加它在我的连接中没有它就不会工作):
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