I want to create an account activation where after registering, a link would be sent to an administrator (or one) email whereby the admin just has to click that link to activate that account.
I have the registration and login working. I'm using MySQL Workbench and have a "flag" or rather just a field in my accounts table (named user_login) to tell whether the account is enabled or disabled, which is disabled by default after registration.
I am stuck and sending a link through email, I'm not sure where to begin. That link that I want to send would contain a random string and would be sent to the admin, say abc/123/random?stringis=1234. Then the admin would just have to open his email and click on the string and then that specific user's account would be activated. I found this and this but that's just for how to send a link through email.
I don't have an idea on the logic. Do I create a function whereby the link would go directly to the function and from there, it would change the value in my table to enabled or whatever I call it so that the user's account is counted as activated? Do I need to create a new field to match the random generated string then?
Main idea is I'm trying to do like those typical sites whereby a link would be sent to the user to activate the account once he/she clicks it in the email, but this time just to a specific email which is the admin's.
EDIT:
In controller
public function activate_user($activation_code)
{
$result = $this->home_model->activate($activation_code);
if($result != FALSE)
{
echo "You have activated :".$result[0]->user_id.".";
}
else
{
echo "Activation failed, something went wrong.";
}
}
In Model:
public function activate($activation_link)
{
$this->db->select('*');
$this->db->from('user_login');
$this->db->where('activation_link', $activation_link);
$query = $this->db->get();
if($query->num_rows() == 1)
{
return $query->result();
}
else
{
return FALSE;
}
}
First
Database
add two column
activation_token{varchar|255}
activation_time{datetime}
After registration Success
add some randome has into activation_token(md5 or sha1(up to you))
add time if registration using Current timestamp(now())
Link
link should be
I strongly prefer userid in activation url
because it's remove the link duplication.
http://sitename.com/activation/{user_id}/{hash}
in controller
public function activation($user_id,$hash)
{
$timeOfexpiration = 3600;
$data = $this->model->get_data($id,$hash);
if(!$data)
{
return false
}
//if user found
//check expiration of linke
//like
if($data['activation_time']+$timeOfexpiration < now())
{
return true;
}
else
{
return false;
}
}
for that you need to add one more field in table called activation_linkwhen user register in site then generate random string and store that in activation_link and send link to the user so once user back then check the link and activate that user.
Related
I am trying to make a login system for normal user and AdminUser. If a normal user types in browser http://localhost/project the login screen comes in and user can login using his Id and Password. But while logged in if user types in browser http://localhost/project/admin the normal user also gets the access in adminpanel which i want to stop. How can I do that ?I am stuck here for long time. Any Help Please?
Login for user:
$query = "SELECT * FROM user WHERE eid='$eid'and password='$password'";
$result = $db->select($query);
if ($result != false) {
$value = $result->fetch_assoc();
Session::set("login", "userLogin");
Session::set("username", $value['username']);
Session::set("email", $value['email']);
Session::set("uid", $value['uid']);
Session::set("image", $value['image']);
header("Location: index.php");
} else { $loginErr = "Username
or Password Not Matched !!";}
Session function for User:
public static function checkSession(){
self::init();
if (self::get("userLogin")!== false) {
self::destroy();
header("Location:login.php");
}
}
Session check for User:
Session::checkSession();
Login for admin
$query = "SELECT * FROM afcadmin WHERE adminname='$adminname'and password='$password'";
$result = $db->select($query);
if ($result != false) {
$value = $result->fetchassoc();
Session::set("loginadmin", "adminLogin");
Session::set("adminname", $value['adminname']);
Session::set("adminemail", $value['adminemail']);
Session::set("adminid", $value['adminid']);
header("Location: index.php");
} else {
$loginErr = "Usernameor Password Not Matched !!";
}
Session function for admin:
public static function checkSessionAdmin(){
self::init();
if (self::get("adminLogin")!== false) {
self::destroy();
header("Location:login.php");
}
}
Session check for admin
Session::checkSessionAdmin();
You don't have to be using different tables for the user and admin login. You just need a column that will help you check if a user has admin privileges. For example: You could create an is_admin column and set it's value to 1 if the user is an admin and 0 if he/she isn't.
# Your query
$stmt = "SELECT
users.id as uid,
users.username as username,
users.is_admin as is_admin
FROM users
WHERE users.username='{$username}'
AND users.password='{$password}'
LIMIT 1
";
You then add the results to a session like you are doing already.
var_dump($_SESSION['user']);
Array {
'uid' => '125',
'username' => 'SomeGuy',
'is_admin' => '1',
}
Your session will now contain a value is_admin and so you can check if a user is an administration by using a simple if statement.
if ($_SESSION['user']['is_admin'] == 1) {
// Admin only stuff here
}
As I can see you having two separate tables for user and admin to store their data, so i think that shouldn't be any problem for your query, when its for user we can not stop to brows them any page.
But if user can use its own detail to log in admin panel that means you have multiple data in your both table, that may be caused because of you may insert same data in both table or there is something wrong in your insert Query.
But as a solution i think its better to add Roles field in both database which define where there its user or admin and after your select query make if condition to check if they fall in with your requirements and than set the session.
But From My point of view best thing is to have single Table for both Users and Admin to store all comment data and make Admin table to store user_id and some priority. when you make checking query check where there user_id is belongs to admin table or not and define them as admin or user and than set session.
This may solve your issue, but if need more help let me know.
You can have user_type field in the database and in the admin session you can see if the user_type is admin or customer. If its admin then redirect him to the admin dashboard otherwise to the customer dashboard. In the admin header, put a check for the same.
Hope this helps.
I've found the solution. I replaced the following code.
Code for User login:
Replaced Session::set("login", "userLogin"); by Session::set("login", "true");
Code for Session Function User:
Replaced if (self::get("login")!== false) by if (self::get("login")== false)
Code for Admin login:
Replaced Session::Session::set("loginadmin", "adminLogin"); by Session::set("adminlogin", "true");
Code for Session Function Admin:
Replaced if (self::get("adminlogin")!== false) by if (self::get("adminlogin")== false)
I have a sit developed in cakephp, and I have a page to edit user.
My user table has many field and one of this is password in md5.
The user can modify all its fields and password but if he leave blank this field I have t take from the database the old password and save it.
But return me error on save on the password field.
This is my action into the controller:
if ($this->request->is ('post')){
$this->User->id = $this->request->data['User']['id'];
if($this->request->data['User']['password'] == ''){
$user = $this->User->find('first',array('conditions'=>array('User.id' => $this->request->data['User']['id'])));
$this->request->data['User']['password'] = md5($user['User']['password']);
$this->request->data['User']['password_confirm'] = md5($user['User']['password']);
}
if ($this->User->save($this->request->data)) {
$this->redirect (array ('action'=>'index'));
}
else{
debug($this->User->validationErrors);
$this->Session->write('flash_element','error');
$this->Session->setFlash ('Errore di salvataggio dello user.');
}
}
And this is the method beforeSave into the UserModel:
public function beforeSave(){
if (isset($this->data['User']['password'])){
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
}
}
The problem is when I try to save return me error on the field password lie is inappropriate type.
If I print the field password before save I see something like: ***** but if I print the variable md5($user['User']['password']) return me the right value of password crypted.
Thanks
IMO, don't have the "password" field where the user edits his profile information.
You can have 2 forms on the page, where the second one is a change password form. This way, if the user changes their "first name" (which is in the first form) for example, your code does not have to check or do anything with their password.
After seeing many different frameworks, and creating systems myself, I can't say I recall anything where I have seen in the "wild" something handled like your doing. You are doing an extra step by getting their old password and "putting it back" just so you don't lose their password in the database when they want to change their profile details.
If its for security, you can make them "confirm" their password so it must match before changing the profile details.
Having the "password" box on the "edit profile" form is just bad code logic.
First comment, there is nothing wrong using md5 but I would use sha1.
Second, you can use only one form, not 2.
Then, in your controller you just need to check if user entered a new password, which you are already doing, if the field is empty then you unset that field, so cake won't update that field.
if ($this->request->is ('post')){
$this->User->id = $this->request->data['User']['id'];
if ($this->request->data['User']['password'] == '') {
unset($this->request->data['User']['password'], $this->request->data['User']['password_confirm']);
}
if ($this->User->save($this->request->data)) {
$this->redirect (array ('action'=>'index'));
}
else{
debug($this->User->validationErrors);
$this->Session->write('flash_element','error');
$this->Session->setFlash ('Errore di salvataggio dello user.');
}
}
By the way, I would change this
$this->User->id = $this->request->data['User']['id'];
For something like
$this->request->data['User']['id'] = $this->Session->read('Auth.id');
in order to prevent data tampering, but due I don't know if you are keeping the user id in a session I didn't write it in the example code
I am building a friendship system in CakePHP that uses two tables: Users and Friends.
In Users (id,username,email,password) and Friends (id,user_from,user_to,status)
A user requests another user to be friends and this creates a record in the friends table storing both the user ids and setting a status of 'Requested'. The user can either accept the friendship and the status changes to 'Accepted' or cancel the friendship and the record is deleted from the database.
An example link for the request looks like and could be shown either in a users list or on the users details page:
<?php echo $this->Html->link('Add as Friend', array('controller'=>'friends','action'=>'add_friend',$user['User']['id'])); ?>
Question 1 is how could I make this link change to a cancel request link if the user has a request against them or is already friends?
This link corresponds to the following method in the controller:
function add_friend ( $id )
{
if(!empty($this->data))
{
$this->Friend->Create();
if($this->Friend->save($this->data))
{
$this->Session->setFlash('Friendship Requested');
$this->redirect(array('controller'=>'users','action'=>'login'));
}
}
}
So we are passing the ID to the method which will be the user_to and then the 'user_from' needs to be the currently logged in user and set the status to 'Requested'. Question 2 is how to do I do this? Also how do I prevent a user from creating multiple records by just calling that method over and show a message saying you've already requested friendship.
The next method is:
function accept_friendship ( $id )
{
$this->Session->setFlash('Friendship Accepted');
$this->redirect(array('controller'=>'friends','action'=>'index'));
}
}
}
Question 3: But again I'm confused as to how I would change the status of the record and mark the users as friends when the method is called. Also need to prevent this from being called multiple times on the same record.
The final bit is listing the friends for the user or another user:
function users_friends( $id )
{
$this->set('friends', $this->Friend->find('all'));
}
function my_friends()
{
$this->set('friends', $this->Friend->find('all'));
}
As you can see the first method requires the id of the user you are viewing and then the second method will use the currently logged in user id. Question 4: How do I then use this to list the friends of that user?
If anyone can help put me on the right track with this it'd be much appreciated as I've ground to a halt and not sure how to do those 4 things and trying to learn CakePHP as best I can so help is much appreciated. Thanks
EDIT: It has occurred to me that a view with hidden fields could be used to store the information regarding the friend request that the user confirms but this isn't ideal as it means sending the user off somewhere else when in fact I want to just run the function and do the redirect straight off. NOT AJAX THOUGH!
Answer 1 and 2:
function add_friend ( $id )
{
if(!empty($this->data))
{
$this->Friend->Create();
if($this->Friend->save($this->data))
{
$this->Session->setFlash('Friendship Requested');
$this->redirect(array('controller'=>'users','action'=>'login'));
}
}
if(empty($this->data))
{
$this->set('friends', $this->Friend->find('all',array('Friend.id'=>$id));
}
}
<?php
if($friends['Friend']['status']=="Requested")
{
echo $this->Html->link('Request Pending', '#');
}
else if($friends['Friend']['status']=="Accepted")
{
echo $this->Html->link('Already Friend', '#');
}
else
{
echo $this->Html->link('Add as Friend', array('controller'=>'friends','action'=>'add_friend',$user['User']['id']));
}
?>
Answer 3 and 4:
funcrion friendlist($user_id)
{
$session_user_id = $this->Session->read('Auth.User.id')
if($user_id == $session_user_id )
{
$user_to = $session_user_id ;
}
else
{
$user_to = $user_id;
}
$this->Friend->find('all',array('Friend.user_to'=>$user_to,'Friend.status'=>'Accepted')
}
Answer 3 is something like this:
function accept_friendship ( $id ) {
$this->Friend->id = $id;
$current_status = $this->Friend->field('status');
if($current_status=='Requested') {
$this->Application->saveField('status', 'Accepted');
}
$this->Session->setFlash('Friendship Accepted');
$this->redirect(array('controller'=>'friends','action'=>'index'));
}
Essentially get the ID of the friend request, check the status field, and if it's equal to Requested, then update it to Accepted. This way it will only be called once.
And also to prevent people from repeatedly "accepting" a friend, just remove the "Accept" link once it's been accepted. The if statement stops your code from updating unnecessarily.
You should also put some kind of prevention in place so that only the requested friend can accept the request. Otherwise I could type the URL yoursite.com/friends/accept_friendship/123 and accept a random persons request without any authentication.
I have this method:
public function activation_code()
{ //activation code sent into db
$activation_code = random_string('alnum', 32);
return $activation_code;
}
What I'm trying to do is provide this with the post data that gets sent to my database but also provide a copy of that same activation code so I can concatenate it with the "click here to confirm email" url that is in my confirmation email that is sent to users upon registration.
How can I do this? I can't provide the method because if I do the database code and the email URL code will be different so user wouldn't be able to match them and confirm their email address.
I've tried many other ways such as providing the method in one place e.g.
public function create()
{ //get post data and insert into db
$dbcolumn->group_id = 2; //group 1 for admin group 2 for member
$dbcolumn->first_name = $this->input->post('first_name');
$dbcolumn->last_name = $this->input->post('last_name');
$dbcolumn->email = $this->input->post('email');
$dbcolumn->password = $this->hashed();
$dbcolumn->birthday = $this->input->post('year') .
'-' . $this->input->post('month') . '-' . $this->input->post('day');
$dbcolumn->sex = $this->input->post('sex');
$dbcolumn->activation_code = $this->activation_code();
// date and time user joined the website
$dbcolumn->created_on = date('Y-m-d H:i:s', now());
$this->db->insert('users', $dbcolumn);
}
If you look at the dbcolumn->activation code line you'll see what I've done. That works and the code is stored in the database. If I provide the same "$this->activation_code() method to the email that's sent the codes will obviously be different.
public function send_confirmation_email()
{ //receives variable from create method
$this->load->library('email');
$this->email->from('wengerarsen#gmail.com', 'my site');
$this->email->to($this->input->post('email'));
$this->email->subject('my site - Activate your account');
//copy of activation code returned from create method
$this->email->message('We\'re back, please click the link to activate your account ' . anchor('http://mysite.com/activation/' . $this->activation_code(), 'Activate my account'));
$this->email->send();
}
As you can see I have the same method $activation_code() pulled into my send confirmation email method. This will just generate a whole new code meaning I won't be able to match the database activation code and the URI segment code in the users email.
I have tried to make the variable in the return public and call it in the send confirmaton email method but it doesn't work. The code ends up missing from he end of the URL in the email.
I've tried so many different ways and nothings working.
Maybe I'm missing something here?
Advice, examples etc will be much appreciated.
Every time you're calling activation_code() you're going to be creating a new code, because you're only storing it in the scope of that function.
A better idea would be to store it as an object property, like follows:
public var $_activation_code = null;
public function activation_code() {
if (is_null($this->_activation_code)) {
$this->_activation_code = random_string('alnum', 32);
}
return $this->_activation_code;
}
This will create the code if it hasn't already been done so for this object, or will simply return the current code if the method has been called more than once, meaning the code will be consistent across the object.
When a user enters his login information and hits submit, i want to check if the user already exists or not.
So, i have the following two questions
1. Which hook is needed to be implemented , for the case when user hits the submit button on the login form. I need the username entered by the user.
2. How to check if a user already exists in drupal or not programmatically ?
Some sample code would be really appreciated.
Please help.
Thank You.
Drupal 7 provides a function to get a user object by name :
$user = user_load_by_name($name);
if(!$user){
// User doesn't exist
}
else {
// User exists
}
http://api.drupal.org/api/drupal/modules%21user%21user.module/function/user_load_by_name/7
This can be done with hook_form_alter:
function module_(&$form, &$form_state, $form_id) {
$user_login_forms = array('user_login', 'user_login_block');
if (in_array($form_id, $user_login_forms)) {
$form['#validate'][] = 'my_validate_function';
}
}
function my_validate_function(&$form, &$form_state) {
$name = $form_state['values']['name'];
// Drupal 6:
if (!db_result(db_query("SELECT COUNT(*) FROM {users} WHERE name = '%s';", $name))) {
// User doesn't exist
}
// Drupal 7:
if (!db_query("SELECT COUNT(*) FROM {users} WHERE name = :name;", array(':name' => $name))->fetchField()) {
// User doesn't exist
}
}
It's better to query the DB directly in this case than than using user_load as it hooks into other modules as well.
In Drupal 7, substitute for this in the validation function:
if (!db_query("SELECT COUNT(*) FROM {users} WHERE name = :name", array(':name' => $name))->fetchField()) {
// User doesn't exist
}
I realize this is almost 2 years old, but user_authenticate does this nicely.
$existing_user = user_authenticate($name,$password);
if($existing_user)
// user exists
else
// user doesn't exist
Hope this helps someone else.
You can try to look on these 2 modules for inspiration: friendly_register and username_check.