Step 13 – Uploading multiple files (images) in CodeIgniter

(created at: December 15, 2014; last update: December 18, 2014)
Among the misunderstandings when comes to CodeIgniter are related to multiple file (image) uploading and image manipulation. So I thought I’d give it a try (with the help of a reader’s request). I can’t stress out enough that this is not just a copy/paste code. So, for all the copy-paster people in the world, please, read before talking.

First draft

Being a testing controller, I will only use an upload field. First of all, let’s create the controller that will load the view with the form. I chose to work with index() method inside the Welcome class:

Welcome.php

PHP

1

2

3

4

5

6

7

8

9

10

11

12

<?phpdefined('BASEPATH')ORexit('No direct script access allowed');

classWelcomeextendsCI_Controller{

publicfunctionindex()

{

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

$data=array();

$data['title']='Multiple file upload';

$this->load->view('upload_form',$data);

}

}

Now, after we’ve done the basic controller, we need to create the form that will help users upload multiple files. As we are going to have a form, it would be a good idea to load the form helper. So, create upload_form.php inside the views folder:

upload_form.php

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<!DOCTYPEhtml>

<html>

<head>

<title><?phpecho$title;?></title>

</head>

<body>

<h1>Uploadmultiplefiles</h1>

<?phpechoform_open_multipart();?>

<p>Upload file(s):</p>

<?phpechoform_upload('uploadedimages[]','','multiple');?>

<br/>

<br/>

<?phpechoform_submit('submit','Upload');?>

<?phpechoform_close();?>

</body>

</html>

Being a form that will have a file input field, it has to have a multipart attribute. As you can see, we’ve added no parameters to form_open_multipart, because we want the form to be processed by the same controller that outputs it.

The most important part about the form is the file input field. To upload multiple files, we need to put as attributes for the input field the “multiple” attribute. Also, when talking about multiple values for a field, is important that the name of the input field to have square brackets at the end “fieldname[]“.

Now let’s return to our controller and see what will happen if we load two images (I will advise you to have two or more images for testing). For this, we will change it to first verify if there was a form submission. If there was a form submission we will output the uploaded files’ properties to see if the upload took place. Else, we will output the form:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

publicfunctionindex()

{

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

$data=array();

$data['title']='Multiple file upload';

if($this->input->post())

{

echo'<pre>';

print_r($_FILES);

echo'</pre>';

}

else

{

$this->load->view('upload_form',$data);

}

}

Now, to test it, let’s visit http://localhost (or whatever controller and method you chose), and upload two or more files in the form. If you submit the form you will be able to see how the $_FILES work. Take a good look at the array that is passed as $_FILES:

Of course the values may differ, but the principle is the same in all situations involving $_FILES.

Now, before processing the files, let’s see what we want to do. We will first upload the original files in upload directory, and then we will work with them. So, let’s create a directory named upload in the public area of the server (where we also keep the css and javascripts). If you have XAMPP, that will be in YOUR_XAMPP_DIRECTORY/htdocs/upload. Make sure that upload directory is writable.

After that, we get back to our controller and make a few changes. First of all, we have to do a small hack so that we can use the upload library with more than one file:

Welcome.php

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

publicfunctionindex()

{

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

$data=array();

$data['title']='Multiple file upload';

if($this->input->post())

{

// retrieve the number of images uploaded;

$number_of_files=sizeof($_FILES['uploadedimages']['tmp_name']);

// considering that do_upload() accepts single files, we will have to do a small hack so that we can upload multiple files. For this we will have to keep the data of uploaded files in a variable, and redo the $_FILE.

// now, taking into account that there can be more than one file, for each file we will have to do the upload

// we first load the upload library

$this->load->library('upload');

// next we pass the upload path for the images

$config['upload_path']=FCPATH.'upload/';

// also, we make sure we allow only certain type of images

$config['allowed_types']='gif|jpg|png';

for($i=0;$i<$number_of_files;$i++){

$_FILES['uploadedimage']['name']=$files['name'][$i];

$_FILES['uploadedimage']['type']=$files['type'][$i];

$_FILES['uploadedimage']['tmp_name']=$files['tmp_name'][$i];

$_FILES['uploadedimage']['error']=$files['error'][$i];

$_FILES['uploadedimage']['size']=$files['size'][$i];

//now we initialize the upload library

$this->upload->initialize($config);

// we retrieve the number of files that were uploaded

if($this->upload->do_upload('uploadedimage'))

{

$data['uploads'][$i]=$this->upload->data();

}

else

{

$data['upload_errors'][$i]=$this->upload->display_errors();

}

}

}

else

{

print_r($errors);

}

echo'<pre>';

print_r($data);

echo'</pre>';

}

else

{

$this->load->view('upload_form',$data);

}

}

If now we’re testing the upload form with image files and/or other type of files, we will either receive an array with the uploaded images’ data or an array with errors.

Cleaning up the code

