Category Archives: CakePHP - Page 3

Automatic DB Field Encryption in CakePHP

UPDATE: I’ve posted an improved version of this behavior here

I’ve written the following behavior for a project I recently completed in Cake, and I thought it would be worth sharing:

class CryptableBehavior extends ModelBehavior {
	var $settings = array();
 
	function setup(&$model, $settings) {
		if (!isset($this->settings[$model->alias])) {
			$this->settings[$model->alias] = array(
				'fields' => array()
			);
		}
 
		$this->settings[$model->alias] = array_merge($this->settings[$model->alias], $settings);
	}
 
	function beforeFind(&$model, $queryData) {
		foreach ($this->settings[$model->alias]['fields'] AS $field) {
			if (isset($queryData['conditions'][$model->alias.'.'.$field])) {
				$queryData['conditions'][$model->alias.'.'.$field] = $this->encrypt($queryData['conditions'][$model->alias.'.'.$field]);
			}
		}
		return $queryData;
	}
 
	function afterFind(&$model, $results, $primary) {
		foreach ($this->settings[$model->alias]['fields'] AS $field) {
			if ($primary) {
				foreach ($results AS $key => $value) {
					if (isset($value[$model->alias][$field])) {
						$results[$key][$model->alias][$field] = $this->decrypt($value[$model->alias][$field]);
					}
				}
			} else {
				if (isset($results[$field])) {
					$results[$field] = $this->decrypt($results[$field]);
				}
			}
		}
 
		return $results;
	}
 
	function beforeSave(&$model) {
		foreach ($this->settings[$model->alias]['fields'] AS $field) {
			if (isset($model->data[$model->alias][$field])) {
				$model->data[$model->alias]['cleartext_'.$field] = $model->data[$model->alias][$field];
				$model->data[$model->alias][$field] = $this->encrypt($model->data[$model->alias][$field]);
			}
		}
		return true;
	}
 
	public function encrypt($data) {
		if ($data !== '') {
			return base64_encode(mcrypt_encrypt(Configure::read('Cryptable.cipher'), Configure::read('Cryptable.key'), $data, 'cbc', Configure::read('Cryptable.iv')));
		} else {
			return '';
		}
	}
 
	public function decrypt($data, $data2 = null) {
		if (is_object($data)) {
			unset($data);
			$data = $data2;
		}
 
		if ($data != '') {
			return trim(mcrypt_decrypt(Configure::read('Cryptable.cipher'), Configure::read('Cryptable.key'), base64_decode($data), 'cbc', Configure::read('Cryptable.iv')));
		} else {
			return '';
		}
	}
}

All you need to do is add three lines to your bootstrap, and then load the behavior in any model you want to use it.

Here are the lines for your bootstrap:

Configure::write('Cryptable.cipher', 'rijndael-192');
Configure::write('Cryptable.key','random key string here');
Configure::write('Cryptable.iv', base64_decode('base64 encoded IV here')); // Create with mcrypt_create_iv with the appropriate size for your cipher

Here’s an example of how to load it in your model:

	var $actsAs = array(
		'Cryptable' => array(
			'fields' => array(
				'password'
			)
		)
	);

If you need to encrypt or decrypt a field outside of the normal find methods, you can simply call those methods on the model, passing in the string that needs worked on.

Download Cyptable Behavior

CakePHP + FirePHP

I was poking through the addons for Firebug today, and liked the look of FirePHP, so I started looking into how I could use it. As many of you know, I’m a big fan of CakePHP as a framework, so I looked up how to integrate the two together and make them work nicely. I found this guide on the Cake Bakery, and followed it with a few modifications, so here they are. Read more »

CakePHP: Paginate with Deep Associations

Got some CakePHP models with deep associations that you need to pull into the data that you display when you paginate them? This used to be a royal pain in the butt, and pretty much required custom pagination, but no more!

Behold:

$this->paginate = array(
    'Customer' => array(
        'contain' => array(
            'Order(id)',
            'Order.AccessCode(id)',
            'ShippingAddress(city,state)'
        )
    )
);
$this->set('customers', $this->paginate('Customer'));

All you need to do for this to work? Make sure you have your associations defined, and add the Containable behavior to each of the models in question. It works flawlessly, and can go as deep as you need, and retrieve just the fields you need. I haven’t tested sorting on deep relationships yet, but I don’t think that works, because of the way Cake does its queries. But still, this is better than nothing.

CakePHP Requests Blocking

I just finished tracking down a bug that I’ve been working on for nearly two days, and it turns out to have been something VERY simple.

The basic problem was that while a long running CakePHP request was running, the rest of the Cake app was non-responsive. This is because of a ‘feature’ of PHP. A given session can only be accessed by one apache thread at a time. Since CakePHP auto-starts sessions by default, my long running process was blocking all other requests to the UI, causing them to simply hang until the long process was complete. I solved it by turning off session autostart, and only activating sessions where I need them.

The critical clue came from this post: http://www.nabble.com/Cake-Stalling-(or-blocking)-td20769012.html

So, if you experience something similar, make sure to check your sessions.

Why CakePHP?

There are many frameworks out there for PHP. Too many, even, some might say. So how did I settle on using CakePHP for my prefered framework? Well, to be honest, I think I was just lucky. Chuck, a guy I work with, introduced me to it for a project we were working on, and I reluctantly tried it. The reluctance didn’t last long, however. Within a week or two, I was an avid fan, and a very eager convert. I have since worked on several personal projects, and at least as many paying jobs with CakePHP as the architecture of choice.

The thing I like most about Cake is the strong structure it brings to a project. “But wait!” I hear you say, “All frameworks do that!” Yes, they do. But the structure and methodology of Cake work very well for me. For other people, perhaps Symphony would be better. Or Zend. But my own rather biased opinion is that Cake is better than all the others. I’ve since looked at code written in a handful of other frameworks, and I’ve not been impressed by it. Perhaps it was merely that the code was written by people who didn’t really know what they were doing, so they didn’t properly take advantage of the framework. But I found all the other frameworks I looked at to be needlessly verbose and repetitious.

I also love how flexible Cake is, while still maintaining it’s structure. I can make it do almost anything I need. It may not be as efficient as a hand-coded solution to many problems, but the time it saves me in development is a huge payoff. Nothing I write is likely to ever need high end scalability. And if it does end up needing hand-tuning, then I’ll take the time and effort needed.

So, to make a long story short, I prefer CakePHP because it Just Works. It’s well structured, yet flexible, and it makes sense to me.