Wednesday, June 18, 2014

How to Upload Files with CodeIgniter and AJAX?

Uploading files asynchronously with CodeIgniter can be confusing and frustrating experience. In this tutorial I will share the steps how I successfully implemented a file upload with CodeIgniter and ajax.

You need CodeIgniter, jQuery, and the script AjaxFileUpload which you can copy from bottom of this tutorial.

It's assumed you have a working knowledge of CodeIgniter and jQuery. But no prior knowledge of AjaxFileUpload is necessary. It is also assumed that you already have successfully set up CodeIgniter. For the sake of brevity and clarity, we are not going to use database to save file information.

Step 1. Creating a form
Create your view and name it upload.php. This view will contain our upload form.

<!doctype html>
<html>
<head>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
 <script src="<?php echo base_url()?>js/custom.js"></script>
 <script src="<?php echo base_url()?>js/ajaxfileupload.js"></script>
</head>
<body>
 <h1>Upload File</h1>
 <form method="post" action="" id="upload_file">
 <label for="userfile">File</label>
<input type="file" name="userfile" id="userfile" size="20" /> <input type="submit" name="submit" id="submit" /> </form> <h2>Files</h2> <div id="files"></div> </body> </html>
At the top; jQuery, AjaxFileUpload, and our own custom javascript files are loaded.
Then, we created a standard HTML form. The empty #files div is where the confirmation/failure message will be displayed.
Step 2. Custom Javascript
Create custom.js inside 'js' folder and Place the following code:
$(function() {
    $('#upload_file').submit(function(e) {
        e.preventDefault();
        $.ajaxFileUpload({
            url             :base_url + './upload/upload_file/', 
            secureuri       :false,
            fileElementId   :'userfile',
            dataType: 'JSON',
            success : function (data)
            {
               var obj = jQuery.parseJSON(data);                
                if(obj['status'] == 'success')
                {
                    $('#files').html(obj['msg']);
                 }
                else
                 {
                    $('#files').html('Some failure message');
                  }
            }
        });
        return false;
    });
});
The JavaScript hijacks the form submit and AjaxFileUpload takes over. In the background, it creates an iframe and submits the data via that.
We then check our return (which will be in JSON). Depending on the status(success/error), we display message.
Step 3. Uploading a File
The Controller
The URL we are uploading to is /upload/upload_file/, so create a new method in the upload controller, and place the following code in it.
public function upload_file()
{
  $status = "";
  $msg = "";
  $file_element_name = 'userfile';

 if ($status != "error")
{
  $config['upload_path'] = './uploads/';
  $config['allowed_types'] = 'gif|jpg|png|doc|txt';
  $config['max_size'] = 1024 * 8;
  $config['encrypt_name'] = FALSE;

  $this->load->library('upload', $config);
  if (!$this->upload->do_upload($file_element_name))
  {
    $status = 'error';
    $msg = $this->upload->display_errors('', '');
  }
  else
   {
   $data = $this->upload->data();
   $image_path = $data['full_path'];
   if(file_exists($image_path))
   {
      $status = "success";
      $msg = "File successfully uploaded";
 }
 else
 {
  $status = "error";
  $msg = "Something went wrong when saving the file, please try again.";
 }
}
 @unlink($_FILES[$file_element_name]);
 }
 echo json_encode(array('status' => $status, 'msg' => $msg));
}

This code loads in the CodeIgniter upload library with a custom config. Remember to delete the temp file off the server, and echo out the JSON so we know what happened.

Files Folder
We should also create the folder our files will be uploaded to. Create new file in your web root called 'uploads', making sure it is writable by the server.

That's it, tutorial complete! If you run it, you should be able to upload a file, see it appear, all without leaving the page.

Note: I haven't added displaying, editing and deleting files.

Goodies:
Copy and paste the following javascript code and save as ajaxfileupload.js.

