Introduction to CakePHP features (build an app in less than 15 minutes)

I would like to showcase the awesome power of CakePHP by providing an introductory tutorial, which is going to cover some basics as well as slightly more advanced features such as the Auth (user authorization) component.

The goal of this tutorial is to setup a working application, which is going to have: user registration, login/logout functionality, user homepage, basic access control, data (form) validation and a flexible base to expand upon. Oh yeah, we’ll get all that done in just under 15 minutes and with only about 120 lines of code…

I assume that at this point you’ve got CakePHP installed and working. It would also be helpful to know the basic concepts and possibly have tried the blog tutorial.

The steps I take to build the app may not be very intuitive for a beginner, but I do provide explanations of each feature/step and hopefully at the end you’ll see how everything comes together.

Let’s begin…

We need a users table in our database to hold the User data, here’s a sample for MySQL:

[sourcecode language=”sql”]
`id` int(11) NOT NULL auto_increment,
`name` varchar(200) NOT NULL,
`email` varchar(200) NOT NULL,
`username` varchar(200) NOT NULL,
`password` varchar(200) NOT NULL,
`status` tinyint(1) NOT NULL default ‘1’,
`company_id` int(11) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,

Next, we’ll create a system-wide controller, otherwise known as App Controller. Think of it as a global controller, whose properties and methods are accessible to all other controllers of the application.

Go into your main app directory (something like /home/teknoid/cake/app) and create a file named app_controller.php there.

This is what it should look like:

class AppController extends Controller {
    var $components = array('Auth');

