凌峰创科服务平台

Android如何用PHP实现图片上传到服务器?

  1. 准备工作
  2. 服务器端 (PHP)
    • 创建接收文件的服务器脚本
    • 配置服务器 (.htaccess)
  3. Android 客户端
    • 添加网络权限
    • 选择图片 (从相册或相机)
    • 将图片转换为 Base64 字符串 (最简单的方式)
    • 使用 OkHttp 发送 POST 请求
    • 处理服务器响应
  4. 完整代码示例
  5. 重要注意事项与优化

准备工作

在开始之前,你需要:

Android如何用PHP实现图片上传到服务器?-图1
(图片来源网络,侵删)
  • 一台 Web 服务器:你可以购买云服务器,或者使用本地环境工具(如 XAMPP, WAMP, MAMP)来模拟服务器。
  • PHP 环境:确保你的服务器上安装了 PHP 5.4+ 或更高版本。
  • Android Studio:用于开发 Android 应用。
  • 网络库:我们推荐使用 OkHttp,它是目前 Android 上最流行的网络请求库。

服务器端 (PHP)

服务器端需要一个脚本来接收客户端上传的文件,我们将使用 Base64 编码的字符串,PHP 需要解码并保存它。

a. 创建 upload.php 文件

在你的网站根目录(htdocswww)下,创建一个名为 uploads 的文件夹,并赋予它可写权限(755777,生产环境请使用更安全的权限)。

创建 upload.php 文件,内容如下:

<?php
// 设置响应头为 JSON,方便客户端解析
header('Content-Type: application/json');
// 定义上传目录,确保这个目录存在并且有写入权限
$uploadDir = 'uploads/';
// 检查上传目录是否存在,如果不存在则创建
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}
// 检查是否有文件通过 POST 请求上传
if (isset($_POST['image'])) {
    // 获取 Base64 编码的图片数据
    $base64Image = $_POST['image'];
    // 移除 Base64 URL 前缀 (data:image/png;base64,)
    $ifp = fopen($uploadDir . time() . '.png', 'wb'); // 使用时间戳作为文件名,避免重名
    $data = explode(',', $base64Image);
    fwrite($ifp, base64_decode($data[1]));
    fclose($ifp);
    // 返回成功响应
    $response = [
        'success' => true,
        'message' => '图片上传成功!',
        'file_path' => $uploadDir . time() . '.png'
    ];
    echo json_encode($response);
} else {
    // 如果没有接收到图片数据,返回错误
    $response = [
        'success' => false,
        'message' => '没有接收到图片数据。'
    ];
    echo json_encode($response);
}
?>

代码解释:

Android如何用PHP实现图片上传到服务器?-图2
(图片来源网络,侵删)
  1. header('Content-Type: application/json');:告诉客户端我们将返回 JSON 格式的数据。
  2. $uploadDir = 'uploads/';:定义文件保存的目录。
  3. isset($_POST['image']):检查 POST 请求中是否存在我们自定义的 image 字段。
  4. explode(',', $base64Image)Base64 数据通常以 data:image/...;base64, 开头,我们需要用逗号分割它,取第二部分(纯编码数据)。
  5. base64_decode($data[1]):将纯编码数据解码为二进制文件流。
  6. fopen, fwrite, fclose:将解码后的二进制数据写入到服务器文件中。
  7. json_encode($response):将 PHP 数组转换为 JSON 字符串并返回给客户端。

b. 配置 .htaccess (可选但推荐)

为了安全,你可以创建一个 .htaccess 文件在你的项目根目录,限制对 upload.php 的直接访问,或者限制上传文件的大小。

# 限制上传文件大小为 10M
php_value upload_max_filesize 10M
php_value post_max_size 10M
# (可选) 禁止列出目录内容
Options -Indexes

Android 客户端

我们将使用 Kotlin 语言来演示,因为它现在是 Android 开发的首选,如果你使用 Java,逻辑基本相同。

a. 添加依赖和权限

app/build.gradle 文件中添加 OkHttp 依赖:

dependencies {
    // ... 其他依赖
    implementation("com.squareup.okhttp3:okhttp:4.12.0") // 使用最新版本
}

app/src/main/AndroidManifest.xml 中添加网络权限:

Android如何用PHP实现图片上传到服务器?-图3
(图片来源网络,侵删)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 添加网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 如果需要从相机拍照,还需要相机权限 -->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 如果需要从相册选择,需要读取存储权限 (Android 13+ 是 READ_MEDIA_IMAGES) -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- Android 13+ 的媒体图片权限 -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <!-- Android (API 33-) 的存储权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />
    <application ...>
        ...
    </application>
</manifest>

重要提示:对于 Android 13 (API 33) 及以上版本,READ_EXTERNAL_STORAGE 已被废弃,需要分别请求 READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO,上面的清单文件已包含兼容写法。

b. 选择图片 (从相册)

这里我们使用一个简单的方法,通过 Intent 打开相册。

// 在你的 Activity 或 Fragment 中
private val pickImageRequestCode = 1001
fun openGallery() {
    val intent = Intent(Intent.ACTION_PICK).apply {
        type = "image/*"
    }
    startActivityForResult(intent, pickImageRequestCode)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == pickImageRequestCode && resultCode == Activity.RESULT_OK) {
        val selectedImageUri: Uri? = data?.data
        selectedImageUri?.let {
            // 将 URI 转换为 Base64 字符串
            val base64String = uriToBase64(it)
            // 上传图片
            uploadImageToServer(base64String)
        }
    }
}
// 将 Uri 转换为 Base64 字符串
private fun uriToBaseUri(uri: Uri): String? {
    return try {
        contentResolver.openInputStream(uri)?.use { inputStream ->
            inputStream.readBytes().toBase64()
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}
// 扩展函数,将 ByteArray 转换为 Base64
private fun ByteArray.toBase64(): String {
    return android.util.Base64.encodeToString(this, android.util.Base64.NO_WRAP)
}

c. 上传图片到服务器 (使用 OkHttp)

我们来实现上传的核心逻辑。

// 使用 OkHttp 进行网络请求
private fun uploadImageToServer(base64Image: String) {
    // 1. 创建 OkHttp 客户端
    val client = OkHttpClient()
    // 2. 构建 RequestBody
    // 我们发送的是表单数据,所以使用 FormBody.Builder
    val requestBody = FormBody.Builder()
        .add("image", base64Image) // key 必须和 PHP 端 $_POST['image'] 中的 'image' 一致
        .build()
    // 3. 构建 Request
    // !!! 将 YOUR_SERVER_URL 替换为你的实际服务器地址,http://yourdomain.com/upload.php
    val request = Request.Builder()
        .url("YOUR_SERVER_URL/upload.php") // <--- 修改这里!
        .post(requestBody)
        .build()
    // 4. 异步执行请求
    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            // 请求失败,在主线程更新 UI
            runOnUiThread {
                Toast.makeText(this@YourActivity, "上传失败: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
        override fun onResponse(call: Call, response: Response) {
            // 请求成功
            response.use { resp ->
分享:
扫描分享到社交APP
上一篇
下一篇