I have a good amount of experience with MVC but can't seem to figure what is going wrong here.
I'm trying to update the user's model but for some reason what should be an update is attempting to execute as an insert.
Edit: I'm using this starter site for Laravel which uses Ardent
$user = User::find(Auth::user()->id);
$user->recipient_id = "xxxxxxxxx";
if ($user->save()) {
return true;
} else {
print_r($user->errors()->all()); die();
}
The above outputs
Array (
[0] => The username has already been taken.
[1] => The email has already been taken.
[2] => The password confirmation does not match.
)
Any help would be really appreciated! I have a feeling its something trivial...
Actually while validating it uses rules of the User Model class.
This happens because use of these lines in models.
public $autoHydrateEntityFromInput = true; // hydrates on new entries' validation
public $forceEntityHydrationFromInput = true; // hydrates whenever validation is called
What you have to do is to change the rules dynamically.
$user = User::find(Auth::user()->id);
$user->recipient_id = "xxxxxxxxx";
$user::$rules['username'] = 'required|regex:/^[a-zA-Z\- ]+$/|unique:users,username,'.$user_id;
$user::$rules['email'] = 'required|email|unique:users,email,'.$user_id;
$user::$rules['password'] = 'required';
//this will ignore current username and email
if ($user->save()) {
return true;
} else {
print_r($user->errors()->all()); die();
}
Related
I am new in php and working on REST API in cakephp3 for my android application.
after setting up php and composer and routing I created login function..
public function login() {
$this->request->allowMethod('post');
$this->loadModel('Users');
$entity = $this->Users->newEntity($this->request->data, ['validate' => 'LoginApi']);
if ($entity->errors()) {
$this->httpStatusCode = 400;
$this->apiResponse['message'] = 'Validation failed.';
foreach ($entity->errors() as $field => $validationMessage) {
$this->apiResponse['error'][$field] = $validationMessage[key($validationMessage)];
}
} else {
$hasher = new DefaultPasswordHasher();
$password = $hasher->hash($entity->password);
$user = $this->Users->find()
->where([
'email' => $entity->email,
'password' => $password
])
->first();
if (empty($user)) {
$this->httpStatusCode = 403;
$this->apiResponse['error'] = 'Invalid email or password.';
return;
}
$payload = ['email' => $user->email, 'name' => $user->name];
$this->apiResponse['token'] = JwtToken::generateToken($payload);
$this->apiResponse['message'] = 'Logged in successfully.';
isset($user);
isset($payload);
}
}
I use 123456 for password and this hasher returns random string every time, but the password which is already saved in database for 123456 is
$2y$10$f7K02jamD7ZeGHLcTkP6Weh6VsthMWHiwqHJmcqbsxuLCKGCQCGCu this.
that is why it gives Invalid password in response.
My question is how to match the exact same string or hashing for request.
thanks in advance.
With reference to this answer
Use this line
password_verify($entity->password, $user->password)
instead of this
$hasher = new DefaultPasswordHasher();
$password = $hasher->hash($entity->password);
you can try this function
public function login()
{
$this->request->allowMethod('post');
$this->loadModel('Users');
$entity = $this->Users->newEntity($this->request->data, ['validate' => 'LoginApi']);
if ($entity->errors()) {
$this->httpStatusCode = 400;
$this->apiResponse['message'] = 'Validation failed.';
foreach ($entity->errors() as $field => $validationMessage) {
$this->apiResponse['error'][$field] = $validationMessage[key($validationMessage)];
}
} else {
$user = $this->Users->find()->where(['email' => $entity->email])->first();
if (count($user)) {
if (password_verify($entity->password, $user->password)) {
$payload = ['email' => $user->email, 'password' => $user->password];
$this->apiResponse['token'] = JwtToken::generateToken($payload);
unset($user->password);
$this->apiResponse['response'] = array($user);
unset($user);
unset($payload);
} else {
$this->httpStatusCode = 403;
$this->apiResponse['error'] = 'Incorrect password';
return;
}
} else {
$this->httpStatusCode = 403;
$this->apiResponse['error'] = 'Email not found';
return;
}
}
}
The general idea would be to hash according to a key you specify.
An advice would be to keep changing the key periodically. You will then need to dehash your save into the clear again using the old key then rehash on new.
I'm not sure if the option is available to you, so you might want to take it with a grain of salt.
Cheers
First of all, CakePHP ships with authentication functionality out of the box, and I'd strongly suggest that you make use of that instead of running your own, given that it sounds as if you're looking for deterministic algorithms, this can very easily backfire.
If you are using CakePHP 3.5+, look into the authentication middleware plugin (currently in RC phase), for earlier CakePHP versions, use the authentication component.
For the sake of completeness, if you were to do this manually, you'd first query the user by its unique identifier (in your case the email address), and then compare the password at PHP level, using the password hashers AbstractPasswordHasher::check() implementation:
$user = $this->Users
->find()
->where([
'email' => $this->request->data('email')
])
->first();
if (!$user ||
$hasher->check($this->request->data('password'), $user->password) !== true
) {
// authentication failed
} else {
// authentication succeeded
}
I need to check if a user is existing in the mgrUser table. now the propblem is the controller is in the adminController while the model is in the mgrUserModel. how do i use Auth for this? Thats the reason why I made a generic login code.
public function login() {
// if ($this->Auth->login()) {
// return $this->redirect($this->Auth->redirectUrl());
// }
// $this->Flash->error(
// __('Username ou password incorrect')
// );
//since the model is in a different view, I needed to includ the mgrModel and create a generic login
//will revamp the code to fit the built in Aut code for php cake
if(isset($_POST['submit'])) {
$User_ID = htmlspecialchars($_POST['user_id']);
$Pass = htmlspecialchars($_POST['pass']);
try {
$mgrUserModel = new MgrUser();
$isValid = $mgrUserModel->find('first', array(
'conditions' => array("user_id" => $User_ID)
));
if($isValid != null){
if (($isValid['MgrUser']['pass']) == $Pass) {
//this doesnot work
$this->Auth->allow();
$this->redirect($this->Auth->redirectUrl());
}
else{
}
}
} catch (Exception $e) {
//echo "not logged in";
}
// this echo will show the id and pass that was taken based on the user_id and pass that the user will input
//for testing only
// echo $isValid2['MgrUser']['id'];
// echo $isValid2['MgrUser']['pass'];
}
}
You need double == to compare things,
function checkMe()
{
if($user == 'me'){
$this->Auth->allow('detail');
}
}
what you did was assign "me" string to variable $user which always returns true because assignment was possible
Anyway you should use it in beforeFilter which is running before every action from this controller, which makes much more sense
public function beforeFilter() {
parent::beforeFilter();
if($user == 'me'){
$this->Auth->allow('detail');
}
}
the Auth component could be configured to read the user information via another userModel (The model name of the users table). It defaults to Users.
please consult the book for appropriate cakephp version: https://book.cakephp.org/3.0/en/controllers/components/authentication.html#configuring-authentication-handlers
public function actionUpdateprofile(){
$user = User::model()->findByPk($_POST['User']['user_id']);
$profile = Profile::model()->findByPk($_POST['User']['user_id']);
if(isset($_POST['User']) || isset($_POST['Profile'])){
$user->attributes = $_POST['User'];
$profile->attributes = $_POST['Profile'];
$user->save();
$profile->save();
}
}
I did this code for update the value in profile and user table. But it's not working.
If i send $_POST['Profile']['email'] = 'abc#gmail.com';
There is no error but database still showed old value. why?
What i did wrong in there?
This is the result for $profile->attributes. email still have old value.
Array
(
[user_id] => 35
[lastname] => asd
[firstname] => asrtyr
[email] => xyz.gmail.com
[phoneno] => 123456
[prof_img] =>
[phoneno2] => 0
[agentKey] =>
[fb_id] =>
)
I suggest you to add error reporting like below
if(!$user->save()){
echo 'Error to save user model<br />';
var_dump($user->getErrors());
}
if(!$profile->save()){
echo 'Error to save profile model<br />';
var_dump($profile->getErrors());
}
I'd reccommend to check possible errors on saving:
istead of
$user->save();
you could use
if (!$user->save()){
print_r($user->getErrors());
}
First, do this to check if it has to do with validation (look example below) and test it:
public function actionUpdateprofile(){
$user = User::model()->findByPk($_POST['User']['user_id']);
$profile = Profile::model()->findByPk($_POST['User']['user_id']);
if(isset($_POST['User']) || isset($_POST['Profile'])){
$user->attributes = $_POST['User'];
$profile->attributes = $_POST['Profile'];
$user->save(false);
$profile->save(false);
}
}
Which will bypass the validation. If it works, and you really need the validation (and you most certainly do), remove the false's I added and build it up by following the validation guide. The thing to remember is: the property not associated with a rule in rules() array is considered unsafe and is NOT saved into the database. This might be your problem.
I currently have 1 table, Users which looks like this
|**id**|**username**|**password**|**role**|**email**|
I'm using CakePHP's form helper to automatically fill in editable form fields. I'm creating an edit page in which users can change there username/password/email, but should NOT be able to change their role. I'm currently checking to make sure the user hasn't injected a role POST field into the request and was wondering if there is any better way to do this? It's trivial in this scenario with such a small table, but I can see this becoming tiresome on fields/tables with a large amount of columns. My current edit action looks like this.
public function edit($id = null)
{
$this->User->id = $id;
if(!$this->User->exists())
{
throw new NotFoundException('Invalid user');
}
$userToEdit = $this->User->findById($id);
if(!$userToEdit)
{
throw new NotFoundException('Invalid user');
}
if($this->getUserRole() != 'admin' && $userToEdit['User']['owner'] != $this->Auth->user('id'))
{
throw new ForbiddenException("You do not have permission to edit this user");
}
if($this->request->is('post') || $this->request->is('put'))
{
//Do not reset password if empty
if(empty($this->request->data['User']['password']))
unset($this->request->data['User']['password']);
if(isset($this->request->data['User']['role']))
unset($this->request->data['User']['role']);
if($this->User->save($this->request->data))
{
$this->set('success', true);
}
else
$this->set('success', false);
}
else
{
$this->request->data = $this->User->read();
//Prevent formhelper from displaying hashed password.
unset($this->request->data['User']['password']);
}
}
The third parameter of save() method lets you to define the list of fields to save. Model::save() docs
$this->User->id = $this->Auth->user('id');
$this->User->save($this->request->data, true, array('username', 'email'))
I am completing my login function for my application and I'm receiving the trying to get property of non object on a few lines. The first one is shown below that does a function call to the is_user_locked method using the object property lock_date inside the user_data object. I understand that this means that at this point their is no user_data to work with so it can not use the properties. I'm curious to know how should I account for this so that I don't abuse using too many nested if statements.
if (count($user_data) == 0) {
$output = array('content' => 'The user was not found in the database!', 'title' =>
'User Not Found');
}
if ($this->is_user_locked($user_data->lock_date)) {
$output = array('content' => 'This user account is currently locked!', 'title' =>
'Account Locked');
}
Any ideas on why this could be? Any and all suggestions would be helpful.
I'm curious to know how should I account for this so that I don't
abuse using too many nested if statements.
How about something like this ?
if( $user_data ) {
// $user_data contains something so let's proceed
if ($this->is_user_locked($user_data->lock_date)) {
$output = array('content' => 'This user account is currently locked!', 'title' => 'Account Locked');
}
} else {
// Nothing in $user_data so throw Exception or display error
$output = array('content' => 'The user was not found in the database!', 'title' =>
'User Not Found');
}
See this link.
if($var): same as $var == NULL.
What seems to be happening is $user_data->lock_date should be $user_data['lock_date']. I'm not 100% sure by the code you posted but it seems you're just referencing an array element incorrectly.
Terinary operators can be used to avoid if statements
$user_data === null ? "it's null" : "otherwise it's not";
i am a huge fan of negative if checks. the idea is that if you do not get what you expect, you immediately exit. this can be getting back a result, or doing a true false check. Of course you are first going to validate the user name using CI form validation. so for example in your model, the method that checks for the user name - if the result is 0, just have it return false. Then in your controller:
// Validate the user name and other form info
// if validation passes, grab the username,
// note the TRUE, that tells CI to run it through XSS clean
$username = $this->input->post( 'username', TRUE ) ;
// if we did NOT get a user back from model, immediately go to new method
if ( ! $user = $this->users_m->_findUser($username) ) {
$this->_userNotFound(); }
// similar, if the user account is locked, go to new method
// if you return an array from model this would be $user['lock_date']
elseif ($this->isUserLocked($user->lock_date) == TRUE) {
// DO NOT try and write messages etc here. put all that in a separate method
$this->_userAccountLocked(); }
else {
// you have a $user and the user is not locked
// its tempting to write a bunch of stuff here
// do not do that. keep it clean, and go to separate method
$this->_displayAccount($user) ; }
Note that i put an underscore before all the method names - CI will automatically make those private.
Also note the Camel case for method names -- versus underscores. some people prefer it.
You could do this:
if (count($user_data) == 0) {
$output = array('content' => 'The user was not found in the database!', 'title' =>
'User Not Found');
} else if ($this->is_user_locked($user_data->lock_date)) {
$output = array('content' => 'This user account is currently locked!', 'title' =>
'Account Locked');
}
Which is pretty much identical to your initial code, but with an else thrown in.