Reputation: 1401
My app uses Codeigniter validation successfully in multiple controller for various input fields. But when it comes to uploading and validating an uploaded image the validation complains.
I have the following form: require_once('head.php'); echo '
if($info)
echo '<div class="info">'.$info.'</div>';
$attributes = array('class' => 'updateavatarform', 'id' => 'updateavatarform');
echo form_open_multipart('user/avatar', $attributes);
echo '<div>Select Image</div>';
$data = array(
'name' => 'avatar',
'id' => 'avatar',
'value' => '',
'maxlength' => '',
'size' => '48',
);
echo form_upload($data);
echo '<br/><br/>';
echo form_submit('submit', 'Submit');
echo form_close();
require_once('footer.php');
The controller looks like:
function avatar()
{
$data['user'] = $this->authorize->isLoggedIn();
if(!$data['user'])
$this->authorize->protectUser();
$data['title'] = 'Evcenter User Update Avatar';
$data['keywords'] = 'alternative fuel';
$data['description'] = 'evcenter.org';
$data['info'] = FALSE;
if($_POST)
{
$this->load->model('User_model', '', TRUE);
$this->load->library('form_validation');
$input['avatar'] = trim($this->input->post('avatar', TRUE));
$this->form_validation->set_rules('avatar', 'Avatar', 'trim|required|xss_clean');
if($this->form_validation->run() == FALSE)
{
$this->load->view('avatar', $data);
}
else
{
$avatar = $this->User_model->getAvatar($data['user']['user_id']);
$old_avatar = $this->config->item('avatarpath').$avatar['avatar'];
unset($old_avatar);
$input['avatar'] = $this->uploadAvatar();
$input['id'] = $data['user']['user_id'];
$this->User_model->updateAvatar($input);
$data['info'] = 'Your avatar has been updated';
$this->load->view('avatar', $data);
}
}
else
{
$this->load->view('avatar', $data);
}
}
The validation throws the following error with or w/o an uploaded image "The Avatar field is required." Needless to say $this->uploadAvatar(); works when called from the register controller.
Can anyone see what's wrong? Do FILE uploads need to be validated differently than text input?
Upvotes: 1
Views: 7007
Reputation: 3605
*Assuming you already happen to have a MY_Form_Validation library that extends the built in CodeIgniter stuff.*
I added some functions to validate portions of the $_FILE upload based on this:
http://devbro.com/testing/ci_form_validation/
I just copied the functions, not the entire file. I don't need the custom run or execute methods. Just the validation methods. (I already have a customization that allows me to mix the form_validation config file AND the controller rules together.)
/**
* tests to see if a required file is uploaded
*
* @param mixed $file
*/
function file_required($file)
{
if($file['size']===0)
{
$this->CI->form_validation->set_message('file_required','Uploading a file for %s is required.');
return FALSE;
}
return TRUE;
}
/**
* tests the file extension for valid file types
*
* @param mixed $file
* @param mixed $type
*/
function file_allowed_type($file,$type)
{
//is type of format a,b,c,d? -> convert to array
$exts = explode(',',$type);
//is $type array? run self recursively
if(count($exts)>1)
{
foreach($exts as $v)
{
$rc = $this->file_allowed_type($file,$v);
if($rc===TRUE)
{
return TRUE;
}
}
}
//is type a group type? image, application, word_document, code, zip .... -> load proper array
$ext_groups = array();
$ext_groups['image'] = array('jpg','jpeg','gif','png');
$ext_groups['application'] = array('exe','dll','so','cgi');
$ext_groups['php_code'] = array('php','php4','php5','inc','phtml');
$ext_groups['word_document'] = array('rtf','doc','docx');
$ext_groups['compressed'] = array('zip','gzip','tar','gz');
$ext_groups['pdf'] = array('pdf');
if(array_key_exists($exts[0],$ext_groups))
{
$exts = $ext_groups[$exts[0]];
}
//get file ext
$file_ext = strtolower(strrchr($file['name'],'.'));
$file_ext = substr($file_ext,1);
if(!in_array($file_ext,$exts))
{
$this->CI->form_validation->set_message('file_allowed_type',"%s should be $type.");
return false;
}
else
{
return TRUE;
}
}
etc, etc.
I added the rules I wanted to my form_validation.php config file, but I treat my FILE input as if were included in the $_POST. Of course it isn't, but I will fix that in a moment. DON'T use the other types of validations built into CodeIgniter, only use your FILE validations!
$config = array(
'form/index' => array(
array( 'field'=>'my_upload_file', 'label'=>'File To Upload', 'rules'=>'file_required|file_allowed_type[pdf]'),
...
In my controller, add the $_FILE['my_upload_file'] to the $_POST array
if ( isset($_FILES['my_upload_file']) )
{
$_POST['my_upload_file'] = $_FILES['my_upload_file'];
}
I think the big caveat is if you use the $_POST to populate your models or other actions. My code projects specifically grabs elements out of input->post() and I don't use mass assignment for much of anything. If you do use mass assignment, I would assume you messed up your assumptions.
Upvotes: 2
Reputation: 17977
Correct, files need to be validated differently than text inputs - as they are, not text inputs !
From the docs:
function do_upload()
{
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = '100';
$config['max_width'] = '1024';
$config['max_height'] = '768';
$this->load->library('upload', $config);
if ( ! $this->upload->do_upload())
{
$error = array('error' => $this->upload->display_errors());
$this->load->view('upload_form', $error);
}
else
{
$data = array('upload_data' => $this->upload->data());
$this->load->view('upload_success', $data);
}
}
note the call to $this->upload->do_upload()
and $this->upload->display_errors()
Uploading in CI with text fields can be annoying (imo), I would upload the file first in your controller, then if it is successful do the rest of the POST data and update your database.
That way if there's a problem with the upload later on, you won't have invalid records.
Upvotes: 5