Uploader Class

Derek Jones edited this page Jul 5, 2012 · 3 revisions
Clone this wiki locally

I have created Uploader class used for uploading XML and Image files, using the CI's upload class methods and using Exceptions for better error handling. In order to get it work, you need to create uploads folder in your root folder where you have installed CI or if you have different name for it, you can change the class to suit your needs. In your application/libraries folder create new file called Uploader.php and in it place this code:


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

//CodeIgniter improved class to upload XML and Image files.
//Based on CodeIgniter's upload class with modifications to use Exceptions for better error handling.
class Uploader
{

    //Instance to keep Uploader object.
    private static $instance;

    //Private properties of the class, change them with the setters methods bellow.
    private $uploadPath = './uploads/';
    private $newName = 'newName';
    private $maxSize = 2000;
    private $maxHeight = 2000;
    private $maxWidth = 2000;
    private $fileType = 'image';

    //No direct instantiating or cloning of the object. We need only one.
    private function __construct(){}

    private function __clone(){}

    //Singleton method to fill up the instance.
    public static function getSingleton()
    {
        if(!self::$instance OR is_null(self::$instance))
        {
            self::$instance = new Uploader();
        }
        return self::$instance;
    }

    //Main method to do the upload. Just pass the name of the input. <input type="file" name="formFile" />
    //Returns the path with the new name.
    public function doUpload($formFile)
    {
        //No file to upload.
        if(!isset($_FILES[$formFile]) OR $_FILES[$formFile]['error'] != 0)
        {
            throw new Exception('There was no file to upload');
        }
        //Check if it's uploaded file.
        if(!is_uploaded_file($_FILES[$formFile]['tmp_name']))
        {
            $this->_errorDelete($formFile);
            throw new Exception('The file is not uploaded one');
        }
        //Get the extension or false.
        $extension = $this->_isCorrectFile($_FILES[$formFile]['type'], $this->fileType, $formFile);
        if(!$extension)
        {
            $this->_errorDelete($formFile);
            throw new Exception('The file you tried to upload is not '.$this->fileType.' file');
        }

        //Check for any upload errors.
        if($_FILES[$formFile]['error'] != 0)
        {
            $this->_errorDelete($formFile);
            throw new Exception('There was an error while trying to upload the file');
        }

        //Check for the maximum size of the file.
        if($_FILES[$formFile]['size'] > $this->maxSize * 1024)
        {
            $this->_errorDelete($formFile);
            throw new Exception('The size of the file is over the limit');
        }

        //If we have image. Check for maximum width and height.
        if($this->_isExtImg($extension))
        {
            $dimension = @getimagesize($_FILES[$formFile]['tmp_name']);
            if($dimension[0] > $this->maxWidth)
            {
                $this->_errorDelete($formFile);
                throw new Exception('The width is bigger than the maximum allowed one');
            }
            if($dimension[1] > $this->maxHeight)
            {
                $this->_errorDelete($formFile);
                throw new Exception('The height is bigger than the maximum allowed one');
            }
        }

        //Clean the name and check if it's empty.
        $_FILES[$formFile]['name'] = $this->_cleanFileName($_FILES[$formFile]['name']);
        if($_FILES[$formFile]['name'] == '')
        {
            $this->_errorDelete($formFile);
            throw new Exception('Baaad file');
        }

        //Try to copy or move the uploaded file. This is from the CI upload class.
        if(!@copy($_FILES[$formFile]['tmp_name'], $this->uploadPath.$this->newName))
        {
            if(!@move_uploaded_file($_FILES[$form_file]['tmp_name'], $this->uploadPath.$this->newName))
            {
                $this->_errorDelete($formFile);
                throw new Exception('The file could not be uploaded');
            }
        }

        //Return the path and the new name with the extension... Change it to whatever you want.
        return $this->uploadPath.$this->newName.'.'.$extension;
    }

    //Public setter methods for more flexibility.
    public function setPath($path)
    {
        $this->uploadPath = $path;
    }

    public function setNewName($name)
    {
        $this->newName = $name;
    }

    public function setMaxSize($size)
    {
        $this->maxSize = $size;
    }

    public function setMaxWidth($width)
    {
        $this->maxWidth = $width;
    }

    public function setMaxHeight($height)
    {
        $this->maxHeight = $height;
    }

    public function setFileType($type)
    {
        $this->fileType = $type;
    }


    //Private methods.

    //Try to delete the file without throwing error.
    private function _errorDelete($formFile)
    {
        @unlink($_FILES[$formFile]['tmp_name']);
    }

