var $validate = array(
'username' => array(
'Username must contain only letters and numbers' => array(
'rule' => '/^[a-z0-9]{3,}$/i',
'required' => true
),
'This username is already taken' => array(
'rule' => 'isUnique'
),
'Username must be at least 5 characters' => array(
'rule' => array('minlength', 5),
)
)
);
Wednesday, August 3, 2011
More Validation Tips and Tricks
A good shortcut when creating Validation rules is to use the desired message as the key name. CakePHP will automatically use the key name as the error message in the absence of an explicit message.
Tuesday, August 2, 2011
Authentication and Passwords
One issue that will pop up is trying to add or edit users with Authentication enabled. Validation won't work properly on the password field because Authentication will hash the password BEFORE it attempts to validate. For example checking for a minimum length will always succeed regardless of the actual password because SHA1 hashed passwords will always be 40 characters.
One method around this is performing the hashing manually. To do this you have to tell your users controller you want to perform your own hashing. Edit
Next edit the users model
Another problem, however, is when editing a user, the hashed password is used in the password field of the form and becomes hashed again on save, actually changing the password! I'm surprised this issue isn't addressed in the core of CakePHP.
One way around this is to modify your edit view to clear the password field of the hashed password. Edit
So to get around that simply remove the
Then, to edit the password create a
One method around this is performing the hashing manually. To do this you have to tell your users controller you want to perform your own hashing. Edit
/app/controllers/users_controller.php and add the following function:
function beforeFilter(){
parent::beforeFilter();
if($this->action == 'add' || $this->action == 'edit' || $this->action == 'password'){
$this->Auth->authenticate = $this->User;
}
}Now when you are using the add or edit actions authentication is done manually. You'll see why the action password is in there later.
Next edit the users model
/app/model/users.php and add the following functions:
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;
}Now your users model will hash the passwords before save, allowing validation to take place first.
Another problem, however, is when editing a user, the hashed password is used in the password field of the form and becomes hashed again on save, actually changing the password! I'm surprised this issue isn't addressed in the core of CakePHP.
One way around this is to modify your edit view to clear the password field of the hashed password. Edit
/app/views/users/edit.ctp and change this
echo $this->Form->input('password'); to this
echo $this->Form->input('password', array('value' => '')); This will require you to enter a password every time you edit the user because your validation is set to require 5 characters in the password field.
So to get around that simply remove the
password field from your edit form. You can also remove the edit action from your beforeFilter function in the users controller. Now you can edit the user without worrying about the password.
Then, to edit the password create a
password function in your controller and a separate view. Edit /app/controllers/users_controller.php and add this function:
function password($id = null){
/* Only edit own account unless admin */
if(!$this->Auth->user('admin')){
$id = $this->Auth->user('id');
}
if (!$id && empty($this->data)) {
$this->Session->setFlash(__('Invalid user', true));
$this->redirect(array('action' => 'index'));
}
if (!empty($this->data)) {
if ($this->User->save($this->data, array('fieldList' => array('password')))) {
$this->Session->setFlash(__('The password has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The password could not be saved. Please, try again.', true));
}
}
if (empty($this->data)) {
$this->data = $this->User->read(null, $id);
/* Don't display current hashed password */
$this->data['User']['password'] = '';
}
Now create /app/views/users/password.ctp
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset><legend>Change Password</legend>
<?php
echo $this->Form->hidden('id');
echo $this->Form->input('password', array('label' => 'New Password'));
echo $this->Form->input('confirm_password', array('type' => 'password'));
?>
</fieldset>
<?php echo $this->Form->end('Save Password'); ?>
</div>
Then modify your users model /app/models/user.php and add the following validation rules and functions:
'password' => array(
'Your password must be at least 5 characters' => array(
'rule' => array('minlength', 5)
),
'You must enter the same password twice' => array(
'rule' => array('matchPasswords', 'confirm_password'),
'on' => 'update'
)
),
'confirm_password' => array(
'rule' => 'notEmpty'
)
function matchPasswords($data, $confirm_password){
if ($data['password'] != $this->data[$this->alias][$confirm_password]) {
$this->invalidate($confirm_password, 'You must enter the same password twice');
return false;
}
return true;
}Set appropriate authentication as desired, upload the files and you should be all set.
Monday, July 25, 2011
Log Database Errors
First read here: Catch database errors before it’s too late
It's as simple as adding an
Edit
It's as simple as adding an
onError function to your app_model.php file, and whenever there is a database error, the error in the database will be logged in your CakePHP log.
Edit
/app/app_model.php and add the following function:
public function onError() {
$db = ConnectionManager::getDataSource('default');
$err = $db->lastError();
$this->log($err);
$this->log($this->data);
}
Simple Form Security
First read this post: Make your CakePHP forms a lot more secure
The nuts and bolts of it is that by simply adding the
And you can implment it as easy as this: Edit
The nuts and bolts of it is that by simply adding the
Security component, it will automatically add a hash to all your forms and if someone tries modifying your form, it won't work.
And you can implment it as easy as this: Edit
/app/app_controller.php and change the var $components line to include Security like this: var $components = array('Auth', 'Security', 'Session');
Stylesheets and Print Stylesheet
Adding a stylesheet to your site is as simple as changing the default layout.
Open
For a Print Stylesheet, it is a little different. To set a print stylesheet you need to set the options to include the media type.
Open
/app/views/layouts/default.ctp and within the first 10 lines of the page is the line echo $this->Html->css('cake.generic'); Cake comes with a default style in /app/webroot/css/cake.generic.css which you can edit until your heart's content. Or you can create your own stylesheet and put it into the same folder and change that line to direct your pages to the new style. Observe how the .css extension is not included in the cake function call.
For a Print Stylesheet, it is a little different. To set a print stylesheet you need to set the options to include the media type.
echo $this->Html->css('cake.print', 'stylesheet', array('media' => 'print'));
Thursday, July 14, 2011
Validation Tips and Tricks
When using validation, as mentioned previously, there are some tricks to automatically adding the class
required to your form fields. Any validation rule that has minlength works. So a short, simple rule to just ensure the required class is added to the field label could look something like this:
var $validate = array(
'field_name' => array(
'rule' => array('minlength', 1)
)
);
If you want to require user input but don't care about the required class for your labels, you can actually use something as simple as this:
var $validate = array( 'field_name' => 'notEmpty' );If you expand that to the following code, however, you will also get the
required class for your field label.
var $validate = array( 'field_name' => array( 'rule' => 'notEmpty' ) );This is very useful when you want the
required class for select fields.
Wednesday, July 13, 2011
Model: User: Display Name
When adding a record that has a relationship of "belongs to" with another table as mentioned previously, CakePHP automatically lists the records of the other table using the display name of that model. By default that display name field is "name". However, if your field doesn't have a "name" field, such as the Users table, you can specify the display name manually in the model.
Edit
Edit
Edit
app/models/user.php and add the following line:
var $displayField = 'username';This does not support multiple fields, for example if you wanted to combine
first_name and last_name. In order to do this you need to use virtualFields in your model. Virtual fields allow you to access a created field, but you cannot save it.
Edit
app/models/user.php and add the following line:
var $virtualFields = array( 'full_name' => "CONCAT(User.first_name, ' ', User.last_name)");then change the display field from
username to full_name.
Subscribe to:
Posts (Atom)
