Membuat File Upload di Android dan PHP

written by Arief Bayu Purwanto on June 18, 2012 in Tutorial with 6 comments

Saya tahu ini adalah proses yang sangat sederhana di PHP. Tapi, di android lumayan njelimet juga. Karena, proses ini memaksa anda untuk sedikit banyak mengerti, bagaimana sebuah http request dibuat.

Membuat PHP Backend

Sebelum kita membuat aplikasi android, siapkan dulu script untuk menerima file yang akan diupload. Sederhana saja, yang penting tujuan menerima file bisa terpenuhi. berikut script PHP yang saya gunakan:

<?php
header('Content-Type: Text/Plain');
//print_r($_POST);
//print_r($_FILES);
if(isset($_POST['submit'])){
	echo "isi pesan: " . $_POST['pesan'] . "\n";
	$counter = 0;
	foreach($_FILES['upload']['error'] as $key => $value){
		$counter++;
		if($_FILES['upload']['error'][$key] === UPLOAD_ERR_OK){
			echo "file upload #" . $counter . " berhasil.\n";
			echo "  nama file: " . $_FILES['upload']['name'][$key] . "\n";
			echo "  ukuran file: " . $_FILES['upload']['size'][$key] . "\n";
		} else {
			echo "file upload #" . $counter . " gagal.\n";
		}
	}
}

Untuk contoh ini, simpanlah script di atas dengan nama upload-receiver.php

Test PHP Backend

Step berikutnya, mencoba apakah script di atas sudah benar. Jangan sampai sudah capek sampai keriting ngutak-atik kode android, ternyata yang salah adalah script php-nya. Untuk tujuan testing ini, saya pakai kode html berikut:

<html>
	<head>
		<title>test upload receiver</title>
	</head>
	<body>
		<form method="post" enctype="multipart/form-data" action="upload-receiver.php">
		Masukkan pesan yang ingin disampaikan: <input type="text" name="pesan" /> <br/>
		Masukkan file yang ingin diupload:<br />
			<input type="file" name="upload[]"/><br/>
			<input type="file" name="upload[]"/><br/>
			<input type="submit" name="submit" value="Upload" />
		</form>
	</body>
</html>

Silahkan disimpan dengan nama sesuka anda, misal test-upload.html. Lalu jalankan di browser. Hasilnya, sedikit banyak akan seperti ini:

Free Image Hosting at www.ImageShack.us

Output HTML

Free Image Hosting at www.ImageShack.us

Output PHP setelah menerima data dari HTML

Membuar Android Client

Setelah semua lancar di sisi backend (php), kita masuk ke proses di aplikasi android. Di bagian ini, saya tidak akan menjelaskan lebih banyak untuk bagaimana membuat layout, menghandle onClick() dan juga cara untuk membuat gallery. Semua itu berada di luar scope dari tutorial ini. Yang akan saya jelaskan adalah bagaimana cara membuka koneksi HTTP, mengirimkan data, dan membaca hasil dari proses tersebut.

Inisialisasi HttpURLConnection

Kita akan menggunakan class HttpURLConnection untuk proses upload ini:

HttpURLConnection conn = null;
conn = (HttpURLConnection) url.openConnection();

conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");

Kemudian, seperti yang biasa dilakukan saat mengupload file dari php, kita juga harus mengatur Content-Type ke multipart/form-data.

conn.setRequestProperty("Content-Type",
	"multipart/form-data; boundary=" + HTTP_FIELD_BOUNDARY);

Coba perhatikan, di sini kita tambahkan property boundary. Property ini digunakan untuk menentikan pemisah antara data field-field form yang dikirim. Boundary merupakan rangkaian string acak yang bisa kita definisikan sendiri, tidak ada yang baku.

Menambahkan Field Post Normal

Untuk menambahkan field, pertama kali yang harus dilakukan adalah membuka OutputStream:

DataOutputStream dataOS = new DataOutputStream(conn.getOutputStream());

