CakePHP Tips And Tricks

In: Development | No Comments
Tags: , , ,
By: Ross

Pumping CakePHP Weights

Recently I’ve been using CakePHP quite a bit, but prior to the large projects I had to undertake, because of how the projects I’d worked on previously had been somewhat small in scale, I didn’t have much experience using it in more irregular scenarios. Lately, however, I’ve been pushed a lot more and have been thrown in to the deep end if you will, of CakePHP. Dealing with topics like caching, security, and integration with APIs and vendors, I learnt a lot in a short amount of time. Therefore, I’m going to list a few of the things that I found helpful, so that maybe I can save someone some time in searching for the answers that took me long enough on my own.

Security

Security was a must on one of my projects, and thus, the Security component became my best friend pretty quickly. To start using its functionality, its as simple as including it in your components array at the top of your controller. Be sure to have it as the first component in the array so that its functionality can be used in the other components as well.

$components = array('Security', 'Auth');

If your security level in your core.php config file is set to medium or higher, by just adding the Security component to your application, all forms will have a hidden field added containing a hashed token specific to the form it has been embedded in. On each form submit, the token will be checked to see if it is valid in relation to your application and the form that was submitted, and deny any requests that do not validate by returning a black hole page (which by default is a blank page – this can be changed by changing the Security component’s blackHoleCallback property to the action to be triggered on black hole requests). Because the form’s fields are used to create the hashed token though, this token does not change frequently.

The above just isn’t enough though to deter all CSRF requests. This can be changed pretty easily though by adding the line of code below to your controller’s beforeFilter() method:

$this->Security->requireAuth('action_name');

Just by adding this line of code, you are telling the Security component to add another hidden field with a token, that gets refreshed ON EACH PAGE LOAD. This forces the user submitting the page to load the page each time he/she wishes to submit a form request so that a valid token is submitted along with it. And if you still don’t feel your application is safe enough, you can always add another key for self-assurance, such as in the code below:

In your controller’s action:

$key = Security::generateAuthKey();
$this->set('safe', $key);
$this->Session->write('safe', $key);

In your view:

echo $this->Form->create('Post');
echo $this->Form->hidden('safe', $safe);
echo $this->Form->input('title');
echo $this->Form->input('content');
echo $this->Form->end('Submit');

And in your controller’s action again, before where the key is generated:

if(!empty($this->data) && strlen($this->data['Post']['safe']) > 0 && strlen($this->Session->read('safe')) > 0 && $this->data['Post']['safe'] == $this->Session->read('safe'))
{
   $this->Post->create();
   $this->Post->save($this->data);
}

Also remember to make use of methods like requirePost() to force certain methods that require certain types of requests to deny all others, as they are invalid. If you still feel like you need an extra line of defence, you can always use Recaptcha, and its pretty easy to implement.

Caching

If you have already explored caching with CakePHP or have read articles like Mark Story’s, you’ll probably know what’s being mentioned below, but I found it extremely helpful in improving performance on my sites, so I will mention it anyway.

The first method that I started making use of wherever I could, was the combining of elements with the requestAction method, which is generally avoided by CakePHP developers (as I did myself, I treated it like the plague before I realised how useful it could be in situations such as these), to improve caching performance, and to modularise code in an easier-to-understand way.

Basically, this works by using a requestAction request inside your element to obtain a list of records from the database, and then display them within the element itself. How you would use this to improve performance though, is use the caching functionality provided by the elements. Find an example below:

In view/layout:

echo $this->element('recent-posts', array('cache'=>'+1 hour'));

In the ‘recent-posts.ctp’ element:

$posts = $this->requestAction(array('controller'=>'posts', 'action'=>'getRecent'), array('return'));

/* Loop through posts and display them as per usual - Sorry for the lack of HTML, pre tags just dont cut it.*/

foreach($posts as $post):
   echo $post['Post']['title'];
endforeach;

From the moment you implement this you will see that if you make any changes to your recent posts’ titles, or add a new post, the list will not change until an hour has passed since the last cached request. If you were to have 100 additional visits in that time, you would have saved your server the strain of serving 100 queries, and similarly if you were already using requestAction in the element, 100 queries and 100 requests. As you can imagine, this can be tremendously helpful.

Another way to make use of caching performance benefits, is to determine if you have any queries that you perform frequently, and then create a method within the model itself to automatically return those results. You would then simply check if there is a cached version of the results available to return and if not, perform the query, store it into cache, and then return it. See below for an example:

function getRecent()
{
	$cache = Cache::read('recent-posts');
	if(!$cache)
	{
		$posts = $this->find('all', array('order'=>'Post.date_created DESC', 'limit'=>5, 'recursive'=>-1));
		Cache::write('recent-posts', $posts, 'default');
		return $posts;
	}
	else
	{
		return $cache;
	}
}

Using the above, recent posts would be cached for the length of time specified in your caching preferences array in your core.php config file. The database is most commonly the bottleneck of an application, so caching results like shown above can have tremendous performance benefits by eliminating frequent but unimportant queries.

Note that when caching is enabled, CakePHP will automatically cache the database schema for however long your default caching configuration is set to, so if you change your schema, and cannot figure out for the life of you why you cannot submit forms successfully and so on, make sure you do a quick Cache::clear() to clear the cache so that CakePHP rereads the schema on the next request.

Other Stuff

Looking at a cool CakePHP performance article the other day I saw that trying out persistent database connections was recommended by the author, as it could supposedly greatly improve performance by eliminating the need for closing and reopening database connections for each request. I decided to try it out, and lo and behold, the site response time decreased by a large margin. I definitely recommend it to other CakePHP developers, as unless your site is receiving hundreds of views per second, it shouldn’t cause any technical issues, and the performance benefits are substantial and worth it.

Another thing I made sure to make use of was checking if my application was in debug mode or not in certain parts of my application. Using this, I can basically determine whether the application is residing on my machine, or on the live server, without having to set anything else except the debug variable in the core.php config file. This enables me to prevent caching from interfering with development.

if(Configure::read('debug') != 2)
{
    /* Do caching/other live server stuff */
}

Conclusion

Hopefully this article is of use to someone out there. I’m still no CakePHP expert, but I’m improving, and I have a feeling that, unless another PHP framework comes out to rival it in its time saving features and behind the scenes functionality (Lithium?), I’ll most likely be using it for many projects to come.

Related Posts

Leave a comment Name

Follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.

No Comments Up Down

Want a custom image by your comment? We use Gravatar [ Free & Quick ]