Upload ảnh lên server bằng PHP dễ dàng nhất

0
608

Bạn đang có ý tưởng về một ứng dụng chia sẻ ảnh với rất nhiều người. Để bắt đầu ý tưởng này có lẽ chúng ta cần bắt đầu từ việc tạo một ứng dụng upload ảnh lên server.

Có nhiều cách để upload hình ảnh hay bất kỳ một file nào từ Android lên Server. Nếu bạn mới học lập trình android thì nghĩ rằng làm ứng dụng kiểu này sẽ rất khó. Vì bạn sẽ phải lập trình cả phía server nữa?

Thực ra cũng không khó lắm đâu!

Hôm nay mình hướng dẫn các bạn tự xây dựng ứng dụng android có thể upload ảnh lên server, upload file trong PHP. Phía server sẽ được lập trình bằng ngôn ngữ PHP.

Tạo ứng dụng upload ảnh lên server PHP

Upload ảnh lên server gồm những công đoạn:

  1. Chọn ảnh từ thư viện hình ảnh của điện thoại.
  2. Tiến hành mã hóa hình ảnh dưới dạng Base64.
  3. Gửi hình ảnh đã mã hóa lên server theo phương thức POST.
  4. Server sẽ nhận hình ảnh đã mã hóa đó.
  5. Giải mã hình ảnh và lưu lại trên server.

Chúng ta bắt đầu thôi!

#Xây dựng ứng dụng android upload ảnh lên server

Nói tổng thể, chúng ta sẽ cần phải xây dựng hai ứng dụng: Ứng dụng phía client(chính là ứng dụng android), và ứng dụng trên server(viết bằng PHP).

Đầu tiên, chúng ta bắt tay vào code ứng dụng Android trước nhé.

Trong ứng dụng này, để tải hình ảnh lên server, mình sử dụng thư viện Retrofit. Các bạn thêm dependencies của Retrofit vào build.gradle

implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'

Ứng dụng của chúng ta sẽ có giao diện như sau:

Demo ứng dụng upload ảnh lên server PHP
Demo ứng dụng upload ảnh lên server PHP

Tạo layout ứng dụng để upload ảnh lên server

Để tạo được layout như demo, các bạn tạo file activity_main.xml như bên dưới:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:contentDescription="@null"
        android:scaleType="centerCrop" />

    <LinearLayout
        style="?android:attr/buttonBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:weightSum="2">

        <Button
            android:id="@+id/selectImageButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:layout_weight="1"
            android:text="@string/select_image"
            tools:ignore="ButtonStyle" />

        <Button
            android:id="@+id/uploadImageButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/select_image"
            tools:ignore="ButtonStyle" />

    </LinearLayout>

</RelativeLayout>

Tạo tính năng chọn ảnh

Trong MainActivity khi người dùng click chọn nút selectImage, Gallery của ứng dụng sẽ được mở ra và bạn có thể lựa chọn hình ảnh.

Dưới đây là phần code khi người dùng nhấn nút selectImage.

findViewById<Button>(R.id.selectImageButton).setOnClickListener {
            val intent = Intent(
                    Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST_CODE)
}

Khi người dùng chọn xong hình ảnh từ Gallery kết quả sẽ xuất hiện trong hàm onActivityResult().

Dưới đây là hàm onActivityResult() của MainActivity.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
     super.onActivityResult(requestCode, resultCode, data)
     if (requestCode == PICK_IMAGE_REQUEST_CODE && RESULT_OK == resultCode) {
         data?.let {
             try {
                 bitmap = uiHelper.decodeUri(this, it.data)
                 imageView.setImageBitmap(bitmap)
             } catch (e: Exception) {
                 if (bitmap != null) imageView.setImageBitmap(bitmap)
             }
         }
     }
 }

Sau khi người dùng đã chọn hình ảnh, hàm onActivityResult() sẽ được gọi. Do vậy, chúng ta phải lưu trữ hình ảnh dưới dạng Bitmap trong global bitmap object.

>> Tham khảo thêm về onActivityResult: Tìm hiểu Activity trong Android – Cách tạo và sử dụng

Trước khi tiến hành bước tiếp theo chúng ta phải decode hình ảnh bằng hàm decodeUri để nhận kết quả từ bitmap.

Dưới đây là hàm decodeUri()

@Throws(FileNotFoundException::class)
fun decodeUri(context: Context, selectedImage: Uri): Bitmap {
    val o = BitmapFactory.Options()
    o.inJustDecodeBounds = true
    BitmapFactory.decodeStream(context.contentResolver.openInputStream(selectedImage), null, o)
    val REQUIRED_SIZE = 140
    var width_tmp = o.outWidth
    var height_tmp = o.outHeight
    var scale = 1
    while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) {
            break
        }
        width_tmp /= 2
        height_tmp /= 2
        scale *= 2
    }
    val o2 = BitmapFactory.Options()
    o2.inSampleSize = scale
    return BitmapFactory.decodeStream(context.contentResolver.openInputStream(selectedImage), null, o2)
}

Tạo tính năng upload ảnh lên server

Vậy là, chúng ta chọn hình ảnh và lưu chúng trong bitmap object. Giờ chỉ cần upload hình ảnh khi người dùng nhấn nút “Upload Image”.