Selanjutnya menambahkan field itu sendiri:

dataOS.writeBytes(HttpUtil.getRequestParameter(HTTP_FIELD_BOUNDARY,
		"submit", "submit"));
dataOS.writeBytes(HttpUtil.getRequestParameter(HTTP_FIELD_BOUNDARY,
		"pesan", txtPesan.getText().toString()));

Perhatikan kalau saya menggunakan function HttpUtil.getRequestParameter(). Ini adalah function yang saya buat sendiri, untuk memudahkan. Isinya seperti ini:

public static String _getRequestParameterImpl(String bounrdy, String key,
		String value) {
	StringBuilder requestBody = new StringBuilder();
	requestBody.append("--");
	requestBody.append(bounrdy);
	requestBody.append("\r\n");
	requestBody.append("Content-Disposition: form-data; name=\"" + key
			+ "\"");
	requestBody.append("\r\n");
	requestBody.append("\r\n");
	requestBody.append(value);
	requestBody.append("\r\n");

	return requestBody.toString();
}

Kalau kalian perhatikan, di sana ada banyak karakter-karakter terulang. Sebenarnya itu adalah format penulisan field di http. Untuk lebih jelasnya, silahkan baca artikel tentang spesifikasi http post multipart ini.

Menambahkan Field Post File

Sedangkan cara untuk menambahkan file, adalah seperti berikut:

Pertama-tama, kita buka dulu filenya, lalu buat deklarasi field untuk file upload. Perhatikan bagian name dan filename. Untuk name, adalah nama yang akan dikirimkan sebagai nama field, sedangkan filename adalah path dari file yang diupload.

File fileToUpload = new File(selectedImagePath1);
dataOS.writeBytes("--" + HTTP_FIELD_BOUNDARY + "\r\n");
dataOS.writeBytes("Content-Disposition: form-data; name=\"upload[]\"; filename=\""
		+ fileToUpload.getAbsoluteFile() + "\";" + "\r\n");
dataOS.writeBytes("Content-Type: image/jpeg" + "\r\n");
dataOS.writeBytes("\r\n");

Selanjutnya, kita baca dan tambahkan isi file tersebut dalam bentuk byte.

FileInputStream fileInputStream = new FileInputStream(fileToUpload);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);

while (bytesRead > 0) {
	dataOS.write(buffer, 0, bufferSize);
	bytesAvailable = fileInputStream.available();
	bufferSize = Math.min(bytesAvailable, maxBufferSize);
	bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}

yang terakhir, kita tutup field ini dengan karakter \r\n. Kalau bingung maksudnya, silahkan baca lagi url yang saya sertakan di atas tentang spesifikasi http post multipart.

dataOS.writeBytes("\r\n");

Mengirim, Mengecek dan Membaca Hasil

Bagian ini cukup sederhana, untuk mengirim request dan mendapatkan hasil, dilakukan secara simultan oleh baris kode berikut:

int responseCode = conn.getResponseCode();

if (responseCode != 200) {
	Log.i("LOG", String.format(
			"Received the response code %d from the URL %s",
			responseCode, url));
} else {
    //kode untuk membaca response
}

Dan di bawah ini, adalah potongan kode untuk membaca response dari server:

InputStream is = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
while ((bytesRead = is.read(bytes)) != -1) {
	baos.write(bytes, 0, bytesRead);
}
byte[] bytesReceived = baos.toByteArray();
baos.close();

is.close();
String response = new String(bytesReceived);
txtResult.setText(response);
Log.i("LOG", response);

Membuar Android Client

Beginilah contoh tangkapan layar dari aplikasi android, setelah semua kode di atas dijadikan satu:

Free Image Hosting at www.ImageShack.us
Free Image Hosting at www.ImageShack.us

Kode di atas masih sangat sederhana. Tapi sangat cukup untuk menjadi basis pengembangan selanjutnya. Silahkan download sourcecode-nya di bawah ini.