thiagobraga
8/29/2012 - 12:32 PM

Valums AJAX File Uploader for CodeIgniter

Valums AJAX File Uploader for CodeIgniter

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<link href="<?php echo base_url(); ?>assets/css/file-uploader.css" rel="stylesheet" type="text/css">	
	<link href="<?php echo base_url(); ?>assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">	
    <style>    	
		body {font-size:13px; font-family:arial, sans-serif; width:700px; margin:100px auto;}
    </style>	
</head>
<body>		    
    
	<p>To upload a file, click on the button below. Drag-and-drop is supported in FF, Chrome.</p>
	<p>Progress-bar is supported in FF3.6+, Chrome6+, Safari4+</p>
<?php
/*
	<div class="progress progress-striped active">
	  <div class="bar" style="display:none;"></div>
	</div>
 */
?>
	<div class="well">		
		Drag and Drop files here to upload.
		<div class="qq-upload-extra-drop-area"></div>
	</div>    

	<div id="image-uploader"></div>

    <!-- Assets::add_js(); -->
    <script src="<?php echo base_url('/assets/js/file-uploader.js'); ?>" type="text/javascript"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>        

        function createUploader(){            
            var ajaxuploader = new qq.FileUploader({
                element: document.getElementById('image-uploader'),
                action: "<?php echo site_url();?>ajax_uploader/upload_files",
                debug: true,
                extraDropzones: [qq.getByClass(document, 'qq-upload-extra-drop-area')[0]],

				template:   '<div class="qq-uploader">' +
							'<div class="qq-upload-drop-area"><span>{dragText}</span></div>' +
							'<div class="qq-upload-button btn btn-primary btn-large">{uploadButtonText}</div>' +
							'<ul class="qq-upload-list"></ul>' +
							'</div>',

				// template for one item in file list
				fileTemplate: '<li>' +
						'<span class="qq-progress-bar"></span>' +
						'<span class="qq-upload-spinner"></span>' +
						'<span class="qq-upload-finished"></span>' +
						'<span class="qq-upload-file"></span>' +
						'<span class="qq-upload-size"></span>' +
						'<a class="qq-upload-cancel btn btn-danger" href="#">{cancelButtonText}</a>' +
						'<span class="qq-upload-failed-text alert alert-danger">{failUploadtext}</span>' +
						'</li>',

				classes: {
					// used to get elements from templates
					button: 'qq-upload-button',
					drop: 'qq-upload-drop-area',
					dropActive: 'qq-upload-drop-area-active',
					dropDisabled: 'qq-upload-drop-area-disabled',
					list: 'qq-upload-list',
					progressBar: 'qq-progress-bar',
					file: 'qq-upload-file',
					spinner: 'qq-upload-spinner',
					finished: 'qq-upload-finished',
					size: 'qq-upload-size',
					cancel: 'qq-upload-cancel',

					// added to list item <li> when upload completes
					// used in css to hide progress spinner
					success: 'qq-upload-success',
					fail: 'qq-upload-fail',

					successIcon: null,
					failIcon: null,
				},
				
				showMessage: function(message){
					alert(message);
				},
<?php
/*
				onProgress: function(id, fileName, loaded, total) {
					var progress = Math.round((loaded/total)*100);
					$('.progress .bar').css({
						'width':  progress,
					});
				},				
 */
?>
            });           
        }

        $(document).ready(function() {
        	createUploader();
        });
        
        // Wrap in doc Ready 
        // don't wait for the window to load  
        //window.onload = createUploader;     
    </script>    

