Multiple Image Uploads Into Single MySQL Table (CakePHP)

The impossible has been done - uploading multiple images in CakePHP. Find out how easy it is, and why it was never really impossible to begin with.

There have been updates to this article. Please make sure you note any changes before commenting.

This article assumes you use the CakePHP image upload component I covered a while back. If you’re not using it, you should be.

The goal of this article is to explain how to upload multiple photos in CakePHP using a single MySQL table. The images will be uploaded into an uploads folder, while the image names will be stored in a single MySQL table.

Pretext

I’ll assume your upload form is placed in /app/views/images/upload.thtml and your images component sits at /app/controllers/images_controller.php. If you need an example of either file, download the complete package and follow along.

Configure Your View

In order to upload a single image via CakePHP, our view upload.thtml would consist of a single upload field:

<ul>
    <li>
        <?php echo $form->labelTag('Image/images', 'Image:' );?>
        <?php echo $html->file('Image/filedata');?>
    </li>
</ul>

But we want the ability to upload multiple images at once, so let’s adjust our view accordingly:

<ul>
    <li>
        <?php echo $form->labelTag('Image/images', 'Image 1:' );?>
        <?php echo $html->file('Image/filedata1');?>
    </li>
    <li>
        <?php echo $form->labelTag('Image/images', 'Image 2:' );?>
        <?php echo $html->file('Image/filedata2');?>
    </li>
    <li>
        <?php echo $form->labelTag('Image/images', 'Image 3:' );?>
        <?php echo $html->file('Image/filedata3');?>
    </li>
</ul>

All we’ve done is added more upload fields to our form. Of course we also named them accordingly: filedata followed by a number.

Dressing Up The Controller

Next we need to modify our controller (/app/controllers/images_controller.php) to handle the multiple files.

The tricky part comes when we need to store each file name in a single MySQL table called images. We’ll do this by creating an array of each file name, implode the array, then store the resulting string in MySQL. Sounds confusing, but it’s not. Read on.

// set the upload destination folder
$destination = realpath('../../app/webroot/img/uploads/') . '/';

// number of file form fields
$num = 3;

/* take care of image uploads */

$array = "";
// loop through each image field
for ($i=1; $i<=$num; $i++)
   {
	$file = $this->data['Image']['filedata'.$i];
	if (!$file['name']) continue;

	// upload image
	$result = $this->Upload->upload($file, $destination, null, array('type' => 'resizecrop', 'size' => array('100', '100'), 'output' => 'jpg'));

	// error check
	if($result || !empty($this->Upload->errors)) {

		// there's been an error, delete any uploaded images
		if(is_array($array) && count($array) >= 1) {
			foreach($array as $file) { // delete each file
				unlink($destination.$file);
			}
		}

           // display error
		$errors = $this->Upload->errors;

		// piece together errors
		if(is_array($errors)){ $errors = implode("<br />",$errors); }

		$this->Session->setFlash($errors);
		$this->redirect('/images/upload');
		exit();
	}

	// add the image filename to the $array
	if(!is_array($array)){
		$array = array();
		array_push($array, $this->Upload->result);
	} else {
		array_push($array, $this->Upload->result);
	}

}

The for loop above makes sure each form field is properly addressed. The script attempts to upload the data and displays a proper error message if it fails.

The above images_controller.php example is only partially complete. For a complete example, download the complete package below.

Download The Package

You can download a working CakePHP example of the files described in this article. The MySQL file needed to create the example images table is included.
Download the complete ‘Multiple Image Uploads (CakePHP)’ package here.

Let me know if I’ve missed anything, or if you need help.

Updates

Nov 8th, 2007: The uploads component (upload.php) has been fixed to correctly handle filetypes.

