Miniware logo
Articles / Upload a file stored in the mobile phone's memory to a web server

Upload a file stored in the mobile phone's memory to a web server

This article describes how to create a java midlet that browses through all stored files in a mobile phone and uploads a selected file to a web server. This midlet uses the JSR 75 API for accessing the filesystem. JSR 75 provides methods for enumerating folder contents as well as reading and writing to a file. However the use of this API demands special permissions which means if your midlet is not signed then an annoying message will pop up every time the midlet tries to access a file or a folder asking for permission from the user. Such an application can be used in various ways, such as backing up online the files stored in a mobile phone, file sharing between a mobile phone user and a computer - or mobile phone - user and in some occasions as a cheap alternative to MMS.

If you want to download directly the code of the midlet go to the end of this page. The code of this midlet is fairly simple. It consists of a List that displays the contents of a folder, one method for reading the contents of a folder, one method for implementing the "back" functionality and one method for sending the file to the web server. But let's begin with the php script that resides on the server side and accepts the incoming file. A very basic script can be the following:

<?
if($_FILES['file']['name']!=""){
    $uploaddir = 'received_files/';
    $file = basename($_FILES['file']['name']);
    $uploadfile = $uploaddir . $file;
    if(!move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)){
        exit();
    }else{
        chmod($uploadfile,0755);
    }
}
?>

What this script is doing is to receive an HTTP Post that includes a file and store in a directory named "received_files" .

As far as the midlet is concerned the code starts as follows ( you can find a link to the full source code at the end of the page):