Now that looks nice, but it doesn’t look too clean. What if the form will have more than just upload field? It will all look too messy. So let’s try in put all the upload inside a validation callback and make a method that will be the callback. Also, considering that the callback will also return the upload data, we should make sure that we will use a variable that is available across the entire controller and not just in the callback function. So just before we start the methods, we should define an _uploaded variable: private $_uploaded = array();

That means that the class would look like this now:

Welcome.php

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

<?phpdefined('BASEPATH')ORexit('No direct script access allowed');

classWelcomeextendsCI_Controller{

private$_uploaded;

publicfunctionindex()

{

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

$data['title']='Multiple file upload';

// let's consider that the form would come with more fields than just the files to be uploaded. If this is the case, we would need to do some sort of validation. If we are talking about images, the only method of validation for us would be to put the upload process inside a validation callback;

// from here on you can do whatever you wish with the uploaded data or the other form fields that you might have. I decided to exit here, since this is not the object of our tutorial.

exit;

}

}

$this->load->view('upload_form',$data);

}

// now the callback validation that deals with the upload of files

publicfunctionfileupload_check()

{

// we retrieve the number of files that were uploaded

$number_of_files=sizeof($_FILES['uploadedimages']['tmp_name']);

// considering that do_upload() accepts single files, we will have to do a small hack so that we can upload multiple files. For this we will have to keep the data of uploaded files in a variable, and redo the $_FILE.

I sure hope I didn’t loose you there… I only moved the uploading part inside a callback function for cleaner and easier to understand code.

Now, we just have to make sure that we echo the errors that come from the callback function. For this, we return to the upload_form view and do an echo of the eventual errors:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<!DOCTYPEhtml>

<html>

<head>

<title><?phpecho$title;?></title>

</head>

<body>

<h1>Uploadmultiplefiles</h1>

<?phpechoform_open_multipart();?>

<p>Upload file(s):</p>

<?phpechoform_error('uploadedimages[]');?>

<?phpechoform_upload('uploadedimages[]','','multiple');?>

<br/>

<br/>

<?phpechoform_submit('submit','Upload');?>

<?phpechoform_close();?>

</body>

</html>

Now, if we are trying to upload a file that is not an image (or doesn’t respect your conditions set in the configuration of the upload libary), we should get an error and be returned to the form. Instead, if we upload images, we should be greeted with the upload data.

With these in hand, you can work with the image library. But this will be the subject of another tutorial. (I sure hope you don’t mind about this Rodge, but this is a big subject so I have to split it in two…)

Thank you very much for this wonderful tutorial. I really appreciate your effort.
Again, you gave me additional knowledge that I can use to my project and future projects.
I am going to start another adventure using this tutorial and I hope you create more tutorials that may help other beginner like me.
I wish you more power and lucks.
Thank you very much!

Nice tutorial regarding multiple file uploads. but, could you also please cover, how to customize file upload error message(s). i have posted a question about it under http://forum.codeigniter.com/thread-61531.html codeigniter forum.

I have just one question, is it possible in codeigniter to have more than one browse for image button in a single form to save all in one table in a database.I have two text fields and I want different images for each one. I want to save one or more than one images with 1st text box and one or more than one images with the second text box in single form.

When i want to retrieve these images and text fields all should be load with a page slug.

Hello, how can I rename picture with callback processing before getting my lastinsert(id)
I’d like to rename with the lastinsert(id) and a number like this 234-1.jpeg,234-2.jpeg,234-3.jpeg for exemple with 3 pictures.
Thanks

Well… you can’t create a file name without having the name you need. As you can see, I’ve uploaded the files in a validation callback (as the simple upload of the files being the validation itself). I guess that you want the images to be loaded with a post or something, and you want to name the images using the post ID. But you can only retrieve a last insert id after the post was submitted and validated, validation being already done with the upload of the image files. Even if you won’t be able to name the images inside the callback validation method, you can at any time work with the data provided by the method by using the $this->_uploaded array, which tells you everything about what was uploaded, including the name of the files and their location. Let’s suppose you’ve retrieved the last insert id when you inserted the post into the table (we will store it in a variable called $lastinsertid). If you have a name and a location of the image files, you simply rename them by iterating through the array:
foreach($this->_uploaded as $key => $file)
{
rename($file['full_path'], $file['file_path'].$lastinsertid.'-'.$key);
}

Excellent tutorials. I have one question though. I downloaded your Github repository. I just wanted to know if you could either explain how to do this in a tutorial, or email me to share your ideas about it.

I want to make a relation to the permissions from groups to menu & page items, so when I add a new menu item or a new page, or for when I am editing an existing one, that the permissions can be set to which groups can view that content, perhaps via a check-box, or a drop-down menu. If a user does not have the appropriate permissions to view the content/menu item, then they are redirected to the Index method of the main frontend controller when they try to access it.

Also, how easy would it be to link a menu item to an existing page using the pages slug? If I can figure out how to link to permissions to menu items/pages. And link a menu item to a page instead of a parent item or a slug, I would be most appreciative for your help. Your tutorials are amazing my friend, they truly are.