I have searched many topic in here but I can't solve my problem. Please check this for me.
I made the register page and when I made for password field...
I had users_controller.php like:
class UsersController extends AppController
{
var $name = "Users";
var $helpers = array('Paginator','Html');
var $paginate = array();
//Doi tuong component de thuc thi thao tac login
public $components = array
(
'Auth' => array
(
'authorize' => 'controller',
'loginRedirect' => array
(
'admin' => FALSE,
'controller' => 'users',
'action' => 'dashboard'
),
'loginError' => 'Invalid account',
'authError' => 'You don\'t have permission'
),
'Session'
);
//Ham loc cac user truoc khi truy cap trang
public function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('add');
$this->Auth->allow('viewuserall');
}
//Ham them moi user
public function add()
{
$this->layout = 'TDCake';
$this->User->set($this->data);
if($this->User->valid_user() == TRUE)
{
if(!empty($this->data))
{
$this->User->create();
if($this->User->save($this->data))
{
$this->Session->setFlash('User has been created!');
$this->redirect(array('action'=>'login'));
}
else
{
$this->Session->setFlash('Please correct the errors');
}
};
}
else
{
$this->Session->setFlash("Your data is NOT available");
}
}
//Ham login cho user
public function login()
{
$this->layout = 'TDCake';
if
(
!empty($this->data) &&
!empty($this->Auth->data['User']['username'])&&
!empty($this->Auth->data['User']['password'])
)
{
$user = $this->User->find
(
'first',array
(
'conditions'=>array
(
'User.email'=>$this->Auth->data['User']['username'],
'User.password'=>$this->Auth->data['User']['password']
),
'recursive' => -1
)
);
if(!empty($user) && $this->Auth->login($user))
{
if($this->Auth->autoRedirect)
{
$this->redirect($this->Auth->redirect());
}
}
else
{
$this->Session->setFlash
(
$this->Auth->loginError,
$this->Auth->flashElement,
array(),'auth'
);
}
}
}
//Ham logout cho user
public function logout()
{
$this->redirect($this->Auth->logout());
}
//Ham gi cha biet, de do tinh sau =))
public function dashboard()
{
$this->layout = 'TDCake';
}
//Ham view cac user khong dieu kien trong table users
function viewuserall()
{
$this->layout = 'TDCake';
$this->paginate=array
(
'limit' => 10,
'order' => array('id' => 'asc'),
);
$data = $this->paginate("User");
$this->set("data",$data);
}
}
User.php in Model is:
class User extends AppModel
{
var $name = "User";
var $validate = array();
function validate_passwords()
{
if($this->data[$this->alias]['pass'] == $this->data[$this->alias]['rpass'])
{
return $this->data[$this->alias]['pass'] = $this->data['User']['password'];
}
else return FALSE;
}
function valid_user()
{
$this->validate = array
(
//Kiem tra username truoc khi add
'username' => array
(
'rule01_notEmpty' => array
(
'rule' => 'notEmpty',
'message' => 'You must enter your Username !'
),
'rule02_max16' => array
(
'rule' => array('maxLength', 20),
'message' => 'Your Username must be less than 20 chars !'
),
'rule03_exists' => array
(
'rule' => 'isUnique',
'message' => 'Your Username have already existed !'
)
),
//Kiem tra email truoc khi add
'email' => array
(
'rule01_notEmpty' => array
(
'rule' => 'notEmpty',
'message' => 'You must enter your Email !'
),
'rule02_exists' => array
(
'rule' => 'isUnique',
'message' => 'Your Email have already existed !'
),
'rule03_emailtype' => array
(
'rule' => 'email',
'message' => 'You didn\'t type a email !'
)
),
//Kiem tra password truoc khi add
'pass' => array
(
'length' => array
(
'rule' => array('between', 6, 20),
'message' => 'Your password must be between 8 and 40 characters.',
),
),
'rpass' => array
(
'length' => array
(
'rule' => array('between', 6, 20),
'message' => 'Your password must be between 8 and 40 characters.',
),
'compare' => array
(
'rule' => 'validate_passwords',
'message' => 'The passwords you entered do not match.',
)
)
);//End this->validate=array
if($this->validates($this->validate==TRUE))
{
return TRUE;
}
else
{
return FALSE;
}
}//End function valid_user
}
add.ctp is
echo $this->Session->flash('auth');
echo $this->Form->create();
echo $this->Form->input('username', array('label' => ('Username')));
echo $this->Form->input('email', array('label' => ('Email')));
echo $this->Form->input('pass', array('label' => ('Password'),'type' => 'password', 'value' => ''));
echo $this->Form->input('rpass', array('label' => ('Repeat Password'), 'type' => 'password', 'value' => ''));
echo $this->Form->input('firstname', array('label' =>('Firstname')));
echo $this->Form->input('lastname', array('label' =>('Lastname')));
echo $this->Form->input('dob', array('label' =>('DOB'),'type' => 'date'));
echo $this->Form->end('Register');
Explanation:
So, in this case, I can validate 2 Password Fields (empty, not equal,...), but it can't insert to the database. That mean it INSERTED current data into the DB but password column in DB is EMPTY. In database, my password column name "password" also.
In another case, I change the name "pass" into "password" for the
echo $this->Form->input('pass', array(
Of course, I have changed any place related to...
and in that case, it can be inserted the password but can not validate anything.
I am too confused about this...I don't know what I am wrong is....can anybody help me.
I am not sure why you are doing an assignment in your validate function:
return $this->data[$this->alias]['pass'] = $this->data['User']['password'];
And even if you were doing an assignment, it should be:
return $this->data['User']['password'] = $this->data[$this->alias]['pass'];
Realize that the field "password" is getting the value from $this->data which has the information, not the other way around.
Also. It would be better (in terms of clarity), to break this code in two lines.
$this->data['User']['password'] = $this->data[$this->alias]['pass'];
return $this->data['User']['password'];
You should name your field the exact name "password" if that's what it is called in the database AND if you are not explicitly assigning it.
Your add function is not doing the above, and further more, as a best practice, you should be hashing the password.
See the CakePHP book on tutorials and examples.
Take some time to go through it with all the snippets and recommendations. And don't forget the standards. :)
Related
I'm running a 2.2.2 CakePHP Application, everything works as desired. Now I'm developing a Android App for it and therefore need to create the interfaces between those two apps. That's why I need to login users manually. So I created a whole new controller, the AndroidController, in order to bundle everything at one place. First thing to do would be the Login-Action. So I setup the following controller:
<?php
App::uses('AppController', 'Controller');
/**
* Android Controller
*
* #package app.Controller
*/
class AndroidController extends AppController {
public $components = array('RequestHandler','Auth');
public $uses = array('User');
public function beforeFilter() {
$this->Auth->allow();
}
public function login() {
//For testing purposes
$postarray = array('_method' => 'POST','data' => array('User' => array('email' => 'user#gmail.com', 'password' => 'THISisDEFINITELYaWRONGpassword')));
$id = $this->tryToGetUserID($postarray['data']['User']['email']);
if($id == 0){
//return Error json, unknown User
$this->set('result', array(
'tag' => 'login',
'success' => 0,
'error' => 1,
'error_msg' => 'Unknown User'
));
}else{
// if ($this->request->is('post')) {
$postarray['data']['User'] = array_merge($postarray['data']['User'], array('id' => $id));
$this->User->id = $id;
if ( $this->Auth->login($postarray['data']['User'])) {
// Login successfull
$this->User->saveField('lastlogin', date(DATE_ATOM));
$user = $this->User->find('all', array(
'recursive' => 0, //int
'conditions' => array('User.id' => $id)
));
$loggedInUser = array(
'tag' => 'login',
'success' => 1,
'error' => 0,
'uid' => '??',
'user' => array(
'name' => $user['0']['User']['forename'].' '.$user['0']['User']['surname'],
'email' => $user['0']['User']['email'],
'created_at' => $user['0']['User']['created'],
'updated_at' => $user['0']['User']['lastlogin']
)
);
$this->set('result', $loggedInUser);
} else {
// Login failed
$this->set('result', array(
'tag' => 'login',
'success' => 0,
'error' => 2,
'error_msg' => 'Incorrect password!'
));
}
// }
}
}
public function tryToGetUserID($email = null) {
$user = $this->User->find('list', array(
'conditions' => array('User.email' => $email)
));
if(!empty($user)){
return array_keys($user)['0'];
}else{
return 0;
}
}
}
You need to know that this method will be called as a POST request, but for testing purposes I manually created a post-array. In future I will use the $_POST array.
So, what happens: The Login with a registered user works, but it works every time! Even though the password is wrong or missing! The program never reaches the part in code with the "Login failed" comment.
Am I missing something here..?
Thank you!
If you take a closer look at the documentation you will notice that AuthComponent::login() will ...
In 2.x $this->Auth->login($this->request->data) will log the user in with whatever data is posted
I have a model Interesttype where i want two fields to be validated one should not be more than the other and none should be less than a particular set value. Here is my model.
class Interesttype extends AppModel
{
public $primaryKey = 'int_id';
public $displayField = 'int_name';
public $hasMany= array(
'Loan' => array(
'className' => 'Loan',
'foreignKey' => 'lon_int_id'
)
);
public $validate = array(
'int_name'=> array(
'rule' => 'notEmpty',
'allowEmpty' => false,
'message' => 'The interest type name is required.'
),
'int_active'=>array(
'rule'=>array('boolean'),
'allowEmpty'=>false,
'message'=>'Please select the status of this interest type'
),
'int_max'=> array(
'numeric'=>array(
'rule' => 'numeric',
'allowEmpty' => false,
'message' => 'Please specify a valid maximum interest rate.'
),
'comparison'=>array(
'rule' => array('comparison','>',1000),
'allowEmpty' => false,
'message' => 'The Maximum interest rate cannot be less than the special rate.'
),
'checklimits'=>array(
'rule' => array('checkRateLimits','int_min'),
'allowEmpty' => false,
'message' => 'The Maximum interest rate cannot be less than the minimum rate.'
)
),
'int_min'=> array(
'numeric'=>array(
'rule' => 'numeric',
'allowEmpty' => false,
'message' => 'Please specify a valid minimum interest rate.'
),
'comparison'=>array(
'rule' => array('comparison','>',1000),
'allowEmpty' => false,
'message' => 'The Minimum interest rate cannot be less than the special rate.'
))
);
function checkRateLimits($maxr,$minr){
if($maxr>=$minr){
return true;
}
else{
return false;
}
}
}
the above model validates my forms well except that one check will not be done, it will not check if the maximum interest rate is indeed more than or equal to the minimum inerest rate.
Where am i going wrong on the validation?
You'll have to add your own Validation Method to make this possible. Here's a pretty generic example that makes use of Validation::comparison() and supports all of its operators (>, <, >=, <=, ==, !=, isgreater, isless, greaterorequal, lessorequal, equalto, notequal) as the second argument in the options array and a field name to compare the validated value to as a third parameter.
class MyModel extends AppModel
{
/* Example usage of custom validation function */
public $validate = array(
'myfield' => array(
'lessThanMyOtherField' => array(
'rule' => array('comparisonWithField', '<', 'myotherfield'),
'message' => 'Myfield value has to be lower then Myotherfield value.',
),
),
);
/* Custom validation function */
public function comparisonWithField($validationFields = array(), $operator = null, $compareFieldName = '') {
if (!isset($this->data[$this->name][$compareFieldName])) {
throw new CakeException(sprintf(__('Can\'t compare to the non-existing field "%s" of model %s.'), $compareFieldName, $this->name));
}
$compareTo = $this->data[$this->name][$compareFieldName];
foreach ($validationFields as $key => $value) {
if (!Validation::comparison($value, $operator, $compareTo)) {
return false;
}
}
return true;
}
}
This is generic, so you could throw the function in your AppModel if you want to make use of it in multiple models in your App. You could also make this a Behavior to share it between different models.
I won't help you to do your code however I will suggest you to read the following backery article http://bakery.cakephp.org/articles/aranworld/2008/01/14/using-equalto-validation-to-compare-two-form-fields
<?php
class Contact extends AppModel
{
var $name = 'Contact';
var $validate = array(
'email' => array(
'identicalFieldValues' => array(
'rule' => array('identicalFieldValues', 'confirm_email' ),
'message' => 'Please re-enter your password twice so that the values match'
)
)
);
function identicalFieldValues( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
}
?>
modify the code I think it should be easy from here.
I don't think you can achieve this with directly inserting it into the validate array in a model. You can however specify your own validation function. An example is given here (look at the model code):
Example custom validation function
In your Model your validate should be field name with rule pointing to the function you want to run.
And "None should be less than a particular set value" I would use the "range" validation as seen below. The example will accept any value which is larger than 0 (e.g., 1) and less than 10
public $validate = array(
'maxr'=>array(
'Rate Limits'=>array(
'rule'=>'checkRateLimits',
'message'=>'Your Error Message'
),
'Greater Than'=>array(
'rule'=>array('range', -1, 11),
'message'=>'Please enter a number between 0 and 10'
)
),
);
In the function you pass $data which is the fields being passed. If $data doesn't work try $this->data['Model']['field'] ex($this->data['Model']['maxr'] >= $this->data['Model']['minr'])
function checkRateLimits($data){
if ( $data['maxr'] >= $data['minr'] ) {
return true;
} else {
$this->invalidate('minr', 'Your error message here');
return false;
}
}
Your Form would be something like
echo $this->Form->create('Model');
echo $this->Form->input('maxr');
echo $this->Form->input('minr');
echo $this->Form->end('Submit');
I'm writing a customer management system using cakePHP (the first thing I've ever attempted to build using this framework), and I'm struggling to figure out how to validate certain fields when adding a new customer.
Each customer has an id that I need to be able to add manually, and a username that has to be unique but can be empty.
Here is what I want to happen:
When adding a new customer:
Check whether the id already exists and alert the user if it does (and not add the user)
Check whether the username already exists and alert the user if it does (and not add the user)
When updating a customer profile (the id cannot be modified at this point):
If the username has been modified, check whether it already exists and alert the user.
As it now stands, whenever I try adding a user with an existing id, cakePHP simply overwrites the existing id's info with the new info.
I've tried several validation options but nothing seems to work.
Here's the first:
public $validate = array(
'id' => array(
'idRule-1' => array(
'on' => 'create',
'rule' => 'uniqueID',
'message' => 'This Oracle ID already exists.',
'last' => false
),
'idRule-2' => array(
'rule' => 'numeric',
'message' => 'Oracle ID can only contain numbers.',
'last' => false
),
),
'username' => array(
'userRule-1' => array(
'on' => 'create',
'rule' => 'uniqueUser',
'message' => 'This username already exists',
'last' => false,
),
'userRule-2' => array(
'on' => 'update',
'rule' => 'oneUser',
'message' => 'The eBay username you are trying to modify already belongs to another seller',
'last' => false,
),
)
);
public function uniqueID() {
return ($this->find('count', array('conditions' =>array('Seller.id' => $this->data['Seller']['id']))) == 0);
}
public function uniqueUser() {
return ($this->find('count', array('conditions' =>array('Seller.username' => $this->data['Seller']['username']))) == 0);
}
public function oneUser() {
return ($this->find('count', array('conditions' =>array('Seller.username' => $this->data['Seller']['username']))) == 1);
}
and the second (only for the id):
public $validate = array(
'id' => array(
'unique' => array(
'rule' => 'isUnique',
'on' => 'create',
'message' => 'This Oracle ID already exists.',
)
)
);
And here are the add() and edit() methods of the controller:
public function add() {
if ($this->request->is('post')) {
$this->Seller->create();
if ($this->Seller->save($this->request->data)) {
$this->Session->setFlash(__('The seller has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The seller could not be saved. Please, try again.'));
}
}
$accountManagers = $this->Seller->AccountManager->find('list');
$primaries = $this->Seller->Primary->find('list');
$thirdParties = $this->Seller->ThirdParty->find('list');
$sites = $this->Seller->Site->find('list');
$meetings = $this->Seller->Meeting->find('list');
$this->set(compact('accountManagers', 'primaries', 'thirdParties', 'sites', 'meetings'));
}
/**
* edit method
*
* #throws NotFoundException
* #param string $id
* #return void
*/
public function edit($id = null) {
if (!$this->Seller->exists($id)) {
throw new NotFoundException(__('Invalid seller'));
}
if ($this->request->is('post') || $this->request->is('put')) {
$this->Seller->id = $id;
if ($this->Seller->save($this->request->data)) {
$this->Session->setFlash(__('The seller has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The seller could not be saved. Please, try again.'));
}
debug($this->Seller->validationErrors);
} else {
$options = array('conditions' => array('Seller.' . $this->Seller->primaryKey => $id));
$this->request->data = $this->Seller->find('first', $options);
}
$accountManagers = $this->Seller->AccountManager->find('list');
$primaries = $this->Seller->Primary->find('list');
$thirdParties = $this->Seller->ThirdParty->find('list');
$sites = $this->Seller->Site->find('list');
$meetings = $this->Seller->Meeting->find('list');
$this->set(compact('accountManagers', 'primaries', 'thirdParties', 'sites', 'meetings'));
}
Any and all tips will be greatly appreciated!
If the data you are trying to save contains an id, CakePHP assumes that you are updating an existing record. For a validation rule to be triggered on "create", the id should not be set. If the id is set, Cake will check for "update" rules.
So you should let your database affect ids for new records with an autoincrement, and then only manage validation when editing your existing users.
I'm trying to set up validation for user registration but I'm having troubles. When I only have the email,role and password fields in the $validation array (remove the others) it works and will save a new user. When I try to add the other fields it fails and gives the flash message error "The user could not be saved. Please, try again."
I'm pretty sure it's the re_password check. When I remove the validation for that it works. However, the re_password validation does display an error when the passwords are different, so I'm not sure where to look
Here's my users table
id | email | password | location | website | role | created | modified
Here's the validation requirements. To get it to save a new user I have to remove everything but email, password and role.
public $validate = array(
'email' => 'email'
,
'password' => array(
'required' => array(
'rule' => array('minLength', '8'),
'message' => 'A password with a minimum length of 8 characters is required'
)
),
're_password' => array(
'required' => array(
'rule' => array('equalTo', 'password' ),
'message' => 'Both password fields must be filled out'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
),
'location' => array(
'valid' => array(
'rule' => array('notEmpty'),
'message' => 'Please select a location'
)
)
);
Here's the form (the options array is above, figured it's not necessary to show)
echo $this->Form->input('email');
echo $this->Form->input('password');
echo $this->Form->input('re_password', array('type'=>'password', 'label'=>'Re-Enter Password', 'value'=>'', 'autocomplete'=>'off'));
echo $this->Form->input('location', array('options' => $options, 'label' => 'Select Nearest Location'));
echo $this->Form->input('website',array('label'=>'Enter your website, such as www.example.com. '));
echo $this->Form->input('role', array('type' => 'hidden', 'default' => 'user'));
Here's the re_password checking function in the User model
function check_user_password($userid) {
$salt = Configure::read('Security.salt');
$this->User->id = $userid;
$hashed_password = $this->User->field('password');
// check password
if($hashed_password == md5($data['User']['re_password'].$salt)) {
return true;
} else {
return false;
}
}
And finally, here's the add function in UsersController
public function add() {
if ($this->request->is('post')) {
$this->User->create(); //create initiates a form on User/add.ctp
if ($this->User->save($this->request->data)) { //save the form data
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('controller' => 'demos', 'action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
Please let me know if there's anything else you need to see
I believe that your re_passwords valiadtion rule equalTo compares its value to string password and not the actual field. I like to use custom functions for this.
so try replacing re_passwords rule array
//'rule' => array('equalTo', 'password' ),
'rule' => array('equalToField', 'password'),
and declare equalToField function in that model
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
** Also in the future when you seem to have a problem with validation rules
try this in your controllers action (its faster than removing every single rule)
if ($this->User->save($this->request->data)) {
...
} else {
debug($this->User->validationErrors);
...
}
I hope this helps.
Hi Please use following code for your requirement :
override equalTo function by putting your own method in user model:
function equalTo( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
Attention, in #luboss answer, where he declares:
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
That cannot work as we are comparing inconsistent fields:
the left member of strcmp has already been hashed, but not the right member.
This happens as a CakePHP automation because the field is called password.
The way I got this to work was to reuse the hashing function in the equalToField helper:
public function equalToField($array, $field) {
$valueFirstOccurrence = $this->data[$this->alias][$field];
$valueSecondOccurrence = Security::hash($this->data[$this->alias][key($array)], $type = 'sha1', $salt = true) ;
return !strcmp($valueFirstOccurrence, $valueSecondOccurrence);
}
Other point :
If you are interested in adding a minLength validation field for your password field, you want to read this good post first:
minLength data validation is not working with Auth component for CakePHP
I have my validation rules in model, and everything is fine. It validates like I want to, but in the Edit actions, although it not validates, don't show me de red error marks under textbox.
Any tip?
Thanks.
The Model Code(Model name is Safpercent):
var $validate = array(
'sequencia' => array(
'must_be_numeric' => array(
'rule' => 'Numeric',
'message' => 'Number Field: insert only numbers.'
)
),
);
View Text Box:
echo $form->input('Safpercent.sequence', array('id' => 'sequence', 'options' => $criteria, 'label' => false, 'div' => false, 'style' => 'width: 300px'));
Controller Code:
function edit($id = null) {
$criteria = $this->Safpercent->Safrequirement->find('list', array('fields' => array('Safrequirement.sequencia', 'Safrequirement.descricao'), 'conditions' => array('Safrequirement.tipo' => 'ILC')));
$this->set('criteria', $criteria);
if (!$id && empty($this->data)) {
$this->Session->setFlash(RecordNotValid, 'flash_failure');
$this->redirect(array('controller' => 'safpercents', 'action'=>'index'));
}
if (!empty($this->data)) {
$sequencia = $this->data['Safpercent']['sequencia'];
if($this->data['Safpercent']['tipo'] == ''){$tipo = 'ILC';}else{$tipo = $this->data['Safpercent']['tipo'];}
$encontro = $this->Safpercent->Safrequirement->find('all', array('conditions' => array('sequencia' => $sequencia, 'tipo' => $tipo)));
if($encontro <> array()){
if ($this->Safpercent->save($this->data)) {
$this->Session->setFlash(RecordSaved, 'flash_success');
$this->redirect(array('controller' => 'safpercents', 'action'=>'index'));
}else{
$this->Session->setFlash(RecordNotSaved, 'flash_failure');
}
}else{
$this->Session->setFlash('A Sequência que tentou Inserir não existe. Verifique a tabela de novo, por favor.');
}
}
if (empty($this->data)) {
$this->data = $this->Safpercent->read(null, $id);
$this->set('id', $id);
}
$this->set('cod_percent',$this->Safpercent->read(null, $id));
}
(Portuguese Variables and Text in some cases)
Try
debug($this->Safpercent->validationErrors)
and see if it shows any errors.
I see now. In your controller, you are using the sequencia field that you are validating, but not doing any validation at this stage. It passes a non-number to the find query, which then returns an error or something, and the save never gets called?
Before you do this:
$sequencia = $this->data['Safpercent']['sequencia'];
You should check that the data validates, by calling this:
$this->ModelName->set($this->data);
if ($this->ModelName->validates()) {
... //do your business here
So basically, change:
if (!empty($this->data)) {
to:
$this->Safpercent->set($this->data);
if (!empty($this->data) && $this->Safpercent->validates()) {