public class FileUpload extends MIDlet implements CommandListener,Runnable {
    List fileList;
    Display display;
    Command back;
    String currentFolder; //keeps the current directory so to implement the back functionality
    String serverURL; //the url of the web page that recieves the file
    public void startApp() {
        fileList = new List ("Select File", Choice.IMPLICIT);
        back = new Command("Back",Command.BACK,1);
        display = Display.getDisplay(this);
        currentFolder = "";
        fileList.setCommandListener(this);
        this.listRootDirectories();
        display.setCurrent(fileList);
        serverURL = "http://localhost/upload.php";
    }

As we can see, it declares a List that will holds the contents of the folders, a String named currentFolder that is used to keep the current path so to be able to implement the "back"
functionality as well as the back command and the serverURL string that it holds the url of the php script. The midlet implements the Runnable interface as we want the network communication to be held by a separate thread. Initially what the fileList should show is the root directories, thus a method name listRootDirectories has been created and it is called at the beginning of the execution. the code for this method is the following:

private void listRootDirectories(){
    fileList.deleteAll();
    Enumeration rootDirectories = FileSystemRegistry.listRoots();
    while (rootDirectories.hasMoreElements())
        fileList.append((String)rootDirectories.nextElement(),null);
    fileList.removeCommand(back);
}

What this method is doing is to clear the List of any entries, to enumerate the root directories and remove the back command from the list in case there exists because there is no more back! The method for listing folder contents is the following:

private void listFolderContents (FileConnection folder){
    fileList.deleteAll();
    try{
        Enumeration folderContents = folder.list();
        while (folderContents.hasMoreElements())
            fileList.append((String)folderContents.nextElement(),null);
            fileList.addCommand(back);
            folder.close();
        display.setCurrent(fileList);
    }catch (IOException e){}
}

It is obvious the code is very similar to the method displaying the root directories. It receives as input a FileConnection class that represents the folder and it sets the contents of the list accordingly to the contents of the folder. The code for going one directory up is the following:

private void goOneDirectoryUp(){
    int lastFolderSlashIndex = currentFolder.lastIndexOf('/',currentFolder.length() -2);
    if (lastFolderSlashIndex == -1){//up directory is the root
        this.listRootDirectories();
        currentFolder = "";
    }
    else{
        currentFolder = currentFolder.substring(0,lastFolderSlashIndex + 1);
        try{
            FileConnection fc = (FileConnection)Connector.open("file:///" + currentFolder);
            this.listFolderContents(fc);
            }catch(IOException e){}
    }
}

This method makes use of the currentFolder string that holds the path to the current directory. If the path contains only one slash (i.e c:/ ) then the root directories should be shown, if not then the previous directory is being found by the position of the second slash counting form the end (i.e if currentFolder is "c:/pictures/memory/ then the previous directory is c:/pictures/). Now it's time to see what happens when a command is invoked:

public void commandAction(Command com, Displayable dis) {
    if (com == List.SELECT_COMMAND){ // A direcotroy or folder has been selected
        try{
            FileConnection fc = (FileConnection)Connector.open("file:///" + currentFolder +
            fileList.getString(fileList.getSelectedIndex()));
            if (fc.isDirectory()){
                currentFolder = currentFolder + fileList.getString(fileList.getSelectedIndex());
                this.listFolderContents(fc);
            }else{// it is a file, upload it to the server
                try{
                    Thread t = new Thread(this);
                    t.start();
                }catch(Exception e){ }
            }
        }catch(IOException e){}
    }
    if (com == back){
        this.goOneDirectoryUp();
    }
}

As it can been seen, when the user press select the code checks whether the selected item is folder or file. It it is a folder it creates a FileConnection class that represents the folder, it sets accordingly the currentFolder string and it calls the listFolderContents. If the selected item is a file then it calls the run method of the current thhread which - as it will be shown later on - it send the file to the web server. If thee user press the back command the code simply calls the goOneDirectoryUp method. The last method of the midlet is the run method which send the file to the web server. The implementation of this method is the follwoing:

public void run(){
    try{
        FileConnection fc = (FileConnection)Connector.open("file:///" + currentFolder +
        fileList.getString(fileList.getSelectedIndex()));
        currentFolder = currentFolder + "/";
        int fileSize = (int)(fc.fileSize());
        //Build a form that it will displays a progress bar and
        //the amount of data that haw been sent
        Form form = new Form ("Uploading....");
        Gauge gauge = new Gauge("Progress",false,fileSize,0);
        StringItem stringitem = new StringItem ("","0 / " + fileSize);
        form.append(gauge);
        form.append(stringitem);
        display.setCurrent(form);
        //Build the necessary http post messages
        String message1, message2;
        message1 = "--file\r\n";
        message1 += "Content-Disposition: form-data; name=\"file\"; filename=\"" + fc.getName()+ "\"\r\n";
        message1 += "Content-Type: text/plain\r\n\r\n";
        message2 = "\r\n--file--\r\n";
        String length = Integer.toString((message1.length() + message2.length() + fileSize));
        OutputStream os = null;
        HttpConnection conn = (HttpConnection)Connector.open(serverURL,Connector.READ_WRITE);
        conn.setRequestMethod(HttpConnection.POST );
        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=file");
        os = conn.openOutputStream( );
        os.write(message1.getBytes());
        InputStream ins = fc.openInputStream();
        byte[] buffer = new byte[2048];
        int sendCounter = fileSize;
        //Write the contents of the file
        while (ins.read(buffer)> 0){
            if (sendCounter >=2048)
            os.write(buffer,0,2048);
        else
            os.write(buffer,0,sendCounter);
            sendCounter = sendCounter - 2048;
            gauge.setValue(gauge.getValue() + buffer.length);
            stringitem.setText(gauge.getValue() + " / " + fileSize);
        }
        //Flushing the output
        stringitem.setText("Please wait...");
        os.close();
        stringitem.setText("Upload completed");
        form.addCommand(back);
        form.setCommandListener(this);
    }catch(Exception e){}
}

As it can been seen this method, initially opens the selected file, it appends a slash to the currentFolder string so the "back" functionality to work correctly, it creates a form that shows the progress of the process using a gauge as well as a string item, it constructs the necessary HTTP messages, it connects to the web server, it sends the data, it adds the back command to the form and it finishes

The complete source code can be found here

The content of this page can be reproduced as long as the author and the source are mentioned. For questions please use the forum. Nikos Fotiou
Comments
(Post new comment)