</body>
</html>
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Ajax_uploader extends CI_Controller {

	// ------------------------------------------------------------------------
	
	/**
	 * Array of allowed file extensions to upload.
	 * 
	 * @var array
	 */
	protected $_extensions = array('png', 'jpeg', 'jpg', 'gif', 'bmp'); // Acceptable file extensions

	/**
	 * Directory files get uploaded to.
	 * 
	 * @var string
	 */
	protected $_directory = 'media';

	/**
	 * Max Upload Size limit in bytes.
	 * 
	 * @var integer
	 */
	protected $_size_limit = 10485760;

	/**
	 * Place holder for error message.
	 * 
	 * @var string
	 */
	public $error;

	// ------------------------------------------------------------------------
	
	public function index()
	{
		echo 'test';

	}
	public function __construct()
	{
		parent::__construct();
		
		// Everything that happens here gets told in JSON format!
		$this->output->set_content_type('application/json');

		if ($this->input->get_post('sizeLimit'))
		{
			logit('Ajax_uploader - Setting sizeLimit via script to - ' . $this->input->post('sizeLimit'));
			$this->_size_limit = (int) $this->input->post('sizeLimit');
		}

		// Check directory exists, is writable, etc.
		$this->_directory = $this->check_directory();

		$this->_directory = rtrim($this->_directory, '/') . '/';

		// Check the server post/upload size against the size_limit.
		//$this->check_server_settings();

		$this->load->helper('security');
		$this->load->library('security');
		logit('Ajax_uploader class inited');

	}

	// ------------------------------------------------------------------------
	
	/**
	 * The main method, handles uploading files via Valums Ajax File script.
	 * 
	 * @return void
	 */
	public function upload_files()
	{
		$json = array('error' => 'Something really really bad happened, and well I donnu what :(.');

		$file = NULL;		
		if ($this->input->get('qqfile'))
		{
			$file = $this->input->get('qqfile');
		}
		elseif (isset($_FILES) && array_key_exists('qqfile', $_FILES))
		{
			$file = $_FILES['qqfile']['tmp_name'];
		}

		if (isset($file) && $file !== NULL) //$this->security->xss_clean($file)
		{
			$ext = pathinfo($file, PATHINFO_EXTENSION);			
					
			if (in_array($ext, $this->_extensions))
			{
				$directory = $this->_directory;

				$this->load->helper('url');

				$filename = str_replace('.'.$ext, '', $file);
				$filename = strtolower(url_title($filename));
				$filename .= '.' . $ext;

				if ($this->input->get('qqfile'))
				{
					$input		= fopen('php://input', 'r');
					$temp		= tmpfile();
					if ($temp === FALSE)
					{
						$this->error_report('Failed to create upload file.');
					}

					$real_size	= stream_copy_to_stream($input, $temp);
					fclose($input);
/*
					if ($real_size != $this->get_size())
					{
						$this->error_report('File did not completely upload. Try again.');						
 					}
  */       

					$target = fopen($directory . $filename, 'w');
					fseek($temp, 0, SEEK_SET);
					stream_copy_to_stream($temp, $target);
					fclose($target);
				}
				elseif ($_FILES['qqfile'])
				{
					move_uploaded_file($_FILES['qqfile']['tmp_name'], $directory . $filename.'.' .$ext);
				}

				$json = array('success' => 'true', 'filename' => $file);
			}
			else
			{
				$this->error_report('File type not supported.');				
			}
		}
	
		$this->output->set_output(json_encode($json));
	}


	// ------------------------------------------------------------------------
	// PRIVATE METHODS!
	// ------------------------------------------------------------------------

	// ------------------------------------------------------------------------

	/**
	 * Gets File Size by Content Length Server Setting. Isn't Ajax File Uploading Fun!
	 * 
	 * @return int
	 */
 	private function get_size() 
 	{
        if ($this->input->server('CONTENT_LENGTH'))
        {
            return (int)$this->input->server('CONTENT_LENGTH');
        } else {
        	logit('Ajax_Uploader Failed - Getting content length is not supported.', 'error');
            throw new Exception('Getting content length is not supported.');
        }      
    }   

    // ------------------------------------------------------------------------
	
	/**
	 * Handles Error reports, logs them, and sends a json response back to the script.
	 *
	 * @access private
	 * 
	 * @param  string $message Error message to display
	 * 
	 * @return void
	 */
	private function error_report($message = '')
	{
	    $this->error = $message;
	    logit('Ajax_Uploader failed - '.$this->error, 'error');
	    $this->output->set_output(json_encode(array('error', $message)));
	    die;	    
	}

    // ------------------------------------------------------------------------

	/**
	 * Checks Server Max Upload and Post Sizes against the Size limit to verify your not nuts.
	 *
	 * @access private
	 * 
	 * @return void
	 */
    private function check_server_settings()
    {        
        $post_size   = $this->to_bytes(ini_get('post_max_size'));
        $upload_size = $this->to_bytes(ini_get('upload_max_filesize'));        
        
        if ($post_size < $this->_size_limit || $upload_size < $this->_size_limit)
        {
            $size = max(1, $this->_size_limit / 1024 / 1024) . 'M';
            $this->error_report('Increase post_max_size and upload_max_filesize to ' . $size);
            return FALSE;            
        }        
    }

	// ------------------------------------------------------------------------
    
    /**
     * Converts Filesize into Kilobytes.
     *
     * @access private
     * 
     * @param  string $str Filesize to be converted
     * 
     * @return int
     */
    private function to_bytes($str)
    {
        $val  = trim($str);
        $last = strtolower($str[strlen($str)-1]);
        switch($last) 
        {
            case 'g': $val *= 1024;
            case 'm': $val *= 1024;
            case 'k': $val *= 1024;        
        }
        return $val;
    }

	// ------------------------------------------------------------------------

	/**
	 * Checks upload directory to make sure it exists, if not trys to create one or fails with status message.
	 *
	 * @access private
	 * 
	 * @return string
	 */
	private function check_directory()
	{
		$directory = realpath(FCPATH . $this->_directory);

		if ( ! is_dir($directory))
		{
			$status = mkdir($directory, DIR_WRITE_MODE);		
			if ( ! $status)
			{
				$this->error_report('Directory does not exist and could not be created.');
			}
		}

        if ( ! is_writable($directory))
        {
        	$status = chmod($directory, DIR_WRITE_MODE);
        	if ( ! $status)
        	{
				$this->error_report('Server error. Upload directory isn\'t writable.');	
        	}
        }

		return $directory;
	}


}

/* End of file ajax_uploader.php */
/* Location: ./application/controllers/ajax_uploader.php */