findViewById<Button>(R.id.uploadImageButton).setOnClickListener {
            if (bitmap != null) {
                val imageBytes = uiHelper.getImageBytes(bitmap!!)
                uploadImage(imageBytes)
            } else
                Toast.makeText(this, "No image selected", Toast.LENGTH_SHORT).show()
        }

Để tải hình ảnh lên, đầu tiên chúng ta phải kiểm tra xem người dùng đã chọn hình ảnh chưa.

Sau đó, chúng ta cần chuyển bitmap vào trong Base64 ByteArray.

cuối cùng là tải ảnh lên server. Dưới đây là hàm getImageBytes.

fun getImageUrl(bitmap: Bitmap): String {
    val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
    val bytes = byteArrayOutputStream.toByteArray()
    return Base64.encodeToString(bytes, Base64.DEFAULT)
}

Các công đoạn chuẩn bị đã xong. Giờ là lúc tải hình ảnh lên server.

Dưới đây là hàm uploadImage.

private fun uploadImage(imageBytes: String) {
    ServiceApi.Factory.getInstance(this).uploadImage(imageBytes)
            .enqueue(object : Callback<StatusMessageResponse> {
                override fun onFailure(call: Call<StatusMessageResponse>?, t: Throwable?) {
                    Toast.makeText(MainActivity.this,"Image uploaded",Toast.LENGTH_SHORT).show()
                    // Image uploaded successfully
                }

                override fun onResponse(call: Call<StatusMessageResponse>?, response: Response<StatusMessageResponse>?) {
                    // Error Occurred during uploading
                }
            })

}

ServerApi là một instance của interface Retrofit. Dưới đây là lớp ServerApi.

interface ServiceApi {

    companion object {
        private const val BASE_URL = ""  // Base url of your hosting
    }

    @FormUrlEncoded
    @POST("")   // end_point url
    fun uploadImage(@Field("image_bytes") imageBytes: String): Call<StatusMessageResponse>

    class Factory {

        companion object {
            private var service: ServiceApi? = null
            fun getInstance(context: Context): ServiceApi? {
                if (service == null) {
                    val builder = OkHttpClient().newBuilder()
                    builder.readTimeout(15, TimeUnit.SECONDS)
                    builder.connectTimeout(15, TimeUnit.SECONDS)
                    builder.writeTimeout(15, TimeUnit.SECONDS)
                    if (BuildConfig.DEBUG) {
                        val interceptor = HttpLoggingInterceptor()
                        interceptor.level = HttpLoggingInterceptor.Level.BODY
                        builder.addInterceptor(interceptor)
                    }
                    val file = File(context.cacheDir, "cache_dir")
                    if (!file.exists())
                        file.mkdirs()
                    val cacheSize: Long = 10 * 1024 * 1024 // 10 MiB
                    val cache = okhttp3.Cache(file, cacheSize)
                    builder.cache(cache)
                    val retrofit: Retrofit
                    retrofit = Retrofit.Builder()
                            .client(builder.build())
                            .addConverterFactory(GsonConverterFactory.create())
                            .baseUrl(BASE_URL)
                            .build()
                    service = retrofit.create(ServiceApi::class.java)
                    return service
                } else {
                    return service
                }
            }
        }
    }
}

Trong bài viết này, mình sẽ không hướng dẫn chi tiết cách sử dụng thư viện Retrofit. Bạn có thể tìm hiểu về Retrofit từ bài viết này: Kết nối rest API bằng Retrofit trong Android

Với Retrofit, mỗi request đều là HTTP bất đồng bộ, điều này giúp ứng dụng của bạn không bị “treo” khi thực hiện upload.

Chú ý: Bạn phải thêm web server của chính bạn thông qua constast BASE_URL. Thứ hai, thêm end-point URL vào phần chú thích của POST. Và cuối cùng, đừng quên thêm quyền truy cập Internet vào file Manifest.

#Tạo ứng dụng phía server(PHP)

Phía server, mình không xử lý nhiều, chỉ đơn giản là nhận ảnh và lưu lại.

// receive image as POST Parameter
$image = str_replace('data:image/png;base64,', '', $_POST['image']);
$image = str_replace(' ', '+', $image);
// Decode the Base64 encoded Image
$data = base64_decode($image);
// Create Image path with Image name and Extension
$file = '../images/' . "MyImage" . '.jpg';
// Save Image in the Image Directory
$success = file_put_contents($file, $data);

Mình sẽ không hướng dẫn cách triển khai một ứng dụng PHP trên server ở bài viết này. Hẹn các bạn ở bài viết sau nhé( Nếu các bạn có hứng thú!)

#Tạm kết

Như vậy, mình đã hướng dẫn chi tiết cách tạo ứng dụng upload ảnh lên server với PHP.

Mình hi vọng, qua bài viết này, các bạn có thể tự phát triển nó thành một ứng dụng hoàn chỉnh hơn, với nhiều tính năng cao cấp hơn. Tất cả đang chờ bạn.

Bạn có thể lấy source code hoàn chỉnh của ứng dụng trên từ GitHub.

Đừng quên để lại bình luận về ý kiến của bạn ở bên dưới nhé.

Bình luận. Đặt câu hỏi cũng là một cách học

avatar
  Theo dõi bình luận  
Thông báo