CakePHP Image Uploading with Database

Uploading images using CakePHP doesn't have to be difficult. Here is a simple way.

Now updated for CakePHP 2!

I have a friend learning to develop websites using CakePHP and he asked if there were any tutorials out there for uploading images and storing them in a database, as everything he found was quite difficult to follow.

So I figured I'd write my own to help him out and hopefully some others :)

In this example, we are going to add a picture for each user - resizing the image dynamically is a little bit beyond this post but might be something I look at doing another blog post on.

The View

First, lets assume you already have a form for adding users, which would be in /app/View/Users/create.ctp and look something like the following:

<?php echo $this->Form->create('User', array('url' => array('action' => 'create'))); ?>

        ... form fields here ...
<?php echo $this->Form->end('Save'); ?>

In order to upload files, we need to add an enctype to the form. Your create line should look like this:

<?php echo $this->Form->create('User', array('url' => array('action' => 'create'), 'enctype' => 'multipart/form-data')); ?>

For our next trick, we need an input for it. As we will be storing the filename in the database and uploading the file to a folder on the server, we run into issues if we use the database field name for the input.

For example, if our field name in the users database table is "image" and we use:

<?php echo $this->Form->input('image', array('type' => 'file')); ?>

What actually gets sent through to the controller is an array which it then tries to insert into the database field - not going to work...

So we call it something else. I prefer to use upload, so the input would look like this:

<?php echo $this->Form->input('upload', array('type' => 'file')); ?>

The Controller

Now then, that's all we need in the view, so let's move on to the controller. Open /app/Controller/UsersController.php

Your function will already look similar to the following:

function create()
{
        if(!empty($this->request->data))
        {
                if($this->User->save($this->request->data)) {...} else {...}
        }
}

Uploading our image involves the following steps:

  1. Check if an image has been submitted.
  2. Check the file extension is valid
  3. Upload the file
  4. Prepare the filename to be saved into the database

The updated function looks like this:

function create()
{
        if(!empty($this->request->data))
        {
                //Check if image has been uploaded
                if(!empty($this->request->data['User']['upload']['name']))
                {
                        $file = $this->request->data['User']['upload']; //put the data into a var for easy use

                        $ext = substr(strtolower(strrchr($file['name'], '.')), 1); //get the extension
                        $arr_ext = array('jpg', 'jpeg', 'gif'); //set allowed extensions

//only process if the extension is valid
                        if(in_array($ext, $arr_ext))
                        {
                                //do the actual uploading of the file. First arg is the tmp name, second arg is
                                //where we are putting it
                                move_uploaded_file($file['tmp_name'], WWW_ROOT . 'img/uploads/users/' . $file['name']);

                                //prepare the filename for database entry
                                $this->data['User']['image'] = $file['name'];
                        }
                }

//now do the save
                if($this->User->save($this->data)) {...} else {...}
        }
}

The Grand Finale...

And that's it! Obviously resizing gets a bit trickier but happens before you prepare the filename for database entry. When you want to display the image, simply use:

<?php echo $this->Html->image('uploads/users/' . $data['User']['image']); ?>

This of course assumes you have fetched the record and passed it through to the view in a variable called $data.

Have fun with your image uploading and if you do something differently, let me know what works for you!