    //If you want to add more types, extend this method. And add another method to check for the new type.
    private function _isCorrectFile($file, $type = 'image', $formFile)
    {
        switch($type)
        {
            case 'image':
                return $this->_isImage($file);
            break;

            case 'xml':
                return $this->_isXml($formFile);
            break;
        }
    }

    //Methods to check if the file is xml. Return is xml
    private function _isXml($formFile)
    {
        $extension = end(explode('.', $_FILES[$formFile]['name']));
        if($extension == 'xml')
        {
            return 'xml';
        }
        return false;
    }

    //Possible returns are: png, jpeg, gif or false. Taken from CI.
    private function _isImage($file)
    {
        $pngMimes  = array('image/x-png', 'image/png');
        $jpegMimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
        $gifMimes = array('image/gif');
        if(in_array($file, $pngMimes))
        {
            $file = 'png';
        }
        if(in_array($file, $jpegMimes))
        {
            $file = 'jpeg';
        }
        if(in_array($file, $gifMimes))
        {
            $file = 'gif';
        }
        $imgMimes = array(
            'gif',
            'jpeg',
            'png',
        );
        return (in_array($file, $imgMimes)) ? $file : FALSE;
    }

    //Check if the extension is image one.
    private function _isExtImg($ext)
    {
        $imgs = array('png', 'jpeg', 'gif');
        if(in_array($ext, $imgs))
        {
            return true;
        }
        return false;
    }


    //CI method to clean the file name.
    private function _cleanFileName($filename)
    {
        $bad = array(
                        "<!--",
                        "-->",
                        "'",
                        "<",
                        ">",
                        '"',
                        '&',
                        '$',
                        '=',
                        ';',
                        '?',
                        '/',
                        " ",
                        """,
                        "<",        // <
                        "%3c",     // <
                        ">",         // >
                        "",         // >
                        "(",         // (
                        ")",         // )
                        "%28",     // (
                        "&",         // &
                        "$",         // $
                        "?",         // ?
                        ";",         // ;
                        "="        // =
                    );

        $filename = str_replace($bad, '', $filename);
        return stripslashes($filename);
    }
}

//Instantiate singleton object
$uploader = Uploader::getSingleton();

Then in your application/controllers folder, create new controller home.php with the following code:


&lt;?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Home extends Controller
{
    public function Home()
    {
        parent::Controller();    
    }

    public function index()
    {
        $this->load->view('welcome_message');
    }

    public function upload()
    {
        if(isset($_POST['doUpload']))
        {
            //Cause we are using singleton, no need of $this->load->library('Uploader');
            require_once(APPPATH.'libraries/Uploader.php');

            //Change the type of file you want to upload. 'image' is default.
            //$uploader->setFileType('xml');

            //Set your own name.
            $uploader->setNewName('My Image');

            //Set your own maximum width and height in Pixels;
            $uploader->setMaxWidth(200);
            $uploader->setMaxHeight(200);

            //Set your own upload path
            //Make sure the folder exists and it is in the root.
            //$uploader->setPath('./my_upload_folder/');

            //Try to upload the file and echo the result.
            try
            {
                echo $uploader->doUpload('myFile');
            }
            //If any exception occurs, catch it... and process it.
            catch(Exception $e)
            {
                //here you can do whatever you want according to your error.
                die('The error: '.$e->getMessage());
                /*
                    In the uploader class you can throw exceptions with messages like:
                        throw new Exception('2');

                    Then here check for them:
                        if($e->getMessage() == '2')
                        {
                            do something if the code is 2.
                        }

                    To see all the methods from the Exception class:
                        print_r(get_class_methods(Exception));
                */
            }
        }
    }
}

And in your application/views folder, create the welcome_message.php file.


&lt;?php if(!defined('BASEPATH')) exit('No direct script acess is allowed'); ?&gt;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
&lt;html &gt;
    &lt;head&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
        &lt;title&gt;Upload testing&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;?php echo form_open_multipart('home/upload'); ?&gt;
        &lt;input type="file" name="myFile" /&gt;
        <p>&lt;input type="submit" name="doUpload" value="Upload" /&gt;&lt;/p>
        &lt;?php echo form_close(); ?&gt;
    &lt;/body&gt;
&lt;/html&gt;

Exceptions are very powerful way of handling errors, you can suppress the PHP errors and generate your own and handle them as you wish. Comments, suggestions and questions are always welcome on: zoran.lazarevski1980@gmail.com