CodeIgniter File Upload: Changing the File Name

There has been some interest lately about how to change the file name of uploaded files with CodeIgniter. I will review how to do this with the base File Upload library as well as extending the library to allow for a defined file name.

Using the Base File Upload Library

The base file upload library has a built-in option to “encrypt” the file name for a freshly uploaded file. According to the documentation, that option is ‘encrypt_name’ and takes a Boolean value. If set to TRUE, the file name is renamed by running it through this set of functions:

$filename = md5(uniqid(mt_rand())).$this->file_ext;

This essentially generates a nice random MD5 hash that will likely not collide with other files in your directory. Most of the time this method for renaming will work just fine, but what if we want to specify the name rather than have it random?

Extending the File Upload Library

This method involves extending the base library which I’ve have done before for other file upload customizations. In this method, the do_upload() function accepts a file name and applies it to the file. Here is the code used to accomplish that outcome:

<?php

function do_upload($field = 'userfile', $new_name='') {

	if ( ! isset($_FILES[$field])) {
		$this->set_error('upload_no_file_selected');
		return FALSE;
	}
	
	if ( ! $this->validate_upload_path()) {
		return FALSE;
	}
	
	if ( ! is_uploaded_file($_FILES[$field]['tmp_name'])) {
		$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
	  
		switch($error) {
			case 1: // UPLOAD_ERR_INI_SIZE
				$this->set_error('upload_file_exceeds_limit');
				break;
			case 2: // UPLOAD_ERR_FORM_SIZE
				$this->set_error('upload_file_exceeds_form_limit');
				break;
			case 3: // UPLOAD_ERR_PARTIAL
				$this->set_error('upload_file_partial');
				break;
			case 4: // UPLOAD_ERR_NO_FILE
				$this->set_error('upload_no_file_selected');
				break;
			case 6: // UPLOAD_ERR_NO_TMP_DIR
				$this->set_error('upload_no_temp_directory');
				break;
			case 7: // UPLOAD_ERR_CANT_WRITE
				$this->set_error('upload_unable_to_write_file');
				break;
			case 8: // UPLOAD_ERR_EXTENSION
				$this->set_error('upload_stopped_by_extension');
				break;
			default :
				$this->set_error('upload_no_file_selected');
				break;
		}
	  
		return FALSE;
	}
	
	$this->file_temp = $_FILES[$field]['tmp_name'];
	$this->file_size = $_FILES[$field]['size'];
	$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $_FILES[$field]['type']);
	$this->file_type = strtolower($this->file_type);
	$this->file_ext  = $this->get_extension($_FILES[$field]['name']);
	
	// check if a name has been specified, if so set it
	if ($new_name != '') {
		$this->file_name = $this->_prep_filename($new_name . $this->file_ext);
	}
	else {
		$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
	}
	
	if ($this->file_size > 0) {
	  $this->file_size = round($this->file_size/1024, 2);
	}
	
	if ( ! $this->is_allowed_filetype()) {
		$this->set_error('upload_invalid_filetype');
		return FALSE;
	}
	
	if ( ! $this->is_allowed_filesize()) {
		$this->set_error('upload_invalid_filesize');
		return FALSE;
	}
	
	if ( ! $this->is_allowed_dimensions()) {
		$this->set_error('upload_invalid_dimensions');
		return FALSE;
	}
	
	$this->file_name = $this->clean_file_name($this->file_name);
	
	if ($this->max_filename > 0) {
		$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
	}
	
	if ($this->remove_spaces == TRUE) {
		$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
	}
	
	$this->orig_name = $this->file_name;
	
	if ($this->overwrite == FALSE) {
		$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
	  
		if ($this->file_name === FALSE)
		{
			return FALSE;
		}
	}
	
	if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name)) {
		if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
		{
			$this->set_error('upload_destination_error');
			return FALSE;
		}
	}
	
	if ($this->xss_clean == TRUE) {
		$this->do_xss_clean();
	}
	
	$this->set_image_properties($this->upload_path.$this->file_name);
	
	return TRUE;

}

Much of this code is taken from the existing File Upload library, but is provided above for the sake of completeness. Comments have been removed to shorten it up a bit, but can be found in the original Upload.php for further understanding. The file name can be set in the controller by calling the do_upload() function as follows:

$this->upload->do_upload('form_field_name', 'new_file_name');

With this extended File Upload library, the following circumstances exist:

  1. The file name provided in do_upload() should not have an extension. The extension from the original file will be applied.
  2. If ‘encrypt_name’ is set in $config, it will take precedence over the specified file name.

Have any other tips for changing the file name for uploaded files in CodeIgniter? Share it in the comments!

UPDATE: As of version 1.7.2, CodeIgniter now has a built-in option to specify the uploaded file name. Placed in the $config array, ‘file_name’ sets the desired end name and should be provided without an extension. The extension will be carried across from the original file.