13 Comments so far

  1. [...] Next we’ll slap the necessary code in place to handle a single image upload. (To upload multiple images at once, check out this article.) [...]

  2. [...] Multiple Image Uploads Into Single MySQL Table (CakePHP) [...]

  3. Moelle on November 8th, 2007

    Thanks again for providing help with multiple uploads. I do have one “problem”. If I use the new upload component (upload.php) that you provide in the complete ‘Multiple Images Uploads Package’ you posted here, I can’t upload any images. I keep receiving the ‘File type not allowed.’ message, although they are .jpg and those types are allowed. But when I use the old upload component from a while back it works excellent. Did I do something wrong or is there something wrong with the new upload component(upload.php) you made?

  4. Koa on November 8th, 2007

    Moelle, the filetype error was my mistake. All fixed!

  5. Moelle on November 10th, 2007

    So the multiple upload works GREAT but it would be better for me if each image had it’s own record in MySQL instead of one recorde with multiple images. I tried it myself to modify the controller but i couldn’t get it to work. Can you help me with that?

  6. releod on November 20th, 2007

    I totally agree with the comment above, would love to see this adding its own record for each file upload, instead of imploding them all into the same record.

    Great work though.

  7. [...] files via CakePHP has been covered a few times on Labs. Based on the feedback, it’s safe to assume bridging the gap between file [...]

  8. Livetoday on February 16th, 2008

    Releod, that worked for me ;O)

    
    foreach($array as $arr):
       $this->Image->query("INSERT INTO images(id,imgSrc) VALUES(NULL,"'.$arr.'")");
    endforeach;
    
  9. Eric on February 29th, 2008

    Hi,

    First off, thanks for posting these components. I removed a bunch of the code so I could use them for general file uploads rather then just images.

    I ran into a few things on the way I thought I should share.
    The upload() function does not always return true or false depending on if the upload succeeds. This is important because in the code the $result is relied on in the image controller. I moved some things around, but at the bottom of the function I added this line which should take care of the issue:

    
    // if no errors, then return true
    return $this->error === false ? true : false ;
    

    Also in the upload function, you go through the effort of adding an ending slash to the $directory variable being passed in, and assign it to $this->_destination. However, a few lines later when you need to use the slash appended directory, you use the $directory variable again rather then the freshly appended $this->_destination

    
    $fileName = ($name == NULL) ? $this->uniquename($this->_destination......
    

    The last thing I found, this may not be a big issue for some people, but in the uniquename function, and in the upload function, you hard code the “/” to separate directories. This is not a problem if you are on *nix, but windows has a problem with this. To get around this problem, just replace the slash with PHP constant DIRECTORY_SEPARATOR.

    Thanks again for the work!

  10. venkat on March 17th, 2008

    very nice

  11. mus on April 17th, 2008

    If you want multiple sql records for each images try this:

    Remove the implode array line and then do a foreach,

    very important to set the id to null or in each loop it will overwrite the date from the previous one and only add the last one.

    
    if (!empty($array)){
    	//save the data
    
    	foreach ($array as $value) {
    		$this->Image->id = null;
    		$this->data['Image']['images'] = $value;
    		$this->Image->save($this->data);
    	}	
    
    } else {
    	$this->Session->setFlash('No images have been uploaded!');
    	$this->redirect('/images/index');
    	exit();
    }
    
    $this->redirect('/images/index');
    
  12. Suganya on May 5th, 2008

    When i download and execute this code im getting this error….

    Class ‘AppController’ not found in C:\wamp\www\multipleimage\multiple-uploads-11062007\app\controllers\images_controller.php on line 2

    Send me a reply and send this function

  13. Boris on July 14th, 2008

    Your code kind of sucks, why use a fixed amount of file-uploads in combination with a manual numbering?

    You could more easier use a array for storing multiple file-uploads. So instead of using $html->file (or $form->file in cake 1.2), create a custom element:

    
    < ?php for($x=0;$x
    

    In the controller you can use:

    
    data[image] as $image) {
       $this->Image->create();
       $this->Image->save($image);
    }
    ?>
    

    Consider the controller code pseudo, since the array does not yet have the required structure for a valid insert into our Image table. Also there is no file handling implemented yet.

Leave a Reply