    function beforeFilter() {
        $this->Auth->loginRedirect = array('controller'=>'users', 'action'=>'index');

Let’s take a look at what we did here…
We know that our app is going to need user authentication, therefore we include CakePHP’s built-in component with var $components = array(‘Auth’);
We then create a special function beforeFilter(), which is going to be executed before all other actions in our application, so this is a pretty good time to tell the Auth component about some things (settings) that it should be aware of.
For example, we allow a special action called ‘display’ $this->Auth->allow(‘display’) and we also tell the Auth component that, by default, upon login a user should be redirected to the ‘index’ action (or their homepage) $this->Auth->loginRedirect = array(‘controller’=>’users’, ‘action’=>’index’);.
I do not want to go into much detail about the specifics of this setup, but overall this is a pretty basic and generic way to set-up the authentication in a CakePHP application.

Next, we are going to build our Users Controller.
Go into app/controllers and create a file named users_controller.php

This is what it should look like:

class UsersController extends AppController {

        var $name = 'Users';
        var $helpers = array('Time');

        function beforeFilter() {

           if($this->action == 'add') {
               $this->Auth->authenticate = $this->User;


        function index() {
            $this->set('user', $this->User->find('first',

        function add() {
            if(!empty($this->data)) {

        function login() {


        function logout() {


Here’s what we did…
We’ve included the built-in Time Helper var $helpers = array(‘Time’);, which basically helps to format (into something human readable) the date and time fields from the database… amongst other things. Later we’ll use it to format the date/time information on our user’s homepage.

You’ve noticed that we have another beforeFilter() function as we did in the App Controller. In this example we inherit our parent (App Controller) functionality by using parent::beforeFilter() and then we specify some additional settings for Auth that will be specific to the Users Controller.

Before we procede, I’d like to point out that Auth component will automatically hash your passwords with sha1() + a security salt you’ve setup during configuration/installation of CakePHP. Be sure to make the password column in your DB long enough to account for the hashed value (plain text passwords will not be stored).

This line $this->Auth->authenticate = $this->User; might be a little unusual…
The quick explanation, as to why I did that, is because Auth component allows us to override the way it handles some things, which offers great flexibility. Personally, I had a little beef with the way Auth handles password hashing, but as you can see it only bothered me during the ‘add’ action if($this->action == ‘add’), in which case I provided my own authentication object (the User model). This is going to become a lot more clear later on (just keep it in mind for now).

To keep things secure from the get-go, we have to be very explicit about what actions we allow the user to access without having to login first. By default Auth is going to redirect the user to the login form regardless of what page one tries to access. Of course it would be really sad for the user, if we didn’t tell Auth that ‘add’ action can be accessed without login $this->Auth->allow(‘add’);.
It is important to point out that Auth will assume that ‘login’ and ‘logout’ are always accessible and you shouldn’t specify those in the list of allowed actions.

Alright, our basic setup is complete and now we’ve added some actions into our Users Controller.

index() This is going to be our user’s homepage. Remember how we told Auth that upon login the user should be redirected $this->Auth->loginRedirect = array(‘controller’=>’users’, ‘action’=>’index’);? Well, now we’ve actually got that part taken care of. The action is really simple, it finds all the information about our logged in user and sets it ready for the view.

add() No mystery here, this is our user registration action and it should be quite obvious as to what it does.

login() It is this easy to get the basic login functionality working… i.e. you don’t even need to write any code. Auth is smart enough to do the work for you. Of course you can easily change the way Auth does things by extending this action beyond the basics.

logout() Once the user clicks a “Log out” link he/she will be redirected to the default location, which happens to be back to the login form. Good enough for this example.

Now that we’ve got some of our actions finished up, let’s create the views for each one (a view is the actual page that the user is going to see in the browser).

Go to app/views/ and create a directory named ‘users’. Then in that directory add a view file for each of the actions (except logout, since it doesn’t need one).

index.ctp – our homepage

<?php echo $html->link('Log out', array('controller'=>'users', 'action'=>'logout')); ?>

    Hello, <?php echo $user['User']['name']; ?>

    Your account was created <?php echo $time->niceShort($user['User']['created']); ?>

This is a very simple view page, but it does show how you can access the various user information in the view. If you look back to our index() action in the Users Controller, you’ll see that we set a $user variable, which contains an array of user data and now we can echo it in the view.
Remember that Time Helper we’ve included earlier in our Users Controller? Well, here we’re using it to transform our database DATETIME field’s value, into a nice, human readable output by using: echo $time->niceShort($user[‘User’][‘created’]);

login.ctp – our login page

if  ($session->check('Message.auth')) $session->flash('auth');

    echo $form->create('User', array('action' => 'login'));
    echo $form->input('username');
    echo $form->input('password');
    echo $form->end('Login');

Even though we don’t need any code for the login() action we still need to setup a basic form to display to the user. Nothing fascinating here, just note that first line if ($session->check(‘Message.auth’)) $session->flash(‘auth’);, which allows us to display any messages triggered by the Auth component.

add.ctp – our registration page

    echo $form->create();
    echo $form->input('name');
    echo $form->input('email');
    echo $form->input('username');
    echo $form->input('password');
    echo $form->input('password_confirm', array('type'=>'password'));
    echo $form->end('Register');

Here we have setup a basic form for the registration. Again there is really nothing fancy here… just a basic form, which will be brilliantly built by the Form Helper.

If you haven’t tried already, go ahead now:

Try to access http://yourlocalhost/users/shouldntAccessThis
– Auth component should redirect you to the login form, since we’ve never specified that ‘shouldntAccessThis’ is allowed.

Try to access http://yourlocalhost/users/add
– You should see a registration form

So far so good, but we’ve got to setup some validation rules for our registration form…
For this we create our User Model.

In app/models/ create the file user.php

This is what it should look like:

class User extends AppModel {

        var $name = 'User';

        var $validate = array(
                          'rule'=>array('minLength', 4),
                          'message'=>'Name has to be at least four characters'),

                          'message'=>'Please enter a valid email'),

                              'Username has to be at least four characters'=>array(
                                  'rule'=>array('minLength', 4)
                              'This username is already taken, please try another'=>array(

                              'Password cannot be empty'=>array(
                              'Password must be at least four characters'=>array(
                                   'rule'=>array('minLength', 4)
                              'Passwords must match'=>array(
                                   'rule'=>array('passwordCompare', 'password_confirm')

        function passwordCompare($data, $fieldTwo) {

            if($data['password'] != $this->data[$this->alias][$fieldTwo]) {
                 $this->invalidate($fieldTwo, 'Passwords must match');
                 return false;

            return true;

        function hashPasswords($data, $enforce=false) {

           if($enforce && isset($this->data[$this->alias]['password'])) {
              if(!empty($this->data[$this->alias]['password'])) {
                  $this->data[$this->alias]['password'] = Security::hash($this->data[$this->alias]['password'], null, true);

           return $data;

        function beforeSave() {
            $this->hashPasswords(null, true);

            return true;

So this is the big guy. The User Model handles our validation logic and also overrides some of the default Auth component functionality. Remember how I said that we’ll use the User model to override default Auth behavior $this->Auth->authenticate = $this->User; during the ‘add’ action? Well here I have built my own hashPasswords() method, which overrides the Auth component’s default one. Without going into a long winded explanation I’ll just say that I prefer to hash the passwords just before saving the data (hence the little beforeSave() method) because it makes my life easier, and it also shows how easily Auth can be extended to behave the way you want it to.

Let’s take a look at passwordCompare(). This is my custom validation method to compare ‘password’ and ‘password_confirm’ fields (look back to our add.ctp view).
$this->invalidate($fieldTwo, ‘Passwords must match’); will cause the ‘password_confirm’ field to be marked as invalid in addition to the ‘password’ field. This is nice if you’ve got some CSS that, perhaps, puts a red border on the input box for the invalid field (notice that we’ve also set the error message).
Another trick (I’m not quite sure honestly if it’s a documented feature) is to use really nice, human readable names for a given rule. This is in case you use multiple rules per field as we do for our ‘password’ field. This way, in case of an error, the arbitrary rule name will be used for the error message.

Go ahead, try it out with some invalid and then valid data… If all goes well, you should see an SQL debug showing the inserted user data, which confirms that your form is working correctly.

And there you have it… A complete, functional app in about 10-12 minutes.

P.S. I have posted a follow-up to this tutorial, which covers some of the Auth features used here in more detail.

  • Pingback: Signets remarquables du 03/10/2008 au 07/10/2008 | Cherry on the...()

  • keymaster

    Hi Teknoid,

    Firstly, thanks for your contributions to the cake world. Your blog is one of the most informative around.

    A small point regarding setting people’s expectations… I felt this is relevant as this post will be viewed by those beginning with cakePHP.

    There is alot of “you can build a blog in under 12 minutes” kinda stuff thrown around in the cakePHP world.

    I don’t claim to be anything near a cake guru, but having worked with cake for a year or so, and having used cake for a fair sized project or two, I still don’t feel I could create this (even your) app in 15 minutes from the get go.

    Once I’ve completed all the pre-planning, referencing API’s/manual for parameters, creating the data model, tables, structuring out the app, validation rules, views, etc. one might say the remaining “typing time” is under 12 minutes.

    But, even then, you pretty much have to know exactly what you will be typing before you hit the first key, to make the 12 minutes.

    Developing an app is more than just typing, though.

    So, while it is true cake makes things so much faster to develop, requires so much less code, gives you best practices and a tremendous (the best)community, etc., etc., … I think we may be hyping things up a bit too much when we say things like developers can “create complete functional apps in 12 minutes”, from the get-go.

    I rather think the “under 120 lines of code” is the better benchmark we should be promoting.

  • teknoid


    Thank you for your response. Your points are valid, I think that anyone just starting with cake will not be able to sit down and cook an app in 15 minutes. Yes, it took me a while to be able to prepare a fresh app so quickly, but ultimately it is not impossible.
    I agree that “build an app in 15 minutes” is more of a hype than a real-world scenario, but you gotta add some flavor to make it catchy… I don’t think much harm is done there. One can clearly see that it does only take about 120 lines of code (with a lot of it just spacing and rules definitions plus views :)) so the potential for extremely fast development is certainly and clearly there.

  • this may be wrong, you can delete it if necessary:
    it seems that line 48 of the UserModel should be

    $this->data[$this->alias][‘password’] = Security::hash($this->data[$this->alias][‘password_confirm’], null, true);

    right? it should check against the password_confirm field? just askin’.

  • teknoid

    @dave rupert

    That line is in the hashing function, so it basically hashes the plain-text password into the sha1() + security salt hash before saving it (this particular methods overrides the one in Auth component).

  • I like your trick of using the key for the error message, its a nice shortcut. Its expected behavior, I just never thought of using it to avoid the need for the message key.

  • teknoid

    @Mark Story

    Thanks for your comment and confirmation of the expected behavior. I discovered it pretty much by accident, as I forgot to set the ‘message’ key the rule name was displayed instead, so I figured… why not? :)

  • Joel Perras

    To reduce the amount of typing required to display form elements, you could use the $form->inputs() mega-automagic method in login.ctp and add.ctp.

    While very restricted in usefulness, it’s some automagic goodness for starting a project that often gets overlooked.

  • teknoid

    @Joel Perras

    Good point on the inputs() method, I’ll probably modify the examples to use it later on. Thanks.

  • I think a great followup to this may be a short discussion of what the following line of code does (and other Auth methods):

    It took me multiple weeks of hanging out in the IRC channel for someone to tell me the reason my homepage was not accessible from any account that was not given (full, site-wide) Administrative privileges, and I couldn’t figure out why. People looking at my setup were unsure as well. I didn’t know about the ‘display’ type coming from the PagesController. I’ll never, ever forget now! :)

    I agree with Mark Story on the error message key. Cool trick!

  • teknoid

    @Brendon Kozlowski

    Heh, I was just about to start a follow up explaining some of the Auth features I’ve used and why…
    Thanks for additional push for this ;)

  • Paolo Stancato

    Hi mate, it’s a good trick of using the key, but how would you translate it if you need internationalization? I think is not a good practice…


  • teknoid

    @Paolo Stancato

    Well, for that reason you should use the ‘message’ key. But, considering that a vast majority of apps are only developed for one language, it’s a useful shortcut.

  • damopdharan

    hi i am beginner for the cake PHP

    am following your code i got error like

    Notice: If you want to customize this error message, create app\views/errors/missing_component_file.thtml.

    Fatal: Create the class below in file : app\controllers\components\auth.php

    after i create this i got like
    Fatal error: Call to undefined method AuthComponent::allow() in C:\Program Files\xampp\htdocs\comp\app\app_controller.php on line 8
    please help me to solve mail me

  • teknoid


    It seems that you’ve downloaded the 1.1 version of cake. All of my posts pretty much assume that you are using the latest release of 1.2, which is a lot more powerful and has greatly improved features.

  • Nice stuff . i like this site . Content is king ..always

  • brian

    can someone point me to how I can use my own redirect in user login function and turn off autoredirect, I know how to turn off autoredirect, but when I try to implement the redirect in my user login, they have to submit the form twice to get it to work

  • @mzee.richo

    Thank you.


    Never seen that happen before. Please double check at the google group.

  • Pingback: Введение в возможности CakePHP (как-создать-приложение-за-15-минут) | Bunyan.Ru()

  • Pingback: Codeword: Design and Development » Blog Archive » CakePHP()

  • Great tutorial Teknoid, it answered a bunch of my questions. Unfortunately I still have more!

    I took your examples here as a base for learning how to make a user management section on a site, and am working on allowing a user to edit their account. Editing their information seems to be a non-issue, but how would you handle someone updating their passwords? Typically, they would be required to input their old password, and then the new password twice. I’ve attempted a few goes at this but have not really been successful. What approach would you recommend?

  • @Gabriel

    Do you want an honest answer or a correct one? …. well, honestly I handled that right in the model with a (pseudo code) ‘if empty… don’t do shit;… otherwise hash as shown in the above function.

    Correctly, I do not have an answer, but it does seem to work quite well so far.

  • I think I’ve got a method figured out, but I’m having trouble verifying the user’s current password in the Model before hashing the new password and submitting that to the database.

    Hopefully this link is right:

    Take a look at it, let me know what you think?

  • @Gabriel

    $this->user[‘password’] doesn’t seem right, should it be $this->data[‘password’]?
    I would also urge you to ask at the google group as you get faster/better help there…

  • Good news, I have a working solution now:


  • @Gabriel

    Well, I’m glad you’ve got it worked out.
    And thanks for sharing your code.

  • Baiju

    Hi..Nice work..Your code is working fine for me..But after i login its not redirecting to index page showing error
    Warning (2): Cannot modify header information – headers already sent by (output started….

    can you please guide me why this error is arising..


  • @Baiju

    You forgot the most important part of the warning message, where it tells you the line at which the output had started. Chances are it is caused by an infamous blank space after the ?> tag or before

  • Baiju

    Hi thank you for your help…my code is working now….thanks a lot…have a great day….

  • sukh

    hi tekonid, Thanx for nice tutorial, In my application one administrator add the users, so administrator must be logged in to create user. if we use this technique is nt the add action unprotected for all?

  • @Baiju

    No problem ;)


    You might look into admin routing for this:

  • Sage

    I really like this technique for validating and hashing passwords. But it took me a while to figure out how to automatically log in users who register new accounts. After a lot of debugging, I found the following code works in my users/register controller.

    if (!empty($this->data)) {
    if ($this->User->save($this->data)) {
    $this->Session->setFlash(‘Your account has been created!’);
    $user[‘User’][‘username’] = $this->data[‘User’][‘username’];
    $user[‘User’][‘password’] = Security::hash($this->data[‘User’][‘password’],null, true);
    } else {
    $this->Session->setFlash(‘Your account could not be created. Please fix the errors below and try again.’);

    Hope this helps someone else.

  • @Sage

    Glad you’ve found it helpful. And thanks for sharing your code with everyone.


  • Henry

    hi pro..

    i’m a noob here.. i need help.. ^^

    i tried your tutorial and it seems working overall until i tried to login. I got a problem there. is it because the hash?? after we registered, the password was hashed to the DB, on the other hand, we type unhashed password to the login form. so, is it correct that it makes our password become INVALID all the times?? do you have the solution?? I’m really need help..


  • @Henry

    The Auth component should hash the password on login (automatically).
    Check the query output to make sure that it actually happens as it should, if you see a plain-text password compared to the hashed in the SQL, there’s something wrong with the setup.

  • Henry

    may i know how to check it?? so if there is really something wrong with the setup, then how to fix it??

    thanks.. ^^

  • @Henry

    Please check the comments in the follow up post linked above.
    It seems there are other people having a similar issue, but unfortunately I have no way to reproduce it. Perhaps it will give you some hints on what to do.

    Also, please ask at the google group or the cake’s IRC channel.
    It’s better to have a fresh pair of eyes looking at the code. Not to mention the core developers might have a much better insight.

  • chuck

    Thanx for the tutorial.

    I just started working with cakephp and I used the code you provided on my system to see if it would work. Unfortunately, it didn’t work and I get the following error:

    Fatal error: Class ‘AppController’ not found in /var/cake_1.2/cake/libs/controller/pages_controller.php on line 35

    Can you help?

  • @chuck

    Looks like your AppController is not found, are you sure you didn’t misspell the class name?
    Did you create the file in your /app root as pointed out above?

    You might want to jump on IRC to get this resolved, as it’s hard to do this over the blog.

  • chuck


    Yes I created the file in my /app directory. My directory path is: /var/cake_1.2/…

    I copied/pasted the code you provided for the AppController class.

    • @chuck

      At this point my guess is as good as yours.
      For whatever reason your App Controller is not found.

  • chuck


    Thanx for your fast response!

  • chuck


    I also checked the permissions of the /var/cake_1.2/ directory…
    /var/cake_1.2$ ls -ld
    drwxr-xr-x 5 chuck chuck 4096 2009-03-19 16:32 .
    I changed the permissions of php_controller.php and app_controller.php…
    -rwxr-xr-x 1 chuck chuck 2073 2008-12-18 20:16

    I really don’t know why I’m having this problem.

  • @chuck

    I am really not sure what could be causing the problem. Maybe you could try a fresh install on a different system.

  • chuck


    I solved the issue. Very trivial mistake… solved it. Forgot to include it.

  • @chuck

    Would you mind posting the solution?
    … just in case someone else runs into a similar problem.


  • chuck

    For whatever reason I posted it before but it didn’t show. But the solution was as simple as including “” at the end.

    • Henry

      I’m getting the same error. I am not clear what you mean by “the solution was as simple as “” at the end ”

      Fatal error: Class ‘AppController’ not found in /home/content/y/w/2/yw2radmin/html/app/controllers/songs_controller.php on line 2


  • Pingback: victor perotti » Daily Digest for 2009-06-01()

  • ionas

    I just wanted to say thank you. I remembered you wrote something about stopping the auto hashing, and I found it here again. Its so simple when you know it ;).

    Now (besides a missing captcha) my whole user registration with activation just works like a charm :)

    • Hey you probably did not started wyour script… thats a very common mistake….
      try to check if you are starting and closing it….

      PD. let us know if it works

  • @ionas

    Good to hear ;)

  • Zzella

    Just starting with CakePHP and your tutorials on Auth and i18n have been invaluable so a big thank you!!!

    For some reason despite the rule in the User model stating that the password field should not be empty, the ‘required’ styling was not showing up on the password field (in default Cake CSS, required fields are made bold).
    I had to force it by adding array(‘div’=>’input text required’) to the form field. Any idea why this is the case?

  • @Zzella

    You know, I’ve had the exact same problem happen before… I believe it was reported as a bug.

  • nore

    Hello, great tutorial.

    After I fill in the password and password_confirm field and submit. “Passwords must match” is thrown at me. I noticed that when submitting, the password field gets filled with more characters (meaning that it got hashed), while the password_confirm stays the same. And matching fails. What could I be doing wrong ?

  • @nore

    You are not overriding the password hash method as explained. Please double check the code, or see the follow up post, which explains this in more detail.

  • nore

    Everything is fine now, I forgot to change the name of the action in beforeFilter as i’m using admin_* actions.

    Another thing, what can I do/add to the validation rules so that I can allow the user to edit his username ? since when editing, isUnique is set which doesn’t allow the update, and if isUnique is on for create, I can’t allow the user to update the username without setting isUnique or duplicates will appear.


  • @nore

    Glad you worked it out. Please check the manual on validation. There is an ‘on’ key (create/update) for your validation rules, I hope you see how that would work ;) Cheers.

  • nore

    I know about the “on” key as i mentioned it in “…and if isUnique is on for create…”.
    Now the problem when ‘on’ is ‘create’ is that I can’t ensure that unique values are entered when editing/updating since there is no unique validation here. Do you get my point?

    I want to create a unique username and I want to allow the user to edit/update the username, and of course it *must* be unique if edited. Therefore, that won’t happen since the unique validation is only for create and not update.

    I hope you get my point.

  • @nore

    Sorry, I misunderstood.
    If you need to ensure uniqueness on both creation and updating, well… remove the key.
    Then you need to store the original username and check if it matches the same one coming from the form. If it does, that essentially means the user didn’t make any change, so you can unset it from your data array (as one option), thus bypassing the validation.

  • Laurent


    Thanks for the useful tutorial. I tried to use it because I needed to implement a ‘confirm password’ functionality. But I seem to have some problems.

    I can’t login with the saved password anymore. It’s succesfully hashed in the db, but according to me I can’t login because the AuthComponent takes care of this but it uses its default hashing mechanism in the login process (thus not the custom made hashing function).

    How can I fix this?


  • teknoid


    I am not quite clear on the problem, but if you password is already hashed in the DB, you can use Security::setHash() method to set appropriate hashing method for your app.

    Please see the API for more details.

  • Laurent

    I’m just getting an error “login failed” because the username/pass combination isn’t right. Before I implemented the confirm password field the Auth system was working properly so I must have broken something in the process :)

    Btw I don’t know if this is normal but when I do a debug($this->data) in the login method of the UserController I get an empty value for $this->data[‘User’][‘password’]. I reckon this is quite odd.

    [User] => Array
    [email] => myemailadress
    [password] =>


    • Laurent

      this is for newly created users too btw.

  • Laurent

    I noticed the password I type in the login form is not getting hashed at all. I just typed in the hash I get from the mysql database and I’m getting successfully logged in.

    Seems some more people have this problem (according to the comments on your blog), but I didn’t find an appropriate solution. Probably a change in the cakePHP core.

    Any ideas if this could be solved in a way?


  • giuseppe

    Fresh install. Point the browser to localhost/cakephp and always I get the error
    Fatal error: Class ‘AppController’ not found in C:\public_html\cakephp\cake\libs\controller\pages_controller.php on line 32

%d bloggers like this: