Read on Android Upload File To Server Programmatically PHP-MySQL Tutorial.
I will guide you how to upload any file to php-MySQL server from android app.
We will use httpclient and multipart functionality to accomplish our goal.
A PHP script will help us to establish interaction between android app and remote server.
Final Output Video
See the following video which gives the output.
PHP Scripts
We need to create one PHP file which will help us to insert the file on to the remote server as well as MySQL database.
Make a new php file and give it a name like config.php
Write down the below source lines in config.php
<?php $host="localhost"; $user="your username"; $password="your password"; $db = "your db name"; $con = mysqli_connect($host,$user,$password,$db); // Check connection if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); }else{ //echo "Connect"; } ?>
Create another PHP file and its name should be uploadfile.php
Following is the code for uploadfile.php
<?php if($_SERVER['REQUEST_METHOD']=='POST'){ // echo $_SERVER["DOCUMENT_ROOT"]; // /home1/demonuts/public_html //including the database connection file include_once("config.php"); //$_FILES['image']['name'] give original name from parameter where 'image' == parametername eg. city.jpg //$_FILES['image']['tmp_name'] temporary system generated name $originalImgName= $_FILES['filename']['name']; $tempName= $_FILES['filename']['tmp_name']; $folder="uploadedFiles/"; $url = "https://www.demonuts.com/Demonuts/JsonTest/Tennis/uploadedFiles/".$originalImgName; //update path as per your directory structure if(move_uploaded_file($tempName,$folder.$originalImgName)){ $query = "INSERT INTO upload_image_video (pathToFile) VALUES ('$url')"; if(mysqli_query($con,$query)){ $query= "SELECT * FROM upload_image_video WHERE pathToFile='$url'"; $result= mysqli_query($con, $query); $emparray = array(); if(mysqli_num_rows($result) > 0){ while ($row = mysqli_fetch_assoc($result)) { $emparray[] = $row; } echo json_encode(array( "status" => "true","message" => "Successfully file added!" , "data" => $emparray) ); }else{ echo json_encode(array( "status" => "false","message" => "Failed!") ); } }else{ echo json_encode(array( "status" => "false","message" => "Failed!") ); } //echo "moved to ".$url; }else{ echo json_encode(array( "status" => "false","message" => "Failed!") ); } } ?>
Now our PHP related work is complete. Now in your android studio, create a new project.
Step 1. Gradle Modifications
Every android studio have two types of gradle files.
First of all, open your build.gradle(Module :app) file, you need to add below lines in this file
implementation group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1' implementation('org.apache.httpcomponents:httpmime:4.3') { exclude module: "httpclient" } implementation 'com.karumi:dexter:5.0.0'
First two lines are integrating some classes which will allow us to use httpclient and multipart in our android project.
Last line is for dexter library. This library will help us to simplify the process of asking the runtime permissions to the user.
After this, write the following lines in build.gradle(Module :app) file
android{ useLibrary 'org.apache.http.legacy' } packagingOptions { exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' }
So, final code for build.gradle(Module :app) file is as the below
apply plugin: 'com.android.application' android { compileSdkVersion 27 defaultConfig { applicationId "com.example.parsaniahardik.upload_file_zerones" minSdkVersion 15 targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } android{ useLibrary 'org.apache.http.legacy' } packagingOptions { exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1' implementation('org.apache.httpcomponents:httpmime:4.3') { exclude module: "httpclient" } implementation 'com.karumi:dexter:5.0.0' }
Now it is time to update second gradle file which have the name like build.gradle(Project: Upload_file_Zerone). In this file name Upload_file_Zerone is the name of our android studio project.
Add the below line in this file
maven { url 'https://jitpack.io' }
So last source code for build.gradle(Project: Upload_file_Zerone) is like the below
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() maven { url 'https://jitpack.io' } } } task clean(type: Delete) { delete rootProject.buildDir }
Step 2. Making Permissions
In this project, we need to have three permissions from user.
Add the following source lines in AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I have defined three permissions : Internet, Read external storage and Write external storage.
We also need to write runtime permissions code but I will cover them in MainActivity.java file.
Step 3. Necessary Interface
Create a new Interface and set the name as “AsyncTaskCompleteListener.java”
Source snippet for AsyncTaskCompleteListener.java is as the below
public interface AsyncTaskCompleteListener { void onTaskCompleted(String response, int serviceCode); }
We need to implement this interface in the main activity.
Step 4. Multipart related Class
Create a new JAVA class and set its name as MultiPartRequester.java
Write down the below lines in MultiPartRequester.java
import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.os.AsyncTask; import android.util.Log; import android.widget.Toast; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MIME; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.util.EntityUtils; import java.io.File; import java.util.Map; public class MultiPartRequester { private Map<String, String> map; private AsyncTaskCompleteListener mAsynclistener; private int serviceCode; private HttpClient httpclient; private Activity activity; private AsyncHttpRequest request; public MultiPartRequester(Activity activity, Map<String, String> map, int serviceCode, AsyncTaskCompleteListener asyncTaskCompleteListener) { this.map = map; this.serviceCode = serviceCode; this.activity = activity; mAsynclistener = (AsyncTaskCompleteListener) asyncTaskCompleteListener; request = (AsyncHttpRequest) new AsyncHttpRequest().execute(map .get("url")); } class AsyncHttpRequest extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { map.remove("url"); try { HttpPost httppost = new HttpPost(urls[0]); httpclient = new DefaultHttpClient(); HttpConnectionParams.setConnectionTimeout( httpclient.getParams(), 600000); MultipartEntityBuilder builder = MultipartEntityBuilder .create(); for (String key : map.keySet()) { if (key.equalsIgnoreCase("filename")) { File f = new File(map.get(key)); builder.addBinaryBody(key, f, ContentType.MULTIPART_FORM_DATA, f.getName()); } else { builder.addTextBody(key, map.get(key), ContentType .create("text/plain", MIME.DEFAULT_CHARSET)); } Log.d("TAG", key + "---->" + map.get(key)); // System.out.println(key + "---->" + map.get(key)); } httppost.setEntity(builder.build()); ActivityManager manager = (ActivityManager) activity .getSystemService(Context.ACTIVITY_SERVICE); if (manager.getMemoryClass() < 25) { System.gc(); } HttpResponse response = httpclient.execute(httppost); String responseBody = EntityUtils.toString( response.getEntity(), "UTF-8"); return responseBody; } catch (Exception e) { e.printStackTrace(); } catch (OutOfMemoryError oume) { System.gc(); Toast.makeText( activity.getParent().getParent(), "Run out of memory please colse the other background apps and try again!", Toast.LENGTH_LONG).show(); } finally { if (httpclient != null) httpclient.getConnectionManager().shutdown(); } return null; } @Override protected void onPostExecute(String response) { if (mAsynclistener != null) { mAsynclistener.onTaskCompleted(response, serviceCode); } } } private void showToast(String msg) { Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show(); } }
This multipart class will help us to make http calls using its objects.
We will use this class as a library, so do not change anything in this class.
Step 5. Main Activity Works
This is the final step in this tutorial.
There are two main files in this project. One is activity_main.xml and another is MainActivity.java
First, add the below code in activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#900ce2" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:textColor="#000" android:textSize="25sp" android:text="Below is the URL to Uploaded file"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:textColor="#fff" android:textSize="25sp" android:text="URL to File"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:text="Select Any file to Upload" /> </LinearLayout>
This layout file has one button and two text views.
One text view is static and we will not change it’s value. Another text view will hold the text as the URL of the uploaded file.
When the user clicks the button, system will open the file manager.
Now following is the code block for MainActivity.java file
import android.Manifest; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.karumi.dexter.Dexter; import com.karumi.dexter.MultiplePermissionsReport; import com.karumi.dexter.PermissionToken; import com.karumi.dexter.listener.DexterError; import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.PermissionRequestErrorListener; import com.karumi.dexter.listener.multi.MultiplePermissionsListener; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; public class MainActivity extends AppCompatActivity implements AsyncTaskCompleteListener{ private Button btn; private TextView tv; private String url = "https://www.google.com"; private static final int BUFFER_SIZE = 1024 * 2; private static final String IMAGE_DIRECTORY = "/demonuts_files"; private final int GALLERY = 1; private ArrayList<HashMap<String, String>> arraylist; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestMultiplePermissions(); btn = findViewById(R.id.btn); tv = findViewById(R.id.tv); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("file/*"); startActivityForResult(intent,1); } }); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { // Get the Uri of the selected file Uri uri = data.getData(); String path = getFilePathFromURI(MainActivity.this,uri); Log.d("ioooo",path); uploadPDFfile(path); } super.onActivityResult(requestCode, resultCode, data); } private void uploadPDFfile(String path) { HashMap<String, String> map = new HashMap<String, String>(); map.put("url", "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php"); map.put("filename", path); new MultiPartRequester(this, map, GALLERY, this); } @Override public void onTaskCompleted(String response, int serviceCode) { Log.d("res", response); switch (serviceCode) { case GALLERY: try { JSONObject jsonObject = new JSONObject(response); jsonObject.toString().replace("\\\\",""); if (jsonObject.getString("status").equals("true")) { arraylist = new ArrayList<HashMap<String, String>>(); JSONArray dataArray = jsonObject.getJSONArray("data"); for (int i = 0; i < dataArray.length(); i++) { JSONObject dataobj = dataArray.getJSONObject(i); url = dataobj.optString("pathToFile"); } tv.setText(url); } } catch (JSONException e) { e.printStackTrace(); } } } public static String getFilePathFromURI(Context context, Uri contentUri) { //copy file and send new file path String fileName = getFileName(contentUri); File wallpaperDirectory = new File( Environment.getExternalStorageDirectory() + IMAGE_DIRECTORY); // have the object build the directory structure, if needed. if (!wallpaperDirectory.exists()) { wallpaperDirectory.mkdirs(); } if (!TextUtils.isEmpty(fileName)) { File copyFile = new File(wallpaperDirectory + File.separator + Calendar.getInstance() .getTimeInMillis()+".txt"); // create folder if not exists copy(context, contentUri, copyFile); return copyFile.getAbsolutePath(); } return null; } public static String getFileName(Uri uri) { if (uri == null) return null; String fileName = null; String path = uri.getPath(); int cut = path.lastIndexOf('/'); if (cut != -1) { fileName = path.substring(cut + 1); } return fileName; } public static void copy(Context context, Uri srcUri, File dstFile) { try { InputStream inputStream = context.getContentResolver().openInputStream(srcUri); if (inputStream == null) return; OutputStream outputStream = new FileOutputStream(dstFile); copystream(inputStream, outputStream); inputStream.close(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static int copystream(InputStream input, OutputStream output) throws Exception, IOException { byte[] buffer = new byte[BUFFER_SIZE]; BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE); BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE); int count = 0, n = 0; try { while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) { out.write(buffer, 0, n); count += n; } out.flush(); } finally { try { out.close(); } catch (IOException e) { Log.e(e.getMessage(), String.valueOf(e)); } try { in.close(); } catch (IOException e) { Log.e(e.getMessage(), String.valueOf(e)); } } return count; } private void requestMultiplePermissions(){ Dexter.withActivity(this) .withPermissions( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) .withListener(new MultiplePermissionsListener() { @Override public void onPermissionsChecked(MultiplePermissionsReport report) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(getApplicationContext(), "All permissions are granted by user!", Toast.LENGTH_SHORT).show(); } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied()) { // show alert dialog navigating to Settings } } @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) { token.continuePermissionRequest(); } }). withErrorListener(new PermissionRequestErrorListener() { @Override public void onError(DexterError error) { Toast.makeText(getApplicationContext(), "Some Error! ", Toast.LENGTH_SHORT).show(); } }) .onSameThread() .check(); } }
Reading above code
First of all, see the below source
private Button btn; private TextView tv; private String url = "https://www.google.com"; private static final int BUFFER_SIZE = 1024 * 2; private static final String IMAGE_DIRECTORY = "/demonuts_files"; private final int GALLERY = 1; private ArrayList<HashMap<String, String>> arraylist;
First line is making an object of button class. Second one is for text view class.
Third line is making one string variable and its value is google URL.
Fourth one making an integer variable which defines buffer size.
Fifth line is string variable which holds the “directory” where we will save the file.
Sixth line is integer variable and last one is making one araylist of Hashmaps.
Now read the onCreate() method. It holds a method requestMultiplePermissions()
Source lines for requestMultiplePermissions() method is as the following
private void requestMultiplePermissions(){ Dexter.withActivity(this) .withPermissions( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) .withListener(new MultiplePermissionsListener() { @Override public void onPermissionsChecked(MultiplePermissionsReport report) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(getApplicationContext(), "All permissions are granted by user!", Toast.LENGTH_SHORT).show(); } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied()) { // show alert dialog navigating to Settings } } @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) { token.continuePermissionRequest(); } }). withErrorListener(new PermissionRequestErrorListener() { @Override public void onError(DexterError error) { Toast.makeText(getApplicationContext(), "Some Error! ", Toast.LENGTH_SHORT).show(); } }) .onSameThread() .check(); }
This method is taking care of runtime permissions stuff.
We will ask for two permissions : Read and write external storage.
Method will use dexter library to implement professional behavior regarding runtime permission environment.
Now consider the following source snippet
btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("file/*"); startActivityForResult(intent,1); } });
System will run the above code when the user clicks the button.
It will create one intent which will led the user to the new screen.
New screen will open all the files of android device and user can select any one to upload it to the server.
Now see the below source lines
tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent); } });
When user clicks the text view, compiler will open the URL in web browser to which file is uploaded.
After selecting the file from file manager, compiler will run the onActivityResult() method.
Below is the source for onActivityResult() method.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { // Get the Uri of the selected file Uri uri = data.getData(); String path = getFilePathFromURI(MainActivity.this,uri); Log.d("ioooo",path); uploadPDFfile(path); } super.onActivityResult(requestCode, resultCode, data); }
Compiler will first get the Uri of the selected file.
Then it will store the file using getFilePathFromURI() method. This method will return the path to the saved file.
Using this path, compiler will run the uploadPDFfile() function.
Below is the source lines for uploadPDFfile() function.
private void uploadPDFfile(String path) { HashMap<String, String> map = new HashMap<String, String>(); map.put("url", "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php"); map.put("filename", path); new MultiPartRequester(this, map, GALLERY, this); }
Here, compiler will create one Hashmap with string as a key and value.
It will add url in first map and a path to the file in the second map.
Then it will make the http call using the MultipartRequester class.
After successful http call, compiler will run the onTaskCompleted() method.
Following is the code snippet for onTaskCompleted() method.
@Override public void onTaskCompleted(String response, int serviceCode) { Log.d("res", response); switch (serviceCode) { case GALLERY: try { JSONObject jsonObject = new JSONObject(response); jsonObject.toString().replace("\\\\",""); if (jsonObject.getString("status").equals("true")) { arraylist = new ArrayList<HashMap<String, String>>(); JSONArray dataArray = jsonObject.getJSONArray("data"); for (int i = 0; i < dataArray.length(); i++) { JSONObject dataobj = dataArray.getJSONObject(i); url = dataobj.optString("pathToFile"); } tv.setText(url); } } catch (JSONException e) { e.printStackTrace(); } } }
In this method, compiler will have a JSON response in the string format.
It will parse this JSON response and will get the URL where the uploaded file resides.
Then it will set this URL as the value of the text view.