Search code examples
kohana-3

Kohana 3 - file size validation


I am using code below for file validation. Strange thing is that if I am trying to upload file which is above size limit I get not empty error instead of error related to size limit. Can anyone explain where is the problem ?

$validate = Validate::factory($_FILES);
             $validate->rules('image',
                     array(
                     'Upload::valid' => array(),
                     'Upload::not_empty' => array(), 
                     'Upload::type' =>array('Upload::type' => array('jpg','png','gif')), 
                     'Upload::size' => array('1M'))
                     );


             if ($validate->check())
            {           
             //ok
             $directory = DOCROOT.'uploads/';
             $filepath = Upload::save($_FILES['image'], '123zxhahaxdfdgsdfsdha.jpg', $directory);   
             Request::instance()->redirect($redirect);                  
            }
             else
             {
             //error    
                 $this->errors = $validate->errors('errors');
                 $errors = $this->errors;
             //echo $errors;
             }

Solution

  • You can fix this by changing the order of the elements in your validation array, i.e. change

    $validate->rules(
        'image',
        array(
            'Upload::valid' => array(),
            'Upload::not_empty' => array(), 
            'Upload::type' =>array('Upload::type' => array('jpg','png','gif')), 
            'Upload::size' => array('1M'),
        )
    );
    

    to

    $validate->rules(
        'image',
        array(
            'Upload::valid' => array(),
            'Upload::size' => array('1M'),
            'Upload::not_empty' => array(), 
            'Upload::type' =>array('Upload::type' => array('jpg','png','gif')), 
        )
    );
    

    "Wut‽", you may well have thought. Well, the way validation rules are processed in Kohana, the checker stops checking for more rules. If you want to see this for yourself, look for these lines in system/classes/kohana/validate.php:

        //This field has an error, stop executing rules.
        break;
    

    You'll find them in Kohana 3.0, which you appear to be using, but also in the current 3.3.

    And you were, presumably, testing your application by uploading a file with size large enough to be blocked by PHP or even by your web server. The most likely culprit is PHP's upload_max_filesize value, which in default PHP installations is only 2M, cf. this page from the PHP manual. This would mean that the file upload IS empty (as in, there is no file) because of being blocked by PHP for being too big.

    That would explain why your code was giving the behaviour you reported. But Kohana's Upload::size function is (of course!) clever enough to detect that the file size is too big -- you'll find these lines in system/classes/kohana/upload.php:

        if ($file['error'] === UPLOAD_ERR_INI_SIZE)
        {
            // Upload is larger than PHP allowed size
            return FALSE;
        }
    

    So if it checks that first, it will fail on that rule, which is why my re-shuffling of your code should get rid of the unwanted behaviour you reported.

    Two other, tangential, remarks:

    Firstly, in system/classes/kohana/upload.php you will notice this comment:

    If you _do_ require a file to be uploaded, add
    the [Upload::not_empty] rule before this rule.
    

    But I've not taken that before into account when re-ordering your validation rules because TBH I think it's misleading/incorrect: surely you want to check that the upload is valid, i.e. that all the array fields are set, before doing tests on the values of those fields.

    Secondly, note that Upload::not_empty does not check that the file size is greater than zero; to make it do that you could create application/classes/upload.php with the following content:

    class Upload extends Kohana_Upload {
    
        public static function not_empty(array $file)
        {
            return (parent::not_empty($file)
                AND $file['size']);
        }
    
    }