jQuery.extend({	

  createUploadIframe: function(id, uri)
	{
			//create frame
      var frameId = 'jUploadFrame' + id;
      var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"';
			if(window.ActiveXObject)
			{
        if(typeof uri== 'boolean'){
iframeHtml += ' src="' + 'javascript:false' + '"';

        }
        else if(typeof uri== 'string'){
iframeHtml += ' src="' + uri + '"';

        }	
			}
			iframeHtml += ' />';
			jQuery(iframeHtml).appendTo(document.body);

      return jQuery('#' + frameId).get(0);			
  },
  createUploadForm: function(id, fileElementId, data)
	{
		//create form	
		var formId = 'jUploadForm' + id;
		var fileId = 'jUploadFile' + id;
		var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');	
		if(data)
		{
			for(var i in data)
			{
				jQuery('<input type="hidden" name="' + i + '" value="' + data[i] + '" />').appendTo(form);
			}			
		}		
		var oldElement = jQuery('#' + fileElementId);
		var newElement = jQuery(oldElement).clone();
		jQuery(oldElement).attr('id', fileId);
		jQuery(oldElement).before(newElement);
		jQuery(oldElement).appendTo(form);
		
		//set attributes
		jQuery(form).css('position', 'absolute');
		jQuery(form).css('top', '-1200px');
		jQuery(form).css('left', '-1200px');
		jQuery(form).appendTo('body');		
		return form;
  },

  ajaxFileUpload: function(s) {
    // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout		
    s = jQuery.extend({}, jQuery.ajaxSettings, s);
    var id = new Date().getTime()    
		var form = jQuery.createUploadForm(id, s.fileElementId, (typeof(s.data)=='undefined'?false:s.data));
		var io = jQuery.createUploadIframe(id, s.secureuri);
		var frameId = 'jUploadFrame' + id;
		var formId = 'jUploadForm' + id;		
    // Watch for a new set of requests
    if ( s.global && ! jQuery.active++ )
		{
			jQuery.event.trigger( "ajaxStart" );
		}      
    var requestDone = false;
    // Create the request object
    var xml = {} 
    if ( s.global )
      jQuery.event.trigger("ajaxSend", [xml, s]);
    // Wait for a response to come back
    var uploadCallback = function(isTimeout)
		{			
			var io = document.getElementById(frameId);
      try
			{				
				if(io.contentWindow)
				{
 xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
        	 xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;

				}else if(io.contentDocument)
				{
 xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
        	xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
				}	
      }catch(e)
			{
				jQuery.handleError(s, xml, null, e);
			}
      if ( xml || isTimeout == "timeout")
			{				
        requestDone = true;
        var status;
        try {
          status = isTimeout != "timeout" ? "success" : "error";
          // Make sure that the request was successful or notmodified
          if ( status != "error" )
{
            // process the data (runs the xml through httpData regardless of callback)
            var data = jQuery.uploadHttpData( xml, s.dataType );  
            // If a local callback was specified, fire it and pass it the data
            if ( s.success )
              s.success( data, status );
 
            // Fire the global callback
            if( s.global )
              jQuery.event.trigger( "ajaxSuccess", [xml, s] );
          } else
            jQuery.handleError(s, xml, status);
        } catch(e)
				{
          status = "error";
          jQuery.handleError(s, xml, status, e);
        }

        // The request was completed
        if( s.global )
          jQuery.event.trigger( "ajaxComplete", [xml, s] );

        // Handle the global AJAX counter
        if ( s.global && ! --jQuery.active )
          jQuery.event.trigger( "ajaxStop" );

        // Process result
        if ( s.complete )
          s.complete(xml, status);

        jQuery(io).unbind()

        setTimeout(function()
				{	try
					{
						jQuery(io).remove();
						jQuery(form).remove();	
						
					} catch(e)
					{
						jQuery.handleError(s, xml, null, e);
					}				

				}, 100)

        xml = null

      }
    }
    // Timeout checker
    if ( s.timeout > 0 )
		{
      setTimeout(function(){
        // Check to see if the request is still happening
        if( !requestDone ) uploadCallback( "timeout" );
      }, s.timeout);
    }
    try
		{

			var form = jQuery('#' + formId);
			jQuery(form).attr('action', s.url);
			jQuery(form).attr('method', 'POST');
			jQuery(form).attr('target', frameId);
      if(form.encoding)
			{
				jQuery(form).attr('encoding', 'multipart/form-data');   			
      }
      else
			{	
				jQuery(form).attr('enctype', 'multipart/form-data');			
      }			
      jQuery(form).submit();

    } catch(e)
		{			
      jQuery.handleError(s, xml, null, e);
    }
		
		jQuery('#' + frameId).load(uploadCallback	);
    return {abort: function () {}};	

  },

  uploadHttpData: function( r, type ) {
    var data = !type;
    data = type == "xml" || data ? r.responseXML : r.responseText;
    // If the type is "script", eval it in global context
    if ( type == "script" )
      jQuery.globalEval( data );
    // Get the JavaScript object, if JSON is used.
    if ( type == "json" )
      eval( "data = " + data );
    // evaluate scripts within html
    if ( type == "html" )
      jQuery("<div>").html(data).evalScripts();

    return data;
  }
})


If you are looking for delete and display features, you can find in below tutorial.

Reference site: http://code.tutsplus.com/tutorials/how-to-upload-files-with-codeigniter-and-ajax--net-21684

14 comments:

  1. How to add file name to database.

    ReplyDelete
  2. your code works fine now only i need to add progress bar please help

    ReplyDelete
  3. its not working for me it showing $.ajaxFileUpload is not a function

    ReplyDelete
  4. Usually I do not read post on blogs, but I would like to say that this write-up very forced me to try and do it! Your writing style has been surprised me. Great work admin.Keep update more blog.
    PHP Training in Chennai

    ReplyDelete
  5. We are a group of volunteers and starting a new initiative in a community. Your blog provided us valuable information to work on.You have done a marvellous job!

    java training in chennai | java training in bangalore

    java training in tambaram | java training in velachery

    java training in omr | oracle training in chennai

    ReplyDelete
  6. Inspiring writings and I greatly admired what you have to say , I hope you continue to provide new ideas for us all and greetings success always for you..Keep update more information..

    rpa training in Chennai | rpa training in pune

    rpa training in tambaram | rpa training in sholinganallur

    rpa training in Chennai | rpa training in velachery

    rpa online training | rpa training in bangalore

    ReplyDelete
  7. You got an extremely helpful website I actually have been here reading for regarding an hour. I’m an initiate and your success is incredibly a lot of a concept on behalf of me.
    python training in Bangalore
    python training in pune

    ReplyDelete
  8. A very nice guide. I will definitely follow these tips. Thank you for sharing such detailed article. I am learning a lot from you.
    java training in jayanagar | java training in electronic city

    java training in chennai | java training in USA

    ReplyDelete
  9. I appreciate your efforts because it conveys the message of what you are trying to say. It's a great skill to make even the person who doesn't know about the subject could able to understand the subject . Your blogs are understandable and also elaborately described. I hope to read more and more interesting articles from your blog. All the best.

    Data Science training in Chennai
    Data science training in bangalore
    Data science training in pune
    Data science online training

    ReplyDelete
  10. Wonderful bloggers like yourself who would positively reply encouraged me to be more open and engaging in commenting.So know it's helpful.
    python training in tambaram
    python training in annanagar
    python training in jayanagar

    ReplyDelete
  11. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.
    Devops training in marathahalli
    Devops training in rajajinagar

    ReplyDelete